diff options
Diffstat (limited to 'Alc/ALc.c')
-rw-r--r-- | Alc/ALc.c | 1470 |
1 files changed, 892 insertions, 578 deletions
@@ -13,8 +13,8 @@ * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * Or go to http://www.gnu.org/copyleft/lgpl.html */ @@ -35,7 +35,6 @@ #include "alBuffer.h" #include "alAuxEffectSlot.h" #include "alError.h" -#include "alMidi.h" #include "bs2b.h" #include "alu.h" @@ -44,7 +43,6 @@ #include "alstring.h" #include "backends/base.h" -#include "midi/base.h" /************************************************ @@ -59,8 +57,11 @@ struct BackendInfo { BackendFuncs Funcs; }; -#define EmptyFuncs { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } +#define EmptyFuncs { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } static struct BackendInfo BackendList[] = { +#ifdef HAVE_JACK + { "jack", ALCjackBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, +#endif #ifdef HAVE_PULSEAUDIO { "pulse", ALCpulseBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, #endif @@ -74,7 +75,7 @@ static struct BackendInfo BackendList[] = { { "oss", ALCossBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, #endif #ifdef HAVE_SOLARIS - { "solaris", NULL, alc_solaris_init, alc_solaris_deinit, alc_solaris_probe, EmptyFuncs }, + { "solaris", ALCsolarisBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, #endif #ifdef HAVE_SNDIO { "sndio", NULL, alc_sndio_init, alc_sndio_deinit, alc_sndio_probe, EmptyFuncs }, @@ -89,10 +90,10 @@ static struct BackendInfo BackendList[] = { { "dsound", ALCdsoundBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, #endif #ifdef HAVE_WINMM - { "winmm", NULL, alcWinMMInit, alcWinMMDeinit, alcWinMMProbe, EmptyFuncs }, + { "winmm", ALCwinmmBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, #endif #ifdef HAVE_PORTAUDIO - { "port", NULL, alc_pa_init, alc_pa_deinit, alc_pa_probe, EmptyFuncs }, + { "port", ALCportBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, #endif #ifdef HAVE_OPENSL { "opensl", NULL, alc_opensl_init, alc_opensl_deinit, alc_opensl_probe, EmptyFuncs }, @@ -100,7 +101,7 @@ static struct BackendInfo BackendList[] = { { "null", ALCnullBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, #ifdef HAVE_WAVE - { "wave", NULL, alc_wave_init, alc_wave_deinit, alc_wave_probe, EmptyFuncs }, + { "wave", ALCwaveBackendFactory_getFactory, NULL, NULL, NULL, EmptyFuncs }, #endif { NULL, NULL, NULL, NULL, NULL, EmptyFuncs } @@ -157,6 +158,9 @@ static const ALCfunction alcFunctions[] = { DECL(alcDevicePauseSOFT), DECL(alcDeviceResumeSOFT), + DECL(alcGetStringiSOFT), + DECL(alcResetDeviceSOFT), + DECL(alcGetInteger64vSOFT), DECL(alEnable), @@ -290,44 +294,6 @@ static const ALCfunction alcFunctions[] = { DECL(alGetSource3i64SOFT), DECL(alGetSourcei64vSOFT), - DECL(alGenSoundfontsSOFT), - DECL(alDeleteSoundfontsSOFT), - DECL(alIsSoundfontSOFT), - DECL(alSoundfontSamplesSOFT), - DECL(alGetSoundfontSamplesSOFT), - DECL(alSoundfontMapSamplesSOFT), - DECL(alSoundfontUnmapSamplesSOFT), - DECL(alGetSoundfontivSOFT), - DECL(alSoundfontPresetsSOFT), - DECL(alGenPresetsSOFT), - DECL(alDeletePresetsSOFT), - DECL(alIsPresetSOFT), - DECL(alPresetiSOFT), - DECL(alPresetivSOFT), - DECL(alGetPresetivSOFT), - DECL(alPresetFontsoundsSOFT), - DECL(alGenFontsoundsSOFT), - DECL(alDeleteFontsoundsSOFT), - DECL(alIsFontsoundSOFT), - DECL(alFontsoundiSOFT), - DECL(alFontsound2iSOFT), - DECL(alFontsoundivSOFT), - DECL(alGetFontsoundivSOFT), - DECL(alFontsoundModulatoriSOFT), - DECL(alGetFontsoundModulatorivSOFT), - DECL(alMidiSoundfontSOFT), - DECL(alMidiSoundfontvSOFT), - DECL(alMidiEventSOFT), - DECL(alMidiSysExSOFT), - DECL(alMidiPlaySOFT), - DECL(alMidiPauseSOFT), - DECL(alMidiStopSOFT), - DECL(alMidiResetSOFT), - DECL(alMidiGainSOFT), - DECL(alGetInteger64SOFT), - DECL(alGetInteger64vSOFT), - DECL(alLoadSoundfontSOFT), - { NULL, NULL } }; #undef DECL @@ -379,6 +345,19 @@ static const ALCenums enumeration[] = { 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_NO_ERROR), DECL(ALC_INVALID_DEVICE), DECL(ALC_INVALID_CONTEXT), @@ -419,6 +398,7 @@ static const ALCenums enumeration[] = { 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), @@ -501,6 +481,14 @@ static const ALCenums enumeration[] = { DECL(AL_7POINT1_8_SOFT), DECL(AL_7POINT1_16_SOFT), DECL(AL_7POINT1_32F_SOFT), + 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_MONO_SOFT), DECL(AL_STEREO_SOFT), @@ -592,7 +580,9 @@ static const ALCenums enumeration[] = { DECL(AL_EFFECT_PITCH_SHIFTER), #endif DECL(AL_EFFECT_RING_MODULATOR), +#if 0 DECL(AL_EFFECT_AUTOWAH), +#endif DECL(AL_EFFECT_COMPRESSOR), DECL(AL_EFFECT_EQUALIZER), DECL(AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT), @@ -666,10 +656,12 @@ static const ALCenums enumeration[] = { DECL(AL_RING_MODULATOR_HIGHPASS_CUTOFF), DECL(AL_RING_MODULATOR_WAVEFORM), +#if 0 DECL(AL_AUTOWAH_ATTACK_TIME), DECL(AL_AUTOWAH_PEAK_GAIN), DECL(AL_AUTOWAH_RELEASE_TIME), DECL(AL_AUTOWAH_RESONANCE), +#endif DECL(AL_COMPRESSOR_ONOFF), @@ -714,20 +706,20 @@ static ALCchar *alcCaptureDefaultDeviceSpecifier; /* Default context extensions */ static const ALchar alExtList[] = - "AL_EXT_ALAW AL_EXT_DOUBLE AL_EXT_EXPONENT_DISTANCE AL_EXT_FLOAT32 " - "AL_EXT_IMA4 AL_EXT_LINEAR_DISTANCE AL_EXT_MCFORMATS AL_EXT_MULAW " - "AL_EXT_MULAW_MCFORMATS AL_EXT_OFFSET AL_EXT_source_distance_model " - "AL_LOKI_quadriphonic AL_SOFT_block_alignment AL_SOFT_buffer_samples " - "AL_SOFT_buffer_sub_data AL_SOFT_deferred_updates AL_SOFT_direct_channels " - "AL_SOFT_loop_points AL_SOFTX_MSADPCM AL_SOFT_source_latency " - "AL_SOFTX_source_length"; + "AL_EXT_ALAW AL_EXT_BFORMAT AL_EXT_DOUBLE AL_EXT_EXPONENT_DISTANCE " + "AL_EXT_FLOAT32 AL_EXT_IMA4 AL_EXT_LINEAR_DISTANCE AL_EXT_MCFORMATS " + "AL_EXT_MULAW AL_EXT_MULAW_BFORMAT AL_EXT_MULAW_MCFORMATS AL_EXT_OFFSET " + "AL_EXT_source_distance_model AL_LOKI_quadriphonic AL_SOFT_block_alignment " + "AL_SOFT_buffer_samples AL_SOFT_buffer_sub_data AL_SOFT_deferred_updates " + "AL_SOFT_direct_channels AL_SOFT_loop_points AL_SOFT_MSADPCM " + "AL_SOFT_source_latency AL_SOFT_source_length"; -static volatile ALCenum LastNullDeviceError = ALC_NO_ERROR; +static ATOMIC(ALCenum) LastNullDeviceError = ATOMIC_INIT_STATIC(ALC_NO_ERROR); /* Thread-local current context */ static altss_t LocalContext; /* Process-wide current context */ -static ALCcontext *volatile GlobalContext = NULL; +static ATOMIC(ALCcontext*) GlobalContext = ATOMIC_INIT_STATIC(NULL); /* Mixing thread piority level */ ALint RTPrioLevel; @@ -748,6 +740,11 @@ static alonce_flag alc_config_once = AL_ONCE_FLAG_INIT; /* Default effect that applies to sources that don't have an effect on send 0 */ static ALeffect DefaultEffect; +/* Flag to specify if alcSuspendContext/alcProcessContext should defer/process + * updates. + */ +static ALCboolean SuspendDefers = ALC_TRUE; + /************************************************ * ALC information @@ -758,8 +755,8 @@ static const ALCchar alcNoDeviceExtList[] = static const ALCchar alcExtensionList[] = "ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE " "ALC_EXT_DEDICATED ALC_EXT_disconnect ALC_EXT_EFX " - "ALC_EXT_thread_local_context ALC_SOFTX_device_clock ALC_SOFTX_HRTF " - "ALC_SOFT_loopback ALC_SOFTX_midi_interface ALC_SOFTX_pause_device"; + "ALC_EXT_thread_local_context ALC_SOFTX_device_clock ALC_SOFT_HRTF " + "ALC_SOFT_loopback ALC_SOFT_pause_device"; static const ALCint alcMajorVersion = 1; static const ALCint alcMinorVersion = 1; @@ -770,7 +767,7 @@ static const ALCint alcEFXMinorVersion = 0; /************************************************ * Device lists ************************************************/ -static ALCdevice *volatile DeviceList = NULL; +static ATOMIC(ALCdevice*) DeviceList = ATOMIC_INIT_STATIC(NULL); static almtx_t ListLock; static inline void LockLists(void) @@ -908,9 +905,23 @@ static void alc_initconfig(void) } ReadALConfig(); + str = getenv("__ALSOFT_SUSPEND_CONTEXT"); + if(str && *str) + { + if(strcasecmp(str, "ignore") == 0) + { + SuspendDefers = ALC_FALSE; + TRACE("Selected context suspend behavior, \"ignore\"\n"); + } + else + ERR("Unhandled context suspend behavior setting: \"%s\"\n", str); + } + capfilter = 0; #if defined(HAVE_SSE4_1) - capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE4_1; + capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3 | CPU_CAP_SSE4_1; +#elif defined(HAVE_SSE3) + capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3; #elif defined(HAVE_SSE2) capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2; #elif defined(HAVE_SSE) @@ -919,7 +930,7 @@ static void alc_initconfig(void) #ifdef HAVE_NEON capfilter |= CPU_CAP_NEON; #endif - if(ConfigValueStr(NULL, "disable-cpu-exts", &str)) + if(ConfigValueStr(NULL, NULL, "disable-cpu-exts", &str)) { if(strcasecmp(str, "all") == 0) capfilter = 0; @@ -944,6 +955,8 @@ static void alc_initconfig(void) capfilter &= ~CPU_CAP_SSE; else if(len == 4 && strncasecmp(str, "sse2", len) == 0) capfilter &= ~CPU_CAP_SSE2; + else if(len == 4 && strncasecmp(str, "sse3", len) == 0) + capfilter &= ~CPU_CAP_SSE3; else if(len == 6 && strncasecmp(str, "sse4.1", len) == 0) capfilter &= ~CPU_CAP_SSE4_1; else if(len == 4 && strncasecmp(str, "neon", len) == 0) @@ -960,27 +973,9 @@ static void alc_initconfig(void) #else RTPrioLevel = 0; #endif - ConfigValueInt(NULL, "rt-prio", &RTPrioLevel); - - if(ConfigValueStr(NULL, "resampler", &str)) - { - if(strcasecmp(str, "point") == 0 || strcasecmp(str, "none") == 0) - DefaultResampler = PointResampler; - else if(strcasecmp(str, "linear") == 0) - DefaultResampler = LinearResampler; - else if(strcasecmp(str, "cubic") == 0) - DefaultResampler = CubicResampler; - else - { - char *end; + ConfigValueInt(NULL, NULL, "rt-prio", &RTPrioLevel); - n = strtol(str, &end, 0); - if(*end == '\0' && (n == PointResampler || n == LinearResampler || n == CubicResampler)) - DefaultResampler = n; - else - WARN("Invalid resampler: %s\n", str); - } - } + aluInitMixer(); str = getenv("ALSOFT_TRAP_ERROR"); if(str && (strcasecmp(str, "true") == 0 || strtol(str, NULL, 0) == 1)) @@ -993,21 +988,21 @@ static void alc_initconfig(void) str = getenv("ALSOFT_TRAP_AL_ERROR"); if(str && (strcasecmp(str, "true") == 0 || strtol(str, NULL, 0) == 1)) TrapALError = AL_TRUE; - TrapALError = GetConfigValueBool(NULL, "trap-al-error", TrapALError); + TrapALError = GetConfigValueBool(NULL, NULL, "trap-al-error", TrapALError); str = getenv("ALSOFT_TRAP_ALC_ERROR"); if(str && (strcasecmp(str, "true") == 0 || strtol(str, NULL, 0) == 1)) TrapALCError = ALC_TRUE; - TrapALCError = GetConfigValueBool(NULL, "trap-alc-error", TrapALCError); + TrapALCError = GetConfigValueBool(NULL, NULL, "trap-alc-error", TrapALCError); } - if(ConfigValueFloat("reverb", "boost", &valf)) + if(ConfigValueFloat(NULL, "reverb", "boost", &valf)) ReverbBoost *= powf(10.0f, valf / 20.0f); - EmulateEAXReverb = GetConfigValueBool("reverb", "emulate-eax", AL_FALSE); + EmulateEAXReverb = GetConfigValueBool(NULL, "reverb", "emulate-eax", AL_FALSE); if(((devs=getenv("ALSOFT_DRIVERS")) && devs[0]) || - ConfigValueStr(NULL, "drivers", &devs)) + ConfigValueStr(NULL, NULL, "drivers", &devs)) { int n; size_t len; @@ -1122,7 +1117,7 @@ static void alc_initconfig(void) V0(factory,init)(); } - if(ConfigValueStr(NULL, "excludefx", &str)) + if(ConfigValueStr(NULL, NULL, "excludefx", &str)) { size_t len; const char *next = str; @@ -1148,7 +1143,7 @@ static void alc_initconfig(void) InitEffect(&DefaultEffect); str = getenv("ALSOFT_DEFAULT_REVERB"); - if((str && str[0]) || ConfigValueStr(NULL, "default-reverb", &str)) + if((str && str[0]) || ConfigValueStr(NULL, NULL, "default-reverb", &str)) LoadReverbPreset(str, &DefaultEffect); } #define DO_INITCONFIG() alcall_once(&alc_config_once, alc_initconfig) @@ -1169,7 +1164,7 @@ static void alc_cleanup(void) free(alcCaptureDefaultDeviceSpecifier); alcCaptureDefaultDeviceSpecifier = NULL; - if((dev=ExchangePtr((XchgPtr*)&DeviceList, NULL)) != NULL) + if((dev=ATOMIC_EXCHANGE(ALCdevice*, &DeviceList, NULL)) != NULL) { ALCuint num = 0; do { @@ -1228,48 +1223,33 @@ static void alc_deinit(void) /************************************************ * Device enumeration ************************************************/ -static void ProbeDevices(al_string *list, enum DevProbe type) +static void ProbeDevices(al_string *list, struct BackendInfo *backendinfo, enum DevProbe type) { DO_INITCONFIG(); LockLists(); al_string_clear(list); - if(type == ALL_DEVICE_PROBE && (PlaybackBackend.Probe || PlaybackBackend.getFactory)) - { - if(!PlaybackBackend.getFactory) - PlaybackBackend.Probe(type); - else - { - ALCbackendFactory *factory = PlaybackBackend.getFactory(); - V(factory,probe)(type); - } - } - else if(type == CAPTURE_DEVICE_PROBE && (CaptureBackend.Probe || CaptureBackend.getFactory)) + if(!backendinfo->getFactory) + backendinfo->Probe(type); + else { - if(!CaptureBackend.getFactory) - CaptureBackend.Probe(type); - else - { - ALCbackendFactory *factory = CaptureBackend.getFactory(); - V(factory,probe)(type); - } + ALCbackendFactory *factory = backendinfo->getFactory(); + V(factory,probe)(type); } + UnlockLists(); } static void ProbeAllDevicesList(void) -{ ProbeDevices(&alcAllDevicesList, ALL_DEVICE_PROBE); } +{ ProbeDevices(&alcAllDevicesList, &PlaybackBackend, ALL_DEVICE_PROBE); } static void ProbeCaptureDeviceList(void) -{ ProbeDevices(&alcCaptureDeviceList, CAPTURE_DEVICE_PROBE); } +{ ProbeDevices(&alcCaptureDeviceList, &CaptureBackend, CAPTURE_DEVICE_PROBE); } static void AppendDevice(const ALCchar *name, al_string *devnames) { size_t len = strlen(name); if(len > 0) - { - al_string_append_range(devnames, name, name+len); - al_string_append_char(devnames, '\0'); - } + al_string_append_range(devnames, name, name+len+1); } void AppendAllDevicesList(const ALCchar *name) { AppendDevice(name, &alcAllDevicesList); } @@ -1302,9 +1282,10 @@ const ALCchar *DevFmtChannelsString(enum DevFmtChannels chans) case DevFmtStereo: return "Stereo"; case DevFmtQuad: return "Quadraphonic"; case DevFmtX51: return "5.1 Surround"; - case DevFmtX51Side: return "5.1 Side"; + case DevFmtX51Rear: return "5.1 Surround (Rear)"; case DevFmtX61: return "6.1 Surround"; case DevFmtX71: return "7.1 Surround"; + case DevFmtBFormat3D: return "B-Format 3D"; } return "(unknown channels)"; } @@ -1332,9 +1313,10 @@ ALuint ChannelsFromDevFmt(enum DevFmtChannels chans) case DevFmtStereo: return 2; case DevFmtQuad: return 4; case DevFmtX51: return 6; - case DevFmtX51Side: return 6; + case DevFmtX51Rear: return 6; case DevFmtX61: return 7; case DevFmtX71: return 8; + case DevFmtBFormat3D: return 4; } return 0; } @@ -1421,19 +1403,15 @@ DECL_CONST static ALCboolean IsValidALCChannels(ALCenum channels) /************************************************ * Miscellaneous ALC helpers ************************************************/ +enum HrtfRequestMode { + Hrtf_Default = 0, + Hrtf_Enable = 1, + Hrtf_Disable = 2, +}; + extern inline void LockContext(ALCcontext *context); extern inline void UnlockContext(ALCcontext *context); -ALint64 ALCdevice_GetLatencyDefault(ALCdevice *UNUSED(device)) -{ - return 0; -} - -ALint64 ALCdevice_GetLatency(ALCdevice *device) -{ - return V0(device->Backend,getLatency)(); -} - void ALCdevice_Lock(ALCdevice *device) { V0(device->Backend,lock)(); @@ -1453,52 +1431,65 @@ void SetDefaultWFXChannelOrder(ALCdevice *device) { ALuint i; - for(i = 0;i < MaxChannels;i++) - device->ChannelOffsets[i] = INVALID_OFFSET; + for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) + device->ChannelName[i] = InvalidChannel; switch(device->FmtChans) { - case DevFmtMono: device->ChannelOffsets[FrontCenter] = 0; - break; - case DevFmtStereo: device->ChannelOffsets[FrontLeft] = 0; - device->ChannelOffsets[FrontRight] = 1; - break; - case DevFmtQuad: device->ChannelOffsets[FrontLeft] = 0; - device->ChannelOffsets[FrontRight] = 1; - device->ChannelOffsets[BackLeft] = 2; - device->ChannelOffsets[BackRight] = 3; - break; - case DevFmtX51: device->ChannelOffsets[FrontLeft] = 0; - device->ChannelOffsets[FrontRight] = 1; - device->ChannelOffsets[FrontCenter] = 2; - device->ChannelOffsets[LFE] = 3; - device->ChannelOffsets[BackLeft] = 4; - device->ChannelOffsets[BackRight] = 5; - break; - case DevFmtX51Side: device->ChannelOffsets[FrontLeft] = 0; - device->ChannelOffsets[FrontRight] = 1; - device->ChannelOffsets[FrontCenter] = 2; - device->ChannelOffsets[LFE] = 3; - device->ChannelOffsets[SideLeft] = 4; - device->ChannelOffsets[SideRight] = 5; - break; - case DevFmtX61: device->ChannelOffsets[FrontLeft] = 0; - device->ChannelOffsets[FrontRight] = 1; - device->ChannelOffsets[FrontCenter] = 2; - device->ChannelOffsets[LFE] = 3; - device->ChannelOffsets[BackCenter] = 4; - device->ChannelOffsets[SideLeft] = 5; - device->ChannelOffsets[SideRight] = 6; - break; - case DevFmtX71: device->ChannelOffsets[FrontLeft] = 0; - device->ChannelOffsets[FrontRight] = 1; - device->ChannelOffsets[FrontCenter] = 2; - device->ChannelOffsets[LFE] = 3; - device->ChannelOffsets[BackLeft] = 4; - device->ChannelOffsets[BackRight] = 5; - device->ChannelOffsets[SideLeft] = 6; - device->ChannelOffsets[SideRight] = 7; - break; + case DevFmtMono: + device->ChannelName[0] = FrontCenter; + break; + case DevFmtStereo: + device->ChannelName[0] = FrontLeft; + device->ChannelName[1] = FrontRight; + break; + case DevFmtQuad: + device->ChannelName[0] = FrontLeft; + device->ChannelName[1] = FrontRight; + device->ChannelName[2] = BackLeft; + device->ChannelName[3] = BackRight; + break; + case DevFmtX51: + device->ChannelName[0] = FrontLeft; + device->ChannelName[1] = FrontRight; + device->ChannelName[2] = FrontCenter; + device->ChannelName[3] = LFE; + device->ChannelName[4] = SideLeft; + device->ChannelName[5] = SideRight; + break; + case DevFmtX51Rear: + device->ChannelName[0] = FrontLeft; + device->ChannelName[1] = FrontRight; + device->ChannelName[2] = FrontCenter; + device->ChannelName[3] = LFE; + device->ChannelName[4] = BackLeft; + device->ChannelName[5] = BackRight; + break; + case DevFmtX61: + device->ChannelName[0] = FrontLeft; + device->ChannelName[1] = FrontRight; + device->ChannelName[2] = FrontCenter; + device->ChannelName[3] = LFE; + device->ChannelName[4] = BackCenter; + device->ChannelName[5] = SideLeft; + device->ChannelName[6] = SideRight; + break; + case DevFmtX71: + device->ChannelName[0] = FrontLeft; + device->ChannelName[1] = FrontRight; + device->ChannelName[2] = FrontCenter; + device->ChannelName[3] = LFE; + device->ChannelName[4] = BackLeft; + device->ChannelName[5] = BackRight; + device->ChannelName[6] = SideLeft; + device->ChannelName[7] = SideRight; + break; + case DevFmtBFormat3D: + device->ChannelName[0] = BFormatW; + device->ChannelName[1] = BFormatX; + device->ChannelName[2] = BFormatY; + device->ChannelName[3] = BFormatZ; + break; } } @@ -1510,37 +1501,114 @@ void SetDefaultChannelOrder(ALCdevice *device) { ALuint i; - for(i = 0;i < MaxChannels;i++) - device->ChannelOffsets[i] = INVALID_OFFSET; + for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) + device->ChannelName[i] = InvalidChannel; switch(device->FmtChans) { - case DevFmtX51: device->ChannelOffsets[FrontLeft] = 0; - device->ChannelOffsets[FrontRight] = 1; - device->ChannelOffsets[BackLeft] = 2; - device->ChannelOffsets[BackRight] = 3; - device->ChannelOffsets[FrontCenter] = 4; - device->ChannelOffsets[LFE] = 5; - return; - case DevFmtX71: device->ChannelOffsets[FrontLeft] = 0; - device->ChannelOffsets[FrontRight] = 1; - device->ChannelOffsets[BackLeft] = 2; - device->ChannelOffsets[BackRight] = 3; - device->ChannelOffsets[FrontCenter] = 4; - device->ChannelOffsets[LFE] = 5; - device->ChannelOffsets[SideLeft] = 6; - device->ChannelOffsets[SideRight] = 7; - return; + case DevFmtX51Rear: + device->ChannelName[0] = FrontLeft; + device->ChannelName[1] = FrontRight; + device->ChannelName[2] = BackLeft; + device->ChannelName[3] = BackRight; + device->ChannelName[4] = FrontCenter; + device->ChannelName[5] = LFE; + return; + case DevFmtX71: + device->ChannelName[0] = FrontLeft; + device->ChannelName[1] = FrontRight; + device->ChannelName[2] = BackLeft; + device->ChannelName[3] = BackRight; + device->ChannelName[4] = FrontCenter; + device->ChannelName[5] = LFE; + device->ChannelName[6] = SideLeft; + device->ChannelName[7] = SideRight; + return; /* Same as WFX order */ case DevFmtMono: case DevFmtStereo: case DevFmtQuad: - case DevFmtX51Side: + case DevFmtX51: case DevFmtX61: + case DevFmtBFormat3D: + SetDefaultWFXChannelOrder(device); break; } - SetDefaultWFXChannelOrder(device); +} + +extern inline ALint GetChannelIdxByName(const ALCdevice *device, enum Channel chan); + + +/* ALCcontext_DeferUpdates + * + * Defers/suspends updates for the given context's listener and sources. This + * does *NOT* stop mixing, but rather prevents certain property changes from + * taking effect. + */ +void ALCcontext_DeferUpdates(ALCcontext *context) +{ + ALCdevice *device = context->Device; + FPUCtl oldMode; + + SetMixerFPUMode(&oldMode); + + V0(device->Backend,lock)(); + if(!context->DeferUpdates) + { + context->DeferUpdates = AL_TRUE; + + /* Make sure all pending updates are performed */ + UpdateContextSources(context); +#define UPDATE_SLOT(iter) do { \ + if(ATOMIC_EXCHANGE(ALenum, &(*iter)->NeedsUpdate, AL_FALSE)) \ + V((*iter)->EffectState,update)(device, *iter); \ +} while(0) + VECTOR_FOR_EACH(ALeffectslot*, context->ActiveAuxSlots, UPDATE_SLOT); +#undef UPDATE_SLOT + } + V0(device->Backend,unlock)(); + + RestoreFPUMode(&oldMode); +} + +/* ALCcontext_ProcessUpdates + * + * Resumes update processing after being deferred. + */ +void ALCcontext_ProcessUpdates(ALCcontext *context) +{ + ALCdevice *device = context->Device; + + V0(device->Backend,lock)(); + if(context->DeferUpdates) + { + ALsizei pos; + + context->DeferUpdates = AL_FALSE; + + LockUIntMapRead(&context->SourceMap); + for(pos = 0;pos < context->SourceMap.size;pos++) + { + ALsource *Source = context->SourceMap.array[pos].value; + ALenum new_state; + + if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) && + Source->Offset >= 0.0) + { + WriteLock(&Source->queue_lock); + ApplyOffset(Source); + WriteUnlock(&Source->queue_lock); + } + + new_state = Source->new_state; + Source->new_state = AL_NONE; + if(new_state) + SetSourceState(Source, context, new_state); + } + UnlockUIntMapRead(&context->SourceMap); + } + V0(device->Backend,unlock)(); } @@ -1562,9 +1630,9 @@ static void alcSetError(ALCdevice *device, ALCenum errorCode) } if(device) - device->LastError = errorCode; + ATOMIC_STORE(&device->LastError, errorCode); else - LastNullDeviceError = errorCode; + ATOMIC_STORE(&LastNullDeviceError, errorCode); } @@ -1588,10 +1656,14 @@ static inline void UpdateClockBase(ALCdevice *device) static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) { ALCcontext *context; + enum HrtfRequestMode hrtf_appreq = Hrtf_Default; + enum HrtfRequestMode hrtf_userreq = Hrtf_Default; enum DevFmtChannels oldChans; enum DevFmtType oldType; ALCuint oldFreq; FPUCtl oldMode; + ALCsizei hrtf_id = -1; + size_t size; // Check for attributes if(device->Type == Loopback) @@ -1663,12 +1735,17 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(attrList[attrIdx] == ALC_HRTF_SOFT) { - if(attrList[attrIdx + 1] != ALC_FALSE) - device->Flags |= DEVICE_HRTF_REQUEST; + if(attrList[attrIdx + 1] == ALC_FALSE) + hrtf_appreq = Hrtf_Disable; + else if(attrList[attrIdx + 1] == ALC_TRUE) + hrtf_appreq = Hrtf_Enable; else - device->Flags &= ~DEVICE_HRTF_REQUEST; + hrtf_appreq = Hrtf_Default; } + if(attrList[attrIdx] == ALC_HRTF_ID_SOFT) + hrtf_id = attrList[attrIdx + 1]; + attrIdx += 2; } @@ -1678,15 +1755,15 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) return ALC_INVALID_VALUE; } - ConfigValueUInt(NULL, "sends", &numSends); + ConfigValueUInt(NULL, NULL, "sends", &numSends); numSends = minu(MAX_SENDS, numSends); if((device->Flags&DEVICE_RUNNING)) V0(device->Backend,stop)(); device->Flags &= ~DEVICE_RUNNING; - if(freq != device->Frequency) - UpdateClockBase(device); + UpdateClockBase(device); + device->Frequency = freq; device->FmtChans = schans; device->FmtType = stype; @@ -1732,29 +1809,34 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(attrList[attrIdx] == ALC_HRTF_SOFT) { - if(attrList[attrIdx + 1] != ALC_FALSE) - device->Flags |= DEVICE_HRTF_REQUEST; + if(attrList[attrIdx + 1] == ALC_FALSE) + hrtf_appreq = Hrtf_Disable; + else if(attrList[attrIdx + 1] == ALC_TRUE) + hrtf_appreq = Hrtf_Enable; else - device->Flags &= ~DEVICE_HRTF_REQUEST; + hrtf_appreq = Hrtf_Default; } + if(attrList[attrIdx] == ALC_HRTF_ID_SOFT) + hrtf_id = attrList[attrIdx + 1]; + attrIdx += 2; } - ConfigValueUInt(NULL, "frequency", &freq); + ConfigValueUInt(al_string_get_cstr(device->DeviceName), NULL, "frequency", &freq); freq = maxu(freq, MIN_OUTPUT_RATE); - ConfigValueUInt(NULL, "sends", &numSends); + ConfigValueUInt(al_string_get_cstr(device->DeviceName), NULL, "sends", &numSends); numSends = minu(MAX_SENDS, numSends); + UpdateClockBase(device); + device->UpdateSize = (ALuint64)device->UpdateSize * freq / device->Frequency; /* SSE and Neon do best with the update size being a multiple of 4 */ if((CPUCapFlags&(CPU_CAP_SSE|CPU_CAP_NEON)) != 0) device->UpdateSize = (device->UpdateSize+3)&~3; - if(freq != device->Frequency) - UpdateClockBase(device); device->Frequency = freq; device->NumMonoSources = numMono; device->NumStereoSources = numStereo; @@ -1764,42 +1846,90 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if((device->Flags&DEVICE_RUNNING)) return ALC_NO_ERROR; - UpdateClockBase(device); + al_free(device->DryBuffer); + device->DryBuffer = NULL; - oldFreq = device->Frequency; - oldChans = device->FmtChans; - oldType = device->FmtType; - - TRACE("Pre-reset: %s%s, %s%s, %s%uhz, %u update size x%d\n", - (device->Flags&DEVICE_CHANNELS_REQUEST)?"*":"", - DevFmtChannelsString(device->FmtChans), - (device->Flags&DEVICE_SAMPLE_TYPE_REQUEST)?"*":"", - DevFmtTypeString(device->FmtType), - (device->Flags&DEVICE_FREQUENCY_REQUEST)?"*":"", - device->Frequency, - device->UpdateSize, device->NumUpdates); + UpdateClockBase(device); + device->Hrtf_Status = ALC_HRTF_DISABLED_SOFT; if(device->Type != Loopback) { - int nohrtf = !(device->Flags&DEVICE_HRTF_REQUEST); - if(GetConfigValueBool(NULL, "hrtf", !nohrtf)) - device->Flags |= DEVICE_HRTF_REQUEST; - else - device->Flags &= ~DEVICE_HRTF_REQUEST; + const char *hrtf; + if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "hrtf", &hrtf)) + { + if(strcasecmp(hrtf, "true") == 0) + hrtf_userreq = Hrtf_Enable; + else if(strcasecmp(hrtf, "false") == 0) + hrtf_userreq = Hrtf_Disable; + else if(strcasecmp(hrtf, "auto") != 0) + ERR("Unexpected hrtf value: %s\n", hrtf); + } + + if(hrtf_userreq == Hrtf_Enable || (hrtf_userreq != Hrtf_Disable && hrtf_appreq == Hrtf_Enable)) + { + if(VECTOR_SIZE(device->Hrtf_List) == 0) + { + VECTOR_DEINIT(device->Hrtf_List); + device->Hrtf_List = EnumerateHrtf(device->DeviceName); + } + if(VECTOR_SIZE(device->Hrtf_List) > 0) + { + device->FmtChans = DevFmtStereo; + if(hrtf_id >= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->Hrtf_List)) + device->Frequency = GetHrtfSampleRate(VECTOR_ELEM(device->Hrtf_List, hrtf_id).hrtf); + else + device->Frequency = GetHrtfSampleRate(VECTOR_ELEM(device->Hrtf_List, 0).hrtf); + device->Flags |= DEVICE_CHANNELS_REQUEST | DEVICE_FREQUENCY_REQUEST; + } + else + { + hrtf_userreq = hrtf_appreq = Hrtf_Default; + device->Hrtf_Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; + } + } } - if((device->Flags&DEVICE_HRTF_REQUEST)) + else if(hrtf_appreq == Hrtf_Enable) { - enum DevFmtChannels chans; - ALCuint freq; - if(FindHrtfFormat(device, &chans, &freq)) + size_t i; + /* Loopback device. We don't need to match to a specific HRTF entry + * here. If the requested ID matches, we'll pick that later, if not, + * we'll try to auto-select one anyway. */ + if(device->FmtChans != DevFmtStereo) + i = VECTOR_SIZE(device->Hrtf_List); + else { - device->Frequency = freq; - device->FmtChans = chans; - device->Flags |= DEVICE_CHANNELS_REQUEST | - DEVICE_FREQUENCY_REQUEST; + if(VECTOR_SIZE(device->Hrtf_List) == 0) + { + VECTOR_DEINIT(device->Hrtf_List); + device->Hrtf_List = EnumerateHrtf(device->DeviceName); + } + for(i = 0;i < VECTOR_SIZE(device->Hrtf_List);i++) + { + const struct Hrtf *hrtf = VECTOR_ELEM(device->Hrtf_List, i).hrtf; + if(GetHrtfSampleRate(hrtf) == device->Frequency) + break; + } + } + if(i == VECTOR_SIZE(device->Hrtf_List)) + { + ERR("Requested format not HRTF compatible: %s, %uhz\n", + DevFmtChannelsString(device->FmtChans), device->Frequency); + hrtf_appreq = Hrtf_Default; + device->Hrtf_Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; } } + oldFreq = device->Frequency; + oldChans = device->FmtChans; + oldType = device->FmtType; + + TRACE("Pre-reset: %s%s, %s%s, %s%uhz, %u update size x%d\n", + (device->Flags&DEVICE_CHANNELS_REQUEST)?"*":"", DevFmtChannelsString(device->FmtChans), + (device->Flags&DEVICE_SAMPLE_TYPE_REQUEST)?"*":"", DevFmtTypeString(device->FmtType), + (device->Flags&DEVICE_FREQUENCY_REQUEST)?"*":"", device->Frequency, + device->UpdateSize, device->NumUpdates + ); + if(V0(device->Backend,reset)() == ALC_FALSE) return ALC_INVALID_DEVICE; @@ -1822,61 +1952,170 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } TRACE("Post-reset: %s, %s, %uhz, %u update size x%d\n", - DevFmtChannelsString(device->FmtChans), - DevFmtTypeString(device->FmtType), device->Frequency, - device->UpdateSize, device->NumUpdates); - - aluInitPanning(device); - - V(device->Synth,update)(device); + DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), + device->Frequency, device->UpdateSize, device->NumUpdates + ); - device->Hrtf = NULL; - if((device->Flags&DEVICE_HRTF_REQUEST)) + if((device->UpdateSize&3) != 0) { - device->Hrtf = GetHrtf(device); - if(!device->Hrtf) - device->Flags &= ~DEVICE_HRTF_REQUEST; + if((CPUCapFlags&CPU_CAP_SSE)) + WARN("SSE performs best with multiple of 4 update sizes (%u)\n", device->UpdateSize); + if((CPUCapFlags&CPU_CAP_NEON)) + WARN("NEON performs best with multiple of 4 update sizes (%u)\n", device->UpdateSize); } - TRACE("HRTF %s\n", device->Hrtf?"enabled":"disabled"); - if(!device->Hrtf && device->Bs2bLevel > 0 && device->Bs2bLevel <= 6) + device->Hrtf = NULL; + device->Hrtf_Mode = DisabledHrtf; + al_string_clear(&device->Hrtf_Name); + if(device->FmtChans != DevFmtStereo) { - if(!device->Bs2b) - { - device->Bs2b = calloc(1, sizeof(*device->Bs2b)); - bs2b_clear(device->Bs2b); - } - bs2b_set_srate(device->Bs2b, device->Frequency); - bs2b_set_level(device->Bs2b, device->Bs2bLevel); - TRACE("BS2B level %d\n", device->Bs2bLevel); + if(hrtf_appreq == Hrtf_Enable) + device->Hrtf_Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; + + free(device->Bs2b); + device->Bs2b = NULL; } else { - free(device->Bs2b); - device->Bs2b = NULL; - TRACE("BS2B disabled\n"); + bool headphones = device->IsHeadphones; + enum HrtfMode hrtf_mode = FullHrtf; + ALCenum hrtf_status = device->Hrtf_Status; + const char *mode; + int bs2blevel; + int usehrtf; + + if(device->Type != Loopback) + { + if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "stereo-mode", &mode)) + { + if(strcasecmp(mode, "headphones") == 0) + headphones = true; + else if(strcasecmp(mode, "speakers") == 0) + headphones = false; + else if(strcasecmp(mode, "auto") != 0) + ERR("Unexpected stereo-mode: %s\n", mode); + } + + if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "hrtf-mode", &mode)) + { + if(strcasecmp(mode, "full") == 0) + hrtf_mode = FullHrtf; + else if(strcasecmp(mode, "basic") == 0) + hrtf_mode = BasicHrtf; + else + ERR("Unexpected hrtf-mode: %s\n", mode); + } + } + + + if(hrtf_userreq == Hrtf_Default) + { + usehrtf = (headphones && hrtf_appreq != Hrtf_Disable) || + (hrtf_appreq == Hrtf_Enable); + if(headphones && hrtf_appreq != Hrtf_Disable) + hrtf_status = ALC_HRTF_HEADPHONES_DETECTED_SOFT; + else if(usehrtf) + hrtf_status = ALC_HRTF_ENABLED_SOFT; + } + else + { + usehrtf = (hrtf_userreq == Hrtf_Enable); + if(!usehrtf) + hrtf_status = ALC_HRTF_DENIED_SOFT; + else + hrtf_status = ALC_HRTF_REQUIRED_SOFT; + } + + if(!usehrtf) + device->Hrtf_Status = hrtf_status; + else + { + size_t i; + + device->Hrtf_Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; + if(VECTOR_SIZE(device->Hrtf_List) == 0) + { + VECTOR_DEINIT(device->Hrtf_List); + device->Hrtf_List = EnumerateHrtf(device->DeviceName); + } + + if(hrtf_id >= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->Hrtf_List)) + { + const HrtfEntry *entry = &VECTOR_ELEM(device->Hrtf_List, hrtf_id); + if(GetHrtfSampleRate(entry->hrtf) == device->Frequency) + { + device->Hrtf = entry->hrtf; + al_string_copy(&device->Hrtf_Name, entry->name); + } + } + if(!device->Hrtf) + { + for(i = 0;i < VECTOR_SIZE(device->Hrtf_List);i++) + { + const HrtfEntry *entry = &VECTOR_ELEM(device->Hrtf_List, i); + if(GetHrtfSampleRate(entry->hrtf) == device->Frequency) + { + device->Hrtf = entry->hrtf; + al_string_copy(&device->Hrtf_Name, entry->name); + break; + } + } + } + } + if(device->Hrtf) + { + device->Hrtf_Mode = hrtf_mode; + device->Hrtf_Status = hrtf_status; + TRACE("HRTF enabled, \"%s\"\n", al_string_get_cstr(device->Hrtf_Name)); + free(device->Bs2b); + device->Bs2b = NULL; + } + else + { + TRACE("HRTF disabled\n"); + + bs2blevel = ((headphones && hrtf_appreq != Hrtf_Disable) || + (hrtf_appreq == Hrtf_Enable)) ? 5 : 0; + if(device->Type != Loopback) + ConfigValueInt(al_string_get_cstr(device->DeviceName), NULL, "cf_level", &bs2blevel); + if(bs2blevel > 0 && bs2blevel <= 6) + { + if(!device->Bs2b) + { + device->Bs2b = calloc(1, sizeof(*device->Bs2b)); + bs2b_clear(device->Bs2b); + } + bs2b_set_params(device->Bs2b, bs2blevel, device->Frequency); + TRACE("BS2B enabled\n"); + } + else + { + free(device->Bs2b); + device->Bs2b = NULL; + TRACE("BS2B disabled\n"); + } + } } - device->Flags &= ~DEVICE_WIDE_STEREO; - if(device->Type != Loopback && !device->Hrtf && GetConfigValueBool(NULL, "wide-stereo", AL_FALSE)) - device->Flags |= DEVICE_WIDE_STEREO; + aluInitPanning(device); - if(!device->Hrtf && (device->UpdateSize&3)) + /* With HRTF, allocate two extra channels for the post-filter output. */ + size = sizeof(device->DryBuffer[0]) * (device->NumChannels + (device->Hrtf ? 2 : 0)); + device->DryBuffer = al_calloc(16, size); + if(!device->DryBuffer) { - if((CPUCapFlags&CPU_CAP_SSE)) - WARN("SSE performs best with multiple of 4 update sizes (%u)\n", device->UpdateSize); - if((CPUCapFlags&CPU_CAP_NEON)) - WARN("NEON performs best with multiple of 4 update sizes (%u)\n", device->UpdateSize); + ERR("Failed to allocate "SZFMT" bytes for mix buffer\n", size); + return ALC_INVALID_DEVICE; } SetMixerFPUMode(&oldMode); - ALCdevice_Lock(device); - context = device->ContextList; + V0(device->Backend,lock)(); + context = ATOMIC_LOAD(&device->ContextList); while(context) { ALsizei pos; - context->UpdateSources = AL_FALSE; + ATOMIC_STORE(&context->UpdateSources, AL_FALSE); LockUIntMapRead(&context->EffectSlotMap); for(pos = 0;pos < context->EffectSlotMap.size;pos++) { @@ -1885,11 +2124,11 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(V(slot->EffectState,deviceUpdate)(device) == AL_FALSE) { UnlockUIntMapRead(&context->EffectSlotMap); - ALCdevice_Unlock(device); + V0(device->Backend,unlock)(); RestoreFPUMode(&oldMode); return ALC_INVALID_DEVICE; } - slot->NeedsUpdate = AL_FALSE; + ATOMIC_STORE(&slot->NeedsUpdate, AL_FALSE); V(slot->EffectState,update)(device, slot); } UnlockUIntMapRead(&context->EffectSlotMap); @@ -1908,24 +2147,28 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) source->Send[s].GainHF = 1.0f; s++; } - source->NeedsUpdate = AL_TRUE; + ATOMIC_STORE(&source->NeedsUpdate, AL_TRUE); } UnlockUIntMapRead(&context->SourceMap); - for(pos = 0;pos < context->ActiveSourceCount;pos++) + for(pos = 0;pos < context->VoiceCount;pos++) { - ALactivesource *src = context->ActiveSources[pos]; - ALsource *source = src->Source; + ALvoice *voice = &context->Voices[pos]; + ALsource *source = voice->Source; ALuint s = device->NumAuxSends; + while(s < MAX_SENDS) { - src->Send[s].Moving = AL_FALSE; - src->Send[s].Counter = 0; + voice->Send[s].Moving = AL_FALSE; + voice->Send[s].Counter = 0; s++; } - src->Update(src, context); - source->NeedsUpdate = AL_FALSE; + if(source) + { + ATOMIC_STORE(&source->NeedsUpdate, AL_FALSE); + voice->Update(voice, source, context); + } } context = context->next; @@ -1936,14 +2179,14 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(V(slot->EffectState,deviceUpdate)(device) == AL_FALSE) { - ALCdevice_Unlock(device); + V0(device->Backend,unlock)(); RestoreFPUMode(&oldMode); return ALC_INVALID_DEVICE; } - slot->NeedsUpdate = AL_FALSE; + ATOMIC_STORE(&slot->NeedsUpdate, AL_FALSE); V(slot->EffectState,update)(device, slot); } - ALCdevice_Unlock(device); + V0(device->Backend,unlock)(); RestoreFPUMode(&oldMode); if(!(device->Flags&DEVICE_PAUSED)) @@ -1969,9 +2212,6 @@ static ALCvoid FreeDevice(ALCdevice *device) DELETE_OBJ(device->Backend); device->Backend = NULL; - DELETE_OBJ(device->Synth); - device->Synth = NULL; - if(device->DefaultSlot) { ALeffectState *state = device->DefaultSlot->EffectState; @@ -1979,10 +2219,6 @@ static ALCvoid FreeDevice(ALCdevice *device) DELETE_OBJ(state); } - if(device->DefaultSfont) - ALsoundfont_deleteSoundfont(device->DefaultSfont, device); - device->DefaultSfont = NULL; - if(device->BufferMap.size > 0) { WARN("(%p) Deleting %d Buffer(s)\n", device, device->BufferMap.size); @@ -2004,32 +2240,17 @@ static ALCvoid FreeDevice(ALCdevice *device) } ResetUIntMap(&device->FilterMap); - if(device->SfontMap.size > 0) - { - WARN("(%p) Deleting %d Soundfont(s)\n", device, device->SfontMap.size); - ReleaseALSoundfonts(device); - } - ResetUIntMap(&device->SfontMap); - - if(device->PresetMap.size > 0) - { - WARN("(%p) Deleting %d Preset(s)\n", device, device->PresetMap.size); - ReleaseALPresets(device); - } - ResetUIntMap(&device->PresetMap); - - if(device->FontsoundMap.size > 0) - { - WARN("(%p) Deleting %d Fontsound(s)\n", device, device->FontsoundMap.size); - ReleaseALFontsounds(device); - } - ResetUIntMap(&device->FontsoundMap); + AL_STRING_DEINIT(device->Hrtf_Name); + FreeHrtfList(&device->Hrtf_List); free(device->Bs2b); device->Bs2b = NULL; AL_STRING_DEINIT(device->DeviceName); + al_free(device->DryBuffer); + device->DryBuffer = NULL; + al_free(device); } @@ -2053,22 +2274,26 @@ void ALCdevice_DecRef(ALCdevice *device) * * Checks if the device handle is valid, and increments its ref count if so. */ -static ALCdevice *VerifyDevice(ALCdevice *device) +static ALCboolean VerifyDevice(ALCdevice **device) { ALCdevice *tmpDevice; - if(!device) - return NULL; - LockLists(); - tmpDevice = DeviceList; - while(tmpDevice && tmpDevice != device) + tmpDevice = ATOMIC_LOAD(&DeviceList); + while(tmpDevice) + { + if(tmpDevice == *device) + { + ALCdevice_IncRef(tmpDevice); + UnlockLists(); + return ALC_TRUE; + } tmpDevice = tmpDevice->next; - - if(tmpDevice) - ALCdevice_IncRef(tmpDevice); + } UnlockLists(); - return tmpDevice; + + *device = NULL; + return ALC_FALSE; } @@ -2078,35 +2303,29 @@ static ALCdevice *VerifyDevice(ALCdevice *device) */ static ALvoid InitContext(ALCcontext *Context) { - ALint i, j; - + ALlistener *listener = Context->Listener; //Initialise listener - Context->Listener->Gain = 1.0f; - Context->Listener->MetersPerUnit = 1.0f; - Context->Listener->Position[0] = 0.0f; - Context->Listener->Position[1] = 0.0f; - Context->Listener->Position[2] = 0.0f; - Context->Listener->Velocity[0] = 0.0f; - Context->Listener->Velocity[1] = 0.0f; - Context->Listener->Velocity[2] = 0.0f; - Context->Listener->Forward[0] = 0.0f; - Context->Listener->Forward[1] = 0.0f; - Context->Listener->Forward[2] = -1.0f; - Context->Listener->Up[0] = 0.0f; - Context->Listener->Up[1] = 1.0f; - Context->Listener->Up[2] = 0.0f; - for(i = 0;i < 4;i++) - { - for(j = 0;j < 4;j++) - Context->Listener->Params.Matrix[i][j] = ((i==j) ? 1.0f : 0.0f); - } - for(i = 0;i < 3;i++) - Context->Listener->Params.Velocity[i] = 0.0f; + listener->Gain = 1.0f; + listener->MetersPerUnit = 1.0f; + aluVectorSet(&listener->Position, 0.0f, 0.0f, 0.0f, 1.0f); + aluVectorSet(&listener->Velocity, 0.0f, 0.0f, 0.0f, 0.0f); + listener->Forward[0] = 0.0f; + listener->Forward[1] = 0.0f; + listener->Forward[2] = -1.0f; + listener->Up[0] = 0.0f; + listener->Up[1] = 1.0f; + listener->Up[2] = 0.0f; + aluMatrixdSet(&listener->Params.Matrix, + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0 + ); + aluVectorSet(&listener->Params.Velocity, 0.0f, 0.0f, 0.0f, 0.0f); //Validate Context - Context->LastError = AL_NO_ERROR; - Context->UpdateSources = AL_FALSE; - Context->ActiveSourceCount = 0; + ATOMIC_INIT(&Context->LastError, AL_NO_ERROR); + ATOMIC_INIT(&Context->UpdateSources, AL_FALSE); InitUIntMap(&Context->SourceMap, Context->Device->MaxNoOfSources); InitUIntMap(&Context->EffectSlotMap, Context->Device->AuxiliaryEffectSlotMax); @@ -2127,10 +2346,8 @@ static ALvoid InitContext(ALCcontext *Context) * Cleans up the context, and destroys any remaining objects the app failed to * delete. Called once there's no more references on the context. */ -static ALCvoid FreeContext(ALCcontext *context) +static void FreeContext(ALCcontext *context) { - ALsizei i; - TRACE("%p\n", context); if(context->SourceMap.size > 0) @@ -2147,15 +2364,10 @@ static ALCvoid FreeContext(ALCcontext *context) } ResetUIntMap(&context->EffectSlotMap); - for(i = 0;i < context->MaxActiveSources;i++) - { - al_free(context->ActiveSources[i]); - context->ActiveSources[i] = NULL; - } - free(context->ActiveSources); - context->ActiveSources = NULL; - context->ActiveSourceCount = 0; - context->MaxActiveSources = 0; + al_free(context->Voices); + context->Voices = NULL; + context->VoiceCount = 0; + context->MaxVoices = 0; VECTOR_DEINIT(context->ActiveAuxSlots); @@ -2164,7 +2376,7 @@ static ALCvoid FreeContext(ALCcontext *context) //Invalidate context memset(context, 0, sizeof(ALCcontext)); - free(context); + al_free(context); } /* ReleaseContext @@ -2174,7 +2386,8 @@ static ALCvoid FreeContext(ALCcontext *context) */ static void ReleaseContext(ALCcontext *context, ALCdevice *device) { - ALCcontext *volatile*tmp_ctx; + ALCcontext *nextctx; + ALCcontext *origctx; if(altss_get(LocalContext) == context) { @@ -2183,16 +2396,20 @@ static void ReleaseContext(ALCcontext *context, ALCdevice *device) ALCcontext_DecRef(context); } - if(CompExchangePtr((XchgPtr*)&GlobalContext, context, NULL) == context) + origctx = context; + if(ATOMIC_COMPARE_EXCHANGE_STRONG(ALCcontext*, &GlobalContext, &origctx, NULL)) ALCcontext_DecRef(context); ALCdevice_Lock(device); - tmp_ctx = &device->ContextList; - while(*tmp_ctx) + origctx = context; + nextctx = context->next; + if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALCcontext*, &device->ContextList, &origctx, nextctx)) { - if(CompExchangePtr((XchgPtr*)tmp_ctx, context, context->next) == context) - break; - tmp_ctx = &(*tmp_ctx)->next; + ALCcontext *list; + do { + list = origctx; + origctx = context; + } while(!COMPARE_EXCHANGE(&list->next, &origctx, nextctx)); } ALCdevice_Unlock(device); @@ -2224,30 +2441,31 @@ static void ReleaseThreadCtx(void *ptr) * * Checks that the given context is valid, and increments its reference count. */ -static ALCcontext *VerifyContext(ALCcontext *context) +static ALCboolean VerifyContext(ALCcontext **context) { ALCdevice *dev; LockLists(); - dev = DeviceList; + dev = ATOMIC_LOAD(&DeviceList); while(dev) { - ALCcontext *tmp_ctx = dev->ContextList; - while(tmp_ctx) + ALCcontext *ctx = ATOMIC_LOAD(&dev->ContextList); + while(ctx) { - if(tmp_ctx == context) + if(ctx == *context) { - ALCcontext_IncRef(tmp_ctx); + ALCcontext_IncRef(ctx); UnlockLists(); - return tmp_ctx; + return ALC_TRUE; } - tmp_ctx = tmp_ctx->next; + ctx = ctx->next; } dev = dev->next; } UnlockLists(); - return NULL; + *context = NULL; + return ALC_FALSE; } @@ -2266,7 +2484,7 @@ ALCcontext *GetContextRef(void) else { LockLists(); - context = GlobalContext; + context = ATOMIC_LOAD(&GlobalContext); if(context) ALCcontext_IncRef(context); UnlockLists(); @@ -2288,13 +2506,13 @@ ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device) { ALCenum errorCode; - if(VerifyDevice(device)) + if(VerifyDevice(&device)) { - errorCode = ExchangeInt(&device->LastError, ALC_NO_ERROR); + errorCode = ATOMIC_EXCHANGE(ALCenum, &device->LastError, ALC_NO_ERROR); ALCdevice_DecRef(device); } else - errorCode = ExchangeInt(&LastNullDeviceError, ALC_NO_ERROR); + errorCode = ATOMIC_EXCHANGE(ALCenum, &LastNullDeviceError, ALC_NO_ERROR); return errorCode; } @@ -2302,18 +2520,38 @@ ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device) /* alcSuspendContext * - * Not functional + * Suspends updates for the given context */ -ALC_API ALCvoid ALC_APIENTRY alcSuspendContext(ALCcontext *UNUSED(context)) +ALC_API ALCvoid ALC_APIENTRY alcSuspendContext(ALCcontext *context) { + if(!SuspendDefers) + return; + + if(!VerifyContext(&context)) + alcSetError(NULL, ALC_INVALID_CONTEXT); + else + { + ALCcontext_DeferUpdates(context); + ALCcontext_DecRef(context); + } } /* alcProcessContext * - * Not functional + * Resumes processing updates for the given context */ -ALC_API ALCvoid ALC_APIENTRY alcProcessContext(ALCcontext *UNUSED(context)) +ALC_API ALCvoid ALC_APIENTRY alcProcessContext(ALCcontext *context) { + if(!SuspendDefers) + return; + + if(!VerifyContext(&context)) + alcSetError(NULL, ALC_INVALID_CONTEXT); + else + { + ALCcontext_ProcessUpdates(context); + ALCcontext_DecRef(context); + } } @@ -2356,7 +2594,7 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para break; case ALC_ALL_DEVICES_SPECIFIER: - if(VerifyDevice(Device)) + if(VerifyDevice(&Device)) { value = al_string_get_cstr(Device->DeviceName); ALCdevice_DecRef(Device); @@ -2369,7 +2607,7 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para break; case ALC_CAPTURE_DEVICE_SPECIFIER: - if(VerifyDevice(Device)) + if(VerifyDevice(&Device)) { value = al_string_get_cstr(Device->DeviceName); ALCdevice_DecRef(Device); @@ -2390,7 +2628,7 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para if(al_string_empty(alcAllDevicesList)) ProbeAllDevicesList(); - Device = VerifyDevice(Device); + VerifyDevice(&Device); free(alcDefaultAllDevicesSpecifier); alcDefaultAllDevicesSpecifier = strdup(al_string_get_cstr(alcAllDevicesList)); @@ -2405,10 +2643,10 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para if(al_string_empty(alcCaptureDeviceList)) ProbeCaptureDeviceList(); - Device = VerifyDevice(Device); + VerifyDevice(&Device); free(alcCaptureDefaultDeviceSpecifier); - alcCaptureDefaultDeviceSpecifier = strdup(al_string_get_cstr(alcAllDevicesList)); + alcCaptureDefaultDeviceSpecifier = strdup(al_string_get_cstr(alcCaptureDeviceList)); if(!alcCaptureDefaultDeviceSpecifier) alcSetError(Device, ALC_OUT_OF_MEMORY); @@ -2417,7 +2655,7 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para break; case ALC_EXTENSIONS: - if(!VerifyDevice(Device)) + if(!VerifyDevice(&Device)) value = alcNoDeviceExtList; else { @@ -2426,8 +2664,20 @@ ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *Device, ALCenum para } break; + case ALC_HRTF_SPECIFIER_SOFT: + if(!VerifyDevice(&Device)) + alcSetError(NULL, ALC_INVALID_DEVICE); + else + { + LockLists(); + value = (Device->Hrtf ? al_string_get_cstr(Device->Hrtf_Name) : ""); + UnlockLists(); + ALCdevice_DecRef(Device); + } + break; + default: - Device = VerifyDevice(Device); + VerifyDevice(&Device); alcSetError(Device, ALC_INVALID_ENUM); if(Device) ALCdevice_DecRef(Device); break; @@ -2483,9 +2733,9 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC switch(param) { case ALC_CAPTURE_SAMPLES: - ALCdevice_Lock(device); + V0(device->Backend,lock)(); values[0] = V0(device->Backend,availableSamples)(); - ALCdevice_Unlock(device); + V0(device->Backend,unlock)(); return 1; case ALC_CONNECTED: @@ -2519,11 +2769,11 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC return 1; case ALC_ATTRIBUTES_SIZE: - values[0] = 15; + values[0] = 17; return 1; case ALC_ALL_ATTRIBUTES: - if(size < 15) + if(size < 17) { alcSetError(device, ALC_INVALID_VALUE); return 0; @@ -2562,6 +2812,9 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC values[i++] = ALC_HRTF_SOFT; values[i++] = (device->Hrtf ? ALC_TRUE : ALC_FALSE); + values[i++] = ALC_HRTF_STATUS_SOFT; + values[i++] = device->Hrtf_Status; + values[i++] = 0; return i; @@ -2625,6 +2878,16 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC values[0] = (device->Hrtf ? ALC_TRUE : ALC_FALSE); return 1; + case ALC_HRTF_STATUS_SOFT: + values[0] = device->Hrtf_Status; + return 1; + + case ALC_NUM_HRTF_SPECIFIERS_SOFT: + FreeHrtfList(&device->Hrtf_List); + device->Hrtf_List = EnumerateHrtf(device->DeviceName); + values[0] = (ALCint)VECTOR_SIZE(device->Hrtf_List); + return 1; + default: alcSetError(device, ALC_INVALID_ENUM); return 0; @@ -2638,7 +2901,7 @@ static ALCsizei GetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALC */ ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values) { - device = VerifyDevice(device); + VerifyDevice(&device); if(size <= 0 || values == NULL) alcSetError(device, ALC_INVALID_VALUE); else @@ -2651,7 +2914,7 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, ALCint *ivals; ALsizei i; - device = VerifyDevice(device); + VerifyDevice(&device); if(size <= 0 || values == NULL) alcSetError(device, ALC_INVALID_VALUE); else if(!device || device->Type == Capture) @@ -2667,11 +2930,11 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, switch(pname) { case ALC_ATTRIBUTES_SIZE: - *values = 17; + *values = 19; break; case ALC_ALL_ATTRIBUTES: - if(size < 17) + if(size < 19) alcSetError(device, ALC_INVALID_VALUE); else { @@ -2710,6 +2973,9 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, values[i++] = ALC_HRTF_SOFT; values[i++] = (device->Hrtf ? ALC_TRUE : ALC_FALSE); + values[i++] = ALC_HRTF_STATUS_SOFT; + values[i++] = device->Hrtf_Status; + values[i++] = ALC_DEVICE_CLOCK_SOFT; values[i++] = device->ClockBase + (device->SamplesDone * DEVICE_CLOCK_RES / device->Frequency); @@ -2748,7 +3014,7 @@ ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const A { ALCboolean bResult = ALC_FALSE; - device = VerifyDevice(device); + VerifyDevice(&device); if(!extName) alcSetError(device, ALC_INVALID_VALUE); @@ -2788,7 +3054,7 @@ ALC_API ALCvoid* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar if(!funcName) { - device = VerifyDevice(device); + VerifyDevice(&device); alcSetError(device, ALC_INVALID_VALUE); if(device) ALCdevice_DecRef(device); } @@ -2814,7 +3080,7 @@ ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *e if(!enumName) { - device = VerifyDevice(device); + VerifyDevice(&device); alcSetError(device, ALC_INVALID_VALUE); if(device) ALCdevice_DecRef(device); } @@ -2840,7 +3106,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin ALCenum err; LockLists(); - if(!(device=VerifyDevice(device)) || device->Type == Capture || !device->Connected) + if(!VerifyDevice(&device) || device->Type == Capture || !device->Connected) { UnlockLists(); alcSetError(device, ALC_INVALID_DEVICE); @@ -2848,7 +3114,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin return NULL; } - device->LastError = ALC_NO_ERROR; + ATOMIC_STORE(&device->LastError, ALC_NO_ERROR); if((err=UpdateDeviceParams(device, attrList)) != ALC_NO_ERROR) { @@ -2856,15 +3122,15 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin alcSetError(device, err); if(err == ALC_INVALID_DEVICE) { - ALCdevice_Lock(device); + V0(device->Backend,lock)(); aluHandleDisconnect(device); - ALCdevice_Unlock(device); + V0(device->Backend,unlock)(); } ALCdevice_DecRef(device); return NULL; } - ALContext = calloc(1, sizeof(ALCcontext)+sizeof(ALlistener)); + ALContext = al_calloc(16, sizeof(ALCcontext)+sizeof(ALlistener)); if(ALContext) { InitRef(&ALContext->ref, 1); @@ -2872,13 +3138,13 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin VECTOR_INIT(ALContext->ActiveAuxSlots); - ALContext->MaxActiveSources = 256; - ALContext->ActiveSources = calloc(ALContext->MaxActiveSources, - sizeof(ALContext->ActiveSources[0])); + ALContext->VoiceCount = 0; + ALContext->MaxVoices = 256; + ALContext->Voices = al_calloc(16, ALContext->MaxVoices * sizeof(ALContext->Voices[0])); } - if(!ALContext || !ALContext->ActiveSources) + if(!ALContext || !ALContext->Voices) { - if(!device->ContextList) + if(!ATOMIC_LOAD(&device->ContextList)) { V0(device->Backend,stop)(); device->Flags &= ~DEVICE_RUNNING; @@ -2887,12 +3153,12 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin if(ALContext) { - free(ALContext->ActiveSources); - ALContext->ActiveSources = NULL; + al_free(ALContext->Voices); + ALContext->Voices = NULL; VECTOR_DEINIT(ALContext->ActiveAuxSlots); - free(ALContext); + al_free(ALContext); ALContext = NULL; } @@ -2905,9 +3171,12 @@ ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCin ALCdevice_IncRef(device); InitContext(ALContext); - do { - ALContext->next = device->ContextList; - } while(CompExchangePtr((XchgPtr*)&device->ContextList, ALContext->next, ALContext) != ALContext->next); + { + ALCcontext *head = ATOMIC_LOAD(&device->ContextList); + do { + ALContext->next = head; + } while(!ATOMIC_COMPARE_EXCHANGE_WEAK(ALCcontext*, &device->ContextList, &head, ALContext)); + } UnlockLists(); ALCdevice_DecRef(device); @@ -2930,7 +3199,7 @@ ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context) if(Device) { ReleaseContext(context, Device); - if(!Device->ContextList) + if(!ATOMIC_LOAD(&Device->ContextList)) { V0(Device->Backend,stop)(); Device->Flags &= ~DEVICE_RUNNING; @@ -2946,11 +3215,8 @@ ALC_API ALCvoid ALC_APIENTRY alcDestroyContext(ALCcontext *context) */ ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void) { - ALCcontext *Context; - - Context = altss_get(LocalContext); - if(!Context) Context = GlobalContext; - + ALCcontext *Context = altss_get(LocalContext); + if(!Context) Context = ATOMIC_LOAD(&GlobalContext); return Context; } @@ -2960,9 +3226,7 @@ ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void) */ ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void) { - ALCcontext *Context; - Context = altss_get(LocalContext); - return Context; + return altss_get(LocalContext); } @@ -2974,13 +3238,13 @@ ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void) ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context) { /* context must be valid or NULL */ - if(context && !(context=VerifyContext(context))) + if(context && !VerifyContext(&context)) { alcSetError(NULL, ALC_INVALID_CONTEXT); return ALC_FALSE; } /* context's reference count is already incremented */ - context = ExchangePtr((XchgPtr*)&GlobalContext, context); + context = ATOMIC_EXCHANGE(ALCcontext*, &GlobalContext, context); if(context) ALCcontext_DecRef(context); if((context=altss_get(LocalContext)) != NULL) @@ -3001,7 +3265,7 @@ ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context) ALCcontext *old; /* context must be valid or NULL */ - if(context && !(context=VerifyContext(context))) + if(context && !VerifyContext(&context)) { alcSetError(NULL, ALC_INVALID_CONTEXT); return ALC_FALSE; @@ -3023,7 +3287,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *Context) { ALCdevice *Device; - if(!(Context=VerifyContext(Context))) + if(!VerifyContext(&Context)) { alcSetError(NULL, ALC_INVALID_CONTEXT); return NULL; @@ -3053,7 +3317,16 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) return NULL; } - if(deviceName && (!deviceName[0] || strcasecmp(deviceName, alcDefaultName) == 0 || strcasecmp(deviceName, "openal-soft") == 0)) + if(deviceName && (!deviceName[0] || strcasecmp(deviceName, alcDefaultName) == 0 || strcasecmp(deviceName, "openal-soft") == 0 +#ifdef _WIN32 + /* Some old Windows apps hardcode these expecting OpenAL to use a + * specific audio API, even when they're not enumerated. Creative's + * router effectively ignores them too. + */ + || strcasecmp(deviceName, "DirectSound3D") == 0 || strcasecmp(deviceName, "DirectSound") == 0 + || strcasecmp(deviceName, "MMSYSTEM") == 0 +#endif + )) deviceName = NULL; device = al_calloc(16, sizeof(ALCdevice)+sizeof(ALeffectslot)); @@ -3067,14 +3340,17 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) InitRef(&device->ref, 1); device->Connected = ALC_TRUE; device->Type = Playback; - device->LastError = ALC_NO_ERROR; + ATOMIC_INIT(&device->LastError, ALC_NO_ERROR); device->Flags = 0; device->Bs2b = NULL; - device->Bs2bLevel = 0; + VECTOR_INIT(device->Hrtf_List); + AL_STRING_INIT(device->Hrtf_Name); + device->Hrtf_Mode = DisabledHrtf; AL_STRING_INIT(device->DeviceName); + device->DryBuffer = NULL; - device->ContextList = NULL; + ATOMIC_INIT(&device->ContextList, NULL); device->ClockBase = 0; device->SamplesDone = 0; @@ -3086,14 +3362,12 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) InitUIntMap(&device->BufferMap, ~0); InitUIntMap(&device->EffectMap, ~0); InitUIntMap(&device->FilterMap, ~0); - InitUIntMap(&device->SfontMap, ~0); - InitUIntMap(&device->PresetMap, ~0); - InitUIntMap(&device->FontsoundMap, ~0); //Set output format device->FmtChans = DevFmtChannelsDefault; device->FmtType = DevFmtTypeDefault; device->Frequency = DEFAULT_OUTPUT_RATE; + device->IsHeadphones = AL_FALSE; device->NumUpdates = 4; device->UpdateSize = 1024; @@ -3113,7 +3387,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) } - if(ConfigValueStr(NULL, "channels", &fmt)) + if(ConfigValueStr(deviceName, NULL, "channels", &fmt)) { static const struct { const char name[16]; @@ -3125,6 +3399,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) { "surround51", DevFmtX51 }, { "surround61", DevFmtX61 }, { "surround71", DevFmtX71 }, + { "surround51rear", DevFmtX51Rear }, }; size_t i; @@ -3140,7 +3415,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) if(i == COUNTOF(chanlist)) ERR("Unsupported channels: %s\n", fmt); } - if(ConfigValueStr(NULL, "sample-type", &fmt)) + if(ConfigValueStr(deviceName, NULL, "sample-type", &fmt)) { static const struct { const char name[16]; @@ -3168,57 +3443,8 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) if(i == COUNTOF(typelist)) ERR("Unsupported sample-type: %s\n", fmt); } -#define DEVICE_FORMAT_REQUEST (DEVICE_CHANNELS_REQUEST|DEVICE_SAMPLE_TYPE_REQUEST) - if((device->Flags&DEVICE_FORMAT_REQUEST) != DEVICE_FORMAT_REQUEST && - ConfigValueStr(NULL, "format", &fmt)) - { - static const struct { - const char name[32]; - enum DevFmtChannels channels; - enum DevFmtType type; - } formats[] = { - { "AL_FORMAT_MONO32", DevFmtMono, DevFmtFloat }, - { "AL_FORMAT_STEREO32", DevFmtStereo, DevFmtFloat }, - { "AL_FORMAT_QUAD32", DevFmtQuad, DevFmtFloat }, - { "AL_FORMAT_51CHN32", DevFmtX51, DevFmtFloat }, - { "AL_FORMAT_61CHN32", DevFmtX61, DevFmtFloat }, - { "AL_FORMAT_71CHN32", DevFmtX71, DevFmtFloat }, - - { "AL_FORMAT_MONO16", DevFmtMono, DevFmtShort }, - { "AL_FORMAT_STEREO16", DevFmtStereo, DevFmtShort }, - { "AL_FORMAT_QUAD16", DevFmtQuad, DevFmtShort }, - { "AL_FORMAT_51CHN16", DevFmtX51, DevFmtShort }, - { "AL_FORMAT_61CHN16", DevFmtX61, DevFmtShort }, - { "AL_FORMAT_71CHN16", DevFmtX71, DevFmtShort }, - - { "AL_FORMAT_MONO8", DevFmtMono, DevFmtByte }, - { "AL_FORMAT_STEREO8", DevFmtStereo, DevFmtByte }, - { "AL_FORMAT_QUAD8", DevFmtQuad, DevFmtByte }, - { "AL_FORMAT_51CHN8", DevFmtX51, DevFmtByte }, - { "AL_FORMAT_61CHN8", DevFmtX61, DevFmtByte }, - { "AL_FORMAT_71CHN8", DevFmtX71, DevFmtByte } - }; - size_t i; - - ERR("Option 'format' is deprecated, please use 'channels' and 'sample-type'\n"); - for(i = 0;i < COUNTOF(formats);i++) - { - if(strcasecmp(fmt, formats[i].name) == 0) - { - if(!(device->Flags&DEVICE_CHANNELS_REQUEST)) - device->FmtChans = formats[i].channels; - if(!(device->Flags&DEVICE_SAMPLE_TYPE_REQUEST)) - device->FmtType = formats[i].type; - device->Flags |= DEVICE_FORMAT_REQUEST; - break; - } - } - if(i == COUNTOF(formats)) - ERR("Unsupported format: %s\n", fmt); - } -#undef DEVICE_FORMAT_REQUEST - if(ConfigValueUInt(NULL, "frequency", &device->Frequency)) + if(ConfigValueUInt(deviceName, NULL, "frequency", &device->Frequency)) { device->Flags |= DEVICE_FREQUENCY_REQUEST; if(device->Frequency < MIN_OUTPUT_RATE) @@ -3226,41 +3452,29 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) device->Frequency = maxu(device->Frequency, MIN_OUTPUT_RATE); } - ConfigValueUInt(NULL, "periods", &device->NumUpdates); + ConfigValueUInt(deviceName, NULL, "periods", &device->NumUpdates); device->NumUpdates = clampu(device->NumUpdates, 2, 16); - ConfigValueUInt(NULL, "period_size", &device->UpdateSize); + ConfigValueUInt(deviceName, NULL, "period_size", &device->UpdateSize); device->UpdateSize = clampu(device->UpdateSize, 64, 8192); - if((CPUCapFlags&CPU_CAP_SSE)) + if((CPUCapFlags&(CPU_CAP_SSE|CPU_CAP_NEON)) != 0) device->UpdateSize = (device->UpdateSize+3)&~3; - ConfigValueUInt(NULL, "sources", &device->MaxNoOfSources); + ConfigValueUInt(deviceName, NULL, "sources", &device->MaxNoOfSources); if(device->MaxNoOfSources == 0) device->MaxNoOfSources = 256; - ConfigValueUInt(NULL, "slots", &device->AuxiliaryEffectSlotMax); + ConfigValueUInt(deviceName, NULL, "slots", &device->AuxiliaryEffectSlotMax); if(device->AuxiliaryEffectSlotMax == 0) device->AuxiliaryEffectSlotMax = 4; - ConfigValueUInt(NULL, "sends", &device->NumAuxSends); + ConfigValueUInt(deviceName, NULL, "sends", &device->NumAuxSends); if(device->NumAuxSends > MAX_SENDS) device->NumAuxSends = MAX_SENDS; - ConfigValueInt(NULL, "cf_level", &device->Bs2bLevel); - device->NumStereoSources = 1; device->NumMonoSources = device->MaxNoOfSources - device->NumStereoSources; - device->Synth = SynthCreate(device); - if(!device->Synth) - { - DELETE_OBJ(device->Backend); - al_free(device); - alcSetError(NULL, ALC_OUT_OF_MEMORY); - return NULL; - } - // Find a playback device to open if((err=V(device->Backend,open)(deviceName)) != ALC_NO_ERROR) { - DELETE_OBJ(device->Synth); DELETE_OBJ(device->Backend); al_free(device); alcSetError(NULL, err); @@ -3284,9 +3498,12 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) } } - do { - device->next = DeviceList; - } while(CompExchangePtr((XchgPtr*)&DeviceList, device->next, device) != device->next); + { + ALCdevice *head = ATOMIC_LOAD(&DeviceList); + do { + device->next = head; + } while(!ATOMIC_COMPARE_EXCHANGE_WEAK(ALCdevice*, &DeviceList, &head, device)); + } TRACE("Created device %p, \"%s\"\n", device, al_string_get_cstr(device->DeviceName)); return device; @@ -3296,36 +3513,48 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) * * Closes the given device. */ -ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *Device) +ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) { - ALCdevice *volatile*list; + ALCdevice *list, *origdev, *nextdev; ALCcontext *ctx; LockLists(); - list = &DeviceList; - while(*list && *list != Device) - list = &(*list)->next; - - if(!*list || (*list)->Type == Capture) + list = ATOMIC_LOAD(&DeviceList); + do { + if(list == device) + break; + } while((list=list->next) != NULL); + if(!list || list->Type == Capture) { - alcSetError(*list, ALC_INVALID_DEVICE); + alcSetError(list, ALC_INVALID_DEVICE); UnlockLists(); return ALC_FALSE; } - *list = (*list)->next; + origdev = device; + nextdev = device->next; + if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALCdevice*, &DeviceList, &origdev, nextdev)) + { + do { + list = origdev; + origdev = device; + } while(!COMPARE_EXCHANGE(&list->next, &origdev, nextdev)); + } UnlockLists(); - while((ctx=Device->ContextList) != NULL) + ctx = ATOMIC_LOAD(&device->ContextList); + while(ctx != NULL) { + ALCcontext *next = ctx->next; WARN("Releasing context %p\n", ctx); - ReleaseContext(ctx, Device); + ReleaseContext(ctx, device); + ctx = next; } - if((Device->Flags&DEVICE_RUNNING)) - V0(Device->Backend,stop)(); - Device->Flags &= ~DEVICE_RUNNING; + if((device->Flags&DEVICE_RUNNING)) + V0(device->Backend,stop)(); + device->Flags &= ~DEVICE_RUNNING; - ALCdevice_DecRef(Device); + ALCdevice_DecRef(device); return ALC_TRUE; } @@ -3368,14 +3597,15 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, device->Connected = ALC_TRUE; device->Type = Capture; + VECTOR_INIT(device->Hrtf_List); + AL_STRING_INIT(device->Hrtf_Name); + AL_STRING_INIT(device->DeviceName); + device->DryBuffer = NULL; InitUIntMap(&device->BufferMap, ~0); InitUIntMap(&device->EffectMap, ~0); InitUIntMap(&device->FilterMap, ~0); - InitUIntMap(&device->SfontMap, ~0); - InitUIntMap(&device->PresetMap, ~0); - InitUIntMap(&device->FontsoundMap, ~0); if(!CaptureBackend.getFactory) device->Backend = create_backend_wrapper(device, &CaptureBackend.Funcs, @@ -3402,6 +3632,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, alcSetError(NULL, ALC_INVALID_ENUM); return NULL; } + device->IsHeadphones = AL_FALSE; device->UpdateSize = samples; device->NumUpdates = 1; @@ -3413,52 +3644,70 @@ ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *deviceName, return NULL; } - do { - device->next = DeviceList; - } while(CompExchangePtr((XchgPtr*)&DeviceList, device->next, device) != device->next); + { + ALCdevice *head = ATOMIC_LOAD(&DeviceList); + do { + device->next = head; + } while(!ATOMIC_COMPARE_EXCHANGE_WEAK(ALCdevice*, &DeviceList, &head, device)); + } TRACE("Created device %p, \"%s\"\n", device, al_string_get_cstr(device->DeviceName)); return device; } -ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *Device) +ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) { - ALCdevice *volatile*list; + ALCdevice *list, *next, *nextdev; LockLists(); - list = &DeviceList; - while(*list && *list != Device) - list = &(*list)->next; - - if(!*list || (*list)->Type != Capture) + list = ATOMIC_LOAD(&DeviceList); + do { + if(list == device) + break; + } while((list=list->next) != NULL); + if(!list || list->Type != Capture) { - alcSetError(*list, ALC_INVALID_DEVICE); + alcSetError(list, ALC_INVALID_DEVICE); UnlockLists(); return ALC_FALSE; } - *list = (*list)->next; + next = device; + nextdev = device->next; + if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALCdevice*, &DeviceList, &next, nextdev)) + { + do { + list = next; + next = device; + } while(!COMPARE_EXCHANGE(&list->next, &next, nextdev)); + } UnlockLists(); - ALCdevice_DecRef(Device); + ALCdevice_DecRef(device); return ALC_TRUE; } ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device) { - if(!(device=VerifyDevice(device)) || device->Type != Capture) + if(!VerifyDevice(&device) || device->Type != Capture) alcSetError(device, ALC_INVALID_DEVICE); else { - ALCdevice_Lock(device); - if(device->Connected) + V0(device->Backend,lock)(); + if(!device->Connected) + alcSetError(device, ALC_INVALID_DEVICE); + else if(!(device->Flags&DEVICE_RUNNING)) { - if(!(device->Flags&DEVICE_RUNNING)) - V0(device->Backend,start)(); - device->Flags |= DEVICE_RUNNING; + if(V0(device->Backend,start)()) + device->Flags |= DEVICE_RUNNING; + else + { + aluHandleDisconnect(device); + alcSetError(device, ALC_INVALID_DEVICE); + } } - ALCdevice_Unlock(device); + V0(device->Backend,unlock)(); } if(device) ALCdevice_DecRef(device); @@ -3466,15 +3715,15 @@ ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device) ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device) { - if(!(device=VerifyDevice(device)) || device->Type != Capture) + if(!VerifyDevice(&device) || device->Type != Capture) alcSetError(device, ALC_INVALID_DEVICE); else { - ALCdevice_Lock(device); + V0(device->Backend,lock)(); if((device->Flags&DEVICE_RUNNING)) V0(device->Backend,stop)(); device->Flags &= ~DEVICE_RUNNING; - ALCdevice_Unlock(device); + V0(device->Backend,unlock)(); } if(device) ALCdevice_DecRef(device); @@ -3482,16 +3731,16 @@ ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device) ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples) { - if(!(device=VerifyDevice(device)) || device->Type != Capture) + if(!VerifyDevice(&device) || device->Type != Capture) alcSetError(device, ALC_INVALID_DEVICE); else { ALCenum err = ALC_INVALID_VALUE; - ALCdevice_Lock(device); + V0(device->Backend,lock)(); if(samples >= 0 && V0(device->Backend,availableSamples)() >= (ALCuint)samples) err = V(device->Backend,captureSamples)(buffer, samples); - ALCdevice_Unlock(device); + V0(device->Backend,unlock)(); if(err != ALC_NO_ERROR) alcSetError(device, err); @@ -3533,14 +3782,17 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN InitRef(&device->ref, 1); device->Connected = ALC_TRUE; device->Type = Loopback; - device->LastError = ALC_NO_ERROR; + ATOMIC_INIT(&device->LastError, ALC_NO_ERROR); device->Flags = 0; + VECTOR_INIT(device->Hrtf_List); + AL_STRING_INIT(device->Hrtf_Name); device->Bs2b = NULL; - device->Bs2bLevel = 0; + device->Hrtf_Mode = DisabledHrtf; AL_STRING_INIT(device->DeviceName); + device->DryBuffer = NULL; - device->ContextList = NULL; + ATOMIC_INIT(&device->ContextList, NULL); device->ClockBase = 0; device->SamplesDone = 0; @@ -3552,9 +3804,6 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN InitUIntMap(&device->BufferMap, ~0); InitUIntMap(&device->EffectMap, ~0); InitUIntMap(&device->FilterMap, ~0); - InitUIntMap(&device->SfontMap, ~0); - InitUIntMap(&device->PresetMap, ~0); - InitUIntMap(&device->FontsoundMap, ~0); factory = ALCloopbackFactory_getFactory(); device->Backend = V(factory,createBackend)(device, ALCbackend_Loopback); @@ -3572,33 +3821,29 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN device->Frequency = DEFAULT_OUTPUT_RATE; device->FmtChans = DevFmtChannelsDefault; device->FmtType = DevFmtTypeDefault; + device->IsHeadphones = AL_FALSE; - ConfigValueUInt(NULL, "sources", &device->MaxNoOfSources); + ConfigValueUInt(NULL, NULL, "sources", &device->MaxNoOfSources); if(device->MaxNoOfSources == 0) device->MaxNoOfSources = 256; - ConfigValueUInt(NULL, "slots", &device->AuxiliaryEffectSlotMax); + ConfigValueUInt(NULL, NULL, "slots", &device->AuxiliaryEffectSlotMax); if(device->AuxiliaryEffectSlotMax == 0) device->AuxiliaryEffectSlotMax = 4; - ConfigValueUInt(NULL, "sends", &device->NumAuxSends); + ConfigValueUInt(NULL, NULL, "sends", &device->NumAuxSends); if(device->NumAuxSends > MAX_SENDS) device->NumAuxSends = MAX_SENDS; device->NumStereoSources = 1; device->NumMonoSources = device->MaxNoOfSources - device->NumStereoSources; - device->Synth = SynthCreate(device); - if(!device->Synth) - { - DELETE_OBJ(device->Backend); - al_free(device); - alcSetError(NULL, ALC_OUT_OF_MEMORY); - return NULL; - } - // Open the "backend" V(device->Backend,open)("Loopback"); - do { - device->next = DeviceList; - } while(CompExchangePtr((XchgPtr*)&DeviceList, device->next, device) != device->next); + + { + ALCdevice *head = ATOMIC_LOAD(&DeviceList); + do { + device->next = head; + } while(!ATOMIC_COMPARE_EXCHANGE_WEAK(ALCdevice*, &DeviceList, &head, device)); + } TRACE("Created device %p\n", device); return device; @@ -3612,7 +3857,7 @@ ALC_API ALCboolean ALC_APIENTRY alcIsRenderFormatSupportedSOFT(ALCdevice *device { ALCboolean ret = ALC_FALSE; - if(!(device=VerifyDevice(device)) || device->Type != Loopback) + if(!VerifyDevice(&device) || device->Type != Loopback) alcSetError(device, ALC_INVALID_DEVICE); else if(freq <= 0) alcSetError(device, ALC_INVALID_VALUE); @@ -3635,7 +3880,7 @@ ALC_API ALCboolean ALC_APIENTRY alcIsRenderFormatSupportedSOFT(ALCdevice *device */ FORCE_ALIGN ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, ALCvoid *buffer, ALCsizei samples) { - if(!(device=VerifyDevice(device)) || device->Type != Loopback) + if(!VerifyDevice(&device) || device->Type != Loopback) alcSetError(device, ALC_INVALID_DEVICE); else if(samples < 0 || (samples > 0 && buffer == NULL)) alcSetError(device, ALC_INVALID_VALUE); @@ -3655,7 +3900,7 @@ FORCE_ALIGN ALC_API void ALC_APIENTRY alcRenderSamplesSOFT(ALCdevice *device, AL */ ALC_API void ALC_APIENTRY alcDevicePauseSOFT(ALCdevice *device) { - if(!(device=VerifyDevice(device)) || device->Type != Playback) + if(!VerifyDevice(&device) || device->Type != Playback) alcSetError(device, ALC_INVALID_DEVICE); else { @@ -3675,7 +3920,7 @@ ALC_API void ALC_APIENTRY alcDevicePauseSOFT(ALCdevice *device) */ ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device) { - if(!(device=VerifyDevice(device)) || device->Type != Playback) + if(!VerifyDevice(&device) || device->Type != Playback) alcSetError(device, ALC_INVALID_DEVICE); else { @@ -3683,16 +3928,16 @@ ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device) if((device->Flags&DEVICE_PAUSED)) { device->Flags &= ~DEVICE_PAUSED; - if(device->ContextList != NULL) + if(ATOMIC_LOAD(&device->ContextList) != NULL) { if(V0(device->Backend,start)() != ALC_FALSE) device->Flags |= DEVICE_RUNNING; else { alcSetError(device, ALC_INVALID_DEVICE); - ALCdevice_Lock(device); + V0(device->Backend,lock)(); aluHandleDisconnect(device); - ALCdevice_Unlock(device); + V0(device->Backend,unlock)(); } } } @@ -3700,3 +3945,72 @@ ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device) } if(device) ALCdevice_DecRef(device); } + + +/************************************************ + * ALC HRTF functions + ************************************************/ + +/* alcGetStringiSOFT + * + * Gets a string parameter at the given index. + */ +ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum paramName, ALCsizei index) +{ + const ALCchar *str = NULL; + + if(!VerifyDevice(&device) || device->Type == Capture) + alcSetError(device, ALC_INVALID_DEVICE); + else switch(paramName) + { + case ALC_HRTF_SPECIFIER_SOFT: + if(index >= 0 && (size_t)index < VECTOR_SIZE(device->Hrtf_List)) + str = al_string_get_cstr(VECTOR_ELEM(device->Hrtf_List, index).name); + else + alcSetError(device, ALC_INVALID_VALUE); + break; + + default: + alcSetError(device, ALC_INVALID_ENUM); + break; + } + if(device) ALCdevice_DecRef(device); + + return str; +} + +/* alcResetDeviceSOFT + * + * Resets the given device output, using the specified attribute list. + */ +ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCint *attribs) +{ + ALCenum err; + + LockLists(); + if(!VerifyDevice(&device) || device->Type == Capture || !device->Connected) + { + UnlockLists(); + alcSetError(device, ALC_INVALID_DEVICE); + if(device) ALCdevice_DecRef(device); + return ALC_FALSE; + } + + if((err=UpdateDeviceParams(device, attribs)) != ALC_NO_ERROR) + { + UnlockLists(); + alcSetError(device, err); + if(err == ALC_INVALID_DEVICE) + { + V0(device->Backend,lock)(); + aluHandleDisconnect(device); + V0(device->Backend,unlock)(); + } + ALCdevice_DecRef(device); + return ALC_FALSE; + } + UnlockLists(); + ALCdevice_DecRef(device); + + return ALC_TRUE; +} |