diff options
85 files changed, 4076 insertions, 3934 deletions
diff --git a/.travis.yml b/.travis.yml index 426eef40..e24ed7d8 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,18 @@ 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/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/*' \ + '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 +52,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 \ . @@ -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 * @@ -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); @@ -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; @@ -1563,12 +1568,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 +1616,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 +1659,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 +1676,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 +1717,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 +1728,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/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/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 */ 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 <stdio.h> -#include <string.h> -#include <ctype.h> - -#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..088d4a85 --- /dev/null +++ b/Alc/ambdec.cpp @@ -0,0 +1,425 @@ + +#include "config.h" + +#include "ambdec.h" + +#include <cstring> +#include <cctype> + +#include <limits> +#include <string> +#include <fstream> +#include <sstream> + +#include "compat.h" + + +namespace { + +int readline(std::istream &f, std::string &output) +{ + while(f.good() && f.peek() == '\n') + f.ignore(); + + std::getline(f, output); + return !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; + if(endpos < buffer.length()) + return false; + return true; +} + + +bool load_ambdec_speakers(AmbDecConf *conf, std::istream &f, std::string &buffer) +{ + ALsizei cur = 0; + while(cur < conf->NumSpeakers) + { + 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") + { + 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.c_str()); + return false; + } + + istr.clear(); + std::istream::pos_type endpos{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(ALfloat *gains, ALfloat (*matrix)[MAX_AMBI_COEFFS], ALsizei maxrow, std::istream &f, std::string &buffer) +{ + bool gotgains = false; + ALsizei cur = 0; + 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") + { + ALuint curgain = 0; + float value; + while(istr.good()) + { + istr >> value; + 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()); + return false; + } + if(curgain < MAX_AMBI_ORDER+1) + gains[curgain++] = value; + } + while(curgain < MAX_AMBI_ORDER+1) + gains[curgain++] = 0.0f; + gotgains = true; + } + else if(cmd == "add_row") + { + ALuint curidx = 0; + 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()+istr.tellg()); + return false; + } + if(curidx < MAX_AMBI_COEFFS) + matrix[cur][curidx++] = value; + } + while(curidx < MAX_AMBI_COEFFS) + matrix[cur][curidx++] = 0.0f; + cur++; + } + else + { + ERR("Unexpected matrix command: %s\n", cmd.c_str()); + return false; + } + + istr.clear(); + std::istream::pos_type endpos{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) +{ + al::ifstream f{fname}; + if(!f.is_open()) + { + ERR("Failed to open: %s\n", fname); + return 0; + } + + 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()+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()+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()+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 >> NumSpeakers; + if(!istr.eof() && !std::isspace(istr.peek())) + { + ERR("Extra junk after speakers: %s\n", buffer.c_str()+istr.tellg()); + return 0; + } + if(NumSpeakers > MAX_OUTPUT_CHANNELS) + { + ERR("Unsupported speaker count: %u\n", NumSpeakers); + return 0; + } + } + 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()+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()+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/{") + { + std::istream::pos_type endpos{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(this, 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/{") + { + std::istream::pos_type endpos{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, NumSpeakers, f, buffer)) + return 0; + } + else + { + if(command == "/lfmatrix/{") + { + if(!load_ambdec_matrix(LFOrderGain, LFMatrix, NumSpeakers, f, buffer)) + return 0; + } + else if(command == "/hfmatrix/{") + { + if(!load_ambdec_matrix(HFOrderGain, HFMatrix, NumSpeakers, 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") + { + std::istream::pos_type endpos{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(); + std::istream::pos_type endpos{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 index 0bb84072..d6d154fb 100644 --- a/Alc/ambdec.h +++ b/Alc/ambdec.h @@ -1,34 +1,35 @@ #ifndef AMBDEC_H #define AMBDEC_H -#include "alstring.h" +#include <string> + #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 */ @@ -37,10 +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); + int load(const char *fname); +}; #endif /* AMBDEC_H */ 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.c b/Alc/backends/dsound.cpp index c368cffb..e760e9f5 100644 --- a/Alc/backends/dsound.c +++ b/Alc/backends/dsound.cpp @@ -32,12 +32,16 @@ #include <ksmedia.h> #endif +#include <atomic> +#include <thread> +#include <string> +#include <vector> +#include <algorithm> + #include "alMain.h" #include "alu.h" #include "ringbuffer.h" -#include "threads.h" #include "compat.h" -#include "alstring.h" #include "backends/base.h" @@ -58,8 +62,18 @@ #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 " @@ -71,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) @@ -84,17 +100,18 @@ static ALCboolean DSoundLoad(void) if(!ds_handle) { ds_handle = LoadLib("dsound.dll"); - if(ds_handle == NULL) + if(!ds_handle) { 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) { \ + p##f = reinterpret_cast<decltype(p##f)>(GetSymbol(ds_handle, #f)); \ + if(!p##f) \ + { \ CloseLib(ds_handle); \ - ds_handle = NULL; \ + ds_handle = nullptr; \ return ALC_FALSE; \ } \ } while(0) @@ -111,85 +128,72 @@ static ALCboolean DSoundLoad(void) #define MAX_UPDATES 128 -typedef struct { - al_string name; +struct DevMap { + std::string name; GUID guid; -} DevMap; -TYPEDEF_VECTOR(DevMap, vector_DevMap) -static vector_DevMap PlaybackDevices; -static vector_DevMap CaptureDevices; + template<typename T0, typename T1> + DevMap(T0&& name_, T1&& guid_) + : name{std::forward<T0>(name_)}, guid{std::forward<T1>(guid_)} + { } +}; -static void clear_devlist(vector_DevMap *list) +std::vector<DevMap> PlaybackDevices; +std::vector<DevMap> CaptureDevices; + +bool checkName(const std::vector<DevMap> &list, const std::string &name) { -#define DEINIT_STR(i) AL_STRING_DEINIT((i)->name) - VECTOR_FOR_EACH(DevMap, *list, DEINIT_STR); - VECTOR_RESIZE(*list, 0, 0); -#undef DEINIT_STR + return std::find_if(list.cbegin(), list.cend(), + [&name](const DevMap &entry) -> bool + { return entry.name == name; } + ) != list.cend(); } -static BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHAR* UNUSED(drvname), void *data) +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); + auto& devices = *reinterpret_cast<std::vector<DevMap>*>(data); + const std::string basename{DEVNAME_HEAD + wstr_to_utf8(desc)}; - count = 0; - while(1) + int count{1}; + std::string newname{basename}; + while(checkName(devices, newname)) { - 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++; + newname = basename; + newname += " #"; + newname += std::to_string(++count); } - entry.guid = *guid; + devices.emplace_back(std::move(newname), *guid); + const DevMap &newentry = devices.back(); - hr = StringFromCLSID(guid, &guidstr); + OLECHAR *guidstr{nullptr}; + HRESULT hr{StringFromCLSID(*guid, &guidstr)}; if(SUCCEEDED(hr)) { - TRACE("Got device \"%s\", GUID \"%ls\"\n", alstr_get_cstr(entry.name), guidstr); + TRACE("Got device \"%s\", GUID \"%ls\"\n", newentry.name.c_str(), guidstr); CoTaskMemFree(guidstr); } - VECTOR_PUSH_BACK(*devices, entry); - return TRUE; } +} // namespace -typedef struct ALCdsoundPlayback { - DERIVE_FROM_TYPE(ALCbackend); - IDirectSound *DS; - IDirectSoundBuffer *PrimaryBuffer; - IDirectSoundBuffer *Buffer; - IDirectSoundNotify *Notifies; - HANDLE NotifyEvent; +struct ALCdsoundPlayback final : public ALCbackend { + IDirectSound *DS{nullptr}; + IDirectSoundBuffer *PrimaryBuffer{nullptr}; + IDirectSoundBuffer *Buffer{nullptr}; + IDirectSoundNotify *Notifies{nullptr}; + HANDLE NotifyEvent{nullptr}; - ATOMIC(ALenum) killNow; - althrd_t thread; -} ALCdsoundPlayback; + std::atomic<ALenum> killNow{AL_TRUE}; + std::thread thread; +}; -static int ALCdsoundPlayback_mixerProc(void *ptr); +static int ALCdsoundPlayback_mixerProc(ALCdsoundPlayback *self); static void ALCdsoundPlayback_Construct(ALCdsoundPlayback *self, ALCdevice *device); static void ALCdsoundPlayback_Destruct(ALCdsoundPlayback *self); @@ -209,61 +213,47 @@ 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); - - 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; + self->Notifies->Release(); + self->Notifies = nullptr; if(self->Buffer) - IDirectSoundBuffer_Release(self->Buffer); - self->Buffer = NULL; - if(self->PrimaryBuffer != NULL) - IDirectSoundBuffer_Release(self->PrimaryBuffer); - self->PrimaryBuffer = NULL; + self->Buffer->Release(); + self->Buffer = nullptr; + if(self->PrimaryBuffer) + self->PrimaryBuffer->Release(); + self->PrimaryBuffer = nullptr; if(self->DS) - IDirectSound_Release(self->DS); - self->DS = NULL; + self->DS->Release(); + self->DS = nullptr; if(self->NotifyEvent) CloseHandle(self->NotifyEvent); - self->NotifyEvent = NULL; + self->NotifyEvent = nullptr; ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); + self->~ALCdsoundPlayback(); } -FORCE_ALIGN static int ALCdsoundPlayback_mixerProc(void *ptr) +FORCE_ALIGN static int ALCdsoundPlayback_mixerProc(ALCdsoundPlayback *self) { - 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)); + IDirectSoundBuffer *const Buffer{self->Buffer}; + + DSBCAPS DSBCaps{}; DSBCaps.dwSize = sizeof(DSBCaps); - err = IDirectSoundBuffer_GetCaps(self->Buffer, &DSBCaps); + HRESULT err{Buffer->GetCaps(&DSBCaps)}; if(FAILED(err)) { ERR("Failed to get buffer caps: 0x%lx\n", err); @@ -273,22 +263,25 @@ FORCE_ALIGN static int ALCdsoundPlayback_mixerProc(void *ptr) return 1; } - FrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); - FragSize = device->UpdateSize * FrameSize; + ALsizei FrameSize{FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder)}; + DWORD FragSize{device->UpdateSize * FrameSize}; - IDirectSoundBuffer_GetCurrentPosition(self->Buffer, &LastCursor, NULL); - while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && + bool Playing{false}; + DWORD LastCursor{0u}; + Buffer->GetCurrentPosition(&LastCursor, nullptr); + while(!self->killNow.load(std::memory_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; + DWORD PlayCursor; + Buffer->GetCurrentPosition(&PlayCursor, nullptr); + DWORD avail = (PlayCursor-LastCursor+DSBCaps.dwBufferBytes) % DSBCaps.dwBufferBytes; if(avail < FragSize) { if(!Playing) { - err = IDirectSoundBuffer_Play(self->Buffer, 0, 0, DSBPLAY_LOOPING); + err = Buffer->Play(0, 0, DSBPLAY_LOOPING); if(FAILED(err)) { ERR("Failed to play buffer: 0x%lx\n", err); @@ -297,7 +290,7 @@ FORCE_ALIGN static int ALCdsoundPlayback_mixerProc(void *ptr) ALCdevice_Unlock(device); return 1; } - Playing = TRUE; + Playing = true; } avail = WaitForSingleObjectEx(self->NotifyEvent, 2000, FALSE); @@ -308,20 +301,21 @@ FORCE_ALIGN static int ALCdsoundPlayback_mixerProc(void *ptr) avail -= avail%FragSize; // Lock output buffer - WriteCnt1 = 0; - WriteCnt2 = 0; - err = IDirectSoundBuffer_Lock(self->Buffer, LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0); + 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 = IDirectSoundBuffer_Restore(self->Buffer); + err = Buffer->Restore(); if(SUCCEEDED(err)) { - Playing = FALSE; + Playing = false; LastCursor = 0; - err = IDirectSoundBuffer_Lock(self->Buffer, 0, DSBCaps.dwBufferBytes, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0); + err = Buffer->Lock(0, DSBCaps.dwBufferBytes, &WritePtr1, &WriteCnt1, + &WritePtr2, &WriteCnt2, 0); } } @@ -335,7 +329,7 @@ FORCE_ALIGN static int ALCdsoundPlayback_mixerProc(void *ptr) ALCdevice_Unlock(device); // Unlock output buffer only when successfully locked - IDirectSoundBuffer_Unlock(self->Buffer, WritePtr1, WriteCnt1, WritePtr2, WriteCnt2); + Buffer->Unlock(WritePtr1, WriteCnt1, WritePtr2, WriteCnt2); } else { @@ -356,14 +350,13 @@ FORCE_ALIGN static int ALCdsoundPlayback_mixerProc(void *ptr) static ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *deviceName) { - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - const GUID *guid = NULL; - HRESULT hr, hrcom; + ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; - if(VECTOR_SIZE(PlaybackDevices) == 0) + HRESULT hr; + if(PlaybackDevices.empty()) { /* Initialize COM to prevent name truncation */ - hrcom = CoInitialize(NULL); + HRESULT hrcom{CoInitialize(nullptr)}; hr = DirectSoundEnumerateW(DSoundEnumDevices, &PlaybackDevices); if(FAILED(hr)) ERR("Error enumerating DirectSound devices (0x%lx)!\n", hr); @@ -371,42 +364,34 @@ static ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *de CoUninitialize(); } - if(!deviceName && VECTOR_SIZE(PlaybackDevices) > 0) + const GUID *guid{nullptr}; + if(!deviceName && !PlaybackDevices.empty()) { - deviceName = alstr_get_cstr(VECTOR_FRONT(PlaybackDevices).name); - guid = &VECTOR_FRONT(PlaybackDevices).guid; + deviceName = PlaybackDevices[0].name.c_str(); + guid = &PlaybackDevices[0].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)) + 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(NULL, FALSE, FALSE, NULL); - if(self->NotifyEvent == NULL) - hr = E_FAIL; + self->NotifyEvent = CreateEventW(nullptr, FALSE, FALSE, nullptr); + if(!self->NotifyEvent) hr = E_FAIL; //DirectSound Init code if(SUCCEEDED(hr)) - hr = DirectSoundCreate(guid, &self->DS, NULL); + hr = DirectSoundCreate(guid, &self->DS, nullptr); if(SUCCEEDED(hr)) - hr = IDirectSound_SetCooperativeLevel(self->DS, GetForegroundWindow(), DSSCL_PRIORITY); + hr = self->DS->SetCooperativeLevel(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; } @@ -419,22 +404,16 @@ static ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *de 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; + self->Notifies->Release(); + self->Notifies = nullptr; if(self->Buffer) - IDirectSoundBuffer_Release(self->Buffer); - self->Buffer = NULL; - if(self->PrimaryBuffer != NULL) - IDirectSoundBuffer_Release(self->PrimaryBuffer); - self->PrimaryBuffer = NULL; + self->Buffer->Release(); + self->Buffer = nullptr; + if(self->PrimaryBuffer) + self->PrimaryBuffer->Release(); + self->PrimaryBuffer = nullptr; switch(device->FmtType) { @@ -457,7 +436,9 @@ static ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self) break; } - hr = IDirectSound_GetSpeakerConfig(self->DS, &speakers); + WAVEFORMATEXTENSIBLE OutputType{}; + DWORD speakers; + HRESULT hr{self->DS->GetSpeakerConfig(&speakers)}; if(SUCCEEDED(hr)) { speakers = DSSPEAKER_CONFIG(speakers); @@ -558,20 +539,20 @@ retry_open: OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; if(self->PrimaryBuffer) - IDirectSoundBuffer_Release(self->PrimaryBuffer); - self->PrimaryBuffer = NULL; + self->PrimaryBuffer->Release(); + self->PrimaryBuffer = nullptr; } 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); + DSBUFFERDESC DSBDescription{}; + DSBDescription.dwSize = sizeof(DSBDescription); + DSBDescription.dwFlags = DSBCAPS_PRIMARYBUFFER; + hr = self->DS->CreateSoundBuffer(&DSBDescription, &self->PrimaryBuffer, nullptr); } if(SUCCEEDED(hr)) - hr = IDirectSoundBuffer_SetFormat(self->PrimaryBuffer,&OutputType.Format); + hr = self->PrimaryBuffer->SetFormat(&OutputType.Format); } if(SUCCEEDED(hr)) @@ -583,13 +564,15 @@ retry_open: 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); + 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; @@ -599,34 +582,37 @@ retry_open: if(SUCCEEDED(hr)) { - hr = IDirectSoundBuffer_QueryInterface(self->Buffer, &IID_IDirectSoundNotify, (void**)&self->Notifies); + void *ptr; + hr = self->Buffer->QueryInterface(IID_IDirectSoundNotify, &ptr); if(SUCCEEDED(hr)) { - DSBPOSITIONNOTIFY notifies[MAX_UPDATES]; - ALuint i; + auto Notifies = reinterpret_cast<IDirectSoundNotify*>(ptr); + self->Notifies = Notifies; + + device->NumUpdates = minu(device->NumUpdates, MAX_UPDATES); - for(i = 0;i < device->NumUpdates;++i) + std::array<DSBPOSITIONNOTIFY,MAX_UPDATES> nots; + for(ALuint i{0};i < device->NumUpdates;++i) { - notifies[i].dwOffset = i * device->UpdateSize * - OutputType.Format.nBlockAlign; - notifies[i].hEventNotify = self->NotifyEvent; + nots[i].dwOffset = i * device->UpdateSize * OutputType.Format.nBlockAlign; + nots[i].hEventNotify = self->NotifyEvent; } - if(IDirectSoundNotify_SetNotificationPositions(self->Notifies, device->NumUpdates, notifies) != DS_OK) + if(Notifies->SetNotificationPositions(device->NumUpdates, nots.data()) != 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; + 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; } @@ -638,36 +624,38 @@ retry_open: 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; + try { + self->killNow.store(AL_FALSE, std::memory_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) { - 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); - - IDirectSoundBuffer_Stop(self->Buffer); -} + self->thread.join(); + self->Buffer->Stop(); +} -typedef struct ALCdsoundCapture { - DERIVE_FROM_TYPE(ALCbackend); - IDirectSoundCapture *DSC; - IDirectSoundCaptureBuffer *DSCbuffer; - DWORD BufferBytes; - DWORD Cursor; +struct ALCdsoundCapture final : public ALCbackend { + IDirectSoundCapture *DSC{nullptr}; + IDirectSoundCaptureBuffer *DSCbuffer{nullptr}; + DWORD BufferBytes{0u}; + DWORD Cursor{0u}; - ll_ringbuffer_t *Ring; -} ALCdsoundCapture; + ll_ringbuffer_t *Ring{nullptr}; +}; static void ALCdsoundCapture_Construct(ALCdsoundCapture *self, ALCdevice *device); static void ALCdsoundCapture_Destruct(ALCdsoundCapture *self); @@ -686,47 +674,41 @@ 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); - - self->DSC = NULL; - self->DSCbuffer = NULL; - self->Ring = NULL; } static void ALCdsoundCapture_Destruct(ALCdsoundCapture *self) { ll_ringbuffer_free(self->Ring); - self->Ring = NULL; + self->Ring = nullptr; - if(self->DSCbuffer != NULL) + if(self->DSCbuffer) { - IDirectSoundCaptureBuffer_Stop(self->DSCbuffer); - IDirectSoundCaptureBuffer_Release(self->DSCbuffer); - self->DSCbuffer = NULL; + self->DSCbuffer->Stop(); + self->DSCbuffer->Release(); + self->DSCbuffer = nullptr; } if(self->DSC) - IDirectSoundCapture_Release(self->DSC); - self->DSC = NULL; + 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; - WAVEFORMATEXTENSIBLE InputType; - DSCBUFFERDESC DSCBDescription; - const GUID *guid = NULL; - HRESULT hr, hrcom; - ALuint samples; - if(VECTOR_SIZE(CaptureDevices) == 0) + HRESULT hr; + if(CaptureDevices.empty()) { /* Initialize COM to prevent name truncation */ - hrcom = CoInitialize(NULL); + HRESULT hrcom{CoInitialize(nullptr)}; hr = DirectSoundCaptureEnumerateW(DSoundEnumDevices, &CaptureDevices); if(FAILED(hr)) ERR("Error enumerating DirectSound devices (0x%lx)!\n", hr); @@ -734,19 +716,19 @@ static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *devi CoUninitialize(); } - if(!deviceName && VECTOR_SIZE(CaptureDevices) > 0) + const GUID *guid{nullptr}; + if(!deviceName && !CaptureDevices.empty()) { - deviceName = alstr_get_cstr(VECTOR_FRONT(CaptureDevices).name); - guid = &VECTOR_FRONT(CaptureDevices).guid; + deviceName = CaptureDevices[0].name.c_str(); + guid = &CaptureDevices[0].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)) + 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; } @@ -766,7 +748,7 @@ static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *devi break; } - memset(&InputType, 0, sizeof(InputType)); + WAVEFORMATEXTENSIBLE InputType{}; switch(device->FmtChans) { case DevFmtMono: @@ -841,25 +823,24 @@ static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *devi InputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); } - samples = device->UpdateSize * device->NumUpdates; + ALuint samples{device->UpdateSize * device->NumUpdates}; samples = maxu(samples, 100 * device->Frequency / 1000); - memset(&DSCBDescription, 0, sizeof(DSCBUFFERDESC)); - DSCBDescription.dwSize = sizeof(DSCBUFFERDESC); + 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, NULL); + hr = DirectSoundCaptureCreate(guid, &self->DSC, nullptr); if(SUCCEEDED(hr)) - hr = IDirectSoundCapture_CreateCaptureBuffer(self->DSC, &DSCBDescription, &self->DSCbuffer, NULL); + 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 == NULL) - hr = DSERR_OUTOFMEMORY; + if(!self->Ring) hr = DSERR_OUTOFMEMORY; } if(FAILED(hr)) @@ -867,13 +848,13 @@ static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *devi 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; + self->Ring = nullptr; + if(self->DSCbuffer) + self->DSCbuffer->Release(); + self->DSCbuffer = nullptr; if(self->DSC) - IDirectSoundCapture_Release(self->DSC); - self->DSC = NULL; + self->DSC->Release(); + self->DSC = nullptr; return ALC_INVALID_VALUE; } @@ -888,9 +869,7 @@ static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *devi static ALCboolean ALCdsoundCapture_start(ALCdsoundCapture *self) { - HRESULT hr; - - hr = IDirectSoundCaptureBuffer_Start(self->DSCbuffer, DSCBSTART_LOOPING); + HRESULT hr{self->DSCbuffer->Start(DSCBSTART_LOOPING)}; if(FAILED(hr)) { ERR("start failed: 0x%08lx\n", hr); @@ -904,9 +883,7 @@ static ALCboolean ALCdsoundCapture_start(ALCdsoundCapture *self) static void ALCdsoundCapture_stop(ALCdsoundCapture *self) { - HRESULT hr; - - hr = IDirectSoundCaptureBuffer_Stop(self->DSCbuffer); + HRESULT hr{self->DSCbuffer->Stop()}; if(FAILED(hr)) { ERR("stop failed: 0x%08lx\n", hr); @@ -917,44 +894,40 @@ static void ALCdsoundCapture_stop(ALCdsoundCapture *self) static ALCenum ALCdsoundCapture_captureSamples(ALCdsoundCapture *self, ALCvoid *buffer, ALCuint samples) { - ll_ringbuffer_read(self->Ring, buffer, samples); + ll_ringbuffer_read(self->Ring, reinterpret_cast<char*>(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; + return ll_ringbuffer_read_space(self->Ring); - FrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder); - BufferBytes = self->BufferBytes; - LastCursor = self->Cursor; + ALsizei FrameSize{FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder)}; + DWORD BufferBytes{self->BufferBytes}; + DWORD LastCursor{self->Cursor}; - hr = IDirectSoundCaptureBuffer_GetCurrentPosition(self->DSCbuffer, NULL, &ReadCursor); + DWORD ReadCursor; + void *ReadPtr1, *ReadPtr2; + DWORD ReadCnt1, ReadCnt2; + HRESULT hr{self->DSCbuffer->GetCurrentPosition(nullptr, &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); + 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, ReadPtr1, ReadCnt1/FrameSize); - if(ReadPtr2 != NULL) - ll_ringbuffer_write(self->Ring, ReadPtr2, ReadCnt2/FrameSize); - hr = IDirectSoundCaptureBuffer_Unlock(self->DSCbuffer, - ReadPtr1, ReadCnt1, - ReadPtr2, ReadCnt2); + ll_ringbuffer_write(self->Ring, reinterpret_cast<const char*>(ReadPtr1), + ReadCnt1/FrameSize); + if(ReadPtr2 != nullptr) + ll_ringbuffer_write(self->Ring, reinterpret_cast<const char*>(ReadPtr2), + ReadCnt2/FrameSize); + hr = self->DSCbuffer->Unlock(ReadPtr1, ReadCnt1, ReadPtr2, ReadCnt2); self->Cursor = (LastCursor+ReadCnt1+ReadCnt2) % BufferBytes; } @@ -964,15 +937,14 @@ static ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self) aluHandleDisconnect(device, "Failure retrieving capture data: 0x%lx", hr); } -done: - return (ALCuint)ll_ringbuffer_read_space(self->Ring); + return ll_ringbuffer_read_space(self->Ring); } -typedef struct ALCdsoundBackendFactory { - DERIVE_FROM_TYPE(ALCbackendFactory); -} ALCdsoundBackendFactory; -#define ALCDSOUNDBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCdsoundBackendFactory, ALCbackendFactory) } } +struct ALCdsoundBackendFactory final : public ALCbackendFactory { + ALCdsoundBackendFactory() noexcept; +}; +#define ALCDSOUNDBACKENDFACTORY_INITIALIZER GET_VTABLE2(ALCdsoundBackendFactory, ALCbackendFactory) ALCbackendFactory *ALCdsoundBackendFactory_getFactory(void); @@ -984,18 +956,20 @@ static ALCbackend* ALCdsoundBackendFactory_createBackend(ALCdsoundBackendFactory DEFINE_ALCBACKENDFACTORY_VTABLE(ALCdsoundBackendFactory); +ALCdsoundBackendFactory::ALCdsoundBackendFactory() noexcept + : ALCbackendFactory{ALCDSOUNDBACKENDFACTORY_INITIALIZER} +{ } + + ALCbackendFactory *ALCdsoundBackendFactory_getFactory(void) { - static ALCdsoundBackendFactory factory = ALCDSOUNDBACKENDFACTORY_INITIALIZER; + static ALCdsoundBackendFactory factory{}; 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; @@ -1003,16 +977,13 @@ static ALCboolean ALCdsoundBackendFactory_init(ALCdsoundBackendFactory* UNUSED(s static void ALCdsoundBackendFactory_deinit(ALCdsoundBackendFactory* UNUSED(self)) { - clear_devlist(&PlaybackDevices); - VECTOR_DEINIT(PlaybackDevices); - - clear_devlist(&CaptureDevices); - VECTOR_DEINIT(CaptureDevices); + PlaybackDevices.clear(); + CaptureDevices.clear(); #ifdef HAVE_DYNLOAD if(ds_handle) CloseLib(ds_handle); - ds_handle = NULL; + ds_handle = nullptr; #endif } @@ -1025,33 +996,36 @@ static ALCboolean ALCdsoundBackendFactory_querySupport(ALCdsoundBackendFactory* static void ALCdsoundBackendFactory_probe(ALCdsoundBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) { - HRESULT hr, hrcom; + 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 */ - hrcom = CoInitialize(NULL); + HRESULT hr; + HRESULT hrcom{CoInitialize(nullptr)}; 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); + PlaybackDevices.clear(); 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); + std::for_each(PlaybackDevices.cbegin(), PlaybackDevices.cend(), add_device); break; case CAPTURE_DEVICE_PROBE: - clear_devlist(&CaptureDevices); + CaptureDevices.clear(); 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); + std::for_each(CaptureDevices.cbegin(), CaptureDevices.cend(), add_device); break; -#undef APPEND_OUTNAME } if(SUCCEEDED(hrcom)) CoUninitialize(); @@ -1063,7 +1037,7 @@ static ALCbackend* ALCdsoundBackendFactory_createBackend(ALCdsoundBackendFactory { ALCdsoundPlayback *backend; NEW_OBJ(backend, ALCdsoundPlayback)(device); - if(!backend) return NULL; + if(!backend) return nullptr; return STATIC_CAST(ALCbackend, backend); } @@ -1071,9 +1045,9 @@ static ALCbackend* ALCdsoundBackendFactory_createBackend(ALCdsoundBackendFactory { ALCdsoundCapture *backend; NEW_OBJ(backend, ALCdsoundCapture)(device); - if(!backend) return NULL; + if(!backend) return nullptr; return STATIC_CAST(ALCbackend, backend); } - return NULL; + return nullptr; } diff --git a/Alc/backends/jack.c b/Alc/backends/jack.c index fdbe93f2..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; @@ -266,7 +268,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 +280,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/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) { diff --git a/Alc/backends/pulseaudio.c b/Alc/backends/pulseaudio.cpp index b34d7abc..e2845032 100644 --- a/Alc/backends/pulseaudio.c +++ b/Alc/backends/pulseaudio.cpp @@ -23,10 +23,16 @@ #include <string.h> +#include <array> +#include <string> +#include <vector> +#include <atomic> +#include <thread> +#include <algorithm> + #include "alMain.h" #include "alu.h" #include "alconfig.h" -#include "threads.h" #include "compat.h" #include "backends/base.h" @@ -35,9 +41,11 @@ #if PA_API_VERSION == 12 +namespace { + #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_context_unref); MAKE_FUNC(pa_sample_spec_valid); MAKE_FUNC(pa_frame_size); @@ -107,6 +115,7 @@ 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 @@ -174,16 +183,17 @@ MAKE_FUNC(pa_stream_begin_write); #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 pulse_load(void) { - ALCboolean ret = ALC_TRUE; + ALCboolean ret{ALC_TRUE}; #ifdef HAVE_DYNLOAD if(!pa_handle) { - al_string missing_funcs = AL_STRING_INIT_STATIC(); + std::string missing_funcs; #ifdef _WIN32 #define PALIB "libpulse-0.dll" @@ -200,10 +210,10 @@ static ALCboolean pulse_load(void) } #define LOAD_FUNC(x) do { \ - p##x = GetSymbol(pa_handle, #x); \ + p##x = reinterpret_cast<decltype(p##x)>(GetSymbol(pa_handle, #x)); \ if(!(p##x)) { \ ret = ALC_FALSE; \ - alstr_append_cstr(&missing_funcs, "\n" #x); \ + missing_funcs += "\n" #x; \ } \ } while(0) LOAD_FUNC(pa_context_unref); @@ -277,50 +287,112 @@ static ALCboolean pulse_load(void) if(ret == ALC_FALSE) { - WARN("Missing expected functions:%s\n", alstr_get_cstr(missing_funcs)); + WARN("Missing expected functions:%s\n", missing_funcs.c_str()); CloseLib(pa_handle); - pa_handle = NULL; + pa_handle = nullptr; } - alstr_reset(&missing_funcs); } #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; +} + + +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 */ -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) { - pa_threaded_mainloop *loop = pdata; - pa_context_state_t state; - - state = pa_context_get_state(context); + auto loop = reinterpret_cast<pa_threaded_mainloop*>(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); } -static void stream_state_callback(pa_stream *stream, void *pdata) +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); + auto loop = reinterpret_cast<pa_threaded_mainloop*>(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); } -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) { - pa_threaded_mainloop *loop = pdata; + auto loop = reinterpret_cast<pa_threaded_mainloop*>(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) { @@ -331,30 +403,29 @@ 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(); - pa_context_state_t state; - pa_context *context; - int err; + const char *name{"OpenAL Soft"}; + al_string binname{AL_STRING_INIT_STATIC()}; - GetProcBinary(NULL, &binname); + GetProcBinary(nullptr, &binname); if(!alstr_empty(binname)) name = alstr_get_cstr(binname); - 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"); alstr_reset(&binname); - return NULL; + return nullptr; } pa_context_set_state_callback(context, context_state_callback, loop); - if((err=pa_context_connect(context, NULL, pulse_ctx_flags, NULL)) >= 0) + 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)) @@ -367,14 +438,14 @@ static pa_context *connect_context(pa_threaded_mainloop *loop, ALboolean silent) pa_threaded_mainloop_wait(loop); } } - pa_context_set_state_callback(context, NULL, NULL); + 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 = NULL; + context = nullptr; } alstr_reset(&binname); @@ -382,162 +453,152 @@ static pa_context *connect_context(pa_threaded_mainloop *loop, ALboolean silent) } -static ALCboolean pulse_open(pa_threaded_mainloop **loop, pa_context **context, - void(*state_cb)(pa_context*,void*), void *ptr) +using MainloopContextPair = std::pair<pa_threaded_mainloop*,pa_context*>; +MainloopContextPair pulse_open(void(*state_cb)(pa_context*,void*), void *ptr) { - if(!(*loop = pa_threaded_mainloop_new())) + pa_threaded_mainloop *loop{pa_threaded_mainloop_new()}; + if(UNLIKELY(!loop)) { ERR("pa_threaded_mainloop_new() failed!\n"); - return ALC_FALSE; + return {nullptr, nullptr}; } - if(pa_threaded_mainloop_start(*loop) < 0) + if(UNLIKELY(pa_threaded_mainloop_start(loop) < 0)) { ERR("pa_threaded_mainloop_start() failed\n"); - goto error; + pa_threaded_mainloop_free(loop); + return {nullptr, nullptr}; } - pa_threaded_mainloop_lock(*loop); - - *context = connect_context(*loop, AL_FALSE); - if(!*context) + unique_palock palock{loop}; + pa_context *context{connect_context(loop, AL_FALSE)}; + if(UNLIKELY(!context)) { - pa_threaded_mainloop_unlock(*loop); - pa_threaded_mainloop_stop(*loop); - goto error; + 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); - - pa_threaded_mainloop_unlock(*loop); - return ALC_TRUE; - -error: - pa_threaded_mainloop_free(*loop); - *loop = NULL; - - return ALC_FALSE; + 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) +void pulse_close(pa_threaded_mainloop *loop, pa_context *context, pa_stream *stream) { - pa_threaded_mainloop_lock(loop); + { 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); + } - 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_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) +struct DevMap { + std::string name; + std::string device_name; -static vector_DevMap PlaybackDevices; -static vector_DevMap CaptureDevices; + template<typename StrT0, typename StrT1> + DevMap(StrT0&& name_, StrT1&& devname_) + : name{std::forward<StrT0>(name_)}, device_name{std::forward<StrT1>(devname_)} + { } +}; -static void clear_devlist(vector_DevMap *list) +bool checkName(const std::vector<DevMap> &list, const std::string &name) { -#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); + return std::find_if(list.cbegin(), list.cend(), + [&name](const DevMap &entry) -> bool + { return entry.name == name; } + ) != list.cend(); } +std::vector<DevMap> PlaybackDevices; +std::vector<DevMap> CaptureDevices; -typedef struct ALCpulsePlayback { - DERIVE_FROM_TYPE(ALCbackend); +} // namespace - al_string device_name; + +struct PulsePlayback final : public ALCbackend { + std::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) + pa_threaded_mainloop *loop{nullptr}; + + pa_stream *stream{nullptr}; + pa_context *context{nullptr}; + + std::atomic<ALenum> 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(ALCpulsePlayback, ALCbackend, self); - - self->loop = NULL; - AL_STRING_INIT(self->device_name); - ATOMIC_INIT(&self->killNow, AL_TRUE); + SET_VTABLE2(PulsePlayback, ALCbackend, self); } -static void ALCpulsePlayback_Destruct(ALCpulsePlayback *self) +static void PulsePlayback_Destruct(PulsePlayback *self) { if(self->loop) { pulse_close(self->loop, self->context, self->stream); - self->loop = NULL; - self->context = NULL; - self->stream = NULL; + self->loop = nullptr; + self->context = nullptr; + self->stream = nullptr; } - AL_STRING_DEINIT(self->device_name); ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); + self->~PulsePlayback(); } -static void ALCpulsePlayback_deviceCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata) +static void PulsePlayback_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; + auto loop = reinterpret_cast<pa_threaded_mainloop*>(pdata); if(eol) { @@ -545,86 +606,74 @@ static void ALCpulsePlayback_deviceCallback(pa_context *UNUSED(context), const p 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); + /* 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; - count = 0; - while(1) + /* 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)) { - 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++; + newname = info->description; + newname += " #"; + newname += std::to_string(++count); } + PlaybackDevices.emplace_back(std::move(newname), info->name); + DevMap &newentry = PlaybackDevices.back(); - TRACE("Got device \"%s\", \"%s\"\n", alstr_get_cstr(entry.name), alstr_get_cstr(entry.device_name)); - - VECTOR_PUSH_BACK(PlaybackDevices, entry); + TRACE("Got device \"%s\", \"%s\"\n", newentry.name.c_str(), newentry.device_name.c_str()); } -static void ALCpulsePlayback_probeDevices(void) +static void PulsePlayback_probeDevices(void) { - pa_threaded_mainloop *loop; + PlaybackDevices.clear(); - clear_devlist(&PlaybackDevices); - - if((loop=pa_threaded_mainloop_new()) && - pa_threaded_mainloop_start(loop) >= 0) + pa_threaded_mainloop *loop{pa_threaded_mainloop_new()}; + if(loop && pa_threaded_mainloop_start(loop) >= 0) { - pa_context *context; + unique_palock palock{loop}; - pa_threaded_mainloop_lock(loop); - context = connect_context(loop, AL_FALSE); + pa_context *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; + 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; - stream = ALCpulsePlayback_connectStream(NULL, loop, context, flags, - NULL, &spec, NULL); + pa_stream *stream{PulsePlayback_connectStream(nullptr, + loop, context, flags, nullptr, &spec, nullptr + )}; 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_operation *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 = NULL; + stream = nullptr; } - o = pa_context_get_sink_info_list(context, ALCpulsePlayback_deviceCallback, loop); - wait_for_operation(o, loop); + pa_operation *op{pa_context_get_sink_info_list(context, + PulsePlayback_deviceCallback, loop + )}; + wait_for_operation(op, loop); pa_context_disconnect(context); pa_context_unref(context); } - pa_threaded_mainloop_unlock(loop); + palock = unique_palock{}; pa_threaded_mainloop_stop(loop); } if(loop) @@ -632,9 +681,9 @@ static void ALCpulsePlayback_probeDevices(void) } -static void ALCpulsePlayback_bufferAttrCallback(pa_stream *stream, void *pdata) +static void PulsePlayback_bufferAttrCallback(pa_stream *stream, void *pdata) { - ALCpulsePlayback *self = pdata; + auto self = reinterpret_cast<PulsePlayback*>(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); @@ -645,9 +694,9 @@ static void ALCpulsePlayback_bufferAttrCallback(pa_stream *stream, void *pdata) */ } -static void ALCpulsePlayback_contextStateCallback(pa_context *context, void *pdata) +static void PulsePlayback_contextStateCallback(pa_context *context, void *pdata) { - ALCpulsePlayback *self = pdata; + auto self = reinterpret_cast<PulsePlayback*>(pdata); if(pa_context_get_state(context) == PA_CONTEXT_FAILED) { ERR("Received context failure!\n"); @@ -656,9 +705,9 @@ static void ALCpulsePlayback_contextStateCallback(pa_context *context, void *pda pa_threaded_mainloop_signal(self->loop, 0); } -static void ALCpulsePlayback_streamStateCallback(pa_stream *stream, void *pdata) +static void PulsePlayback_streamStateCallback(pa_stream *stream, void *pdata) { - ALCpulsePlayback *self = pdata; + auto self = reinterpret_cast<PulsePlayback*>(pdata); if(pa_stream_get_state(stream) == PA_STREAM_FAILED) { ERR("Received stream failure!\n"); @@ -667,18 +716,19 @@ static void ALCpulsePlayback_streamStateCallback(pa_stream *stream, void *pdata) pa_threaded_mainloop_signal(self->loop, 0); } -static void ALCpulsePlayback_streamWriteCallback(pa_stream* UNUSED(p), size_t UNUSED(nbytes), void *pdata) +static void PulsePlayback_streamWriteCallback(pa_stream* UNUSED(p), size_t UNUSED(nbytes), void *pdata) { - ALCpulsePlayback *self = pdata; + auto self = reinterpret_cast<PulsePlayback*>(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 void PulsePlayback_sinkInfoCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata) { - static const struct { - enum DevFmtChannels chans; + struct ChannelMap { + DevFmtChannels chans; pa_channel_map map; - } chanmaps[] = { + }; + static constexpr std::array<ChannelMap,7> chanmaps{{ { DevFmtX71, { 8, { PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, @@ -709,10 +759,8 @@ static void ALCpulsePlayback_sinkInfoCallback(pa_context *UNUSED(context), const 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; + }}; + auto self = reinterpret_cast<PulsePlayback*>(pdata); if(eol) { @@ -720,18 +768,19 @@ static void ALCpulsePlayback_sinkInfoCallback(pa_context *UNUSED(context), const return; } - for(i = 0;i < COUNTOF(chanmaps);i++) + 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(pa_channel_map_superset(&info->channel_map, &chanmaps[i].map)) - { - if(!(device->Flags&DEVICE_CHANNELS_REQUEST)) - device->FmtChans = chanmaps[i].chans; - break; - } + if(!(device->Flags&DEVICE_CHANNELS_REQUEST)) + device->FmtChans = chanmap->chans; } - if(i == COUNTOF(chanmaps)) + else { - char chanmap_str[PA_CHANNEL_MAP_SNPRINT_MAX] = ""; + 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); } @@ -743,10 +792,9 @@ static void ALCpulsePlayback_sinkInfoCallback(pa_context *UNUSED(context), const device->FmtChans == DevFmtStereo); } -static void ALCpulsePlayback_sinkNameCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata) +static void PulsePlayback_sinkNameCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata) { - ALCpulsePlayback *self = pdata; - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + auto self = reinterpret_cast<PulsePlayback*>(pdata); if(eol) { @@ -754,90 +802,84 @@ static void ALCpulsePlayback_sinkNameCallback(pa_context *UNUSED(context), const return; } + ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; alstr_copy_cstr(&device->DeviceName, info->description); } -static void ALCpulsePlayback_streamMovedCallback(pa_stream *stream, void *pdata) +static void PulsePlayback_streamMovedCallback(pa_stream *stream, void *pdata) { - ALCpulsePlayback *self = pdata; + auto self = reinterpret_cast<PulsePlayback*>(pdata); - alstr_copy_cstr(&self->device_name, pa_stream_get_device_name(stream)); + self->device_name = pa_stream_get_device_name(stream); - TRACE("Stream moved to %s\n", alstr_get_cstr(self->device_name)); + TRACE("Stream moved to %s\n", self->device_name.c_str()); } -static pa_stream *ALCpulsePlayback_connectStream(const char *device_name, +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) { - 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; + device_name = nullptr; } - stream = pa_stream_new_with_proplist(context, "Playback Stream", spec, chanmap, prop_filter); + 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 NULL; + return nullptr; } pa_stream_set_state_callback(stream, stream_state_callback, loop); - if(pa_stream_connect_playback(stream, device_name, attr, flags, NULL, NULL) < 0) + 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 NULL; + 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 NULL; + return nullptr; } pa_threaded_mainloop_wait(loop); } - pa_stream_set_state_callback(stream, NULL, NULL); + pa_stream_set_state_callback(stream, nullptr, nullptr); return stream; } -static int ALCpulsePlayback_mixerProc(void *ptr) +static int PulsePlayback_mixerProc(PulsePlayback *self) { - ALCpulsePlayback *self = ptr; - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - ALuint buffer_size; - size_t frame_size; - ssize_t len; + ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; SetRTPriority(); althrd_setname(althrd_current(), MIXER_THREAD_NAME); - pa_threaded_mainloop_lock(self->loop); - frame_size = pa_frame_size(&self->spec); + unique_palock palock{self->loop}; + size_t frame_size{pa_frame_size(&self->spec)}; - while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) && + while(!self->killNow.load(std::memory_order_acquire) && ATOMIC_LOAD(&device->Connected, almemory_order_acquire)) { - void *buf; - int ret; - - len = pa_stream_writable_size(self->stream); - if(len < 0) + ssize_t len{static_cast<ssize_t>(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); @@ -848,20 +890,20 @@ static int ALCpulsePlayback_mixerProc(void *ptr) * 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; + ALint buffer_size{static_cast<int32_t>(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 = mini(len - (ssize_t)self->attr.tlength, 0) + buffer_size; - if(len < (int32_t)self->attr.minreq) + 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 *o; - o = pa_stream_cork(self->stream, 0, NULL, NULL); - if(o) pa_operation_unref(o); + pa_operation *op{pa_stream_cork(self->stream, 0, nullptr, nullptr)}; + if(op) pa_operation_unref(op); } pa_threaded_mainloop_wait(self->loop); continue; @@ -870,122 +912,111 @@ static int ALCpulsePlayback_mixerProc(void *ptr) len -= len%self->attr.minreq; len -= len%frame_size; - buf = pa_xmalloc(len); - + void *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)); + 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)); } - pa_threaded_mainloop_unlock(self->loop); return 0; } -static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name) +static ALCenum PulsePlayback_open(PulsePlayback *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; + const char *pulse_name{nullptr}; + const char *dev_name{nullptr}; if(name) { - const DevMap *iter; + if(PlaybackDevices.empty()) + PulsePlayback_probeDevices(); - 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)) + 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 = alstr_get_cstr(iter->device_name); - dev_name = iter->name; + pulse_name = iter->device_name.c_str(); + dev_name = iter->name.c_str(); } - if(!pulse_open(&self->loop, &self->context, ALCpulsePlayback_contextStateCallback, self)) - return ALC_INVALID_VALUE; + std::tie(self->loop, self->context) = pulse_open(PulsePlayback_contextStateCallback, self); + if(!self->loop) return ALC_INVALID_VALUE; - pa_threaded_mainloop_lock(self->loop); + unique_palock palock{self->loop}; - flags = PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | - PA_STREAM_FIX_CHANNELS; - if(!GetConfigValueBool(NULL, "pulse", "allow-moves", 0)) + 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 = ALCpulsePlayback_connectStream(pulse_name, self->loop, self->context, - flags, NULL, &spec, NULL); + self->stream = PulsePlayback_connectStream(pulse_name, self->loop, self->context, + flags, nullptr, &spec, nullptr); if(!self->stream) { - pa_threaded_mainloop_unlock(self->loop); + palock = unique_palock{}; pulse_close(self->loop, self->context, self->stream); - self->loop = NULL; - self->context = NULL; + self->loop = nullptr; + self->context = nullptr; return ALC_INVALID_VALUE; } - pa_stream_set_moved_callback(self->stream, ALCpulsePlayback_streamMovedCallback, self); + pa_stream_set_moved_callback(self->stream, PulsePlayback_streamMovedCallback, self); - alstr_copy_cstr(&self->device_name, pa_stream_get_device_name(self->stream)); - if(alstr_empty(dev_name)) + self->device_name = pa_stream_get_device_name(self->stream); + if(!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); + 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; - alstr_copy(&device->DeviceName, dev_name); + ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; + alstr_copy_cstr(&device->DeviceName, dev_name); } - pa_threaded_mainloop_unlock(self->loop); - return ALC_NO_ERROR; } -static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self) +static ALCboolean PulsePlayback_reset(PulsePlayback *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); + unique_palock palock{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_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 = NULL; + self->stream = nullptr; } - 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); + 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); + 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; - 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) { @@ -1017,10 +1048,11 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self) if(pa_sample_spec_valid(&self->spec) == 0) { ERR("Invalid sample format\n"); - pa_threaded_mainloop_unlock(self->loop); return ALC_FALSE; } + const char *mapname{nullptr}; + pa_channel_map chanmap; switch(device->FmtChans) { case DevFmtMono: @@ -1051,7 +1083,6 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self) 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); @@ -1062,17 +1093,14 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self) 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->stream = PulsePlayback_connectStream(self->device_name.c_str(), 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); + 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) @@ -1088,15 +1116,15 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self) 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); + 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, ALCpulsePlayback_bufferAttrCallback, self); - ALCpulsePlayback_bufferAttrCallback(self->stream, 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 @@ -1111,7 +1139,7 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self) */ if(self->attr.prebuf != 0) { - ALuint len = self->attr.prebuf / pa_frame_size(&self->spec); + 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); @@ -1123,24 +1151,29 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self) } } - pa_threaded_mainloop_unlock(self->loop); return ALC_TRUE; } -static ALCboolean ALCpulsePlayback_start(ALCpulsePlayback *self) +static ALCboolean PulsePlayback_start(PulsePlayback *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; + try { + self->killNow.store(AL_FALSE, std::memory_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 ALCpulsePlayback_stop(ALCpulsePlayback *self) +static void PulsePlayback_stop(PulsePlayback *self) { - pa_operation *o; - int res; - - if(!self->stream || ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel)) + self->killNow.store(AL_TRUE, std::memory_order_release); + if(!self->stream || !self->thread.joinable()) return; /* Signal the main loop in case PulseAudio isn't sending us audio requests @@ -1148,30 +1181,29 @@ static void ALCpulsePlayback_stop(ALCpulsePlayback *self) * 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); + unique_palock palock{self->loop}; + palock.unlock(); - pa_threaded_mainloop_lock(self->loop); + pa_threaded_mainloop_signal(self->loop, 0); + self->thread.join(); - o = pa_stream_cork(self->stream, 1, stream_success_callback, self->loop); - wait_for_operation(o, self->loop); + palock.lock(); - pa_threaded_mainloop_unlock(self->loop); + pa_operation *op{pa_stream_cork(self->stream, 1, stream_success_callback, self->loop)}; + wait_for_operation(op, self->loop); } -static ClockLatency ALCpulsePlayback_getClockLatency(ALCpulsePlayback *self) +static ClockLatency PulsePlayback_getClockLatency(PulsePlayback *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); + { 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)) { @@ -1192,94 +1224,87 @@ static ClockLatency ALCpulsePlayback_getClockLatency(ALCpulsePlayback *self) } -static void ALCpulsePlayback_lock(ALCpulsePlayback *self) +static void PulsePlayback_lock(PulsePlayback *self) { pa_threaded_mainloop_lock(self->loop); } -static void ALCpulsePlayback_unlock(ALCpulsePlayback *self) +static void PulsePlayback_unlock(PulsePlayback *self) { pa_threaded_mainloop_unlock(self->loop); } -typedef struct ALCpulseCapture { - DERIVE_FROM_TYPE(ALCbackend); - - al_string device_name; +struct PulseCapture final : public ALCbackend { + std::string device_name; - const void *cap_store; - size_t cap_len; - size_t cap_remain; + const void *cap_store{nullptr}; + size_t cap_len{0}; + size_t cap_remain{0}; - ALCuint last_readable; + ALCuint last_readable{0}; 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) + 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(ALCpulseCapture, ALCbackend, self); - - self->loop = NULL; - AL_STRING_INIT(self->device_name); + SET_VTABLE2(PulseCapture, ALCbackend, self); } -static void ALCpulseCapture_Destruct(ALCpulseCapture *self) +static void PulseCapture_Destruct(PulseCapture *self) { if(self->loop) { pulse_close(self->loop, self->context, self->stream); - self->loop = NULL; - self->context = NULL; - self->stream = NULL; + self->loop = nullptr; + self->context = nullptr; + self->stream = nullptr; } - AL_STRING_DEINIT(self->device_name); ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); + self->~PulseCapture(); } -static void ALCpulseCapture_deviceCallback(pa_context *UNUSED(context), const pa_source_info *info, int eol, void *pdata) +static void PulseCapture_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; + auto loop = reinterpret_cast<pa_threaded_mainloop*>(pdata); if(eol) { @@ -1287,86 +1312,74 @@ static void ALCpulseCapture_deviceCallback(pa_context *UNUSED(context), const pa 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); + /* 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; - count = 0; - while(1) + /* 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)) { - 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++; + 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", alstr_get_cstr(entry.name), alstr_get_cstr(entry.device_name)); - - VECTOR_PUSH_BACK(CaptureDevices, entry); + TRACE("Got device \"%s\", \"%s\"\n", newentry.name.c_str(), newentry.device_name.c_str()); } -static void ALCpulseCapture_probeDevices(void) +static void PulseCapture_probeDevices(void) { - pa_threaded_mainloop *loop; + CaptureDevices.clear(); - clear_devlist(&CaptureDevices); - - if((loop=pa_threaded_mainloop_new()) && - pa_threaded_mainloop_start(loop) >= 0) + pa_threaded_mainloop *loop{pa_threaded_mainloop_new()}; + if(loop && pa_threaded_mainloop_start(loop) >= 0) { - pa_context *context; + unique_palock palock{loop}; - pa_threaded_mainloop_lock(loop); - context = connect_context(loop, AL_FALSE); + pa_context *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; + 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; - stream = ALCpulseCapture_connectStream(NULL, loop, context, flags, - NULL, &spec, NULL); + pa_stream *stream{PulseCapture_connectStream(nullptr, + loop, context, flags, nullptr, &spec, nullptr + )}; 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_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 = NULL; + stream = nullptr; } - o = pa_context_get_source_info_list(context, ALCpulseCapture_deviceCallback, loop); - wait_for_operation(o, loop); + 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); } - pa_threaded_mainloop_unlock(loop); + palock.unlock(); pa_threaded_mainloop_stop(loop); } if(loop) @@ -1374,9 +1387,9 @@ static void ALCpulseCapture_probeDevices(void) } -static void ALCpulseCapture_contextStateCallback(pa_context *context, void *pdata) +static void PulseCapture_contextStateCallback(pa_context *context, void *pdata) { - ALCpulseCapture *self = pdata; + auto self = reinterpret_cast<PulseCapture*>(pdata); if(pa_context_get_state(context) == PA_CONTEXT_FAILED) { ERR("Received context failure!\n"); @@ -1385,9 +1398,9 @@ static void ALCpulseCapture_contextStateCallback(pa_context *context, void *pdat pa_threaded_mainloop_signal(self->loop, 0); } -static void ALCpulseCapture_streamStateCallback(pa_stream *stream, void *pdata) +static void PulseCapture_streamStateCallback(pa_stream *stream, void *pdata) { - ALCpulseCapture *self = pdata; + auto self = reinterpret_cast<PulseCapture*>(pdata); if(pa_stream_get_state(stream) == PA_STREAM_FAILED) { ERR("Received stream failure!\n"); @@ -1397,10 +1410,9 @@ static void ALCpulseCapture_streamStateCallback(pa_stream *stream, void *pdata) } -static void ALCpulseCapture_sourceNameCallback(pa_context *UNUSED(context), const pa_source_info *info, int eol, void *pdata) +static void PulseCapture_sourceNameCallback(pa_context *UNUSED(context), const pa_source_info *info, int eol, void *pdata) { - ALCpulseCapture *self = pdata; - ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + auto self = reinterpret_cast<PulseCapture*>(pdata); if(eol) { @@ -1408,33 +1420,33 @@ static void ALCpulseCapture_sourceNameCallback(pa_context *UNUSED(context), cons return; } + ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; alstr_copy_cstr(&device->DeviceName, info->description); } -static void ALCpulseCapture_streamMovedCallback(pa_stream *stream, void *pdata) +static void PulseCapture_streamMovedCallback(pa_stream *stream, void *pdata) { - ALCpulseCapture *self = pdata; + auto self = reinterpret_cast<PulseCapture*>(pdata); - alstr_copy_cstr(&self->device_name, pa_stream_get_device_name(stream)); + self->device_name = pa_stream_get_device_name(stream); - TRACE("Stream moved to %s\n", alstr_get_cstr(self->device_name)); + TRACE("Stream moved to %s\n", self->device_name.c_str()); } -static pa_stream *ALCpulseCapture_connectStream(const char *device_name, +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) { - pa_stream_state_t state; - pa_stream *stream; - - stream = pa_stream_new_with_proplist(context, "Capture Stream", spec, chanmap, prop_filter); + 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 NULL; + return nullptr; } pa_stream_set_state_callback(stream, stream_state_callback, loop); @@ -1443,55 +1455,51 @@ static pa_stream *ALCpulseCapture_connectStream(const char *device_name, { ERR("Stream did not connect: %s\n", pa_strerror(pa_context_errno(context))); pa_stream_unref(stream); - return NULL; + 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 NULL; + return nullptr; } pa_threaded_mainloop_wait(loop); } - pa_stream_set_state_callback(stream, NULL, NULL); + pa_stream_set_state_callback(stream, nullptr, nullptr); return stream; } -static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name) +static ALCenum PulseCapture_open(PulseCapture *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; + ALCdevice *device{STATIC_CAST(ALCbackend,self)->mDevice}; + const char *pulse_name{nullptr}; if(name) { - const DevMap *iter; - - if(VECTOR_SIZE(CaptureDevices) == 0) - ALCpulseCapture_probeDevices(); + if(CaptureDevices.empty()) + PulseCapture_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)) + 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 = alstr_get_cstr(iter->device_name); - alstr_copy(&device->DeviceName, iter->name); + pulse_name = iter->device_name.c_str(); + alstr_copy_cstr(&device->DeviceName, iter->name.c_str()); } - if(!pulse_open(&self->loop, &self->context, ALCpulseCapture_contextStateCallback, self)) - return ALC_INVALID_VALUE; + std::tie(self->loop, self->context) = pulse_open(PulseCapture_contextStateCallback, self); + if(!self->loop) return ALC_INVALID_VALUE; - pa_threaded_mainloop_lock(self->loop); + unique_palock palock{self->loop}; switch(device->FmtType) { @@ -1511,10 +1519,11 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name) case DevFmtUShort: case DevFmtUInt: ERR("%s capture samples not supported\n", DevFmtTypeString(device->FmtType)); - pa_threaded_mainloop_unlock(self->loop); - goto fail; + return ALC_INVALID_VALUE; } + const char *mapname{nullptr}; + pa_channel_map chanmap; switch(device->FmtChans) { case DevFmtMono: @@ -1540,14 +1549,12 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name) break; case DevFmtAmbi3D: ERR("%s capture samples not supported\n", DevFmtChannelsString(device->FmtChans)); - pa_threaded_mainloop_unlock(self->loop); - goto fail; + return ALC_INVALID_VALUE; } 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; + return ALC_INVALID_VALUE; } self->spec.rate = device->Frequency; @@ -1556,18 +1563,16 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name) if(pa_sample_spec_valid(&self->spec) == 0) { ERR("Invalid sample format\n"); - pa_threaded_mainloop_unlock(self->loop); - goto fail; + 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); - pa_threaded_mainloop_unlock(self->loop); - goto fail; + return ALC_INVALID_VALUE; } - samples = device->UpdateSize * device->NumUpdates; + ALuint samples{device->UpdateSize * device->NumUpdates}; samples = maxu(samples, 100 * device->Frequency / 1000); self->attr.minreq = -1; @@ -1577,85 +1582,66 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name) 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)) + 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 = ALCpulseCapture_connectStream(pulse_name, + self->stream = PulseCapture_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); + return ALC_INVALID_VALUE; + pa_stream_set_moved_callback(self->stream, PulseCapture_streamMovedCallback, self); + pa_stream_set_state_callback(self->stream, PulseCapture_streamStateCallback, self); - alstr_copy_cstr(&self->device_name, pa_stream_get_device_name(self->stream)); + 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_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); } - 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) +static ALCboolean PulseCapture_start(PulseCapture *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); + palock_guard _{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; } -static void ALCpulseCapture_stop(ALCpulseCapture *self) +static void PulseCapture_stop(PulseCapture *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); + 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 ALCpulseCapture_captureSamples(ALCpulseCapture *self, ALCvoid *buffer, ALCuint samples) +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<ALCuint>(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); + unique_palock palock{self->loop}; while(todo > 0) { - size_t rem = todo; + size_t rem{todo}; if(self->cap_len == 0) { - pa_stream_state_t state; - - 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); - break; + return ALC_INVALID_DEVICE; } if(pa_stream_peek(self->stream, &self->cap_store, &self->cap_len) < 0) { @@ -1663,7 +1649,7 @@ static ALCenum ALCpulseCapture_captureSamples(ALCpulseCapture *self, ALCvoid *bu pa_strerror(pa_context_errno(self->context))); aluHandleDisconnect(device, "Failed retrieving capture samples: %s", pa_strerror(pa_context_errno(self->context))); - break; + return ALC_INVALID_DEVICE; } self->cap_remain = self->cap_len; } @@ -1683,31 +1669,29 @@ static ALCenum ALCpulseCapture_captureSamples(ALCpulseCapture *self, ALCvoid *bu self->cap_len = 0; } } - pa_threaded_mainloop_unlock(self->loop); + palock.unlock(); if(todo > 0) memset(buffer, ((device->FmtType==DevFmtUByte) ? 0x80 : 0), todo); return ALC_NO_ERROR; } -static ALCuint ALCpulseCapture_availableSamples(ALCpulseCapture *self) +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)) { - ssize_t got; - pa_threaded_mainloop_lock(self->loop); - got = pa_stream_readable_size(self->stream); - if(got < 0) + palock_guard _{self->loop}; + size_t got{pa_stream_readable_size(self->stream)}; + if(static_cast<ssize_t>(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; - pa_threaded_mainloop_unlock(self->loop); } if(self->last_readable < readable) @@ -1716,16 +1700,16 @@ static ALCuint ALCpulseCapture_availableSamples(ALCpulseCapture *self) } -static ClockLatency ALCpulseCapture_getClockLatency(ALCpulseCapture *self) +static ClockLatency PulseCapture_getClockLatency(PulseCapture *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); + { 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)) { @@ -1741,52 +1725,50 @@ static ClockLatency ALCpulseCapture_getClockLatency(ALCpulseCapture *self) } -static void ALCpulseCapture_lock(ALCpulseCapture *self) +static void PulseCapture_lock(PulseCapture *self) { pa_threaded_mainloop_lock(self->loop); } -static void ALCpulseCapture_unlock(ALCpulseCapture *self) +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); +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* UNUSED(self)) +PulseBackendFactory::PulseBackendFactory() noexcept + : ALCbackendFactory{ALCPULSEBACKENDFACTORY_INITIALIZER} { - ALCboolean ret = ALC_FALSE; +} + - VECTOR_INIT(PlaybackDevices); - VECTOR_INIT(CaptureDevices); +static ALCboolean PulseBackendFactory_init(PulseBackendFactory* UNUSED(self)) +{ + ALCboolean ret{ALC_FALSE}; if(pulse_load()) { - pa_threaded_mainloop *loop; - - pulse_ctx_flags = 0; - if(!GetConfigValueBool(NULL, "pulse", "spawn-server", 1)) + pulse_ctx_flags = PA_CONTEXT_NOFLAGS; + if(!GetConfigValueBool(nullptr, "pulse", "spawn-server", 1)) pulse_ctx_flags |= PA_CONTEXT_NOAUTOSPAWN; - if((loop=pa_threaded_mainloop_new()) && - pa_threaded_mainloop_start(loop) >= 0) + pa_threaded_mainloop *loop{pa_threaded_mainloop_new()}; + if(loop && pa_threaded_mainloop_start(loop) >= 0) { - pa_context *context; - - pa_threaded_mainloop_lock(loop); - context = connect_context(loop, AL_TRUE); + unique_palock palock{loop}; + pa_context *context{connect_context(loop, AL_TRUE)}; if(context) { ret = ALC_TRUE; @@ -1796,13 +1778,13 @@ static ALCboolean ALCpulseBackendFactory_init(ALCpulseBackendFactory* UNUSED(sel * 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_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); } - pa_threaded_mainloop_unlock(loop); + palock.unlock(); pa_threaded_mainloop_stop(loop); } if(loop) @@ -1812,68 +1794,68 @@ static ALCboolean ALCpulseBackendFactory_init(ALCpulseBackendFactory* UNUSED(sel return ret; } -static void ALCpulseBackendFactory_deinit(ALCpulseBackendFactory* UNUSED(self)) +static void PulseBackendFactory_deinit(PulseBackendFactory* UNUSED(self)) { - clear_devlist(&PlaybackDevices); - VECTOR_DEINIT(PlaybackDevices); - - clear_devlist(&CaptureDevices); - VECTOR_DEINIT(CaptureDevices); + PlaybackDevices.clear(); + CaptureDevices.clear(); if(prop_filter) pa_proplist_free(prop_filter); - prop_filter = NULL; + prop_filter = nullptr; /* 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 + { + 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(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); + PulsePlayback_probeDevices(); + std::for_each(PlaybackDevices.cbegin(), PlaybackDevices.cend(), add_device); break; case CAPTURE_DEVICE_PROBE: - ALCpulseCapture_probeDevices(); - VECTOR_FOR_EACH(const DevMap, CaptureDevices, APPEND_OUTNAME); + PulseCapture_probeDevices(); + std::for_each(CaptureDevices.cbegin(), CaptureDevices.cend(), add_device); break; -#undef APPEND_OUTNAME } } -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) { - ALCpulsePlayback *backend; - NEW_OBJ(backend, ALCpulsePlayback)(device); - if(!backend) return NULL; + PulsePlayback *backend; + NEW_OBJ(backend, PulsePlayback)(device); + if(!backend) return nullptr; return STATIC_CAST(ALCbackend, backend); } if(type == ALCbackend_Capture) { - ALCpulseCapture *backend; - NEW_OBJ(backend, ALCpulseCapture)(device); - if(!backend) return NULL; + PulseCapture *backend; + NEW_OBJ(backend, PulseCapture)(device); + if(!backend) return nullptr; return STATIC_CAST(ALCbackend, backend); } - return NULL; + return nullptr; } @@ -1881,40 +1863,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 NULL; + 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.c b/Alc/backends/wasapi.cpp index 971a1f72..f2adf328 100644 --- a/Alc/backends/wasapi.c +++ b/Alc/backends/wasapi.cpp @@ -20,7 +20,6 @@ #include "config.h" -#define COBJMACROS #include <stdlib.h> #include <stdio.h> #include <memory.h> @@ -39,10 +38,15 @@ #include <ksmedia.h> #endif +#include <atomic> +#include <thread> +#include <vector> +#include <string> +#include <algorithm> + #include "alMain.h" #include "alu.h" #include "ringbuffer.h" -#include "threads.h" #include "compat.h" #include "alstring.h" #include "converter.h" @@ -50,13 +54,24 @@ #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 + * 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) @@ -72,43 +87,63 @@ 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) +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) +struct PropVariant { + PROPVARIANT mProp; + +public: + PropVariant() { PropVariantInit(&mProp); } + ~PropVariant() { clear(); } + + void clear() { PropVariantClear(&mProp); } -static void clear_devlist(vector_DevMap *list) + 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<typename T0, typename T1, typename T2> + DevMap(T0&& name_, T1&& guid_, T2&& devid_) + : name{std::forward<T0>(name_)} + , endpoint_guid{std::forward<T1>(guid_)} + , devid{std::forward<T2>(devid_)} + { } +}; + +bool checkName(const std::vector<DevMap> &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 = NULL; \ -} 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<DevMap> PlaybackDevices; +std::vector<DevMap> CaptureDevices; -static HANDLE ThreadHdl; -static DWORD ThreadID; +HANDLE ThreadHdl; +DWORD ThreadID; -typedef struct { +struct ThreadRequest { HANDLE FinishedEvt; HRESULT result; -} ThreadRequest; +}; + #define WM_USER_First (WM_USER+0) #define WM_USER_OpenDevice (WM_USER+0) @@ -128,13 +163,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; @@ -143,252 +178,183 @@ static HRESULT WaitForResponse(ThreadRequest *req) } -static void get_device_name_and_guid(IMMDevice *device, al_string *name, al_string *guid) +using NameGUIDPair = std::pair<std::string,std::string>; +NameGUIDPair get_device_name_and_guid(IMMDevice *device) { - IPropertyStore *ps; - PROPVARIANT pvname; - PROPVARIANT pvguid; - HRESULT hr; + std::string name{DEVNAME_HEAD}; + std::string guid; - alstr_copy_cstr(name, DEVNAME_HEAD); - - hr = IMMDevice_OpenPropertyStore(device, 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!=NULL)alstr_copy_cstr(guid, "Unknown Device GUID"); - return; + return { name+"Unknown Device Name", "Unknown Device GUID" }; } - PropVariantInit(&pvname); - - hr = IPropertyStore_GetValue(ps, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pvname); + PropVariant pvprop; + hr = ps->GetValue(reinterpret_cast<const PROPERTYKEY&>(DEVPKEY_Device_FriendlyName), pvprop.get()); 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); + else if(pvprop->vt == VT_LPWSTR) + name += wstr_to_utf8(pvprop->pwszVal); else { - WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvname.vt); - alstr_append_cstr(name, "Unknown Device Name"); + WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvprop->vt); + 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); + pvprop.clear(); + hr = ps->GetValue(reinterpret_cast<const PROPERTYKEY&>(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(); - IPropertyStore_Release(ps); + return {name, guid}; } -static void get_device_formfactor(IMMDevice *device, EndpointFormFactor *formfactor) +void get_device_formfactor(IMMDevice *device, EndpointFormFactor *formfactor) { IPropertyStore *ps; - PROPVARIANT pvform; - HRESULT hr; - - hr = IMMDevice_OpenPropertyStore(device, STGM_READ, &ps); + HRESULT hr = device->OpenPropertyStore(STGM_READ, &ps); if(FAILED(hr)) { WARN("OpenPropertyStore failed: 0x%08lx\n", hr); return; } - PropVariantInit(&pvform); - - hr = IPropertyStore_GetValue(ps, &PKEY_AudioEndpoint_FormFactor, &pvform); + PropVariant pvform; + hr = ps->GetValue(reinterpret_cast<const PROPERTYKEY&>(PKEY_AudioEndpoint_FormFactor), pvform.get()); 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) + else if(pvform->vt == VT_UI4) + *formfactor = static_cast<EndpointFormFactor>(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); - IPropertyStore_Release(ps); + ps->Release(); } -static void add_device(IMMDevice *device, const WCHAR *devid, vector_DevMap *list) +void add_device(IMMDevice *device, const WCHAR *devid, std::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); + std::string basename, guidstr; + std::tie(basename, guidstr) = get_device_name_and_guid(device); - entry.devid = strdupW(devid); - get_device_name_and_guid(device, &tmpname, &entry.endpoint_guid); - - 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 *get_device_id(IMMDevice *device) { WCHAR *devid; - HRESULT hr; - hr = IMMDevice_GetId(device, &devid); + HRESULT hr = device->GetId(&devid); if(FAILED(hr)) { ERR("Failed to get device id: %lx\n", hr); - return NULL; + return nullptr; } return devid; } -static HRESULT probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, vector_DevMap *list) +HRESULT probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, std::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); + 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; - hr = IMMDeviceCollection_GetCount(coll, &count); + 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 = IMMDeviceEnumerator_GetDefaultAudioEndpoint(devenum, flowdir, - eMultimedia, &defdev); + hr = devenum->GetDefaultAudioEndpoint(flowdir, eMultimedia, &defdev); } - if(SUCCEEDED(hr) && defdev != NULL) + if(SUCCEEDED(hr) && defdev != nullptr) { defdevid = get_device_id(defdev); if(defdevid) add_device(defdev, defdevid, list); } - for(i = 0;i < count;++i) + for(UINT i{0};i < count;++i) { IMMDevice *device; - WCHAR *devid; - - hr = IMMDeviceCollection_Item(coll, i, &device); + 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) add_device(device, devid, list); CoTaskMemFree(devid); } - IMMDevice_Release(device); + device->Release(); } - if(defdev) IMMDevice_Release(defdev); + if(defdev) defdev->Release(); if(defdevid) CoTaskMemFree(defdevid); - IMMDeviceCollection_Release(coll); + coll->Release(); return S_OK; } /* Proxy interface used by the message handler. */ -struct ALCwasapiProxyVtable; - -typedef struct ALCwasapiProxy { - const struct ALCwasapiProxyVtable *vtbl; -} ALCwasapiProxy; +struct WasapiProxy { + virtual HRESULT openProxy() = 0; + virtual void closeProxy() = 0; -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) +DWORD CALLBACK WasapiProxy_messageHandler(void *ptr) { - ThreadRequest *req = ptr; - IMMDeviceEnumerator *Enumerator; - ALuint deviceCount = 0; - ALCwasapiProxy *proxy; - HRESULT hr, cohr; - MSG msg; + auto req = reinterpret_cast<ThreadRequest*>(ptr); TRACE("Starting message thread\n"); - cohr = CoInitializeEx(NULL, COINIT_MULTITHREADED); + HRESULT cohr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); if(FAILED(cohr)) { WARN("Failed to initialize COM: 0x%08lx\n", cohr); @@ -396,7 +362,8 @@ static DWORD CALLBACK ALCwasapiProxy_messageHandler(void *ptr) return 0; } - hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, 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); @@ -404,9 +371,9 @@ static DWORD CALLBACK ALCwasapiProxy_messageHandler(void *ptr) ReturnMsgResponse(req, hr); return 0; } - Enumerator = ptr; - IMMDeviceEnumerator_Release(Enumerator); - Enumerator = NULL; + auto Enumerator = reinterpret_cast<IMMDeviceEnumerator*>(ptr); + Enumerator->Release(); + Enumerator = nullptr; CoUninitialize(); @@ -414,30 +381,34 @@ static DWORD CALLBACK ALCwasapiProxy_messageHandler(void *ptr) * returning success, otherwise PostThreadMessage may fail if it gets * called before GetMessage. */ - PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); + 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"); - while(GetMessage(&msg, NULL, WM_USER_First, WM_USER_Last)) + ALuint deviceCount{0}; + 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 ); + + WasapiProxy *proxy{nullptr}; switch(msg.message) { case WM_USER_OpenDevice: - req = (ThreadRequest*)msg.wParam; - proxy = (ALCwasapiProxy*)msg.lParam; + req = reinterpret_cast<ThreadRequest*>(msg.wParam); + proxy = reinterpret_cast<WasapiProxy*>(msg.lParam); hr = cohr = S_OK; if(++deviceCount == 1) - hr = cohr = CoInitializeEx(NULL, COINIT_MULTITHREADED); + hr = cohr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); if(SUCCEEDED(hr)) - hr = V0(proxy,openProxy)(); + hr = proxy->openProxy(); if(FAILED(hr)) { if(--deviceCount == 0 && SUCCEEDED(cohr)) @@ -448,34 +419,34 @@ static DWORD CALLBACK ALCwasapiProxy_messageHandler(void *ptr) continue; case WM_USER_ResetDevice: - req = (ThreadRequest*)msg.wParam; - proxy = (ALCwasapiProxy*)msg.lParam; + req = reinterpret_cast<ThreadRequest*>(msg.wParam); + proxy = reinterpret_cast<WasapiProxy*>(msg.lParam); - hr = V0(proxy,resetProxy)(); + hr = proxy->resetProxy(); ReturnMsgResponse(req, hr); continue; case WM_USER_StartDevice: - req = (ThreadRequest*)msg.wParam; - proxy = (ALCwasapiProxy*)msg.lParam; + req = reinterpret_cast<ThreadRequest*>(msg.wParam); + proxy = reinterpret_cast<WasapiProxy*>(msg.lParam); - hr = V0(proxy,startProxy)(); + hr = proxy->startProxy(); ReturnMsgResponse(req, hr); continue; case WM_USER_StopDevice: - req = (ThreadRequest*)msg.wParam; - proxy = (ALCwasapiProxy*)msg.lParam; + req = reinterpret_cast<ThreadRequest*>(msg.wParam); + proxy = reinterpret_cast<WasapiProxy*>(msg.lParam); - V0(proxy,stopProxy)(); + proxy->stopProxy(); ReturnMsgResponse(req, S_OK); continue; case WM_USER_CloseDevice: - req = (ThreadRequest*)msg.wParam; - proxy = (ALCwasapiProxy*)msg.lParam; + req = reinterpret_cast<ThreadRequest*>(msg.wParam); + proxy = reinterpret_cast<WasapiProxy*>(msg.lParam); - V0(proxy,closeProxy)(); + proxy->closeProxy(); if(--deviceCount == 0) CoUninitialize(); @@ -483,24 +454,24 @@ static DWORD CALLBACK ALCwasapiProxy_messageHandler(void *ptr) continue; case WM_USER_Enumerate: - req = (ThreadRequest*)msg.wParam; + req = reinterpret_cast<ThreadRequest*>(msg.wParam); hr = cohr = S_OK; if(++deviceCount == 1) - hr = cohr = CoInitializeEx(NULL, COINIT_MULTITHREADED); + hr = cohr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); if(SUCCEEDED(hr)) - hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr); + hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, &ptr); if(SUCCEEDED(hr)) { - Enumerator = ptr; + Enumerator = reinterpret_cast<IMMDeviceEnumerator*>(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); - IMMDeviceEnumerator_Release(Enumerator); - Enumerator = NULL; + Enumerator->Release(); + Enumerator = nullptr; } if(--deviceCount == 0 && SUCCEEDED(cohr)) @@ -519,39 +490,40 @@ static DWORD CALLBACK ALCwasapiProxy_messageHandler(void *ptr) return 0; } +} // namespace -typedef struct ALCwasapiPlayback { - DERIVE_FROM_TYPE(ALCbackend); - DERIVE_FROM_TYPE(ALCwasapiProxy); - WCHAR *devid; +struct ALCwasapiPlayback final : public ALCbackend, WasapiProxy { + HRESULT openProxy() override; + void closeProxy() override; + + HRESULT resetProxy() override; + HRESULT startProxy() override; + void stopProxy() override; - IMMDevice *mmdev; - IAudioClient *client; - IAudioRenderClient *render; - HANDLE NotifyEvent; + std::wstring mDevId; - HANDLE MsgEvent; + IMMDevice *mMMDev{nullptr}; + IAudioClient *mClient{nullptr}; + IAudioRenderClient *mRender{nullptr}; + HANDLE mNotifyEvent{nullptr}; - ATOMIC(UINT32) Padding; + HANDLE mMsgEvent{nullptr}; - ATOMIC(int) killNow; - althrd_t thread; -} ALCwasapiPlayback; + std::atomic<UINT32> mPadding{0u}; + + std::atomic<ALenum> mKillNow{AL_TRUE}; + std::thread mThread; +}; -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); 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); @@ -559,78 +531,51 @@ 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) { + 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 = 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) + 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<WasapiProxy*>(self); + if(PostThreadMessage(ThreadID, WM_USER_CloseDevice, (WPARAM)&req, (LPARAM)proxy)) (void)WaitForResponse(&req); - CloseHandle(self->MsgEvent); - self->MsgEvent = NULL; + CloseHandle(self->mMsgEvent); + self->mMsgEvent = nullptr; } - 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; + if(self->mNotifyEvent != nullptr) + CloseHandle(self->mNotifyEvent); + self->mNotifyEvent = nullptr; + if(self->mMsgEvent != nullptr) + CloseHandle(self->mMsgEvent); + self->mMsgEvent = 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) { - 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); + ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; + IAudioClient *client{self->mClient}; + IAudioRenderClient *render{self->mRender}; + + HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); if(FAILED(hr)) { - ERR("CoInitializeEx(NULL, COINIT_MULTITHREADED) failed: 0x%08lx\n", 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)(); @@ -640,11 +585,12 @@ 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->mKillNow.load(std::memory_order_relaxed)) { - hr = IAudioClient_GetCurrentPadding(self->client, &written); + UINT32 written; + hr = client->GetCurrentPadding(&written); if(FAILED(hr)) { ERR("Failed to get padding: 0x%08lx\n", hr); @@ -653,27 +599,28 @@ FORCE_ALIGN static int ALCwasapiPlayback_mixerProc(void *arg) V0(device->Backend,unlock)(); break; } - ATOMIC_STORE(&self->Padding, written, almemory_order_relaxed); + self->mPadding.store(written, std::memory_order_relaxed); - len = buffer_len - written; + 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; } len -= len%update_size; - hr = IAudioRenderClient_GetBuffer(self->render, len, &buffer); + 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->mPadding.store(written + len, std::memory_order_relaxed); ALCwasapiPlayback_unlock(self); - hr = IAudioRenderClient_ReleaseBuffer(self->render, len, 0); + hr = render->ReleaseBuffer(len, 0); } if(FAILED(hr)) { @@ -684,7 +631,7 @@ FORCE_ALIGN static int ALCwasapiPlayback_mixerProc(void *arg) break; } } - ATOMIC_STORE(&self->Padding, 0, almemory_order_release); + self->mPadding.store(0u, std::memory_order_release); CoUninitialize(); return 0; @@ -734,9 +681,9 @@ static ALCenum ALCwasapiPlayback_open(ALCwasapiPlayback *self, const ALCchar *de { 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) + 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; @@ -746,40 +693,38 @@ 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 }; + ThreadRequest req = { self->mMsgEvent, 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)) + 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, NULL, 0)) > 0) + if((len=MultiByteToWideChar(CP_UTF8, 0, deviceName, -1, nullptr, 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); + std::vector<WCHAR> 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(); } + ); } } - 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->mDevId = iter->devid; + alstr_copy_range(&device->DeviceName, &*iter->name.cbegin(), &*iter->name.cend()); hr = S_OK; } } @@ -787,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<WasapiProxy*>(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()); @@ -798,15 +744,14 @@ static ALCenum ALCwasapiPlayback_open(ALCwasapiPlayback *self, const ALCchar *de if(FAILED(hr)) { - if(self->NotifyEvent != NULL) - CloseHandle(self->NotifyEvent); - self->NotifyEvent = NULL; - if(self->MsgEvent != NULL) - CloseHandle(self->MsgEvent); - self->MsgEvent = NULL; + if(self->mNotifyEvent != nullptr) + CloseHandle(self->mNotifyEvent); + self->mNotifyEvent = nullptr; + if(self->mMsgEvent != nullptr) + CloseHandle(self->mMsgEvent); + self->mMsgEvent = nullptr; - free(self->devid); - self->devid = NULL; + self->mDevId.clear(); ERR("Device init failed: 0x%08lx\n", hr); return ALC_INVALID_VALUE; @@ -815,106 +760,104 @@ 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, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr); + void *ptr; + HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, &ptr); if(SUCCEEDED(hr)) { - IMMDeviceEnumerator *Enumerator = ptr; - if(!self->devid) - hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(Enumerator, eRender, eMultimedia, &self->mmdev); + auto Enumerator = reinterpret_cast<IMMDeviceEnumerator*>(ptr); + if(mDevId.empty()) + hr = Enumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, &mMMDev); else - hr = IMMDeviceEnumerator_GetDevice(Enumerator, self->devid, &self->mmdev); - IMMDeviceEnumerator_Release(Enumerator); - Enumerator = NULL; + hr = Enumerator->GetDevice(mDevId.c_str(), &mMMDev); + Enumerator->Release(); } if(SUCCEEDED(hr)) - hr = IMMDevice_Activate(self->mmdev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, &ptr); + hr = mMMDev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, &ptr); if(SUCCEEDED(hr)) { - self->client = ptr; + mClient = reinterpret_cast<IAudioClient*>(ptr); if(alstr_empty(device->DeviceName)) - get_device_name_and_guid(self->mmdev, &device->DeviceName, NULL); + { + std::string devname; + 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) - IMMDevice_Release(self->mmdev); - self->mmdev = NULL; + if(mMMDev) + mMMDev->Release(); + mMMDev = nullptr; } return hr; } - -static void ALCwasapiPlayback_closeProxy(ALCwasapiPlayback *self) +void ALCwasapiPlayback::closeProxy() { - if(self->client) - IAudioClient_Release(self->client); - self->client = NULL; + if(mClient) + mClient->Release(); + mClient = nullptr; - if(self->mmdev) - IMMDevice_Release(self->mmdev); - self->mmdev = NULL; + if(mMMDev) + mMMDev->Release(); + mMMDev = nullptr; } static ALCboolean ALCwasapiPlayback_reset(ALCwasapiPlayback *self) { - ThreadRequest req = { self->MsgEvent, 0 }; - HRESULT hr = E_FAIL; + 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<WasapiProxy*>(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 = NULL; - REFERENCE_TIME min_per, buf_time; - UINT32 buffer_len, min_len; - void *ptr = NULL; - HRESULT hr; + ALCdevice *device{STATIC_CAST(ALCbackend, this)->mDevice}; - if(self->client) - IAudioClient_Release(self->client); - self->client = NULL; + if(mClient) + mClient->Release(); + mClient = nullptr; - hr = IMMDevice_Activate(self->mmdev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, &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 = ptr; + mClient = reinterpret_cast<IAudioClient*>(ptr); - hr = IAudioClient_GetMixFormat(self->client, &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); return E_FAIL; } CoTaskMemFree(wfx); - wfx = NULL; + 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; @@ -1011,11 +954,11 @@ static HRESULT ALCwasapiPlayback_resetProxy(ALCwasapiPlayback *self) OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec * OutputType.Format.nBlockAlign; - hr = IAudioClient_IsFormatSupported(self->client, 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 = IAudioClient_GetMixFormat(self->client, &wfx); + hr = mClient->GetMixFormat(&wfx); } if(FAILED(hr)) { @@ -1023,7 +966,7 @@ static HRESULT ALCwasapiPlayback_resetProxy(ALCwasapiPlayback *self) return hr; } - if(wfx != NULL) + if(wfx != nullptr) { if(!MakeExtensible(&OutputType, wfx)) { @@ -1031,7 +974,7 @@ static HRESULT ALCwasapiPlayback_resetProxy(ALCwasapiPlayback *self) return E_FAIL; } CoTaskMemFree(wfx); - wfx = NULL; + wfx = nullptr; device->Frequency = OutputType.Format.nSamplesPerSec; if(OutputType.Format.nChannels == 1 && OutputType.dwChannelMask == MONO) @@ -1056,7 +999,7 @@ static HRESULT ALCwasapiPlayback_resetProxy(ALCwasapiPlayback *self) OutputType.dwChannelMask = STEREO; } - if(IsEqualGUID(&OutputType.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) + if(IsEqualGUID(OutputType.SubFormat, KSDATAFORMAT_SUBTYPE_PCM)) { if(OutputType.Format.wBitsPerSample == 8) device->FmtType = DevFmtUByte; @@ -1070,7 +1013,7 @@ static HRESULT ALCwasapiPlayback_resetProxy(ALCwasapiPlayback *self) OutputType.Format.wBitsPerSample = 16; } } - else if(IsEqualGUID(&OutputType.SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) + else if(IsEqualGUID(OutputType.SubFormat, KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) { device->FmtType = DevFmtFloat; OutputType.Format.wBitsPerSample = 32; @@ -1084,30 +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 = IAudioClient_Initialize(self->client, AUDCLNT_SHAREMODE_SHARED, - AUDCLNT_STREAMFLAGS_EVENTCALLBACK, - buf_time, 0, &OutputType.Format, NULL); + 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 = IAudioClient_GetDevicePeriod(self->client, &min_per, NULL); + 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 = IAudioClient_GetBufferSize(self->client, &buffer_len); + hr = mClient->GetBufferSize(&buffer_len); } if(FAILED(hr)) { @@ -1124,7 +1070,7 @@ static HRESULT ALCwasapiPlayback_resetProxy(ALCwasapiPlayback *self) device->UpdateSize = buffer_len / device->NumUpdates; } - hr = IAudioClient_SetEventHandle(self->client, self->NotifyEvent); + hr = mClient->SetEventHandle(mNotifyEvent); if(FAILED(hr)) { ERR("Failed to set event handle: 0x%08lx\n", hr); @@ -1137,77 +1083,81 @@ static HRESULT ALCwasapiPlayback_resetProxy(ALCwasapiPlayback *self) static ALCboolean ALCwasapiPlayback_start(ALCwasapiPlayback *self) { - ThreadRequest req = { self->MsgEvent, 0 }; - HRESULT hr = E_FAIL; + 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<WasapiProxy*>(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 = IAudioClient_Start(self->client); + HRESULT hr = mClient->Start(); if(FAILED(hr)) + { ERR("Failed to start audio client: 0x%08lx\n", hr); + return hr; + } - if(SUCCEEDED(hr)) - hr = IAudioClient_GetService(self->client, &IID_IAudioRenderClient, &ptr); + void *ptr; + hr = mClient->GetService(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); + mRender = reinterpret_cast<IAudioRenderClient*>(ptr); + try { + mKillNow.store(AL_FALSE, std::memory_order_release); + mThread = std::thread(ALCwasapiPlayback_mixerProc, this); + } + catch(...) { + mRender->Release(); + mRender = nullptr; ERR("Failed to start thread\n"); hr = E_FAIL; } } + if(FAILED(hr)) + mClient->Stop(); + 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))) + ThreadRequest req{ self->mMsgEvent, 0 }; + auto proxy = static_cast<WasapiProxy*>(self); + if(PostThreadMessage(ThreadID, WM_USER_StopDevice, (WPARAM)&req, (LPARAM)proxy)) (void)WaitForResponse(&req); } -static void ALCwasapiPlayback_stopProxy(ALCwasapiPlayback *self) +void ALCwasapiPlayback::stopProxy() { - int res; - - if(!self->render) + if(!mRender || !mThread.joinable()) return; - ATOMIC_STORE_SEQ(&self->killNow, 1); - althrd_join(self->thread, &res); + mKillNow.store(AL_TRUE); + mThread.join(); - IAudioRenderClient_Release(self->render); - self->render = NULL; - IAudioClient_Stop(self->client); + 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 = ATOMIC_LOAD(&self->Padding, almemory_order_relaxed) * DEVICE_CLOCK_RES / + ret.Latency = self->mPadding.load(std::memory_order_relaxed) * DEVICE_CLOCK_RES / device->Frequency; ALCwasapiPlayback_unlock(self); @@ -1215,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; - WCHAR *devid; + HRESULT resetProxy() override; + HRESULT startProxy() override; + void stopProxy() override; - IMMDevice *mmdev; - IAudioClient *client; - IAudioCaptureClient *capture; - HANDLE NotifyEvent; + std::wstring mDevId; - HANDLE MsgEvent; + IMMDevice *mMMDev{nullptr}; + IAudioClient *mClient{nullptr}; + IAudioCaptureClient *mCapture{nullptr}; + HANDLE mNotifyEvent{nullptr}; - ChannelConverter *ChannelConv; - SampleConverter *SampleConv; - ll_ringbuffer_t *Ring; + HANDLE mMsgEvent{nullptr}; - ATOMIC(int) killNow; - althrd_t thread; -} ALCwasapiCapture; + ChannelConverter *mChannelConv{nullptr}; + SampleConverter *mSampleConv{nullptr}; + ll_ringbuffer_t *mRing{nullptr}; + + std::atomic<int> mKillNow{AL_TRUE}; + std::thread mThread; +}; -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); 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) @@ -1256,75 +1205,53 @@ 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) { + 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 = 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) + 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<WasapiProxy*>(self); + if(PostThreadMessage(ThreadID, WM_USER_CloseDevice, (WPARAM)&req, (LPARAM)proxy)) (void)WaitForResponse(&req); - CloseHandle(self->MsgEvent); - self->MsgEvent = NULL; + CloseHandle(self->mMsgEvent); + self->mMsgEvent = nullptr; } - if(self->NotifyEvent != NULL) - CloseHandle(self->NotifyEvent); - self->NotifyEvent = NULL; + if(self->mNotifyEvent != nullptr) + CloseHandle(self->mNotifyEvent); + self->mNotifyEvent = nullptr; - ll_ringbuffer_free(self->Ring); - self->Ring = NULL; + ll_ringbuffer_free(self->mRing); + self->mRing = nullptr; - DestroySampleConverter(&self->SampleConv); - DestroyChannelConverter(&self->ChannelConv); + DestroySampleConverter(&self->mSampleConv); + DestroyChannelConverter(&self->mChannelConv); - free(self->devid); - self->devid = NULL; - - 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) { - ALCwasapiCapture *self = arg; - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - ALfloat *samples = NULL; - size_t samplesmax = 0; - HRESULT hr; + ALCdevice *device{STATIC_CAST(ALCbackend, self)->mDevice}; + IAudioCaptureClient *capture{self->mCapture}; - hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); + HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); if(FAILED(hr)) { - ERR("CoInitializeEx(NULL, COINIT_MULTITHREADED) failed: 0x%08lx\n", 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)(); @@ -1333,12 +1260,13 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(void *arg) althrd_setname(althrd_current(), RECORD_THREAD_NAME); - while(!ATOMIC_LOAD(&self->killNow, almemory_order_relaxed)) + std::vector<float> samples; + while(!self->mKillNow.load(std::memory_order_relaxed)) { UINT32 avail; DWORD res; - hr = IAudioCaptureClient_GetNextPacketSize(self->capture, &avail); + hr = capture->GetNextPacketSize(&avail); if(FAILED(hr)) ERR("Failed to get next packet size: 0x%08lx\n", hr); else if(avail > 0) @@ -1347,38 +1275,28 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(void *arg) DWORD flags; BYTE *rdata; - hr = IAudioCaptureClient_GetBuffer(self->capture, - &rdata, &numsamples, &flags, NULL, NULL - ); + 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(self->mChannelConv) { - 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; + samples.resize(numsamples*2); + ChannelConverterInput(self->mChannelConv, rdata, samples.data(), numsamples); + rdata = reinterpret_cast<BYTE*>(samples.data()); } - ll_ringbuffer_get_write_vector(self->Ring, data); + ll_ringbuffer_data_t data[2]; + ll_ringbuffer_get_write_vector(self->mRing, data); - if(self->SampleConv) + size_t dstframes; + 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) @@ -1387,7 +1305,7 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(void *arg) * 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) ); } @@ -1405,9 +1323,9 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(void *arg) dstframes = len1 + len2; } - ll_ringbuffer_write_advance(self->Ring, dstframes); + ll_ringbuffer_write_advance(self->mRing, dstframes); - hr = IAudioCaptureClient_ReleaseBuffer(self->capture, numsamples); + hr = capture->ReleaseBuffer(numsamples); if(FAILED(hr)) ERR("Failed to release capture buffer: 0x%08lx\n", hr); } } @@ -1420,15 +1338,11 @@ FORCE_ALIGN int ALCwasapiCapture_recordProc(void *arg) 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); } - al_free(samples); - samples = NULL; - samplesmax = 0; - CoUninitialize(); return 0; } @@ -1436,11 +1350,11 @@ 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(NULL, FALSE, FALSE, NULL); - self->MsgEvent = CreateEventW(NULL, FALSE, FALSE, NULL); - if(self->NotifyEvent == NULL || self->MsgEvent == NULL) + 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; @@ -1450,40 +1364,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->mMsgEvent, 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, NULL, 0)) > 0) + if((len=MultiByteToWideChar(CP_UTF8, 0, deviceName, -1, nullptr, 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); + std::vector<WCHAR> 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(); } + ); } } - 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->mDevId = iter->devid; + alstr_copy_range(&device->DeviceName, &*iter->name.cbegin(), &*iter->name.cend()); hr = S_OK; } } @@ -1491,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<WasapiProxy*>(self); + if(PostThreadMessage(ThreadID, WM_USER_OpenDevice, (WPARAM)&req, (LPARAM)proxy)) hr = WaitForResponse(&req); else ERR("Failed to post thread message: %lu\n", GetLastError()); @@ -1502,25 +1415,25 @@ static ALCenum ALCwasapiCapture_open(ALCwasapiCapture *self, const ALCchar *devi if(FAILED(hr)) { - if(self->NotifyEvent != NULL) - CloseHandle(self->NotifyEvent); - self->NotifyEvent = NULL; - if(self->MsgEvent != NULL) - CloseHandle(self->MsgEvent); - self->MsgEvent = NULL; + if(self->mNotifyEvent != nullptr) + CloseHandle(self->mNotifyEvent); + self->mNotifyEvent = nullptr; + if(self->mMsgEvent != nullptr) + CloseHandle(self->mMsgEvent); + self->mMsgEvent = nullptr; - free(self->devid); - self->devid = NULL; + 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<WasapiProxy*>(self); + if(PostThreadMessage(ThreadID, WM_USER_ResetDevice, (WPARAM)&req, (LPARAM)proxy)) hr = WaitForResponse(&req); else ERR("Failed to post thread message: %lu\n", GetLastError()); @@ -1536,85 +1449,81 @@ 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; - void *ptr; - HRESULT hr; + ALCdevice *device{STATIC_CAST(ALCbackend, this)->mDevice}; - hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr); + void *ptr; + HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_INPROC_SERVER, + IID_IMMDeviceEnumerator, &ptr); if(SUCCEEDED(hr)) { - IMMDeviceEnumerator *Enumerator = ptr; - if(!self->devid) - hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(Enumerator, eCapture, eMultimedia, &self->mmdev); + auto Enumerator = reinterpret_cast<IMMDeviceEnumerator*>(ptr); + if(mDevId.empty()) + hr = Enumerator->GetDefaultAudioEndpoint(eCapture, eMultimedia, &mMMDev); else - hr = IMMDeviceEnumerator_GetDevice(Enumerator, self->devid, &self->mmdev); - IMMDeviceEnumerator_Release(Enumerator); - Enumerator = NULL; + hr = Enumerator->GetDevice(mDevId.c_str(), &mMMDev); + Enumerator->Release(); } if(SUCCEEDED(hr)) - hr = IMMDevice_Activate(self->mmdev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, &ptr); + hr = mMMDev->Activate(IID_IAudioClient, CLSCTX_INPROC_SERVER, nullptr, &ptr); if(SUCCEEDED(hr)) { - self->client = ptr; + mClient = reinterpret_cast<IAudioClient*>(ptr); if(alstr_empty(device->DeviceName)) - get_device_name_and_guid(self->mmdev, &device->DeviceName, NULL); + { + std::string devname; + 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) - IMMDevice_Release(self->mmdev); - self->mmdev = NULL; + if(mMMDev) + mMMDev->Release(); + mMMDev = nullptr; } return hr; } - -static void ALCwasapiCapture_closeProxy(ALCwasapiCapture *self) +void ALCwasapiCapture::closeProxy() { - if(self->client) - IAudioClient_Release(self->client); - self->client = NULL; + if(mClient) + mClient->Release(); + mClient = nullptr; - if(self->mmdev) - IMMDevice_Release(self->mmdev); - self->mmdev = NULL; + if(mMMDev) + mMMDev->Release(); + mMMDev = nullptr; } - -static HRESULT ALCwasapiCapture_resetProxy(ALCwasapiCapture *self) +HRESULT ALCwasapiCapture::resetProxy() { - 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; + ALCdevice *device{STATIC_CAST(ALCbackend, this)->mDevice}; - if(self->client) - IAudioClient_Release(self->client); - self->client = NULL; + if(mClient) + mClient->Release(); + mClient = nullptr; - hr = IMMDevice_Activate(self->mmdev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, &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 = ptr; + mClient = reinterpret_cast<IAudioClient*>(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) { @@ -1682,19 +1591,18 @@ static HRESULT ALCwasapiCapture_resetProxy(ALCwasapiCapture *self) OutputType.Format.nBlockAlign; OutputType.Format.cbSize = sizeof(OutputType) - sizeof(OutputType.Format); - hr = IAudioClient_IsFormatSupported(self->client, - AUDCLNT_SHAREMODE_SHARED, &OutputType.Format, &wfx - ); + 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; } - DestroySampleConverter(&self->SampleConv); - DestroyChannelConverter(&self->ChannelConv); + DestroySampleConverter(&mSampleConv); + DestroyChannelConverter(&mChannelConv); - if(wfx != NULL) + if(wfx != nullptr) { if(!(wfx->nChannels == OutputType.Format.nChannels || (wfx->nChannels == 1 && OutputType.Format.nChannels == 2) || @@ -1714,10 +1622,11 @@ static HRESULT ALCwasapiCapture_resetProxy(ALCwasapiCapture *self) return E_FAIL; } CoTaskMemFree(wfx); - wfx = NULL; + wfx = nullptr; } - if(IsEqualGUID(&OutputType.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM)) + enum DevFmtType srcType; + if(IsEqualGUID(OutputType.SubFormat, KSDATAFORMAT_SUBTYPE_PCM)) { if(OutputType.Format.wBitsPerSample == 8) srcType = DevFmtUByte; @@ -1731,7 +1640,7 @@ static HRESULT ALCwasapiCapture_resetProxy(ALCwasapiCapture *self) return E_FAIL; } } - else if(IsEqualGUID(&OutputType.SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) + else if(IsEqualGUID(OutputType.SubFormat, KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) { if(OutputType.Format.wBitsPerSample == 32) srcType = DevFmtFloat; @@ -1749,9 +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; @@ -1764,9 +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; @@ -1777,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), @@ -1793,17 +1700,16 @@ static HRESULT ALCwasapiCapture_resetProxy(ALCwasapiCapture *self) device->Frequency, DevFmtTypeString(srcType), OutputType.Format.nSamplesPerSec); } - hr = IAudioClient_Initialize(self->client, - AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, - buf_time, 0, &OutputType.Format, NULL - ); + 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 = IAudioClient_GetBufferSize(self->client, &buffer_len); + UINT32 buffer_len; + hr = mClient->GetBufferSize(&buffer_len); if(FAILED(hr)) { ERR("Failed to get buffer size: 0x%08lx\n", hr); @@ -1811,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 = IAudioClient_SetEventHandle(self->client, self->NotifyEvent); + hr = mClient->SetEventHandle(mNotifyEvent); if(FAILED(hr)) { ERR("Failed to set event handle: 0x%08lx\n", hr); @@ -1835,46 +1741,48 @@ static HRESULT ALCwasapiCapture_resetProxy(ALCwasapiCapture *self) static ALCboolean ALCwasapiCapture_start(ALCwasapiCapture *self) { - ThreadRequest req = { self->MsgEvent, 0 }; - HRESULT hr = E_FAIL; + 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<WasapiProxy*>(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() { - HRESULT hr; - void *ptr; + ResetEvent(mNotifyEvent); - ResetEvent(self->NotifyEvent); - hr = IAudioClient_Start(self->client); + HRESULT hr{mClient->Start()}; if(FAILED(hr)) { ERR("Failed to start audio client: 0x%08lx\n", hr); return hr; } - hr = IAudioClient_GetService(self->client, &IID_IAudioCaptureClient, &ptr); + void *ptr; + hr = mClient->GetService(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) - { + mCapture = reinterpret_cast<IAudioCaptureClient*>(ptr); + try { + mKillNow.store(AL_FALSE, std::memory_order_release); + mThread = std::thread(ALCwasapiCapture_recordProc, this); + } + catch(...) { + mCapture->Release(); + mCapture = nullptr; 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); + mClient->Stop(); + mClient->Reset(); } return hr; @@ -1883,46 +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<WasapiProxy*>(self); + if(PostThreadMessage(ThreadID, WM_USER_StopDevice, (WPARAM)&req, (LPARAM)proxy)) (void)WaitForResponse(&req); } -static void ALCwasapiCapture_stopProxy(ALCwasapiCapture *self) +void ALCwasapiCapture::stopProxy() { - int res; - - if(!self->capture) + if(!mCapture || !mThread.joinable()) return; - ATOMIC_STORE_SEQ(&self->killNow, 1); - althrd_join(self->thread, &res); + mKillNow.store(AL_TRUE); + mThread.join(); - IAudioCaptureClient_Release(self->capture); - self->capture = NULL; - IAudioClient_Stop(self->client); - IAudioClient_Reset(self->client); + mCapture->Release(); + mCapture = nullptr; + mClient->Stop(); + mClient->Reset(); } -ALuint ALCwasapiCapture_availableSamples(ALCwasapiCapture *self) +static ALuint ALCwasapiCapture_availableSamples(ALCwasapiCapture *self) { - return (ALuint)ll_ringbuffer_read_space(self->Ring); + return (ALuint)ll_ringbuffer_read_space(self->mRing); } -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; - ll_ringbuffer_read(self->Ring, buffer, samples); + ll_ringbuffer_read(self->mRing, reinterpret_cast<char*>(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); @@ -1932,26 +1839,28 @@ static ALCbackend* ALCwasapiBackendFactory_createBackend(ALCwasapiBackendFactory DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwasapiBackendFactory); +ALCwasapiBackendFactory::ALCwasapiBackendFactory() noexcept + : ALCbackendFactory{ALCWASAPIBACKENDFACTORY_INITIALIZER} +{ +} + 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) + req.FinishedEvt = CreateEventW(nullptr, FALSE, FALSE, nullptr); + if(req.FinishedEvt == nullptr) ERR("Failed to create event: %lu\n", GetLastError()); else { - ThreadHdl = CreateThread(NULL, 0, ALCwasapiProxy_messageHandler, &req, 0, &ThreadID); - if(ThreadHdl != NULL) + ThreadHdl = CreateThread(nullptr, 0, WasapiProxy_messageHandler, &req, 0, &ThreadID); + if(ThreadHdl != nullptr) InitResult = WaitForResponse(&req); CloseHandle(req.FinishedEvt); } @@ -1962,18 +1871,15 @@ 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) { TRACE("Sending WM_QUIT to Thread %04lx\n", ThreadID); PostThreadMessage(ThreadID, WM_QUIT, 0, 0); CloseHandle(ThreadHdl); - ThreadHdl = NULL; + ThreadHdl = nullptr; } } @@ -1986,34 +1892,37 @@ static ALCboolean ALCwasapiBackendFactory_querySupport(ALCwasapiBackendFactory* static void ALCwasapiBackendFactory_probe(ALCwasapiBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames) { - ThreadRequest req = { NULL, 0 }; + ThreadRequest req{ nullptr, 0 }; - req.FinishedEvt = CreateEventW(NULL, FALSE, FALSE, NULL); - if(req.FinishedEvt == NULL) + 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 = NULL; + req.FinishedEvt = nullptr; } } @@ -2023,23 +1932,23 @@ static ALCbackend* ALCwasapiBackendFactory_createBackend(ALCwasapiBackendFactory { ALCwasapiPlayback *backend; NEW_OBJ(backend, ALCwasapiPlayback)(device); - if(!backend) return NULL; + if(!backend) return nullptr; return STATIC_CAST(ALCbackend, backend); } if(type == ALCbackend_Capture) { ALCwasapiCapture *backend; NEW_OBJ(backend, ALCwasapiCapture)(device); - if(!backend) return NULL; + if(!backend) return nullptr; return STATIC_CAST(ALCbackend, backend); } - return NULL; + return nullptr; } ALCbackendFactory *ALCwasapiBackendFactory_getFactory(void) { - static ALCwasapiBackendFactory factory = ALCWASAPIBACKENDFACTORY_INITIALIZER; + static ALCwasapiBackendFactory factory{}; return STATIC_CAST(ALCbackendFactory, &factory); } diff --git a/Alc/bformatdec.c b/Alc/bformatdec.cpp index 5233d06f..7d1e36ff 100644 --- a/Alc/bformatdec.c +++ b/Alc/bformatdec.cpp @@ -1,6 +1,9 @@ #include "config.h" +#include <array> +#include <vector> + #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] = { +constexpr 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] = { +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 }, @@ -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] = { +constexpr 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<typename T, size_t alignment> +class aligned_allocator : public std::allocator<T> { +public: + using size_type = size_t; + using pointer = T*; + using const_pointer = const T*; + + template<typename U> + struct rebind { + using other = aligned_allocator<U, alignment>; + }; + + pointer allocate(size_type n, const void* = nullptr) + { return reinterpret_cast<T*>(al_malloc(alignment, n*sizeof(T))); } + + void deallocate(pointer p, size_type) + { al_free(p); } + + aligned_allocator() : std::allocator<T>() { } + aligned_allocator(const aligned_allocator &a) : std::allocator<T>(a) { } + template<class U> + aligned_allocator(const aligned_allocator<U,alignment> &a) + : std::allocator<T>(a) + { } + ~aligned_allocator() { } +}; + +template<typename T, size_t alignment> +using aligned_vector = std::vector<T, aligned_allocator<T, alignment>>; + +} // 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<std::array<ALfloat,BUFFERSIZE>, 16> Samples; /* These two alias into Samples */ - ALfloat (*SamplesHF)[BUFFERSIZE]; - ALfloat (*SamplesLF)[BUFFERSIZE]; + std::array<ALfloat,BUFFERSIZE> *SamplesHF; + std::array<ALfloat,BUFFERSIZE> *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 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] = { + static constexpr ALsizei map2DTo3D[MAX_AMBI2D_COEFFS] = { 0, 1, 3, 4, 8, 9, 15 }; const ALfloat *coeff_scale = N3D2N3DScale; @@ -143,23 +191,22 @@ 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 = 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; 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)); @@ -304,15 +351,14 @@ 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; - 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], + 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<ALfloat(&)[BUFFERSIZE]>(dec->SamplesHF[0]), + dec->NumChannels, 0, SamplesToDo ); MixRowSamples(dec->ChannelMix, dec->Matrix.Dual[chan][LF_BAND], - dec->SamplesLF, dec->NumChannels, 0, SamplesToDo + &reinterpret_cast<ALfloat(&)[BUFFERSIZE]>(dec->SamplesLF[0]), + dec->NumChannels, 0, SamplesToDo ); for(i = 0;i < SamplesToDo;i++) @@ -350,7 +398,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; @@ -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<ALfloat(&)[BUFFERSIZE]>(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 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; } } @@ -473,7 +509,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..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; @@ -39,10 +42,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 +55,10 @@ 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); + +#ifdef __cplusplus +} // extern "C" +#endif #endif /* BFORMATDEC_H */ @@ -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/compat.h b/Alc/compat.h index 495bfdf2..1c348c34 100644 --- a/Alc/compat.h +++ b/Alc/compat.h @@ -19,14 +19,213 @@ FILE *al_fopen(const char *fname, const char *mode); #define HAVE_DYNLOAD 1 +#ifdef __cplusplus +} // extern "C" + +#include <array> +#include <string> +#include <fstream> + +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<char_type,4096> 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 */ + #else #define al_fopen fopen -#if defined(HAVE_DLFCN_H) && !defined(IN_IDE_PARSER) +#if defined(HAVE_DLFCN_H) #define HAVE_DYNLOAD 1 #endif + +#ifdef __cplusplus +} // extern "C" + +#include <fstream> + +namespace al { + +using filebuf = std::filebuf; +using ifstream = std::ifstream; + +} // namespace al + +extern "C" { +#endif /* __cplusplus */ + #endif struct FileMapping { 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/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 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..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; @@ -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..82ea5d26 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)) { } @@ -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/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/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/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/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/filters/splitter.c b/Alc/filters/splitter.cpp index e99f4b95..6aed7493 100644 --- a/Alc/filters/splitter.c +++ b/Alc/filters/splitter.cpp @@ -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..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 { @@ -14,7 +17,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 +30,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 { @@ -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/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; @@ -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]; @@ -9,6 +9,10 @@ #include "atomic.h" +#ifdef __cplusplus +extern "C" { +#endif + #define HRTF_HISTORY_BITS (6) #define HRTF_HISTORY_LENGTH (1<<HRTF_HISTORY_BITS) #define HRTF_HISTORY_MASK (HRTF_HISTORY_LENGTH-1) @@ -71,7 +75,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 +83,10 @@ 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); + +#ifdef __cplusplus +} // extern "C" +#endif #endif /* ALC_HRTF_H */ 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 <android/log.h> -#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/Alc/mastering.c b/Alc/mastering.c index 52ff5b23..5ccf3a9e 100644 --- a/Alc/mastering.c +++ b/Alc/mastering.c @@ -6,6 +6,19 @@ #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. */ @@ -83,8 +96,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 +135,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 +153,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 +186,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 +215,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 +236,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 +273,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 +366,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); @@ -463,14 +476,14 @@ 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(*)[])(Comp->Hold + 1); + Comp->Delay = (ALfloat(*)[BUFFERSIZE])(Comp->Hold + 1); } else { - Comp->Delay = (ALfloat(*)[])(Comp + 1); + Comp->Delay = (ALfloat(*)[BUFFERSIZE])(Comp + 1); } } @@ -481,11 +494,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.cpp index 2c0f3bf2..db476884 100644 --- a/Alc/panning.c +++ b/Alc/panning.cpp @@ -38,12 +38,6 @@ #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 */ @@ -151,7 +145,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 +160,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; @@ -281,50 +275,50 @@ 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; if(sscanf(name, "AUX%u%c", &n, &c) == 1 && n < 16) - ch = Aux0+n; + ch = static_cast<enum Channel>(Aux0+n); else { ERR("AmbDec speaker label \"%s\" not recognized\n", name); @@ -335,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; @@ -381,7 +375,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; @@ -429,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 ); @@ -449,7 +443,8 @@ static void InitDistanceComp(ALCdevice *device, const AmbDecConf *conf, const AL if(total > 0) { - device->ChannelDelay[0].Buffer = al_calloc(16, total * sizeof(ALfloat)); + device->ChannelDelay[0].Buffer = reinterpret_cast<float*>( + al_calloc(16, total * sizeof(ALfloat))); for(i = 1;i < MAX_OUTPUT_CHANNELS;i++) { size_t len = RoundUp(device->ChannelDelay[i-1].Length, 4); @@ -644,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++) @@ -730,7 +725,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; @@ -845,8 +840,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; @@ -860,7 +855,8 @@ static void InitHrtfPanning(ALCdevice *device) count = COUNTOF(IndexMap); } - device->Hrtf = al_calloc(16, FAM_SIZE(DirectHrtfState, Chan, count)); + device->Hrtf = reinterpret_cast<DirectHrtfState*>( + al_calloc(16, FAM_SIZE(DirectHrtfState, Chan, count))); for(i = 0;i < count;i++) { @@ -967,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) { @@ -988,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 { @@ -1044,7 +1038,8 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf * higher). */ ALfloat scale = (ALfloat)(5000.0 / device->Frequency); - FrontStablizer *stablizer = al_calloc(16, sizeof(*stablizer)); + FrontStablizer *stablizer = reinterpret_cast<FrontStablizer*>( + al_calloc(16, sizeof(*stablizer))); bandsplit_init(&stablizer->LFilter, scale); stablizer->RFilter = stablizer->LFilter; @@ -1065,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; } @@ -1194,7 +1188,7 @@ no_hrtf: ConfigValueInt(alstr_get_cstr(device->DeviceName), NULL, "cf_level", &bs2blevel); if(bs2blevel > 0 && bs2blevel <= 6) { - device->Bs2b = al_calloc(16, sizeof(*device->Bs2b)); + device->Bs2b = reinterpret_cast<struct bs2b*>(al_calloc(16, sizeof(*device->Bs2b))); bs2b_set_params(device->Bs2b, bs2blevel, device->Frequency); TRACE("BS2B enabled\n"); InitPanning(device); @@ -1212,7 +1206,7 @@ no_hrtf: } if(device->Render_Mode == NormalRender) { - device->Uhj_Encoder = al_calloc(16, sizeof(Uhj2Encoder)); + device->Uhj_Encoder = reinterpret_cast<Uhj2Encoder*>(al_calloc(16, sizeof(Uhj2Encoder))); TRACE("UHJ enabled\n"); InitUhjPanning(device); return; diff --git a/Alc/polymorphism.h b/Alc/polymorphism.h index fa31fad2..83d5585f 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<to*>(obj) +#define STATIC_UPCAST(to, from, obj) static_cast<to*>(obj) +#else + #define DERIVE_FROM_TYPE(t) t t##_parent #define STATIC_CAST(to, obj) (&(obj)->to##_parent) -#ifdef __GNUC__ + +#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) \ @@ -54,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); } @@ -74,17 +81,15 @@ 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)); \ T##_Construct(_res EXTRACT_NEW_ARGS /* Destructs and deallocate an object. */ diff --git a/Alc/uhjfilter.c b/Alc/uhjfilter.cpp index 42b0bc40..4fae721f 100644 --- a/Alc/uhjfilter.c +++ b/Alc/uhjfilter.cpp @@ -4,19 +4,21 @@ #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 -static const ALfloat Filter1CoeffSqr[4] = { +constexpr ALfloat Filter1CoeffSqr[4] = { 0.479400865589f, 0.876218493539f, 0.976597589508f, 0.997499255936f }; -static const ALfloat Filter2CoeffSqr[4] = { +constexpr 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) +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]; @@ -34,6 +36,8 @@ static void allpass_process(AllPassState *state, ALfloat *restrict dst, const AL 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 @@ -55,7 +59,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..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; @@ -44,6 +48,10 @@ 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); + +#ifdef __cplusplus +} // extern "C" +#endif #endif /* UHJFILTER_H */ 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<typename T> +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<T*>(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) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6fea142a..ba1db905 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") @@ -29,6 +32,7 @@ INCLUDE(CheckSymbolExists) INCLUDE(CheckCCompilerFlag) INCLUDE(CheckCXXCompilerFlag) INCLUDE(CheckCSourceCompiles) +INCLUDE(CheckCXXSourceCompiles) INCLUDE(CheckTypeSize) include(CheckStructHasMember) include(CheckFileOffsetBits) @@ -145,26 +149,29 @@ 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}") +# 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() -SET(CPP_DEFS ${CPP_DEFS} _LARGEFILE_SOURCE _LARGE_FILES) -SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -D_LARGEFILE_SOURCE -D_LARGE_FILES") -# 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() +# 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 inline +IF(MSVC) + # 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) @@ -283,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}") @@ -343,11 +350,57 @@ int main() }" HAVE_STATIC_LIBGCC_SWITCH ) - if(HAVE_STATIC_LIBGCC_SWITCH) - SET(LINKER_FLAGS ${LINKER_FLAGS} -static-libgcc) + 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++" OFF) + 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 <cstdlib> +int main() +{ + return 0; +}" + HAVE_STATIC_LIBSTDCXX_SWITCH + ) 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 <cstdlib> +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() @@ -768,7 +821,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 @@ -814,7 +867,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 @@ -825,13 +878,13 @@ 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.cpp Alc/ambdec.h - Alc/bformatdec.c + Alc/bformatdec.cpp Alc/bformatdec.h - Alc/panning.c + Alc/panning.cpp Alc/polymorphism.h Alc/mixvoice.c Alc/mixer/defs.h @@ -1098,7 +1151,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() @@ -1111,7 +1164,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() @@ -1153,7 +1206,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() @@ -1412,11 +1465,11 @@ 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}) - 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) @@ -1443,7 +1496,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}) 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() 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/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<bool>(mCtx); } + + 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 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/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/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 */ 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.cpp index ed712434..b33dc584 100644 --- a/OpenAL32/alBuffer.c +++ b/OpenAL32/alBuffer.cpp @@ -23,11 +23,15 @@ #include <stdlib.h> #include <stdio.h> #include <assert.h> -#include <limits.h> #ifdef HAVE_MALLOC_H #include <malloc.h> #endif +#include <array> +#include <vector> +#include <limits> +#include <algorithm> + #include "alMain.h" #include "alu.h" #include "alError.h" @@ -35,128 +39,484 @@ #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); +namespace { + +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)}; -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) +ALbuffer *AllocBuffer(ALCcontext *context) +{ + ALCdevice *device = context->Device; + std::unique_lock<almtx_t> 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<ALbuffer*>(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)<<slidx); + + return buffer; +} + +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; +} + +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); + return nullptr; + BufferSubList *sublist{&VECTOR_ELEM(device->BufferList, lidx)}; if(UNLIKELY(sublist->FreeMask & (U64(1)<<slidx))) - return NULL; + return nullptr; return sublist->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) +ALsizei SanitizeAlignment(UserFmtType type, ALsizei align) { - ALCcontext *context; - ALsizei cur = 0; - - context = GetContextRef(); - if(!context) return; + if(align < 0) + return 0; - if(!(n >= 0)) - alSetError(context, AL_INVALID_VALUE, "Generating %d buffers", n); - else for(cur = 0;cur < n;cur++) + if(align == 0) { - ALbuffer *buffer = AllocBuffer(context); - if(!buffer) + if(type == UserFmtIMA4) { - alDeleteBuffers(cur, buffers); - break; + /* 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; + } - buffers[cur] = buffer->id; + 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; } - ALCcontext_DecRef(context); + return align; } -AL_API ALvoid AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers) + +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 "<internal type error>"; +} + +/* + * 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) { - ALCdevice *device; - ALCcontext *context; - ALbuffer *ALBuf; - ALsizei i; + if(UNLIKELY(ReadRef(&ALBuf->ref) != 0 || ALBuf->MappedAccess != 0)) + SETERR_RETURN(context, AL_INVALID_OPERATION,, "Modifying storage for in-use buffer %u", + ALBuf->id); - context = GetContextRef(); - if(!context) return; + /* 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"); - device = context->Device; + /* 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; + } - LockBufferList(device); - if(UNLIKELY(n < 0)) + /* 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)) { - alSetError(context, AL_INVALID_VALUE, "Deleting %d buffers", n); - goto done; + if(UNLIKELY((long)SrcType != (long)DstType)) + SETERR_RETURN(context, AL_INVALID_VALUE,, "%s samples cannot be mapped", + NameFromUserFmtType(SrcType)); } - for(i = 0;i < n;i++) + 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)) { - if(!buffers[i]) - continue; + /* 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<ALsizei>::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<ALsizei>::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}; - /* Check for valid Buffer ID, and make sure it's not in use. */ - if((ALBuf=LookupBuffer(device, buffers[i])) == NULL) + /* 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<ALsizei>::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)) { - alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffers[i]); - goto done; + ALsizei tocopy{std::min(newsize, ALBuf->BytesAlloc)}; + if(tocopy > 0) memcpy(temp, ALBuf->data, tocopy); } - if(ReadRef(&ALBuf->ref) != 0) + 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<ALshort*>(ALBuf->data), + static_cast<const ALubyte*>(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<ALshort*>(ALBuf->data), + static_cast<const ALubyte*>(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<FormatMap,46> 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) { - alSetError(context, AL_INVALID_OPERATION, "Deleting in-use buffer %u", buffers[i]); - goto done; + *chans = fmt.channels; + *type = fmt.type; + return AL_TRUE; } } - for(i = 0;i < n;i++) + + return AL_FALSE; +} + +} // namespace + + +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)) { - if((ALBuf=LookupBuffer(device, buffers[i])) != NULL) - FreeBuffer(device, ALBuf); + /* 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<ALuint> ids; + ids.reserve(n); + do { + ALbuffer *buffer = AllocBuffer(context.get()); + if(!buffer) + { + alDeleteBuffers(ids.size(), ids.data()); + return; + } -done: - UnlockBufferList(device); - ALCcontext_DecRef(context); + ids.emplace_back(buffer->id); + } while(--n); + std::copy(ids.begin(), ids.end(), buffers); + } } -AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer) +AL_API ALvoid AL_APIENTRY alDeleteBuffers(ALsizei n, const ALuint *buffers) { - ALCcontext *context; - ALboolean ret; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - context = GetContextRef(); - if(!context) return AL_FALSE; + if(UNLIKELY(n < 0)) + { + alSetError(context.get(), AL_INVALID_VALUE, "Deleting %d buffers", n); + return; + } + if(UNLIKELY(n == 0)) + return; - LockBufferList(context->Device); - ret = ((!buffer || LookupBuffer(context->Device, buffer)) ? - AL_TRUE : AL_FALSE); - UnlockBufferList(context->Device); + ALCdevice *device = context->Device; + std::lock_guard<almtx_t> _{device->BufferLock}; - ALCcontext_DecRef(context); + /* 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)); } + ); + } +} - return ret; +AL_API ALboolean AL_APIENTRY alIsBuffer(ALuint buffer) +{ + ContextRef context{GetContextRef()}; + if(LIKELY(context)) + { + ALCdevice *device = context->Device; + std::lock_guard<almtx_t> _{device->BufferLock}; + if(!buffer || LookupBuffer(device, buffer)) + return AL_TRUE; + } + return AL_FALSE; } @@ -165,138 +525,123 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi 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); + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard<almtx_t> _{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(size < 0)) - alSetError(context, AL_INVALID_VALUE, "Negative storage size %d", size); + alSetError(context.get(), AL_INVALID_VALUE, "Negative storage size %d", size); else if(UNLIKELY(freq < 1)) - alSetError(context, AL_INVALID_VALUE, "Invalid sample rate %d", freq); + alSetError(context.get(), 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", + 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, AL_INVALID_VALUE, + 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, AL_INVALID_ENUM, "Invalid format 0x%04x", format); + alSetError(context.get(), AL_INVALID_ENUM, "Invalid format 0x%04x", format); else - LoadData(context, albuf, freq, size, srcchannels, srctype, data, flags); - - UnlockBufferList(device); - ALCcontext_DecRef(context); + LoadData(context.get(), albuf, freq, size, srcchannels, srctype, data, flags); } 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); + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return nullptr; + + ALCdevice *device = context->Device; + std::lock_guard<almtx_t> _{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, AL_INVALID_VALUE, "Invalid map flags 0x%x", access&INVALID_MAP_FLAGS); + 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, AL_INVALID_VALUE, "Mapping buffer %u without read or write access", + 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, AL_INVALID_OPERATION, + alSetError(context.get(), 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); + alSetError(context.get(), AL_INVALID_OPERATION, "Mapping already-mapped buffer %u", buffer); else if(UNLIKELY((unavailable&AL_MAP_READ_BIT_SOFT))) - alSetError(context, AL_INVALID_VALUE, + 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, AL_INVALID_VALUE, + 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, AL_INVALID_VALUE, + 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, AL_INVALID_VALUE, "Mapping invalid range %d+%d for buffer %u", + alSetError(context.get(), AL_INVALID_VALUE, "Mapping invalid range %d+%d for buffer %u", offset, length, buffer); else { - retval = (ALbyte*)albuf->data + offset; + void *retval = (ALbyte*)albuf->data + offset; albuf->MappedAccess = access; albuf->MappedOffset = offset; albuf->MappedSize = length; + return retval; } } - UnlockBufferList(device); - ALCcontext_DecRef(context); - return retval; + return nullptr; } AL_API void AL_APIENTRY alUnmapBufferSOFT(ALuint buffer) { - ALCdevice *device; - ALCcontext *context; - ALbuffer *albuf; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - context = GetContextRef(); - if(!context) return; + ALCdevice *device = context->Device; + std::lock_guard<almtx_t> _{device->BufferLock}; - device = context->Device; - LockBufferList(device); - if((albuf=LookupBuffer(device, buffer)) == NULL) - alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + 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, AL_INVALID_OPERATION, "Unmapping unmapped buffer %u", buffer); + alSetError(context.get(), 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; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - context = GetContextRef(); - if(!context) return; + ALCdevice *device = context->Device; + std::lock_guard<almtx_t> _{device->BufferLock}; - device = context->Device; - LockBufferList(device); - if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL)) - alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + 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, AL_INVALID_OPERATION, + 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, AL_INVALID_VALUE, "Flushing invalid range %d+%d on buffer %u", + alSetError(context.get(), AL_INVALID_VALUE, "Flushing invalid range %d+%d on buffer %u", offset, length, buffer); else { @@ -307,49 +652,44 @@ AL_API void AL_APIENTRY alFlushMappedBufferSOFT(ALuint buffer, ALsizei offset, A */ 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); + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; + + ALCdevice *device = context->Device; + std::lock_guard<almtx_t> _{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)) - alSetError(context, AL_INVALID_ENUM, "Invalid format 0x%04x", format); + 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; - 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); + 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, AL_INVALID_ENUM, "Unpacking data with mismatched format"); + alSetError(context.get(), AL_INVALID_ENUM, "Unpacking data with mismatched format"); else if(UNLIKELY(align != albuf->OriginalAlign)) - alSetError(context, AL_INVALID_VALUE, + 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, AL_INVALID_OPERATION, "Unpacking data into mapped buffer %u", + alSetError(context.get(), AL_INVALID_OPERATION, "Unpacking data into mapped buffer %u", buffer); else { @@ -364,14 +704,14 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons 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", + 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, AL_INVALID_VALUE, + 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, AL_INVALID_VALUE, + 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 @@ -380,11 +720,13 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons offset = offset/byte_align * align * frame_size; length = length/byte_align * align; - dst = (ALbyte*)albuf->data + offset; + void *dst = static_cast<ALbyte*>(albuf->data) + offset; if(srctype == UserFmtIMA4 && albuf->FmtType == FmtShort) - Convert_ALshort_ALima4(dst, data, num_chans, length, align); + Convert_ALshort_ALima4(static_cast<ALshort*>(dst), + static_cast<const ALubyte*>(data), num_chans, length, align); else if(srctype == UserFmtMSADPCM && albuf->FmtType == FmtShort) - Convert_ALshort_ALmsadpcm(dst, data, num_chans, length, align); + Convert_ALshort_ALmsadpcm(static_cast<ALshort*>(dst), + static_cast<const ALubyte*>(data), num_chans, length, align); else { assert((long)srctype == (long)albuf->FmtType); @@ -393,9 +735,6 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons } } } - UnlockBufferList(device); - - ALCcontext_DecRef(context); } @@ -403,224 +742,181 @@ 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; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - context = GetContextRef(); - if(!context) return; - - alSetError(context, AL_INVALID_OPERATION, "alBufferSamplesSOFT not supported"); - - ALCcontext_DecRef(context); + 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)) { - ALCcontext *context; - - context = GetContextRef(); - if(!context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - alSetError(context, AL_INVALID_OPERATION, "alBufferSubSamplesSOFT not supported"); - - ALCcontext_DecRef(context); + 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)) { - ALCcontext *context; - - context = GetContextRef(); - if(!context) return; - - alSetError(context, AL_INVALID_OPERATION, "alGetBufferSamplesSOFT not supported"); + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - ALCcontext_DecRef(context); + alSetError(context.get(), AL_INVALID_OPERATION, "alGetBufferSamplesSOFT not supported"); } AL_API ALboolean AL_APIENTRY alIsBufferFormatSupportedSOFT(ALenum UNUSED(format)) { - ALCcontext *context; - - context = GetContextRef(); + ContextRef context{GetContextRef()}; if(!context) return AL_FALSE; - alSetError(context, AL_INVALID_OPERATION, "alIsBufferFormatSupportedSOFT not supported"); - - ALCcontext_DecRef(context); + 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)) { - ALCdevice *device; - ALCcontext *context; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - context = GetContextRef(); - if(!context) return; + ALCdevice *device = context->Device; + std::lock_guard<almtx_t> _{device->BufferLock}; - device = context->Device; - LockBufferList(device); - if(UNLIKELY(LookupBuffer(device, buffer) == NULL)) - alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else switch(param) { default: - alSetError(context, AL_INVALID_ENUM, "Invalid buffer float property 0x%04x", param); + alSetError(context.get(), 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; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - context = GetContextRef(); - if(!context) return; + ALCdevice *device = context->Device; + std::lock_guard<almtx_t> _{device->BufferLock}; - device = context->Device; - LockBufferList(device); - if(UNLIKELY(LookupBuffer(device, buffer) == NULL)) - alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) + alSetError(context.get(), 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); + alSetError(context.get(), 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; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - context = GetContextRef(); - if(!context) return; + ALCdevice *device = context->Device; + std::lock_guard<almtx_t> _{device->BufferLock}; - device = context->Device; - LockBufferList(device); - if(UNLIKELY(LookupBuffer(device, buffer) == NULL)) - alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) + alSetError(context.get(), AL_INVALID_NAME, "Invalid buffer ID %u", buffer); else if(UNLIKELY(!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 buffer float-vector property 0x%04x", param); + alSetError(context.get(), 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; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - context = GetContextRef(); - if(!context) return; + ALCdevice *device = context->Device; + std::lock_guard<almtx_t> _{device->BufferLock}; - device = context->Device; - LockBufferList(device); - if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL)) - alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + 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, AL_INVALID_VALUE, "Invalid unpack block alignment %d", value); + 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, AL_INVALID_VALUE, "Invalid pack block alignment %d", value); + alSetError(context.get(), 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); + alSetError(context.get(), 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; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - context = GetContextRef(); - if(!context) return; + ALCdevice *device = context->Device; + std::lock_guard<almtx_t> _{device->BufferLock}; - device = context->Device; - LockBufferList(device); - if(UNLIKELY(LookupBuffer(device, buffer) == NULL)) - alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + if(UNLIKELY(LookupBuffer(device, buffer) == nullptr)) + alSetError(context.get(), 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); + alSetError(context.get(), 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; + case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: + case AL_PACK_BLOCK_ALIGNMENT_SOFT: + alBufferi(buffer, param, values[0]); + return; } } - context = GetContextRef(); - if(!context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - device = context->Device; - LockBufferList(device); - if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL)) - alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + ALCdevice *device = context->Device; + std::lock_guard<almtx_t> _{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, AL_INVALID_VALUE, "NULL pointer"); + alSetError(context.get(), 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", + 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, AL_INVALID_VALUE, "Invalid loop point range %d -> %d o buffer %u", + alSetError(context.get(), AL_INVALID_VALUE, "Invalid loop point range %d -> %d o buffer %u", values[0], values[1], buffer); else { @@ -630,71 +926,55 @@ AL_API void AL_APIENTRY alBufferiv(ALuint buffer, ALenum param, const ALint *val break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x", + alSetError(context.get(), 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; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - context = GetContextRef(); - if(!context) return; + ALCdevice *device = context->Device; + std::lock_guard<almtx_t> _{device->BufferLock}; - device = context->Device; - LockBufferList(device); - if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL)) - alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + 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, AL_INVALID_VALUE, "NULL pointer"); + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else switch(param) { default: - alSetError(context, AL_INVALID_ENUM, "Invalid buffer float property 0x%04x", param); + alSetError(context.get(), 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; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - context = GetContextRef(); - if(!context) return; + ALCdevice *device = context->Device; + std::lock_guard<almtx_t> _{device->BufferLock}; - device = context->Device; - LockBufferList(device); - if(UNLIKELY(LookupBuffer(device, buffer) == NULL)) - alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + 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, AL_INVALID_VALUE, "NULL pointer"); + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else switch(param) { default: - alSetError(context, AL_INVALID_ENUM, "Invalid buffer 3-float property 0x%04x", param); + alSetError(context.get(), 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: @@ -702,41 +982,37 @@ AL_API void AL_APIENTRY alGetBufferfv(ALuint buffer, ALenum param, ALfloat *valu return; } - context = GetContextRef(); - if(!context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - device = context->Device; - LockBufferList(device); - if(UNLIKELY(LookupBuffer(device, buffer) == NULL)) - alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + ALCdevice *device = context->Device; + std::lock_guard<almtx_t> _{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, AL_INVALID_VALUE, "NULL pointer"); + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else switch(param) { default: - alSetError(context, AL_INVALID_ENUM, "Invalid buffer float-vector property 0x%04x", param); + alSetError(context.get(), 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; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - context = GetContextRef(); - if(!context) return; + ALCdevice *device = context->Device; + std::lock_guard<almtx_t> _{device->BufferLock}; - device = context->Device; - LockBufferList(device); - if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL)) - alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + 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, AL_INVALID_VALUE, "NULL pointer"); + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else switch(param) { case AL_FREQUENCY: @@ -765,45 +1041,33 @@ AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid buffer integer property 0x%04x", param); + alSetError(context.get(), 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; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - context = GetContextRef(); - if(!context) return; + ALCdevice *device = context->Device; + std::lock_guard<almtx_t> _{device->BufferLock}; - device = context->Device; - LockBufferList(device); - if(UNLIKELY(LookupBuffer(device, buffer) == NULL)) - alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + 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, AL_INVALID_VALUE, "NULL pointer"); + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else switch(param) { default: - alSetError(context, AL_INVALID_ENUM, "Invalid buffer 3-integer property 0x%04x", param); + alSetError(context.get(), 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: @@ -819,15 +1083,17 @@ AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values return; } - context = GetContextRef(); - if(!context) return; + ContextRef context{GetContextRef()}; + if(UNLIKELY(!context)) return; - device = context->Device; - LockBufferList(device); - if(UNLIKELY((albuf=LookupBuffer(device, buffer)) == NULL)) - alSetError(context, AL_INVALID_NAME, "Invalid buffer ID %u", buffer); + ALCdevice *device = context->Device; + std::lock_guard<almtx_t> _{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, AL_INVALID_VALUE, "NULL pointer"); + alSetError(context.get(), AL_INVALID_VALUE, "NULL pointer"); else switch(param) { case AL_LOOP_POINTS_SOFT: @@ -836,194 +1102,13 @@ AL_API void AL_APIENTRY alGetBufferiv(ALuint buffer, ALenum param, ALint *values break; default: - alSetError(context, AL_INVALID_ENUM, "Invalid buffer integer-vector property 0x%04x", + alSetError(context.get(), 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 "<internal type error>"; -} - -/* - * 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) +ALsizei BytesFromUserFmt(UserFmtType type) { switch(type) { @@ -1038,7 +1123,7 @@ ALsizei BytesFromUserFmt(enum UserFmtType type) } return 0; } -ALsizei ChannelsFromUserFmt(enum UserFmtChannels chans) +ALsizei ChannelsFromUserFmt(UserFmtChannels chans) { switch(chans) { @@ -1054,86 +1139,8 @@ ALsizei ChannelsFromUserFmt(enum UserFmtChannels chans) } 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) +ALsizei BytesFromFmt(FmtType type) { switch(type) { @@ -1146,7 +1153,7 @@ ALsizei BytesFromFmt(enum FmtType type) } return 0; } -ALsizei ChannelsFromFmt(enum FmtChannels chans) +ALsizei ChannelsFromFmt(FmtChannels chans) { switch(chans) { @@ -1163,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 = 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)<<slidx); - almtx_unlock(&device->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() @@ -1301,5 +1198,5 @@ ALvoid ReleaseALBuffers(ALCdevice *device) sublist->FreeMask = ~usemask; } if(leftover > 0) - WARN("(%p) Deleted "SZFMT" Buffer%s\n", device, leftover, (leftover==1)?"":"s"); + WARN("(%p) Deleted " SZFMT " Buffer%s\n", device, leftover, (leftover==1)?"":"s"); } 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..1f76a069 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) < 1) 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 { @@ -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 { @@ -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); @@ -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); @@ -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/appveyor.yml b/appveyor.yml index 6d826eed..010a2da1 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: 1.19.0.{build} +version: 1.19.1.{build} environment: matrix: @@ -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 diff --git a/common/align.h b/common/align.h index e2dc81df..53a5806a 100644 --- a/common/align.h +++ b/common/align.h @@ -5,11 +5,8 @@ #include <stdalign.h> #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(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 diff --git a/common/atomic.h b/common/atomic.h index 39daa1dc..17e616bb 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 <atomic> + +#define _Atomic(T) std::atomic<T> +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 <stdatomic.h> +#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 <stdatomic.h> - #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 @@ -119,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" \ @@ -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 diff --git a/common/bool.h b/common/bool.h index 6f714d09..eb1d9174 100644 --- a/common/bool.h +++ b/common/bool.h @@ -5,7 +5,7 @@ #include <stdbool.h> #endif -#ifndef bool +#if !defined(bool) && !defined(__cplusplus) #ifdef HAVE_C99_BOOL #define bool _Bool #else 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)) 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 <assert.h> -#ifndef static_assert +#if !defined(static_assert) && !defined(__cplusplus) #ifdef HAVE_C11_STATIC_ASSERT #define static_assert _Static_assert #else 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..7fbe20cd 100644 --- a/common/threads.h +++ b/common/threads.h @@ -130,13 +130,21 @@ inline int altss_set(altss_t tss_id, void *val) #include <stdint.h> #include <errno.h> #include <pthread.h> +#ifdef __APPLE__ +#include <dispatch/dispatch.h> +#else /* !__APPLE__ */ #include <semaphore.h> +#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; @@ -254,7 +262,66 @@ int altimespec_get(struct timespec *ts, int base); void al_nssleep(unsigned long nsec); #ifdef __cplusplus -} +} // extern "C" + +#include <mutex> + +/* 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> { + 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> { + 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 */ 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/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 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/al.c b/router/al.cpp index 8dd888d9..4c8b0006 100644 --- a/router/al.c +++ b/router/al.cpp @@ -7,36 +7,36 @@ #include "router.h" -atomic_DriverIfacePtr CurrentCtxDriver = ATOMIC_INIT_STATIC(NULL); +std::atomic<DriverIface*> CurrentCtxDriver{nullptr}; #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);\ + 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 = 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 = 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 = 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 = 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 = 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.c b/router/alc.cpp index 946c7d4c..c129198a 100644 --- a/router/alc.c +++ b/router/alc.cpp @@ -6,18 +6,20 @@ #include <string.h> #include <stdio.h> +#include <mutex> +#include <algorithm> +#include <array> + #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 { +#define DECL(x) { #x, reinterpret_cast<void*>(x) } +struct FuncExportEntry { const ALCchar *funcName; ALCvoid *address; -} alcFunctions[] = { +}; +static const std::array<FuncExportEntry,95> alcFunctions{{ DECL(alcCreateContext), DECL(alcMakeContextCurrent), DECL(alcProcessContext), @@ -115,14 +117,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<EnumExportEntry,92> alcEnumerations{{ DECL(ALC_INVALID), DECL(ALC_FALSE), DECL(ALC_TRUE), @@ -228,7 +231,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"; @@ -245,77 +248,54 @@ 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 PtrIntMap DeviceIfaceMap = PTRINTMAP_STATIC_INITIALIZE; -static PtrIntMap ContextIfaceMap = PTRINTMAP_STATIC_INITIALIZE; +static std::atomic<ALCenum> LastError{ALC_NO_ERROR}; +static PtrIntMap DeviceIfaceMap; +static PtrIntMap ContextIfaceMap; 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; + std::vector<ALCchar> Names; + std::vector<ALCint> Indicies; - al_free(list->Indicies); - list->Indicies = NULL; - 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 = 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; + 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) { @@ -327,30 +307,11 @@ static ALint GetDriverIndexForName(const EnumeratedList *list, const ALCchar *na 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; + ALCdevice *device = nullptr; + 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 @@ -360,51 +321,51 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename) strcmp(devicename, "DirectSound3D") == 0 || strcmp(devicename, "DirectSound") == 0 || strcmp(devicename, "MMSYSTEM") == 0)) - devicename = NULL; + devicename = nullptr; 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); + { std::lock_guard<std::mutex> _{EnumerationLock}; + if(DevicesList.Names.empty()) + (void)alcGetString(nullptr, ALC_DEVICE_SPECIFIER); + idx = GetDriverIndexForName(&DevicesList, devicename); + if(idx < 0) + { + if(AllDevicesList.Names.empty()) + (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 NULL; + 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++) + for(const auto &drv : DriverList) { - if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || - DriverList[i].alcIsExtensionPresent(NULL, "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(NULL); + device = drv.alcOpenDevice(nullptr); break; } + ++idx; } } if(device) { - if(InsertPtrIntMapEntry(&DeviceIfaceMap, device, idx) != ALC_NO_ERROR) + if(DeviceIfaceMap.insert(device, idx) != ALC_NO_ERROR) { DriverList[idx].alcCloseDevice(device); - device = NULL; + device = nullptr; } } @@ -415,14 +376,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) { - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + 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; } @@ -432,18 +393,18 @@ 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) { - 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) { - if(InsertPtrIntMapEntry(&ContextIfaceMap, context, idx) != ALC_NO_ERROR) + if(ContextIfaceMap.insert(context, idx) != ALC_NO_ERROR) { DriverList[idx].alcDestroyContext(context); - context = NULL; + context = nullptr; } } @@ -454,21 +415,17 @@ ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context) { ALint idx = -1; - almtx_lock(&ContextSwitchLock); + std::lock_guard<std::mutex> _{ContextSwitchLock}; if(context) { - idx = LookupPtrIntMapKey(&ContextIfaceMap, context); + idx = ContextIfaceMap.lookupByKey(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 @@ -476,22 +433,21 @@ ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context) */ 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); + DriverIface *oldiface = ThreadCtxDriver; + if(oldiface) oldiface->alcSetThreadContext(nullptr); + oldiface = CurrentCtxDriver.exchange(nullptr); + if(oldiface) oldiface->alcMakeContextCurrent(nullptr); } else { - DriverIface *oldiface = altss_get(ThreadCtxDriver); + DriverIface *oldiface = ThreadCtxDriver; if(oldiface && oldiface != &DriverList[idx]) - oldiface->alcSetThreadContext(NULL); - oldiface = ATOMIC_EXCHANGE_PTR_SEQ(&CurrentCtxDriver, &DriverList[idx]); + oldiface->alcSetThreadContext(nullptr); + oldiface = CurrentCtxDriver.exchange(&DriverList[idx]); if(oldiface && oldiface != &DriverList[idx]) - oldiface->alcMakeContextCurrent(NULL); + oldiface->alcMakeContextCurrent(nullptr); } - almtx_unlock(&ContextSwitchLock); - altss_set(ThreadCtxDriver, NULL); + ThreadCtxDriver = nullptr; return ALC_TRUE; } @@ -500,55 +456,55 @@ 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); } - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT); + LastError.store(ALC_INVALID_CONTEXT); } 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); } - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT); + LastError.store(ALC_INVALID_CONTEXT); } ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context) { ALint idx; - if(!context || (idx=LookupPtrIntMapKey(&ContextIfaceMap, context)) < 0) + if(!context || (idx=ContextIfaceMap.lookupByKey(context)) < 0) { - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT); + LastError.store(ALC_INVALID_CONTEXT); return; } DriverList[idx].alcDestroyContext(context); - RemovePtrIntMapKey(&ContextIfaceMap, context); + ContextIfaceMap.removeByKey(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; + DriverIface *iface = ThreadCtxDriver; + if(!iface) iface = CurrentCtxDriver.load(); + return iface ? iface->alcGetCurrentContext() : nullptr; } 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); } - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT); - return NULL; + LastError.store(ALC_INVALID_CONTEXT); + return nullptr; } @@ -556,11 +512,11 @@ 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); } - 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) @@ -570,10 +526,10 @@ 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) { - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + LastError.store(ALC_INVALID_DEVICE); return ALC_FALSE; } return DriverList[idx].alcIsExtensionPresent(device, extname); @@ -585,7 +541,7 @@ ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const A { if(strncasecmp(ptr, extname, len) == 0 && (ptr[len] == '\0' || isspace(ptr[len]))) return ALC_TRUE; - if((ptr=strchr(ptr, ' ')) != NULL) + if((ptr=strchr(ptr, ' ')) != nullptr) { do { ++ptr; @@ -597,61 +553,53 @@ 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); + ALint idx = DeviceIfaceMap.lookupByKey(device); if(idx < 0) { - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); - return NULL; + LastError.store(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 NULL; + 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); + ALint idx = DeviceIfaceMap.lookupByKey(device); if(idx < 0) { - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + LastError.store(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; + 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) { - ALsizei i = 0; - if(device) { - ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + ALint idx = DeviceIfaceMap.lookupByKey(device); if(idx < 0) { - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); - return NULL; + LastError.store(ALC_INVALID_DEVICE); + return nullptr; } return DriverList[idx].alcGetString(device, param); } @@ -674,104 +622,135 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum para return alcExtensionList; case ALC_DEVICE_SPECIFIER: - almtx_lock(&EnumerationLock); - ClearDeviceList(&DevicesList); - for(i = 0;i < DriverListSize;i++) + { std::lock_guard<std::mutex> _{EnumerationLock}; + 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(NULL, "ALC_ENUMERATION_EXT")) + if(drv.ALCVer >= MAKE_ALC_VER(1, 1) || + drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT")) AppendDeviceList(&DevicesList, - DriverList[i].alcGetString(NULL, ALC_DEVICE_SPECIFIER), i + drv.alcGetString(nullptr, ALC_DEVICE_SPECIFIER), idx ); + idx++; } - almtx_unlock(&EnumerationLock); - 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: - almtx_lock(&EnumerationLock); - ClearDeviceList(&AllDevicesList); - for(i = 0;i < DriverListSize;i++) + { std::lock_guard<std::mutex> _{EnumerationLock}; + 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(NULL, "ALC_ENUMERATE_ALL_EXT")) + if(drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT")) AppendDeviceList(&AllDevicesList, - DriverList[i].alcGetString(NULL, 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(NULL, "ALC_ENUMERATION_EXT")) + else if(drv.ALCVer >= MAKE_ALC_VER(1, 1) || + drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT")) AppendDeviceList(&AllDevicesList, - DriverList[i].alcGetString(NULL, ALC_DEVICE_SPECIFIER), i + drv.alcGetString(nullptr, ALC_DEVICE_SPECIFIER), idx ); + ++idx; } - almtx_unlock(&EnumerationLock); - 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: - almtx_lock(&EnumerationLock); - ClearDeviceList(&CaptureDevicesList); - for(i = 0;i < DriverListSize;i++) + { std::lock_guard<std::mutex> _{EnumerationLock}; + CaptureDevicesList.clear(); + ALint idx = 0; + for(const auto &drv : DriverList) { - if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || - DriverList[i].alcIsExtensionPresent(NULL, "ALC_EXT_CAPTURE")) + if(drv.ALCVer >= MAKE_ALC_VER(1, 1) || + drv.alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE")) AppendDeviceList(&CaptureDevicesList, - DriverList[i].alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER), i + drv.alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER), idx ); + ++idx; } - almtx_unlock(&EnumerationLock); - 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(NULL, "ALC_ENUMERATION_EXT")) - return DriverList[i].alcGetString(NULL, 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(NULL, "ALC_ENUMERATE_ALL_EXT")) - return DriverList[i].alcGetString(NULL, 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(NULL, "ALC_EXT_CAPTURE")) - return DriverList[i].alcGetString(NULL, 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: - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_ENUM); + LastError.store(ALC_INVALID_ENUM); break; } - return NULL; + return nullptr; } ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values) { if(device) { - ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + ALint idx = DeviceIfaceMap.lookupByKey(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); } - if(size <= 0 || values == NULL) + if(size <= 0 || values == nullptr) { - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_VALUE); + LastError.store(ALC_INVALID_VALUE); return; } @@ -790,7 +769,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: @@ -801,11 +780,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; } } @@ -813,23 +792,24 @@ 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 = NULL; - ALint idx; + ALCdevice *device = nullptr; + ALint idx = 0; if(devicename && devicename[0] == '\0') - devicename = NULL; + devicename = nullptr; if(devicename) { - almtx_lock(&EnumerationLock); - if(!CaptureDevicesList.Names) - (void)alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); - idx = GetDriverIndexForName(&CaptureDevicesList, devicename); - almtx_unlock(&EnumerationLock); + { std::lock_guard<std::mutex> _{EnumerationLock}; + if(CaptureDevicesList.Names.empty()) + (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 NULL; + return nullptr; } TRACE("Found driver %d for name \"%s\"\n", idx, devicename); device = DriverList[idx].alcCaptureOpenDevice( @@ -838,28 +818,27 @@ 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(NULL, "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( - NULL, frequency, format, buffersize + device = drv.alcCaptureOpenDevice( + nullptr, frequency, format, buffersize ); break; } + ++idx; } } if(device) { - if(InsertPtrIntMapEntry(&DeviceIfaceMap, device, idx) != ALC_NO_ERROR) + if(DeviceIfaceMap.insert(device, idx) != ALC_NO_ERROR) { DriverList[idx].alcCaptureCloseDevice(device); - device = NULL; + device = nullptr; } } @@ -870,14 +849,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) { - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + 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; } @@ -885,33 +864,33 @@ 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); } - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + LastError.store(ALC_INVALID_DEVICE); } 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); } - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + LastError.store(ALC_INVALID_DEVICE); } ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples) { if(device) { - ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + ALint idx = DeviceIfaceMap.lookupByKey(device); if(idx >= 0) return DriverList[idx].alcCaptureSamples(device, buffer, samples); } - ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + LastError.store(ALC_INVALID_DEVICE); } @@ -922,35 +901,35 @@ ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context) if(!context) { - DriverIface *oldiface = altss_get(ThreadCtxDriver); - if(oldiface && !oldiface->alcSetThreadContext(NULL)) + DriverIface *oldiface = ThreadCtxDriver; + if(oldiface && !oldiface->alcSetThreadContext(nullptr)) return ALC_FALSE; - altss_set(ThreadCtxDriver, NULL); + ThreadCtxDriver = nullptr; return ALC_TRUE; } - idx = LookupPtrIntMapKey(&ContextIfaceMap, context); + idx = ContextIfaceMap.lookupByKey(context); if(idx >= 0) { if(DriverList[idx].alcSetThreadContext(context)) { - DriverIface *oldiface = altss_get(ThreadCtxDriver); + DriverIface *oldiface = ThreadCtxDriver; if(oldiface != &DriverList[idx]) { - altss_set(ThreadCtxDriver, &DriverList[idx]); - if(oldiface) oldiface->alcSetThreadContext(NULL); + ThreadCtxDriver = &DriverList[idx]; + if(oldiface) oldiface->alcSetThreadContext(nullptr); } return ALC_TRUE; } - err = DriverList[idx].alcGetError(NULL); + 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 = altss_get(ThreadCtxDriver); + DriverIface *iface = ThreadCtxDriver; if(iface) return iface->alcGetThreadContext(); - return NULL; + return nullptr; } diff --git a/router/router.c b/router/router.cpp index bff73776..66bf5dd3 100644 --- a/router/router.c +++ b/router/router.cpp @@ -13,12 +13,9 @@ #include "version.h" +std::vector<DriverIface> DriverList; -DriverIface *DriverList = NULL; -int DriverListSize = 0; -static int DriverListSizeMax = 0; - -altss_t ThreadCtxDriver; +thread_local DriverIface *ThreadCtxDriver; enum LogLevel LogLevel = LogLevel_Error; FILE *LogFile; @@ -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) { @@ -39,7 +35,7 @@ BOOL APIENTRY DllMain(HINSTANCE UNUSED(module), DWORD reason, void* UNUSED(reser if(str && *str != '\0') { FILE *f = fopen(str, "w"); - if(f == NULL) + if(f == nullptr) ERR("Could not open log file: %s\n", str); else LogFile = f; @@ -47,74 +43,49 @@ BOOL APIENTRY DllMain(HINSTANCE UNUSED(module), DWORD reason, void* UNUSED(reser str = getenv("ALROUTER_LOGLEVEL"); if(str && *str != '\0') { - char *end = NULL; + 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 = l; + LogLevel = static_cast<enum 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; + DriverList.clear(); if(LogFile && LogFile != stderr) fclose(LogFile); - LogFile = NULL; + 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++) + 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(drv.Name == name) { TRACE("Skipping similarly-named module %ls\n", name); FreeLibrary(module); @@ -122,22 +93,14 @@ 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 = newlist; - DriverListSizeMax = newmax; - } + DriverList.emplace_back(name, module); + DriverIface &newdrv = DriverList.back(); - memset(&newdrv, 0, sizeof(newdrv)); /* Load required functions. */ + int err = 0; #define LOAD_PROC(x) do { \ - newdrv.x = CAST_FUNC(newdrv.x) GetProcAddress(module, #x); \ + newdrv.x = reinterpret_cast<decltype(newdrv.x)>( \ + GetProcAddress(module, #x)); \ if(!newdrv.x) \ { \ ERR("Failed to find entry point for %s in %ls\n", #x, name); \ @@ -241,63 +204,62 @@ static void AddModule(HMODULE module, const WCHAR *name) 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.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 = CAST_FUNC(newdrv.x) newdrv.alcGetProcAddress(NULL, #x); \ + newdrv.x = reinterpret_cast<decltype(newdrv.x)>( \ + 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(NULL, "ALC_EXT_thread_local_context")) + if(newdrv.alcIsExtensionPresent(nullptr, "ALC_EXT_thread_local_context")) { LOAD_PROC(alcSetThreadContext); LOAD_PROC(alcGetThreadContext); } } - 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 } 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)); @@ -307,7 +269,7 @@ static void SearchDrivers(WCHAR *path) static WCHAR *strrchrW(WCHAR *str, WCHAR ch) { - WCHAR *res = NULL; + WCHAR *res = nullptr; while(str && *str != '\0') { if(*str == ch) @@ -319,7 +281,7 @@ static WCHAR *strrchrW(WCHAR *str, WCHAR ch) static int GetLoadedModuleDirectory(const WCHAR *name, WCHAR *moddir, DWORD length) { - HMODULE module = NULL; + HMODULE module = nullptr; WCHAR *sep0, *sep1; if(name) @@ -359,7 +321,7 @@ void LoadDriverList(void) cwd_path[len-1] = '\0'; TRACE("Got current working directory %ls\n", cwd_path); - if(GetLoadedModuleDirectory(NULL, proc_path, MAX_PATH)) + if(GetLoadedModuleDirectory(nullptr, proc_path, MAX_PATH)) TRACE("Got proc path %ls\n", proc_path); GetSystemDirectoryW(sys_path, MAX_PATH); @@ -388,38 +350,28 @@ void LoadDriverList(void) } -void InitPtrIntMap(PtrIntMap *map) -{ - map->keys = NULL; - map->values = NULL; - map->size = 0; - map->capacity = 0; - RWLockInit(&map->lock); -} - -void ResetPtrIntMap(PtrIntMap *map) +PtrIntMap::~PtrIntMap() { - WriteLock(&map->lock); - al_free(map->keys); - map->keys = NULL; - map->values = NULL; - map->size = 0; - map->capacity = 0; - WriteUnlock(&map->lock); + std::lock_guard<std::mutex> 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<std::mutex> 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 { @@ -429,63 +381,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 = NULL; - ALint *values; + ALvoid **newkeys = nullptr; + ALint *newvalues; 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); + newcap = (mCapacity ? (mCapacity<<1) : 4); + if(newcap > mCapacity) + newkeys = reinterpret_cast<ALvoid**>( + al_calloc(16, (sizeof(mKeys[0])+sizeof(mValues[0]))*newcap) + ); + 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<std::mutex> 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 { @@ -493,35 +442,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<std::mutex> 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 { @@ -529,9 +476,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 32a91dcb..d2574e74 100644 --- a/router/router.h +++ b/router/router.h @@ -7,12 +7,14 @@ #include <stdio.h> +#include <vector> +#include <string> +#include <atomic> +#include <mutex> + #include "AL/alc.h" #include "AL/al.h" #include "AL/alext.h" -#include "atomic.h" -#include "rwlock.h" -#include "threads.h" #ifndef UNUSED @@ -29,138 +31,143 @@ #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; -} DriverIface; - -extern DriverIface *DriverList; -extern int DriverListSize; - -extern altss_t ThreadCtxDriver; -typedef ATOMIC(DriverIface*) atomic_DriverIfacePtr; -extern atomic_DriverIfacePtr CurrentCtxDriver; - - -typedef struct PtrIntMap { - ALvoid **keys; - /* Shares memory with keys. */ - ALint *values; +struct DriverIface { + 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(std::wstring name, HMODULE mod) + : Name(std::move(name)), Module(mod) + { } + ~DriverIface() + { + if(Module) + FreeLibrary(Module); + Module = nullptr; + } +}; + +extern std::vector<DriverIface> DriverList; - ALsizei size; - ALsizei capacity; - RWLock lock; -} PtrIntMap; -#define PTRINTMAP_STATIC_INITIALIZE { NULL, NULL, 0, 0, RWLOCK_STATIC_INITIALIZE } +extern thread_local DriverIface *ThreadCtxDriver; +extern std::atomic<DriverIface*> CurrentCtxDriver; -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); +class PtrIntMap { + ALvoid **mKeys{nullptr}; + /* Shares memory with keys. */ + ALint *mValues{nullptr}; + + ALsizei mSize{0}; + ALsizei mCapacity{0}; + std::mutex mLock; -void InitALC(void); -void ReleaseALC(void); +public: + PtrIntMap() = default; + ~PtrIntMap(); + + ALenum insert(ALvoid *key, ALint value); + ALint removeByKey(ALvoid *key); + ALint lookupByKey(ALvoid *key); +}; enum LogLevel { 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); 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; |