diff options
Diffstat (limited to 'alc/alc.cpp')
-rw-r--r-- | alc/alc.cpp | 1253 |
1 files changed, 317 insertions, 936 deletions
diff --git a/alc/alc.cpp b/alc/alc.cpp index af8ff55d..6017e743 100644 --- a/alc/alc.cpp +++ b/alc/alc.cpp @@ -38,6 +38,7 @@ #include <climits> #include <cmath> #include <csignal> +#include <cstddef> #include <cstdint> #include <cstdio> #include <cstdlib> @@ -48,11 +49,13 @@ #include <memory> #include <mutex> #include <new> +#include <optional> #include <stddef.h> #include <stdexcept> #include <string> #include <type_traits> #include <utility> +#include <vector> #include "AL/al.h" #include "AL/alc.h" @@ -61,16 +64,16 @@ #include "al/auxeffectslot.h" #include "al/buffer.h" +#include "al/debug.h" #include "al/effect.h" #include "al/filter.h" #include "al/listener.h" #include "al/source.h" +#include "alc/events.h" #include "albit.h" -#include "albyte.h" #include "alconfig.h" #include "almalloc.h" #include "alnumeric.h" -#include "aloptional.h" #include "alspan.h" #include "alstring.h" #include "alu.h" @@ -96,12 +99,11 @@ #include "core/voice_change.h" #include "device.h" #include "effects/base.h" +#include "export_list.h" #include "inprogext.h" #include "intrusive_ptr.h" #include "opthelpers.h" #include "strutils.h" -#include "threads.h" -#include "vector.h" #include "backends/base.h" #include "backends/null.h" @@ -161,13 +163,6 @@ #endif // ALSOFT_EAX -FILE *gLogFile{stderr}; -#ifdef _DEBUG -LogLevel gLogLevel{LogLevel::Warning}; -#else -LogLevel gLogLevel{LogLevel::Error}; -#endif - /************************************************ * Library initialization ************************************************/ @@ -179,7 +174,7 @@ BOOL APIENTRY DllMain(HINSTANCE module, DWORD reason, LPVOID /*reserved*/) case DLL_PROCESS_ATTACH: /* Pin the DLL so we won't get unloaded until the process terminates */ GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_PIN | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, - reinterpret_cast<WCHAR*>(module), &module); + al::bit_cast<WCHAR*>(module), &module); break; } return TRUE; @@ -261,673 +256,6 @@ BackendFactory *PlaybackFactory{}; BackendFactory *CaptureFactory{}; -/************************************************ - * Functions, enums, and errors - ************************************************/ -#define DECL(x) { #x, reinterpret_cast<void*>(x) } -const struct { - const char *funcName; - void *address; -} alcFunctions[] = { - DECL(alcCreateContext), - DECL(alcMakeContextCurrent), - DECL(alcProcessContext), - DECL(alcSuspendContext), - DECL(alcDestroyContext), - DECL(alcGetCurrentContext), - DECL(alcGetContextsDevice), - DECL(alcOpenDevice), - DECL(alcCloseDevice), - DECL(alcGetError), - DECL(alcIsExtensionPresent), - DECL(alcGetProcAddress), - DECL(alcGetEnumValue), - DECL(alcGetString), - DECL(alcGetIntegerv), - DECL(alcCaptureOpenDevice), - DECL(alcCaptureCloseDevice), - DECL(alcCaptureStart), - DECL(alcCaptureStop), - DECL(alcCaptureSamples), - - DECL(alcSetThreadContext), - DECL(alcGetThreadContext), - - DECL(alcLoopbackOpenDeviceSOFT), - DECL(alcIsRenderFormatSupportedSOFT), - DECL(alcRenderSamplesSOFT), - - DECL(alcDevicePauseSOFT), - DECL(alcDeviceResumeSOFT), - - DECL(alcGetStringiSOFT), - DECL(alcResetDeviceSOFT), - - DECL(alcGetInteger64vSOFT), - - DECL(alcReopenDeviceSOFT), - - DECL(alEnable), - DECL(alDisable), - DECL(alIsEnabled), - DECL(alGetString), - DECL(alGetBooleanv), - DECL(alGetIntegerv), - DECL(alGetFloatv), - DECL(alGetDoublev), - DECL(alGetBoolean), - DECL(alGetInteger), - DECL(alGetFloat), - DECL(alGetDouble), - DECL(alGetError), - DECL(alIsExtensionPresent), - DECL(alGetProcAddress), - DECL(alGetEnumValue), - DECL(alListenerf), - DECL(alListener3f), - DECL(alListenerfv), - DECL(alListeneri), - DECL(alListener3i), - DECL(alListeneriv), - DECL(alGetListenerf), - DECL(alGetListener3f), - DECL(alGetListenerfv), - DECL(alGetListeneri), - DECL(alGetListener3i), - DECL(alGetListeneriv), - DECL(alGenSources), - DECL(alDeleteSources), - DECL(alIsSource), - DECL(alSourcef), - DECL(alSource3f), - DECL(alSourcefv), - DECL(alSourcei), - DECL(alSource3i), - DECL(alSourceiv), - DECL(alGetSourcef), - DECL(alGetSource3f), - DECL(alGetSourcefv), - DECL(alGetSourcei), - DECL(alGetSource3i), - DECL(alGetSourceiv), - DECL(alSourcePlayv), - DECL(alSourceStopv), - DECL(alSourceRewindv), - DECL(alSourcePausev), - DECL(alSourcePlay), - DECL(alSourceStop), - DECL(alSourceRewind), - DECL(alSourcePause), - DECL(alSourceQueueBuffers), - DECL(alSourceUnqueueBuffers), - DECL(alGenBuffers), - DECL(alDeleteBuffers), - DECL(alIsBuffer), - DECL(alBufferData), - DECL(alBufferf), - DECL(alBuffer3f), - DECL(alBufferfv), - DECL(alBufferi), - DECL(alBuffer3i), - DECL(alBufferiv), - DECL(alGetBufferf), - DECL(alGetBuffer3f), - DECL(alGetBufferfv), - DECL(alGetBufferi), - DECL(alGetBuffer3i), - DECL(alGetBufferiv), - DECL(alDopplerFactor), - DECL(alDopplerVelocity), - DECL(alSpeedOfSound), - DECL(alDistanceModel), - - DECL(alGenFilters), - DECL(alDeleteFilters), - DECL(alIsFilter), - DECL(alFilteri), - DECL(alFilteriv), - DECL(alFilterf), - DECL(alFilterfv), - DECL(alGetFilteri), - DECL(alGetFilteriv), - DECL(alGetFilterf), - DECL(alGetFilterfv), - DECL(alGenEffects), - DECL(alDeleteEffects), - DECL(alIsEffect), - DECL(alEffecti), - DECL(alEffectiv), - DECL(alEffectf), - DECL(alEffectfv), - DECL(alGetEffecti), - DECL(alGetEffectiv), - DECL(alGetEffectf), - DECL(alGetEffectfv), - DECL(alGenAuxiliaryEffectSlots), - DECL(alDeleteAuxiliaryEffectSlots), - DECL(alIsAuxiliaryEffectSlot), - DECL(alAuxiliaryEffectSloti), - DECL(alAuxiliaryEffectSlotiv), - DECL(alAuxiliaryEffectSlotf), - DECL(alAuxiliaryEffectSlotfv), - DECL(alGetAuxiliaryEffectSloti), - DECL(alGetAuxiliaryEffectSlotiv), - DECL(alGetAuxiliaryEffectSlotf), - DECL(alGetAuxiliaryEffectSlotfv), - - DECL(alDeferUpdatesSOFT), - DECL(alProcessUpdatesSOFT), - - DECL(alSourcedSOFT), - DECL(alSource3dSOFT), - DECL(alSourcedvSOFT), - DECL(alGetSourcedSOFT), - DECL(alGetSource3dSOFT), - DECL(alGetSourcedvSOFT), - DECL(alSourcei64SOFT), - DECL(alSource3i64SOFT), - DECL(alSourcei64vSOFT), - DECL(alGetSourcei64SOFT), - DECL(alGetSource3i64SOFT), - DECL(alGetSourcei64vSOFT), - - DECL(alGetStringiSOFT), - - DECL(alBufferStorageSOFT), - DECL(alMapBufferSOFT), - DECL(alUnmapBufferSOFT), - DECL(alFlushMappedBufferSOFT), - - DECL(alEventControlSOFT), - DECL(alEventCallbackSOFT), - DECL(alGetPointerSOFT), - DECL(alGetPointervSOFT), - - DECL(alBufferCallbackSOFT), - DECL(alGetBufferPtrSOFT), - DECL(alGetBuffer3PtrSOFT), - DECL(alGetBufferPtrvSOFT), - - DECL(alAuxiliaryEffectSlotPlaySOFT), - DECL(alAuxiliaryEffectSlotPlayvSOFT), - DECL(alAuxiliaryEffectSlotStopSOFT), - DECL(alAuxiliaryEffectSlotStopvSOFT), - - DECL(alSourcePlayAtTimeSOFT), - DECL(alSourcePlayAtTimevSOFT), - - DECL(alBufferSubDataSOFT), - - DECL(alBufferDataStatic), -#ifdef ALSOFT_EAX -}, eaxFunctions[] = { - DECL(EAXGet), - DECL(EAXSet), - DECL(EAXGetBufferMode), - DECL(EAXSetBufferMode), -#endif -}; -#undef DECL - -#define DECL(x) { #x, (x) } -constexpr struct { - const ALCchar *enumName; - ALCenum value; -} alcEnumerations[] = { - DECL(ALC_INVALID), - DECL(ALC_FALSE), - DECL(ALC_TRUE), - - DECL(ALC_MAJOR_VERSION), - DECL(ALC_MINOR_VERSION), - DECL(ALC_ATTRIBUTES_SIZE), - DECL(ALC_ALL_ATTRIBUTES), - DECL(ALC_DEFAULT_DEVICE_SPECIFIER), - DECL(ALC_DEVICE_SPECIFIER), - DECL(ALC_ALL_DEVICES_SPECIFIER), - DECL(ALC_DEFAULT_ALL_DEVICES_SPECIFIER), - DECL(ALC_EXTENSIONS), - DECL(ALC_FREQUENCY), - DECL(ALC_REFRESH), - DECL(ALC_SYNC), - DECL(ALC_MONO_SOURCES), - DECL(ALC_STEREO_SOURCES), - DECL(ALC_CAPTURE_DEVICE_SPECIFIER), - DECL(ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER), - DECL(ALC_CAPTURE_SAMPLES), - DECL(ALC_CONNECTED), - - DECL(ALC_EFX_MAJOR_VERSION), - DECL(ALC_EFX_MINOR_VERSION), - DECL(ALC_MAX_AUXILIARY_SENDS), - - DECL(ALC_FORMAT_CHANNELS_SOFT), - DECL(ALC_FORMAT_TYPE_SOFT), - - DECL(ALC_MONO_SOFT), - DECL(ALC_STEREO_SOFT), - DECL(ALC_QUAD_SOFT), - DECL(ALC_5POINT1_SOFT), - DECL(ALC_6POINT1_SOFT), - DECL(ALC_7POINT1_SOFT), - DECL(ALC_BFORMAT3D_SOFT), - - DECL(ALC_BYTE_SOFT), - DECL(ALC_UNSIGNED_BYTE_SOFT), - DECL(ALC_SHORT_SOFT), - DECL(ALC_UNSIGNED_SHORT_SOFT), - DECL(ALC_INT_SOFT), - DECL(ALC_UNSIGNED_INT_SOFT), - DECL(ALC_FLOAT_SOFT), - - DECL(ALC_HRTF_SOFT), - DECL(ALC_DONT_CARE_SOFT), - DECL(ALC_HRTF_STATUS_SOFT), - DECL(ALC_HRTF_DISABLED_SOFT), - DECL(ALC_HRTF_ENABLED_SOFT), - DECL(ALC_HRTF_DENIED_SOFT), - DECL(ALC_HRTF_REQUIRED_SOFT), - DECL(ALC_HRTF_HEADPHONES_DETECTED_SOFT), - DECL(ALC_HRTF_UNSUPPORTED_FORMAT_SOFT), - DECL(ALC_NUM_HRTF_SPECIFIERS_SOFT), - DECL(ALC_HRTF_SPECIFIER_SOFT), - DECL(ALC_HRTF_ID_SOFT), - - DECL(ALC_AMBISONIC_LAYOUT_SOFT), - DECL(ALC_AMBISONIC_SCALING_SOFT), - DECL(ALC_AMBISONIC_ORDER_SOFT), - DECL(ALC_ACN_SOFT), - DECL(ALC_FUMA_SOFT), - DECL(ALC_N3D_SOFT), - DECL(ALC_SN3D_SOFT), - - DECL(ALC_OUTPUT_LIMITER_SOFT), - - DECL(ALC_DEVICE_CLOCK_SOFT), - DECL(ALC_DEVICE_LATENCY_SOFT), - DECL(ALC_DEVICE_CLOCK_LATENCY_SOFT), - DECL(AL_SAMPLE_OFFSET_CLOCK_SOFT), - DECL(AL_SEC_OFFSET_CLOCK_SOFT), - - DECL(ALC_OUTPUT_MODE_SOFT), - DECL(ALC_ANY_SOFT), - DECL(ALC_STEREO_BASIC_SOFT), - DECL(ALC_STEREO_UHJ_SOFT), - DECL(ALC_STEREO_HRTF_SOFT), - DECL(ALC_SURROUND_5_1_SOFT), - DECL(ALC_SURROUND_6_1_SOFT), - DECL(ALC_SURROUND_7_1_SOFT), - - DECL(ALC_NO_ERROR), - DECL(ALC_INVALID_DEVICE), - DECL(ALC_INVALID_CONTEXT), - DECL(ALC_INVALID_ENUM), - DECL(ALC_INVALID_VALUE), - DECL(ALC_OUT_OF_MEMORY), - - - DECL(AL_INVALID), - DECL(AL_NONE), - DECL(AL_FALSE), - DECL(AL_TRUE), - - DECL(AL_SOURCE_RELATIVE), - DECL(AL_CONE_INNER_ANGLE), - DECL(AL_CONE_OUTER_ANGLE), - DECL(AL_PITCH), - DECL(AL_POSITION), - DECL(AL_DIRECTION), - DECL(AL_VELOCITY), - DECL(AL_LOOPING), - DECL(AL_BUFFER), - DECL(AL_GAIN), - DECL(AL_MIN_GAIN), - DECL(AL_MAX_GAIN), - DECL(AL_ORIENTATION), - DECL(AL_REFERENCE_DISTANCE), - DECL(AL_ROLLOFF_FACTOR), - DECL(AL_CONE_OUTER_GAIN), - DECL(AL_MAX_DISTANCE), - DECL(AL_SEC_OFFSET), - DECL(AL_SAMPLE_OFFSET), - DECL(AL_BYTE_OFFSET), - DECL(AL_SOURCE_TYPE), - DECL(AL_STATIC), - DECL(AL_STREAMING), - DECL(AL_UNDETERMINED), - DECL(AL_METERS_PER_UNIT), - DECL(AL_LOOP_POINTS_SOFT), - DECL(AL_DIRECT_CHANNELS_SOFT), - - DECL(AL_DIRECT_FILTER), - DECL(AL_AUXILIARY_SEND_FILTER), - DECL(AL_AIR_ABSORPTION_FACTOR), - DECL(AL_ROOM_ROLLOFF_FACTOR), - DECL(AL_CONE_OUTER_GAINHF), - DECL(AL_DIRECT_FILTER_GAINHF_AUTO), - DECL(AL_AUXILIARY_SEND_FILTER_GAIN_AUTO), - DECL(AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO), - - DECL(AL_SOURCE_STATE), - DECL(AL_INITIAL), - DECL(AL_PLAYING), - DECL(AL_PAUSED), - DECL(AL_STOPPED), - - DECL(AL_BUFFERS_QUEUED), - DECL(AL_BUFFERS_PROCESSED), - - DECL(AL_FORMAT_MONO8), - DECL(AL_FORMAT_MONO16), - DECL(AL_FORMAT_MONO_FLOAT32), - DECL(AL_FORMAT_MONO_DOUBLE_EXT), - DECL(AL_FORMAT_STEREO8), - DECL(AL_FORMAT_STEREO16), - DECL(AL_FORMAT_STEREO_FLOAT32), - DECL(AL_FORMAT_STEREO_DOUBLE_EXT), - DECL(AL_FORMAT_MONO_IMA4), - DECL(AL_FORMAT_STEREO_IMA4), - DECL(AL_FORMAT_MONO_MSADPCM_SOFT), - DECL(AL_FORMAT_STEREO_MSADPCM_SOFT), - DECL(AL_FORMAT_QUAD8_LOKI), - DECL(AL_FORMAT_QUAD16_LOKI), - DECL(AL_FORMAT_QUAD8), - DECL(AL_FORMAT_QUAD16), - DECL(AL_FORMAT_QUAD32), - DECL(AL_FORMAT_51CHN8), - DECL(AL_FORMAT_51CHN16), - DECL(AL_FORMAT_51CHN32), - DECL(AL_FORMAT_61CHN8), - DECL(AL_FORMAT_61CHN16), - DECL(AL_FORMAT_61CHN32), - DECL(AL_FORMAT_71CHN8), - DECL(AL_FORMAT_71CHN16), - DECL(AL_FORMAT_71CHN32), - DECL(AL_FORMAT_REAR8), - DECL(AL_FORMAT_REAR16), - DECL(AL_FORMAT_REAR32), - DECL(AL_FORMAT_MONO_MULAW), - DECL(AL_FORMAT_MONO_MULAW_EXT), - DECL(AL_FORMAT_STEREO_MULAW), - DECL(AL_FORMAT_STEREO_MULAW_EXT), - DECL(AL_FORMAT_QUAD_MULAW), - DECL(AL_FORMAT_51CHN_MULAW), - DECL(AL_FORMAT_61CHN_MULAW), - DECL(AL_FORMAT_71CHN_MULAW), - DECL(AL_FORMAT_REAR_MULAW), - DECL(AL_FORMAT_MONO_ALAW_EXT), - DECL(AL_FORMAT_STEREO_ALAW_EXT), - - DECL(AL_FORMAT_BFORMAT2D_8), - DECL(AL_FORMAT_BFORMAT2D_16), - DECL(AL_FORMAT_BFORMAT2D_FLOAT32), - DECL(AL_FORMAT_BFORMAT2D_MULAW), - DECL(AL_FORMAT_BFORMAT3D_8), - DECL(AL_FORMAT_BFORMAT3D_16), - DECL(AL_FORMAT_BFORMAT3D_FLOAT32), - DECL(AL_FORMAT_BFORMAT3D_MULAW), - - DECL(AL_FREQUENCY), - DECL(AL_BITS), - DECL(AL_CHANNELS), - DECL(AL_SIZE), - DECL(AL_UNPACK_BLOCK_ALIGNMENT_SOFT), - DECL(AL_PACK_BLOCK_ALIGNMENT_SOFT), - - DECL(AL_SOURCE_RADIUS), - - DECL(AL_SAMPLE_OFFSET_LATENCY_SOFT), - DECL(AL_SEC_OFFSET_LATENCY_SOFT), - - DECL(AL_STEREO_ANGLES), - - DECL(AL_UNUSED), - DECL(AL_PENDING), - DECL(AL_PROCESSED), - - DECL(AL_NO_ERROR), - DECL(AL_INVALID_NAME), - DECL(AL_INVALID_ENUM), - DECL(AL_INVALID_VALUE), - DECL(AL_INVALID_OPERATION), - DECL(AL_OUT_OF_MEMORY), - - DECL(AL_VENDOR), - DECL(AL_VERSION), - DECL(AL_RENDERER), - DECL(AL_EXTENSIONS), - - DECL(AL_DOPPLER_FACTOR), - DECL(AL_DOPPLER_VELOCITY), - DECL(AL_DISTANCE_MODEL), - DECL(AL_SPEED_OF_SOUND), - DECL(AL_SOURCE_DISTANCE_MODEL), - DECL(AL_DEFERRED_UPDATES_SOFT), - DECL(AL_GAIN_LIMIT_SOFT), - - DECL(AL_INVERSE_DISTANCE), - DECL(AL_INVERSE_DISTANCE_CLAMPED), - DECL(AL_LINEAR_DISTANCE), - DECL(AL_LINEAR_DISTANCE_CLAMPED), - DECL(AL_EXPONENT_DISTANCE), - DECL(AL_EXPONENT_DISTANCE_CLAMPED), - - DECL(AL_FILTER_TYPE), - DECL(AL_FILTER_NULL), - DECL(AL_FILTER_LOWPASS), - DECL(AL_FILTER_HIGHPASS), - DECL(AL_FILTER_BANDPASS), - - DECL(AL_LOWPASS_GAIN), - DECL(AL_LOWPASS_GAINHF), - - DECL(AL_HIGHPASS_GAIN), - DECL(AL_HIGHPASS_GAINLF), - - DECL(AL_BANDPASS_GAIN), - DECL(AL_BANDPASS_GAINHF), - DECL(AL_BANDPASS_GAINLF), - - DECL(AL_EFFECT_TYPE), - DECL(AL_EFFECT_NULL), - DECL(AL_EFFECT_REVERB), - DECL(AL_EFFECT_EAXREVERB), - DECL(AL_EFFECT_CHORUS), - DECL(AL_EFFECT_DISTORTION), - DECL(AL_EFFECT_ECHO), - DECL(AL_EFFECT_FLANGER), - DECL(AL_EFFECT_PITCH_SHIFTER), - DECL(AL_EFFECT_FREQUENCY_SHIFTER), - DECL(AL_EFFECT_VOCAL_MORPHER), - DECL(AL_EFFECT_RING_MODULATOR), - DECL(AL_EFFECT_AUTOWAH), - DECL(AL_EFFECT_COMPRESSOR), - DECL(AL_EFFECT_EQUALIZER), - DECL(AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT), - DECL(AL_EFFECT_DEDICATED_DIALOGUE), - - DECL(AL_EFFECTSLOT_EFFECT), - DECL(AL_EFFECTSLOT_GAIN), - DECL(AL_EFFECTSLOT_AUXILIARY_SEND_AUTO), - DECL(AL_EFFECTSLOT_NULL), - - DECL(AL_EAXREVERB_DENSITY), - DECL(AL_EAXREVERB_DIFFUSION), - DECL(AL_EAXREVERB_GAIN), - DECL(AL_EAXREVERB_GAINHF), - DECL(AL_EAXREVERB_GAINLF), - DECL(AL_EAXREVERB_DECAY_TIME), - DECL(AL_EAXREVERB_DECAY_HFRATIO), - DECL(AL_EAXREVERB_DECAY_LFRATIO), - DECL(AL_EAXREVERB_REFLECTIONS_GAIN), - DECL(AL_EAXREVERB_REFLECTIONS_DELAY), - DECL(AL_EAXREVERB_REFLECTIONS_PAN), - DECL(AL_EAXREVERB_LATE_REVERB_GAIN), - DECL(AL_EAXREVERB_LATE_REVERB_DELAY), - DECL(AL_EAXREVERB_LATE_REVERB_PAN), - DECL(AL_EAXREVERB_ECHO_TIME), - DECL(AL_EAXREVERB_ECHO_DEPTH), - DECL(AL_EAXREVERB_MODULATION_TIME), - DECL(AL_EAXREVERB_MODULATION_DEPTH), - DECL(AL_EAXREVERB_AIR_ABSORPTION_GAINHF), - DECL(AL_EAXREVERB_HFREFERENCE), - DECL(AL_EAXREVERB_LFREFERENCE), - DECL(AL_EAXREVERB_ROOM_ROLLOFF_FACTOR), - DECL(AL_EAXREVERB_DECAY_HFLIMIT), - - DECL(AL_REVERB_DENSITY), - DECL(AL_REVERB_DIFFUSION), - DECL(AL_REVERB_GAIN), - DECL(AL_REVERB_GAINHF), - DECL(AL_REVERB_DECAY_TIME), - DECL(AL_REVERB_DECAY_HFRATIO), - DECL(AL_REVERB_REFLECTIONS_GAIN), - DECL(AL_REVERB_REFLECTIONS_DELAY), - DECL(AL_REVERB_LATE_REVERB_GAIN), - DECL(AL_REVERB_LATE_REVERB_DELAY), - DECL(AL_REVERB_AIR_ABSORPTION_GAINHF), - DECL(AL_REVERB_ROOM_ROLLOFF_FACTOR), - DECL(AL_REVERB_DECAY_HFLIMIT), - - DECL(AL_CHORUS_WAVEFORM), - DECL(AL_CHORUS_PHASE), - DECL(AL_CHORUS_RATE), - DECL(AL_CHORUS_DEPTH), - DECL(AL_CHORUS_FEEDBACK), - DECL(AL_CHORUS_DELAY), - - DECL(AL_DISTORTION_EDGE), - DECL(AL_DISTORTION_GAIN), - DECL(AL_DISTORTION_LOWPASS_CUTOFF), - DECL(AL_DISTORTION_EQCENTER), - DECL(AL_DISTORTION_EQBANDWIDTH), - - DECL(AL_ECHO_DELAY), - DECL(AL_ECHO_LRDELAY), - DECL(AL_ECHO_DAMPING), - DECL(AL_ECHO_FEEDBACK), - DECL(AL_ECHO_SPREAD), - - DECL(AL_FLANGER_WAVEFORM), - DECL(AL_FLANGER_PHASE), - DECL(AL_FLANGER_RATE), - DECL(AL_FLANGER_DEPTH), - DECL(AL_FLANGER_FEEDBACK), - DECL(AL_FLANGER_DELAY), - - DECL(AL_FREQUENCY_SHIFTER_FREQUENCY), - DECL(AL_FREQUENCY_SHIFTER_LEFT_DIRECTION), - DECL(AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION), - - DECL(AL_RING_MODULATOR_FREQUENCY), - DECL(AL_RING_MODULATOR_HIGHPASS_CUTOFF), - DECL(AL_RING_MODULATOR_WAVEFORM), - - DECL(AL_PITCH_SHIFTER_COARSE_TUNE), - DECL(AL_PITCH_SHIFTER_FINE_TUNE), - - DECL(AL_COMPRESSOR_ONOFF), - - DECL(AL_EQUALIZER_LOW_GAIN), - DECL(AL_EQUALIZER_LOW_CUTOFF), - DECL(AL_EQUALIZER_MID1_GAIN), - DECL(AL_EQUALIZER_MID1_CENTER), - DECL(AL_EQUALIZER_MID1_WIDTH), - DECL(AL_EQUALIZER_MID2_GAIN), - DECL(AL_EQUALIZER_MID2_CENTER), - DECL(AL_EQUALIZER_MID2_WIDTH), - DECL(AL_EQUALIZER_HIGH_GAIN), - DECL(AL_EQUALIZER_HIGH_CUTOFF), - - DECL(AL_DEDICATED_GAIN), - - DECL(AL_AUTOWAH_ATTACK_TIME), - DECL(AL_AUTOWAH_RELEASE_TIME), - DECL(AL_AUTOWAH_RESONANCE), - DECL(AL_AUTOWAH_PEAK_GAIN), - - DECL(AL_VOCAL_MORPHER_PHONEMEA), - DECL(AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING), - DECL(AL_VOCAL_MORPHER_PHONEMEB), - DECL(AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING), - DECL(AL_VOCAL_MORPHER_WAVEFORM), - DECL(AL_VOCAL_MORPHER_RATE), - - DECL(AL_EFFECTSLOT_TARGET_SOFT), - - DECL(AL_NUM_RESAMPLERS_SOFT), - DECL(AL_DEFAULT_RESAMPLER_SOFT), - DECL(AL_SOURCE_RESAMPLER_SOFT), - DECL(AL_RESAMPLER_NAME_SOFT), - - DECL(AL_SOURCE_SPATIALIZE_SOFT), - DECL(AL_AUTO_SOFT), - - DECL(AL_MAP_READ_BIT_SOFT), - DECL(AL_MAP_WRITE_BIT_SOFT), - DECL(AL_MAP_PERSISTENT_BIT_SOFT), - DECL(AL_PRESERVE_DATA_BIT_SOFT), - - DECL(AL_EVENT_CALLBACK_FUNCTION_SOFT), - DECL(AL_EVENT_CALLBACK_USER_PARAM_SOFT), - DECL(AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT), - DECL(AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT), - DECL(AL_EVENT_TYPE_DISCONNECTED_SOFT), - - DECL(AL_DROP_UNMATCHED_SOFT), - DECL(AL_REMIX_UNMATCHED_SOFT), - - DECL(AL_AMBISONIC_LAYOUT_SOFT), - DECL(AL_AMBISONIC_SCALING_SOFT), - DECL(AL_FUMA_SOFT), - DECL(AL_ACN_SOFT), - DECL(AL_SN3D_SOFT), - DECL(AL_N3D_SOFT), - - DECL(AL_BUFFER_CALLBACK_FUNCTION_SOFT), - DECL(AL_BUFFER_CALLBACK_USER_PARAM_SOFT), - - DECL(AL_UNPACK_AMBISONIC_ORDER_SOFT), - - DECL(AL_EFFECT_CONVOLUTION_REVERB_SOFT), - DECL(AL_EFFECTSLOT_STATE_SOFT), - - DECL(AL_FORMAT_UHJ2CHN8_SOFT), - DECL(AL_FORMAT_UHJ2CHN16_SOFT), - DECL(AL_FORMAT_UHJ2CHN_FLOAT32_SOFT), - DECL(AL_FORMAT_UHJ3CHN8_SOFT), - DECL(AL_FORMAT_UHJ3CHN16_SOFT), - DECL(AL_FORMAT_UHJ3CHN_FLOAT32_SOFT), - DECL(AL_FORMAT_UHJ4CHN8_SOFT), - DECL(AL_FORMAT_UHJ4CHN16_SOFT), - DECL(AL_FORMAT_UHJ4CHN_FLOAT32_SOFT), - DECL(AL_STEREO_MODE_SOFT), - DECL(AL_NORMAL_SOFT), - DECL(AL_SUPER_STEREO_SOFT), - DECL(AL_SUPER_STEREO_WIDTH_SOFT), - - DECL(AL_FORMAT_UHJ2CHN_MULAW_SOFT), - DECL(AL_FORMAT_UHJ2CHN_ALAW_SOFT), - DECL(AL_FORMAT_UHJ2CHN_IMA4_SOFT), - DECL(AL_FORMAT_UHJ2CHN_MSADPCM_SOFT), - DECL(AL_FORMAT_UHJ3CHN_MULAW_SOFT), - DECL(AL_FORMAT_UHJ3CHN_ALAW_SOFT), - DECL(AL_FORMAT_UHJ4CHN_MULAW_SOFT), - DECL(AL_FORMAT_UHJ4CHN_ALAW_SOFT), - - DECL(AL_STOP_SOURCES_ON_DISCONNECT_SOFT), - -#ifdef ALSOFT_EAX -}, eaxEnumerations[] = { - DECL(AL_EAX_RAM_SIZE), - DECL(AL_EAX_RAM_FREE), - DECL(AL_STORAGE_AUTOMATIC), - DECL(AL_STORAGE_HARDWARE), - DECL(AL_STORAGE_ACCESSIBLE), -#endif // ALSOFT_EAX -}; -#undef DECL - constexpr ALCchar alcNoError[] = "No Error"; constexpr ALCchar alcErrInvalidDevice[] = "Invalid Device"; constexpr ALCchar alcErrInvalidContext[] = "Invalid Context"; @@ -974,16 +302,20 @@ constexpr ALCchar alcNoDeviceExtList[] = "ALC_ENUMERATE_ALL_EXT " "ALC_ENUMERATION_EXT " "ALC_EXT_CAPTURE " + "ALC_EXTX_direct_context " "ALC_EXT_EFX " "ALC_EXT_thread_local_context " "ALC_SOFT_loopback " "ALC_SOFT_loopback_bformat " - "ALC_SOFT_reopen_device"; + "ALC_SOFT_reopen_device " + "ALC_SOFT_system_events"; constexpr ALCchar alcExtensionList[] = "ALC_ENUMERATE_ALL_EXT " "ALC_ENUMERATION_EXT " "ALC_EXT_CAPTURE " + "ALC_EXT_debug " "ALC_EXT_DEDICATED " + "ALC_EXTX_direct_context " "ALC_EXT_disconnect " "ALC_EXT_EFX " "ALC_EXT_thread_local_context " @@ -994,7 +326,8 @@ constexpr ALCchar alcExtensionList[] = "ALC_SOFT_output_limiter " "ALC_SOFT_output_mode " "ALC_SOFT_pause_device " - "ALC_SOFT_reopen_device"; + "ALC_SOFT_reopen_device " + "ALC_SOFT_system_events"; constexpr int alcMajorVersion{1}; constexpr int alcMinorVersion{1}; @@ -1008,8 +341,8 @@ using DeviceRef = al::intrusive_ptr<ALCdevice>; /************************************************ * Device lists ************************************************/ -al::vector<ALCdevice*> DeviceList; -al::vector<ALCcontext*> ContextList; +std::vector<ALCdevice*> DeviceList; +std::vector<ALCcontext*> ContextList; std::recursive_mutex ListLock; @@ -1034,7 +367,7 @@ void alc_initconfig(void) if(logf) gLogFile = logf; else { - auto u8name = wstr_to_utf8(logfile->c_str()); + auto u8name = wstr_to_utf8(*logfile); ERR("Failed to open log file '%s'\n", u8name.c_str()); } } @@ -1051,7 +384,7 @@ void alc_initconfig(void) ALSOFT_GIT_BRANCH); { std::string names; - if(al::size(BackendList) < 1) + if(std::size(BackendList) < 1) names = "(none)"; else { @@ -1171,13 +504,7 @@ void alc_initconfig(void) } Voice::InitMixer(ConfigValueStr(nullptr, nullptr, "resampler")); - auto uhjfiltopt = ConfigValueStr(nullptr, "uhj", "decode-filter"); - if(!uhjfiltopt) - { - if((uhjfiltopt = ConfigValueStr(nullptr, "uhj", "filter"))) - WARN("uhj/filter is deprecated, please use uhj/decode-filter\n"); - } - if(uhjfiltopt) + if(auto uhjfiltopt = ConfigValueStr(nullptr, "uhj", "decode-filter")) { if(al::strcasecmp(uhjfiltopt->c_str(), "fir256") == 0) UhjDecodeQuality = UhjQualityType::FIR256; @@ -1188,7 +515,7 @@ void alc_initconfig(void) else WARN("Unsupported uhj/decode-filter: %s\n", uhjfiltopt->c_str()); } - if((uhjfiltopt = ConfigValueStr(nullptr, "uhj", "encode-filter"))) + if(auto uhjfiltopt = ConfigValueStr(nullptr, "uhj", "encode-filter")) { if(al::strcasecmp(uhjfiltopt->c_str(), "fir256") == 0) UhjEncodeQuality = UhjQualityType::FIR256; @@ -1407,48 +734,58 @@ void ProbeCaptureDeviceList() struct DevFmtPair { DevFmtChannels chans; DevFmtType type; }; -al::optional<DevFmtPair> DecomposeDevFormat(ALenum format) +std::optional<DevFmtPair> DecomposeDevFormat(ALenum format) { static const struct { ALenum format; DevFmtChannels channels; DevFmtType type; } list[] = { - { AL_FORMAT_MONO8, DevFmtMono, DevFmtUByte }, - { AL_FORMAT_MONO16, DevFmtMono, DevFmtShort }, + { AL_FORMAT_MONO8, DevFmtMono, DevFmtUByte }, + { AL_FORMAT_MONO16, DevFmtMono, DevFmtShort }, + { AL_FORMAT_MONO_I32, DevFmtMono, DevFmtInt }, { AL_FORMAT_MONO_FLOAT32, DevFmtMono, DevFmtFloat }, - { AL_FORMAT_STEREO8, DevFmtStereo, DevFmtUByte }, - { AL_FORMAT_STEREO16, DevFmtStereo, DevFmtShort }, + { AL_FORMAT_STEREO8, DevFmtStereo, DevFmtUByte }, + { AL_FORMAT_STEREO16, DevFmtStereo, DevFmtShort }, + { AL_FORMAT_STEREO_I32, DevFmtStereo, DevFmtInt }, { AL_FORMAT_STEREO_FLOAT32, DevFmtStereo, DevFmtFloat }, - { AL_FORMAT_QUAD8, DevFmtQuad, DevFmtUByte }, - { AL_FORMAT_QUAD16, DevFmtQuad, DevFmtShort }, - { AL_FORMAT_QUAD32, DevFmtQuad, DevFmtFloat }, - - { AL_FORMAT_51CHN8, DevFmtX51, DevFmtUByte }, - { AL_FORMAT_51CHN16, DevFmtX51, DevFmtShort }, - { AL_FORMAT_51CHN32, DevFmtX51, DevFmtFloat }, - - { AL_FORMAT_61CHN8, DevFmtX61, DevFmtUByte }, - { AL_FORMAT_61CHN16, DevFmtX61, DevFmtShort }, - { AL_FORMAT_61CHN32, DevFmtX61, DevFmtFloat }, - - { AL_FORMAT_71CHN8, DevFmtX71, DevFmtUByte }, - { AL_FORMAT_71CHN16, DevFmtX71, DevFmtShort }, - { AL_FORMAT_71CHN32, DevFmtX71, DevFmtFloat }, + { AL_FORMAT_QUAD8, DevFmtQuad, DevFmtUByte }, + { AL_FORMAT_QUAD16, DevFmtQuad, DevFmtShort }, + { AL_FORMAT_QUAD32, DevFmtQuad, DevFmtFloat }, + { AL_FORMAT_QUAD_I32, DevFmtQuad, DevFmtInt }, + { AL_FORMAT_QUAD_FLOAT32, DevFmtQuad, DevFmtFloat }, + + { AL_FORMAT_51CHN8, DevFmtX51, DevFmtUByte }, + { AL_FORMAT_51CHN16, DevFmtX51, DevFmtShort }, + { AL_FORMAT_51CHN32, DevFmtX51, DevFmtFloat }, + { AL_FORMAT_51CHN_I32, DevFmtX51, DevFmtInt }, + { AL_FORMAT_51CHN_FLOAT32, DevFmtX51, DevFmtFloat }, + + { AL_FORMAT_61CHN8, DevFmtX61, DevFmtUByte }, + { AL_FORMAT_61CHN16, DevFmtX61, DevFmtShort }, + { AL_FORMAT_61CHN32, DevFmtX61, DevFmtFloat }, + { AL_FORMAT_61CHN_I32, DevFmtX61, DevFmtInt }, + { AL_FORMAT_61CHN_FLOAT32, DevFmtX61, DevFmtFloat }, + + { AL_FORMAT_71CHN8, DevFmtX71, DevFmtUByte }, + { AL_FORMAT_71CHN16, DevFmtX71, DevFmtShort }, + { AL_FORMAT_71CHN32, DevFmtX71, DevFmtFloat }, + { AL_FORMAT_71CHN_I32, DevFmtX71, DevFmtInt }, + { AL_FORMAT_71CHN_FLOAT32, DevFmtX71, DevFmtFloat }, }; for(const auto &item : list) { if(item.format == format) - return al::make_optional<DevFmtPair>({item.channels, item.type}); + return DevFmtPair{item.channels, item.type}; } - return al::nullopt; + return std::nullopt; } -al::optional<DevFmtType> DevFmtTypeFromEnum(ALCenum type) +std::optional<DevFmtType> DevFmtTypeFromEnum(ALCenum type) { switch(type) { @@ -1461,7 +798,7 @@ al::optional<DevFmtType> DevFmtTypeFromEnum(ALCenum type) case ALC_FLOAT_SOFT: return DevFmtFloat; } WARN("Unsupported format type: 0x%04x\n", type); - return al::nullopt; + return std::nullopt; } ALCenum EnumFromDevFmt(DevFmtType type) { @@ -1478,7 +815,7 @@ ALCenum EnumFromDevFmt(DevFmtType type) throw std::runtime_error{"Invalid DevFmtType: "+std::to_string(int(type))}; } -al::optional<DevFmtChannels> DevFmtChannelsFromEnum(ALCenum channels) +std::optional<DevFmtChannels> DevFmtChannelsFromEnum(ALCenum channels) { switch(channels) { @@ -1491,7 +828,7 @@ al::optional<DevFmtChannels> DevFmtChannelsFromEnum(ALCenum channels) case ALC_BFORMAT3D_SOFT: return DevFmtAmbi3D; } WARN("Unsupported format channels: 0x%04x\n", channels); - return al::nullopt; + return std::nullopt; } ALCenum EnumFromDevFmt(DevFmtChannels channels) { @@ -1511,7 +848,7 @@ ALCenum EnumFromDevFmt(DevFmtChannels channels) throw std::runtime_error{"Invalid DevFmtChannels: "+std::to_string(int(channels))}; } -al::optional<DevAmbiLayout> DevAmbiLayoutFromEnum(ALCenum layout) +std::optional<DevAmbiLayout> DevAmbiLayoutFromEnum(ALCenum layout) { switch(layout) { @@ -1519,7 +856,7 @@ al::optional<DevAmbiLayout> DevAmbiLayoutFromEnum(ALCenum layout) case ALC_ACN_SOFT: return DevAmbiLayout::ACN; } WARN("Unsupported ambisonic layout: 0x%04x\n", layout); - return al::nullopt; + return std::nullopt; } ALCenum EnumFromDevAmbi(DevAmbiLayout layout) { @@ -1531,7 +868,7 @@ ALCenum EnumFromDevAmbi(DevAmbiLayout layout) throw std::runtime_error{"Invalid DevAmbiLayout: "+std::to_string(int(layout))}; } -al::optional<DevAmbiScaling> DevAmbiScalingFromEnum(ALCenum scaling) +std::optional<DevAmbiScaling> DevAmbiScalingFromEnum(ALCenum scaling) { switch(scaling) { @@ -1540,7 +877,7 @@ al::optional<DevAmbiScaling> DevAmbiScalingFromEnum(ALCenum scaling) case ALC_N3D_SOFT: return DevAmbiScaling::N3D; } WARN("Unsupported ambisonic scaling: 0x%04x\n", scaling); - return al::nullopt; + return std::nullopt; } ALCenum EnumFromDevAmbi(DevAmbiScaling scaling) { @@ -1554,95 +891,60 @@ ALCenum EnumFromDevAmbi(DevAmbiScaling scaling) } -/* Downmixing channel arrays, to map the given format's missing channels to - * existing ones. Based on Wine's DSound downmix values, which are based on - * PulseAudio's. +/* Downmixing channel arrays, to map a device format's missing channels to + * existing ones. Based on what PipeWire does, though simplified. */ -constexpr std::array<InputRemixMap::TargetMix,2> FrontStereoSplit{{ - {FrontLeft, 0.5f}, {FrontRight, 0.5f} -}}; -constexpr std::array<InputRemixMap::TargetMix,1> FrontLeft9{{ - {FrontLeft, 1.0f/9.0f} -}}; -constexpr std::array<InputRemixMap::TargetMix,1> FrontRight9{{ - {FrontRight, 1.0f/9.0f} -}}; -constexpr std::array<InputRemixMap::TargetMix,2> BackMonoToFrontSplit{{ - {FrontLeft, 0.5f/9.0f}, {FrontRight, 0.5f/9.0f} -}}; -constexpr std::array<InputRemixMap::TargetMix,2> LeftStereoSplit{{ - {FrontLeft, 0.5f}, {BackLeft, 0.5f} -}}; -constexpr std::array<InputRemixMap::TargetMix,2> RightStereoSplit{{ - {FrontRight, 0.5f}, {BackRight, 0.5f} -}}; -constexpr std::array<InputRemixMap::TargetMix,2> BackStereoSplit{{ - {BackLeft, 0.5f}, {BackRight, 0.5f} -}}; -constexpr std::array<InputRemixMap::TargetMix,2> SideStereoSplit{{ - {SideLeft, 0.5f}, {SideRight, 0.5f} -}}; -constexpr std::array<InputRemixMap::TargetMix,1> ToSideLeft{{ - {SideLeft, 1.0f} -}}; -constexpr std::array<InputRemixMap::TargetMix,1> ToSideRight{{ - {SideRight, 1.0f} -}}; -constexpr std::array<InputRemixMap::TargetMix,2> BackLeftSplit{{ - {SideLeft, 0.5f}, {BackCenter, 0.5f} -}}; -constexpr std::array<InputRemixMap::TargetMix,2> BackRightSplit{{ - {SideRight, 0.5f}, {BackCenter, 0.5f} -}}; - -const std::array<InputRemixMap,6> StereoDownmix{{ - { FrontCenter, FrontStereoSplit }, - { SideLeft, FrontLeft9 }, - { SideRight, FrontRight9 }, - { BackLeft, FrontLeft9 }, - { BackRight, FrontRight9 }, - { BackCenter, BackMonoToFrontSplit }, -}}; -const std::array<InputRemixMap,4> QuadDownmix{{ - { FrontCenter, FrontStereoSplit }, - { SideLeft, LeftStereoSplit }, - { SideRight, RightStereoSplit }, - { BackCenter, BackStereoSplit }, -}}; -const std::array<InputRemixMap,3> X51Downmix{{ - { BackLeft, ToSideLeft }, - { BackRight, ToSideRight }, - { BackCenter, SideStereoSplit }, -}}; -const std::array<InputRemixMap,2> X61Downmix{{ - { BackLeft, BackLeftSplit }, - { BackRight, BackRightSplit }, -}}; -const std::array<InputRemixMap,1> X71Downmix{{ - { BackCenter, BackStereoSplit }, -}}; - - -/** Stores the latest ALC device error. */ -void alcSetError(ALCdevice *device, ALCenum errorCode) -{ - WARN("Error generated on device %p, code 0x%04x\n", voidp{device}, errorCode); - if(TrapALCError) - { -#ifdef _WIN32 - /* DebugBreak() will cause an exception if there is no debugger */ - if(IsDebuggerPresent()) - DebugBreak(); -#elif defined(SIGTRAP) - raise(SIGTRAP); -#endif - } - - if(device) - device->LastError.store(errorCode); - else - LastNullDeviceError.store(errorCode); -} +constexpr float inv_sqrt2f{static_cast<float>(1.0 / al::numbers::sqrt2)}; +constexpr std::array FrontStereo3dB{ + InputRemixMap::TargetMix{FrontLeft, inv_sqrt2f}, + InputRemixMap::TargetMix{FrontRight, inv_sqrt2f} +}; +constexpr std::array FrontStereo6dB{ + InputRemixMap::TargetMix{FrontLeft, 0.5f}, + InputRemixMap::TargetMix{FrontRight, 0.5f} +}; +constexpr std::array SideStereo3dB{ + InputRemixMap::TargetMix{SideLeft, inv_sqrt2f}, + InputRemixMap::TargetMix{SideRight, inv_sqrt2f} +}; +constexpr std::array BackStereo3dB{ + InputRemixMap::TargetMix{BackLeft, inv_sqrt2f}, + InputRemixMap::TargetMix{BackRight, inv_sqrt2f} +}; +constexpr std::array FrontLeft3dB{InputRemixMap::TargetMix{FrontLeft, inv_sqrt2f}}; +constexpr std::array FrontRight3dB{InputRemixMap::TargetMix{FrontRight, inv_sqrt2f}}; +constexpr std::array SideLeft0dB{InputRemixMap::TargetMix{SideLeft, 1.0f}}; +constexpr std::array SideRight0dB{InputRemixMap::TargetMix{SideRight, 1.0f}}; +constexpr std::array BackLeft0dB{InputRemixMap::TargetMix{BackLeft, 1.0f}}; +constexpr std::array BackRight0dB{InputRemixMap::TargetMix{BackRight, 1.0f}}; +constexpr std::array BackCenter3dB{InputRemixMap::TargetMix{BackCenter, inv_sqrt2f}}; + +constexpr std::array StereoDownmix{ + InputRemixMap{FrontCenter, FrontStereo3dB}, + InputRemixMap{SideLeft, FrontLeft3dB}, + InputRemixMap{SideRight, FrontRight3dB}, + InputRemixMap{BackLeft, FrontLeft3dB}, + InputRemixMap{BackRight, FrontRight3dB}, + InputRemixMap{BackCenter, FrontStereo6dB}, +}; +constexpr std::array QuadDownmix{ + InputRemixMap{FrontCenter, FrontStereo3dB}, + InputRemixMap{SideLeft, BackLeft0dB}, + InputRemixMap{SideRight, BackRight0dB}, + InputRemixMap{BackCenter, BackStereo3dB}, +}; +constexpr std::array X51Downmix{ + InputRemixMap{BackLeft, SideLeft0dB}, + InputRemixMap{BackRight, SideRight0dB}, + InputRemixMap{BackCenter, SideStereo3dB}, +}; +constexpr std::array X61Downmix{ + InputRemixMap{BackLeft, BackCenter3dB}, + InputRemixMap{BackRight, BackCenter3dB}, +}; +constexpr std::array X71Downmix{ + InputRemixMap{BackCenter, BackStereo3dB}, +}; std::unique_ptr<Compressor> CreateDeviceLimiter(const ALCdevice *device, const float threshold) @@ -1695,13 +997,13 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList) uint numMono{device->NumMonoSources}; uint numStereo{device->NumStereoSources}; uint numSends{device->NumAuxSends}; - al::optional<StereoEncoding> stereomode; - al::optional<bool> optlimit; - al::optional<uint> optsrate; - al::optional<DevFmtChannels> optchans; - al::optional<DevFmtType> opttype; - al::optional<DevAmbiLayout> optlayout; - al::optional<DevAmbiScaling> optscale; + std::optional<StereoEncoding> stereomode; + std::optional<bool> optlimit; + std::optional<uint> optsrate; + std::optional<DevFmtChannels> optchans; + std::optional<DevFmtType> opttype; + std::optional<DevAmbiLayout> optlayout; + std::optional<DevAmbiScaling> optscale; uint period_size{DEFAULT_UPDATE_SIZE}; uint buffer_size{DEFAULT_UPDATE_SIZE * DEFAULT_NUM_UPDATES}; int hrtf_id{-1}; @@ -1844,7 +1146,7 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList) if(attrList && attrList[0]) { ALenum outmode{ALC_ANY_SOFT}; - al::optional<bool> opthrtf; + std::optional<bool> opthrtf; int freqAttr{}; #define ATTRIBUTE(a) a: TRACE("%s = %d\n", #a, attrList[attrIdx + 1]); @@ -1904,7 +1206,7 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList) else if(attrList[attrIdx + 1] == ALC_TRUE) opthrtf = true; else if(attrList[attrIdx + 1] == ALC_DONT_CARE_SOFT) - opthrtf = al::nullopt; + opthrtf = std::nullopt; break; case ATTRIBUTE(ALC_HRTF_ID_SOFT) @@ -1917,7 +1219,7 @@ ALCenum UpdateDeviceParams(ALCdevice *device, const int *attrList) else if(attrList[attrIdx + 1] == ALC_TRUE) optlimit = true; else if(attrList[attrIdx + 1] == ALC_DONT_CARE_SOFT) - optlimit = al::nullopt; + optlimit = std::nullopt; break; case ATTRIBUTE(ALC_OUTPUT_MODE_SOFT) @@ -2542,6 +1844,11 @@ ContextRef VerifyContext(ALCcontext *context) } // namespace +FORCE_ALIGN void ALC_APIENTRY alsoft_set_log_callback(LPALSOFTLOGCALLBACK callback, void *userptr) noexcept +{ + al_set_log_callback(callback, userptr); +} + /** Returns a new reference to the currently active context for this thread. */ ContextRef GetContextRef(void) { @@ -2562,58 +1869,86 @@ ContextRef GetContextRef(void) return ContextRef{context}; } +void alcSetError(ALCdevice *device, ALCenum errorCode) +{ + WARN("Error generated on device %p, code 0x%04x\n", voidp{device}, errorCode); + if(TrapALCError) + { +#ifdef _WIN32 + /* DebugBreak() will cause an exception if there is no debugger */ + if(IsDebuggerPresent()) + DebugBreak(); +#elif defined(SIGTRAP) + raise(SIGTRAP); +#endif + } + + if(device) + device->LastError.store(errorCode); + else + LastNullDeviceError.store(errorCode); +} /************************************************ * Standard ALC functions ************************************************/ -ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device) -START_API_FUNC +ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device) noexcept { DeviceRef dev{VerifyDevice(device)}; if(dev) return dev->LastError.exchange(ALC_NO_ERROR); return LastNullDeviceError.exchange(ALC_NO_ERROR); } -END_API_FUNC -ALC_API void ALC_APIENTRY alcSuspendContext(ALCcontext *context) -START_API_FUNC +ALC_API void ALC_APIENTRY alcSuspendContext(ALCcontext *context) noexcept { - if(!SuspendDefers) - return; - ContextRef ctx{VerifyContext(context)}; if(!ctx) + { alcSetError(nullptr, ALC_INVALID_CONTEXT); - else + return; + } + + if(context->mContextFlags.test(ContextFlags::DebugBit)) UNLIKELY + ctx->debugMessage(DebugSource::API, DebugType::Portability, 0, DebugSeverity::Medium, + "alcSuspendContext behavior is not portable -- some implementations suspend all " + "rendering, some only defer property changes, and some are completely no-op; consider " + "using alcDevicePauseSOFT to suspend all rendering, or alDeferUpdatesSOFT to only " + "defer property changes"); + + if(SuspendDefers) { std::lock_guard<std::mutex> _{ctx->mPropLock}; ctx->deferUpdates(); } } -END_API_FUNC -ALC_API void ALC_APIENTRY alcProcessContext(ALCcontext *context) -START_API_FUNC +ALC_API void ALC_APIENTRY alcProcessContext(ALCcontext *context) noexcept { - if(!SuspendDefers) - return; - ContextRef ctx{VerifyContext(context)}; if(!ctx) + { alcSetError(nullptr, ALC_INVALID_CONTEXT); - else + return; + } + + if(context->mContextFlags.test(ContextFlags::DebugBit)) UNLIKELY + ctx->debugMessage(DebugSource::API, DebugType::Portability, 0, DebugSeverity::Medium, + "alcProcessContext behavior is not portable -- some implementations resume rendering, " + "some apply deferred property changes, and some are completely no-op; consider using " + "alcDeviceResumeSOFT to resume rendering, or alProcessUpdatesSOFT to apply deferred " + "property changes"); + + if(SuspendDefers) { std::lock_guard<std::mutex> _{ctx->mPropLock}; ctx->processUpdates(); } } -END_API_FUNC -ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum param) -START_API_FUNC +ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum param) noexcept { const ALCchar *value{nullptr}; @@ -2732,7 +2067,6 @@ START_API_FUNC return value; } -END_API_FUNC static size_t GetIntegerv(ALCdevice *device, ALCenum param, const al::span<int> values) @@ -3056,8 +2390,7 @@ static size_t GetIntegerv(ALCdevice *device, ALCenum param, const al::span<int> return 0; } -ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values) -START_API_FUNC +ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values) noexcept { DeviceRef dev{VerifyDevice(device)}; if(size <= 0 || values == nullptr) @@ -3065,10 +2398,8 @@ START_API_FUNC else GetIntegerv(dev.get(), param, {values, static_cast<uint>(size)}); } -END_API_FUNC -ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, ALCsizei size, ALCint64SOFT *values) -START_API_FUNC +ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, ALCsizei size, ALCint64SOFT *values) noexcept { DeviceRef dev{VerifyDevice(device)}; if(size <= 0 || values == nullptr) @@ -3078,7 +2409,7 @@ START_API_FUNC } if(!dev || dev->Type == DeviceType::Capture) { - auto ivals = al::vector<int>(static_cast<uint>(size)); + auto ivals = std::vector<int>(static_cast<uint>(size)); if(size_t got{GetIntegerv(dev.get(), pname, ivals)}) std::copy_n(ivals.begin(), got, values); return; @@ -3197,17 +2528,15 @@ START_API_FUNC break; default: - auto ivals = al::vector<int>(static_cast<uint>(size)); + auto ivals = std::vector<int>(static_cast<uint>(size)); if(size_t got{GetIntegerv(dev.get(), pname, ivals)}) std::copy_n(ivals.begin(), got, values); break; } } -END_API_FUNC -ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extName) -START_API_FUNC +ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extName) noexcept { DeviceRef dev{VerifyDevice(device)}; if(!extName) @@ -3231,11 +2560,12 @@ START_API_FUNC } return ALC_FALSE; } -END_API_FUNC -ALC_API ALCvoid* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcName) -START_API_FUNC +ALCvoid* ALC_APIENTRY alcGetProcAddress2(ALCdevice *device, const ALCchar *funcName) noexcept +{ return alcGetProcAddress(device, funcName); } + +ALC_API ALCvoid* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcName) noexcept { if(!funcName) { @@ -3243,6 +2573,7 @@ START_API_FUNC alcSetError(dev.get(), ALC_INVALID_VALUE); return nullptr; } + #ifdef ALSOFT_EAX if(eax_g_is_enabled) { @@ -3260,11 +2591,9 @@ START_API_FUNC } return nullptr; } -END_API_FUNC -ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumName) -START_API_FUNC +ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumName) noexcept { if(!enumName) { @@ -3272,6 +2601,7 @@ START_API_FUNC alcSetError(dev.get(), ALC_INVALID_VALUE); return 0; } + #ifdef ALSOFT_EAX if(eax_g_is_enabled) { @@ -3290,11 +2620,9 @@ START_API_FUNC return 0; } -END_API_FUNC -ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint *attrList) -START_API_FUNC +ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint *attrList) noexcept { /* Explicitly hold the list lock while taking the StateLock in case the * device is asynchronously destroyed, to ensure this new context is @@ -3320,7 +2648,34 @@ START_API_FUNC return nullptr; } - ContextRef context{new ALCcontext{dev}}; + ContextFlagBitset ctxflags{0}; + if(attrList) + { + for(size_t i{0};attrList[i];i+=2) + { + if(attrList[i] == ALC_CONTEXT_FLAGS_EXT) + { + ctxflags = static_cast<ALuint>(attrList[i+1]); + break; + } + } + } + + ContextRef context{[](auto&& ...args) -> ContextRef + { + try { + return ContextRef{new ALCcontext{std::forward<decltype(args)>(args)...}}; + } + catch(std::exception& e) { + ERR("Failed to create ALCcontext: %s\n", e.what()); + return ContextRef{}; + } + }(dev, ctxflags)}; + if(!context) + { + alcSetError(dev.get(), ALC_OUT_OF_MEMORY); + return nullptr; + } context->init(); if(auto volopt = dev->configValue<float>(nullptr, "volume-adjust")) @@ -3374,7 +2729,7 @@ START_API_FUNC if(ALeffectslot *slot{context->mDefaultSlot.get()}) { - ALenum sloterr{slot->initEffect(ALCcontext::sDefaultEffect.type, + ALenum sloterr{slot->initEffect(0, ALCcontext::sDefaultEffect.type, ALCcontext::sDefaultEffect.Props, context.get())}; if(sloterr == AL_NO_ERROR) slot->updateProps(context.get()); @@ -3385,10 +2740,8 @@ START_API_FUNC TRACE("Created context %p\n", voidp{context.get()}); return context.release(); } -END_API_FUNC -ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context) -START_API_FUNC +ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context) noexcept { std::unique_lock<std::recursive_mutex> listlock{ListLock}; auto iter = std::lower_bound(ContextList.begin(), ContextList.end(), context); @@ -3414,26 +2767,20 @@ START_API_FUNC Device->Flags.reset(DeviceRunning); } } -END_API_FUNC -ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void) -START_API_FUNC +ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void) noexcept { ALCcontext *Context{ALCcontext::getThreadContext()}; if(!Context) Context = ALCcontext::sGlobalContext.load(); return Context; } -END_API_FUNC /** Returns the currently active thread-local context. */ -ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void) -START_API_FUNC +ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void) noexcept { return ALCcontext::getThreadContext(); } -END_API_FUNC -ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context) -START_API_FUNC +ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context) noexcept { /* context must be valid or nullptr */ ContextRef ctx; @@ -3467,11 +2814,9 @@ START_API_FUNC return ALC_TRUE; } -END_API_FUNC /** Makes the given context the active context for the current thread. */ -ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context) -START_API_FUNC +ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context) noexcept { /* context must be valid or nullptr */ ContextRef ctx; @@ -3490,11 +2835,9 @@ START_API_FUNC return ALC_TRUE; } -END_API_FUNC -ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *Context) -START_API_FUNC +ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *Context) noexcept { ContextRef ctx{VerifyContext(Context)}; if(!ctx) @@ -3504,11 +2847,9 @@ START_API_FUNC } return ctx->mALDevice.get(); } -END_API_FUNC -ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) -START_API_FUNC +ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) noexcept { InitConfig(); @@ -3565,9 +2906,26 @@ START_API_FUNC device->NumAuxSends = DefaultSends; try { + /* We need to ensure the device name isn't too long. The string_view is + * printed using the "%.*s" formatter, which uses an int for the + * precision/length. It wouldn't be a significant problem if larger + * values simply printed fewer characters due to truncation, but + * negative values are ignored, treating it like a normal null- + * terminated string, and string_views don't need to be null- + * terminated. + * + * Other than the annoyance of checking, this shouldn't be a problem. + * Two billion bytes is enough for a device name. + */ + const std::string_view devname{deviceName ? deviceName : ""}; + if(devname.length() >= std::numeric_limits<int>::max()) + throw al::backend_exception{al::backend_error::NoDevice, + "Device name too long (%zu >= %d)", devname.length(), + std::numeric_limits<int>::max()}; + auto backend = PlaybackFactory->createBackend(device.get(), BackendType::Playback); std::lock_guard<std::recursive_mutex> _{ListLock}; - backend->open(deviceName); + backend->open(devname); device->Backend = std::move(backend); } catch(al::backend_exception &e) { @@ -3586,10 +2944,8 @@ START_API_FUNC TRACE("Created device %p, \"%s\"\n", voidp{device.get()}, device->DeviceName.c_str()); return device.release(); } -END_API_FUNC -ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) -START_API_FUNC +ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) noexcept { std::unique_lock<std::recursive_mutex> listlock{ListLock}; auto iter = std::lower_bound(DeviceList.begin(), DeviceList.end(), device); @@ -3611,7 +2967,7 @@ START_API_FUNC DeviceList.erase(iter); std::unique_lock<std::mutex> statelock{dev->StateLock}; - al::vector<ContextRef> orphanctxs; + std::vector<ContextRef> orphanctxs; for(ContextBase *ctx : *dev->mContexts.load()) { auto ctxiter = std::lower_bound(ContextList.begin(), ContextList.end(), ctx); @@ -3636,14 +2992,12 @@ START_API_FUNC return ALC_TRUE; } -END_API_FUNC /************************************************ * ALC capture functions ************************************************/ -ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei samples) -START_API_FUNC +ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei samples) noexcept { InitConfig(); @@ -3688,14 +3042,20 @@ START_API_FUNC device->UpdateSize = static_cast<uint>(samples); device->BufferSize = static_cast<uint>(samples); + TRACE("Capture format: %s, %s, %uhz, %u / %u buffer\n", DevFmtChannelsString(device->FmtChans), + DevFmtTypeString(device->FmtType), device->Frequency, device->UpdateSize, + device->BufferSize); + try { - TRACE("Capture format: %s, %s, %uhz, %u / %u buffer\n", - DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), - device->Frequency, device->UpdateSize, device->BufferSize); + const std::string_view devname{deviceName ? deviceName : ""}; + if(devname.length() >= std::numeric_limits<int>::max()) + throw al::backend_exception{al::backend_error::NoDevice, + "Device name too long (%zu >= %d)", devname.length(), + std::numeric_limits<int>::max()}; auto backend = CaptureFactory->createBackend(device.get(), BackendType::Capture); std::lock_guard<std::recursive_mutex> _{ListLock}; - backend->open(deviceName); + backend->open(devname); device->Backend = std::move(backend); } catch(al::backend_exception &e) { @@ -3714,10 +3074,8 @@ START_API_FUNC TRACE("Created capture device %p, \"%s\"\n", voidp{device.get()}, device->DeviceName.c_str()); return device.release(); } -END_API_FUNC -ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) -START_API_FUNC +ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) noexcept { std::unique_lock<std::recursive_mutex> listlock{ListLock}; auto iter = std::lower_bound(DeviceList.begin(), DeviceList.end(), device); @@ -3743,10 +3101,8 @@ START_API_FUNC return ALC_TRUE; } -END_API_FUNC -ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device) -START_API_FUNC +ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device) noexcept { DeviceRef dev{VerifyDevice(device)}; if(!dev || dev->Type != DeviceType::Capture) @@ -3772,10 +3128,8 @@ START_API_FUNC } } } -END_API_FUNC -ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device) -START_API_FUNC +ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device) noexcept { DeviceRef dev{VerifyDevice(device)}; if(!dev || dev->Type != DeviceType::Capture) @@ -3788,10 +3142,8 @@ START_API_FUNC dev->Flags.reset(DeviceRunning); } } -END_API_FUNC -ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples) -START_API_FUNC +ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples) noexcept { DeviceRef dev{VerifyDevice(device)}; if(!dev || dev->Type != DeviceType::Capture) @@ -3818,9 +3170,8 @@ START_API_FUNC return; } - backend->captureSamples(static_cast<al::byte*>(buffer), usamples); + backend->captureSamples(static_cast<std::byte*>(buffer), usamples); } -END_API_FUNC /************************************************ @@ -3828,8 +3179,7 @@ END_API_FUNC ************************************************/ /** Open a loopback device, for manual rendering. */ -ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceName) -START_API_FUNC +ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceName) noexcept { InitConfig(); @@ -3886,13 +3236,11 @@ START_API_FUNC TRACE("Created loopback device %p\n", voidp{device.get()}); return device.release(); } -END_API_FUNC /** * Determines if the loopback device supports the given format for rendering. */ -ALC_API ALCboolean ALC_APIENTRY alcIsRenderFormatSupportedSOFT(ALCdevice *device, ALCsizei freq, ALCenum channels, ALCenum type) -START_API_FUNC +ALC_API ALCboolean ALC_APIENTRY alcIsRenderFormatSupportedSOFT(ALCdevice *device, ALCsizei freq, ALCenum channels, ALCenum type) noexcept { DeviceRef dev{VerifyDevice(device)}; if(!dev || dev->Type != DeviceType::Loopback) @@ -3908,23 +3256,26 @@ START_API_FUNC return ALC_FALSE; } -END_API_FUNC /** * Renders some samples into a buffer, using the format last set by the * attributes given to alcCreateContext. */ -FORCE_ALIGN ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, ALCvoid *buffer, ALCsizei samples) -START_API_FUNC +#if defined(__GNUC__) && defined(__i386__) +/* Needed on x86-32 even without SSE codegen, since the mixer may still use SSE + * and GCC assumes the stack is aligned (x86-64 ABI guarantees alignment). + */ +[[gnu::force_align_arg_pointer]] +#endif +ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, ALCvoid *buffer, ALCsizei samples) noexcept { - if(!device || device->Type != DeviceType::Loopback) + if(!device || device->Type != DeviceType::Loopback) UNLIKELY alcSetError(device, ALC_INVALID_DEVICE); - else if(samples < 0 || (samples > 0 && buffer == nullptr)) + else if(samples < 0 || (samples > 0 && buffer == nullptr)) UNLIKELY alcSetError(device, ALC_INVALID_VALUE); else device->renderSamples(buffer, static_cast<uint>(samples), device->channelsFromFmt()); } -END_API_FUNC /************************************************ @@ -3932,8 +3283,7 @@ END_API_FUNC ************************************************/ /** Pause the DSP to stop audio processing. */ -ALC_API void ALC_APIENTRY alcDevicePauseSOFT(ALCdevice *device) -START_API_FUNC +ALC_API void ALC_APIENTRY alcDevicePauseSOFT(ALCdevice *device) noexcept { DeviceRef dev{VerifyDevice(device)}; if(!dev || dev->Type != DeviceType::Playback) @@ -3947,11 +3297,9 @@ START_API_FUNC dev->Flags.set(DevicePaused); } } -END_API_FUNC /** Resume the DSP to restart audio processing. */ -ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device) -START_API_FUNC +ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device) noexcept { DeviceRef dev{VerifyDevice(device)}; if(!dev || dev->Type != DeviceType::Playback) @@ -3982,7 +3330,6 @@ START_API_FUNC DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), device->Frequency, device->UpdateSize, device->BufferSize); } -END_API_FUNC /************************************************ @@ -3990,8 +3337,7 @@ END_API_FUNC ************************************************/ /** Gets a string parameter at the given index. */ -ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum paramName, ALCsizei index) -START_API_FUNC +ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum paramName, ALCsizei index) noexcept { DeviceRef dev{VerifyDevice(device)}; if(!dev || dev->Type == DeviceType::Capture) @@ -4011,11 +3357,9 @@ START_API_FUNC return nullptr; } -END_API_FUNC /** Resets the given device output, using the specified attribute list. */ -ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCint *attribs) -START_API_FUNC +ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCint *attribs) noexcept { std::unique_lock<std::recursive_mutex> listlock{ListLock}; DeviceRef dev{VerifyDevice(device)}; @@ -4037,7 +3381,6 @@ START_API_FUNC return ResetDeviceParams(dev.get(), attribs) ? ALC_TRUE : ALC_FALSE; } -END_API_FUNC /************************************************ @@ -4046,8 +3389,7 @@ END_API_FUNC /** Reopens the given device output, using the specified name and attribute list. */ FORCE_ALIGN ALCboolean ALC_APIENTRY alcReopenDeviceSOFT(ALCdevice *device, - const ALCchar *deviceName, const ALCint *attribs) -START_API_FUNC + const ALCchar *deviceName, const ALCint *attribs) noexcept { if(deviceName) { @@ -4075,8 +3417,14 @@ START_API_FUNC BackendPtr newbackend; try { + const std::string_view devname{deviceName ? deviceName : ""}; + if(devname.length() >= std::numeric_limits<int>::max()) + throw al::backend_exception{al::backend_error::NoDevice, + "Device name too long (%zu >= %d)", devname.length(), + std::numeric_limits<int>::max()}; + newbackend = PlaybackFactory->createBackend(dev.get(), BackendType::Playback); - newbackend->open(deviceName); + newbackend->open(devname); } catch(al::backend_exception &e) { listlock.unlock(); @@ -4122,4 +3470,37 @@ START_API_FUNC ResetDeviceParams(dev.get(), attribs); return ALC_TRUE; } -END_API_FUNC + +/************************************************ + * ALC event query functions + ************************************************/ + +FORCE_ALIGN ALCenum ALC_APIENTRY alcEventIsSupportedSOFT(ALCenum eventType, ALCenum deviceType) noexcept +{ + auto etype = alc::GetEventType(eventType); + if(!etype) + { + WARN("Invalid event type: 0x%04x\n", eventType); + alcSetError(nullptr, ALC_INVALID_ENUM); + return ALC_EVENT_NOT_SUPPORTED_SOFT; + } + + auto supported = alc::EventSupport::NoSupport; + switch(deviceType) + { + case ALC_PLAYBACK_DEVICE_SOFT: + if(PlaybackFactory) + supported = PlaybackFactory->queryEventSupport(*etype, BackendType::Playback); + break; + + case ALC_CAPTURE_DEVICE_SOFT: + if(CaptureFactory) + supported = CaptureFactory->queryEventSupport(*etype, BackendType::Capture); + break; + + default: + WARN("Invalid device type: 0x%04x\n", deviceType); + alcSetError(nullptr, ALC_INVALID_ENUM); + } + return al::to_underlying(supported); +} |