From e9d77ef7660b77787629503aeb6913be45f49d34 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Tue, 1 Dec 2015 13:40:34 -0400 Subject: [PATCH] Added missing changes to the OpenAL-Soft update. --- CMakeLists.txt | 2 +- libs/openal-soft/Alc/ALc.c | 1292 +++++++++------ libs/openal-soft/Alc/ALu.c | 1404 ++++++++++------- libs/openal-soft/Alc/alcConfig.c | 121 +- libs/openal-soft/Alc/alcRing.c | 276 +++- libs/openal-soft/Alc/alstring.h | 5 +- libs/openal-soft/Alc/backends/alsa.c | 39 +- libs/openal-soft/Alc/backends/base.c | 25 +- libs/openal-soft/Alc/backends/base.h | 5 + libs/openal-soft/Alc/backends/coreaudio.c | 15 +- libs/openal-soft/Alc/backends/dsound.c | 85 +- libs/openal-soft/Alc/backends/loopback.c | 11 +- libs/openal-soft/Alc/backends/mmdevapi.c | 807 +++++++++- libs/openal-soft/Alc/backends/null.c | 13 +- libs/openal-soft/Alc/backends/opensl.c | 23 +- libs/openal-soft/Alc/backends/oss.c | 28 +- libs/openal-soft/Alc/backends/portaudio.c | 414 +++-- libs/openal-soft/Alc/backends/pulseaudio.c | 307 ++-- libs/openal-soft/Alc/backends/qsa.c | 460 ++---- libs/openal-soft/Alc/backends/sndio.c | 7 +- libs/openal-soft/Alc/backends/solaris.c | 212 ++- libs/openal-soft/Alc/backends/wave.c | 327 ++-- libs/openal-soft/Alc/backends/winmm.c | 711 +++++---- libs/openal-soft/Alc/bs2b.c | 23 +- libs/openal-soft/Alc/effects/autowah.c | 26 +- libs/openal-soft/Alc/effects/chorus.c | 26 +- libs/openal-soft/Alc/effects/compressor.c | 25 +- libs/openal-soft/Alc/effects/dedicated.c | 42 +- libs/openal-soft/Alc/effects/distortion.c | 38 +- libs/openal-soft/Alc/effects/echo.c | 34 +- libs/openal-soft/Alc/effects/equalizer.c | 53 +- libs/openal-soft/Alc/effects/flanger.c | 26 +- libs/openal-soft/Alc/effects/modulator.c | 33 +- libs/openal-soft/Alc/effects/null.c | 5 +- libs/openal-soft/Alc/effects/reverb.c | 826 +++++----- libs/openal-soft/Alc/helpers.c | 776 +++++++-- libs/openal-soft/Alc/hrtf.c | 434 ++--- libs/openal-soft/Alc/hrtf.h | 20 +- libs/openal-soft/Alc/mixer.c | 378 +++-- libs/openal-soft/Alc/mixer_c.c | 83 +- libs/openal-soft/Alc/mixer_defs.h | 29 +- libs/openal-soft/Alc/mixer_inc.c | 50 +- libs/openal-soft/Alc/mixer_neon.c | 43 +- libs/openal-soft/Alc/mixer_sse.c | 121 +- libs/openal-soft/Alc/mixer_sse2.c | 9 +- libs/openal-soft/Alc/mixer_sse41.c | 148 +- libs/openal-soft/Alc/panning.c | 861 +++++----- libs/openal-soft/Alc/vector.h | 34 +- libs/openal-soft/CMakeLists.txt | 284 ++-- libs/openal-soft/COPYING | 23 +- libs/openal-soft/ChangeLog | 58 + .../OpenAL32/Include/alAuxEffectSlot.h | 4 +- libs/openal-soft/OpenAL32/Include/alBuffer.h | 8 +- libs/openal-soft/OpenAL32/Include/alEffect.h | 1 - libs/openal-soft/OpenAL32/Include/alFilter.h | 45 +- .../openal-soft/OpenAL32/Include/alListener.h | 9 +- libs/openal-soft/OpenAL32/Include/alMain.h | 424 ++--- libs/openal-soft/OpenAL32/Include/alSource.h | 27 +- libs/openal-soft/OpenAL32/Include/alu.h | 226 ++- libs/openal-soft/OpenAL32/Include/bs2b.h | 11 +- libs/openal-soft/OpenAL32/alAuxEffectSlot.c | 4 +- libs/openal-soft/OpenAL32/alBuffer.c | 52 +- libs/openal-soft/OpenAL32/alEffect.c | 18 +- libs/openal-soft/OpenAL32/alError.c | 4 +- libs/openal-soft/OpenAL32/alExtension.c | 4 +- libs/openal-soft/OpenAL32/alFilter.c | 94 +- libs/openal-soft/OpenAL32/alListener.c | 36 +- libs/openal-soft/OpenAL32/alSource.c | 1120 +++++++------ libs/openal-soft/OpenAL32/alState.c | 177 +-- libs/openal-soft/OpenAL32/alThunk.c | 42 +- libs/openal-soft/README | 10 +- libs/openal-soft/XCompile.txt | 17 +- libs/openal-soft/alsoftrc.sample | 244 ++- .../cmake/CheckFileOffsetBits.cmake | 4 +- .../cmake/CheckSharedFunctionExists.cmake | 14 +- libs/openal-soft/cmake/FindDSound.cmake | 6 +- libs/openal-soft/cmake/FindSDL_sound.cmake | 393 +++-- libs/openal-soft/common/threads.c | 10 +- libs/openal-soft/config.h.in | 22 +- libs/openal-soft/env-vars.txt | 10 + libs/openal-soft/examples/alffplay.c | 74 +- libs/openal-soft/examples/alloopback.c | 6 +- libs/openal-soft/hrtf.txt | 2 +- libs/openal-soft/include/AL/alext.h | 42 +- libs/openal-soft/include/AL/efx-presets.h | 2 +- libs/openal-soft/include/align.h | 8 +- libs/openal-soft/include/atomic.h | 177 ++- libs/openal-soft/include/static_assert.h | 4 + libs/openal-soft/include/threads.h | 2 +- .../utils/alsoft-config/mainwindow.cpp | 307 +++- .../utils/alsoft-config/mainwindow.h | 4 - .../utils/alsoft-config/mainwindow.ui | 433 ++--- libs/openal-soft/utils/makehrtf.c | 94 +- libs/openal-soft/utils/openal-info.c | 30 + 94 files changed, 9219 insertions(+), 6099 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cd151bf3..9886a78d 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -138,7 +138,7 @@ set(MEGA_LIBTHEORA_VER "1.1") set(MEGA_MPG123_VER "1.15.3") set(MEGA_FREETYPE_VER "2.5.0.1") set(MEGA_SDL2_VER "2.0.3-dba168c67bea") -set(MEGA_OPENAL_VER "1.16.0") +set(MEGA_OPENAL_VER "1.17.0") set(MEGA_MODPLUG_VER "0.8.8.4") set(SKIP_INSTALL_ALL TRUE) diff --git a/libs/openal-soft/Alc/ALc.c b/libs/openal-soft/Alc/ALc.c index f7f7b63a..d6d23eba 100644 --- a/libs/openal-soft/Alc/ALc.c +++ b/libs/openal-soft/Alc/ALc.c @@ -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,40 +294,6 @@ static const ALCfunction alcFunctions[] = { DECL(alGetSource3i64SOFT), DECL(alGetSourcei64vSOFT), - DECL(alGenSoundfontsSOFT), - DECL(alDeleteSoundfontsSOFT), - DECL(alIsSoundfontSOFT), - 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 @@ -375,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), @@ -415,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), @@ -497,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), @@ -714,13 +706,13 @@ 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_SOFT_MSADPCM AL_SOFT_source_latency " - "AL_SOFT_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 ATOMIC(ALCenum) LastNullDeviceError = ATOMIC_INIT_STATIC(ALC_NO_ERROR); @@ -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_SOFT_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; @@ -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); + ConfigValueInt(NULL, 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; - - 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) @@ -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(!backendinfo->getFactory) + backendinfo->Probe(type); + else { - 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(!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)(); } @@ -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) @@ -1602,7 +1674,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) GotType = 1<<2, GotAll = GotFreq|GotChans|GotType }; - ALCuint freq, numMono, numStereo, numSends, flags; + ALCuint freq, numMono, numStereo, numSends; enum DevFmtChannels schans; enum DevFmtType stype; ALCuint attrIdx = 0; @@ -1620,7 +1692,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) schans = device->FmtChans; stype = device->FmtType; freq = device->Frequency; - flags = device->Flags; while(attrList[attrIdx]) { @@ -1664,12 +1735,17 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if(attrList[attrIdx] == ALC_HRTF_SOFT) { - if(attrList[attrIdx + 1] != ALC_FALSE) - 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 - flags &= ~DEVICE_HRTF_REQUEST; + hrtf_appreq = Hrtf_Default; } + if(attrList[attrIdx] == ALC_HRTF_ID_SOFT) + hrtf_id = attrList[attrIdx + 1]; + attrIdx += 2; } @@ -1679,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 = (flags & ~DEVICE_RUNNING); + device->Flags &= ~DEVICE_RUNNING; + + UpdateClockBase(device); - if(freq != device->Frequency) - UpdateClockBase(device); device->Frequency = freq; device->FmtChans = schans; device->FmtType = stype; @@ -1733,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; @@ -1765,50 +1846,89 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) if((device->Flags&DEVICE_RUNNING)) return ALC_NO_ERROR; + al_free(device->DryBuffer); + device->DryBuffer = NULL; + UpdateClockBase(device); + device->Hrtf_Status = ALC_HRTF_DISABLED_SOFT; + if(device->Type != Loopback) + { + 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; + } + } + } + else if(hrtf_appreq == Hrtf_Enable) + { + 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 + { + 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(device->Type != Loopback) - { - bool usehrtf = !!(device->Flags&DEVICE_HRTF_REQUEST); - if(GetConfigValueBool(NULL, "hrtf", usehrtf)) - device->Flags |= DEVICE_HRTF_REQUEST; - else - device->Flags &= ~DEVICE_HRTF_REQUEST; - } - if((device->Flags&DEVICE_HRTF_REQUEST)) - { - enum DevFmtChannels chans = device->FmtChans; - ALCuint freq = device->Frequency; - if(FindHrtfFormat(&chans, &freq)) - { - if(device->Type != Loopback) - { - device->Frequency = freq; - device->FmtChans = chans; - device->Flags |= DEVICE_CHANNELS_REQUEST | - DEVICE_FREQUENCY_REQUEST; - } - else if(device->Frequency != freq || device->FmtChans != chans) - { - ERR("Requested format not HRTF compatible: %s, %uhz\n", - DevFmtChannelsString(device->FmtChans), device->Frequency); - device->Flags &= ~DEVICE_HRTF_REQUEST; - } - } - } + (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; @@ -1832,46 +1952,11 @@ 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); + DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), + device->Frequency, device->UpdateSize, device->NumUpdates + ); - aluInitPanning(device); - - V(device->Synth,update)(device); - - device->Hrtf = NULL; - if((device->Flags&DEVICE_HRTF_REQUEST)) - { - device->Hrtf = GetHrtf(device->FmtChans, device->Frequency); - if(!device->Hrtf) - device->Flags &= ~DEVICE_HRTF_REQUEST; - } - TRACE("HRTF %s\n", device->Hrtf?"enabled":"disabled"); - - if(!device->Hrtf && device->Bs2bLevel > 0 && device->Bs2bLevel <= 6) - { - 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); - } - 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; - - if(!device->Hrtf && (device->UpdateSize&3)) + if((device->UpdateSize&3) != 0) { if((CPUCapFlags&CPU_CAP_SSE)) WARN("SSE performs best with multiple of 4 update sizes (%u)\n", device->UpdateSize); @@ -1879,8 +1964,152 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) WARN("NEON performs best with multiple of 4 update sizes (%u)\n", device->UpdateSize); } + device->Hrtf = NULL; + device->Hrtf_Mode = DisabledHrtf; + al_string_clear(&device->Hrtf_Name); + if(device->FmtChans != DevFmtStereo) + { + if(hrtf_appreq == Hrtf_Enable) + device->Hrtf_Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; + + free(device->Bs2b); + device->Bs2b = NULL; + } + else + { + 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"); + } + } + } + + aluInitPanning(device); + + /* 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) + { + ERR("Failed to allocate "SZFMT" bytes for mix buffer\n", size); + return ALC_INVALID_DEVICE; + } + SetMixerFPUMode(&oldMode); - ALCdevice_Lock(device); + V0(device->Backend,lock)(); context = ATOMIC_LOAD(&device->ContextList); while(context) { @@ -1895,7 +2124,7 @@ 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; } @@ -1922,20 +2151,24 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList) } 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); - ATOMIC_STORE(&source->NeedsUpdate, AL_FALSE); + if(source) + { + ATOMIC_STORE(&source->NeedsUpdate, AL_FALSE); + voice->Update(voice, source, context); + } } context = context->next; @@ -1946,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; } 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)) @@ -1979,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; @@ -1989,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); @@ -2014,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); } @@ -2063,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 = ATOMIC_LOAD(&DeviceList); - while(tmpDevice && tmpDevice != device) + 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; } @@ -2088,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 ATOMIC_INIT(&Context->LastError, AL_NO_ERROR); ATOMIC_INIT(&Context->UpdateSources, AL_FALSE); - Context->ActiveSourceCount = 0; InitUIntMap(&Context->SourceMap, Context->Device->MaxNoOfSources); InitUIntMap(&Context->EffectSlotMap, Context->Device->AuxiliaryEffectSlotMax); @@ -2137,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) @@ -2157,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); @@ -2174,7 +2376,7 @@ static ALCvoid FreeContext(ALCcontext *context) //Invalidate context memset(context, 0, sizeof(ALCcontext)); - free(context); + al_free(context); } /* ReleaseContext @@ -2239,7 +2441,7 @@ 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; @@ -2250,11 +2452,11 @@ static ALCcontext *VerifyContext(ALCcontext *context) ALCcontext *ctx = ATOMIC_LOAD(&dev->ContextList); while(ctx) { - if(ctx == context) + if(ctx == *context) { ALCcontext_IncRef(ctx); UnlockLists(); - return ctx; + return ALC_TRUE; } ctx = ctx->next; } @@ -2262,7 +2464,8 @@ static ALCcontext *VerifyContext(ALCcontext *context) } UnlockLists(); - return NULL; + *context = NULL; + return ALC_FALSE; } @@ -2303,7 +2506,7 @@ ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device) { ALCenum errorCode; - if(VerifyDevice(device)) + if(VerifyDevice(&device)) { errorCode = ATOMIC_EXCHANGE(ALCenum, &device->LastError, ALC_NO_ERROR); ALCdevice_DecRef(device); @@ -2317,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); + } } @@ -2371,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); @@ -2384,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); @@ -2405,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)); @@ -2420,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); @@ -2432,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 { @@ -2441,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; @@ -2498,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: @@ -2534,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; @@ -2577,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; @@ -2640,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; @@ -2653,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 @@ -2666,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) @@ -2682,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 { @@ -2725,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); @@ -2763,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); @@ -2803,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); } @@ -2829,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); } @@ -2855,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); @@ -2871,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); @@ -2887,11 +3138,11 @@ 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(!ATOMIC_LOAD(&device->ContextList)) { @@ -2902,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; } @@ -2987,7 +3238,7 @@ 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; @@ -3014,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; @@ -3036,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; @@ -3066,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)); @@ -3084,8 +3344,11 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) 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; ATOMIC_INIT(&device->ContextList, NULL); @@ -3099,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; @@ -3126,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]; @@ -3138,6 +3399,7 @@ ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *deviceName) { "surround51", DevFmtX51 }, { "surround61", DevFmtX61 }, { "surround71", DevFmtX71 }, + { "surround51rear", DevFmtX51Rear }, }; size_t i; @@ -3153,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]; @@ -3181,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) @@ -3239,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); @@ -3396,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, @@ -3430,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; @@ -3487,18 +3690,24 @@ ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) 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); @@ -3506,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); @@ -3522,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); @@ -3576,9 +3785,12 @@ ALC_API ALCdevice* ALC_APIENTRY alcLoopbackOpenDeviceSOFT(const ALCchar *deviceN 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; ATOMIC_INIT(&device->ContextList, NULL); @@ -3592,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); @@ -3612,28 +3821,20 @@ 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"); @@ -3656,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); @@ -3679,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); @@ -3699,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 { @@ -3719,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 { @@ -3734,9 +3935,9 @@ ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device) else { alcSetError(device, ALC_INVALID_DEVICE); - ALCdevice_Lock(device); + V0(device->Backend,lock)(); aluHandleDisconnect(device); - ALCdevice_Unlock(device); + V0(device->Backend,unlock)(); } } } @@ -3744,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; +} diff --git a/libs/openal-soft/Alc/ALu.c b/libs/openal-soft/Alc/ALu.c index a85e1aa0..91c2aa7f 100644 --- a/libs/openal-soft/Alc/ALu.c +++ b/libs/openal-soft/Alc/ALu.c @@ -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 */ @@ -36,15 +36,15 @@ #include "hrtf.h" #include "static_assert.h" -#include "midi/base.h" +#include "mixer_defs.h" +#include "backends/base.h" -static_assert((INT_MAX>>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE, - "MAX_PITCH and/or BUFFERSIZE are too large for FRACTIONBITS!"); struct ChanMap { enum Channel channel; ALfloat angle; + ALfloat elevation; }; /* Cone scalar */ @@ -78,7 +78,64 @@ extern inline ALuint64 maxu64(ALuint64 a, ALuint64 b); extern inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max); extern inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu); -extern inline ALfloat cubic(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALfloat mu); +extern inline ALfloat resample_fir4(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALuint frac); +extern inline ALfloat resample_fir8(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALfloat val4, ALfloat val5, ALfloat val6, ALfloat val7, ALuint frac); + +extern inline void aluVectorSet(aluVector *restrict vector, ALfloat x, ALfloat y, ALfloat z, ALfloat w); + +extern inline void aluMatrixfSetRow(aluMatrixf *matrix, ALuint row, + ALfloat m0, ALfloat m1, ALfloat m2, ALfloat m3); +extern inline void aluMatrixfSet(aluMatrixf *matrix, + ALfloat m00, ALfloat m01, ALfloat m02, ALfloat m03, + ALfloat m10, ALfloat m11, ALfloat m12, ALfloat m13, + ALfloat m20, ALfloat m21, ALfloat m22, ALfloat m23, + ALfloat m30, ALfloat m31, ALfloat m32, ALfloat m33); + +extern inline void aluMatrixdSetRow(aluMatrixd *matrix, ALuint row, + ALdouble m0, ALdouble m1, ALdouble m2, ALdouble m3); +extern inline void aluMatrixdSet(aluMatrixd *matrix, + ALdouble m00, ALdouble m01, ALdouble m02, ALdouble m03, + ALdouble m10, ALdouble m11, ALdouble m12, ALdouble m13, + ALdouble m20, ALdouble m21, ALdouble m22, ALdouble m23, + ALdouble m30, ALdouble m31, ALdouble m32, ALdouble m33); + + +/* NOTE: HRTF is set up a bit special in the device. By default, the device's + * DryBuffer, NumChannels, ChannelName, and Channel fields correspond to the + * output mixing format, and the DryBuffer is then converted and written to the + * backend's audio buffer. + * + * With HRTF, these fields correspond to a virtual format (typically B-Format), + * and the actual output is stored in DryBuffer[NumChannels] for the left + * channel and DryBuffer[NumChannels+1] for the right. As a final output step, + * the virtual channels will have HRTF applied and written to the actual + * output. Things like effects and B-Format decoding will want to write to the + * virtual channels so that they can be mixed with HRTF in full 3D. + * + * Sources that get mixed using HRTF directly (or that want to skip HRTF + * completely) will need to offset the output buffer so that they skip the + * virtual output and write to the actual output channels. This is the reason + * you'll see + * + * voice->Direct.OutBuffer += voice->Direct.OutChannels; + * voice->Direct.OutChannels = 2; + * + * at various points in the code where HRTF is explicitly used or bypassed. + */ + +static inline HrtfMixerFunc SelectHrtfMixer(void) +{ +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return MixHrtf_SSE; +#endif +#ifdef HAVE_NEON + if((CPUCapFlags&CPU_CAP_NEON)) + return MixHrtf_Neon; +#endif + + return MixHrtf_C; +} static inline void aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVector2, ALfloat *outVector) @@ -88,135 +145,333 @@ static inline void aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVe outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0]; } -static inline ALfloat aluDotproduct(const ALfloat *inVector1, const ALfloat *inVector2) +static inline ALfloat aluDotproduct(const aluVector *vec1, const aluVector *vec2) { - return inVector1[0]*inVector2[0] + inVector1[1]*inVector2[1] + - inVector1[2]*inVector2[2]; + return vec1->v[0]*vec2->v[0] + vec1->v[1]*vec2->v[1] + vec1->v[2]*vec2->v[2]; } -static inline void aluNormalize(ALfloat *inVector) +static inline ALfloat aluNormalize(ALfloat *vec) { - ALfloat lengthsqr = aluDotproduct(inVector, inVector); - if(lengthsqr > 0.0f) + ALfloat length = sqrtf(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); + if(length > 0.0f) { - ALfloat inv_length = 1.0f/sqrtf(lengthsqr); - inVector[0] *= inv_length; - inVector[1] *= inv_length; - inVector[2] *= inv_length; + ALfloat inv_length = 1.0f/length; + vec[0] *= inv_length; + vec[1] *= inv_length; + vec[2] *= inv_length; } + return length; } -static inline ALvoid aluMatrixVector(ALfloat *vector, ALfloat w, ALfloat (*restrict matrix)[4]) -{ - ALfloat temp[4] = { - vector[0], vector[1], vector[2], w - }; - vector[0] = temp[0]*matrix[0][0] + temp[1]*matrix[1][0] + temp[2]*matrix[2][0] + temp[3]*matrix[3][0]; - vector[1] = temp[0]*matrix[0][1] + temp[1]*matrix[1][1] + temp[2]*matrix[2][1] + temp[3]*matrix[3][1]; - vector[2] = temp[0]*matrix[0][2] + temp[1]*matrix[1][2] + temp[2]*matrix[2][2] + temp[3]*matrix[3][2]; +static inline void aluCrossproductd(const ALdouble *inVector1, const ALdouble *inVector2, ALdouble *outVector) +{ + outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1]; + outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2]; + outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0]; +} + +static inline ALdouble aluNormalized(ALdouble *vec) +{ + ALdouble length = sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]); + if(length > 0.0) + { + ALdouble inv_length = 1.0/length; + vec[0] *= inv_length; + vec[1] *= inv_length; + vec[2] *= inv_length; + } + return length; +} + +static inline ALvoid aluMatrixdFloat3(ALfloat *vec, ALfloat w, const aluMatrixd *mtx) +{ + ALdouble v[4] = { vec[0], vec[1], vec[2], w }; + + vec[0] = (ALfloat)(v[0]*mtx->m[0][0] + v[1]*mtx->m[1][0] + v[2]*mtx->m[2][0] + v[3]*mtx->m[3][0]); + vec[1] = (ALfloat)(v[0]*mtx->m[0][1] + v[1]*mtx->m[1][1] + v[2]*mtx->m[2][1] + v[3]*mtx->m[3][1]); + vec[2] = (ALfloat)(v[0]*mtx->m[0][2] + v[1]*mtx->m[1][2] + v[2]*mtx->m[2][2] + v[3]*mtx->m[3][2]); +} + +static inline ALvoid aluMatrixdDouble3(ALdouble *vec, ALdouble w, const aluMatrixd *mtx) +{ + ALdouble v[4] = { vec[0], vec[1], vec[2], w }; + + vec[0] = v[0]*mtx->m[0][0] + v[1]*mtx->m[1][0] + v[2]*mtx->m[2][0] + v[3]*mtx->m[3][0]; + vec[1] = v[0]*mtx->m[0][1] + v[1]*mtx->m[1][1] + v[2]*mtx->m[2][1] + v[3]*mtx->m[3][1]; + vec[2] = v[0]*mtx->m[0][2] + v[1]*mtx->m[1][2] + v[2]*mtx->m[2][2] + v[3]*mtx->m[3][2]; +} + +static inline aluVector aluMatrixdVector(const aluMatrixd *mtx, const aluVector *vec) +{ + aluVector v; + v.v[0] = (ALfloat)(vec->v[0]*mtx->m[0][0] + vec->v[1]*mtx->m[1][0] + vec->v[2]*mtx->m[2][0] + vec->v[3]*mtx->m[3][0]); + v.v[1] = (ALfloat)(vec->v[0]*mtx->m[0][1] + vec->v[1]*mtx->m[1][1] + vec->v[2]*mtx->m[2][1] + vec->v[3]*mtx->m[3][1]); + v.v[2] = (ALfloat)(vec->v[0]*mtx->m[0][2] + vec->v[1]*mtx->m[1][2] + vec->v[2]*mtx->m[2][2] + vec->v[3]*mtx->m[3][2]); + v.v[3] = (ALfloat)(vec->v[0]*mtx->m[0][3] + vec->v[1]*mtx->m[1][3] + vec->v[2]*mtx->m[2][3] + vec->v[3]*mtx->m[3][3]); + return v; +} + + +/* Prepares the interpolator for a given rate (determined by increment). A + * result of AL_FALSE indicates that the filter output will completely cut + * the input signal. + * + * With a bit of work, and a trade of memory for CPU cost, this could be + * modified for use with an interpolated increment for buttery-smooth pitch + * changes. + */ +static ALboolean BsincPrepare(const ALuint increment, BsincState *state) +{ + static const ALfloat scaleBase = 1.510578918e-01f, scaleRange = 1.177936623e+00f; + static const ALuint m[BSINC_SCALE_COUNT] = { 24, 24, 24, 24, 24, 24, 24, 20, 20, 20, 16, 16, 16, 12, 12, 12 }; + static const ALuint to[4][BSINC_SCALE_COUNT] = + { + { 0, 24, 408, 792, 1176, 1560, 1944, 2328, 2648, 2968, 3288, 3544, 3800, 4056, 4248, 4440 }, + { 4632, 5016, 5400, 5784, 6168, 6552, 6936, 7320, 7640, 7960, 8280, 8536, 8792, 9048, 9240, 0 }, + { 0, 9432, 9816, 10200, 10584, 10968, 11352, 11736, 12056, 12376, 12696, 12952, 13208, 13464, 13656, 13848 }, + { 14040, 14424, 14808, 15192, 15576, 15960, 16344, 16728, 17048, 17368, 17688, 17944, 18200, 18456, 18648, 0 } + }; + static const ALuint tm[2][BSINC_SCALE_COUNT] = + { + { 0, 24, 24, 24, 24, 24, 24, 20, 20, 20, 16, 16, 16, 12, 12, 12 }, + { 24, 24, 24, 24, 24, 24, 24, 20, 20, 20, 16, 16, 16, 12, 12, 0 } + }; + ALfloat sf; + ALuint si, pi; + ALboolean uncut = AL_TRUE; + + if(increment > FRACTIONONE) + { + sf = (ALfloat)FRACTIONONE / increment; + if(sf < scaleBase) + { + /* Signal has been completely cut. The return result can be used + * to skip the filter (and output zeros) as an optimization. + */ + sf = 0.0f; + si = 0; + uncut = AL_FALSE; + } + else + { + sf = (BSINC_SCALE_COUNT - 1) * (sf - scaleBase) * scaleRange; + si = fastf2u(sf); + /* The interpolation factor is fit to this diagonally-symmetric + * curve to reduce the transition ripple caused by interpolating + * different scales of the sinc function. + */ + sf = 1.0f - cosf(asinf(sf - si)); + } + } + else + { + sf = 0.0f; + si = BSINC_SCALE_COUNT - 1; + } + + state->sf = sf; + state->m = m[si]; + state->l = -(ALint)((m[si] / 2) - 1); + /* The CPU cost of this table re-mapping could be traded for the memory + * cost of a complete table map (1024 elements large). + */ + for(pi = 0;pi < BSINC_PHASE_COUNT;pi++) + { + state->coeffs[pi].filter = &bsincTab[to[0][si] + tm[0][si]*pi]; + state->coeffs[pi].scDelta = &bsincTab[to[1][si] + tm[1][si]*pi]; + state->coeffs[pi].phDelta = &bsincTab[to[2][si] + tm[0][si]*pi]; + state->coeffs[pi].spDelta = &bsincTab[to[3][si] + tm[1][si]*pi]; + } + return uncut; +} + + +/* Calculates the fade time from the changes in gain and listener to source + * angle between updates. The result is a the time, in seconds, for the + * transition to complete. + */ +static ALfloat CalcFadeTime(ALfloat oldGain, ALfloat newGain, const aluVector *olddir, const aluVector *newdir) +{ + ALfloat gainChange, angleChange, change; + + /* Calculate the normalized dB gain change. */ + newGain = maxf(newGain, 0.0001f); + oldGain = maxf(oldGain, 0.0001f); + gainChange = fabsf(log10f(newGain / oldGain) / log10f(0.0001f)); + + /* Calculate the angle change only when there is enough gain to notice it. */ + angleChange = 0.0f; + if(gainChange > 0.0001f || newGain > 0.0001f) + { + /* No angle change when the directions are equal or degenerate (when + * both have zero length). + */ + if(newdir->v[0] != olddir->v[0] || newdir->v[1] != olddir->v[1] || newdir->v[2] != olddir->v[2]) + { + ALfloat dotp = aluDotproduct(olddir, newdir); + angleChange = acosf(clampf(dotp, -1.0f, 1.0f)) / F_PI; + } + } + + /* Use the largest of the two changes, and apply a significance shaping + * function to it. The result is then scaled to cover a 15ms transition + * range. + */ + change = maxf(angleChange * 25.0f, gainChange) * 2.0f; + return minf(change, 1.0f) * 0.015f; +} + + +static void UpdateDryStepping(DirectParams *params, ALuint num_chans, ALuint steps) +{ + ALfloat delta; + ALuint i, j; + + if(steps < 2) + { + for(i = 0;i < num_chans;i++) + { + MixGains *gains = params->Gains[i]; + for(j = 0;j < params->OutChannels;j++) + { + gains[j].Current = gains[j].Target; + gains[j].Step = 0.0f; + } + } + params->Counter = 0; + return; + } + + delta = 1.0f / (ALfloat)steps; + for(i = 0;i < num_chans;i++) + { + MixGains *gains = params->Gains[i]; + for(j = 0;j < params->OutChannels;j++) + { + ALfloat diff = gains[j].Target - gains[j].Current; + if(fabsf(diff) >= GAIN_SILENCE_THRESHOLD) + gains[j].Step = diff * delta; + else + { + gains[j].Current = gains[j].Target; + gains[j].Step = 0.0f; + } + } + } + params->Counter = steps; +} + +static void UpdateWetStepping(SendParams *params, ALuint num_chans, ALuint steps) +{ + ALfloat delta; + ALuint i; + + if(steps < 2) + { + for(i = 0;i < num_chans;i++) + { + params->Gains[i].Current = params->Gains[i].Target; + params->Gains[i].Step = 0.0f; + } + params->Counter = 0; + return; + } + + delta = 1.0f / (ALfloat)steps; + for(i = 0;i < num_chans;i++) + { + ALfloat diff = params->Gains[i].Target - params->Gains[i].Current; + if(fabsf(diff) >= GAIN_SILENCE_THRESHOLD) + params->Gains[i].Step = diff * delta; + else + { + params->Gains[i].Current = params->Gains[i].Target; + params->Gains[i].Step = 0.0f; + } + } + params->Counter = steps; } static ALvoid CalcListenerParams(ALlistener *Listener) { - ALfloat N[3], V[3], U[3], P[3]; + ALdouble N[3], V[3], U[3], P[3]; /* AT then UP */ N[0] = Listener->Forward[0]; N[1] = Listener->Forward[1]; N[2] = Listener->Forward[2]; - aluNormalize(N); + aluNormalized(N); V[0] = Listener->Up[0]; V[1] = Listener->Up[1]; V[2] = Listener->Up[2]; - aluNormalize(V); + aluNormalized(V); /* Build and normalize right-vector */ - aluCrossproduct(N, V, U); - aluNormalize(U); + aluCrossproductd(N, V, U); + aluNormalized(U); - Listener->Params.Matrix[0][0] = U[0]; - Listener->Params.Matrix[0][1] = V[0]; - Listener->Params.Matrix[0][2] = -N[0]; - Listener->Params.Matrix[0][3] = 0.0f; - Listener->Params.Matrix[1][0] = U[1]; - Listener->Params.Matrix[1][1] = V[1]; - Listener->Params.Matrix[1][2] = -N[1]; - Listener->Params.Matrix[1][3] = 0.0f; - Listener->Params.Matrix[2][0] = U[2]; - Listener->Params.Matrix[2][1] = V[2]; - Listener->Params.Matrix[2][2] = -N[2]; - Listener->Params.Matrix[2][3] = 0.0f; - Listener->Params.Matrix[3][0] = 0.0f; - Listener->Params.Matrix[3][1] = 0.0f; - Listener->Params.Matrix[3][2] = 0.0f; - Listener->Params.Matrix[3][3] = 1.0f; + aluMatrixdSet(&Listener->Params.Matrix, + U[0], V[0], -N[0], 0.0, + U[1], V[1], -N[1], 0.0, + U[2], V[2], -N[2], 0.0, + 0.0, 0.0, 0.0, 1.0 + ); - P[0] = Listener->Position[0]; - P[1] = Listener->Position[1]; - P[2] = Listener->Position[2]; - aluMatrixVector(P, 1.0f, Listener->Params.Matrix); - Listener->Params.Matrix[3][0] = -P[0]; - Listener->Params.Matrix[3][1] = -P[1]; - Listener->Params.Matrix[3][2] = -P[2]; + P[0] = Listener->Position.v[0]; + P[1] = Listener->Position.v[1]; + P[2] = Listener->Position.v[2]; + aluMatrixdDouble3(P, 1.0, &Listener->Params.Matrix); + aluMatrixdSetRow(&Listener->Params.Matrix, 3, -P[0], -P[1], -P[2], 1.0f); - Listener->Params.Velocity[0] = Listener->Velocity[0]; - Listener->Params.Velocity[1] = Listener->Velocity[1]; - Listener->Params.Velocity[2] = Listener->Velocity[2]; - aluMatrixVector(Listener->Params.Velocity, 0.0f, Listener->Params.Matrix); + Listener->Params.Velocity = aluMatrixdVector(&Listener->Params.Matrix, &Listener->Velocity); } -ALvoid CalcNonAttnSourceParams(ALactivesource *src, const ALCcontext *ALContext) +ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCcontext *ALContext) { - static const struct ChanMap MonoMap[1] = { { FrontCenter, 0.0f } }; - static const struct ChanMap StereoMap[2] = { - { FrontLeft, DEG2RAD(-30.0f) }, - { FrontRight, DEG2RAD( 30.0f) } - }; - static const struct ChanMap StereoWideMap[2] = { - { FrontLeft, DEG2RAD(-90.0f) }, - { FrontRight, DEG2RAD( 90.0f) } - }; - static const struct ChanMap RearMap[2] = { - { BackLeft, DEG2RAD(-150.0f) }, - { BackRight, DEG2RAD( 150.0f) } - }; - static const struct ChanMap QuadMap[4] = { - { FrontLeft, DEG2RAD( -45.0f) }, - { FrontRight, DEG2RAD( 45.0f) }, - { BackLeft, DEG2RAD(-135.0f) }, - { BackRight, DEG2RAD( 135.0f) } - }; - static const struct ChanMap X51Map[6] = { - { FrontLeft, DEG2RAD( -30.0f) }, - { FrontRight, DEG2RAD( 30.0f) }, - { FrontCenter, DEG2RAD( 0.0f) }, - { LFE, 0.0f }, - { BackLeft, DEG2RAD(-110.0f) }, - { BackRight, DEG2RAD( 110.0f) } - }; - static const struct ChanMap X61Map[7] = { - { FrontLeft, DEG2RAD(-30.0f) }, - { FrontRight, DEG2RAD( 30.0f) }, - { FrontCenter, DEG2RAD( 0.0f) }, - { LFE, 0.0f }, - { BackCenter, DEG2RAD(180.0f) }, - { SideLeft, DEG2RAD(-90.0f) }, - { SideRight, DEG2RAD( 90.0f) } - }; - static const struct ChanMap X71Map[8] = { - { FrontLeft, DEG2RAD( -30.0f) }, - { FrontRight, DEG2RAD( 30.0f) }, - { FrontCenter, DEG2RAD( 0.0f) }, - { LFE, 0.0f }, - { BackLeft, DEG2RAD(-150.0f) }, - { BackRight, DEG2RAD( 150.0f) }, - { SideLeft, DEG2RAD( -90.0f) }, - { SideRight, DEG2RAD( 90.0f) } + static const struct ChanMap MonoMap[1] = { + { FrontCenter, 0.0f, 0.0f } + }, StereoMap[2] = { + { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) }, + { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) } + }, StereoWideMap[2] = { + { FrontLeft, DEG2RAD(-90.0f), DEG2RAD(0.0f) }, + { FrontRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) } + }, RearMap[2] = { + { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) }, + { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) } + }, QuadMap[4] = { + { FrontLeft, DEG2RAD( -45.0f), DEG2RAD(0.0f) }, + { FrontRight, DEG2RAD( 45.0f), DEG2RAD(0.0f) }, + { BackLeft, DEG2RAD(-135.0f), DEG2RAD(0.0f) }, + { BackRight, DEG2RAD( 135.0f), DEG2RAD(0.0f) } + }, X51Map[6] = { + { FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) }, + { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }, + { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) }, + { LFE, 0.0f, 0.0f }, + { SideLeft, DEG2RAD(-110.0f), DEG2RAD(0.0f) }, + { SideRight, DEG2RAD( 110.0f), DEG2RAD(0.0f) } + }, X61Map[7] = { + { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) }, + { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }, + { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) }, + { LFE, 0.0f, 0.0f }, + { BackCenter, DEG2RAD(180.0f), DEG2RAD(0.0f) }, + { SideLeft, DEG2RAD(-90.0f), DEG2RAD(0.0f) }, + { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) } + }, X71Map[8] = { + { FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) }, + { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }, + { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) }, + { LFE, 0.0f, 0.0f }, + { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) }, + { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) }, + { SideLeft, DEG2RAD( -90.0f), DEG2RAD(0.0f) }, + { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) } }; ALCdevice *Device = ALContext->Device; - const ALsource *ALSource = src->Source; ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume; ALbufferlistitem *BufferListItem; enum FmtChannels Channels; @@ -224,13 +479,14 @@ ALvoid CalcNonAttnSourceParams(ALactivesource *src, const ALCcontext *ALContext) ALfloat WetGain[MAX_SENDS]; ALfloat WetGainHF[MAX_SENDS]; ALfloat WetGainLF[MAX_SENDS]; - ALint NumSends, Frequency; + ALuint NumSends, Frequency; + ALboolean Relative; const struct ChanMap *chans = NULL; - ALint num_channels = 0; + ALuint num_channels = 0; ALboolean DirectChannels; - ALfloat hwidth = 0.0f; + ALboolean isbformat = AL_FALSE; ALfloat Pitch; - ALint i, j, c; + ALuint i, j, c; /* Get device properties */ NumSends = Device->NumAuxSends; @@ -244,18 +500,20 @@ ALvoid CalcNonAttnSourceParams(ALactivesource *src, const ALCcontext *ALContext) MinVolume = ALSource->MinGain; MaxVolume = ALSource->MaxGain; Pitch = ALSource->Pitch; + Relative = ALSource->HeadRelative; DirectChannels = ALSource->DirectChannels; - src->Direct.OutBuffer = Device->DryBuffer; + voice->Direct.OutBuffer = Device->DryBuffer; + voice->Direct.OutChannels = Device->NumChannels; for(i = 0;i < NumSends;i++) { ALeffectslot *Slot = ALSource->Send[i].Slot; if(!Slot && i == 0) Slot = Device->DefaultSlot; if(!Slot || Slot->EffectType == AL_EFFECT_NULL) - src->Send[i].OutBuffer = NULL; + voice->Send[i].OutBuffer = NULL; else - src->Send[i].OutBuffer = Slot->WetBuffer; + voice->Send[i].OutBuffer = Slot->WetBuffer; } /* Calculate the stepping value */ @@ -268,13 +526,10 @@ ALvoid CalcNonAttnSourceParams(ALactivesource *src, const ALCcontext *ALContext) { Pitch = Pitch * ALBuffer->Frequency / Frequency; if(Pitch > (ALfloat)MAX_PITCH) - src->Step = MAX_PITCH<Step = MAX_PITCH<Step = fastf2i(Pitch*FRACTIONONE); - if(src->Step == 0) - src->Step = 1; - } + voice->Step = maxi(fastf2i(Pitch*FRACTIONONE + 0.5f), 1); + BsincPrepare(voice->Step, &voice->SincState); Channels = ALBuffer->FmtChannels; break; @@ -303,21 +558,13 @@ ALvoid CalcNonAttnSourceParams(ALactivesource *src, const ALCcontext *ALContext) break; case FmtStereo: - if(!(Device->Flags&DEVICE_WIDE_STEREO)) - { - /* HACK: Place the stereo channels at +/-90 degrees when using non- - * HRTF stereo output. This helps reduce the "monoization" caused - * by them panning towards the center. */ - if(Device->FmtChans == DevFmtStereo && !Device->Hrtf) - chans = StereoWideMap; - else - chans = StereoMap; - } - else - { + /* HACK: Place the stereo channels at +/-90 degrees when using non- + * HRTF stereo output. This helps reduce the "monoization" caused + * by them panning towards the center. */ + if(Device->FmtChans == DevFmtStereo && !Device->Hrtf) chans = StereoWideMap; - hwidth = DEG2RAD(60.0f); - } + else + chans = StereoMap; num_channels = 2; break; @@ -345,229 +592,242 @@ ALvoid CalcNonAttnSourceParams(ALactivesource *src, const ALCcontext *ALContext) chans = X71Map; num_channels = 8; break; + + case FmtBFormat2D: + num_channels = 3; + isbformat = AL_TRUE; + DirectChannels = AL_FALSE; + break; + + case FmtBFormat3D: + num_channels = 4; + isbformat = AL_TRUE; + DirectChannels = AL_FALSE; + break; } - if(DirectChannels != AL_FALSE) + if(isbformat) { - for(c = 0;c < num_channels;c++) + ALfloat N[3], V[3], U[3]; + aluMatrixf matrix; + ALfloat scale; + + /* AT then UP */ + N[0] = ALSource->Orientation[0][0]; + N[1] = ALSource->Orientation[0][1]; + N[2] = ALSource->Orientation[0][2]; + aluNormalize(N); + V[0] = ALSource->Orientation[1][0]; + V[1] = ALSource->Orientation[1][1]; + V[2] = ALSource->Orientation[1][2]; + aluNormalize(V); + if(!Relative) { - MixGains *gains = src->Direct.Mix.Gains[c]; - for(j = 0;j < MaxChannels;j++) - gains[j].Target = 0.0f; + const aluMatrixd *lmatrix = &ALContext->Listener->Params.Matrix; + aluMatrixdFloat3(N, 0.0f, lmatrix); + aluMatrixdFloat3(V, 0.0f, lmatrix); } + /* Build and normalize right-vector */ + aluCrossproduct(N, V, U); + aluNormalize(U); + + /* Build a rotate + conversion matrix (B-Format -> N3D), and include + * scaling for first-order content. */ + scale = Device->AmbiScale * 1.732050808f; + aluMatrixfSet(&matrix, + 1.414213562f, 0.0f, 0.0f, 0.0f, + 0.0f, -N[0]*scale, N[1]*scale, -N[2]*scale, + 0.0f, U[0]*scale, -U[1]*scale, U[2]*scale, + 0.0f, -V[0]*scale, V[1]*scale, -V[2]*scale + ); for(c = 0;c < num_channels;c++) { - MixGains *gains = src->Direct.Mix.Gains[c]; - for(i = 0;i < (ALint)Device->NumChan;i++) - { - enum Channel chan = Device->Speaker2Chan[i]; - if(chan == chans[c].channel) - { - gains[chan].Target = DryGain; - break; - } - } - } + MixGains *gains = voice->Direct.Gains[c]; + ALfloat Target[MAX_OUTPUT_CHANNELS]; - if(!src->Direct.Moving) - { - for(i = 0;i < num_channels;i++) - { - MixGains *gains = src->Direct.Mix.Gains[i]; - for(j = 0;j < MaxChannels;j++) - { - gains[j].Current = gains[j].Target; - gains[j].Step = 1.0f; - } - } - src->Direct.Counter = 0; - src->Direct.Moving = AL_TRUE; - } - else - { - for(i = 0;i < num_channels;i++) - { - MixGains *gains = src->Direct.Mix.Gains[i]; - for(j = 0;j < MaxChannels;j++) - { - ALfloat cur = maxf(gains[j].Current, FLT_EPSILON); - ALfloat trg = maxf(gains[j].Target, FLT_EPSILON); - if(fabs(trg - cur) >= GAIN_SILENCE_THRESHOLD) - gains[j].Step = powf(trg/cur, 1.0f/64.0f); - else - gains[j].Step = 1.0f; - gains[j].Current = cur; - } - } - src->Direct.Counter = 64; + ComputeBFormatGains(Device, matrix.m[c], DryGain, Target); + for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) + gains[i].Target = Target[i]; } + UpdateDryStepping(&voice->Direct, num_channels, (voice->Direct.Moving ? 64 : 0)); + voice->Direct.Moving = AL_TRUE; - src->IsHrtf = AL_FALSE; - } - else if(Device->Hrtf) - { - for(c = 0;c < num_channels;c++) - { - if(chans[c].channel == LFE) - { - /* Skip LFE */ - src->Direct.Mix.Hrtf.Params[c].Delay[0] = 0; - src->Direct.Mix.Hrtf.Params[c].Delay[1] = 0; - for(i = 0;i < HRIR_LENGTH;i++) - { - src->Direct.Mix.Hrtf.Params[c].Coeffs[i][0] = 0.0f; - src->Direct.Mix.Hrtf.Params[c].Coeffs[i][1] = 0.0f; - } - } - else - { - /* Get the static HRIR coefficients and delays for this - * channel. */ - GetLerpedHrtfCoeffs(Device->Hrtf, - 0.0f, chans[c].angle, 1.0f, DryGain, - src->Direct.Mix.Hrtf.Params[c].Coeffs, - src->Direct.Mix.Hrtf.Params[c].Delay); - } - } - src->Direct.Counter = 0; - src->Direct.Moving = AL_TRUE; - src->Direct.Mix.Hrtf.IrSize = GetHrtfIrSize(Device->Hrtf); + voice->IsHrtf = AL_FALSE; - src->IsHrtf = AL_TRUE; + for(i = 0;i < NumSends;i++) + { + /* Only the first channel of B-Format buffers (W) goes to auxiliary + * sends. It also needs to be scaled by sqrt(2) to account for the + * signal being scaled by sqrt(1/2). + */ + voice->Send[i].Gains[0].Target = WetGain[i] * 1.414213562f; + for(c = 1;c < num_channels;c++) + voice->Send[i].Gains[c].Target = 0.0f; + UpdateWetStepping(&voice->Send[i], num_channels, (voice->Send[i].Moving ? 64 : 0)); + voice->Send[i].Moving = AL_TRUE; + } } else { - for(i = 0;i < num_channels;i++) + if(DirectChannels) { - MixGains *gains = src->Direct.Mix.Gains[i]; - for(j = 0;j < MaxChannels;j++) - gains[j].Target = 0.0f; - } - - DryGain *= lerp(1.0f, 1.0f/sqrtf((float)Device->NumChan), hwidth/F_PI); - for(c = 0;c < num_channels;c++) - { - MixGains *gains = src->Direct.Mix.Gains[c]; - ALfloat Target[MaxChannels]; - - /* Special-case LFE */ - if(chans[c].channel == LFE) + if(Device->Hrtf) { - gains[chans[c].channel].Target = DryGain; - continue; - } - ComputeAngleGains(Device, chans[c].angle, hwidth, DryGain, Target); - for(i = 0;i < MaxChannels;i++) - gains[i].Target = Target[i]; - } - - if(!src->Direct.Moving) - { - for(i = 0;i < num_channels;i++) - { - MixGains *gains = src->Direct.Mix.Gains[i]; - for(j = 0;j < MaxChannels;j++) + /* DirectChannels with HRTF enabled. Skip the virtual channels + * and write FrontLeft and FrontRight inputs to the first and + * second outputs. + */ + voice->Direct.OutBuffer += voice->Direct.OutChannels; + voice->Direct.OutChannels = 2; + for(c = 0;c < num_channels;c++) { - gains[j].Current = gains[j].Target; - gains[j].Step = 1.0f; + MixGains *gains = voice->Direct.Gains[c]; + + for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) + gains[j].Target = 0.0f; + + if(chans[c].channel == FrontLeft) + gains[0].Target = DryGain; + else if(chans[c].channel == FrontRight) + gains[1].Target = DryGain; } } - src->Direct.Counter = 0; - src->Direct.Moving = AL_TRUE; + else for(c = 0;c < num_channels;c++) + { + MixGains *gains = voice->Direct.Gains[c]; + int idx; + + for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) + gains[j].Target = 0.0f; + if((idx=GetChannelIdxByName(Device, chans[c].channel)) != -1) + gains[idx].Target = DryGain; + } + UpdateDryStepping(&voice->Direct, num_channels, (voice->Direct.Moving ? 64 : 0)); + voice->Direct.Moving = AL_TRUE; + + voice->IsHrtf = AL_FALSE; + } + else if(Device->Hrtf_Mode == FullHrtf) + { + /* Full HRTF rendering. Skip the virtual channels and render each + * input channel to the real outputs. + */ + voice->Direct.OutBuffer += voice->Direct.OutChannels; + voice->Direct.OutChannels = 2; + for(c = 0;c < num_channels;c++) + { + if(chans[c].channel == LFE) + { + /* Skip LFE */ + voice->Direct.Hrtf[c].Params.Delay[0] = 0; + voice->Direct.Hrtf[c].Params.Delay[1] = 0; + for(i = 0;i < HRIR_LENGTH;i++) + { + voice->Direct.Hrtf[c].Params.Coeffs[i][0] = 0.0f; + voice->Direct.Hrtf[c].Params.Coeffs[i][1] = 0.0f; + } + } + else + { + /* Get the static HRIR coefficients and delays for this + * channel. */ + GetLerpedHrtfCoeffs(Device->Hrtf, + chans[c].elevation, chans[c].angle, 1.0f, DryGain, + voice->Direct.Hrtf[c].Params.Coeffs, + voice->Direct.Hrtf[c].Params.Delay + ); + } + } + voice->Direct.Counter = 0; + voice->Direct.Moving = AL_TRUE; + + voice->IsHrtf = AL_TRUE; } else { - for(i = 0;i < num_channels;i++) + /* Basic or no HRTF rendering. Use normal panning to the output. */ + for(c = 0;c < num_channels;c++) { - MixGains *gains = src->Direct.Mix.Gains[i]; - for(j = 0;j < MaxChannels;j++) - { - ALfloat trg = maxf(gains[j].Target, FLT_EPSILON); - ALfloat cur = maxf(gains[j].Current, FLT_EPSILON); - if(fabs(trg - cur) >= GAIN_SILENCE_THRESHOLD) - gains[j].Step = powf(trg/cur, 1.0f/64.0f); - else - gains[j].Step = 1.0f; - gains[j].Current = cur; - } - } - src->Direct.Counter = 64; - } + MixGains *gains = voice->Direct.Gains[c]; + ALfloat Target[MAX_OUTPUT_CHANNELS]; - src->IsHrtf = AL_FALSE; - } - for(i = 0;i < NumSends;i++) - { - src->Send[i].Gain.Target = WetGain[i]; - if(!src->Send[i].Moving) - { - src->Send[i].Gain.Current = src->Send[i].Gain.Target; - src->Send[i].Gain.Step = 1.0f; - src->Send[i].Counter = 0; - src->Send[i].Moving = AL_TRUE; + /* Special-case LFE */ + if(chans[c].channel == LFE) + { + int idx; + for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) + gains[i].Target = 0.0f; + if((idx=GetChannelIdxByName(Device, chans[c].channel)) != -1) + gains[idx].Target = DryGain; + continue; + } + + ComputeAngleGains(Device, chans[c].angle, chans[c].elevation, DryGain, Target); + for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) + gains[i].Target = Target[i]; + } + UpdateDryStepping(&voice->Direct, num_channels, (voice->Direct.Moving ? 64 : 0)); + voice->Direct.Moving = AL_TRUE; + + voice->IsHrtf = AL_FALSE; } - else + for(i = 0;i < NumSends;i++) { - ALfloat cur = maxf(src->Send[i].Gain.Current, FLT_EPSILON); - ALfloat trg = maxf(src->Send[i].Gain.Target, FLT_EPSILON); - if(fabs(trg - cur) >= GAIN_SILENCE_THRESHOLD) - src->Send[i].Gain.Step = powf(trg/cur, 1.0f/64.0f); - else - src->Send[i].Gain.Step = 1.0f; - src->Send[i].Gain.Current = cur; - src->Send[i].Counter = 64; + for(c = 0;c < num_channels;c++) + voice->Send[i].Gains[c].Target = WetGain[i]; + UpdateWetStepping(&voice->Send[i], num_channels, (voice->Send[i].Moving ? 64 : 0)); + voice->Send[i].Moving = AL_TRUE; } } { - ALfloat gainhf = maxf(0.01f, DryGainHF); - ALfloat gainlf = maxf(0.01f, DryGainLF); ALfloat hfscale = ALSource->Direct.HFReference / Frequency; ALfloat lfscale = ALSource->Direct.LFReference / Frequency; + DryGainHF = maxf(DryGainHF, 0.0001f); + DryGainLF = maxf(DryGainLF, 0.0001f); for(c = 0;c < num_channels;c++) { - src->Direct.Filters[c].ActiveType = AF_None; - if(gainhf != 1.0f) src->Direct.Filters[c].ActiveType |= AF_LowPass; - if(gainlf != 1.0f) src->Direct.Filters[c].ActiveType |= AF_HighPass; + voice->Direct.Filters[c].ActiveType = AF_None; + if(DryGainHF != 1.0f) voice->Direct.Filters[c].ActiveType |= AF_LowPass; + if(DryGainLF != 1.0f) voice->Direct.Filters[c].ActiveType |= AF_HighPass; ALfilterState_setParams( - &src->Direct.Filters[c].LowPass, ALfilterType_HighShelf, gainhf, - hfscale, 0.0f + &voice->Direct.Filters[c].LowPass, ALfilterType_HighShelf, + DryGainHF, hfscale, calc_rcpQ_from_slope(DryGainHF, 0.75f) ); ALfilterState_setParams( - &src->Direct.Filters[c].HighPass, ALfilterType_LowShelf, gainlf, - lfscale, 0.0f + &voice->Direct.Filters[c].HighPass, ALfilterType_LowShelf, + DryGainLF, lfscale, calc_rcpQ_from_slope(DryGainLF, 0.75f) ); } } for(i = 0;i < NumSends;i++) { - ALfloat gainhf = maxf(0.01f, WetGainHF[i]); - ALfloat gainlf = maxf(0.01f, WetGainLF[i]); ALfloat hfscale = ALSource->Send[i].HFReference / Frequency; ALfloat lfscale = ALSource->Send[i].LFReference / Frequency; + WetGainHF[i] = maxf(WetGainHF[i], 0.0001f); + WetGainLF[i] = maxf(WetGainLF[i], 0.0001f); for(c = 0;c < num_channels;c++) { - src->Send[i].Filters[c].ActiveType = AF_None; - if(gainhf != 1.0f) src->Send[i].Filters[c].ActiveType |= AF_LowPass; - if(gainlf != 1.0f) src->Send[i].Filters[c].ActiveType |= AF_HighPass; + voice->Send[i].Filters[c].ActiveType = AF_None; + if(WetGainHF[i] != 1.0f) voice->Send[i].Filters[c].ActiveType |= AF_LowPass; + if(WetGainLF[i] != 1.0f) voice->Send[i].Filters[c].ActiveType |= AF_HighPass; ALfilterState_setParams( - &src->Send[i].Filters[c].LowPass, ALfilterType_HighShelf, gainhf, - hfscale, 0.0f + &voice->Send[i].Filters[c].LowPass, ALfilterType_HighShelf, + WetGainHF[i], hfscale, calc_rcpQ_from_slope(WetGainHF[i], 0.75f) ); ALfilterState_setParams( - &src->Send[i].Filters[c].HighPass, ALfilterType_LowShelf, gainlf, - lfscale, 0.0f + &voice->Send[i].Filters[c].HighPass, ALfilterType_LowShelf, + WetGainLF[i], lfscale, calc_rcpQ_from_slope(WetGainLF[i], 0.75f) ); } } } -ALvoid CalcSourceParams(ALactivesource *src, const ALCcontext *ALContext) +ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCcontext *ALContext) { ALCdevice *Device = ALContext->Device; - const ALsource *ALSource = src->Source; - ALfloat Velocity[3],Direction[3],Position[3],SourceToListener[3]; + aluVector Position, Velocity, Direction, SourceToListener; ALfloat InnerAngle,OuterAngle,Angle,Distance,ClampedDist; ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff; ALfloat ConeVolume,ConeHF,SourceVolume,ListenerGain; @@ -618,15 +878,9 @@ ALvoid CalcSourceParams(ALactivesource *src, const ALCcontext *ALContext) MinVolume = ALSource->MinGain; MaxVolume = ALSource->MaxGain; Pitch = ALSource->Pitch; - Position[0] = ALSource->Position[0]; - Position[1] = ALSource->Position[1]; - Position[2] = ALSource->Position[2]; - Direction[0] = ALSource->Orientation[0]; - Direction[1] = ALSource->Orientation[1]; - Direction[2] = ALSource->Orientation[2]; - Velocity[0] = ALSource->Velocity[0]; - Velocity[1] = ALSource->Velocity[1]; - Velocity[2] = ALSource->Velocity[2]; + Position = ALSource->Position; + Direction = ALSource->Direction; + Velocity = ALSource->Velocity; MinDist = ALSource->RefDistance; MaxDist = ALSource->MaxDistance; Rolloff = ALSource->RollOffFactor; @@ -638,7 +892,8 @@ ALvoid CalcSourceParams(ALactivesource *src, const ALCcontext *ALContext) WetGainHFAuto = ALSource->WetGainHFAuto; RoomRolloffBase = ALSource->RoomRolloffFactor; - src->Direct.OutBuffer = Device->DryBuffer; + voice->Direct.OutBuffer = Device->DryBuffer; + voice->Direct.OutChannels = Device->NumChannels; for(i = 0;i < NumSends;i++) { ALeffectslot *Slot = ALSource->Send[i].Slot; @@ -678,37 +933,37 @@ ALvoid CalcSourceParams(ALactivesource *src, const ALCcontext *ALContext) } if(!Slot || Slot->EffectType == AL_EFFECT_NULL) - src->Send[i].OutBuffer = NULL; + voice->Send[i].OutBuffer = NULL; else - src->Send[i].OutBuffer = Slot->WetBuffer; + voice->Send[i].OutBuffer = Slot->WetBuffer; } /* Transform source to listener space (convert to head relative) */ if(ALSource->HeadRelative == AL_FALSE) { - ALfloat (*restrict Matrix)[4] = ALContext->Listener->Params.Matrix; + const aluMatrixd *Matrix = &ALContext->Listener->Params.Matrix; /* Transform source vectors */ - aluMatrixVector(Position, 1.0f, Matrix); - aluMatrixVector(Direction, 0.0f, Matrix); - aluMatrixVector(Velocity, 0.0f, Matrix); + Position = aluMatrixdVector(Matrix, &Position); + Velocity = aluMatrixdVector(Matrix, &Velocity); + Direction = aluMatrixdVector(Matrix, &Direction); } else { - const ALfloat *ListenerVel = ALContext->Listener->Params.Velocity; + const aluVector *lvelocity = &ALContext->Listener->Params.Velocity; /* Offset the source velocity to be relative of the listener velocity */ - Velocity[0] += ListenerVel[0]; - Velocity[1] += ListenerVel[1]; - Velocity[2] += ListenerVel[2]; + Velocity.v[0] += lvelocity->v[0]; + Velocity.v[1] += lvelocity->v[1]; + Velocity.v[2] += lvelocity->v[2]; } - SourceToListener[0] = -Position[0]; - SourceToListener[1] = -Position[1]; - SourceToListener[2] = -Position[2]; - aluNormalize(SourceToListener); - aluNormalize(Direction); + aluNormalize(Direction.v); + SourceToListener.v[0] = -Position.v[0]; + SourceToListener.v[1] = -Position.v[1]; + SourceToListener.v[2] = -Position.v[2]; + SourceToListener.v[3] = 0.0f; + Distance = aluNormalize(SourceToListener.v); /* Calculate distance attenuation */ - Distance = sqrtf(aluDotproduct(Position, Position)); ClampedDist = Distance; Attenuation = 1.0f; @@ -725,12 +980,12 @@ ALvoid CalcSourceParams(ALactivesource *src, const ALCcontext *ALContext) case InverseDistance: if(MinDist > 0.0f) { - if((MinDist + (Rolloff * (ClampedDist - MinDist))) > 0.0f) - Attenuation = MinDist / (MinDist + (Rolloff * (ClampedDist - MinDist))); + ALfloat dist = lerp(MinDist, ClampedDist, Rolloff); + if(dist > 0.0f) Attenuation = MinDist / dist; for(i = 0;i < NumSends;i++) { - if((MinDist + (RoomRolloff[i] * (ClampedDist - MinDist))) > 0.0f) - RoomAttenuation[i] = MinDist / (MinDist + (RoomRolloff[i] * (ClampedDist - MinDist))); + dist = lerp(MinDist, ClampedDist, RoomRolloff[i]); + if(dist > 0.0f) RoomAttenuation[i] = MinDist / dist; } } break; @@ -780,7 +1035,7 @@ ALvoid CalcSourceParams(ALactivesource *src, const ALCcontext *ALContext) /* Distance-based air absorption */ if(AirAbsorptionFactor > 0.0f && ClampedDist > MinDist) { - ALfloat meters = maxf(ClampedDist-MinDist, 0.0f) * MetersPerUnit; + ALfloat meters = (ClampedDist-MinDist) * MetersPerUnit; DryGainHF *= powf(AIRABSORBGAINHF, AirAbsorptionFactor*meters); for(i = 0;i < NumSends;i++) WetGainHF[i] *= powf(RoomAirAbsorption[i], AirAbsorptionFactor*meters); @@ -805,7 +1060,7 @@ ALvoid CalcSourceParams(ALactivesource *src, const ALCcontext *ALContext) } /* Calculate directional soundcones */ - Angle = RAD2DEG(acosf(aluDotproduct(Direction,SourceToListener)) * ConeScale) * 2.0f; + Angle = RAD2DEG(acosf(aluDotproduct(&Direction, &SourceToListener)) * ConeScale) * 2.0f; if(Angle > InnerAngle && Angle <= OuterAngle) { ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle); @@ -856,7 +1111,7 @@ ALvoid CalcSourceParams(ALactivesource *src, const ALCcontext *ALContext) /* Calculate velocity-based doppler effect */ if(DopplerFactor > 0.0f) { - const ALfloat *ListenerVel = ALContext->Listener->Params.Velocity; + const aluVector *lvelocity = &ALContext->Listener->Params.Velocity; ALfloat VSS, VLS; if(SpeedOfSound < 1.0f) @@ -865,8 +1120,8 @@ ALvoid CalcSourceParams(ALactivesource *src, const ALCcontext *ALContext) SpeedOfSound = 1.0f; } - VSS = aluDotproduct(Velocity, SourceToListener) * DopplerFactor; - VLS = aluDotproduct(ListenerVel, SourceToListener) * DopplerFactor; + VSS = aluDotproduct(&Velocity, &SourceToListener) * DopplerFactor; + VLS = aluDotproduct(lvelocity, &SourceToListener) * DopplerFactor; Pitch *= clampf(SpeedOfSound-VLS, 1.0f, SpeedOfSound*2.0f - 1.0f) / clampf(SpeedOfSound-VSS, 1.0f, SpeedOfSound*2.0f - 1.0f); @@ -882,249 +1137,247 @@ ALvoid CalcSourceParams(ALactivesource *src, const ALCcontext *ALContext) * frequency, and output frequency. */ Pitch = Pitch * ALBuffer->Frequency / Frequency; if(Pitch > (ALfloat)MAX_PITCH) - src->Step = MAX_PITCH<Step = MAX_PITCH<Step = fastf2i(Pitch*FRACTIONONE); - if(src->Step == 0) - src->Step = 1; - } + voice->Step = maxi(fastf2i(Pitch*FRACTIONONE + 0.5f), 1); + BsincPrepare(voice->Step, &voice->SincState); break; } BufferListItem = BufferListItem->next; } - if(Device->Hrtf) + if(Device->Hrtf_Mode == FullHrtf) { - /* Use a binaural HRTF algorithm for stereo headphone playback */ - ALfloat delta, ev = 0.0f, az = 0.0f; + /* Full HRTF rendering. Skip the virtual channels and render to the + * real outputs. + */ + aluVector dir = {{ 0.0f, 0.0f, -1.0f, 0.0f }}; + ALfloat ev = 0.0f, az = 0.0f; ALfloat radius = ALSource->Radius; ALfloat dirfact = 1.0f; + voice->Direct.OutBuffer += voice->Direct.OutChannels; + voice->Direct.OutChannels = 2; + if(Distance > FLT_EPSILON) { - ALfloat invlen = 1.0f/Distance; - Position[0] *= invlen; - Position[1] *= invlen; - Position[2] *= invlen; + dir.v[0] = -SourceToListener.v[0]; + dir.v[1] = -SourceToListener.v[1]; + dir.v[2] = -SourceToListener.v[2] * ZScale; /* Calculate elevation and azimuth only when the source is not at * the listener. This prevents +0 and -0 Z from producing * inconsistent panning. Also, clamp Y in case FP precision errors * cause it to land outside of -1..+1. */ - ev = asinf(clampf(Position[1], -1.0f, 1.0f)); - az = atan2f(Position[0], -Position[2]*ZScale); + ev = asinf(clampf(dir.v[1], -1.0f, 1.0f)); + az = atan2f(dir.v[0], -dir.v[2]); + } + if(radius > 0.0f) + { + if(radius >= Distance) + dirfact *= Distance / radius * 0.5f; + else + dirfact *= 1.0f - (asinf(radius / Distance) / F_PI); } - if(radius > Distance) - dirfact *= Distance / radius; /* Check to see if the HRIR is already moving. */ - if(src->Direct.Moving) + if(voice->Direct.Moving) { - /* Calculate the normalized HRTF transition factor (delta). */ - delta = CalcHrtfDelta(src->Direct.Mix.Hrtf.Gain, DryGain, - src->Direct.Mix.Hrtf.Dir, Position); + ALfloat delta; + delta = CalcFadeTime(voice->Direct.LastGain, DryGain, + &voice->Direct.LastDir, &dir); /* If the delta is large enough, get the moving HRIR target - * coefficients, target delays, steppping values, and counter. */ - if(delta > 0.001f) + * coefficients, target delays, steppping values, and counter. + */ + if(delta > 0.000015f) { ALuint counter = GetMovingHrtfCoeffs(Device->Hrtf, - ev, az, dirfact, DryGain, delta, src->Direct.Counter, - src->Direct.Mix.Hrtf.Params[0].Coeffs, src->Direct.Mix.Hrtf.Params[0].Delay, - src->Direct.Mix.Hrtf.Params[0].CoeffStep, src->Direct.Mix.Hrtf.Params[0].DelayStep + ev, az, dirfact, DryGain, delta, voice->Direct.Counter, + voice->Direct.Hrtf[0].Params.Coeffs, voice->Direct.Hrtf[0].Params.Delay, + voice->Direct.Hrtf[0].Params.CoeffStep, voice->Direct.Hrtf[0].Params.DelayStep ); - src->Direct.Counter = counter; - src->Direct.Mix.Hrtf.Gain = DryGain; - src->Direct.Mix.Hrtf.Dir[0] = Position[0]; - src->Direct.Mix.Hrtf.Dir[1] = Position[1]; - src->Direct.Mix.Hrtf.Dir[2] = Position[2]; + voice->Direct.Counter = counter; + voice->Direct.LastGain = DryGain; + voice->Direct.LastDir = dir; } } else { /* Get the initial (static) HRIR coefficients and delays. */ GetLerpedHrtfCoeffs(Device->Hrtf, ev, az, dirfact, DryGain, - src->Direct.Mix.Hrtf.Params[0].Coeffs, - src->Direct.Mix.Hrtf.Params[0].Delay); - src->Direct.Counter = 0; - src->Direct.Moving = AL_TRUE; - src->Direct.Mix.Hrtf.Gain = DryGain; - src->Direct.Mix.Hrtf.Dir[0] = Position[0]; - src->Direct.Mix.Hrtf.Dir[1] = Position[1]; - src->Direct.Mix.Hrtf.Dir[2] = Position[2]; + voice->Direct.Hrtf[0].Params.Coeffs, + voice->Direct.Hrtf[0].Params.Delay); + voice->Direct.Counter = 0; + voice->Direct.Moving = AL_TRUE; + voice->Direct.LastGain = DryGain; + voice->Direct.LastDir = dir; } - src->Direct.Mix.Hrtf.IrSize = GetHrtfIrSize(Device->Hrtf); - src->IsHrtf = AL_TRUE; + voice->IsHrtf = AL_TRUE; } else { - MixGains *gains = src->Direct.Mix.Gains[0]; - ALfloat DirGain = 0.0f; - ALfloat AmbientGain; + /* Basic or no HRTF rendering. Use normal panning to the output. */ + MixGains *gains = voice->Direct.Gains[0]; + ALfloat dir[3] = { 0.0f, 0.0f, -1.0f }; + ALfloat radius = ALSource->Radius; + ALfloat Target[MAX_OUTPUT_CHANNELS]; - for(j = 0;j < MaxChannels;j++) - gains[j].Target = 0.0f; - - /* Normalize the length, and compute panned gains. */ + /* Get the localized direction, and compute panned gains. */ if(Distance > FLT_EPSILON) { - ALfloat radius = ALSource->Radius; - ALfloat Target[MaxChannels]; - ALfloat invlen = 1.0f/maxf(Distance, radius); - Position[0] *= invlen; - Position[1] *= invlen; - Position[2] *= invlen; - - DirGain = sqrtf(Position[0]*Position[0] + Position[2]*Position[2]); - ComputeAngleGains(Device, atan2f(Position[0], -Position[2]*ZScale), 0.0f, - DryGain*DirGain, Target); - for(j = 0;j < MaxChannels;j++) - gains[j].Target = Target[j]; + dir[0] = -SourceToListener.v[0]; + dir[1] = -SourceToListener.v[1]; + dir[2] = -SourceToListener.v[2] * ZScale; } - - /* Adjustment for vertical offsets. Not the greatest, but simple - * enough. */ - AmbientGain = DryGain * sqrtf(1.0f/Device->NumChan) * (1.0f-DirGain); - for(i = 0;i < (ALint)Device->NumChan;i++) + if(radius > 0.0f) { - enum Channel chan = Device->Speaker2Chan[i]; - gains[chan].Target = maxf(gains[chan].Target, AmbientGain); + ALfloat dirfact; + if(radius >= Distance) + dirfact = Distance / radius * 0.5f; + else + dirfact = 1.0f - (asinf(radius / Distance) / F_PI); + dir[0] *= dirfact; + dir[1] *= dirfact; + dir[2] *= dirfact; } + ComputeDirectionalGains(Device, dir, DryGain, Target); - if(!src->Direct.Moving) - { - for(j = 0;j < MaxChannels;j++) - { - gains[j].Current = gains[j].Target; - gains[j].Step = 1.0f; - } - src->Direct.Counter = 0; - src->Direct.Moving = AL_TRUE; - } - else - { - for(j = 0;j < MaxChannels;j++) - { - ALfloat cur = maxf(gains[j].Current, FLT_EPSILON); - ALfloat trg = maxf(gains[j].Target, FLT_EPSILON); - if(fabs(trg - cur) >= GAIN_SILENCE_THRESHOLD) - gains[j].Step = powf(trg/cur, 1.0f/64.0f); - else - gains[j].Step = 1.0f; - gains[j].Current = cur; - } - src->Direct.Counter = 64; - } + for(j = 0;j < MAX_OUTPUT_CHANNELS;j++) + gains[j].Target = Target[j]; + UpdateDryStepping(&voice->Direct, 1, (voice->Direct.Moving ? 64 : 0)); + voice->Direct.Moving = AL_TRUE; - src->IsHrtf = AL_FALSE; + voice->IsHrtf = AL_FALSE; } for(i = 0;i < NumSends;i++) { - src->Send[i].Gain.Target = WetGain[i]; - if(!src->Send[i].Moving) - { - src->Send[i].Gain.Current = src->Send[i].Gain.Target; - src->Send[i].Gain.Step = 1.0f; - src->Send[i].Counter = 0; - src->Send[i].Moving = AL_TRUE; - } - else - { - ALfloat cur = maxf(src->Send[i].Gain.Current, FLT_EPSILON); - ALfloat trg = maxf(src->Send[i].Gain.Target, FLT_EPSILON); - if(fabs(trg - cur) >= GAIN_SILENCE_THRESHOLD) - src->Send[i].Gain.Step = powf(trg/cur, 1.0f/64.0f); - else - src->Send[i].Gain.Step = 1.0f; - src->Send[i].Gain.Current = cur; - src->Send[i].Counter = 64; - } + voice->Send[i].Gains[0].Target = WetGain[i]; + UpdateWetStepping(&voice->Send[i], 1, (voice->Send[i].Moving ? 64 : 0)); + voice->Send[i].Moving = AL_TRUE; } { - ALfloat gainhf = maxf(0.01f, DryGainHF); - ALfloat gainlf = maxf(0.01f, DryGainLF); ALfloat hfscale = ALSource->Direct.HFReference / Frequency; ALfloat lfscale = ALSource->Direct.LFReference / Frequency; - src->Direct.Filters[0].ActiveType = AF_None; - if(gainhf != 1.0f) src->Direct.Filters[0].ActiveType |= AF_LowPass; - if(gainlf != 1.0f) src->Direct.Filters[0].ActiveType |= AF_HighPass; + DryGainHF = maxf(DryGainHF, 0.0001f); + DryGainLF = maxf(DryGainLF, 0.0001f); + voice->Direct.Filters[0].ActiveType = AF_None; + if(DryGainHF != 1.0f) voice->Direct.Filters[0].ActiveType |= AF_LowPass; + if(DryGainLF != 1.0f) voice->Direct.Filters[0].ActiveType |= AF_HighPass; ALfilterState_setParams( - &src->Direct.Filters[0].LowPass, ALfilterType_HighShelf, gainhf, - hfscale, 0.0f + &voice->Direct.Filters[0].LowPass, ALfilterType_HighShelf, + DryGainHF, hfscale, calc_rcpQ_from_slope(DryGainHF, 0.75f) ); ALfilterState_setParams( - &src->Direct.Filters[0].HighPass, ALfilterType_LowShelf, gainlf, - lfscale, 0.0f + &voice->Direct.Filters[0].HighPass, ALfilterType_LowShelf, + DryGainLF, lfscale, calc_rcpQ_from_slope(DryGainLF, 0.75f) ); } for(i = 0;i < NumSends;i++) { - ALfloat gainhf = maxf(0.01f, WetGainHF[i]); - ALfloat gainlf = maxf(0.01f, WetGainLF[i]); ALfloat hfscale = ALSource->Send[i].HFReference / Frequency; ALfloat lfscale = ALSource->Send[i].LFReference / Frequency; - src->Send[i].Filters[0].ActiveType = AF_None; - if(gainhf != 1.0f) src->Send[i].Filters[0].ActiveType |= AF_LowPass; - if(gainlf != 1.0f) src->Send[i].Filters[0].ActiveType |= AF_HighPass; + WetGainHF[i] = maxf(WetGainHF[i], 0.0001f); + WetGainLF[i] = maxf(WetGainLF[i], 0.0001f); + voice->Send[i].Filters[0].ActiveType = AF_None; + if(WetGainHF[i] != 1.0f) voice->Send[i].Filters[0].ActiveType |= AF_LowPass; + if(WetGainLF[i] != 1.0f) voice->Send[i].Filters[0].ActiveType |= AF_HighPass; ALfilterState_setParams( - &src->Send[i].Filters[0].LowPass, ALfilterType_HighShelf, gainhf, - hfscale, 0.0f + &voice->Send[i].Filters[0].LowPass, ALfilterType_HighShelf, + WetGainHF[i], hfscale, calc_rcpQ_from_slope(WetGainHF[i], 0.75f) ); ALfilterState_setParams( - &src->Send[i].Filters[0].HighPass, ALfilterType_LowShelf, gainlf, - lfscale, 0.0f + &voice->Send[i].Filters[0].HighPass, ALfilterType_LowShelf, + WetGainLF[i], lfscale, calc_rcpQ_from_slope(WetGainLF[i], 0.75f) ); } } -static inline ALint aluF2I25(ALfloat val) +void UpdateContextSources(ALCcontext *ctx) { - /* Clamp the value between -1 and +1. This handles that with only a single branch. */ - if(fabsf(val) > 1.0f) - val = (ALfloat)((0.0f < val) - (val < 0.0f)); - /* Convert to a signed integer, between -16777215 and +16777215. */ - return fastf2i(val*16777215.0f); + ALvoice *voice, *voice_end; + ALsource *source; + + if(ATOMIC_EXCHANGE(ALenum, &ctx->UpdateSources, AL_FALSE)) + { + CalcListenerParams(ctx->Listener); + + voice = ctx->Voices; + voice_end = voice + ctx->VoiceCount; + for(;voice != voice_end;++voice) + { + if(!(source=voice->Source)) continue; + if(source->state != AL_PLAYING && source->state != AL_PAUSED) + voice->Source = NULL; + else + { + ATOMIC_STORE(&source->NeedsUpdate, AL_FALSE); + voice->Update(voice, source, ctx); + } + } + } + else + { + voice = ctx->Voices; + voice_end = voice + ctx->VoiceCount; + for(;voice != voice_end;++voice) + { + if(!(source=voice->Source)) continue; + if(source->state != AL_PLAYING && source->state != AL_PAUSED) + voice->Source = NULL; + else if(ATOMIC_EXCHANGE(ALenum, &source->NeedsUpdate, AL_FALSE)) + voice->Update(voice, source, ctx); + } + } +} + + +/* Specialized function to clamp to [-1, +1] with only one branch. This also + * converts NaN to 0. */ +static inline ALfloat aluClampf(ALfloat val) +{ + if(fabsf(val) <= 1.0f) return val; + return (ALfloat)((0.0f < val) - (val < 0.0f)); } static inline ALfloat aluF2F(ALfloat val) { return val; } + static inline ALint aluF2I(ALfloat val) -{ return aluF2I25(val)<<7; } +{ + /* Floats only have a 24-bit mantissa, so [-16777215, +16777215] is the max + * integer range normalized floats can be safely converted to. + */ + return fastf2i(aluClampf(val)*16777215.0f)<<7; +} static inline ALuint aluF2UI(ALfloat val) { return aluF2I(val)+2147483648u; } + static inline ALshort aluF2S(ALfloat val) -{ return aluF2I25(val)>>9; } +{ return fastf2i(aluClampf(val)*32767.0f); } static inline ALushort aluF2US(ALfloat val) { return aluF2S(val)+32768; } + static inline ALbyte aluF2B(ALfloat val) -{ return aluF2I25(val)>>17; } +{ return fastf2i(aluClampf(val)*127.0f); } static inline ALubyte aluF2UB(ALfloat val) { return aluF2B(val)+128; } #define DECL_TEMPLATE(T, func) \ -static void Write_##T(ALCdevice *device, ALvoid **buffer, ALuint SamplesToDo) \ +static void Write_##T(ALfloatBUFFERSIZE *InBuffer, ALvoid *OutBuffer, \ + ALuint SamplesToDo, ALuint numchans) \ { \ - ALfloat (*restrict DryBuffer)[BUFFERSIZE] = device->DryBuffer; \ - const ALuint numchans = ChannelsFromDevFmt(device->FmtChans); \ - const ALuint *offsets = device->ChannelOffsets; \ ALuint i, j; \ - \ - for(j = 0;j < MaxChannels;j++) \ + for(j = 0;j < numchans;j++) \ { \ - T *restrict out; \ - \ - if(offsets[j] == INVALID_OFFSET) \ - continue; \ - \ - out = (T*)(*buffer) + offsets[j]; \ + const ALfloat *in = InBuffer[j]; \ + T *restrict out = (T*)OutBuffer + j; \ for(i = 0;i < SamplesToDo;i++) \ - out[i*numchans] = func(DryBuffer[j][i]); \ + out[i*numchans] = func(in[i]); \ } \ - *buffer = (char*)(*buffer) + SamplesToDo*numchans*sizeof(T); \ } DECL_TEMPLATE(ALfloat, aluF2F) @@ -1141,8 +1394,9 @@ DECL_TEMPLATE(ALbyte, aluF2B) ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) { ALuint SamplesToDo; - ALeffectslot **slot, **slot_end; - ALactivesource **src, **src_end; + ALvoice *voice, *voice_end; + ALeffectslot *slot; + ALsource *source; ALCcontext *ctx; FPUCtl oldMode; ALuint i, c; @@ -1151,84 +1405,81 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) while(size > 0) { + ALfloat (*OutBuffer)[BUFFERSIZE]; + ALuint OutChannels; + IncrementRef(&device->MixCount); - SamplesToDo = minu(size, BUFFERSIZE); - for(c = 0;c < MaxChannels;c++) - memset(device->DryBuffer[c], 0, SamplesToDo*sizeof(ALfloat)); + OutBuffer = device->DryBuffer; + OutChannels = device->NumChannels; - ALCdevice_Lock(device); - V(device->Synth,process)(SamplesToDo, device->DryBuffer); + SamplesToDo = minu(size, BUFFERSIZE); + for(c = 0;c < OutChannels;c++) + memset(OutBuffer[c], 0, SamplesToDo*sizeof(ALfloat)); + if(device->Hrtf) + { + /* Set OutBuffer/OutChannels to correspond to the actual output + * with HRTF. Make sure to clear them too. */ + OutBuffer += OutChannels; + OutChannels = 2; + for(c = 0;c < OutChannels;c++) + memset(OutBuffer[c], 0, SamplesToDo*sizeof(ALfloat)); + } + + V0(device->Backend,lock)(); + + if((slot=device->DefaultSlot) != NULL) + { + if(ATOMIC_EXCHANGE(ALenum, &slot->NeedsUpdate, AL_FALSE)) + V(slot->EffectState,update)(device, slot); + memset(slot->WetBuffer[0], 0, SamplesToDo*sizeof(ALfloat)); + } ctx = ATOMIC_LOAD(&device->ContextList); while(ctx) { - ALenum DeferUpdates = ctx->DeferUpdates; - ALenum UpdateSources = AL_FALSE; - - if(!DeferUpdates) - UpdateSources = ATOMIC_EXCHANGE(ALenum, &ctx->UpdateSources, AL_FALSE); - - if(UpdateSources) - CalcListenerParams(ctx->Listener); + if(!ctx->DeferUpdates) + { + UpdateContextSources(ctx); +#define UPDATE_SLOT(iter) do { \ + if(ATOMIC_EXCHANGE(ALenum, &(*iter)->NeedsUpdate, AL_FALSE)) \ + V((*iter)->EffectState,update)(device, *iter); \ + memset((*iter)->WetBuffer[0], 0, SamplesToDo*sizeof(ALfloat)); \ +} while(0) + VECTOR_FOR_EACH(ALeffectslot*, ctx->ActiveAuxSlots, UPDATE_SLOT); +#undef UPDATE_SLOT + } + else + { +#define CLEAR_WET_BUFFER(iter) memset((*iter)->WetBuffer[0], 0, SamplesToDo*sizeof(ALfloat)) + VECTOR_FOR_EACH(ALeffectslot*, ctx->ActiveAuxSlots, CLEAR_WET_BUFFER); +#undef CLEAR_WET_BUFFER + } /* source processing */ - src = ctx->ActiveSources; - src_end = src + ctx->ActiveSourceCount; - while(src != src_end) + voice = ctx->Voices; + voice_end = voice + ctx->VoiceCount; + for(;voice != voice_end;++voice) { - ALsource *source = (*src)->Source; - - if(source->state != AL_PLAYING && source->state != AL_PAUSED) - { - ALactivesource *temp = *(--src_end); - *src_end = *src; - *src = temp; - --(ctx->ActiveSourceCount); - continue; - } - - if(!DeferUpdates && (ATOMIC_EXCHANGE(ALenum, &source->NeedsUpdate, AL_FALSE) || - UpdateSources)) - (*src)->Update(*src, ctx); - - if(source->state != AL_PAUSED) - MixSource(*src, device, SamplesToDo); - src++; + source = voice->Source; + if(source && source->state == AL_PLAYING) + MixSource(voice, source, device, SamplesToDo); } /* effect slot processing */ - slot = VECTOR_ITER_BEGIN(ctx->ActiveAuxSlots); - slot_end = VECTOR_ITER_END(ctx->ActiveAuxSlots); - while(slot != slot_end) - { - if(!DeferUpdates && ATOMIC_EXCHANGE(ALenum, &(*slot)->NeedsUpdate, AL_FALSE)) - V((*slot)->EffectState,update)(device, *slot); - - V((*slot)->EffectState,process)(SamplesToDo, (*slot)->WetBuffer[0], - device->DryBuffer); - - for(i = 0;i < SamplesToDo;i++) - (*slot)->WetBuffer[0][i] = 0.0f; - - slot++; - } +#define PROCESS_SLOT(iter) V((*iter)->EffectState,process)( \ + SamplesToDo, (*iter)->WetBuffer[0], device->DryBuffer, device->NumChannels \ +); + VECTOR_FOR_EACH(ALeffectslot*, ctx->ActiveAuxSlots, PROCESS_SLOT); +#undef PROCESS_SLOT ctx = ctx->next; } - slot = &device->DefaultSlot; - if(*slot != NULL) - { - if(ATOMIC_EXCHANGE(ALenum, &(*slot)->NeedsUpdate, AL_FALSE)) - V((*slot)->EffectState,update)(device, *slot); - - V((*slot)->EffectState,process)(SamplesToDo, (*slot)->WetBuffer[0], - device->DryBuffer); - - for(i = 0;i < SamplesToDo;i++) - (*slot)->WetBuffer[0][i] = 0.0f; - } + if((slot=device->DefaultSlot) != NULL) + V(slot->EffectState,process)( + SamplesToDo, slot->WetBuffer[0], device->DryBuffer, device->NumChannels + ); /* Increment the clock time. Every second's worth of samples is * converted and added to clock base so that large sample counts don't @@ -1237,48 +1488,64 @@ ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) device->SamplesDone += SamplesToDo; device->ClockBase += (device->SamplesDone/device->Frequency) * DEVICE_CLOCK_RES; device->SamplesDone %= device->Frequency; - ALCdevice_Unlock(device); + V0(device->Backend,unlock)(); - if(device->Bs2b) + if(device->Hrtf) + { + HrtfMixerFunc HrtfMix = SelectHrtfMixer(); + ALuint irsize = GetHrtfIrSize(device->Hrtf); + for(c = 0;c < device->NumChannels;c++) + HrtfMix(OutBuffer, device->DryBuffer[c], 0, device->Hrtf_Offset, + 0, irsize, &device->Hrtf_Params[c], &device->Hrtf_State[c], + SamplesToDo + ); + device->Hrtf_Offset += SamplesToDo; + } + else if(device->Bs2b) { /* Apply binaural/crossfeed filter */ for(i = 0;i < SamplesToDo;i++) { float samples[2]; - samples[0] = device->DryBuffer[FrontLeft][i]; - samples[1] = device->DryBuffer[FrontRight][i]; + samples[0] = device->DryBuffer[0][i]; + samples[1] = device->DryBuffer[1][i]; bs2b_cross_feed(device->Bs2b, samples); - device->DryBuffer[FrontLeft][i] = samples[0]; - device->DryBuffer[FrontRight][i] = samples[1]; + device->DryBuffer[0][i] = samples[0]; + device->DryBuffer[1][i] = samples[1]; } } if(buffer) { +#define WRITE(T, a, b, c, d) do { \ + Write_##T((a), (b), (c), (d)); \ + buffer = (T*)buffer + (c)*(d); \ +} while(0) switch(device->FmtType) { case DevFmtByte: - Write_ALbyte(device, &buffer, SamplesToDo); + WRITE(ALbyte, OutBuffer, buffer, SamplesToDo, OutChannels); break; case DevFmtUByte: - Write_ALubyte(device, &buffer, SamplesToDo); + WRITE(ALubyte, OutBuffer, buffer, SamplesToDo, OutChannels); break; case DevFmtShort: - Write_ALshort(device, &buffer, SamplesToDo); + WRITE(ALshort, OutBuffer, buffer, SamplesToDo, OutChannels); break; case DevFmtUShort: - Write_ALushort(device, &buffer, SamplesToDo); + WRITE(ALushort, OutBuffer, buffer, SamplesToDo, OutChannels); break; case DevFmtInt: - Write_ALint(device, &buffer, SamplesToDo); + WRITE(ALint, OutBuffer, buffer, SamplesToDo, OutChannels); break; case DevFmtUInt: - Write_ALuint(device, &buffer, SamplesToDo); + WRITE(ALuint, OutBuffer, buffer, SamplesToDo, OutChannels); break; case DevFmtFloat: - Write_ALfloat(device, &buffer, SamplesToDo); + WRITE(ALfloat, OutBuffer, buffer, SamplesToDo, OutChannels); break; } +#undef WRITE } size -= SamplesToDo; @@ -1298,23 +1565,26 @@ ALvoid aluHandleDisconnect(ALCdevice *device) Context = ATOMIC_LOAD(&device->ContextList); while(Context) { - ALactivesource **src, **src_end; + ALvoice *voice, *voice_end; - src = Context->ActiveSources; - src_end = src + Context->ActiveSourceCount; - while(src != src_end) + voice = Context->Voices; + voice_end = voice + Context->VoiceCount; + while(voice != voice_end) { - ALsource *source = (*src)->Source; - if(source->state == AL_PLAYING) + ALsource *source = voice->Source; + voice->Source = NULL; + + if(source && source->state == AL_PLAYING) { source->state = AL_STOPPED; ATOMIC_STORE(&source->current_buffer, NULL); source->position = 0; source->position_fraction = 0; } - src++; + + voice++; } - Context->ActiveSourceCount = 0; + Context->VoiceCount = 0; Context = Context->next; } diff --git a/libs/openal-soft/Alc/alcConfig.c b/libs/openal-soft/Alc/alcConfig.c index 2c9aef41..6fc9db33 100644 --- a/libs/openal-soft/Alc/alcConfig.c +++ b/libs/openal-soft/Alc/alcConfig.c @@ -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 */ @@ -33,11 +33,13 @@ #include #include #ifdef _WIN32_IE +#include #include #endif #include "alMain.h" #include "compat.h" +#include "bool.h" typedef struct ConfigEntry { @@ -137,13 +139,21 @@ static char *expdup(const char *str) } else { + bool hasbraces; char envname[1024]; size_t k = 0; + hasbraces = (*str == '{'); + if(hasbraces) str++; + while((isalnum(*str) || *str == '_') && k < sizeof(envname)-1) envname[k++] = *(str++); envname[k++] = '\0'; + if(hasbraces && *str != '}') + continue; + + if(hasbraces) str++; if((addstr=getenv(envname)) == NULL) continue; addstrlen = strlen(addstr); @@ -192,12 +202,8 @@ static void LoadConfigFromFile(FILE *f) char key[256] = ""; char value[256] = ""; - comment = strchr(buffer, '#'); - if(comment) *(comment++) = 0; - line = rstrip(lstrip(buffer)); - if(!line[0]) - continue; + if(!line[0]) continue; if(line[0] == '[') { @@ -205,10 +211,21 @@ static void LoadConfigFromFile(FILE *f) char *endsection; endsection = strchr(section, ']'); - if(!endsection || section == endsection || endsection[1] != 0) + if(!endsection || section == endsection) { - ERR("config parse error: bad line \"%s\"\n", line); - continue; + ERR("config parse error: bad line \"%s\"\n", line); + continue; + } + if(endsection[1] != 0) + { + char *end = endsection+1; + while(isspace(*end)) + ++end; + if(*end != 0 && *end != '#') + { + ERR("config parse error: bad line \"%s\"\n", line); + continue; + } } *endsection = 0; @@ -223,6 +240,10 @@ static void LoadConfigFromFile(FILE *f) continue; } + comment = strchr(line, '#'); + if(comment) *(comment++) = 0; + if(!line[0]) continue; + if(sscanf(line, "%255[^=] = \"%255[^\"]\"", key, value) == 2 || sscanf(line, "%255[^=] = '%255[^\']'", key, value) == 2 || sscanf(line, "%255[^=] = %255[^\n]", key, value) == 2) @@ -296,27 +317,33 @@ void ReadALConfig(void) if(SHGetSpecialFolderPathW(NULL, buffer, CSIDL_APPDATA, FALSE) != FALSE) { - size_t p = lstrlenW(buffer); - _snwprintf(buffer+p, PATH_MAX-p, L"\\alsoft.ini"); + al_string filepath = AL_STRING_INIT_STATIC(); + al_string_copy_wcstr(&filepath, buffer); + al_string_append_cstr(&filepath, "\\alsoft.ini"); - TRACE("Loading config %ls...\n", buffer); - f = _wfopen(buffer, L"rt"); + TRACE("Loading config %s...\n", al_string_get_cstr(filepath)); + f = al_fopen(al_string_get_cstr(filepath), "rt"); if(f) { LoadConfigFromFile(f); fclose(f); } + al_string_deinit(&filepath); } if((str=_wgetenv(L"ALSOFT_CONF")) != NULL && *str) { - TRACE("Loading config %ls...\n", str); - f = _wfopen(str, L"rt"); + al_string filepath = AL_STRING_INIT_STATIC(); + al_string_copy_wcstr(&filepath, str); + + TRACE("Loading config %s...\n", al_string_get_cstr(filepath)); + f = al_fopen(al_string_get_cstr(filepath), "rt"); if(f) { LoadConfigFromFile(f); fclose(f); } + al_string_deinit(&filepath); } } #else @@ -428,7 +455,7 @@ void FreeALConfig(void) free(cfgBlock.entries); } -const char *GetConfigValue(const char *blockName, const char *keyName, const char *def) +const char *GetConfigValue(const char *devName, const char *blockName, const char *keyName, const char *def) { unsigned int i; char key[256]; @@ -437,16 +464,26 @@ const char *GetConfigValue(const char *blockName, const char *keyName, const cha return def; if(blockName && strcasecmp(blockName, "general") != 0) - snprintf(key, sizeof(key), "%s/%s", blockName, keyName); + { + if(devName) + snprintf(key, sizeof(key), "%s/%s/%s", blockName, devName, keyName); + else + snprintf(key, sizeof(key), "%s/%s", blockName, keyName); + } else { - strncpy(key, keyName, sizeof(key)-1); - key[sizeof(key)-1] = 0; + if(devName) + snprintf(key, sizeof(key), "%s/%s", devName, keyName); + else + { + strncpy(key, keyName, sizeof(key)-1); + key[sizeof(key)-1] = 0; + } } for(i = 0;i < cfgBlock.entryCount;i++) { - if(strcasecmp(cfgBlock.entries[i].key, key) == 0) + if(strcmp(cfgBlock.entries[i].key, key) == 0) { TRACE("Found %s = \"%s\"\n", key, cfgBlock.entries[i].value); if(cfgBlock.entries[i].value[0]) @@ -455,46 +492,50 @@ const char *GetConfigValue(const char *blockName, const char *keyName, const cha } } - TRACE("Key %s not found\n", key); - return def; + if(!devName) + { + TRACE("Key %s not found\n", key); + return def; + } + return GetConfigValue(NULL, blockName, keyName, def); } -int ConfigValueExists(const char *blockName, const char *keyName) +int ConfigValueExists(const char *devName, const char *blockName, const char *keyName) { - const char *val = GetConfigValue(blockName, keyName, ""); + const char *val = GetConfigValue(devName, blockName, keyName, ""); return !!val[0]; } -int ConfigValueStr(const char *blockName, const char *keyName, const char **ret) +int ConfigValueStr(const char *devName, const char *blockName, const char *keyName, const char **ret) { - const char *val = GetConfigValue(blockName, keyName, ""); + const char *val = GetConfigValue(devName, blockName, keyName, ""); if(!val[0]) return 0; *ret = val; return 1; } -int ConfigValueInt(const char *blockName, const char *keyName, int *ret) +int ConfigValueInt(const char *devName, const char *blockName, const char *keyName, int *ret) { - const char *val = GetConfigValue(blockName, keyName, ""); + const char *val = GetConfigValue(devName, blockName, keyName, ""); if(!val[0]) return 0; *ret = strtol(val, NULL, 0); return 1; } -int ConfigValueUInt(const char *blockName, const char *keyName, unsigned int *ret) +int ConfigValueUInt(const char *devName, const char *blockName, const char *keyName, unsigned int *ret) { - const char *val = GetConfigValue(blockName, keyName, ""); + const char *val = GetConfigValue(devName, blockName, keyName, ""); if(!val[0]) return 0; *ret = strtoul(val, NULL, 0); return 1; } -int ConfigValueFloat(const char *blockName, const char *keyName, float *ret) +int ConfigValueFloat(const char *devName, const char *blockName, const char *keyName, float *ret) { - const char *val = GetConfigValue(blockName, keyName, ""); + const char *val = GetConfigValue(devName, blockName, keyName, ""); if(!val[0]) return 0; #ifdef HAVE_STRTOF @@ -505,9 +546,19 @@ int ConfigValueFloat(const char *blockName, const char *keyName, float *ret) return 1; } -int GetConfigValueBool(const char *blockName, const char *keyName, int def) +int ConfigValueBool(const char *devName, const char *blockName, const char *keyName, int *ret) { - const char *val = GetConfigValue(blockName, keyName, ""); + const char *val = GetConfigValue(devName, blockName, keyName, ""); + if(!val[0]) return 0; + + *ret = (strcasecmp(val, "true") == 0 || strcasecmp(val, "yes") == 0 || + strcasecmp(val, "on") == 0 || atoi(val) != 0); + return 1; +} + +int GetConfigValueBool(const char *devName, const char *blockName, const char *keyName, int def) +{ + const char *val = GetConfigValue(devName, blockName, keyName, ""); if(!val[0]) return !!def; return (strcasecmp(val, "true") == 0 || strcasecmp(val, "yes") == 0 || diff --git a/libs/openal-soft/Alc/alcRing.c b/libs/openal-soft/Alc/alcRing.c index 9b5d8214..e9a40a12 100644 --- a/libs/openal-soft/Alc/alcRing.c +++ b/libs/openal-soft/Alc/alcRing.c @@ -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 */ @@ -127,3 +127,275 @@ void ReadRingBuffer(RingBuffer *ring, ALubyte *data, ALsizei len) almtx_unlock(&ring->mtx); } + + +/* NOTE: This lockless ringbuffer implementation is copied from JACK, extended + * to include an element size. Consequently, parameters and return values for a + * size or count is in 'elements', not bytes. Additionally, it only supports + * single-consumer/single-provider operation. */ +struct ll_ringbuffer { + volatile size_t write_ptr; + volatile size_t read_ptr; + size_t size; + size_t size_mask; + size_t elem_size; + int mlocked; + + alignas(16) char buf[]; +}; + +/* Create a new ringbuffer to hold at least `sz' elements of `elem_sz' bytes. + * The number of elements is rounded up to the next power of two. */ +ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz) +{ + ll_ringbuffer_t *rb; + ALuint power_of_two; + + power_of_two = NextPowerOf2(sz); + if(power_of_two < sz) + return NULL; + + rb = al_malloc(16, sizeof(*rb) + power_of_two*elem_sz); + if(!rb) return NULL; + + rb->size = power_of_two; + rb->size_mask = rb->size - 1; + rb->elem_size = elem_sz; + rb->write_ptr = 0; + rb->read_ptr = 0; + rb->mlocked = 0; + return rb; +} + +/* Free all data associated with the ringbuffer `rb'. */ +void ll_ringbuffer_free(ll_ringbuffer_t *rb) +{ + if(rb) + { +#ifdef USE_MLOCK + if(rb->mlocked) + munlock(rb, sizeof(*rb) + rb->size*rb->elem_size); +#endif /* USE_MLOCK */ + al_free(rb); + } +} + +/* Lock the data block of `rb' using the system call 'mlock'. */ +int ll_ringbuffer_mlock(ll_ringbuffer_t *rb) +{ +#ifdef USE_MLOCK + if(!rb->locked && mlock(rb, sizeof(*rb) + rb->size*rb->elem_size)) + return -1; +#endif /* USE_MLOCK */ + rb->mlocked = 1; + return 0; +} + +/* Reset the read and write pointers to zero. This is not thread safe. */ +void ll_ringbuffer_reset(ll_ringbuffer_t *rb) +{ + rb->read_ptr = 0; + rb->write_ptr = 0; + memset(rb->buf, 0, rb->size*rb->elem_size); +} + +/* Return the number of elements available for reading. This is the number of + * elements in front of the read pointer and behind the write pointer. */ +size_t ll_ringbuffer_read_space(const ll_ringbuffer_t *rb) +{ + size_t w = rb->write_ptr; + size_t r = rb->read_ptr; + return (rb->size+w-r) & rb->size_mask; +} +/* Return the number of elements available for writing. This is the number of + * elements in front of the write pointer and behind the read pointer. */ +size_t ll_ringbuffer_write_space(const ll_ringbuffer_t *rb) +{ + size_t w = rb->write_ptr; + size_t r = rb->read_ptr; + return (rb->size+r-w-1) & rb->size_mask; +} + +/* The copying data reader. Copy at most `cnt' elements from `rb' to `dest'. + * Returns the actual number of elements copied. */ +size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, char *dest, size_t cnt) +{ + size_t free_cnt; + size_t cnt2; + size_t to_read; + size_t n1, n2; + + free_cnt = ll_ringbuffer_read_space(rb); + if(free_cnt == 0) return 0; + + to_read = (cnt > free_cnt) ? free_cnt : cnt; + cnt2 = rb->read_ptr + to_read; + if(cnt2 > rb->size) + { + n1 = rb->size - rb->read_ptr; + n2 = cnt2 & rb->size_mask; + } + else + { + n1 = to_read; + n2 = 0; + } + + memcpy(dest, &(rb->buf[rb->read_ptr*rb->elem_size]), n1*rb->elem_size); + rb->read_ptr = (rb->read_ptr + n1) & rb->size_mask; + if(n2) + { + memcpy(dest + n1*rb->elem_size, &(rb->buf[rb->read_ptr*rb->elem_size]), n2*rb->elem_size); + rb->read_ptr = (rb->read_ptr + n2) & rb->size_mask; + } + return to_read; +} + +/* The copying data reader w/o read pointer advance. Copy at most `cnt' + * elements from `rb' to `dest'. Returns the actual number of elements copied. + */ +size_t ll_ringbuffer_peek(ll_ringbuffer_t *rb, char *dest, size_t cnt) +{ + size_t free_cnt; + size_t cnt2; + size_t to_read; + size_t n1, n2; + size_t tmp_read_ptr; + + tmp_read_ptr = rb->read_ptr; + free_cnt = ll_ringbuffer_read_space(rb); + if(free_cnt == 0) return 0; + + to_read = (cnt > free_cnt) ? free_cnt : cnt; + cnt2 = tmp_read_ptr + to_read; + if(cnt2 > rb->size) + { + n1 = rb->size - tmp_read_ptr; + n2 = cnt2 & rb->size_mask; + } + else + { + n1 = to_read; + n2 = 0; + } + + memcpy(dest, &(rb->buf[tmp_read_ptr*rb->elem_size]), n1*rb->elem_size); + tmp_read_ptr = (tmp_read_ptr + n1) & rb->size_mask; + if(n2) + memcpy(dest + n1*rb->elem_size, &(rb->buf[tmp_read_ptr*rb->elem_size]), n2*rb->elem_size); + return to_read; +} + +/* The copying data writer. Copy at most `cnt' elements to `rb' from `src'. + * Returns the actual number of elements copied. */ +size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const char *src, size_t cnt) +{ + size_t free_cnt; + size_t cnt2; + size_t to_write; + size_t n1, n2; + + free_cnt = ll_ringbuffer_write_space(rb); + if(free_cnt == 0) return 0; + + to_write = (cnt > free_cnt) ? free_cnt : cnt; + cnt2 = rb->write_ptr + to_write; + if(cnt2 > rb->size) + { + n1 = rb->size - rb->write_ptr; + n2 = cnt2 & rb->size_mask; + } + else + { + n1 = to_write; + n2 = 0; + } + + memcpy(&(rb->buf[rb->write_ptr*rb->elem_size]), src, n1*rb->elem_size); + rb->write_ptr = (rb->write_ptr + n1) & rb->size_mask; + if(n2) + { + memcpy(&(rb->buf[rb->write_ptr*rb->elem_size]), src + n1*rb->elem_size, n2*rb->elem_size); + rb->write_ptr = (rb->write_ptr + n2) & rb->size_mask; + } + return to_write; +} + +/* Advance the read pointer `cnt' places. */ +void ll_ringbuffer_read_advance(ll_ringbuffer_t *rb, size_t cnt) +{ + size_t tmp = (rb->read_ptr + cnt) & rb->size_mask; + rb->read_ptr = tmp; +} + +/* Advance the write pointer `cnt' places. */ +void ll_ringbuffer_write_advance(ll_ringbuffer_t *rb, size_t cnt) +{ + size_t tmp = (rb->write_ptr + cnt) & rb->size_mask; + rb->write_ptr = tmp; +} + +/* The non-copying data reader. `vec' is an array of two places. Set the values + * at `vec' to hold the current readable data at `rb'. If the readable data is + * in one segment the second segment has zero length. */ +void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t * vec) +{ + size_t free_cnt; + size_t cnt2; + size_t w, r; + + w = rb->write_ptr; + r = rb->read_ptr; + free_cnt = (rb->size+w-r) & rb->size_mask; + + cnt2 = r + free_cnt; + if(cnt2 > rb->size) + { + /* Two part vector: the rest of the buffer after the current write ptr, + * plus some from the start of the buffer. */ + vec[0].buf = (char*)&(rb->buf[r*rb->elem_size]); + vec[0].len = rb->size - r; + vec[1].buf = (char*)rb->buf; + vec[1].len = cnt2 & rb->size_mask; + } + else + { + /* Single part vector: just the rest of the buffer */ + vec[0].buf = (char*)&(rb->buf[r*rb->elem_size]); + vec[0].len = free_cnt; + vec[1].buf = NULL; + vec[1].len = 0; + } +} + +/* The non-copying data writer. `vec' is an array of two places. Set the values + * at `vec' to hold the current writeable data at `rb'. If the writeable data + * is in one segment the second segment has zero length. */ +void ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t *vec) +{ + size_t free_cnt; + size_t cnt2; + size_t w, r; + + w = rb->write_ptr; + r = rb->read_ptr; + free_cnt = (rb->size+r-w-1) & rb->size_mask; + + cnt2 = w + free_cnt; + if(cnt2 > rb->size) + { + /* Two part vector: the rest of the buffer after the current write ptr, + * plus some from the start of the buffer. */ + vec[0].buf = (char*)&(rb->buf[w*rb->elem_size]); + vec[0].len = rb->size - w; + vec[1].buf = (char*)rb->buf; + vec[1].len = cnt2 & rb->size_mask; + } + else + { + vec[0].buf = (char*)&(rb->buf[w*rb->elem_size]); + vec[0].len = free_cnt; + vec[1].buf = NULL; + vec[1].len = 0; + } +} diff --git a/libs/openal-soft/Alc/alstring.h b/libs/openal-soft/Alc/alstring.h index 32f4280a..f53d2c57 100644 --- a/libs/openal-soft/Alc/alstring.h +++ b/libs/openal-soft/Alc/alstring.h @@ -8,6 +8,7 @@ typedef char al_string_char_type; TYPEDEF_VECTOR(al_string_char_type, al_string) +TYPEDEF_VECTOR(al_string, vector_al_string) inline void al_string_deinit(al_string *str) { VECTOR_DEINIT(*str); } @@ -15,7 +16,7 @@ inline void al_string_deinit(al_string *str) #define AL_STRING_INIT_STATIC() ((al_string)NULL) #define AL_STRING_DEINIT(_x) al_string_deinit(&(_x)) -inline ALsizei al_string_length(const_al_string str) +inline size_t al_string_length(const_al_string str) { return VECTOR_SIZE(str); } inline ALboolean al_string_empty(const_al_string str) @@ -40,6 +41,8 @@ void al_string_append_range(al_string *str, const al_string_char_type *from, con #include /* Windows-only methods to deal with WideChar strings. */ void al_string_copy_wcstr(al_string *str, const wchar_t *from); +void al_string_append_wcstr(al_string *str, const wchar_t *from); +void al_string_append_wrange(al_string *str, const wchar_t *from, const wchar_t *to); #endif #endif /* ALSTRING_H */ diff --git a/libs/openal-soft/Alc/backends/alsa.c b/libs/openal-soft/Alc/backends/alsa.c index d5174da8..9a443c09 100644 --- a/libs/openal-soft/Alc/backends/alsa.c +++ b/libs/openal-soft/Alc/backends/alsa.c @@ -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 */ @@ -273,14 +273,14 @@ static void probe_devices(snd_pcm_stream_t stream, vector_DevMap *DeviceList) AL_STRING_INIT(entry.name); AL_STRING_INIT(entry.device_name); al_string_copy_cstr(&entry.name, alsaDevice); - al_string_copy_cstr(&entry.device_name, GetConfigValue("alsa", (stream==SND_PCM_STREAM_PLAYBACK) ? + al_string_copy_cstr(&entry.device_name, GetConfigValue(NULL, "alsa", (stream==SND_PCM_STREAM_PLAYBACK) ? "device" : "capture", "default")); VECTOR_PUSH_BACK(*DeviceList, entry); card = -1; if((err=snd_card_next(&card)) < 0) ERR("Failed to find a card: %s\n", snd_strerror(err)); - ConfigValueStr("alsa", prefix_name(stream), &main_prefix); + ConfigValueStr(NULL, "alsa", prefix_name(stream), &main_prefix); while(card >= 0) { const char *card_prefix = main_prefix; @@ -304,7 +304,7 @@ static void probe_devices(snd_pcm_stream_t stream, vector_DevMap *DeviceList) cardid = snd_ctl_card_info_get_id(info); snprintf(name, sizeof(name), "%s-%s", prefix_name(stream), cardid); - ConfigValueStr("alsa", name, &card_prefix); + ConfigValueStr(NULL, "alsa", name, &card_prefix); dev = -1; while(1) @@ -330,7 +330,7 @@ static void probe_devices(snd_pcm_stream_t stream, vector_DevMap *DeviceList) devname = snd_pcm_info_get_name(pcminfo); snprintf(name, sizeof(name), "%s-%s-%d", prefix_name(stream), cardid, dev); - ConfigValueStr("alsa", name, &device_prefix); + ConfigValueStr(NULL, "alsa", name, &device_prefix); snprintf(name, sizeof(name), "%s, %s (CARD=%s,DEV=%d)", cardname, devname, cardid, dev); @@ -640,7 +640,7 @@ static ALCenum ALCplaybackAlsa_open(ALCplaybackAlsa *self, const ALCchar *name) else { name = alsaDevice; - driver = GetConfigValue("alsa", "device", "default"); + driver = GetConfigValue(NULL, "alsa", "device", "default"); } TRACE("Opening device \"%s\"\n", driver); @@ -704,7 +704,7 @@ static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) break; } - allowmmap = GetConfigValueBool("alsa", "mmap", 1); + allowmmap = GetConfigValueBool(al_string_get_cstr(device->DeviceName), "alsa", "mmap", 1); periods = device->NumUpdates; periodLen = (ALuint64)device->UpdateSize * 1000000 / device->Frequency; bufferLen = periodLen * periods; @@ -770,8 +770,11 @@ static ALCboolean ALCplaybackAlsa_reset(ALCplaybackAlsa *self) } CHECK(snd_pcm_hw_params_set_channels(self->pcmHandle, hp, ChannelsFromDevFmt(device->FmtChans))); /* set rate (implicitly constrains period/buffer parameters) */ - if(snd_pcm_hw_params_set_rate_resample(self->pcmHandle, hp, 0) < 0) - ERR("Failed to disable ALSA resampler\n"); + if(GetConfigValueBool(al_string_get_cstr(device->DeviceName), "alsa", "allow-resampler", 0)) + { + if(snd_pcm_hw_params_set_rate_resample(self->pcmHandle, hp, 0) < 0) + ERR("Failed to disable ALSA resampler\n"); + } CHECK(snd_pcm_hw_params_set_rate_near(self->pcmHandle, hp, &rate, NULL)); /* set buffer time (implicitly constrains period/buffer parameters) */ if((err=snd_pcm_hw_params_set_buffer_time_near(self->pcmHandle, hp, &bufferLen, NULL)) < 0) @@ -965,7 +968,7 @@ static ALCenum ALCcaptureAlsa_open(ALCcaptureAlsa *self, const ALCchar *name) else { name = alsaDevice; - driver = GetConfigValue("alsa", "capture", "default"); + driver = GetConfigValue(NULL, "alsa", "capture", "default"); } TRACE("Opening device \"%s\"\n", driver); @@ -1352,25 +1355,15 @@ static ALCbackend* ALCalsaBackendFactory_createBackend(ALCalsaBackendFactory* UN if(type == ALCbackend_Playback) { ALCplaybackAlsa *backend; - - backend = ALCplaybackAlsa_New(sizeof(*backend)); + NEW_OBJ(backend, ALCplaybackAlsa)(device); if(!backend) return NULL; - memset(backend, 0, sizeof(*backend)); - - ALCplaybackAlsa_Construct(backend, device); - return STATIC_CAST(ALCbackend, backend); } if(type == ALCbackend_Capture) { ALCcaptureAlsa *backend; - - backend = ALCcaptureAlsa_New(sizeof(*backend)); + NEW_OBJ(backend, ALCcaptureAlsa)(device); if(!backend) return NULL; - memset(backend, 0, sizeof(*backend)); - - ALCcaptureAlsa_Construct(backend, device); - return STATIC_CAST(ALCbackend, backend); } diff --git a/libs/openal-soft/Alc/backends/base.c b/libs/openal-soft/Alc/backends/base.c index 37e4ccc9..ebeb31bf 100644 --- a/libs/openal-soft/Alc/backends/base.c +++ b/libs/openal-soft/Alc/backends/base.c @@ -77,7 +77,7 @@ static ALCboolean PlaybackWrapper_start(PlaybackWrapper *self); static void PlaybackWrapper_stop(PlaybackWrapper *self); static DECLARE_FORWARD2(PlaybackWrapper, ALCbackend, ALCenum, captureSamples, void*, ALCuint) static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, ALCuint, availableSamples) -static ALint64 PlaybackWrapper_getLatency(PlaybackWrapper *self); +static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, ALint64, getLatency) static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, lock) static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(PlaybackWrapper) @@ -121,12 +121,6 @@ static void PlaybackWrapper_stop(PlaybackWrapper *self) self->Funcs->StopPlayback(device); } -static ALint64 PlaybackWrapper_getLatency(PlaybackWrapper *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - return self->Funcs->GetLatency(device); -} - typedef struct CaptureWrapper { DERIVE_FROM_TYPE(ALCbackend); @@ -143,13 +137,12 @@ static ALCboolean CaptureWrapper_start(CaptureWrapper *self); static void CaptureWrapper_stop(CaptureWrapper *self); static ALCenum CaptureWrapper_captureSamples(CaptureWrapper *self, void *buffer, ALCuint samples); static ALCuint CaptureWrapper_availableSamples(CaptureWrapper *self); -static ALint64 CaptureWrapper_getLatency(CaptureWrapper *self); +static DECLARE_FORWARD(CaptureWrapper, ALCbackend, ALint64, getLatency) static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, lock) static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, unlock) DECLARE_DEFAULT_ALLOCATORS(CaptureWrapper) DEFINE_ALCBACKEND_VTABLE(CaptureWrapper); - static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device, const BackendFuncs *funcs) { ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); @@ -195,12 +188,6 @@ static ALCuint CaptureWrapper_availableSamples(CaptureWrapper *self) return self->Funcs->AvailableSamples(device); } -static ALint64 CaptureWrapper_getLatency(CaptureWrapper *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - return self->Funcs->GetLatency(device); -} - ALCbackend *create_backend_wrapper(ALCdevice *device, const BackendFuncs *funcs, ALCbackend_Type type) { @@ -208,11 +195,9 @@ ALCbackend *create_backend_wrapper(ALCdevice *device, const BackendFuncs *funcs, { PlaybackWrapper *backend; - backend = PlaybackWrapper_New(sizeof(*backend)); + NEW_OBJ(backend, PlaybackWrapper)(device, funcs); if(!backend) return NULL; - PlaybackWrapper_Construct(backend, device, funcs); - return STATIC_CAST(ALCbackend, backend); } @@ -220,11 +205,9 @@ ALCbackend *create_backend_wrapper(ALCdevice *device, const BackendFuncs *funcs, { CaptureWrapper *backend; - backend = CaptureWrapper_New(sizeof(*backend)); + NEW_OBJ(backend, CaptureWrapper)(device, funcs); if(!backend) return NULL; - CaptureWrapper_Construct(backend, device, funcs); - return STATIC_CAST(ALCbackend, backend); } diff --git a/libs/openal-soft/Alc/backends/base.h b/libs/openal-soft/Alc/backends/base.h index 5573c178..f6b4b80a 100644 --- a/libs/openal-soft/Alc/backends/base.h +++ b/libs/openal-soft/Alc/backends/base.h @@ -123,9 +123,14 @@ static const struct ALCbackendFactoryVtable T##_ALCbackendFactory_vtable = { \ ALCbackendFactory *ALCpulseBackendFactory_getFactory(void); ALCbackendFactory *ALCalsaBackendFactory_getFactory(void); ALCbackendFactory *ALCossBackendFactory_getFactory(void); +ALCbackendFactory *ALCjackBackendFactory_getFactory(void); +ALCbackendFactory *ALCsolarisBackendFactory_getFactory(void); ALCbackendFactory *ALCmmdevBackendFactory_getFactory(void); ALCbackendFactory *ALCdsoundBackendFactory_getFactory(void); +ALCbackendFactory *ALCwinmmBackendFactory_getFactory(void); +ALCbackendFactory *ALCportBackendFactory_getFactory(void); ALCbackendFactory *ALCnullBackendFactory_getFactory(void); +ALCbackendFactory *ALCwaveBackendFactory_getFactory(void); ALCbackendFactory *ALCloopbackFactory_getFactory(void); ALCbackend *create_backend_wrapper(ALCdevice *device, const BackendFuncs *funcs, ALCbackend_Type type); diff --git a/libs/openal-soft/Alc/backends/coreaudio.c b/libs/openal-soft/Alc/backends/coreaudio.c index b3583ffd..43e881da 100644 --- a/libs/openal-soft/Alc/backends/coreaudio.c +++ b/libs/openal-soft/Alc/backends/coreaudio.c @@ -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 */ @@ -383,6 +383,11 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) ca_data *data; OSStatus err; + if(!deviceName) + deviceName = ca_device; + else if(strcmp(deviceName, ca_device) != 0) + return ALC_INVALID_VALUE; + desc.componentType = kAudioUnitType_Output; desc.componentSubType = kAudioUnitSubType_HALOutput; desc.componentManufacturer = kAudioUnitManufacturer_Apple; @@ -514,9 +519,10 @@ static ALCenum ca_open_capture(ALCdevice *device, const ALCchar *deviceName) case DevFmtQuad: case DevFmtX51: - case DevFmtX51Side: + case DevFmtX51Rear: case DevFmtX61: case DevFmtX71: + case DevFmtBFormat3D: ERR("%s not supported\n", DevFmtChannelsString(device->FmtChans)); goto error; } @@ -679,8 +685,7 @@ static const BackendFuncs ca_funcs = { ca_start_capture, ca_stop_capture, ca_capture_samples, - ca_available_samples, - ALCdevice_GetLatencyDefault + ca_available_samples }; ALCboolean alc_ca_init(BackendFuncs *func_list) diff --git a/libs/openal-soft/Alc/backends/dsound.c b/libs/openal-soft/Alc/backends/dsound.c index 2229347e..4db4b557 100644 --- a/libs/openal-soft/Alc/backends/dsound.c +++ b/libs/openal-soft/Alc/backends/dsound.c @@ -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 */ @@ -43,6 +43,9 @@ #ifndef DSSPEAKER_5POINT1 # define DSSPEAKER_5POINT1 0x00000006 #endif +#ifndef DSSPEAKER_5POINT1_BACK +# define DSSPEAKER_5POINT1_BACK 0x00000006 +#endif #ifndef DSSPEAKER_7POINT1 # define DSSPEAKER_7POINT1 0x00000007 #endif @@ -57,6 +60,8 @@ DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); +#define DEVNAME_TAIL " on OpenAL Soft" + #ifdef HAVE_DYNLOAD static void *ds_handle; @@ -118,15 +123,14 @@ static void clear_devlist(vector_DevMap *list) { #define DEINIT_STR(i) AL_STRING_DEINIT((i)->name) VECTOR_FOR_EACH(DevMap, *list, DEINIT_STR); -#undef DEINIT_STR VECTOR_RESIZE(*list, 0); +#undef DEINIT_STR } static BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHAR* UNUSED(drvname), void *data) { vector_DevMap *devices = data; OLECHAR *guidstr = NULL; - DevMap *iter, *end; DevMap entry; HRESULT hr; int count; @@ -137,24 +141,26 @@ static BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHA AL_STRING_INIT(entry.name); count = 0; - do { + while(1) + { + const DevMap *iter; + al_string_copy_wcstr(&entry.name, desc); - if(count != 0) + if(count == 0) + al_string_append_cstr(&entry.name, DEVNAME_TAIL); + else { char str[64]; - snprintf(str, sizeof(str), " #%d", count+1); + snprintf(str, sizeof(str), " #%d"DEVNAME_TAIL, count+1); al_string_append_cstr(&entry.name, str); } - count++; - iter = VECTOR_ITER_BEGIN(*devices); - end = VECTOR_ITER_END(*devices); - for(;iter != end;++iter) - { - if(al_string_cmp(entry.name, iter->name) == 0) - break; - } - } while(iter != end); +#define MATCH_ENTRY(i) (al_string_cmp(entry.name, (i)->name) == 0) + VECTOR_FIND_IF(iter, const DevMap, *devices, MATCH_ENTRY); + if(iter == VECTOR_ITER_END(*devices)) break; +#undef MATCH_ENTRY + count++; + } entry.guid = *guid; hr = StringFromCLSID(guid, &guidstr); @@ -441,28 +447,35 @@ static ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self) hr = IDirectSound_GetSpeakerConfig(self->DS, &speakers); if(SUCCEEDED(hr)) { + speakers = DSSPEAKER_CONFIG(speakers); if(!(device->Flags&DEVICE_CHANNELS_REQUEST)) { - speakers = DSSPEAKER_CONFIG(speakers); if(speakers == DSSPEAKER_MONO) device->FmtChans = DevFmtMono; else if(speakers == DSSPEAKER_STEREO || speakers == DSSPEAKER_HEADPHONE) device->FmtChans = DevFmtStereo; else if(speakers == DSSPEAKER_QUAD) device->FmtChans = DevFmtQuad; - else if(speakers == DSSPEAKER_5POINT1 || speakers == DSSPEAKER_5POINT1_SURROUND) + else if(speakers == DSSPEAKER_5POINT1_SURROUND) device->FmtChans = DevFmtX51; + else if(speakers == DSSPEAKER_5POINT1_BACK) + device->FmtChans = DevFmtX51Rear; else if(speakers == DSSPEAKER_7POINT1 || speakers == DSSPEAKER_7POINT1_SURROUND) device->FmtChans = DevFmtX71; else ERR("Unknown system speaker config: 0x%lx\n", speakers); } + device->IsHeadphones = (device->FmtChans == DevFmtStereo && + speakers == DSSPEAKER_HEADPHONE); switch(device->FmtChans) { case DevFmtMono: OutputType.dwChannelMask = SPEAKER_FRONT_CENTER; break; + case DevFmtBFormat3D: + device->FmtChans = DevFmtStereo; + /*fall-through*/ case DevFmtStereo: OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; @@ -478,16 +491,16 @@ static ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self) SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | - SPEAKER_BACK_LEFT | - SPEAKER_BACK_RIGHT; + SPEAKER_SIDE_LEFT | + SPEAKER_SIDE_RIGHT; break; - case DevFmtX51Side: + case DevFmtX51Rear: OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | - SPEAKER_SIDE_LEFT | - SPEAKER_SIDE_RIGHT; + SPEAKER_BACK_LEFT | + SPEAKER_BACK_RIGHT; break; case DevFmtX61: OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | @@ -745,16 +758,16 @@ static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *devi SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | - SPEAKER_BACK_LEFT | - SPEAKER_BACK_RIGHT; + SPEAKER_SIDE_LEFT | + SPEAKER_SIDE_RIGHT; break; - case DevFmtX51Side: + case DevFmtX51Rear: InputType.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | - SPEAKER_SIDE_LEFT | - SPEAKER_SIDE_RIGHT; + SPEAKER_BACK_LEFT | + SPEAKER_BACK_RIGHT; break; case DevFmtX61: InputType.dwChannelMask = SPEAKER_FRONT_LEFT | @@ -775,6 +788,8 @@ static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *devi SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT; break; + case DevFmtBFormat3D: + break; } InputType.Format.wFormatTag = WAVE_FORMAT_PCM; @@ -1027,26 +1042,16 @@ static ALCbackend* ALCdsoundBackendFactory_createBackend(ALCdsoundBackendFactory if(type == ALCbackend_Playback) { ALCdsoundPlayback *backend; - - backend = ALCdsoundPlayback_New(sizeof(*backend)); + NEW_OBJ(backend, ALCdsoundPlayback)(device); if(!backend) return NULL; - memset(backend, 0, sizeof(*backend)); - - ALCdsoundPlayback_Construct(backend, device); - return STATIC_CAST(ALCbackend, backend); } if(type == ALCbackend_Capture) { ALCdsoundCapture *backend; - - backend = ALCdsoundCapture_New(sizeof(*backend)); + NEW_OBJ(backend, ALCdsoundCapture)(device); if(!backend) return NULL; - memset(backend, 0, sizeof(*backend)); - - ALCdsoundCapture_Construct(backend, device); - return STATIC_CAST(ALCbackend, backend); } diff --git a/libs/openal-soft/Alc/backends/loopback.c b/libs/openal-soft/Alc/backends/loopback.c index 505dfacf..3e577f78 100644 --- a/libs/openal-soft/Alc/backends/loopback.c +++ b/libs/openal-soft/Alc/backends/loopback.c @@ -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 */ @@ -124,13 +124,8 @@ static ALCbackend* ALCloopbackFactory_createBackend(ALCloopbackFactory* UNUSED(s if(type == ALCbackend_Loopback) { ALCloopback *backend; - - backend = ALCloopback_New(sizeof(*backend)); + NEW_OBJ(backend, ALCloopback)(device); if(!backend) return NULL; - memset(backend, 0, sizeof(*backend)); - - ALCloopback_Construct(backend, device); - return STATIC_CAST(ALCbackend, backend); } diff --git a/libs/openal-soft/Alc/backends/mmdevapi.c b/libs/openal-soft/Alc/backends/mmdevapi.c index 430e1cb8..e8563d33 100644 --- a/libs/openal-soft/Alc/backends/mmdevapi.c +++ b/libs/openal-soft/Alc/backends/mmdevapi.c @@ -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 */ @@ -51,14 +51,18 @@ DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14); +DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x8c,0x23, 0xe0,0xc0,0xff,0xee,0x7f,0x0e, 0); #define MONO SPEAKER_FRONT_CENTER #define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT) #define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT) -#define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT) -#define X5DOT1SIDE (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT) +#define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT) +#define X5DOT1REAR (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT) #define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT) #define X7DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT) +#define X7DOT1_WIDE (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_FRONT_LEFT_OF_CENTER|SPEAKER_FRONT_RIGHT_OF_CENTER) + +#define DEVNAME_TAIL " on OpenAL Soft" typedef struct { @@ -69,16 +73,14 @@ TYPEDEF_VECTOR(DevMap, vector_DevMap) static void clear_devlist(vector_DevMap *list) { - DevMap *iter, *end; - - iter = VECTOR_ITER_BEGIN(*list); - end = VECTOR_ITER_END(*list); - for(;iter != end;iter++) - { - AL_STRING_DEINIT(iter->name); - free(iter->devid); - } +#define CLEAR_DEVMAP(i) do { \ + AL_STRING_DEINIT((i)->name); \ + free((i)->devid); \ + (i)->devid = NULL; \ +} while(0) + VECTOR_FOR_EACH(DevMap, *list, CLEAR_DEVMAP); VECTOR_RESIZE(*list, 0); +#undef CLEAR_DEVMAP } static vector_DevMap PlaybackDevices; @@ -134,39 +136,105 @@ static void get_device_name(IMMDevice *device, al_string *name) hr = IPropertyStore_GetValue(ps, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pvname); if(FAILED(hr)) - WARN("GetValue failed: 0x%08lx\n", hr); - else + WARN("GetValue Device_FriendlyName failed: 0x%08lx\n", hr); + else if(pvname.vt == VT_LPWSTR) al_string_copy_wcstr(name, pvname.pwszVal); + else + WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvname.vt); PropVariantClear(&pvname); IPropertyStore_Release(ps); } -static void add_device(IMMDevice *device, vector_DevMap *list) +static void get_device_formfactor(IMMDevice *device, EndpointFormFactor *formfactor) +{ + IPropertyStore *ps; + PROPVARIANT pvform; + HRESULT hr; + + hr = IMMDevice_OpenPropertyStore(device, STGM_READ, &ps); + if(FAILED(hr)) + { + WARN("OpenPropertyStore failed: 0x%08lx\n", hr); + return; + } + + PropVariantInit(&pvform); + + hr = IPropertyStore_GetValue(ps, &PKEY_AudioEndpoint_FormFactor, &pvform); + if(FAILED(hr)) + WARN("GetValue AudioEndpoint_FormFactor failed: 0x%08lx\n", hr); + else if(pvform.vt == VT_UI4) + *formfactor = pvform.ulVal; + else if(pvform.vt == VT_EMPTY) + *formfactor = UnknownFormFactor; + else + WARN("Unexpected PROPVARIANT type: 0x%04x\n", pvform.vt); + + PropVariantClear(&pvform); + IPropertyStore_Release(ps); +} + + +static void add_device(IMMDevice *device, LPCWSTR devid, vector_DevMap *list) +{ + int count = 0; + al_string tmpname; + DevMap entry; + + AL_STRING_INIT(tmpname); + AL_STRING_INIT(entry.name); + + entry.devid = strdupW(devid); + get_device_name(device, &tmpname); + + while(1) + { + const DevMap *iter; + + al_string_copy(&entry.name, tmpname); + if(count == 0) + al_string_append_cstr(&entry.name, DEVNAME_TAIL); + else + { + char str[64]; + snprintf(str, sizeof(str), " #%d"DEVNAME_TAIL, count+1); + al_string_append_cstr(&entry.name, str); + } + +#define MATCH_ENTRY(i) (al_string_cmp(entry.name, (i)->name) == 0) + VECTOR_FIND_IF(iter, const DevMap, *list, MATCH_ENTRY); + if(iter == VECTOR_ITER_END(*list)) break; +#undef MATCH_ENTRY + count++; + } + + TRACE("Got device \"%s\", \"%ls\"\n", al_string_get_cstr(entry.name), entry.devid); + VECTOR_PUSH_BACK(*list, entry); + + AL_STRING_DEINIT(tmpname); +} + +static LPWSTR get_device_id(IMMDevice *device) { LPWSTR devid; HRESULT hr; hr = IMMDevice_GetId(device, &devid); - if(SUCCEEDED(hr)) + if(FAILED(hr)) { - DevMap entry; - AL_STRING_INIT(entry.name); - - entry.devid = strdupW(devid); - get_device_name(device, &entry.name); - - CoTaskMemFree(devid); - - TRACE("Got device \"%s\", \"%ls\"\n", al_string_get_cstr(entry.name), entry.devid); - VECTOR_PUSH_BACK(*list, entry); + ERR("Failed to get device id: %lx\n", hr); + return NULL; } + + return devid; } static HRESULT probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, vector_DevMap *list) { IMMDeviceCollection *coll; IMMDevice *defdev = NULL; + LPWSTR defdevid = NULL; HRESULT hr; UINT count; UINT i; @@ -183,7 +251,7 @@ static HRESULT probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, ve if(SUCCEEDED(hr) && count > 0) { clear_devlist(list); - if(!VECTOR_RESERVE(*list, count+1)) + if(!VECTOR_RESERVE(*list, count)) { IMMDeviceCollection_Release(coll); return E_OUTOFMEMORY; @@ -193,22 +261,32 @@ static HRESULT probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, ve eMultimedia, &defdev); } if(SUCCEEDED(hr) && defdev != NULL) - add_device(defdev, list); + { + defdevid = get_device_id(defdev); + if(defdevid) + add_device(defdev, defdevid, list); + } for(i = 0;i < count;++i) { IMMDevice *device; + LPWSTR devid; - if(FAILED(IMMDeviceCollection_Item(coll, i, &device))) - continue; - - if(device != defdev) - add_device(device, list); + hr = IMMDeviceCollection_Item(coll, i, &device); + if(FAILED(hr)) continue; + devid = get_device_id(device); + if(devid) + { + if(wcscmp(devid, defdevid) != 0) + add_device(device, devid, list); + CoTaskMemFree(devid); + } IMMDevice_Release(device); } if(defdev) IMMDevice_Release(defdev); + if(defdevid) CoTaskMemFree(defdevid); IMMDeviceCollection_Release(coll); return S_OK; @@ -294,7 +372,7 @@ static DWORD CALLBACK ALCmmdevProxy_messageHandler(void *ptr) TRACE("Starting message loop\n"); while(GetMessage(&msg, NULL, WM_USER_First, WM_USER_Last)) { - TRACE("Got message %u\n", msg.message); + TRACE("Got message %u (lparam=%p, wparam=%p)\n", msg.message, (void*)msg.lParam, (void*)msg.wParam); switch(msg.message) { case WM_USER_OpenDevice: @@ -483,9 +561,9 @@ FORCE_ALIGN static int ALCmmdevPlayback_mixerProc(void *arg) if(FAILED(hr)) { ERR("CoInitialize(NULL) failed: 0x%08lx\n", hr); - ALCdevice_Lock(device); + V0(device->Backend,lock)(); aluHandleDisconnect(device); - ALCdevice_Unlock(device); + V0(device->Backend,unlock)(); return 1; } @@ -500,9 +578,9 @@ FORCE_ALIGN static int ALCmmdevPlayback_mixerProc(void *arg) if(FAILED(hr)) { ERR("Failed to get padding: 0x%08lx\n", hr); - ALCdevice_Lock(device); + V0(device->Backend,lock)(); aluHandleDisconnect(device); - ALCdevice_Unlock(device); + V0(device->Backend,unlock)(); break; } self->Padding = written; @@ -521,18 +599,18 @@ FORCE_ALIGN static int ALCmmdevPlayback_mixerProc(void *arg) hr = IAudioRenderClient_GetBuffer(self->render, len, &buffer); if(SUCCEEDED(hr)) { - ALCdevice_Lock(device); + V0(device->Backend,lock)(); aluMixData(device, buffer, len); self->Padding = written + len; - ALCdevice_Unlock(device); + V0(device->Backend,unlock)(); hr = IAudioRenderClient_ReleaseBuffer(self->render, len, 0); } if(FAILED(hr)) { ERR("Failed to buffer data: 0x%08lx\n", hr); - ALCdevice_Lock(device); + V0(device->Backend,lock)(); aluHandleDisconnect(device); - ALCdevice_Unlock(device); + V0(device->Backend,unlock)(); break; } } @@ -599,7 +677,7 @@ static ALCenum ALCmmdevPlayback_open(ALCmmdevPlayback *self, const ALCchar *devi { if(deviceName) { - const DevMap *iter, *end; + const DevMap *iter; if(VECTOR_SIZE(PlaybackDevices) == 0) { @@ -609,19 +687,18 @@ static ALCenum ALCmmdevPlayback_open(ALCmmdevPlayback *self, const ALCchar *devi } hr = E_FAIL; - iter = VECTOR_ITER_BEGIN(PlaybackDevices); - end = VECTOR_ITER_END(PlaybackDevices); - for(;iter != end;iter++) - { - if(al_string_cmp_cstr(iter->name, deviceName) == 0) - { - self->devid = strdupW(iter->devid); - hr = S_OK; - break; - } - } - if(FAILED(hr)) +#define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, deviceName) == 0) + VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME); + if(iter == VECTOR_ITER_END(PlaybackDevices)) WARN("Failed to find device name matching \"%s\"\n", deviceName); + else + { + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + self->devid = strdupW(iter->devid); + al_string_copy(&device->DeviceName, iter->name); + hr = S_OK; + } +#undef MATCH_NAME } } @@ -677,7 +754,11 @@ static HRESULT ALCmmdevPlayback_openProxy(ALCmmdevPlayback *self) if(SUCCEEDED(hr)) { self->client = ptr; - get_device_name(self->mmdev, &device->DeviceName); + if(al_string_empty(device->DeviceName)) + { + get_device_name(self->mmdev, &device->DeviceName); + al_string_append_cstr(&device->DeviceName, DEVNAME_TAIL); + } } if(FAILED(hr)) @@ -734,6 +815,7 @@ static ALCboolean ALCmmdevPlayback_reset(ALCmmdevPlayback *self) static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + EndpointFormFactor formfactor = UnknownFormFactor; WAVEFORMATEXTENSIBLE OutputType; WAVEFORMATEX *wfx = NULL; REFERENCE_TIME min_per, buf_time; @@ -783,11 +865,11 @@ static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self) device->FmtChans = DevFmtQuad; else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1) device->FmtChans = DevFmtX51; - else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1SIDE) - device->FmtChans = DevFmtX51Side; + else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1REAR) + device->FmtChans = DevFmtX51Rear; else if(OutputType.Format.nChannels == 7 && OutputType.dwChannelMask == X6DOT1) device->FmtChans = DevFmtX61; - else if(OutputType.Format.nChannels == 8 && OutputType.dwChannelMask == X7DOT1) + else if(OutputType.Format.nChannels == 8 && (OutputType.dwChannelMask == X7DOT1 || OutputType.dwChannelMask == X7DOT1_WIDE)) device->FmtChans = DevFmtX71; else ERR("Unhandled channel config: %d -- 0x%08lx\n", OutputType.Format.nChannels, OutputType.dwChannelMask); @@ -799,6 +881,9 @@ static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self) OutputType.Format.nChannels = 1; OutputType.dwChannelMask = MONO; break; + case DevFmtBFormat3D: + device->FmtChans = DevFmtStereo; + /*fall-through*/ case DevFmtStereo: OutputType.Format.nChannels = 2; OutputType.dwChannelMask = STEREO; @@ -811,9 +896,9 @@ static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self) OutputType.Format.nChannels = 6; OutputType.dwChannelMask = X5DOT1; break; - case DevFmtX51Side: + case DevFmtX51Rear: OutputType.Format.nChannels = 6; - OutputType.dwChannelMask = X5DOT1SIDE; + OutputType.dwChannelMask = X5DOT1REAR; break; case DevFmtX61: OutputType.Format.nChannels = 7; @@ -894,11 +979,11 @@ static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self) device->FmtChans = DevFmtQuad; else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1) device->FmtChans = DevFmtX51; - else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1SIDE) - device->FmtChans = DevFmtX51Side; + else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1REAR) + device->FmtChans = DevFmtX51Rear; else if(OutputType.Format.nChannels == 7 && OutputType.dwChannelMask == X6DOT1) device->FmtChans = DevFmtX61; - else if(OutputType.Format.nChannels == 8 && OutputType.dwChannelMask == X7DOT1) + else if(OutputType.Format.nChannels == 8 && (OutputType.dwChannelMask == X7DOT1 || OutputType.dwChannelMask == X7DOT1_WIDE)) device->FmtChans = DevFmtX71; else { @@ -936,6 +1021,8 @@ static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self) } OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample; } + get_device_formfactor(self->mmdev, &formfactor); + device->IsHeadphones = (device->FmtChans == DevFmtStereo && formfactor == Headphones); SetDefaultWFXChannelOrder(device); @@ -1055,6 +1142,575 @@ static ALint64 ALCmmdevPlayback_getLatency(ALCmmdevPlayback *self) } +typedef struct ALCmmdevCapture { + DERIVE_FROM_TYPE(ALCbackend); + DERIVE_FROM_TYPE(ALCmmdevProxy); + + WCHAR *devid; + + IMMDevice *mmdev; + IAudioClient *client; + IAudioCaptureClient *capture; + HANDLE NotifyEvent; + + HANDLE MsgEvent; + + ll_ringbuffer_t *Ring; + + volatile int killNow; + althrd_t thread; +} ALCmmdevCapture; + +static int ALCmmdevCapture_recordProc(void *arg); + +static void ALCmmdevCapture_Construct(ALCmmdevCapture *self, ALCdevice *device); +static void ALCmmdevCapture_Destruct(ALCmmdevCapture *self); +static ALCenum ALCmmdevCapture_open(ALCmmdevCapture *self, const ALCchar *name); +static HRESULT ALCmmdevCapture_openProxy(ALCmmdevCapture *self); +static void ALCmmdevCapture_close(ALCmmdevCapture *self); +static void ALCmmdevCapture_closeProxy(ALCmmdevCapture *self); +static DECLARE_FORWARD(ALCmmdevCapture, ALCbackend, ALCboolean, reset) +static HRESULT ALCmmdevCapture_resetProxy(ALCmmdevCapture *self); +static ALCboolean ALCmmdevCapture_start(ALCmmdevCapture *self); +static HRESULT ALCmmdevCapture_startProxy(ALCmmdevCapture *self); +static void ALCmmdevCapture_stop(ALCmmdevCapture *self); +static void ALCmmdevCapture_stopProxy(ALCmmdevCapture *self); +static ALCenum ALCmmdevCapture_captureSamples(ALCmmdevCapture *self, ALCvoid *buffer, ALCuint samples); +static ALuint ALCmmdevCapture_availableSamples(ALCmmdevCapture *self); +static DECLARE_FORWARD(ALCmmdevCapture, ALCbackend, ALint64, getLatency) +static DECLARE_FORWARD(ALCmmdevCapture, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCmmdevCapture, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCmmdevCapture) + +DEFINE_ALCMMDEVPROXY_VTABLE(ALCmmdevCapture); +DEFINE_ALCBACKEND_VTABLE(ALCmmdevCapture); + + +static void ALCmmdevCapture_Construct(ALCmmdevCapture *self, ALCdevice *device) +{ + SET_VTABLE2(ALCmmdevCapture, ALCbackend, self); + SET_VTABLE2(ALCmmdevCapture, ALCmmdevProxy, self); + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + ALCmmdevProxy_Construct(STATIC_CAST(ALCmmdevProxy, self)); + + self->devid = NULL; + + self->mmdev = NULL; + self->client = NULL; + self->capture = NULL; + self->NotifyEvent = NULL; + + self->MsgEvent = NULL; + + self->Ring = NULL; + + self->killNow = 0; +} + +static void ALCmmdevCapture_Destruct(ALCmmdevCapture *self) +{ + ll_ringbuffer_free(self->Ring); + self->Ring = NULL; + + if(self->NotifyEvent != NULL) + CloseHandle(self->NotifyEvent); + self->NotifyEvent = NULL; + if(self->MsgEvent != NULL) + CloseHandle(self->MsgEvent); + self->MsgEvent = NULL; + + free(self->devid); + self->devid = NULL; + + ALCmmdevProxy_Destruct(STATIC_CAST(ALCmmdevProxy, self)); + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); +} + + +FORCE_ALIGN int ALCmmdevCapture_recordProc(void *arg) +{ + ALCmmdevCapture *self = arg; + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + HRESULT hr; + + hr = CoInitialize(NULL); + if(FAILED(hr)) + { + ERR("CoInitialize(NULL) failed: 0x%08lx\n", hr); + V0(device->Backend,lock)(); + aluHandleDisconnect(device); + V0(device->Backend,unlock)(); + return 1; + } + + althrd_setname(althrd_current(), RECORD_THREAD_NAME); + + while(!self->killNow) + { + UINT32 avail; + DWORD res; + + hr = IAudioCaptureClient_GetNextPacketSize(self->capture, &avail); + if(FAILED(hr)) + ERR("Failed to get next packet size: 0x%08lx\n", hr); + else while(avail > 0 && SUCCEEDED(hr)) + { + UINT32 numsamples; + DWORD flags; + BYTE *data; + + hr = IAudioCaptureClient_GetBuffer(self->capture, + &data, &numsamples, &flags, NULL, NULL + ); + if(FAILED(hr)) + { + ERR("Failed to get capture buffer: 0x%08lx\n", hr); + break; + } + + ll_ringbuffer_write(self->Ring, (char*)data, numsamples); + + hr = IAudioCaptureClient_ReleaseBuffer(self->capture, numsamples); + if(FAILED(hr)) + { + ERR("Failed to release capture buffer: 0x%08lx\n", hr); + break; + } + + hr = IAudioCaptureClient_GetNextPacketSize(self->capture, &avail); + if(FAILED(hr)) + ERR("Failed to get next packet size: 0x%08lx\n", hr); + } + + if(FAILED(hr)) + { + V0(device->Backend,lock)(); + aluHandleDisconnect(device); + V0(device->Backend,unlock)(); + break; + } + + res = WaitForSingleObjectEx(self->NotifyEvent, 2000, FALSE); + if(res != WAIT_OBJECT_0) + ERR("WaitForSingleObjectEx error: 0x%lx\n", res); + } + + CoUninitialize(); + return 0; +} + + +static ALCenum ALCmmdevCapture_open(ALCmmdevCapture *self, const ALCchar *deviceName) +{ + HRESULT hr = S_OK; + + self->NotifyEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + self->MsgEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + if(self->NotifyEvent == NULL || self->MsgEvent == NULL) + { + ERR("Failed to create message events: %lu\n", GetLastError()); + hr = E_FAIL; + } + + if(SUCCEEDED(hr)) + { + if(deviceName) + { + const DevMap *iter; + + if(VECTOR_SIZE(CaptureDevices) == 0) + { + ThreadRequest req = { self->MsgEvent, 0 }; + if(PostThreadMessage(ThreadID, WM_USER_Enumerate, (WPARAM)&req, CAPTURE_DEVICE_PROBE)) + (void)WaitForResponse(&req); + } + + hr = E_FAIL; +#define MATCH_NAME(i) (al_string_cmp_cstr((i)->name, deviceName) == 0) + VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME); + if(iter == VECTOR_ITER_END(CaptureDevices)) + WARN("Failed to find device name matching \"%s\"\n", deviceName); + else + { + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + self->devid = strdupW(iter->devid); + al_string_copy(&device->DeviceName, iter->name); + hr = S_OK; + } +#undef MATCH_NAME + } + } + + if(SUCCEEDED(hr)) + { + ThreadRequest req = { self->MsgEvent, 0 }; + + hr = E_FAIL; + if(PostThreadMessage(ThreadID, WM_USER_OpenDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self))) + hr = WaitForResponse(&req); + else + ERR("Failed to post thread message: %lu\n", GetLastError()); + } + + if(FAILED(hr)) + { + if(self->NotifyEvent != NULL) + CloseHandle(self->NotifyEvent); + self->NotifyEvent = NULL; + if(self->MsgEvent != NULL) + CloseHandle(self->MsgEvent); + self->MsgEvent = NULL; + + free(self->devid); + self->devid = NULL; + + ERR("Device init failed: 0x%08lx\n", hr); + return ALC_INVALID_VALUE; + } + else + { + ThreadRequest req = { self->MsgEvent, 0 }; + + hr = E_FAIL; + if(PostThreadMessage(ThreadID, WM_USER_ResetDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self))) + hr = WaitForResponse(&req); + else + ERR("Failed to post thread message: %lu\n", GetLastError()); + + if(FAILED(hr)) + { + ALCmmdevCapture_close(self); + if(hr == E_OUTOFMEMORY) + return ALC_OUT_OF_MEMORY; + return ALC_INVALID_VALUE; + } + } + + return ALC_NO_ERROR; +} + +static HRESULT ALCmmdevCapture_openProxy(ALCmmdevCapture *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + void *ptr; + HRESULT hr; + + hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr); + if(SUCCEEDED(hr)) + { + IMMDeviceEnumerator *Enumerator = ptr; + if(!self->devid) + hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(Enumerator, eCapture, eMultimedia, &self->mmdev); + else + hr = IMMDeviceEnumerator_GetDevice(Enumerator, self->devid, &self->mmdev); + IMMDeviceEnumerator_Release(Enumerator); + Enumerator = NULL; + } + if(SUCCEEDED(hr)) + hr = IMMDevice_Activate(self->mmdev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, &ptr); + if(SUCCEEDED(hr)) + { + self->client = ptr; + if(al_string_empty(device->DeviceName)) + { + get_device_name(self->mmdev, &device->DeviceName); + al_string_append_cstr(&device->DeviceName, DEVNAME_TAIL); + } + } + + if(FAILED(hr)) + { + if(self->mmdev) + IMMDevice_Release(self->mmdev); + self->mmdev = NULL; + } + + return hr; +} + + +static void ALCmmdevCapture_close(ALCmmdevCapture *self) +{ + ThreadRequest req = { self->MsgEvent, 0 }; + + if(PostThreadMessage(ThreadID, WM_USER_CloseDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self))) + (void)WaitForResponse(&req); + + ll_ringbuffer_free(self->Ring); + self->Ring = NULL; + + CloseHandle(self->MsgEvent); + self->MsgEvent = NULL; + + CloseHandle(self->NotifyEvent); + self->NotifyEvent = NULL; + + free(self->devid); + self->devid = NULL; +} + +static void ALCmmdevCapture_closeProxy(ALCmmdevCapture *self) +{ + if(self->client) + IAudioClient_Release(self->client); + self->client = NULL; + + if(self->mmdev) + IMMDevice_Release(self->mmdev); + self->mmdev = NULL; +} + + +static HRESULT ALCmmdevCapture_resetProxy(ALCmmdevCapture *self) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + WAVEFORMATEXTENSIBLE OutputType; + WAVEFORMATEX *wfx = NULL; + REFERENCE_TIME buf_time; + UINT32 buffer_len; + void *ptr = NULL; + HRESULT hr; + + if(self->client) + IAudioClient_Release(self->client); + self->client = NULL; + + hr = IMMDevice_Activate(self->mmdev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, &ptr); + if(FAILED(hr)) + { + ERR("Failed to reactivate audio client: 0x%08lx\n", hr); + return hr; + } + self->client = ptr; + + buf_time = ((REFERENCE_TIME)device->UpdateSize*device->NumUpdates*10000000 + + device->Frequency-1) / device->Frequency; + + OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + switch(device->FmtChans) + { + case DevFmtMono: + OutputType.Format.nChannels = 1; + OutputType.dwChannelMask = MONO; + break; + case DevFmtStereo: + OutputType.Format.nChannels = 2; + OutputType.dwChannelMask = STEREO; + break; + case DevFmtQuad: + OutputType.Format.nChannels = 4; + OutputType.dwChannelMask = QUAD; + break; + case DevFmtX51: + OutputType.Format.nChannels = 6; + OutputType.dwChannelMask = X5DOT1; + break; + case DevFmtX51Rear: + OutputType.Format.nChannels = 6; + OutputType.dwChannelMask = X5DOT1REAR; + break; + case DevFmtX61: + OutputType.Format.nChannels = 7; + OutputType.dwChannelMask = X6DOT1; + break; + case DevFmtX71: + OutputType.Format.nChannels = 8; + OutputType.dwChannelMask = X7DOT1; + break; + + case DevFmtBFormat3D: + return E_FAIL; + } + switch(device->FmtType) + { + case DevFmtUByte: + OutputType.Format.wBitsPerSample = 8; + OutputType.Samples.wValidBitsPerSample = 8; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + break; + case DevFmtShort: + OutputType.Format.wBitsPerSample = 16; + OutputType.Samples.wValidBitsPerSample = 16; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + break; + case DevFmtInt: + OutputType.Format.wBitsPerSample = 32; + OutputType.Samples.wValidBitsPerSample = 32; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + break; + case DevFmtFloat: + OutputType.Format.wBitsPerSample = 32; + OutputType.Samples.wValidBitsPerSample = 32; + OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + break; + + case DevFmtByte: + case DevFmtUShort: + case DevFmtUInt: + WARN("%s capture samples not supported\n", DevFmtTypeString(device->FmtType)); + return E_FAIL; + } + OutputType.Format.nSamplesPerSec = device->Frequency; + + OutputType.Format.nBlockAlign = OutputType.Format.nChannels * + OutputType.Format.wBitsPerSample / 8; + OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec * + OutputType.Format.nBlockAlign; + OutputType.Format.cbSize = sizeof(OutputType) - sizeof(OutputType.Format); + + hr = IAudioClient_IsFormatSupported(self->client, + AUDCLNT_SHAREMODE_SHARED, &OutputType.Format, &wfx + ); + if(FAILED(hr)) + { + ERR("Failed to check format support: 0x%08lx\n", hr); + return hr; + } + + /* FIXME: We should do conversion/resampling if we didn't get a matching format. */ + if(wfx->nSamplesPerSec != OutputType.Format.nSamplesPerSec || + wfx->wBitsPerSample != OutputType.Format.wBitsPerSample || + wfx->nChannels != OutputType.Format.nChannels || + wfx->nBlockAlign != OutputType.Format.nBlockAlign) + { + ERR("Did not get matching format, wanted: %s %s %uhz, got: %d channel(s) %d-bit %luhz\n", + DevFmtChannelsString(device->FmtChans), DevFmtTypeString(device->FmtType), device->Frequency, + wfx->nChannels, wfx->wBitsPerSample, wfx->nSamplesPerSec); + CoTaskMemFree(wfx); + return E_FAIL; + } + + if(!MakeExtensible(&OutputType, wfx)) + { + CoTaskMemFree(wfx); + return E_FAIL; + } + CoTaskMemFree(wfx); + wfx = NULL; + + hr = IAudioClient_Initialize(self->client, + AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, + buf_time, 0, &OutputType.Format, NULL + ); + if(FAILED(hr)) + { + ERR("Failed to initialize audio client: 0x%08lx\n", hr); + return hr; + } + + hr = IAudioClient_GetBufferSize(self->client, &buffer_len); + if(FAILED(hr)) + { + ERR("Failed to get buffer size: 0x%08lx\n", hr); + return hr; + } + + buffer_len = maxu(device->UpdateSize*device->NumUpdates + 1, buffer_len); + ll_ringbuffer_free(self->Ring); + self->Ring = ll_ringbuffer_create(buffer_len, OutputType.Format.nBlockAlign); + if(!self->Ring) + { + ERR("Failed to allocate capture ring buffer\n"); + return E_OUTOFMEMORY; + } + + hr = IAudioClient_SetEventHandle(self->client, self->NotifyEvent); + if(FAILED(hr)) + { + ERR("Failed to set event handle: 0x%08lx\n", hr); + return hr; + } + + return hr; +} + + +static ALCboolean ALCmmdevCapture_start(ALCmmdevCapture *self) +{ + ThreadRequest req = { self->MsgEvent, 0 }; + HRESULT hr = E_FAIL; + + if(PostThreadMessage(ThreadID, WM_USER_StartDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self))) + hr = WaitForResponse(&req); + + return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE; +} + +static HRESULT ALCmmdevCapture_startProxy(ALCmmdevCapture *self) +{ + HRESULT hr; + void *ptr; + + ResetEvent(self->NotifyEvent); + hr = IAudioClient_Start(self->client); + if(FAILED(hr)) + { + ERR("Failed to start audio client: 0x%08lx\n", hr); + return hr; + } + + hr = IAudioClient_GetService(self->client, &IID_IAudioCaptureClient, &ptr); + if(SUCCEEDED(hr)) + { + self->capture = ptr; + self->killNow = 0; + if(althrd_create(&self->thread, ALCmmdevCapture_recordProc, self) != althrd_success) + { + ERR("Failed to start thread\n"); + IAudioCaptureClient_Release(self->capture); + self->capture = NULL; + hr = E_FAIL; + } + } + + if(FAILED(hr)) + { + IAudioClient_Stop(self->client); + IAudioClient_Reset(self->client); + } + + return hr; +} + + +static void ALCmmdevCapture_stop(ALCmmdevCapture *self) +{ + ThreadRequest req = { self->MsgEvent, 0 }; + if(PostThreadMessage(ThreadID, WM_USER_StopDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self))) + (void)WaitForResponse(&req); +} + +static void ALCmmdevCapture_stopProxy(ALCmmdevCapture *self) +{ + int res; + + if(!self->capture) + return; + + self->killNow = 1; + althrd_join(self->thread, &res); + + IAudioCaptureClient_Release(self->capture); + self->capture = NULL; + IAudioClient_Stop(self->client); + IAudioClient_Reset(self->client); +} + + +ALuint ALCmmdevCapture_availableSamples(ALCmmdevCapture *self) +{ + return (ALuint)ll_ringbuffer_read_space(self->Ring); +} + +ALCenum ALCmmdevCapture_captureSamples(ALCmmdevCapture *self, ALCvoid *buffer, ALCuint samples) +{ + if(ALCmmdevCapture_availableSamples(self) < samples) + return ALC_INVALID_VALUE; + ll_ringbuffer_read(self->Ring, buffer, samples); + return ALC_NO_ERROR; +} + + static inline void AppendAllDevicesList2(const DevMap *entry) { AppendAllDevicesList(al_string_get_cstr(entry->name)); } static inline void AppendCaptureDeviceList2(const DevMap *entry) @@ -1125,7 +1781,12 @@ static void ALCmmdevBackendFactory_deinit(ALCmmdevBackendFactory* UNUSED(self)) static ALCboolean ALCmmdevBackendFactory_querySupport(ALCmmdevBackendFactory* UNUSED(self), ALCbackend_Type type) { - if(type == ALCbackend_Playback) + /* TODO: Disable capture with mmdevapi for now, since it doesn't do any + * rechanneling or resampling; if the device is configured for 48000hz + * stereo input, for example, and the app asks for 22050hz mono, + * initialization will fail. + */ + if(type == ALCbackend_Playback /*|| type == ALCbackend_Capture*/) return ALC_TRUE; return ALC_FALSE; } @@ -1162,13 +1823,15 @@ static ALCbackend* ALCmmdevBackendFactory_createBackend(ALCmmdevBackendFactory* if(type == ALCbackend_Playback) { ALCmmdevPlayback *backend; - - backend = ALCmmdevPlayback_New(sizeof(*backend)); + NEW_OBJ(backend, ALCmmdevPlayback)(device); + if(!backend) return NULL; + return STATIC_CAST(ALCbackend, backend); + } + if(type == ALCbackend_Capture) + { + ALCmmdevCapture *backend; + NEW_OBJ(backend, ALCmmdevCapture)(device); if(!backend) return NULL; - memset(backend, 0, sizeof(*backend)); - - ALCmmdevPlayback_Construct(backend, device); - return STATIC_CAST(ALCbackend, backend); } diff --git a/libs/openal-soft/Alc/backends/null.c b/libs/openal-soft/Alc/backends/null.c index 3f09c5d6..99729c0a 100644 --- a/libs/openal-soft/Alc/backends/null.c +++ b/libs/openal-soft/Alc/backends/null.c @@ -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 */ @@ -106,7 +106,7 @@ static int ALCnullBackend_mixerProc(void *ptr) } if(avail-done < device->UpdateSize) - al_nssleep(0, restTime); + al_nssleep(restTime); else while(avail-done >= device->UpdateSize) { aluMixData(device, NULL, device->UpdateSize); @@ -214,13 +214,8 @@ static ALCbackend* ALCnullBackendFactory_createBackend(ALCnullBackendFactory* UN if(type == ALCbackend_Playback) { ALCnullBackend *backend; - - backend = ALCnullBackend_New(sizeof(*backend)); + NEW_OBJ(backend, ALCnullBackend)(device); if(!backend) return NULL; - memset(backend, 0, sizeof(*backend)); - - ALCnullBackend_Construct(backend, device); - return STATIC_CAST(ALCbackend, backend); } diff --git a/libs/openal-soft/Alc/backends/opensl.c b/libs/openal-soft/Alc/backends/opensl.c index 220e6e5c..7b8fdb25 100644 --- a/libs/openal-soft/Alc/backends/opensl.c +++ b/libs/openal-soft/Alc/backends/opensl.c @@ -25,7 +25,7 @@ #include "alMain.h" #include "alu.h" - +#include "threads.h" #include #include @@ -67,7 +67,10 @@ static SLuint32 GetChannelMask(enum DevFmtChannels chans) SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT; case DevFmtX51: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| - SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT; + SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT; + case DevFmtX51Rear: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| + SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| + SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT; case DevFmtX61: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| SL_SPEAKER_BACK_CENTER| @@ -76,9 +79,7 @@ static SLuint32 GetChannelMask(enum DevFmtChannels chans) SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT| SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT; - case DevFmtX51Side: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| - SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| - SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT; + case DevFmtBFormat3D: break; } return 0; } @@ -378,6 +379,15 @@ static void opensl_stop_playback(ALCdevice *Device) result = VCALL0(bufferQueue,Clear)(); PRINTERR(result, "bufferQueue->Clear"); } + if(SL_RESULT_SUCCESS == result) + { + SLAndroidSimpleBufferQueueState state; + do { + althrd_yield(); + result = VCALL(bufferQueue,GetState)(&state); + } while(SL_RESULT_SUCCESS == result && state.count > 0); + PRINTERR(result, "bufferQueue->GetState"); + } free(data->buffer); data->buffer = NULL; @@ -396,8 +406,7 @@ static const BackendFuncs opensl_funcs = { NULL, NULL, NULL, - NULL, - ALCdevice_GetLatencyDefault + NULL }; diff --git a/libs/openal-soft/Alc/backends/oss.c b/libs/openal-soft/Alc/backends/oss.c index 93e026e9..dce42e21 100644 --- a/libs/openal-soft/Alc/backends/oss.c +++ b/libs/openal-soft/Alc/backends/oss.c @@ -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 */ @@ -131,7 +131,7 @@ static int ALCplaybackOSS_mixerProc(void *ptr) break; } - al_nssleep(0, 1000000); + al_nssleep(1000000); continue; } @@ -345,7 +345,7 @@ static int ALCcaptureOSS_recordProc(void *ptr) int amt; SetRTPriority(); - althrd_setname(althrd_current(), "alsoft-record"); + althrd_setname(althrd_current(), RECORD_THREAD_NAME); frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); @@ -362,7 +362,7 @@ static int ALCcaptureOSS_recordProc(void *ptr) } if(amt == 0) { - al_nssleep(0, 1000000); + al_nssleep(1000000); continue; } if(self->doCapture) @@ -562,8 +562,8 @@ ALCbackendFactory *ALCossBackendFactory_getFactory(void) ALCboolean ALCossBackendFactory_init(ALCossBackendFactory* UNUSED(self)) { - ConfigValueStr("oss", "device", &oss_driver); - ConfigValueStr("oss", "capture", &oss_capture); + ConfigValueStr(NULL, "oss", "device", &oss_driver); + ConfigValueStr(NULL, "oss", "capture", &oss_capture); return ALC_TRUE; } @@ -606,25 +606,15 @@ ALCbackend* ALCossBackendFactory_createBackend(ALCossBackendFactory* UNUSED(self if(type == ALCbackend_Playback) { ALCplaybackOSS *backend; - - backend = ALCplaybackOSS_New(sizeof(*backend)); + NEW_OBJ(backend, ALCplaybackOSS)(device); if(!backend) return NULL; - memset(backend, 0, sizeof(*backend)); - - ALCplaybackOSS_Construct(backend, device); - return STATIC_CAST(ALCbackend, backend); } if(type == ALCbackend_Capture) { ALCcaptureOSS *backend; - - backend = ALCcaptureOSS_New(sizeof(*backend)); + NEW_OBJ(backend, ALCcaptureOSS)(device); if(!backend) return NULL; - memset(backend, 0, sizeof(*backend)); - - ALCcaptureOSS_Construct(backend, device); - return STATIC_CAST(ALCbackend, backend); } diff --git a/libs/openal-soft/Alc/backends/portaudio.c b/libs/openal-soft/Alc/backends/portaudio.c index 5f11526d..f45833c6 100644 --- a/libs/openal-soft/Alc/backends/portaudio.c +++ b/libs/openal-soft/Alc/backends/portaudio.c @@ -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 */ @@ -28,6 +28,8 @@ #include "alu.h" #include "compat.h" +#include "backends/base.h" + #include @@ -122,149 +124,171 @@ static ALCboolean pa_load(void) } -typedef struct { +typedef struct ALCportPlayback { + DERIVE_FROM_TYPE(ALCbackend); + PaStream *stream; PaStreamParameters params; ALuint update_size; +} ALCportPlayback; - RingBuffer *ring; -} pa_data; +static int ALCportPlayback_WriteCallback(const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, + const PaStreamCallbackFlags statusFlags, void *userData); + +static void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device); +static void ALCportPlayback_Destruct(ALCportPlayback *self); +static ALCenum ALCportPlayback_open(ALCportPlayback *self, const ALCchar *name); +static void ALCportPlayback_close(ALCportPlayback *self); +static ALCboolean ALCportPlayback_reset(ALCportPlayback *self); +static ALCboolean ALCportPlayback_start(ALCportPlayback *self); +static void ALCportPlayback_stop(ALCportPlayback *self); +static DECLARE_FORWARD2(ALCportPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) +static DECLARE_FORWARD(ALCportPlayback, ALCbackend, ALCuint, availableSamples) +static DECLARE_FORWARD(ALCportPlayback, ALCbackend, ALint64, getLatency) +static DECLARE_FORWARD(ALCportPlayback, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCportPlayback, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCportPlayback) + +DEFINE_ALCBACKEND_VTABLE(ALCportPlayback); -static int pa_callback(const void *UNUSED(inputBuffer), void *outputBuffer, - unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo), - const PaStreamCallbackFlags UNUSED(statusFlags), void *userData) +static void ALCportPlayback_Construct(ALCportPlayback *self, ALCdevice *device) { - ALCdevice *device = (ALCdevice*)userData; + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCportPlayback, ALCbackend, self); - aluMixData(device, outputBuffer, framesPerBuffer); - return 0; + self->stream = NULL; } -static int pa_capture_cb(const void *inputBuffer, void *UNUSED(outputBuffer), - unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo), - const PaStreamCallbackFlags UNUSED(statusFlags), void *userData) +static void ALCportPlayback_Destruct(ALCportPlayback *self) { - ALCdevice *device = (ALCdevice*)userData; - pa_data *data = (pa_data*)device->ExtraData; + if(self->stream) + Pa_CloseStream(self->stream); + self->stream = NULL; - WriteRingBuffer(data->ring, inputBuffer, framesPerBuffer); + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); +} + + +static int ALCportPlayback_WriteCallback(const void *UNUSED(inputBuffer), void *outputBuffer, + unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo), + const PaStreamCallbackFlags UNUSED(statusFlags), void *userData) +{ + ALCportPlayback *self = userData; + + aluMixData(STATIC_CAST(ALCbackend, self)->mDevice, outputBuffer, framesPerBuffer); return 0; } -static ALCenum pa_open_playback(ALCdevice *device, const ALCchar *deviceName) +static ALCenum ALCportPlayback_open(ALCportPlayback *self, const ALCchar *name) { - pa_data *data; + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; PaError err; - if(!deviceName) - deviceName = pa_device; - else if(strcmp(deviceName, pa_device) != 0) + if(!name) + name = pa_device; + else if(strcmp(name, pa_device) != 0) return ALC_INVALID_VALUE; - data = (pa_data*)calloc(1, sizeof(pa_data)); - data->update_size = device->UpdateSize; + self->update_size = device->UpdateSize; - data->params.device = -1; - if(!ConfigValueInt("port", "device", &data->params.device) || - data->params.device < 0) - data->params.device = Pa_GetDefaultOutputDevice(); - data->params.suggestedLatency = (device->UpdateSize*device->NumUpdates) / + self->params.device = -1; + if(!ConfigValueInt(NULL, "port", "device", &self->params.device) || + self->params.device < 0) + self->params.device = Pa_GetDefaultOutputDevice(); + self->params.suggestedLatency = (device->UpdateSize*device->NumUpdates) / (float)device->Frequency; - data->params.hostApiSpecificStreamInfo = NULL; + self->params.hostApiSpecificStreamInfo = NULL; - data->params.channelCount = ((device->FmtChans == DevFmtMono) ? 1 : 2); + self->params.channelCount = ((device->FmtChans == DevFmtMono) ? 1 : 2); switch(device->FmtType) { case DevFmtByte: - data->params.sampleFormat = paInt8; + self->params.sampleFormat = paInt8; break; case DevFmtUByte: - data->params.sampleFormat = paUInt8; + self->params.sampleFormat = paUInt8; break; case DevFmtUShort: /* fall-through */ case DevFmtShort: - data->params.sampleFormat = paInt16; + self->params.sampleFormat = paInt16; break; case DevFmtUInt: /* fall-through */ case DevFmtInt: - data->params.sampleFormat = paInt32; + self->params.sampleFormat = paInt32; break; case DevFmtFloat: - data->params.sampleFormat = paFloat32; + self->params.sampleFormat = paFloat32; break; } retry_open: - err = Pa_OpenStream(&data->stream, NULL, &data->params, device->Frequency, - device->UpdateSize, paNoFlag, pa_callback, device); + err = Pa_OpenStream(&self->stream, NULL, &self->params, + device->Frequency, device->UpdateSize, paNoFlag, + ALCportPlayback_WriteCallback, self + ); if(err != paNoError) { - if(data->params.sampleFormat == paFloat32) + if(self->params.sampleFormat == paFloat32) { - data->params.sampleFormat = paInt16; + self->params.sampleFormat = paInt16; goto retry_open; } ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err)); - free(data); return ALC_INVALID_VALUE; } - device->ExtraData = data; - al_string_copy_cstr(&device->DeviceName, deviceName); + al_string_copy_cstr(&device->DeviceName, name); return ALC_NO_ERROR; + } -static void pa_close_playback(ALCdevice *device) +static void ALCportPlayback_close(ALCportPlayback *self) { - pa_data *data = (pa_data*)device->ExtraData; - PaError err; - - err = Pa_CloseStream(data->stream); + PaError err = Pa_CloseStream(self->stream); if(err != paNoError) ERR("Error closing stream: %s\n", Pa_GetErrorText(err)); - - free(data); - device->ExtraData = NULL; + self->stream = NULL; } -static ALCboolean pa_reset_playback(ALCdevice *device) +static ALCboolean ALCportPlayback_reset(ALCportPlayback *self) { - pa_data *data = (pa_data*)device->ExtraData; + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; const PaStreamInfo *streamInfo; - streamInfo = Pa_GetStreamInfo(data->stream); + streamInfo = Pa_GetStreamInfo(self->stream); device->Frequency = streamInfo->sampleRate; - device->UpdateSize = data->update_size; + device->UpdateSize = self->update_size; - if(data->params.sampleFormat == paInt8) + if(self->params.sampleFormat == paInt8) device->FmtType = DevFmtByte; - else if(data->params.sampleFormat == paUInt8) + else if(self->params.sampleFormat == paUInt8) device->FmtType = DevFmtUByte; - else if(data->params.sampleFormat == paInt16) + else if(self->params.sampleFormat == paInt16) device->FmtType = DevFmtShort; - else if(data->params.sampleFormat == paInt32) + else if(self->params.sampleFormat == paInt32) device->FmtType = DevFmtInt; - else if(data->params.sampleFormat == paFloat32) + else if(self->params.sampleFormat == paFloat32) device->FmtType = DevFmtFloat; else { - ERR("Unexpected sample format: 0x%lx\n", data->params.sampleFormat); + ERR("Unexpected sample format: 0x%lx\n", self->params.sampleFormat); return ALC_FALSE; } - if(data->params.channelCount == 2) + if(self->params.channelCount == 2) device->FmtChans = DevFmtStereo; - else if(data->params.channelCount == 1) + else if(self->params.channelCount == 1) device->FmtChans = DevFmtMono; else { - ERR("Unexpected channel count: %u\n", data->params.channelCount); + ERR("Unexpected channel count: %u\n", self->params.channelCount); return ALC_FALSE; } SetDefaultChannelOrder(device); @@ -272,12 +296,11 @@ static ALCboolean pa_reset_playback(ALCdevice *device) return ALC_TRUE; } -static ALCboolean pa_start_playback(ALCdevice *device) +static ALCboolean ALCportPlayback_start(ALCportPlayback *self) { - pa_data *data = (pa_data*)device->ExtraData; PaError err; - err = Pa_StartStream(data->stream); + err = Pa_StartStream(self->stream); if(err != paNoError) { ERR("Pa_StartStream() returned an error: %s\n", Pa_GetErrorText(err)); @@ -287,161 +310,209 @@ static ALCboolean pa_start_playback(ALCdevice *device) return ALC_TRUE; } -static void pa_stop_playback(ALCdevice *device) +static void ALCportPlayback_stop(ALCportPlayback *self) { - pa_data *data = (pa_data*)device->ExtraData; - PaError err; - - err = Pa_StopStream(data->stream); + PaError err = Pa_StopStream(self->stream); if(err != paNoError) ERR("Error stopping stream: %s\n", Pa_GetErrorText(err)); } -static ALCenum pa_open_capture(ALCdevice *device, const ALCchar *deviceName) +typedef struct ALCportCapture { + DERIVE_FROM_TYPE(ALCbackend); + + PaStream *stream; + PaStreamParameters params; + + ll_ringbuffer_t *ring; +} ALCportCapture; + +static int ALCportCapture_ReadCallback(const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *timeInfo, + const PaStreamCallbackFlags statusFlags, void *userData); + +static void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device); +static void ALCportCapture_Destruct(ALCportCapture *self); +static ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name); +static void ALCportCapture_close(ALCportCapture *self); +static DECLARE_FORWARD(ALCportCapture, ALCbackend, ALCboolean, reset) +static ALCboolean ALCportCapture_start(ALCportCapture *self); +static void ALCportCapture_stop(ALCportCapture *self); +static ALCenum ALCportCapture_captureSamples(ALCportCapture *self, ALCvoid *buffer, ALCuint samples); +static ALCuint ALCportCapture_availableSamples(ALCportCapture *self); +static DECLARE_FORWARD(ALCportCapture, ALCbackend, ALint64, getLatency) +static DECLARE_FORWARD(ALCportCapture, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCportCapture, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCportCapture) + +DEFINE_ALCBACKEND_VTABLE(ALCportCapture); + + +static void ALCportCapture_Construct(ALCportCapture *self, ALCdevice *device) { - ALuint frame_size; - pa_data *data; + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCportCapture, ALCbackend, self); + + self->stream = NULL; +} + +static void ALCportCapture_Destruct(ALCportCapture *self) +{ + if(self->stream) + Pa_CloseStream(self->stream); + self->stream = NULL; + + if(self->ring) + ll_ringbuffer_free(self->ring); + self->ring = NULL; + + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); +} + + +static int ALCportCapture_ReadCallback(const void *inputBuffer, void *UNUSED(outputBuffer), + unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo), + const PaStreamCallbackFlags UNUSED(statusFlags), void *userData) +{ + ALCportCapture *self = userData; + size_t writable = ll_ringbuffer_write_space(self->ring); + + if(framesPerBuffer > writable) + framesPerBuffer = writable; + ll_ringbuffer_write(self->ring, inputBuffer, framesPerBuffer); + return 0; +} + + +static ALCenum ALCportCapture_open(ALCportCapture *self, const ALCchar *name) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALuint samples, frame_size; PaError err; - if(!deviceName) - deviceName = pa_device; - else if(strcmp(deviceName, pa_device) != 0) + if(!name) + name = pa_device; + else if(strcmp(name, pa_device) != 0) return ALC_INVALID_VALUE; - data = (pa_data*)calloc(1, sizeof(pa_data)); - if(data == NULL) - return ALC_OUT_OF_MEMORY; - + samples = device->UpdateSize * device->NumUpdates; + samples = maxu(samples, 100 * device->Frequency / 1000); frame_size = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); - data->ring = CreateRingBuffer(frame_size, device->UpdateSize*device->NumUpdates); - if(data->ring == NULL) - goto error; - data->params.device = -1; - if(!ConfigValueInt("port", "capture", &data->params.device) || - data->params.device < 0) - data->params.device = Pa_GetDefaultInputDevice(); - data->params.suggestedLatency = 0.0f; - data->params.hostApiSpecificStreamInfo = NULL; + self->ring = ll_ringbuffer_create(samples, frame_size); + if(self->ring == NULL) return ALC_INVALID_VALUE; + + self->params.device = -1; + if(!ConfigValueInt(NULL, "port", "capture", &self->params.device) || + self->params.device < 0) + self->params.device = Pa_GetDefaultInputDevice(); + self->params.suggestedLatency = 0.0f; + self->params.hostApiSpecificStreamInfo = NULL; switch(device->FmtType) { case DevFmtByte: - data->params.sampleFormat = paInt8; + self->params.sampleFormat = paInt8; break; case DevFmtUByte: - data->params.sampleFormat = paUInt8; + self->params.sampleFormat = paUInt8; break; case DevFmtShort: - data->params.sampleFormat = paInt16; + self->params.sampleFormat = paInt16; break; case DevFmtInt: - data->params.sampleFormat = paInt32; + self->params.sampleFormat = paInt32; break; case DevFmtFloat: - data->params.sampleFormat = paFloat32; + self->params.sampleFormat = paFloat32; break; case DevFmtUInt: case DevFmtUShort: ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType)); - goto error; + return ALC_INVALID_VALUE; } - data->params.channelCount = ChannelsFromDevFmt(device->FmtChans); + self->params.channelCount = ChannelsFromDevFmt(device->FmtChans); - err = Pa_OpenStream(&data->stream, &data->params, NULL, device->Frequency, - paFramesPerBufferUnspecified, paNoFlag, pa_capture_cb, device); + err = Pa_OpenStream(&self->stream, &self->params, NULL, + device->Frequency, paFramesPerBufferUnspecified, paNoFlag, + ALCportCapture_ReadCallback, self + ); if(err != paNoError) { ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err)); - goto error; + return ALC_INVALID_VALUE; } - al_string_copy_cstr(&device->DeviceName, deviceName); + al_string_copy_cstr(&device->DeviceName, name); - device->ExtraData = data; return ALC_NO_ERROR; - -error: - DestroyRingBuffer(data->ring); - free(data); - return ALC_INVALID_VALUE; } -static void pa_close_capture(ALCdevice *device) +static void ALCportCapture_close(ALCportCapture *self) { - pa_data *data = (pa_data*)device->ExtraData; - PaError err; - - err = Pa_CloseStream(data->stream); + PaError err = Pa_CloseStream(self->stream); if(err != paNoError) ERR("Error closing stream: %s\n", Pa_GetErrorText(err)); + self->stream = NULL; - DestroyRingBuffer(data->ring); - data->ring = NULL; - - free(data); - device->ExtraData = NULL; + ll_ringbuffer_free(self->ring); + self->ring = NULL; } -static void pa_start_capture(ALCdevice *device) -{ - pa_data *data = device->ExtraData; - PaError err; - err = Pa_StartStream(data->stream); +static ALCboolean ALCportCapture_start(ALCportCapture *self) +{ + PaError err = Pa_StartStream(self->stream); if(err != paNoError) + { ERR("Error starting stream: %s\n", Pa_GetErrorText(err)); + return ALC_FALSE; + } + return ALC_TRUE; } -static void pa_stop_capture(ALCdevice *device) +static void ALCportCapture_stop(ALCportCapture *self) { - pa_data *data = (pa_data*)device->ExtraData; - PaError err; - - err = Pa_StopStream(data->stream); + PaError err = Pa_StopStream(self->stream); if(err != paNoError) ERR("Error stopping stream: %s\n", Pa_GetErrorText(err)); } -static ALCenum pa_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples) + +static ALCuint ALCportCapture_availableSamples(ALCportCapture *self) { - pa_data *data = device->ExtraData; - ReadRingBuffer(data->ring, buffer, samples); + return ll_ringbuffer_read_space(self->ring); +} + +static ALCenum ALCportCapture_captureSamples(ALCportCapture *self, ALCvoid *buffer, ALCuint samples) +{ + ll_ringbuffer_read(self->ring, buffer, samples); return ALC_NO_ERROR; } -static ALCuint pa_available_samples(ALCdevice *device) -{ - pa_data *data = device->ExtraData; - return RingBufferSize(data->ring); -} + +typedef struct ALCportBackendFactory { + DERIVE_FROM_TYPE(ALCbackendFactory); +} ALCportBackendFactory; +#define ALCPORTBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCportBackendFactory, ALCbackendFactory) } } + +static ALCboolean ALCportBackendFactory_init(ALCportBackendFactory *self); +static void ALCportBackendFactory_deinit(ALCportBackendFactory *self); +static ALCboolean ALCportBackendFactory_querySupport(ALCportBackendFactory *self, ALCbackend_Type type); +static void ALCportBackendFactory_probe(ALCportBackendFactory *self, enum DevProbe type); +static ALCbackend* ALCportBackendFactory_createBackend(ALCportBackendFactory *self, ALCdevice *device, ALCbackend_Type type); + +DEFINE_ALCBACKENDFACTORY_VTABLE(ALCportBackendFactory); -static const BackendFuncs pa_funcs = { - pa_open_playback, - pa_close_playback, - pa_reset_playback, - pa_start_playback, - pa_stop_playback, - pa_open_capture, - pa_close_capture, - pa_start_capture, - pa_stop_capture, - pa_capture_samples, - pa_available_samples, - ALCdevice_GetLatencyDefault -}; - -ALCboolean alc_pa_init(BackendFuncs *func_list) +static ALCboolean ALCportBackendFactory_init(ALCportBackendFactory* UNUSED(self)) { if(!pa_load()) return ALC_FALSE; - *func_list = pa_funcs; return ALC_TRUE; } -void alc_pa_deinit(void) +static void ALCportBackendFactory_deinit(ALCportBackendFactory* UNUSED(self)) { #ifdef HAVE_DYNLOAD if(pa_handle) @@ -455,7 +526,14 @@ void alc_pa_deinit(void) #endif } -void alc_pa_probe(enum DevProbe type) +static ALCboolean ALCportBackendFactory_querySupport(ALCportBackendFactory* UNUSED(self), ALCbackend_Type type) +{ + if(type == ALCbackend_Playback || type == ALCbackend_Capture) + return ALC_TRUE; + return ALC_FALSE; +} + +static void ALCportBackendFactory_probe(ALCportBackendFactory* UNUSED(self), enum DevProbe type) { switch(type) { @@ -467,3 +545,29 @@ void alc_pa_probe(enum DevProbe type) break; } } + +static ALCbackend* ALCportBackendFactory_createBackend(ALCportBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +{ + if(type == ALCbackend_Playback) + { + ALCportPlayback *backend; + NEW_OBJ(backend, ALCportPlayback)(device); + if(!backend) return NULL; + return STATIC_CAST(ALCbackend, backend); + } + if(type == ALCbackend_Capture) + { + ALCportCapture *backend; + NEW_OBJ(backend, ALCportCapture)(device); + if(!backend) return NULL; + return STATIC_CAST(ALCbackend, backend); + } + + return NULL; +} + +ALCbackendFactory *ALCportBackendFactory_getFactory(void) +{ + static ALCportBackendFactory factory = ALCPORTBACKENDFACTORY_INITIALIZER; + return STATIC_CAST(ALCbackendFactory, &factory); +} diff --git a/libs/openal-soft/Alc/backends/pulseaudio.c b/libs/openal-soft/Alc/backends/pulseaudio.c index 8bd731ff..9ad04a71 100644 --- a/libs/openal-soft/Alc/backends/pulseaudio.c +++ b/libs/openal-soft/Alc/backends/pulseaudio.c @@ -14,8 +14,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 */ @@ -34,13 +34,6 @@ #if PA_API_VERSION == 12 -#ifndef PA_CHECK_VERSION -#define PA_CHECK_VERSION(major,minor,micro) \ - ((PA_MAJOR > (major)) || \ - (PA_MAJOR == (major) && PA_MINOR > (minor)) || \ - (PA_MAJOR == (major) && PA_MINOR == (minor) && PA_MICRO >= (micro))) -#endif - #ifdef HAVE_DYNLOAD static void *pa_handle; #define MAKE_FUNC(x) static __typeof(x) * p##x @@ -108,13 +101,9 @@ MAKE_FUNC(pa_operation_unref); MAKE_FUNC(pa_proplist_new); MAKE_FUNC(pa_proplist_free); MAKE_FUNC(pa_proplist_set); -#if PA_CHECK_VERSION(0,9,15) MAKE_FUNC(pa_channel_map_superset); MAKE_FUNC(pa_stream_set_buffer_attr_callback); -#endif -#if PA_CHECK_VERSION(0,9,16) MAKE_FUNC(pa_stream_begin_write); -#endif #undef MAKE_FUNC #define pa_context_unref ppa_context_unref @@ -181,13 +170,9 @@ MAKE_FUNC(pa_stream_begin_write); #define pa_proplist_new ppa_proplist_new #define pa_proplist_free ppa_proplist_free #define pa_proplist_set ppa_proplist_set -#if PA_CHECK_VERSION(0,9,15) #define pa_channel_map_superset ppa_channel_map_superset #define pa_stream_set_buffer_attr_callback ppa_stream_set_buffer_attr_callback -#endif -#if PA_CHECK_VERSION(0,9,16) #define pa_stream_begin_write ppa_stream_begin_write -#endif #endif @@ -278,18 +263,10 @@ static ALCboolean pulse_load(void) LOAD_FUNC(pa_proplist_new); LOAD_FUNC(pa_proplist_free); LOAD_FUNC(pa_proplist_set); + LOAD_FUNC(pa_channel_map_superset); + LOAD_FUNC(pa_stream_set_buffer_attr_callback); + LOAD_FUNC(pa_stream_begin_write); #undef LOAD_FUNC -#define LOAD_OPTIONAL_FUNC(x) do { \ - p##x = GetSymbol(pa_handle, #x); \ -} while(0) -#if PA_CHECK_VERSION(0,9,15) - LOAD_OPTIONAL_FUNC(pa_channel_map_superset); - LOAD_OPTIONAL_FUNC(pa_stream_set_buffer_attr_callback); -#endif -#if PA_CHECK_VERSION(0,9,16) - LOAD_OPTIONAL_FUNC(pa_stream_begin_write); -#endif -#undef LOAD_OPTIONAL_FUNC if(ret == ALC_FALSE) { @@ -428,8 +405,7 @@ error: return ALC_FALSE; } -static void pulse_close(pa_threaded_mainloop *loop, pa_context *context, - pa_stream *stream) +static void pulse_close(pa_threaded_mainloop *loop, pa_context *context, pa_stream *stream) { pa_threaded_mainloop_lock(loop); @@ -438,10 +414,7 @@ static void pulse_close(pa_threaded_mainloop *loop, pa_context *context, pa_stream_set_state_callback(stream, NULL, NULL); pa_stream_set_moved_callback(stream, NULL, NULL); pa_stream_set_write_callback(stream, NULL, NULL); -#if PA_CHECK_VERSION(0,9,15) - if(pa_stream_set_buffer_attr_callback) - pa_stream_set_buffer_attr_callback(stream, NULL, NULL); -#endif + pa_stream_set_buffer_attr_callback(stream, NULL, NULL); pa_stream_disconnect(stream); pa_stream_unref(stream); } @@ -544,6 +517,7 @@ static void ALCpulsePlayback_deviceCallback(pa_context *UNUSED(context), const p pa_threaded_mainloop *loop = pdata; const DevMap *iter; DevMap entry; + int count; if(eol) { @@ -553,18 +527,34 @@ static void ALCpulsePlayback_deviceCallback(pa_context *UNUSED(context), const p #define MATCH_INFO_NAME(iter) (al_string_cmp_cstr((iter)->device_name, info->name) == 0) VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_INFO_NAME); + if(iter != VECTOR_ITER_END(PlaybackDevices)) return; #undef MATCH_INFO_NAME - if(iter != VECTOR_ITER_END(PlaybackDevices)) - return; - - TRACE("Got device \"%s\", \"%s\"\n", info->description, info->name); AL_STRING_INIT(entry.name); AL_STRING_INIT(entry.device_name); - al_string_copy_cstr(&entry.name, info->description); al_string_copy_cstr(&entry.device_name, info->name); + count = 0; + while(1) + { + al_string_copy_cstr(&entry.name, info->description); + if(count != 0) + { + char str[64]; + snprintf(str, sizeof(str), " #%d", count+1); + al_string_append_cstr(&entry.name, str); + } + +#define MATCH_ENTRY(i) (al_string_cmp(entry.name, (i)->name) == 0) + VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_ENTRY); + if(iter == VECTOR_ITER_END(PlaybackDevices)) break; +#undef MATCH_ENTRY + count++; + } + + TRACE("Got device \"%s\", \"%s\"\n", al_string_get_cstr(entry.name), al_string_get_cstr(entry.device_name)); + VECTOR_PUSH_BACK(PlaybackDevices, entry); } @@ -660,27 +650,44 @@ static void ALCpulsePlayback_streamWriteCallback(pa_stream* UNUSED(p), size_t UN static void ALCpulsePlayback_sinkInfoCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata) { + static const struct { + enum DevFmtChannels chans; + pa_channel_map map; + } chanmaps[] = { + { DevFmtX71, { 8, { + PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, + PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, + PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT, + PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT + } } }, + { DevFmtX61, { 7, { + PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, + PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, + PA_CHANNEL_POSITION_REAR_CENTER, + PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT + } } }, + { DevFmtX51, { 6, { + PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, + PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, + PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT + } } }, + { DevFmtX51Rear, { 6, { + PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, + PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE, + PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT + } } }, + { DevFmtQuad, { 4, { + PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT, + PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT + } } }, + { DevFmtStereo, { 2, { + PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT + } } }, + { DevFmtMono, { 1, {PA_CHANNEL_POSITION_MONO} } } + }; ALCpulsePlayback *self = pdata; ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; - char chanmap_str[256] = ""; - const struct { - const char *str; - enum DevFmtChannels chans; - } chanmaps[] = { - { "front-left,front-right,front-center,lfe,rear-left,rear-right,side-left,side-right", - DevFmtX71 }, - { "front-left,front-right,front-center,lfe,rear-center,side-left,side-right", - DevFmtX61 }, - { "front-left,front-right,front-center,lfe,rear-left,rear-right", - DevFmtX51 }, - { "front-left,front-right,front-center,lfe,side-left,side-right", - DevFmtX51Side }, - { "front-left,front-right,rear-left,rear-right", DevFmtQuad }, - { "front-left,front-right", DevFmtStereo }, - { "mono", DevFmtMono }, - { NULL, 0 } - }; - int i; + size_t i; if(eol) { @@ -688,26 +695,27 @@ static void ALCpulsePlayback_sinkInfoCallback(pa_context *UNUSED(context), const return; } - for(i = 0;chanmaps[i].str;i++) + for(i = 0;i < COUNTOF(chanmaps);i++) { - pa_channel_map map; - if(!pa_channel_map_parse(&map, chanmaps[i].str)) - continue; - - if(pa_channel_map_equal(&info->channel_map, &map) -#if PA_CHECK_VERSION(0,9,15) - || (pa_channel_map_superset && - pa_channel_map_superset(&info->channel_map, &map)) -#endif - ) + if(pa_channel_map_superset(&info->channel_map, &chanmaps[i].map)) { - device->FmtChans = chanmaps[i].chans; - return; + if(!(device->Flags&DEVICE_CHANNELS_REQUEST)) + device->FmtChans = chanmaps[i].chans; + break; } } + if(i == COUNTOF(chanmaps)) + { + char chanmap_str[PA_CHANNEL_MAP_SNPRINT_MAX] = ""; + pa_channel_map_snprint(chanmap_str, sizeof(chanmap_str), &info->channel_map); + WARN("Failed to find format for channel map:\n %s\n", chanmap_str); + } - pa_channel_map_snprint(chanmap_str, sizeof(chanmap_str), &info->channel_map); - ERR("Failed to find format for channel map:\n %s\n", chanmap_str); + if(info->active_port) + TRACE("Active port: %s (%s)\n", info->active_port->name, info->active_port->description); + device->IsHeadphones = (info->active_port && + strcmp(info->active_port->name, "analog-output-headphones") == 0 && + device->FmtChans == DevFmtStereo); } static void ALCpulsePlayback_sinkNameCallback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void *pdata) @@ -818,10 +826,7 @@ static int ALCpulsePlayback_mixerProc(void *ptr) void *buf; pa_free_cb_t free_func = NULL; -#if PA_CHECK_VERSION(0,9,16) - if(!pa_stream_begin_write || - pa_stream_begin_write(self->stream, &buf, &newlen) < 0) -#endif + if(pa_stream_begin_write(self->stream, &buf, &newlen) < 0) { buf = pa_xmalloc(newlen); free_func = pa_xfree; @@ -841,10 +846,10 @@ static int ALCpulsePlayback_mixerProc(void *ptr) static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name) { + const_al_string dev_name = AL_STRING_INIT_STATIC(); const char *pulse_name = NULL; pa_stream_flags_t flags; pa_sample_spec spec; - pa_operation *o; if(name) { @@ -859,6 +864,7 @@ static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name if(iter == VECTOR_ITER_END(PlaybackDevices)) return ALC_INVALID_VALUE; pulse_name = al_string_get_cstr(iter->device_name); + dev_name = iter->name; } if(!pulse_open(&self->loop, &self->context, ALCpulsePlayback_contextStateCallback, self)) @@ -868,7 +874,7 @@ static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name flags = PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | PA_STREAM_FIX_CHANNELS; - if(!GetConfigValueBool("pulse", "allow-moves", 0)) + if(!GetConfigValueBool(NULL, "pulse", "allow-moves", 0)) flags |= PA_STREAM_DONT_MOVE; spec.format = PA_SAMPLE_S16NE; @@ -889,10 +895,19 @@ static ALCenum ALCpulsePlayback_open(ALCpulsePlayback *self, const ALCchar *name pa_stream_set_moved_callback(self->stream, ALCpulsePlayback_streamMovedCallback, self); al_string_copy_cstr(&self->device_name, pa_stream_get_device_name(self->stream)); - o = pa_context_get_sink_info_by_name(self->context, - al_string_get_cstr(self->device_name), - ALCpulsePlayback_sinkNameCallback, self); - wait_for_operation(o, self->loop); + if(al_string_empty(dev_name)) + { + pa_operation *o = pa_context_get_sink_info_by_name( + self->context, al_string_get_cstr(self->device_name), + ALCpulsePlayback_sinkNameCallback, self + ); + wait_for_operation(o, self->loop); + } + else + { + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; + al_string_copy(&device->DeviceName, dev_name); + } pa_threaded_mainloop_unlock(self->loop); @@ -915,37 +930,33 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self) pa_stream_flags_t flags = 0; const char *mapname = NULL; pa_channel_map chanmap; + pa_operation *o; ALuint len; pa_threaded_mainloop_lock(self->loop); if(self->stream) { + pa_stream_set_state_callback(self->stream, NULL, NULL); pa_stream_set_moved_callback(self->stream, NULL, NULL); -#if PA_CHECK_VERSION(0,9,15) - if(pa_stream_set_buffer_attr_callback) - pa_stream_set_buffer_attr_callback(self->stream, NULL, NULL); -#endif + pa_stream_set_write_callback(self->stream, NULL, NULL); + pa_stream_set_buffer_attr_callback(self->stream, NULL, NULL); pa_stream_disconnect(self->stream); pa_stream_unref(self->stream); self->stream = NULL; } - if(!(device->Flags&DEVICE_CHANNELS_REQUEST)) - { - pa_operation *o; - o = pa_context_get_sink_info_by_name(self->context, - al_string_get_cstr(self->device_name), - ALCpulsePlayback_sinkInfoCallback, self); - wait_for_operation(o, self->loop); - } - if(!(device->Flags&DEVICE_FREQUENCY_REQUEST)) - flags |= PA_STREAM_FIX_RATE; + o = pa_context_get_sink_info_by_name(self->context, al_string_get_cstr(self->device_name), + ALCpulsePlayback_sinkInfoCallback, self); + wait_for_operation(o, self->loop); + if(GetConfigValueBool(al_string_get_cstr(device->DeviceName), "pulse", "fix-rate", 0) || + !(device->Flags&DEVICE_FREQUENCY_REQUEST)) + flags |= PA_STREAM_FIX_RATE; flags |= PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE; flags |= PA_STREAM_ADJUST_LATENCY; flags |= PA_STREAM_START_CORKED; - if(!GetConfigValueBool("pulse", "allow-moves", 0)) + if(!GetConfigValueBool(NULL, "pulse", "allow-moves", 0)) flags |= PA_STREAM_DONT_MOVE; switch(device->FmtType) @@ -987,6 +998,9 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self) case DevFmtMono: mapname = "mono"; break; + case DevFmtBFormat3D: + device->FmtChans = DevFmtStereo; + /*fall-through*/ case DevFmtStereo: mapname = "front-left,front-right"; break; @@ -994,11 +1008,11 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self) mapname = "front-left,front-right,rear-left,rear-right"; break; case DevFmtX51: - mapname = "front-left,front-right,front-center,lfe,rear-left,rear-right"; - break; - case DevFmtX51Side: mapname = "front-left,front-right,front-center,lfe,side-left,side-right"; break; + case DevFmtX51Rear: + mapname = "front-left,front-right,front-center,lfe,rear-left,rear-right"; + break; case DevFmtX61: mapname = "front-left,front-right,front-center,lfe,rear-center,side-left,side-right"; break; @@ -1035,8 +1049,6 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self) self->spec = *(pa_stream_get_sample_spec(self->stream)); if(device->Frequency != self->spec.rate) { - pa_operation *o; - /* Server updated our playback rate, so modify the buffer attribs * accordingly. */ device->NumUpdates = (ALuint)((ALdouble)device->NumUpdates / device->Frequency * @@ -1053,15 +1065,10 @@ static ALCboolean ALCpulsePlayback_reset(ALCpulsePlayback *self) device->Frequency = self->spec.rate; } -#if PA_CHECK_VERSION(0,9,15) - if(pa_stream_set_buffer_attr_callback) - pa_stream_set_buffer_attr_callback(self->stream, ALCpulsePlayback_bufferAttrCallback, self); -#endif + pa_stream_set_buffer_attr_callback(self->stream, ALCpulsePlayback_bufferAttrCallback, self); ALCpulsePlayback_bufferAttrCallback(self->stream, self); len = self->attr.minreq / pa_frame_size(&self->spec); - if((CPUCapFlags&CPU_CAP_SSE)) - len = (len+3)&~3; device->NumUpdates = (ALuint)((ALdouble)device->NumUpdates/len*device->UpdateSize + 0.5); device->NumUpdates = clampu(device->NumUpdates, 2, 16); device->UpdateSize = len; @@ -1083,10 +1090,18 @@ static void ALCpulsePlayback_stop(ALCpulsePlayback *self) pa_operation *o; int res; - if(!self->stream) + if(!self->stream || self->killNow) return; self->killNow = AL_TRUE; + /* Signal the main loop in case PulseAudio isn't sending us audio requests + * (e.g. if the device is suspended). We need to lock the mainloop in case + * the mixer is between checking the killNow flag but before waiting for + * the signal. + */ + pa_threaded_mainloop_lock(self->loop); + pa_threaded_mainloop_unlock(self->loop); + pa_threaded_mainloop_signal(self->loop, 0); althrd_join(self->thread, &res); pa_threaded_mainloop_lock(self->loop); @@ -1199,6 +1214,7 @@ static void ALCpulseCapture_deviceCallback(pa_context *UNUSED(context), const pa pa_threaded_mainloop *loop = pdata; const DevMap *iter; DevMap entry; + int count; if(eol) { @@ -1208,18 +1224,34 @@ static void ALCpulseCapture_deviceCallback(pa_context *UNUSED(context), const pa #define MATCH_INFO_NAME(iter) (al_string_cmp_cstr((iter)->device_name, info->name) == 0) VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_INFO_NAME); + if(iter != VECTOR_ITER_END(CaptureDevices)) return; #undef MATCH_INFO_NAME - if(iter != VECTOR_ITER_END(CaptureDevices)) - return; - - TRACE("Got device \"%s\", \"%s\"\n", info->description, info->name); AL_STRING_INIT(entry.name); AL_STRING_INIT(entry.device_name); - al_string_copy_cstr(&entry.name, info->description); al_string_copy_cstr(&entry.device_name, info->name); + count = 0; + while(1) + { + al_string_copy_cstr(&entry.name, info->description); + if(count != 0) + { + char str[64]; + snprintf(str, sizeof(str), " #%d", count+1); + al_string_append_cstr(&entry.name, str); + } + +#define MATCH_ENTRY(i) (al_string_cmp(entry.name, (i)->name) == 0) + VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_ENTRY); + if(iter == VECTOR_ITER_END(CaptureDevices)) break; +#undef MATCH_ENTRY + count++; + } + + TRACE("Got device \"%s\", \"%s\"\n", al_string_get_cstr(entry.name), al_string_get_cstr(entry.device_name)); + VECTOR_PUSH_BACK(CaptureDevices, entry); } @@ -1372,7 +1404,6 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name) const char *pulse_name = NULL; pa_stream_flags_t flags = 0; pa_channel_map chanmap; - pa_operation *o; ALuint samples; if(name) @@ -1388,6 +1419,7 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name) if(iter == VECTOR_ITER_END(CaptureDevices)) return ALC_INVALID_VALUE; pulse_name = al_string_get_cstr(iter->device_name); + al_string_copy(&device->DeviceName, iter->name); } if(!pulse_open(&self->loop, &self->context, ALCpulseCapture_contextStateCallback, self)) @@ -1445,7 +1477,7 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name) pa_frame_size(&self->spec); flags |= PA_STREAM_START_CORKED|PA_STREAM_ADJUST_LATENCY; - if(!GetConfigValueBool("pulse", "allow-moves", 0)) + if(!GetConfigValueBool(NULL, "pulse", "allow-moves", 0)) flags |= PA_STREAM_DONT_MOVE; TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)"); @@ -1461,10 +1493,14 @@ static ALCenum ALCpulseCapture_open(ALCpulseCapture *self, const ALCchar *name) pa_stream_set_state_callback(self->stream, ALCpulseCapture_streamStateCallback, self); al_string_copy_cstr(&self->device_name, pa_stream_get_device_name(self->stream)); - o = pa_context_get_source_info_by_name(self->context, - al_string_get_cstr(self->device_name), - ALCpulseCapture_sourceNameCallback, self); - wait_for_operation(o, self->loop); + if(al_string_empty(device->DeviceName)) + { + pa_operation *o = pa_context_get_source_info_by_name( + self->context, al_string_get_cstr(self->device_name), + ALCpulseCapture_sourceNameCallback, self + ); + wait_for_operation(o, self->loop); + } pa_threaded_mainloop_unlock(self->loop); return ALC_NO_ERROR; @@ -1607,11 +1643,6 @@ static void ALCpulseCapture_unlock(ALCpulseCapture *self) } -static inline void AppendAllDevicesList2(const DevMap *entry) -{ AppendAllDevicesList(al_string_get_cstr(entry->name)); } -static inline void AppendCaptureDeviceList2(const DevMap *entry) -{ AppendCaptureDeviceList(al_string_get_cstr(entry->name)); } - typedef struct ALCpulseBackendFactory { DERIVE_FROM_TYPE(ALCbackendFactory); } ALCpulseBackendFactory; @@ -1638,7 +1669,7 @@ static ALCboolean ALCpulseBackendFactory_init(ALCpulseBackendFactory* UNUSED(sel pa_threaded_mainloop *loop; pulse_ctx_flags = 0; - if(!GetConfigValueBool("pulse", "spawn-server", 1)) + if(!GetConfigValueBool(NULL, "pulse", "spawn-server", 1)) pulse_ctx_flags |= PA_CONTEXT_NOAUTOSPAWN; if((loop=pa_threaded_mainloop_new()) && @@ -1701,12 +1732,16 @@ static void ALCpulseBackendFactory_probe(ALCpulseBackendFactory* UNUSED(self), e { case ALL_DEVICE_PROBE: ALCpulsePlayback_probeDevices(); - VECTOR_FOR_EACH(const DevMap, PlaybackDevices, AppendAllDevicesList2); +#define APPEND_ALL_DEVICES_LIST(e) AppendAllDevicesList(al_string_get_cstr((e)->name)) + VECTOR_FOR_EACH(const DevMap, PlaybackDevices, APPEND_ALL_DEVICES_LIST); +#undef APPEND_ALL_DEVICES_LIST break; case CAPTURE_DEVICE_PROBE: ALCpulseCapture_probeDevices(); - VECTOR_FOR_EACH(const DevMap, CaptureDevices, AppendCaptureDeviceList2); +#define APPEND_CAPTURE_DEVICE_LIST(e) AppendCaptureDeviceList(al_string_get_cstr((e)->name)) + VECTOR_FOR_EACH(const DevMap, CaptureDevices, APPEND_CAPTURE_DEVICE_LIST); +#undef APPEND_CAPTURE_DEVICE_LIST break; } } @@ -1716,25 +1751,15 @@ static ALCbackend* ALCpulseBackendFactory_createBackend(ALCpulseBackendFactory* if(type == ALCbackend_Playback) { ALCpulsePlayback *backend; - - backend = ALCpulsePlayback_New(sizeof(*backend)); + NEW_OBJ(backend, ALCpulsePlayback)(device); if(!backend) return NULL; - memset(backend, 0, sizeof(*backend)); - - ALCpulsePlayback_Construct(backend, device); - return STATIC_CAST(ALCbackend, backend); } if(type == ALCbackend_Capture) { ALCpulseCapture *backend; - - backend = ALCpulseCapture_New(sizeof(*backend)); + NEW_OBJ(backend, ALCpulseCapture)(device); if(!backend) return NULL; - memset(backend, 0, sizeof(*backend)); - - ALCpulseCapture_Construct(backend, device); - return STATIC_CAST(ALCbackend, backend); } diff --git a/libs/openal-soft/Alc/backends/qsa.c b/libs/openal-soft/Alc/backends/qsa.c index 9258e4e5..291e49fc 100644 --- a/libs/openal-soft/Alc/backends/qsa.c +++ b/libs/openal-soft/Alc/backends/qsa.c @@ -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 */ @@ -53,12 +53,12 @@ typedef struct { int card; int dev; } DevMap; +TYPEDEF_VECTOR(DevMap, vector_DevMap) + +static vector_DevMap DeviceNameMap; +static vector_DevMap CaptureNameMap; static const ALCchar qsaDevice[] = "QSA Default"; -static DevMap* allDevNameMap; -static ALuint numDevNames; -static DevMap* allCaptureDevNameMap; -static ALuint numCaptureDevNames; static const struct { int32_t format; @@ -104,69 +104,57 @@ static const struct { {0}, }; -static DevMap *deviceList(int type, ALuint *count) +static void deviceList(int type, vector_DevMap *devmap) { snd_ctl_t* handle; snd_pcm_info_t pcminfo; - int max_cards, card, err, dev, num_devices, idx; - DevMap* dev_list; + int max_cards, card, err, dev; + DevMap entry; char name[1024]; struct snd_ctl_hw_info info; - void* temp; - idx=0; - num_devices=0; - max_cards=snd_cards(); + max_cards = snd_cards(); + if(max_cards < 0) + return; - if (max_cards<=0) + VECTOR_RESERVE(*devmap, max_cards+1); + VECTOR_RESIZE(*devmap, 0); + + entry.name = strdup(qsaDevice); + entry.card = 0; + entry.dev = 0; + VECTOR_PUSH_BACK(*devmap, entry); + + for(card = 0;card < max_cards;card++) { - return 0; - } - - dev_list=malloc(sizeof(DevMap)*1); - dev_list[0].name=strdup(qsaDevice); - num_devices=1; - - for (card=0; cardpcmHandle, &card, &dev, SND_PCM_OPEN_PLAYBACK); - } + if(strcmp(deviceName, qsaDevice) == 0) + status = snd_pcm_open_preferred(&data->pcmHandle, &card, &dev, SND_PCM_OPEN_PLAYBACK); else { - size_t idx; + const DevMap *iter; - if (!allDevNameMap) - { - allDevNameMap=deviceList(SND_PCM_CHANNEL_PLAYBACK, &numDevNames); - } + if(VECTOR_SIZE(DeviceNameMap) == 0) + deviceList(SND_PCM_CHANNEL_PLAYBACK, &DeviceNameMap); - for (idx=0; idx0) - { - break; - } - } - } - if (idx==numDevNames) +#define MATCH_DEVNAME(iter) ((iter)->name && strcmp(deviceName, (iter)->name)==0) + VECTOR_FIND_IF(iter, const DevMap, DeviceNameMap, MATCH_DEVNAME); +#undef MATCH_DEVNAME + if(iter == VECTOR_ITER_END(DeviceNameMap)) { free(data); return ALC_INVALID_DEVICE; } - status=snd_pcm_open(&data->pcmHandle, allDevNameMap[idx].card, allDevNameMap[idx].dev, SND_PCM_OPEN_PLAYBACK); + status = snd_pcm_open(&data->pcmHandle, iter->card, iter->dev, SND_PCM_OPEN_PLAYBACK); } - if (status<0) + if(status < 0) { free(data); return ALC_INVALID_DEVICE; } - data->audio_fd=snd_pcm_file_descriptor(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK); - if (data->audio_fd<0) + data->audio_fd = snd_pcm_file_descriptor(data->pcmHandle, SND_PCM_CHANNEL_PLAYBACK); + if(data->audio_fd < 0) { + snd_pcm_close(data->pcmHandle); free(data); return ALC_INVALID_DEVICE; } @@ -633,72 +598,51 @@ static void qsa_stop_playback(ALCdevice* device) static ALCenum qsa_open_capture(ALCdevice* device, const ALCchar* deviceName) { - qsa_data* data; - int format=-1; - char driver[64]; + qsa_data *data; int card, dev; + int format=-1; int status; - strncpy(driver, GetConfigValue("qsa", "capture", qsaDevice), sizeof(driver)-1); - driver[sizeof(driver)-1]=0; - data=(qsa_data*)calloc(1, sizeof(qsa_data)); if (data==NULL) { return ALC_OUT_OF_MEMORY; } - if (!deviceName) - { - deviceName=driver; - } + if(!deviceName) + deviceName = qsaDevice; - if (strcmp(deviceName, qsaDevice)==0) - { - if (!deviceName) - { - deviceName=qsaDevice; - } - - status=snd_pcm_open_preferred(&data->pcmHandle, &card, &dev, SND_PCM_OPEN_CAPTURE); - } + if(strcmp(deviceName, qsaDevice) == 0) + status = snd_pcm_open_preferred(&data->pcmHandle, &card, &dev, SND_PCM_OPEN_CAPTURE); else { - size_t idx; + const DevMap *iter; - if (!allCaptureDevNameMap) - { - allCaptureDevNameMap=deviceList(SND_PCM_CHANNEL_CAPTURE, &numDevNames); - } + if(VECTOR_SIZE(CaptureNameMap) == 0) + deviceList(SND_PCM_CHANNEL_CAPTURE, &CaptureNameMap); - for (idx=0; idx0) - { - break; - } - } - } - if (idx==numDevNames) +#define MATCH_DEVNAME(iter) ((iter)->name && strcmp(deviceName, (iter)->name)==0) + VECTOR_FIND_IF(iter, const DevMap, CaptureNameMap, MATCH_DEVNAME); +#undef MATCH_DEVNAME + if(iter == VECTOR_ITER_END(CaptureNameMap)) { free(data); return ALC_INVALID_DEVICE; } - status=snd_pcm_open(&data->pcmHandle, allCaptureDevNameMap[idx].card, allCaptureDevNameMap[idx].dev, SND_PCM_OPEN_CAPTURE); + status = snd_pcm_open(&data->pcmHandle, iter->card, iter->dev, SND_PCM_OPEN_CAPTURE); } - if (status<0) + if(status < 0) { free(data); return ALC_INVALID_DEVICE; } - data->audio_fd=snd_pcm_file_descriptor(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE); - if (data->audio_fd<0) + data->audio_fd = snd_pcm_file_descriptor(data->pcmHandle, SND_PCM_CHANNEL_CAPTURE); + if(data->audio_fd < 0) { + snd_pcm_close(data->pcmHandle); free(data); return ALC_INVALID_DEVICE; } @@ -753,170 +697,13 @@ static ALCenum qsa_open_capture(ALCdevice* device, const ALCchar* deviceName) data->cparams.format.voices=ChannelsFromDevFmt(device->FmtChans); data->cparams.format.format=format; - if ((snd_pcm_plugin_params(data->pcmHandle, &data->cparams))<0) + if(snd_pcm_plugin_params(data->pcmHandle, &data->cparams) < 0) { - int original_rate=data->cparams.format.rate; - int original_voices=data->cparams.format.voices; - int original_format=data->cparams.format.format; - int it; - int jt; + snd_pcm_close(data->pcmHandle); + free(data); + device->ExtraData=NULL; - for (it=0; it<1; it++) - { - /* Check for second pass */ - if (it==1) - { - original_rate=ratelist[0].rate; - original_voices=channellist[0].channels; - original_format=formatlist[0].format; - } - - do { - /* At first downgrade sample format */ - jt=0; - do { - if (formatlist[jt].format==data->cparams.format.format) - { - data->cparams.format.format=formatlist[jt+1].format; - break; - } - if (formatlist[jt].format==0) - { - data->cparams.format.format=0; - break; - } - jt++; - } while(1); - - if (data->cparams.format.format==0) - { - data->cparams.format.format=original_format; - - /* At secod downgrade sample rate */ - jt=0; - do { - if (ratelist[jt].rate==data->cparams.format.rate) - { - data->cparams.format.rate=ratelist[jt+1].rate; - break; - } - if (ratelist[jt].rate==0) - { - data->cparams.format.rate=0; - break; - } - jt++; - } while(1); - - if (data->cparams.format.rate==0) - { - data->cparams.format.rate=original_rate; - data->cparams.format.format=original_format; - - /* At third downgrade channels number */ - jt=0; - do { - if(channellist[jt].channels==data->cparams.format.voices) - { - data->cparams.format.voices=channellist[jt+1].channels; - break; - } - if (channellist[jt].channels==0) - { - data->cparams.format.voices=0; - break; - } - jt++; - } while(1); - } - - if (data->cparams.format.voices==0) - { - break; - } - } - - data->cparams.buf.block.frag_size=device->UpdateSize* - data->cparams.format.voices* - snd_pcm_format_width(data->cparams.format.format)/8; - data->cparams.buf.block.frags_max=device->NumUpdates; - data->cparams.buf.block.frags_min=device->NumUpdates; - if ((snd_pcm_plugin_params(data->pcmHandle, &data->cparams))<0) - { - continue; - } - else - { - break; - } - } while(1); - - if (data->cparams.format.voices!=0) - { - break; - } - } - - if (data->cparams.format.voices==0) - { - return ALC_INVALID_VALUE; - } - } - - /* now fill back to the our AL device */ - device->Frequency=data->cparams.format.rate; - - switch (data->cparams.format.voices) - { - case 1: - device->FmtChans=DevFmtMono; - break; - case 2: - device->FmtChans=DevFmtStereo; - break; - case 4: - device->FmtChans=DevFmtQuad; - break; - case 6: - device->FmtChans=DevFmtX51; - break; - case 7: - device->FmtChans=DevFmtX61; - break; - case 8: - device->FmtChans=DevFmtX71; - break; - default: - device->FmtChans=DevFmtMono; - break; - } - - switch (data->cparams.format.format) - { - case SND_PCM_SFMT_S8: - device->FmtType=DevFmtByte; - break; - case SND_PCM_SFMT_U8: - device->FmtType=DevFmtUByte; - break; - case SND_PCM_SFMT_S16_LE: - device->FmtType=DevFmtShort; - break; - case SND_PCM_SFMT_U16_LE: - device->FmtType=DevFmtUShort; - break; - case SND_PCM_SFMT_S32_LE: - device->FmtType=DevFmtInt; - break; - case SND_PCM_SFMT_U32_LE: - device->FmtType=DevFmtUInt; - break; - case SND_PCM_SFMT_FLOAT_LE: - device->FmtType=DevFmtFloat; - break; - default: - device->FmtType=DevFmtShort; - break; + return ALC_INVALID_VALUE; } return ALC_NO_ERROR; @@ -927,9 +714,8 @@ static void qsa_close_capture(ALCdevice* device) qsa_data* data=(qsa_data*)device->ExtraData; if (data->pcmHandle!=NULL) - { snd_pcm_close(data->pcmHandle); - } + free(data); device->ExtraData=NULL; } @@ -954,10 +740,6 @@ static void qsa_start_capture(ALCdevice* device) } snd_pcm_capture_go(data->pcmHandle); - - device->UpdateSize=data->csetup.buf.block.frag_size/ - (ChannelsFromDevFmt(device->FmtChans)*BytesFromDevFmt(device->FmtType)); - device->NumUpdates=data->csetup.buf.block.frags; } static void qsa_stop_capture(ALCdevice* device) @@ -1073,16 +855,7 @@ static ALCenum qsa_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint s return ALC_NO_ERROR; } -static ALint64 qsa_get_latency(ALCdevice* device) -{ - ALint frame_size=FrameSizeFromDevFmt(device->FmtChans, device->FmtType); - - return (ALint64)(device->UpdateSize*device->NumUpdates/frame_size)* - 1000000000/device->Frequency; -} - -BackendFuncs qsa_funcs= -{ +static const BackendFuncs qsa_funcs= { qsa_open_playback, qsa_close_playback, qsa_reset_playback, @@ -1093,69 +866,52 @@ BackendFuncs qsa_funcs= qsa_start_capture, qsa_stop_capture, qsa_capture_samples, - qsa_available_samples, - qsa_get_latency, + qsa_available_samples }; ALCboolean alc_qsa_init(BackendFuncs* func_list) { - *func_list=qsa_funcs; - + *func_list = qsa_funcs; return ALC_TRUE; } void alc_qsa_deinit(void) { - ALuint i; +#define FREE_NAME(iter) free((iter)->name) + VECTOR_FOR_EACH(DevMap, DeviceNameMap, FREE_NAME); + VECTOR_DEINIT(DeviceNameMap); - for (i=0; iname) + VECTOR_FOR_EACH(DevMap, DeviceNameMap, FREE_NAME); +#undef FREE_NAME + VECTOR_RESIZE(DeviceNameMap, 0); + + deviceList(SND_PCM_CHANNEL_PLAYBACK, &DeviceNameMap); +#define APPEND_DEVICE(iter) AppendAllDevicesList((iter)->name) + VECTOR_FOR_EACH(const DevMap, DeviceNameMap, APPEND_DEVICE); +#undef APPEND_DEVICE + break; - allDevNameMap=deviceList(SND_PCM_CHANNEL_PLAYBACK, &numDevNames); - for (i=0; iname) + VECTOR_FOR_EACH(DevMap, CaptureNameMap, FREE_NAME); +#undef FREE_NAME + VECTOR_RESIZE(CaptureNameMap, 0); - allCaptureDevNameMap=deviceList(SND_PCM_CHANNEL_CAPTURE, &numCaptureDevNames); - for (i=0; iname) + VECTOR_FOR_EACH(const DevMap, CaptureNameMap, APPEND_DEVICE); +#undef APPEND_DEVICE + break; } } diff --git a/libs/openal-soft/Alc/backends/sndio.c b/libs/openal-soft/Alc/backends/sndio.c index 7152b2d6..52bff13a 100644 --- a/libs/openal-soft/Alc/backends/sndio.c +++ b/libs/openal-soft/Alc/backends/sndio.c @@ -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 */ @@ -266,8 +266,7 @@ static const BackendFuncs sndio_funcs = { NULL, NULL, NULL, - NULL, - ALCdevice_GetLatencyDefault + NULL }; ALCboolean alc_sndio_init(BackendFuncs *func_list) diff --git a/libs/openal-soft/Alc/backends/solaris.c b/libs/openal-soft/Alc/backends/solaris.c index 20d861d2..52ca9090 100644 --- a/libs/openal-soft/Alc/backends/solaris.c +++ b/libs/openal-soft/Alc/backends/solaris.c @@ -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 */ @@ -36,14 +36,14 @@ #include "threads.h" #include "compat.h" +#include "backends/base.h" + #include -static const ALCchar solaris_device[] = "Solaris Default"; +typedef struct ALCsolarisBackend { + DERIVE_FROM_TYPE(ALCbackend); -static const char *solaris_driver = "/dev/audio"; - -typedef struct { int fd; ALubyte *mix_data; @@ -51,13 +51,58 @@ typedef struct { volatile int killNow; althrd_t thread; -} solaris_data; +} ALCsolarisBackend; + +static int ALCsolarisBackend_mixerProc(void *ptr); + +static void ALCsolarisBackend_Construct(ALCsolarisBackend *self, ALCdevice *device); +static void ALCsolarisBackend_Destruct(ALCsolarisBackend *self); +static ALCenum ALCsolarisBackend_open(ALCsolarisBackend *self, const ALCchar *name); +static void ALCsolarisBackend_close(ALCsolarisBackend *self); +static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self); +static ALCboolean ALCsolarisBackend_start(ALCsolarisBackend *self); +static void ALCsolarisBackend_stop(ALCsolarisBackend *self); +static DECLARE_FORWARD2(ALCsolarisBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint) +static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, ALCuint, availableSamples) +static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, ALint64, getLatency) +static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCsolarisBackend, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCsolarisBackend) + +DEFINE_ALCBACKEND_VTABLE(ALCsolarisBackend); -static int SolarisProc(void *ptr) +static const ALCchar solaris_device[] = "Solaris Default"; + +static const char *solaris_driver = "/dev/audio"; + + +static void ALCsolarisBackend_Construct(ALCsolarisBackend *self, ALCdevice *device) { - ALCdevice *Device = (ALCdevice*)ptr; - solaris_data *data = (solaris_data*)Device->ExtraData; + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCsolarisBackend, ALCbackend, self); + + self->fd = -1; +} + +static void ALCsolarisBackend_Destruct(ALCsolarisBackend *self) +{ + if(self->fd != -1) + close(self->fd); + self->fd = -1; + + free(self->mix_data); + self->mix_data = NULL; + self->data_size = 0; + + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); +} + + +static int ALCsolarisBackend_mixerProc(void *ptr) +{ + ALCsolarisBackend *self = ptr; + ALCdevice *Device = STATIC_CAST(ALCbackend,self)->mDevice; ALint frameSize; int wrote; @@ -66,27 +111,27 @@ static int SolarisProc(void *ptr) frameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType); - while(!data->killNow && Device->Connected) + while(!self->killNow && Device->Connected) { - ALint len = data->data_size; - ALubyte *WritePtr = data->mix_data; + ALint len = self->data_size; + ALubyte *WritePtr = self->mix_data; aluMixData(Device, WritePtr, len/frameSize); - while(len > 0 && !data->killNow) + while(len > 0 && !self->killNow) { - wrote = write(data->fd, WritePtr, len); + wrote = write(self->fd, WritePtr, len); if(wrote < 0) { if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) { ERR("write failed: %s\n", strerror(errno)); - ALCdevice_Lock(Device); + ALCsolarisBackend_lock(self); aluHandleDisconnect(Device); - ALCdevice_Unlock(Device); + ALCsolarisBackend_unlock(self); break; } - al_nssleep(0, 1000000); + al_nssleep(1000000); continue; } @@ -99,43 +144,37 @@ static int SolarisProc(void *ptr) } -static ALCenum solaris_open_playback(ALCdevice *device, const ALCchar *deviceName) +static ALCenum ALCsolarisBackend_open(ALCsolarisBackend *self, const ALCchar *name) { - solaris_data *data; + ALCdevice *device; - if(!deviceName) - deviceName = solaris_device; - else if(strcmp(deviceName, solaris_device) != 0) + if(!name) + name = solaris_device; + else if(strcmp(name, solaris_device) != 0) return ALC_INVALID_VALUE; - data = (solaris_data*)calloc(1, sizeof(solaris_data)); - data->killNow = 0; - - data->fd = open(solaris_driver, O_WRONLY); - if(data->fd == -1) + self->fd = open(solaris_driver, O_WRONLY); + if(self->fd == -1) { - free(data); ERR("Could not open %s: %s\n", solaris_driver, strerror(errno)); return ALC_INVALID_VALUE; } - al_string_copy_cstr(&device->DeviceName, deviceName); - device->ExtraData = data; + device = STATIC_CAST(ALCbackend,self)->mDevice; + al_string_copy_cstr(&device->DeviceName, name); + return ALC_NO_ERROR; } -static void solaris_close_playback(ALCdevice *device) +static void ALCsolarisBackend_close(ALCsolarisBackend *self) { - solaris_data *data = (solaris_data*)device->ExtraData; - - close(data->fd); - free(data); - device->ExtraData = NULL; + close(self->fd); + self->fd = -1; } -static ALCboolean solaris_reset_playback(ALCdevice *device) +static ALCboolean ALCsolarisBackend_reset(ALCsolarisBackend *self) { - solaris_data *data = (solaris_data*)device->ExtraData; + ALCdevice *device = STATIC_CAST(ALCbackend,self)->mDevice; audio_info_t info; ALuint frameSize; int numChannels; @@ -174,7 +213,7 @@ static ALCboolean solaris_reset_playback(ALCdevice *device) frameSize = numChannels * BytesFromDevFmt(device->FmtType); info.play.buffer_size = device->UpdateSize*device->NumUpdates * frameSize; - if(ioctl(data->fd, AUDIO_SETINFO, &info) < 0) + if(ioctl(self->fd, AUDIO_SETINFO, &info) < 0) { ERR("ioctl failed: %s\n", strerror(errno)); return ALC_FALSE; @@ -201,74 +240,72 @@ static ALCboolean solaris_reset_playback(ALCdevice *device) SetDefaultChannelOrder(device); + free(self->mix_data); + self->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + self->mix_data = calloc(1, self->data_size); + return ALC_TRUE; } -static ALCboolean solaris_start_playback(ALCdevice *device) +static ALCboolean ALCsolarisBackend_start(ALCsolarisBackend *self) { - solaris_data *data = (solaris_data*)device->ExtraData; - - data->data_size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType); - data->mix_data = calloc(1, data->data_size); - - data->killNow = 0; - if(althrd_create(&data->thread, SolarisProc, device) != althrd_success) - { - free(data->mix_data); - data->mix_data = NULL; + self->killNow = 0; + if(althrd_create(&self->thread, ALCsolarisBackend_mixerProc, self) != althrd_success) return ALC_FALSE; - } - return ALC_TRUE; } -static void solaris_stop_playback(ALCdevice *device) +static void ALCsolarisBackend_stop(ALCsolarisBackend *self) { - solaris_data *data = (solaris_data*)device->ExtraData; int res; - if(data->killNow) + if(self->killNow) return; - data->killNow = 1; - althrd_join(data->thread, &res); + self->killNow = 1; + althrd_join(self->thread, &res); - if(ioctl(data->fd, AUDIO_DRAIN) < 0) + if(ioctl(self->fd, AUDIO_DRAIN) < 0) ERR("Error draining device: %s\n", strerror(errno)); - - free(data->mix_data); - data->mix_data = NULL; } -static const BackendFuncs solaris_funcs = { - solaris_open_playback, - solaris_close_playback, - solaris_reset_playback, - solaris_start_playback, - solaris_stop_playback, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - ALCdevice_GetLatencyDefault -}; +typedef struct ALCsolarisBackendFactory { + DERIVE_FROM_TYPE(ALCbackendFactory); +} ALCsolarisBackendFactory; +#define ALCSOLARISBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCsolarisBackendFactory, ALCbackendFactory) } } -ALCboolean alc_solaris_init(BackendFuncs *func_list) +ALCbackendFactory *ALCsolarisBackendFactory_getFactory(void); + +static ALCboolean ALCsolarisBackendFactory_init(ALCsolarisBackendFactory *self); +static DECLARE_FORWARD(ALCsolarisBackendFactory, ALCbackendFactory, void, deinit) +static ALCboolean ALCsolarisBackendFactory_querySupport(ALCsolarisBackendFactory *self, ALCbackend_Type type); +static void ALCsolarisBackendFactory_probe(ALCsolarisBackendFactory *self, enum DevProbe type); +static ALCbackend* ALCsolarisBackendFactory_createBackend(ALCsolarisBackendFactory *self, ALCdevice *device, ALCbackend_Type type); +DEFINE_ALCBACKENDFACTORY_VTABLE(ALCsolarisBackendFactory); + + +ALCbackendFactory *ALCsolarisBackendFactory_getFactory(void) { - ConfigValueStr("solaris", "device", &solaris_driver); + static ALCsolarisBackendFactory factory = ALCSOLARISBACKENDFACTORY_INITIALIZER; + return STATIC_CAST(ALCbackendFactory, &factory); +} - *func_list = solaris_funcs; + +static ALCboolean ALCsolarisBackendFactory_init(ALCsolarisBackendFactory* UNUSED(self)) +{ + ConfigValueStr(NULL, "solaris", "device", &solaris_driver); return ALC_TRUE; } -void alc_solaris_deinit(void) +static ALCboolean ALCsolarisBackendFactory_querySupport(ALCsolarisBackendFactory* UNUSED(self), ALCbackend_Type type) { + if(type == ALCbackend_Playback) + return ALC_TRUE; + return ALC_FALSE; } -void alc_solaris_probe(enum DevProbe type) +static void ALCsolarisBackendFactory_probe(ALCsolarisBackendFactory* UNUSED(self), enum DevProbe type) { switch(type) { @@ -286,3 +323,16 @@ void alc_solaris_probe(enum DevProbe type) break; } } + +ALCbackend* ALCsolarisBackendFactory_createBackend(ALCsolarisBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +{ + if(type == ALCbackend_Playback) + { + ALCsolarisBackend *backend; + NEW_OBJ(backend, ALCsolarisBackend)(device); + if(!backend) return NULL; + return STATIC_CAST(ALCbackend, backend); + } + + return NULL; +} diff --git a/libs/openal-soft/Alc/backends/wave.c b/libs/openal-soft/Alc/backends/wave.c index 421ca5d7..6b47c611 100644 --- a/libs/openal-soft/Alc/backends/wave.c +++ b/libs/openal-soft/Alc/backends/wave.c @@ -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 */ @@ -24,26 +24,13 @@ #include #include #include -#ifdef HAVE_WINDOWS_H -#include -#endif #include "alMain.h" #include "alu.h" #include "threads.h" #include "compat.h" - -typedef struct { - FILE *f; - long DataStart; - - ALvoid *buffer; - ALuint size; - - volatile int killNow; - althrd_t thread; -} wave_data; +#include "backends/base.h" static const ALCchar waveDevice[] = "Wave File Writer"; @@ -57,18 +44,15 @@ static const ALubyte SUBTYPE_FLOAT[] = { 0x00, 0x38, 0x9b, 0x71 }; -static const ALuint channel_masks[] = { - 0, /* invalid */ - 0x4, /* Mono */ - 0x1 | 0x2, /* Stereo */ - 0, /* 3 channel */ - 0x1 | 0x2 | 0x10 | 0x20, /* Quad */ - 0, /* 5 channel */ - 0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20, /* 5.1 */ - 0x1 | 0x2 | 0x4 | 0x8 | 0x100 | 0x200 | 0x400, /* 6.1 */ - 0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20 | 0x200 | 0x400, /* 7.1 */ +static const ALubyte SUBTYPE_BFORMAT_PCM[] = { + 0x01, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1, + 0xca, 0x00, 0x00, 0x00 }; +static const ALubyte SUBTYPE_BFORMAT_FLOAT[] = { + 0x03, 0x00, 0x00, 0x00, 0x21, 0x07, 0xd3, 0x11, 0x86, 0x44, 0xc8, 0xc1, + 0xca, 0x00, 0x00, 0x00 +}; static void fwrite16le(ALushort val, FILE *f) { @@ -85,10 +69,57 @@ static void fwrite32le(ALuint val, FILE *f) } -static int WaveProc(void *ptr) +typedef struct ALCwaveBackend { + DERIVE_FROM_TYPE(ALCbackend); + + FILE *mFile; + long mDataStart; + + ALvoid *mBuffer; + ALuint mSize; + + volatile int killNow; + althrd_t thread; +} ALCwaveBackend; + +static int ALCwaveBackend_mixerProc(void *ptr); + +static void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device); +static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, void, Destruct) +static ALCenum ALCwaveBackend_open(ALCwaveBackend *self, const ALCchar *name); +static void ALCwaveBackend_close(ALCwaveBackend *self); +static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self); +static ALCboolean ALCwaveBackend_start(ALCwaveBackend *self); +static void ALCwaveBackend_stop(ALCwaveBackend *self); +static DECLARE_FORWARD2(ALCwaveBackend, ALCbackend, ALCenum, captureSamples, void*, ALCuint) +static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, ALCuint, availableSamples) +static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, ALint64, getLatency) +static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCwaveBackend, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCwaveBackend) + +DEFINE_ALCBACKEND_VTABLE(ALCwaveBackend); + + +static void ALCwaveBackend_Construct(ALCwaveBackend *self, ALCdevice *device) { - ALCdevice *device = (ALCdevice*)ptr; - wave_data *data = (wave_data*)device->ExtraData; + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCwaveBackend, ALCbackend, self); + + self->mFile = NULL; + self->mDataStart = -1; + + self->mBuffer = NULL; + self->mSize = 0; + + self->killNow = 1; +} + + +static int ALCwaveBackend_mixerProc(void *ptr) +{ + ALCwaveBackend *self = (ALCwaveBackend*)ptr; + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; struct timespec now, start; ALint64 avail, done; ALuint frameSize; @@ -106,7 +137,7 @@ static int WaveProc(void *ptr) ERR("Failed to get starting time\n"); return 1; } - while(!data->killNow && device->Connected) + while(!self->killNow && device->Connected) { if(altimespec_get(&now, AL_TIME_UTC) != AL_TIME_UTC) { @@ -125,41 +156,41 @@ static int WaveProc(void *ptr) } if(avail-done < device->UpdateSize) - al_nssleep(0, restTime); + al_nssleep(restTime); else while(avail-done >= device->UpdateSize) { - aluMixData(device, data->buffer, device->UpdateSize); + aluMixData(device, self->mBuffer, device->UpdateSize); done += device->UpdateSize; if(!IS_LITTLE_ENDIAN) { ALuint bytesize = BytesFromDevFmt(device->FmtType); - ALubyte *bytes = data->buffer; + ALubyte *bytes = self->mBuffer; ALuint i; if(bytesize == 1) { - for(i = 0;i < data->size;i++) - fputc(bytes[i], data->f); + for(i = 0;i < self->mSize;i++) + fputc(bytes[i], self->mFile); } else if(bytesize == 2) { - for(i = 0;i < data->size;i++) - fputc(bytes[i^1], data->f); + for(i = 0;i < self->mSize;i++) + fputc(bytes[i^1], self->mFile); } else if(bytesize == 4) { - for(i = 0;i < data->size;i++) - fputc(bytes[i^3], data->f); + for(i = 0;i < self->mSize;i++) + fputc(bytes[i^3], self->mFile); } } else { - fs = fwrite(data->buffer, frameSize, device->UpdateSize, - data->f); + fs = fwrite(self->mBuffer, frameSize, device->UpdateSize, + self->mFile); (void)fs; } - if(ferror(data->f)) + if(ferror(self->mFile)) { ERR("Error writing to file\n"); ALCdevice_Lock(device); @@ -173,52 +204,52 @@ static int WaveProc(void *ptr) return 0; } -static ALCenum wave_open_playback(ALCdevice *device, const ALCchar *deviceName) + +static ALCenum ALCwaveBackend_open(ALCwaveBackend *self, const ALCchar *name) { - wave_data *data; + ALCdevice *device; const char *fname; - fname = GetConfigValue("wave", "file", ""); - if(!fname[0]) + fname = GetConfigValue(NULL, "wave", "file", ""); + if(!fname[0]) return ALC_INVALID_VALUE; + + if(!name) + name = waveDevice; + else if(strcmp(name, waveDevice) != 0) return ALC_INVALID_VALUE; - if(!deviceName) - deviceName = waveDevice; - else if(strcmp(deviceName, waveDevice) != 0) - return ALC_INVALID_VALUE; - - data = (wave_data*)calloc(1, sizeof(wave_data)); - - data->f = al_fopen(fname, "wb"); - if(!data->f) + self->mFile = al_fopen(fname, "wb"); + if(!self->mFile) { - free(data); ERR("Could not open file '%s': %s\n", fname, strerror(errno)); return ALC_INVALID_VALUE; } - al_string_copy_cstr(&device->DeviceName, deviceName); - device->ExtraData = data; + device = STATIC_CAST(ALCbackend, self)->mDevice; + al_string_copy_cstr(&device->DeviceName, name); + return ALC_NO_ERROR; } -static void wave_close_playback(ALCdevice *device) +static void ALCwaveBackend_close(ALCwaveBackend *self) { - wave_data *data = (wave_data*)device->ExtraData; - - fclose(data->f); - free(data); - device->ExtraData = NULL; + if(self->mFile) + fclose(self->mFile); + self->mFile = NULL; } -static ALCboolean wave_reset_playback(ALCdevice *device) +static ALCboolean ALCwaveBackend_reset(ALCwaveBackend *self) { - wave_data *data = (wave_data*)device->ExtraData; - ALuint channels=0, bits=0; + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + ALuint channels=0, bits=0, chanmask=0; + int isbformat = 0; size_t val; - fseek(data->f, 0, SEEK_SET); - clearerr(data->f); + fseek(self->mFile, 0, SEEK_SET); + clearerr(self->mFile); + + if(GetConfigValueBool(NULL, "wave", "bformat", 0)) + device->FmtChans = DevFmtBFormat3D; switch(device->FmtType) { @@ -237,135 +268,156 @@ static ALCboolean wave_reset_playback(ALCdevice *device) case DevFmtFloat: break; } + switch(device->FmtChans) + { + case DevFmtMono: chanmask = 0x04; break; + case DevFmtStereo: chanmask = 0x01 | 0x02; break; + case DevFmtQuad: chanmask = 0x01 | 0x02 | 0x10 | 0x20; break; + case DevFmtX51: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x200 | 0x400; break; + case DevFmtX51Rear: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020; break; + case DevFmtX61: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x100 | 0x200 | 0x400; break; + case DevFmtX71: chanmask = 0x01 | 0x02 | 0x04 | 0x08 | 0x010 | 0x020 | 0x200 | 0x400; break; + case DevFmtBFormat3D: + isbformat = 1; + chanmask = 0; + break; + } bits = BytesFromDevFmt(device->FmtType) * 8; channels = ChannelsFromDevFmt(device->FmtChans); - fprintf(data->f, "RIFF"); - fwrite32le(0xFFFFFFFF, data->f); // 'RIFF' header len; filled in at close + fprintf(self->mFile, "RIFF"); + fwrite32le(0xFFFFFFFF, self->mFile); // 'RIFF' header len; filled in at close - fprintf(data->f, "WAVE"); + fprintf(self->mFile, "WAVE"); - fprintf(data->f, "fmt "); - fwrite32le(40, data->f); // 'fmt ' header len; 40 bytes for EXTENSIBLE + fprintf(self->mFile, "fmt "); + fwrite32le(40, self->mFile); // 'fmt ' header len; 40 bytes for EXTENSIBLE // 16-bit val, format type id (extensible: 0xFFFE) - fwrite16le(0xFFFE, data->f); + fwrite16le(0xFFFE, self->mFile); // 16-bit val, channel count - fwrite16le(channels, data->f); + fwrite16le(channels, self->mFile); // 32-bit val, frequency - fwrite32le(device->Frequency, data->f); + fwrite32le(device->Frequency, self->mFile); // 32-bit val, bytes per second - fwrite32le(device->Frequency * channels * bits / 8, data->f); + fwrite32le(device->Frequency * channels * bits / 8, self->mFile); // 16-bit val, frame size - fwrite16le(channels * bits / 8, data->f); + fwrite16le(channels * bits / 8, self->mFile); // 16-bit val, bits per sample - fwrite16le(bits, data->f); + fwrite16le(bits, self->mFile); // 16-bit val, extra byte count - fwrite16le(22, data->f); + fwrite16le(22, self->mFile); // 16-bit val, valid bits per sample - fwrite16le(bits, data->f); + fwrite16le(bits, self->mFile); // 32-bit val, channel mask - fwrite32le(channel_masks[channels], data->f); + fwrite32le(chanmask, self->mFile); // 16 byte GUID, sub-type format - val = fwrite(((bits==32) ? SUBTYPE_FLOAT : SUBTYPE_PCM), 1, 16, data->f); + val = fwrite(((bits==32) ? (isbformat ? SUBTYPE_BFORMAT_FLOAT : SUBTYPE_FLOAT) : + (isbformat ? SUBTYPE_BFORMAT_PCM : SUBTYPE_PCM)), 1, 16, self->mFile); (void)val; - fprintf(data->f, "data"); - fwrite32le(0xFFFFFFFF, data->f); // 'data' header len; filled in at close + fprintf(self->mFile, "data"); + fwrite32le(0xFFFFFFFF, self->mFile); // 'data' header len; filled in at close - if(ferror(data->f)) + if(ferror(self->mFile)) { ERR("Error writing header: %s\n", strerror(errno)); return ALC_FALSE; } - data->DataStart = ftell(data->f); + self->mDataStart = ftell(self->mFile); SetDefaultWFXChannelOrder(device); return ALC_TRUE; } -static ALCboolean wave_start_playback(ALCdevice *device) +static ALCboolean ALCwaveBackend_start(ALCwaveBackend *self) { - wave_data *data = (wave_data*)device->ExtraData; + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - data->size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType); - data->buffer = malloc(data->size); - if(!data->buffer) + self->mSize = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType); + self->mBuffer = malloc(self->mSize); + if(!self->mBuffer) { ERR("Buffer malloc failed\n"); return ALC_FALSE; } - data->killNow = 0; - if(althrd_create(&data->thread, WaveProc, device) != althrd_success) + self->killNow = 0; + if(althrd_create(&self->thread, ALCwaveBackend_mixerProc, self) != althrd_success) { - free(data->buffer); - data->buffer = NULL; + free(self->mBuffer); + self->mBuffer = NULL; + self->mSize = 0; return ALC_FALSE; } return ALC_TRUE; } -static void wave_stop_playback(ALCdevice *device) +static void ALCwaveBackend_stop(ALCwaveBackend *self) { - wave_data *data = (wave_data*)device->ExtraData; ALuint dataLen; long size; int res; - if(data->killNow) + if(self->killNow) return; - data->killNow = 1; - althrd_join(data->thread, &res); + self->killNow = 1; + althrd_join(self->thread, &res); - free(data->buffer); - data->buffer = NULL; + free(self->mBuffer); + self->mBuffer = NULL; - size = ftell(data->f); + size = ftell(self->mFile); if(size > 0) { - dataLen = size - data->DataStart; - if(fseek(data->f, data->DataStart-4, SEEK_SET) == 0) - fwrite32le(dataLen, data->f); // 'data' header len - if(fseek(data->f, 4, SEEK_SET) == 0) - fwrite32le(size-8, data->f); // 'WAVE' header len + dataLen = size - self->mDataStart; + if(fseek(self->mFile, self->mDataStart-4, SEEK_SET) == 0) + fwrite32le(dataLen, self->mFile); // 'data' header len + if(fseek(self->mFile, 4, SEEK_SET) == 0) + fwrite32le(size-8, self->mFile); // 'WAVE' header len } } -static const BackendFuncs wave_funcs = { - wave_open_playback, - wave_close_playback, - wave_reset_playback, - wave_start_playback, - wave_stop_playback, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - ALCdevice_GetLatencyDefault -}; +typedef struct ALCwaveBackendFactory { + DERIVE_FROM_TYPE(ALCbackendFactory); +} ALCwaveBackendFactory; +#define ALCWAVEBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCwaveBackendFactory, ALCbackendFactory) } } -ALCboolean alc_wave_init(BackendFuncs *func_list) +ALCbackendFactory *ALCwaveBackendFactory_getFactory(void); + +static ALCboolean ALCwaveBackendFactory_init(ALCwaveBackendFactory *self); +static DECLARE_FORWARD(ALCwaveBackendFactory, ALCbackendFactory, void, deinit) +static ALCboolean ALCwaveBackendFactory_querySupport(ALCwaveBackendFactory *self, ALCbackend_Type type); +static void ALCwaveBackendFactory_probe(ALCwaveBackendFactory *self, enum DevProbe type); +static ALCbackend* ALCwaveBackendFactory_createBackend(ALCwaveBackendFactory *self, ALCdevice *device, ALCbackend_Type type); +DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwaveBackendFactory); + + +ALCbackendFactory *ALCwaveBackendFactory_getFactory(void) +{ + static ALCwaveBackendFactory factory = ALCWAVEBACKENDFACTORY_INITIALIZER; + return STATIC_CAST(ALCbackendFactory, &factory); +} + + +static ALCboolean ALCwaveBackendFactory_init(ALCwaveBackendFactory* UNUSED(self)) { - *func_list = wave_funcs; return ALC_TRUE; } -void alc_wave_deinit(void) +static ALCboolean ALCwaveBackendFactory_querySupport(ALCwaveBackendFactory* UNUSED(self), ALCbackend_Type type) { + if(type == ALCbackend_Playback) + return !!ConfigValueExists(NULL, "wave", "file"); + return ALC_FALSE; } -void alc_wave_probe(enum DevProbe type) +static void ALCwaveBackendFactory_probe(ALCwaveBackendFactory* UNUSED(self), enum DevProbe type) { - if(!ConfigValueExists("wave", "file")) - return; - switch(type) { case ALL_DEVICE_PROBE: @@ -375,3 +427,16 @@ void alc_wave_probe(enum DevProbe type) break; } } + +static ALCbackend* ALCwaveBackendFactory_createBackend(ALCwaveBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +{ + if(type == ALCbackend_Playback) + { + ALCwaveBackend *backend; + NEW_OBJ(backend, ALCwaveBackend)(device); + if(!backend) return NULL; + return STATIC_CAST(ALCbackend, backend); + } + + return NULL; +} diff --git a/libs/openal-soft/Alc/backends/winmm.c b/libs/openal-soft/Alc/backends/winmm.c index cad66470..bf97ef2e 100644 --- a/libs/openal-soft/Alc/backends/winmm.c +++ b/libs/openal-soft/Alc/backends/winmm.c @@ -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 */ @@ -31,31 +31,15 @@ #include "alu.h" #include "threads.h" +#include "backends/base.h" + #ifndef WAVE_FORMAT_IEEE_FLOAT #define WAVE_FORMAT_IEEE_FLOAT 0x0003 #endif - -typedef struct { - // MMSYSTEM Device - volatile ALboolean killNow; - althrd_t thread; - - RefCount WaveBuffersCommitted; - WAVEHDR WaveBuffer[4]; - - union { - HWAVEIN In; - HWAVEOUT Out; - } WaveHandle; - - WAVEFORMATEX Format; - - RingBuffer *Ring; -} WinMMData; +#define DEVNAME_TAIL " on OpenAL Soft" -TYPEDEF_VECTOR(al_string, vector_al_string) static vector_al_string PlaybackDevices; static vector_al_string CaptureDevices; @@ -68,7 +52,6 @@ static void clear_devlist(vector_al_string *list) static void ProbePlaybackDevices(void) { - al_string *iter, *end; ALuint numdevs; ALuint i; @@ -79,30 +62,31 @@ static void ProbePlaybackDevices(void) for(i = 0;i < numdevs;i++) { WAVEOUTCAPSW WaveCaps; + const al_string *iter; al_string dname; AL_STRING_INIT(dname); if(waveOutGetDevCapsW(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR) { ALuint count = 0; - do { + while(1) + { al_string_copy_wcstr(&dname, WaveCaps.szPname); - if(count != 0) + if(count == 0) + al_string_append_cstr(&dname, DEVNAME_TAIL); + else { char str[64]; - snprintf(str, sizeof(str), " #%d", count+1); + snprintf(str, sizeof(str), " #%d"DEVNAME_TAIL, count+1); al_string_append_cstr(&dname, str); } count++; - iter = VECTOR_ITER_BEGIN(PlaybackDevices); - end = VECTOR_ITER_END(PlaybackDevices); - for(;iter != end;iter++) - { - if(al_string_cmp(*iter, dname) == 0) - break; - } - } while(iter != end); +#define MATCH_ENTRY(i) (al_string_cmp(dname, *(i)) == 0) + VECTOR_FIND_IF(iter, const al_string, PlaybackDevices, MATCH_ENTRY); + if(iter == VECTOR_ITER_END(PlaybackDevices)) break; +#undef MATCH_ENTRY + } TRACE("Got device \"%s\", ID %u\n", al_string_get_cstr(dname), i); } @@ -112,7 +96,6 @@ static void ProbePlaybackDevices(void) static void ProbeCaptureDevices(void) { - al_string *iter, *end; ALuint numdevs; ALuint i; @@ -123,30 +106,31 @@ static void ProbeCaptureDevices(void) for(i = 0;i < numdevs;i++) { WAVEINCAPSW WaveCaps; + const al_string *iter; al_string dname; AL_STRING_INIT(dname); if(waveInGetDevCapsW(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR) { ALuint count = 0; - do { + while(1) + { al_string_copy_wcstr(&dname, WaveCaps.szPname); - if(count != 0) + if(count == 0) + al_string_append_cstr(&dname, DEVNAME_TAIL); + else { char str[64]; - snprintf(str, sizeof(str), " #%d", count+1); + snprintf(str, sizeof(str), " #%d"DEVNAME_TAIL, count+1); al_string_append_cstr(&dname, str); } count++; - iter = VECTOR_ITER_BEGIN(CaptureDevices); - end = VECTOR_ITER_END(CaptureDevices); - for(;iter != end;iter++) - { - if(al_string_cmp(*iter, dname) == 0) - break; - } - } while(iter != end); +#define MATCH_ENTRY(i) (al_string_cmp(dname, *(i)) == 0) + VECTOR_FIND_IF(iter, const al_string, CaptureDevices, MATCH_ENTRY); + if(iter == VECTOR_ITER_END(CaptureDevices)) break; +#undef MATCH_ENTRY + } TRACE("Got device \"%s\", ID %u\n", al_string_get_cstr(dname), i); } @@ -155,28 +139,82 @@ static void ProbeCaptureDevices(void) } -/* - WaveOutProc +typedef struct ALCwinmmPlayback { + DERIVE_FROM_TYPE(ALCbackend); - Posts a message to 'PlaybackThreadProc' everytime a WaveOut Buffer is completed and - returns to the application (for more data) -*/ -static void CALLBACK WaveOutProc(HWAVEOUT UNUSED(device), UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR UNUSED(param2)) + RefCount WaveBuffersCommitted; + WAVEHDR WaveBuffer[4]; + + HWAVEOUT OutHdl; + + WAVEFORMATEX Format; + + volatile ALboolean killNow; + althrd_t thread; +} ALCwinmmPlayback; + +static void ALCwinmmPlayback_Construct(ALCwinmmPlayback *self, ALCdevice *device); +static void ALCwinmmPlayback_Destruct(ALCwinmmPlayback *self); + +static void CALLBACK ALCwinmmPlayback_waveOutProc(HWAVEOUT device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2); +static int ALCwinmmPlayback_mixerProc(void *arg); + +static ALCenum ALCwinmmPlayback_open(ALCwinmmPlayback *self, const ALCchar *name); +static void ALCwinmmPlayback_close(ALCwinmmPlayback *self); +static ALCboolean ALCwinmmPlayback_reset(ALCwinmmPlayback *self); +static ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self); +static void ALCwinmmPlayback_stop(ALCwinmmPlayback *self); +static DECLARE_FORWARD2(ALCwinmmPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint) +static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, ALCuint, availableSamples) +static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, ALint64, getLatency) +static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCwinmmPlayback, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCwinmmPlayback) + +DEFINE_ALCBACKEND_VTABLE(ALCwinmmPlayback); + + +static void ALCwinmmPlayback_Construct(ALCwinmmPlayback *self, ALCdevice *device) { - ALCdevice *Device = (ALCdevice*)instance; - WinMMData *data = Device->ExtraData; + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCwinmmPlayback, ALCbackend, self); + + InitRef(&self->WaveBuffersCommitted, 0); + self->OutHdl = NULL; + + self->killNow = AL_TRUE; +} + +static void ALCwinmmPlayback_Destruct(ALCwinmmPlayback *self) +{ + if(self->OutHdl) + waveOutClose(self->OutHdl); + self->OutHdl = 0; + + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); +} + + +/* ALCwinmmPlayback_waveOutProc + * + * Posts a message to 'ALCwinmmPlayback_mixerProc' everytime a WaveOut Buffer + * is completed and returns to the application (for more data) + */ +static void CALLBACK ALCwinmmPlayback_waveOutProc(HWAVEOUT UNUSED(device), UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR UNUSED(param2)) +{ + ALCwinmmPlayback *self = (ALCwinmmPlayback*)instance; if(msg != WOM_DONE) return; - DecrementRef(&data->WaveBuffersCommitted); - PostThreadMessage(data->thread, msg, 0, param1); + DecrementRef(&self->WaveBuffersCommitted); + PostThreadMessage(self->thread, msg, 0, param1); } -FORCE_ALIGN static int PlaybackThreadProc(void *arg) +FORCE_ALIGN static int ALCwinmmPlayback_mixerProc(void *arg) { - ALCdevice *Device = (ALCdevice*)arg; - WinMMData *data = Device->ExtraData; + ALCwinmmPlayback *self = arg; + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; WAVEHDR *WaveHdr; MSG msg; @@ -188,78 +226,30 @@ FORCE_ALIGN static int PlaybackThreadProc(void *arg) if(msg.message != WOM_DONE) continue; - if(data->killNow) + if(self->killNow) { - if(ReadRef(&data->WaveBuffersCommitted) == 0) + if(ReadRef(&self->WaveBuffersCommitted) == 0) break; continue; } WaveHdr = ((WAVEHDR*)msg.lParam); - aluMixData(Device, WaveHdr->lpData, WaveHdr->dwBufferLength / - data->Format.nBlockAlign); + aluMixData(device, WaveHdr->lpData, WaveHdr->dwBufferLength / + self->Format.nBlockAlign); // Send buffer back to play more data - waveOutWrite(data->WaveHandle.Out, WaveHdr, sizeof(WAVEHDR)); - IncrementRef(&data->WaveBuffersCommitted); - } - - return 0; -} - -/* - WaveInProc - - Posts a message to 'CaptureThreadProc' everytime a WaveIn Buffer is completed and - returns to the application (with more data) -*/ -static void CALLBACK WaveInProc(HWAVEIN UNUSED(device), UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR UNUSED(param2)) -{ - ALCdevice *Device = (ALCdevice*)instance; - WinMMData *data = Device->ExtraData; - - if(msg != WIM_DATA) - return; - - DecrementRef(&data->WaveBuffersCommitted); - PostThreadMessage(data->thread, msg, 0, param1); -} - -static int CaptureThreadProc(void *arg) -{ - ALCdevice *Device = (ALCdevice*)arg; - WinMMData *data = Device->ExtraData; - WAVEHDR *WaveHdr; - MSG msg; - - althrd_setname(althrd_current(), "alsoft-record"); - - while(GetMessage(&msg, NULL, 0, 0)) - { - if(msg.message != WIM_DATA) - continue; - /* Don't wait for other buffers to finish before quitting. We're - * closing so we don't need them. */ - if(data->killNow) - break; - - WaveHdr = ((WAVEHDR*)msg.lParam); - WriteRingBuffer(data->Ring, (ALubyte*)WaveHdr->lpData, - WaveHdr->dwBytesRecorded/data->Format.nBlockAlign); - - // Send buffer back to capture more data - waveInAddBuffer(data->WaveHandle.In, WaveHdr, sizeof(WAVEHDR)); - IncrementRef(&data->WaveBuffersCommitted); + waveOutWrite(self->OutHdl, WaveHdr, sizeof(WAVEHDR)); + IncrementRef(&self->WaveBuffersCommitted); } return 0; } -static ALCenum WinMMOpenPlayback(ALCdevice *Device, const ALCchar *deviceName) +static ALCenum ALCwinmmPlayback_open(ALCwinmmPlayback *self, const ALCchar *deviceName) { - WinMMData *data = NULL; - const al_string *iter, *end; + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + const al_string *iter; UINT DeviceID; MMRESULT res; @@ -267,129 +257,109 @@ static ALCenum WinMMOpenPlayback(ALCdevice *Device, const ALCchar *deviceName) ProbePlaybackDevices(); // Find the Device ID matching the deviceName if valid - iter = VECTOR_ITER_BEGIN(PlaybackDevices); - end = VECTOR_ITER_END(PlaybackDevices); - for(;iter != end;iter++) - { - if(!al_string_empty(*iter) && - (!deviceName || al_string_cmp_cstr(*iter, deviceName) == 0)) - { - DeviceID = (UINT)(iter - VECTOR_ITER_BEGIN(PlaybackDevices)); - break; - } - } - if(iter == end) +#define MATCH_DEVNAME(iter) (!al_string_empty(*(iter)) && \ + (!deviceName || al_string_cmp_cstr(*(iter), deviceName) == 0)) + VECTOR_FIND_IF(iter, const al_string, PlaybackDevices, MATCH_DEVNAME); + if(iter == VECTOR_ITER_END(PlaybackDevices)) return ALC_INVALID_VALUE; +#undef MATCH_DEVNAME - data = calloc(1, sizeof(*data)); - if(!data) - return ALC_OUT_OF_MEMORY; - Device->ExtraData = data; + DeviceID = (UINT)(iter - VECTOR_ITER_BEGIN(PlaybackDevices)); retry_open: - memset(&data->Format, 0, sizeof(WAVEFORMATEX)); - if(Device->FmtType == DevFmtFloat) + memset(&self->Format, 0, sizeof(WAVEFORMATEX)); + if(device->FmtType == DevFmtFloat) { - data->Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; - data->Format.wBitsPerSample = 32; + self->Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; + self->Format.wBitsPerSample = 32; } else { - data->Format.wFormatTag = WAVE_FORMAT_PCM; - if(Device->FmtType == DevFmtUByte || Device->FmtType == DevFmtByte) - data->Format.wBitsPerSample = 8; + self->Format.wFormatTag = WAVE_FORMAT_PCM; + if(device->FmtType == DevFmtUByte || device->FmtType == DevFmtByte) + self->Format.wBitsPerSample = 8; else - data->Format.wBitsPerSample = 16; + self->Format.wBitsPerSample = 16; } - data->Format.nChannels = ((Device->FmtChans == DevFmtMono) ? 1 : 2); - data->Format.nBlockAlign = data->Format.wBitsPerSample * - data->Format.nChannels / 8; - data->Format.nSamplesPerSec = Device->Frequency; - data->Format.nAvgBytesPerSec = data->Format.nSamplesPerSec * - data->Format.nBlockAlign; - data->Format.cbSize = 0; + self->Format.nChannels = ((device->FmtChans == DevFmtMono) ? 1 : 2); + self->Format.nBlockAlign = self->Format.wBitsPerSample * + self->Format.nChannels / 8; + self->Format.nSamplesPerSec = device->Frequency; + self->Format.nAvgBytesPerSec = self->Format.nSamplesPerSec * + self->Format.nBlockAlign; + self->Format.cbSize = 0; - if((res=waveOutOpen(&data->WaveHandle.Out, DeviceID, &data->Format, (DWORD_PTR)&WaveOutProc, (DWORD_PTR)Device, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR) + if((res=waveOutOpen(&self->OutHdl, DeviceID, &self->Format, (DWORD_PTR)&ALCwinmmPlayback_waveOutProc, (DWORD_PTR)self, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR) { - if(Device->FmtType == DevFmtFloat) + if(device->FmtType == DevFmtFloat) { - Device->FmtType = DevFmtShort; + device->FmtType = DevFmtShort; goto retry_open; } ERR("waveOutOpen failed: %u\n", res); goto failure; } - al_string_copy(&Device->DeviceName, VECTOR_ELEM(PlaybackDevices, DeviceID)); + al_string_copy(&device->DeviceName, VECTOR_ELEM(PlaybackDevices, DeviceID)); return ALC_NO_ERROR; failure: - if(data->WaveHandle.Out) - waveOutClose(data->WaveHandle.Out); + if(self->OutHdl) + waveOutClose(self->OutHdl); + self->OutHdl = NULL; - free(data); - Device->ExtraData = NULL; return ALC_INVALID_VALUE; } -static void WinMMClosePlayback(ALCdevice *device) +static void ALCwinmmPlayback_close(ALCwinmmPlayback* UNUSED(self)) +{ } + +static ALCboolean ALCwinmmPlayback_reset(ALCwinmmPlayback *self) { - WinMMData *data = (WinMMData*)device->ExtraData; - - // Close the Wave device - waveOutClose(data->WaveHandle.Out); - data->WaveHandle.Out = 0; - - free(data); - device->ExtraData = NULL; -} - -static ALCboolean WinMMResetPlayback(ALCdevice *device) -{ - WinMMData *data = (WinMMData*)device->ExtraData; + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; device->UpdateSize = (ALuint)((ALuint64)device->UpdateSize * - data->Format.nSamplesPerSec / + self->Format.nSamplesPerSec / device->Frequency); device->UpdateSize = (device->UpdateSize*device->NumUpdates + 3) / 4; device->NumUpdates = 4; - device->Frequency = data->Format.nSamplesPerSec; + device->Frequency = self->Format.nSamplesPerSec; - if(data->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT) + if(self->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT) { - if(data->Format.wBitsPerSample == 32) + if(self->Format.wBitsPerSample == 32) device->FmtType = DevFmtFloat; else { - ERR("Unhandled IEEE float sample depth: %d\n", data->Format.wBitsPerSample); + ERR("Unhandled IEEE float sample depth: %d\n", self->Format.wBitsPerSample); return ALC_FALSE; } } - else if(data->Format.wFormatTag == WAVE_FORMAT_PCM) + else if(self->Format.wFormatTag == WAVE_FORMAT_PCM) { - if(data->Format.wBitsPerSample == 16) + if(self->Format.wBitsPerSample == 16) device->FmtType = DevFmtShort; - else if(data->Format.wBitsPerSample == 8) + else if(self->Format.wBitsPerSample == 8) device->FmtType = DevFmtUByte; else { - ERR("Unhandled PCM sample depth: %d\n", data->Format.wBitsPerSample); + ERR("Unhandled PCM sample depth: %d\n", self->Format.wBitsPerSample); return ALC_FALSE; } } else { - ERR("Unhandled format tag: 0x%04x\n", data->Format.wFormatTag); + ERR("Unhandled format tag: 0x%04x\n", self->Format.wFormatTag); return ALC_FALSE; } - if(data->Format.nChannels == 2) + if(self->Format.nChannels == 2) device->FmtChans = DevFmtStereo; - else if(data->Format.nChannels == 1) + else if(self->Format.nChannels == 1) device->FmtChans = DevFmtMono; else { - ERR("Unhandled channel count: %d\n", data->Format.nChannels); + ERR("Unhandled channel count: %d\n", self->Format.nChannels); return ALC_FALSE; } SetDefaultWFXChannelOrder(device); @@ -397,18 +367,18 @@ static ALCboolean WinMMResetPlayback(ALCdevice *device) return ALC_TRUE; } -static ALCboolean WinMMStartPlayback(ALCdevice *device) +static ALCboolean ALCwinmmPlayback_start(ALCwinmmPlayback *self) { - WinMMData *data = (WinMMData*)device->ExtraData; + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; ALbyte *BufferData; ALint BufferSize; ALuint i; - data->killNow = AL_FALSE; - if(althrd_create(&data->thread, PlaybackThreadProc, device) != althrd_success) + self->killNow = AL_FALSE; + if(althrd_create(&self->thread, ALCwinmmPlayback_mixerProc, self) != althrd_success) return ALC_FALSE; - InitRef(&data->WaveBuffersCommitted, 0); + InitRef(&self->WaveBuffersCommitted, 0); // Create 4 Buffers BufferSize = device->UpdateSize*device->NumUpdates / 4; @@ -417,49 +387,153 @@ static ALCboolean WinMMStartPlayback(ALCdevice *device) BufferData = calloc(4, BufferSize); for(i = 0;i < 4;i++) { - memset(&data->WaveBuffer[i], 0, sizeof(WAVEHDR)); - data->WaveBuffer[i].dwBufferLength = BufferSize; - data->WaveBuffer[i].lpData = ((i==0) ? (CHAR*)BufferData : - (data->WaveBuffer[i-1].lpData + - data->WaveBuffer[i-1].dwBufferLength)); - waveOutPrepareHeader(data->WaveHandle.Out, &data->WaveBuffer[i], sizeof(WAVEHDR)); - waveOutWrite(data->WaveHandle.Out, &data->WaveBuffer[i], sizeof(WAVEHDR)); - IncrementRef(&data->WaveBuffersCommitted); + memset(&self->WaveBuffer[i], 0, sizeof(WAVEHDR)); + self->WaveBuffer[i].dwBufferLength = BufferSize; + self->WaveBuffer[i].lpData = ((i==0) ? (CHAR*)BufferData : + (self->WaveBuffer[i-1].lpData + + self->WaveBuffer[i-1].dwBufferLength)); + waveOutPrepareHeader(self->OutHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); + waveOutWrite(self->OutHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); + IncrementRef(&self->WaveBuffersCommitted); } return ALC_TRUE; } -static void WinMMStopPlayback(ALCdevice *device) +static void ALCwinmmPlayback_stop(ALCwinmmPlayback *self) { - WinMMData *data = (WinMMData*)device->ExtraData; void *buffer = NULL; int i; - if(data->killNow) + if(self->killNow) return; // Set flag to stop processing headers - data->killNow = AL_TRUE; - althrd_join(data->thread, &i); + self->killNow = AL_TRUE; + althrd_join(self->thread, &i); // Release the wave buffers for(i = 0;i < 4;i++) { - waveOutUnprepareHeader(data->WaveHandle.Out, &data->WaveBuffer[i], sizeof(WAVEHDR)); - if(i == 0) buffer = data->WaveBuffer[i].lpData; - data->WaveBuffer[i].lpData = NULL; + waveOutUnprepareHeader(self->OutHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); + if(i == 0) buffer = self->WaveBuffer[i].lpData; + self->WaveBuffer[i].lpData = NULL; } free(buffer); } -static ALCenum WinMMOpenCapture(ALCdevice *Device, const ALCchar *deviceName) + +typedef struct ALCwinmmCapture { + DERIVE_FROM_TYPE(ALCbackend); + + RefCount WaveBuffersCommitted; + WAVEHDR WaveBuffer[4]; + + HWAVEIN InHdl; + + RingBuffer *Ring; + + WAVEFORMATEX Format; + + volatile ALboolean killNow; + althrd_t thread; +} ALCwinmmCapture; + +static void ALCwinmmCapture_Construct(ALCwinmmCapture *self, ALCdevice *device); +static void ALCwinmmCapture_Destruct(ALCwinmmCapture *self); + +static void CALLBACK ALCwinmmCapture_waveInProc(HWAVEIN device, UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR param2); +static int ALCwinmmCapture_captureProc(void *arg); + +static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name); +static void ALCwinmmCapture_close(ALCwinmmCapture *self); +static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, ALCboolean, reset) +static ALCboolean ALCwinmmCapture_start(ALCwinmmCapture *self); +static void ALCwinmmCapture_stop(ALCwinmmCapture *self); +static ALCenum ALCwinmmCapture_captureSamples(ALCwinmmCapture *self, ALCvoid *buffer, ALCuint samples); +static ALCuint ALCwinmmCapture_availableSamples(ALCwinmmCapture *self); +static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, ALint64, getLatency) +static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, void, lock) +static DECLARE_FORWARD(ALCwinmmCapture, ALCbackend, void, unlock) +DECLARE_DEFAULT_ALLOCATORS(ALCwinmmCapture) + +DEFINE_ALCBACKEND_VTABLE(ALCwinmmCapture); + + +static void ALCwinmmCapture_Construct(ALCwinmmCapture *self, ALCdevice *device) { - const al_string *iter, *end; + ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); + SET_VTABLE2(ALCwinmmCapture, ALCbackend, self); + + InitRef(&self->WaveBuffersCommitted, 0); + self->InHdl = NULL; + + self->killNow = AL_TRUE; +} + +static void ALCwinmmCapture_Destruct(ALCwinmmCapture *self) +{ + if(self->InHdl) + waveInClose(self->InHdl); + self->InHdl = 0; + + ALCbackend_Destruct(STATIC_CAST(ALCbackend, self)); +} + + +/* ALCwinmmCapture_waveInProc + * + * Posts a message to 'ALCwinmmCapture_captureProc' everytime a WaveIn Buffer + * is completed and returns to the application (with more data). + */ +static void CALLBACK ALCwinmmCapture_waveInProc(HWAVEIN UNUSED(device), UINT msg, DWORD_PTR instance, DWORD_PTR param1, DWORD_PTR UNUSED(param2)) +{ + ALCwinmmCapture *self = (ALCwinmmCapture*)instance; + + if(msg != WIM_DATA) + return; + + DecrementRef(&self->WaveBuffersCommitted); + PostThreadMessage(self->thread, msg, 0, param1); +} + +static int ALCwinmmCapture_captureProc(void *arg) +{ + ALCwinmmCapture *self = arg; + WAVEHDR *WaveHdr; + MSG msg; + + althrd_setname(althrd_current(), RECORD_THREAD_NAME); + + while(GetMessage(&msg, NULL, 0, 0)) + { + if(msg.message != WIM_DATA) + continue; + /* Don't wait for other buffers to finish before quitting. We're + * closing so we don't need them. */ + if(self->killNow) + break; + + WaveHdr = ((WAVEHDR*)msg.lParam); + WriteRingBuffer(self->Ring, (ALubyte*)WaveHdr->lpData, + WaveHdr->dwBytesRecorded/self->Format.nBlockAlign); + + // Send buffer back to capture more data + waveInAddBuffer(self->InHdl, WaveHdr, sizeof(WAVEHDR)); + IncrementRef(&self->WaveBuffersCommitted); + } + + return 0; +} + + +static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name) +{ + ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; + const al_string *iter; ALbyte *BufferData = NULL; DWORD CapturedDataSize; - WinMMData *data = NULL; ALint BufferSize; UINT DeviceID; MMRESULT res; @@ -469,21 +543,15 @@ static ALCenum WinMMOpenCapture(ALCdevice *Device, const ALCchar *deviceName) ProbeCaptureDevices(); // Find the Device ID matching the deviceName if valid - iter = VECTOR_ITER_BEGIN(CaptureDevices); - end = VECTOR_ITER_END(CaptureDevices); - for(;iter != end;iter++) - { - if(!al_string_empty(*iter) && - (!deviceName || al_string_cmp_cstr(*iter, deviceName) == 0)) - { - DeviceID = (UINT)(iter - VECTOR_ITER_BEGIN(CaptureDevices)); - break; - } - } - if(iter == end) +#define MATCH_DEVNAME(iter) (!al_string_empty(*(iter)) && (!name || al_string_cmp_cstr(*iter, name) == 0)) + VECTOR_FIND_IF(iter, const al_string, CaptureDevices, MATCH_DEVNAME); + if(iter == VECTOR_ITER_END(CaptureDevices)) return ALC_INVALID_VALUE; +#undef MATCH_DEVNAME - switch(Device->FmtChans) + DeviceID = (UINT)(iter - VECTOR_ITER_BEGIN(CaptureDevices)); + + switch(device->FmtChans) { case DevFmtMono: case DevFmtStereo: @@ -491,13 +559,14 @@ static ALCenum WinMMOpenCapture(ALCdevice *Device, const ALCchar *deviceName) case DevFmtQuad: case DevFmtX51: - case DevFmtX51Side: + case DevFmtX51Rear: case DevFmtX61: case DevFmtX71: + case DevFmtBFormat3D: return ALC_INVALID_ENUM; } - switch(Device->FmtType) + switch(device->FmtType) { case DevFmtUByte: case DevFmtShort: @@ -511,147 +580,134 @@ static ALCenum WinMMOpenCapture(ALCdevice *Device, const ALCchar *deviceName) return ALC_INVALID_ENUM; } - data = calloc(1, sizeof(*data)); - if(!data) - return ALC_OUT_OF_MEMORY; - Device->ExtraData = data; - - memset(&data->Format, 0, sizeof(WAVEFORMATEX)); - data->Format.wFormatTag = ((Device->FmtType == DevFmtFloat) ? + memset(&self->Format, 0, sizeof(WAVEFORMATEX)); + self->Format.wFormatTag = ((device->FmtType == DevFmtFloat) ? WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM); - data->Format.nChannels = ChannelsFromDevFmt(Device->FmtChans); - data->Format.wBitsPerSample = BytesFromDevFmt(Device->FmtType) * 8; - data->Format.nBlockAlign = data->Format.wBitsPerSample * - data->Format.nChannels / 8; - data->Format.nSamplesPerSec = Device->Frequency; - data->Format.nAvgBytesPerSec = data->Format.nSamplesPerSec * - data->Format.nBlockAlign; - data->Format.cbSize = 0; + self->Format.nChannels = ChannelsFromDevFmt(device->FmtChans); + self->Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8; + self->Format.nBlockAlign = self->Format.wBitsPerSample * + self->Format.nChannels / 8; + self->Format.nSamplesPerSec = device->Frequency; + self->Format.nAvgBytesPerSec = self->Format.nSamplesPerSec * + self->Format.nBlockAlign; + self->Format.cbSize = 0; - if((res=waveInOpen(&data->WaveHandle.In, DeviceID, &data->Format, (DWORD_PTR)&WaveInProc, (DWORD_PTR)Device, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR) + if((res=waveInOpen(&self->InHdl, DeviceID, &self->Format, (DWORD_PTR)&ALCwinmmCapture_waveInProc, (DWORD_PTR)self, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR) { ERR("waveInOpen failed: %u\n", res); goto failure; } // Allocate circular memory buffer for the captured audio - CapturedDataSize = Device->UpdateSize*Device->NumUpdates; + CapturedDataSize = device->UpdateSize*device->NumUpdates; // Make sure circular buffer is at least 100ms in size - if(CapturedDataSize < (data->Format.nSamplesPerSec / 10)) - CapturedDataSize = data->Format.nSamplesPerSec / 10; + if(CapturedDataSize < (self->Format.nSamplesPerSec / 10)) + CapturedDataSize = self->Format.nSamplesPerSec / 10; - data->Ring = CreateRingBuffer(data->Format.nBlockAlign, CapturedDataSize); - if(!data->Ring) - goto failure; + self->Ring = CreateRingBuffer(self->Format.nBlockAlign, CapturedDataSize); + if(!self->Ring) goto failure; - InitRef(&data->WaveBuffersCommitted, 0); + InitRef(&self->WaveBuffersCommitted, 0); // Create 4 Buffers of 50ms each - BufferSize = data->Format.nAvgBytesPerSec / 20; - BufferSize -= (BufferSize % data->Format.nBlockAlign); + BufferSize = self->Format.nAvgBytesPerSec / 20; + BufferSize -= (BufferSize % self->Format.nBlockAlign); BufferData = calloc(4, BufferSize); - if(!BufferData) - goto failure; + if(!BufferData) goto failure; for(i = 0;i < 4;i++) { - memset(&data->WaveBuffer[i], 0, sizeof(WAVEHDR)); - data->WaveBuffer[i].dwBufferLength = BufferSize; - data->WaveBuffer[i].lpData = ((i==0) ? (CHAR*)BufferData : - (data->WaveBuffer[i-1].lpData + - data->WaveBuffer[i-1].dwBufferLength)); - data->WaveBuffer[i].dwFlags = 0; - data->WaveBuffer[i].dwLoops = 0; - waveInPrepareHeader(data->WaveHandle.In, &data->WaveBuffer[i], sizeof(WAVEHDR)); - waveInAddBuffer(data->WaveHandle.In, &data->WaveBuffer[i], sizeof(WAVEHDR)); - IncrementRef(&data->WaveBuffersCommitted); + memset(&self->WaveBuffer[i], 0, sizeof(WAVEHDR)); + self->WaveBuffer[i].dwBufferLength = BufferSize; + self->WaveBuffer[i].lpData = ((i==0) ? (CHAR*)BufferData : + (self->WaveBuffer[i-1].lpData + + self->WaveBuffer[i-1].dwBufferLength)); + self->WaveBuffer[i].dwFlags = 0; + self->WaveBuffer[i].dwLoops = 0; + waveInPrepareHeader(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); + waveInAddBuffer(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); + IncrementRef(&self->WaveBuffersCommitted); } - if(althrd_create(&data->thread, CaptureThreadProc, Device) != althrd_success) + self->killNow = AL_FALSE; + if(althrd_create(&self->thread, ALCwinmmCapture_captureProc, self) != althrd_success) goto failure; - al_string_copy(&Device->DeviceName, VECTOR_ELEM(CaptureDevices, DeviceID)); + al_string_copy(&device->DeviceName, VECTOR_ELEM(CaptureDevices, DeviceID)); return ALC_NO_ERROR; failure: if(BufferData) { for(i = 0;i < 4;i++) - waveInUnprepareHeader(data->WaveHandle.In, &data->WaveBuffer[i], sizeof(WAVEHDR)); + waveInUnprepareHeader(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); free(BufferData); } - if(data->Ring) - DestroyRingBuffer(data->Ring); + if(self->Ring) + DestroyRingBuffer(self->Ring); + self->Ring = NULL; - if(data->WaveHandle.In) - waveInClose(data->WaveHandle.In); + if(self->InHdl) + waveInClose(self->InHdl); + self->InHdl = NULL; - free(data); - Device->ExtraData = NULL; return ALC_INVALID_VALUE; } -static void WinMMCloseCapture(ALCdevice *Device) +static void ALCwinmmCapture_close(ALCwinmmCapture *self) { - WinMMData *data = (WinMMData*)Device->ExtraData; void *buffer = NULL; int i; /* Tell the processing thread to quit and wait for it to do so. */ - data->killNow = AL_TRUE; - PostThreadMessage(data->thread, WM_QUIT, 0, 0); + self->killNow = AL_TRUE; + PostThreadMessage(self->thread, WM_QUIT, 0, 0); - althrd_join(data->thread, &i); + althrd_join(self->thread, &i); /* Make sure capture is stopped and all pending buffers are flushed. */ - waveInReset(data->WaveHandle.In); + waveInReset(self->InHdl); // Release the wave buffers for(i = 0;i < 4;i++) { - waveInUnprepareHeader(data->WaveHandle.In, &data->WaveBuffer[i], sizeof(WAVEHDR)); - if(i == 0) buffer = data->WaveBuffer[i].lpData; - data->WaveBuffer[i].lpData = NULL; + waveInUnprepareHeader(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); + if(i == 0) buffer = self->WaveBuffer[i].lpData; + self->WaveBuffer[i].lpData = NULL; } free(buffer); - DestroyRingBuffer(data->Ring); - data->Ring = NULL; + DestroyRingBuffer(self->Ring); + self->Ring = NULL; // Close the Wave device - waveInClose(data->WaveHandle.In); - data->WaveHandle.In = 0; - - free(data); - Device->ExtraData = NULL; + waveInClose(self->InHdl); + self->InHdl = NULL; } -static void WinMMStartCapture(ALCdevice *Device) +static ALCboolean ALCwinmmCapture_start(ALCwinmmCapture *self) { - WinMMData *data = (WinMMData*)Device->ExtraData; - waveInStart(data->WaveHandle.In); + waveInStart(self->InHdl); + return ALC_TRUE; } -static void WinMMStopCapture(ALCdevice *Device) +static void ALCwinmmCapture_stop(ALCwinmmCapture *self) { - WinMMData *data = (WinMMData*)Device->ExtraData; - waveInStop(data->WaveHandle.In); + waveInStop(self->InHdl); } -static ALCenum WinMMCaptureSamples(ALCdevice *Device, ALCvoid *Buffer, ALCuint Samples) +static ALCenum ALCwinmmCapture_captureSamples(ALCwinmmCapture *self, ALCvoid *buffer, ALCuint samples) { - WinMMData *data = (WinMMData*)Device->ExtraData; - ReadRingBuffer(data->Ring, Buffer, Samples); + ReadRingBuffer(self->Ring, buffer, samples); return ALC_NO_ERROR; } -static ALCuint WinMMAvailableSamples(ALCdevice *Device) +static ALCuint ALCwinmmCapture_availableSamples(ALCwinmmCapture *self) { - WinMMData *data = (WinMMData*)Device->ExtraData; - return RingBufferSize(data->Ring); + return RingBufferSize(self->Ring); } @@ -666,31 +722,29 @@ static inline void AppendCaptureDeviceList2(const al_string *name) AppendCaptureDeviceList(al_string_get_cstr(*name)); } -static const BackendFuncs WinMMFuncs = { - WinMMOpenPlayback, - WinMMClosePlayback, - WinMMResetPlayback, - WinMMStartPlayback, - WinMMStopPlayback, - WinMMOpenCapture, - WinMMCloseCapture, - WinMMStartCapture, - WinMMStopCapture, - WinMMCaptureSamples, - WinMMAvailableSamples, - ALCdevice_GetLatencyDefault -}; +typedef struct ALCwinmmBackendFactory { + DERIVE_FROM_TYPE(ALCbackendFactory); +} ALCwinmmBackendFactory; +#define ALCWINMMBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCwinmmBackendFactory, ALCbackendFactory) } } -ALCboolean alcWinMMInit(BackendFuncs *FuncList) +static ALCboolean ALCwinmmBackendFactory_init(ALCwinmmBackendFactory *self); +static void ALCwinmmBackendFactory_deinit(ALCwinmmBackendFactory *self); +static ALCboolean ALCwinmmBackendFactory_querySupport(ALCwinmmBackendFactory *self, ALCbackend_Type type); +static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory *self, enum DevProbe type); +static ALCbackend* ALCwinmmBackendFactory_createBackend(ALCwinmmBackendFactory *self, ALCdevice *device, ALCbackend_Type type); + +DEFINE_ALCBACKENDFACTORY_VTABLE(ALCwinmmBackendFactory); + + +static ALCboolean ALCwinmmBackendFactory_init(ALCwinmmBackendFactory* UNUSED(self)) { VECTOR_INIT(PlaybackDevices); VECTOR_INIT(CaptureDevices); - *FuncList = WinMMFuncs; return ALC_TRUE; } -void alcWinMMDeinit() +static void ALCwinmmBackendFactory_deinit(ALCwinmmBackendFactory* UNUSED(self)) { clear_devlist(&PlaybackDevices); VECTOR_DEINIT(PlaybackDevices); @@ -699,7 +753,14 @@ void alcWinMMDeinit() VECTOR_DEINIT(CaptureDevices); } -void alcWinMMProbe(enum DevProbe type) +static ALCboolean ALCwinmmBackendFactory_querySupport(ALCwinmmBackendFactory* UNUSED(self), ALCbackend_Type type) +{ + if(type == ALCbackend_Playback || type == ALCbackend_Capture) + return ALC_TRUE; + return ALC_FALSE; +} + +static void ALCwinmmBackendFactory_probe(ALCwinmmBackendFactory* UNUSED(self), enum DevProbe type) { switch(type) { @@ -714,3 +775,29 @@ void alcWinMMProbe(enum DevProbe type) break; } } + +static ALCbackend* ALCwinmmBackendFactory_createBackend(ALCwinmmBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type) +{ + if(type == ALCbackend_Playback) + { + ALCwinmmPlayback *backend; + NEW_OBJ(backend, ALCwinmmPlayback)(device); + if(!backend) return NULL; + return STATIC_CAST(ALCbackend, backend); + } + if(type == ALCbackend_Capture) + { + ALCwinmmCapture *backend; + NEW_OBJ(backend, ALCwinmmCapture)(device); + if(!backend) return NULL; + return STATIC_CAST(ALCbackend, backend); + } + + return NULL; +} + +ALCbackendFactory *ALCwinmmBackendFactory_getFactory(void) +{ + static ALCwinmmBackendFactory factory = ALCWINMMBACKENDFACTORY_INITIALIZER; + return STATIC_CAST(ALCbackendFactory, &factory); +} diff --git a/libs/openal-soft/Alc/bs2b.c b/libs/openal-soft/Alc/bs2b.c index d936f75a..6c3f052b 100644 --- a/libs/openal-soft/Alc/bs2b.c +++ b/libs/openal-soft/Alc/bs2b.c @@ -29,9 +29,6 @@ #include "bs2b.h" #include "alu.h" -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif /* Set up all data. */ static void init(struct bs2b *bs2b) @@ -40,8 +37,6 @@ static void init(struct bs2b *bs2b) float G_lo, G_hi; float x, g; - bs2b->srate = clampi(bs2b->srate, 2000, 192000); - switch(bs2b->level) { case BS2B_LOW_CLEVEL: /* Low crossfeed level */ @@ -105,31 +100,25 @@ static void init(struct bs2b *bs2b) bs2b->a1_hi = -x * g; } /* init */ + /* Exported functions. * See descriptions in "bs2b.h" */ -void bs2b_set_level(struct bs2b *bs2b, int level) +void bs2b_set_params(struct bs2b *bs2b, int level, int srate) { - if(level == bs2b->level) - return; + if(srate <= 0) srate = 1; + bs2b->level = level; + bs2b->srate = srate; init(bs2b); -} /* bs2b_set_level */ +} /* bs2b_set_params */ int bs2b_get_level(struct bs2b *bs2b) { return bs2b->level; } /* bs2b_get_level */ -void bs2b_set_srate(struct bs2b *bs2b, int srate) -{ - if (srate == bs2b->srate) - return; - bs2b->srate = srate; - init(bs2b); -} /* bs2b_set_srate */ - int bs2b_get_srate(struct bs2b *bs2b) { return bs2b->srate; diff --git a/libs/openal-soft/Alc/effects/autowah.c b/libs/openal-soft/Alc/effects/autowah.c index c8317c8b..6770f719 100644 --- a/libs/openal-soft/Alc/effects/autowah.c +++ b/libs/openal-soft/Alc/effects/autowah.c @@ -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 */ @@ -31,15 +31,15 @@ /* Auto-wah is simply a low-pass filter with a cutoff frequency that shifts up * or down depending on the input signal, and a resonant peak at the cutoff. * - * Currently, we assume a cutoff frequency range of 500hz (no amplitude) to - * 3khz (peak gain). Peak gain is assumed to be in normalized scale. + * Currently, we assume a cutoff frequency range of 20hz (no amplitude) to + * 20khz (peak gain). Peak gain is assumed to be in normalized scale. */ typedef struct ALautowahState { DERIVE_FROM_TYPE(ALeffectState); /* Effect gains for each channel */ - ALfloat Gain[MaxChannels]; + ALfloat Gain[MAX_OUTPUT_CHANNELS]; /* Effect parameters */ ALfloat AttackRate; @@ -66,7 +66,6 @@ static ALboolean ALautowahState_deviceUpdate(ALautowahState *state, ALCdevice *d static ALvoid ALautowahState_update(ALautowahState *state, ALCdevice *device, const ALeffectslot *slot) { ALfloat attackTime, releaseTime; - ALfloat gain; attackTime = slot->EffectProps.Autowah.AttackTime * state->Frequency; releaseTime = slot->EffectProps.Autowah.ReleaseTime * state->Frequency; @@ -76,19 +75,18 @@ static ALvoid ALautowahState_update(ALautowahState *state, ALCdevice *device, co state->PeakGain = slot->EffectProps.Autowah.PeakGain; state->Resonance = slot->EffectProps.Autowah.Resonance; - gain = sqrtf(1.0f / device->NumChan) * slot->Gain; - SetGains(device, gain, state->Gain); + ComputeAmbientGains(device, slot->Gain, state->Gain); } -static ALvoid ALautowahState_process(ALautowahState *state, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[BUFFERSIZE]) +static ALvoid ALautowahState_process(ALautowahState *state, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[BUFFERSIZE], ALuint NumChannels) { ALuint it, kt; ALuint base; for(base = 0;base < SamplesToDo;) { - ALfloat temps[64]; - ALuint td = minu(SamplesToDo-base, 64); + ALfloat temps[256]; + ALuint td = minu(256, SamplesToDo-base); ALfloat gain = state->GainCtrl; for(it = 0;it < td;it++) @@ -114,7 +112,7 @@ static ALvoid ALautowahState_process(ALautowahState *state, ALuint SamplesToDo, * ALfilterType_LowPass. However, instead of passing a bandwidth, * we use the resonance property for Q. This also inlines the call. */ - w0 = F_2PI * cutoff / state->Frequency; + w0 = F_TAU * cutoff / state->Frequency; /* FIXME: Resonance controls the resonant peak, or Q. How? Not sure * that Q = resonance*0.1. */ @@ -137,10 +135,10 @@ static ALvoid ALautowahState_process(ALautowahState *state, ALuint SamplesToDo, } state->GainCtrl = gain; - for(kt = 0;kt < MaxChannels;kt++) + for(kt = 0;kt < NumChannels;kt++) { ALfloat gain = state->Gain[kt]; - if(!(gain > GAIN_SILENCE_THRESHOLD)) + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) continue; for(it = 0;it < td;it++) diff --git a/libs/openal-soft/Alc/effects/chorus.c b/libs/openal-soft/Alc/effects/chorus.c index a6bb199e..7aa5898b 100644 --- a/libs/openal-soft/Alc/effects/chorus.c +++ b/libs/openal-soft/Alc/effects/chorus.c @@ -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 */ @@ -46,7 +46,7 @@ typedef struct ALchorusState { ALint lfo_disp; /* Gains for left and right sides */ - ALfloat Gain[2][MaxChannels]; + ALfloat Gain[2][MAX_OUTPUT_CHANNELS]; /* effect parameters */ enum ChorusWaveForm waveform; @@ -93,6 +93,8 @@ static ALboolean ALchorusState_deviceUpdate(ALchorusState *state, ALCdevice *Dev static ALvoid ALchorusState_update(ALchorusState *state, ALCdevice *Device, const ALeffectslot *Slot) { + static const ALfloat left_dir[3] = { -1.0f, 0.0f, 0.0f }; + static const ALfloat right_dir[3] = { 1.0f, 0.0f, 0.0f }; ALfloat frequency = (ALfloat)Device->Frequency; ALfloat rate; ALint phase; @@ -111,8 +113,8 @@ static ALvoid ALchorusState_update(ALchorusState *state, ALCdevice *Device, cons state->delay = fastf2i(Slot->EffectProps.Chorus.Delay * frequency); /* Gains for left and right sides */ - ComputeAngleGains(Device, atan2f(-1.0f, 0.0f), 0.0f, Slot->Gain, state->Gain[0]); - ComputeAngleGains(Device, atan2f(+1.0f, 0.0f), 0.0f, Slot->Gain, state->Gain[1]); + ComputeDirectionalGains(Device, left_dir, Slot->Gain, state->Gain[0]); + ComputeDirectionalGains(Device, right_dir, Slot->Gain, state->Gain[1]); phase = Slot->EffectProps.Chorus.Phase; rate = Slot->EffectProps.Chorus.Rate; @@ -132,7 +134,7 @@ static ALvoid ALchorusState_update(ALchorusState *state, ALCdevice *Device, cons state->lfo_scale = 4.0f / state->lfo_range; break; case CWF_Sinusoid: - state->lfo_scale = F_2PI / state->lfo_range; + state->lfo_scale = F_TAU / state->lfo_range; break; } @@ -201,15 +203,15 @@ DECL_TEMPLATE(Sinusoid) #undef DECL_TEMPLATE -static ALvoid ALchorusState_process(ALchorusState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE]) +static ALvoid ALchorusState_process(ALchorusState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { ALuint it, kt; ALuint base; for(base = 0;base < SamplesToDo;) { - ALfloat temps[64][2]; - ALuint td = minu(SamplesToDo-base, 64); + ALfloat temps[128][2]; + ALuint td = minu(128, SamplesToDo-base); switch(state->waveform) { @@ -221,17 +223,17 @@ static ALvoid ALchorusState_process(ALchorusState *state, ALuint SamplesToDo, co break; } - for(kt = 0;kt < MaxChannels;kt++) + for(kt = 0;kt < NumChannels;kt++) { ALfloat gain = state->Gain[0][kt]; - if(gain > GAIN_SILENCE_THRESHOLD) + if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) { for(it = 0;it < td;it++) SamplesOut[kt][it+base] += temps[it][0] * gain; } gain = state->Gain[1][kt]; - if(gain > GAIN_SILENCE_THRESHOLD) + if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) { for(it = 0;it < td;it++) SamplesOut[kt][it+base] += temps[it][1] * gain; diff --git a/libs/openal-soft/Alc/effects/compressor.c b/libs/openal-soft/Alc/effects/compressor.c index 9728cabe..9859a085 100644 --- a/libs/openal-soft/Alc/effects/compressor.c +++ b/libs/openal-soft/Alc/effects/compressor.c @@ -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 */ @@ -31,7 +31,7 @@ typedef struct ALcompressorState { DERIVE_FROM_TYPE(ALeffectState); /* Effect gains for each channel */ - ALfloat Gain[MaxChannels]; + ALfloat Gain[MAX_OUTPUT_CHANNELS]; /* Effect parameters */ ALboolean Enabled; @@ -55,25 +55,22 @@ static ALboolean ALcompressorState_deviceUpdate(ALcompressorState *state, ALCdev return AL_TRUE; } -static ALvoid ALcompressorState_update(ALcompressorState *state, ALCdevice *Device, const ALeffectslot *Slot) +static ALvoid ALcompressorState_update(ALcompressorState *state, ALCdevice *device, const ALeffectslot *slot) { - ALfloat gain; + state->Enabled = slot->EffectProps.Compressor.OnOff; - state->Enabled = Slot->EffectProps.Compressor.OnOff; - - gain = sqrtf(1.0f / Device->NumChan) * Slot->Gain; - SetGains(Device, gain, state->Gain); + ComputeAmbientGains(device, slot->Gain, state->Gain); } -static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[BUFFERSIZE]) +static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[BUFFERSIZE], ALuint NumChannels) { ALuint it, kt; ALuint base; for(base = 0;base < SamplesToDo;) { - ALfloat temps[64]; - ALuint td = minu(SamplesToDo-base, 64); + ALfloat temps[256]; + ALuint td = minu(256, SamplesToDo-base); if(state->Enabled) { @@ -119,10 +116,10 @@ static ALvoid ALcompressorState_process(ALcompressorState *state, ALuint Samples } - for(kt = 0;kt < MaxChannels;kt++) + for(kt = 0;kt < NumChannels;kt++) { ALfloat gain = state->Gain[kt]; - if(!(gain > GAIN_SILENCE_THRESHOLD)) + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) continue; for(it = 0;it < td;it++) diff --git a/libs/openal-soft/Alc/effects/dedicated.c b/libs/openal-soft/Alc/effects/dedicated.c index 89af1c84..e09cc682 100644 --- a/libs/openal-soft/Alc/effects/dedicated.c +++ b/libs/openal-soft/Alc/effects/dedicated.c @@ -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 */ @@ -32,7 +32,7 @@ typedef struct ALdedicatedState { DERIVE_FROM_TYPE(ALeffectState); - ALfloat gains[MaxChannels]; + ALfloat gains[MAX_OUTPUT_CHANNELS]; } ALdedicatedState; @@ -48,27 +48,41 @@ static ALboolean ALdedicatedState_deviceUpdate(ALdedicatedState *UNUSED(state), static ALvoid ALdedicatedState_update(ALdedicatedState *state, ALCdevice *device, const ALeffectslot *Slot) { ALfloat Gain; - ALsizei s; + ALuint i; + + for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) + state->gains[i] = 0.0f; Gain = Slot->Gain * Slot->EffectProps.Dedicated.Gain; - if(Slot->EffectType == AL_EFFECT_DEDICATED_DIALOGUE) - ComputeAngleGains(device, atan2f(0.0f, 1.0f), 0.0f, Gain, state->gains); - else if(Slot->EffectType == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT) + if(Slot->EffectType == AL_EFFECT_DEDICATED_LOW_FREQUENCY_EFFECT) { - for(s = 0;s < MaxChannels;s++) - state->gains[s] = 0.0f; - state->gains[LFE] = Gain; + int idx; + if((idx=GetChannelIdxByName(device, LFE)) != -1) + state->gains[idx] = Gain; + } + else if(Slot->EffectType == AL_EFFECT_DEDICATED_DIALOGUE) + { + int idx; + /* Dialog goes to the front-center speaker if it exists, otherwise it + * plays from the front-center location. */ + if((idx=GetChannelIdxByName(device, FrontCenter)) != -1) + state->gains[idx] = Gain; + else + { + static const ALfloat front_dir[3] = { 0.0f, 0.0f, -1.0f }; + ComputeDirectionalGains(device, front_dir, Gain, state->gains); + } } } -static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE]) +static ALvoid ALdedicatedState_process(ALdedicatedState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { const ALfloat *gains = state->gains; ALuint i, c; - for(c = 0;c < MaxChannels;c++) + for(c = 0;c < NumChannels;c++) { - if(!(gains[c] > GAIN_SILENCE_THRESHOLD)) + if(!(fabsf(gains[c]) > GAIN_SILENCE_THRESHOLD)) continue; for(i = 0;i < SamplesToDo;i++) @@ -94,7 +108,7 @@ ALeffectState *ALdedicatedStateFactory_create(ALdedicatedStateFactory *UNUSED(fa if(!state) return NULL; SET_VTABLE2(ALdedicatedState, ALeffectState, state); - for(s = 0;s < MaxChannels;s++) + for(s = 0;s < MAX_OUTPUT_CHANNELS;s++) state->gains[s] = 0.0f; return STATIC_CAST(ALeffectState, state); diff --git a/libs/openal-soft/Alc/effects/distortion.c b/libs/openal-soft/Alc/effects/distortion.c index b535655b..221cec39 100644 --- a/libs/openal-soft/Alc/effects/distortion.c +++ b/libs/openal-soft/Alc/effects/distortion.c @@ -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 */ @@ -34,7 +34,7 @@ typedef struct ALdistortionState { DERIVE_FROM_TYPE(ALeffectState); /* Effect gains for each channel */ - ALfloat Gain[MaxChannels]; + ALfloat Gain[MAX_OUTPUT_CHANNELS]; /* Effect parameters */ ALfilterState lowpass; @@ -58,7 +58,6 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, ALCdevice *Devi ALfloat bandwidth; ALfloat cutoff; ALfloat edge; - ALfloat gain; /* Store distorted signal attenuation settings */ state->attenuation = Slot->EffectProps.Distortion.Gain; @@ -73,23 +72,23 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, ALCdevice *Devi /* Bandwidth value is constant in octaves */ bandwidth = (cutoff / 2.0f) / (cutoff * 0.67f); ALfilterState_setParams(&state->lowpass, ALfilterType_LowPass, 1.0f, - cutoff / (frequency*4.0f), bandwidth); + cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth) + ); /* Bandpass filter */ cutoff = Slot->EffectProps.Distortion.EQCenter; /* Convert bandwidth in Hz to octaves */ bandwidth = Slot->EffectProps.Distortion.EQBandwidth / (cutoff * 0.67f); ALfilterState_setParams(&state->bandpass, ALfilterType_BandPass, 1.0f, - cutoff / (frequency*4.0f), bandwidth); + cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth) + ); - gain = sqrtf(1.0f / Device->NumChan) * Slot->Gain; - SetGains(Device, gain, state->Gain); + ComputeAmbientGains(Device, Slot->Gain, state->Gain); } -static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE]) +static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { const ALfloat fc = state->edge_coeff; - float oversample_buffer[64][4]; ALuint base; ALuint it; ALuint ot; @@ -97,8 +96,8 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint Samples for(base = 0;base < SamplesToDo;) { - ALfloat temps[64]; - ALuint td = minu(SamplesToDo-base, 64); + float oversample_buffer[64][4]; + ALuint td = minu(64, SamplesToDo-base); /* Perform 4x oversampling to avoid aliasing. */ /* Oversampling greatly improves distortion */ @@ -150,20 +149,19 @@ static ALvoid ALdistortionState_process(ALdistortionState *state, ALuint Samples smp = ALfilterState_processSingle(&state->bandpass, smp); oversample_buffer[it][ot] = smp; } - - /* Fourth step, final, do attenuation and perform decimation, */ - /* store only one sample out of 4. */ - temps[it] = oversample_buffer[it][0] * state->attenuation; } - for(kt = 0;kt < MaxChannels;kt++) + for(kt = 0;kt < NumChannels;kt++) { - ALfloat gain = state->Gain[kt]; - if(!(gain > GAIN_SILENCE_THRESHOLD)) + /* Fourth step, final, do attenuation and perform decimation, + * store only one sample out of 4. + */ + ALfloat gain = state->Gain[kt] * state->attenuation; + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) continue; for(it = 0;it < td;it++) - SamplesOut[kt][base+it] += gain * temps[it]; + SamplesOut[kt][base+it] += gain * oversample_buffer[it][0]; } base += td; diff --git a/libs/openal-soft/Alc/effects/echo.c b/libs/openal-soft/Alc/effects/echo.c index 049ae9c7..f5a53c36 100644 --- a/libs/openal-soft/Alc/effects/echo.c +++ b/libs/openal-soft/Alc/effects/echo.c @@ -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 */ @@ -43,7 +43,7 @@ typedef struct ALechoState { } Tap[2]; ALuint Offset; /* The panning gains for the two taps */ - ALfloat Gain[2][MaxChannels]; + ALfloat Gain[2][MAX_OUTPUT_CHANNELS]; ALfloat FeedGain; @@ -83,9 +83,9 @@ static ALboolean ALechoState_deviceUpdate(ALechoState *state, ALCdevice *Device) static ALvoid ALechoState_update(ALechoState *state, ALCdevice *Device, const ALeffectslot *Slot) { + ALfloat pandir[3] = { 0.0f, 0.0f, 0.0f }; ALuint frequency = Device->Frequency; - ALfloat lrpan, gain; - ALfloat dirGain; + ALfloat gain, lrpan; state->Tap[0].delay = fastf2u(Slot->EffectProps.Echo.Delay * frequency) + 1; state->Tap[1].delay = fastf2u(Slot->EffectProps.Echo.LRDelay * frequency); @@ -95,21 +95,23 @@ static ALvoid ALechoState_update(ALechoState *state, ALCdevice *Device, const AL state->FeedGain = Slot->EffectProps.Echo.Feedback; + gain = minf(1.0f - Slot->EffectProps.Echo.Damping, 0.01f); ALfilterState_setParams(&state->Filter, ALfilterType_HighShelf, - 1.0f - Slot->EffectProps.Echo.Damping, - LOWPASSFREQREF/frequency, 0.0f); + gain, LOWPASSFREQREF/frequency, + calc_rcpQ_from_slope(gain, 0.75f)); gain = Slot->Gain; - dirGain = fabsf(lrpan); /* First tap panning */ - ComputeAngleGains(Device, atan2f(-lrpan, 0.0f), (1.0f-dirGain)*F_PI, gain, state->Gain[0]); + pandir[0] = -lrpan; + ComputeDirectionalGains(Device, pandir, gain, state->Gain[0]); /* Second tap panning */ - ComputeAngleGains(Device, atan2f(+lrpan, 0.0f), (1.0f-dirGain)*F_PI, gain, state->Gain[1]); + pandir[0] = +lrpan; + ComputeDirectionalGains(Device, pandir, gain, state->Gain[1]); } -static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE]) +static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { const ALuint mask = state->BufferLength-1; const ALuint tap1 = state->Tap[0].delay; @@ -121,8 +123,8 @@ static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const for(base = 0;base < SamplesToDo;) { - ALfloat temps[64][2]; - ALuint td = minu(SamplesToDo-base, 64); + ALfloat temps[128][2]; + ALuint td = minu(128, SamplesToDo-base); for(i = 0;i < td;i++) { @@ -138,17 +140,17 @@ static ALvoid ALechoState_process(ALechoState *state, ALuint SamplesToDo, const offset++; } - for(k = 0;k < MaxChannels;k++) + for(k = 0;k < NumChannels;k++) { ALfloat gain = state->Gain[0][k]; - if(gain > GAIN_SILENCE_THRESHOLD) + if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) { for(i = 0;i < td;i++) SamplesOut[k][i+base] += temps[i][0] * gain; } gain = state->Gain[1][k]; - if(gain > GAIN_SILENCE_THRESHOLD) + if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) { for(i = 0;i < td;i++) SamplesOut[k][i+base] += temps[i][1] * gain; diff --git a/libs/openal-soft/Alc/effects/equalizer.c b/libs/openal-soft/Alc/effects/equalizer.c index cfe7c46c..244667ab 100644 --- a/libs/openal-soft/Alc/effects/equalizer.c +++ b/libs/openal-soft/Alc/effects/equalizer.c @@ -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 */ @@ -75,7 +75,7 @@ typedef struct ALequalizerState { DERIVE_FROM_TYPE(ALeffectState); /* Effect gains for each channel */ - ALfloat Gain[MaxChannels]; + ALfloat Gain[MAX_OUTPUT_CHANNELS]; /* Effect parameters */ ALfilterState filter[4]; @@ -93,33 +93,40 @@ static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *UNUSED(state), static ALvoid ALequalizerState_update(ALequalizerState *state, ALCdevice *device, const ALeffectslot *slot) { ALfloat frequency = (ALfloat)device->Frequency; - ALfloat gain = sqrtf(1.0f / device->NumChan) * slot->Gain; + ALfloat gain, freq_mult; - SetGains(device, gain, state->Gain); + ComputeAmbientGains(device, slot->Gain, state->Gain); - /* Calculate coefficients for the each type of filter */ + /* Calculate coefficients for the each type of filter. Note that the shelf + * filters' gain is for the reference frequency, which is the centerpoint + * of the transition band. + */ + gain = sqrtf(slot->EffectProps.Equalizer.LowGain); + freq_mult = slot->EffectProps.Equalizer.LowCutoff/frequency; ALfilterState_setParams(&state->filter[0], ALfilterType_LowShelf, - sqrtf(slot->EffectProps.Equalizer.LowGain), - slot->EffectProps.Equalizer.LowCutoff/frequency, - 0.0f); + gain, freq_mult, calc_rcpQ_from_slope(gain, 0.75f) + ); + gain = slot->EffectProps.Equalizer.Mid1Gain; + freq_mult = slot->EffectProps.Equalizer.Mid1Center/frequency; ALfilterState_setParams(&state->filter[1], ALfilterType_Peaking, - sqrtf(slot->EffectProps.Equalizer.Mid1Gain), - slot->EffectProps.Equalizer.Mid1Center/frequency, - slot->EffectProps.Equalizer.Mid1Width); + gain, freq_mult, calc_rcpQ_from_bandwidth(freq_mult, slot->EffectProps.Equalizer.Mid1Width) + ); + gain = slot->EffectProps.Equalizer.Mid2Gain; + freq_mult = slot->EffectProps.Equalizer.Mid2Center/frequency; ALfilterState_setParams(&state->filter[2], ALfilterType_Peaking, - sqrtf(slot->EffectProps.Equalizer.Mid2Gain), - slot->EffectProps.Equalizer.Mid2Center/frequency, - slot->EffectProps.Equalizer.Mid2Width); + gain, freq_mult, calc_rcpQ_from_bandwidth(freq_mult, slot->EffectProps.Equalizer.Mid2Width) + ); + gain = sqrtf(slot->EffectProps.Equalizer.HighGain); + freq_mult = slot->EffectProps.Equalizer.HighCutoff/frequency; ALfilterState_setParams(&state->filter[3], ALfilterType_HighShelf, - sqrtf(slot->EffectProps.Equalizer.HighGain), - slot->EffectProps.Equalizer.HighCutoff/frequency, - 0.0f); + gain, freq_mult, calc_rcpQ_from_slope(gain, 0.75f) + ); } -static ALvoid ALequalizerState_process(ALequalizerState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE]) +static ALvoid ALequalizerState_process(ALequalizerState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { ALuint base; ALuint it; @@ -128,8 +135,8 @@ static ALvoid ALequalizerState_process(ALequalizerState *state, ALuint SamplesTo for(base = 0;base < SamplesToDo;) { - ALfloat temps[64]; - ALuint td = minu(SamplesToDo-base, 64); + ALfloat temps[256]; + ALuint td = minu(256, SamplesToDo-base); for(it = 0;it < td;it++) { @@ -141,10 +148,10 @@ static ALvoid ALequalizerState_process(ALequalizerState *state, ALuint SamplesTo temps[it] = smp; } - for(kt = 0;kt < MaxChannels;kt++) + for(kt = 0;kt < NumChannels;kt++) { ALfloat gain = state->Gain[kt]; - if(!(gain > GAIN_SILENCE_THRESHOLD)) + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) continue; for(it = 0;it < td;it++) diff --git a/libs/openal-soft/Alc/effects/flanger.c b/libs/openal-soft/Alc/effects/flanger.c index 117cd1f2..f6191abd 100644 --- a/libs/openal-soft/Alc/effects/flanger.c +++ b/libs/openal-soft/Alc/effects/flanger.c @@ -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 */ @@ -46,7 +46,7 @@ typedef struct ALflangerState { ALint lfo_disp; /* Gains for left and right sides */ - ALfloat Gain[2][MaxChannels]; + ALfloat Gain[2][MAX_OUTPUT_CHANNELS]; /* effect parameters */ enum FlangerWaveForm waveform; @@ -93,6 +93,8 @@ static ALboolean ALflangerState_deviceUpdate(ALflangerState *state, ALCdevice *D static ALvoid ALflangerState_update(ALflangerState *state, ALCdevice *Device, const ALeffectslot *Slot) { + static const ALfloat left_dir[3] = { -1.0f, 0.0f, 0.0f }; + static const ALfloat right_dir[3] = { 1.0f, 0.0f, 0.0f }; ALfloat frequency = (ALfloat)Device->Frequency; ALfloat rate; ALint phase; @@ -111,8 +113,8 @@ static ALvoid ALflangerState_update(ALflangerState *state, ALCdevice *Device, co state->delay = fastf2i(Slot->EffectProps.Flanger.Delay * frequency); /* Gains for left and right sides */ - ComputeAngleGains(Device, atan2f(-1.0f, 0.0f), 0.0f, Slot->Gain, state->Gain[0]); - ComputeAngleGains(Device, atan2f(+1.0f, 0.0f), 0.0f, Slot->Gain, state->Gain[1]); + ComputeDirectionalGains(Device, left_dir, Slot->Gain, state->Gain[0]); + ComputeDirectionalGains(Device, right_dir, Slot->Gain, state->Gain[1]); phase = Slot->EffectProps.Flanger.Phase; rate = Slot->EffectProps.Flanger.Rate; @@ -132,7 +134,7 @@ static ALvoid ALflangerState_update(ALflangerState *state, ALCdevice *Device, co state->lfo_scale = 4.0f / state->lfo_range; break; case FWF_Sinusoid: - state->lfo_scale = F_2PI / state->lfo_range; + state->lfo_scale = F_TAU / state->lfo_range; break; } @@ -201,15 +203,15 @@ DECL_TEMPLATE(Sinusoid) #undef DECL_TEMPLATE -static ALvoid ALflangerState_process(ALflangerState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE]) +static ALvoid ALflangerState_process(ALflangerState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { ALuint it, kt; ALuint base; for(base = 0;base < SamplesToDo;) { - ALfloat temps[64][2]; - ALuint td = minu(SamplesToDo-base, 64); + ALfloat temps[128][2]; + ALuint td = minu(128, SamplesToDo-base); switch(state->waveform) { @@ -221,17 +223,17 @@ static ALvoid ALflangerState_process(ALflangerState *state, ALuint SamplesToDo, break; } - for(kt = 0;kt < MaxChannels;kt++) + for(kt = 0;kt < NumChannels;kt++) { ALfloat gain = state->Gain[0][kt]; - if(gain > GAIN_SILENCE_THRESHOLD) + if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) { for(it = 0;it < td;it++) SamplesOut[kt][it+base] += temps[it][0] * gain; } gain = state->Gain[1][kt]; - if(gain > GAIN_SILENCE_THRESHOLD) + if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) { for(it = 0;it < td;it++) SamplesOut[kt][it+base] += temps[it][1] * gain; diff --git a/libs/openal-soft/Alc/effects/modulator.c b/libs/openal-soft/Alc/effects/modulator.c index a5475708..dceb408e 100644 --- a/libs/openal-soft/Alc/effects/modulator.c +++ b/libs/openal-soft/Alc/effects/modulator.c @@ -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 */ @@ -42,7 +42,7 @@ typedef struct ALmodulatorState { ALuint index; ALuint step; - ALfloat Gain[MaxChannels]; + ALfloat Gain[MAX_OUTPUT_CHANNELS]; ALfilterState Filter; } ALmodulatorState; @@ -53,7 +53,7 @@ typedef struct ALmodulatorState { static inline ALfloat Sin(ALuint index) { - return sinf(index*(F_2PI/WAVEFORM_FRACONE) - F_PI)*0.5f + 0.5f; + return sinf(index*(F_TAU/WAVEFORM_FRACONE) - F_PI)*0.5f + 0.5f; } static inline ALfloat Saw(ALuint index) @@ -69,7 +69,7 @@ static inline ALfloat Square(ALuint index) #define DECL_TEMPLATE(func) \ static void Process##func(ALmodulatorState *state, ALuint SamplesToDo, \ const ALfloat *restrict SamplesIn, \ - ALfloat (*restrict SamplesOut)[BUFFERSIZE]) \ + ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) \ { \ const ALuint step = state->step; \ ALuint index = state->index; \ @@ -77,8 +77,8 @@ static void Process##func(ALmodulatorState *state, ALuint SamplesToDo, \ \ for(base = 0;base < SamplesToDo;) \ { \ - ALfloat temps[64]; \ - ALuint td = minu(SamplesToDo-base, 64); \ + ALfloat temps[256]; \ + ALuint td = minu(256, SamplesToDo-base); \ ALuint i, k; \ \ for(i = 0;i < td;i++) \ @@ -92,10 +92,10 @@ static void Process##func(ALmodulatorState *state, ALuint SamplesToDo, \ temps[i] = samp * func(index); \ } \ \ - for(k = 0;k < MaxChannels;k++) \ + for(k = 0;k < NumChannels;k++) \ { \ ALfloat gain = state->Gain[k]; \ - if(!(gain > GAIN_SILENCE_THRESHOLD)) \ + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) \ continue; \ \ for(i = 0;i < td;i++) \ @@ -125,7 +125,7 @@ static ALboolean ALmodulatorState_deviceUpdate(ALmodulatorState *UNUSED(state), static ALvoid ALmodulatorState_update(ALmodulatorState *state, ALCdevice *Device, const ALeffectslot *Slot) { - ALfloat gain, cw, a; + ALfloat cw, a; if(Slot->EffectProps.Modulator.Waveform == AL_RING_MODULATOR_SINUSOID) state->Waveform = SINUSOID; @@ -139,7 +139,7 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, ALCdevice *Device if(state->step == 0) state->step = 1; /* Custom filter coeffs, which match the old version instead of a low-shelf. */ - cw = cosf(F_2PI * Slot->EffectProps.Modulator.HighPassCutoff / Device->Frequency); + cw = cosf(F_TAU * Slot->EffectProps.Modulator.HighPassCutoff / Device->Frequency); a = (2.0f-cw) - sqrtf(powf(2.0f-cw, 2.0f) - 1.0f); state->Filter.b[0] = a; @@ -149,24 +149,23 @@ static ALvoid ALmodulatorState_update(ALmodulatorState *state, ALCdevice *Device state->Filter.a[1] = -a; state->Filter.a[2] = 0.0f; - gain = sqrtf(1.0f/Device->NumChan) * Slot->Gain; - SetGains(Device, gain, state->Gain); + ComputeAmbientGains(Device, Slot->Gain, state->Gain); } -static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE]) +static ALvoid ALmodulatorState_process(ALmodulatorState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { switch(state->Waveform) { case SINUSOID: - ProcessSin(state, SamplesToDo, SamplesIn, SamplesOut); + ProcessSin(state, SamplesToDo, SamplesIn, SamplesOut, NumChannels); break; case SAWTOOTH: - ProcessSaw(state, SamplesToDo, SamplesIn, SamplesOut); + ProcessSaw(state, SamplesToDo, SamplesIn, SamplesOut, NumChannels); break; case SQUARE: - ProcessSquare(state, SamplesToDo, SamplesIn, SamplesOut); + ProcessSquare(state, SamplesToDo, SamplesIn, SamplesOut, NumChannels); break; } } diff --git a/libs/openal-soft/Alc/effects/null.c b/libs/openal-soft/Alc/effects/null.c index 6dacd021..adc4ca81 100644 --- a/libs/openal-soft/Alc/effects/null.c +++ b/libs/openal-soft/Alc/effects/null.c @@ -41,11 +41,8 @@ static ALvoid ALnullState_update(ALnullState* UNUSED(state), ALCdevice* UNUSED(d * input to the output buffer. The result should be added to the output buffer, * not replace it. */ -static ALvoid ALnullState_process(ALnullState* UNUSED(state), ALuint UNUSED(samplesToDo), const ALfloat *restrict UNUSED(samplesIn), ALfloat (*restrict samplesOut)[BUFFERSIZE]) +static ALvoid ALnullState_process(ALnullState* UNUSED(state), ALuint UNUSED(samplesToDo), const ALfloat *restrict UNUSED(samplesIn), ALfloatBUFFERSIZE*restrict UNUSED(samplesOut), ALuint UNUSED(NumChannels)) { - /* NOTE: Couldn't use the UNUSED macro on samplesOut due to the way GCC's - * __attribute__ declaration interacts with the parenthesis. */ - (void)samplesOut; } /* This allocates memory to store the object, before it gets constructed. diff --git a/libs/openal-soft/Alc/effects/reverb.c b/libs/openal-soft/Alc/effects/reverb.c index 245aed41..e1013309 100644 --- a/libs/openal-soft/Alc/effects/reverb.c +++ b/libs/openal-soft/Alc/effects/reverb.c @@ -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 */ @@ -32,6 +32,10 @@ #include "alError.h" +/* This is the maximum number of samples processed for each inner loop + * iteration. */ +#define MAX_UPDATE_SAMPLES 256 + typedef struct DelayLine { // The delay lines use sample lengths that are powers of 2 to allow the @@ -86,7 +90,7 @@ typedef struct ALreverbState { // The gain for each output channel based on 3D panning (only for the // EAX path). - ALfloat PanGain[MaxChannels]; + ALfloat PanGain[4][MAX_OUTPUT_CHANNELS]; } Early; // Decorrelator delay line. @@ -125,7 +129,7 @@ typedef struct ALreverbState { // The gain for each output channel based on 3D panning (only for the // EAX path). - ALfloat PanGain[MaxChannels]; + ALfloat PanGain[4][MAX_OUTPUT_CHANNELS]; } Late; struct { @@ -148,8 +152,8 @@ typedef struct ALreverbState { ALfloat LpCoeff; ALfloat LpSample; - // Echo mixing coefficients. - ALfloat MixCoeff[2]; + // Echo mixing coefficient. + ALfloat MixCoeff; } Echo; // The current read offset for all delay lines. @@ -157,11 +161,11 @@ typedef struct ALreverbState { // The gain for each output channel (non-EAX path only; aliased from // Late.PanGain) - ALfloat *Gain; + ALfloat (*Gain)[MAX_OUTPUT_CHANNELS]; - /* Temporary storage used when processing, before deinterlacing. */ - ALfloat ReverbSamples[BUFFERSIZE][4]; - ALfloat EarlySamples[BUFFERSIZE][4]; + /* Temporary storage used when processing. */ + ALfloat ReverbSamples[MAX_UPDATE_SAMPLES][4]; + ALfloat EarlySamples[MAX_UPDATE_SAMPLES][4]; } ALreverbState; /* This is a user config option for modifying the overall output of the reverb @@ -234,10 +238,93 @@ static inline ALvoid DelayLineIn(DelayLine *Delay, ALuint offset, ALfloat in) Delay->Line[offset&Delay->Mask] = in; } -// Attenuated delay line output routine. -static inline ALfloat AttenuatedDelayLineOut(DelayLine *Delay, ALuint offset, ALfloat coeff) +// Given an input sample, this function produces modulation for the late +// reverb. +static inline ALfloat EAXModulation(ALreverbState *State, ALuint offset, ALfloat in) { - return coeff * Delay->Line[offset&Delay->Mask]; + ALfloat sinus, frac, fdelay; + ALfloat out0, out1; + ALuint delay; + + // Calculate the sinus rythm (dependent on modulation time and the + // sampling rate). The center of the sinus is moved to reduce the delay + // of the effect when the time or depth are low. + sinus = 1.0f - cosf(F_TAU * State->Mod.Index / State->Mod.Range); + + // Step the modulation index forward, keeping it bound to its range. + State->Mod.Index = (State->Mod.Index + 1) % State->Mod.Range; + + // The depth determines the range over which to read the input samples + // from, so it must be filtered to reduce the distortion caused by even + // small parameter changes. + State->Mod.Filter = lerp(State->Mod.Filter, State->Mod.Depth, + State->Mod.Coeff); + + // Calculate the read offset and fraction between it and the next sample. + frac = modff(State->Mod.Filter*sinus + 1.0f, &fdelay); + delay = fastf2u(fdelay); + + // Get the two samples crossed by the offset, and feed the delay line + // with the next input sample. + out0 = DelayLineOut(&State->Mod.Delay, offset - delay); + out1 = DelayLineOut(&State->Mod.Delay, offset - delay - 1); + DelayLineIn(&State->Mod.Delay, offset, in); + + // The output is obtained by linearly interpolating the two samples that + // were acquired above. + return lerp(out0, out1, frac); +} + +// Given some input sample, this function produces four-channel outputs for the +// early reflections. +static inline ALvoid EarlyReflection(ALreverbState *State, ALuint todo, ALfloat (*restrict out)[4]) +{ + ALfloat d[4], v, f[4]; + ALuint i; + + for(i = 0;i < todo;i++) + { + ALuint offset = State->Offset+i; + + // Obtain the decayed results of each early delay line. + d[0] = DelayLineOut(&State->Early.Delay[0], offset-State->Early.Offset[0]) * State->Early.Coeff[0]; + d[1] = DelayLineOut(&State->Early.Delay[1], offset-State->Early.Offset[1]) * State->Early.Coeff[1]; + d[2] = DelayLineOut(&State->Early.Delay[2], offset-State->Early.Offset[2]) * State->Early.Coeff[2]; + d[3] = DelayLineOut(&State->Early.Delay[3], offset-State->Early.Offset[3]) * State->Early.Coeff[3]; + + /* The following uses a lossless scattering junction from waveguide + * theory. It actually amounts to a householder mixing matrix, which + * will produce a maximally diffuse response, and means this can + * probably be considered a simple feed-back delay network (FDN). + * N + * --- + * \ + * v = 2/N / d_i + * --- + * i=1 + */ + v = (d[0] + d[1] + d[2] + d[3]) * 0.5f; + // The junction is loaded with the input here. + v += DelayLineOut(&State->Delay, offset-State->DelayTap[0]); + + // Calculate the feed values for the delay lines. + f[0] = v - d[0]; + f[1] = v - d[1]; + f[2] = v - d[2]; + f[3] = v - d[3]; + + // Re-feed the delay lines. + DelayLineIn(&State->Early.Delay[0], offset, f[0]); + DelayLineIn(&State->Early.Delay[1], offset, f[1]); + DelayLineIn(&State->Early.Delay[2], offset, f[2]); + DelayLineIn(&State->Early.Delay[3], offset, f[3]); + + // Output the results of the junction for all four channels. + out[i][0] = State->Early.Gain * f[0]; + out[i][1] = State->Early.Gain * f[1]; + out[i][2] = State->Early.Gain * f[2]; + out[i][3] = State->Early.Gain * f[3]; + } } // Basic attenuated all-pass input/output routine. @@ -255,115 +342,15 @@ static inline ALfloat AllpassInOut(DelayLine *Delay, ALuint outOffset, ALuint in return (coeff * out) - feed; } -// Given an input sample, this function produces modulation for the late -// reverb. -static inline ALfloat EAXModulation(ALreverbState *State, ALfloat in) -{ - ALfloat sinus, frac; - ALuint offset; - ALfloat out0, out1; - - // Calculate the sinus rythm (dependent on modulation time and the - // sampling rate). The center of the sinus is moved to reduce the delay - // of the effect when the time or depth are low. - sinus = 1.0f - cosf(F_2PI * State->Mod.Index / State->Mod.Range); - - // The depth determines the range over which to read the input samples - // from, so it must be filtered to reduce the distortion caused by even - // small parameter changes. - State->Mod.Filter = lerp(State->Mod.Filter, State->Mod.Depth, - State->Mod.Coeff); - - // Calculate the read offset and fraction between it and the next sample. - frac = (1.0f + (State->Mod.Filter * sinus)); - offset = fastf2u(frac); - frac -= offset; - - // Get the two samples crossed by the offset, and feed the delay line - // with the next input sample. - out0 = DelayLineOut(&State->Mod.Delay, State->Offset - offset); - out1 = DelayLineOut(&State->Mod.Delay, State->Offset - offset - 1); - DelayLineIn(&State->Mod.Delay, State->Offset, in); - - // Step the modulation index forward, keeping it bound to its range. - State->Mod.Index = (State->Mod.Index + 1) % State->Mod.Range; - - // The output is obtained by linearly interpolating the two samples that - // were acquired above. - return lerp(out0, out1, frac); -} - -// Delay line output routine for early reflections. -static inline ALfloat EarlyDelayLineOut(ALreverbState *State, ALuint index) -{ - return AttenuatedDelayLineOut(&State->Early.Delay[index], - State->Offset - State->Early.Offset[index], - State->Early.Coeff[index]); -} - -// Given an input sample, this function produces four-channel output for the -// early reflections. -static inline ALvoid EarlyReflection(ALreverbState *State, ALfloat in, ALfloat *restrict out) -{ - ALfloat d[4], v, f[4]; - - // Obtain the decayed results of each early delay line. - d[0] = EarlyDelayLineOut(State, 0); - d[1] = EarlyDelayLineOut(State, 1); - d[2] = EarlyDelayLineOut(State, 2); - d[3] = EarlyDelayLineOut(State, 3); - - /* The following uses a lossless scattering junction from waveguide - * theory. It actually amounts to a householder mixing matrix, which - * will produce a maximally diffuse response, and means this can probably - * be considered a simple feed-back delay network (FDN). - * N - * --- - * \ - * v = 2/N / d_i - * --- - * i=1 - */ - v = (d[0] + d[1] + d[2] + d[3]) * 0.5f; - // The junction is loaded with the input here. - v += in; - - // Calculate the feed values for the delay lines. - f[0] = v - d[0]; - f[1] = v - d[1]; - f[2] = v - d[2]; - f[3] = v - d[3]; - - // Re-feed the delay lines. - DelayLineIn(&State->Early.Delay[0], State->Offset, f[0]); - DelayLineIn(&State->Early.Delay[1], State->Offset, f[1]); - DelayLineIn(&State->Early.Delay[2], State->Offset, f[2]); - DelayLineIn(&State->Early.Delay[3], State->Offset, f[3]); - - // Output the results of the junction for all four channels. - out[0] = State->Early.Gain * f[0]; - out[1] = State->Early.Gain * f[1]; - out[2] = State->Early.Gain * f[2]; - out[3] = State->Early.Gain * f[3]; -} - // All-pass input/output routine for late reverb. -static inline ALfloat LateAllPassInOut(ALreverbState *State, ALuint index, ALfloat in) +static inline ALfloat LateAllPassInOut(ALreverbState *State, ALuint offset, ALuint index, ALfloat in) { return AllpassInOut(&State->Late.ApDelay[index], - State->Offset - State->Late.ApOffset[index], - State->Offset, in, State->Late.ApFeedCoeff, + offset - State->Late.ApOffset[index], + offset, in, State->Late.ApFeedCoeff, State->Late.ApCoeff[index]); } -// Delay line output routine for late reverb. -static inline ALfloat LateDelayLineOut(ALreverbState *State, ALuint index) -{ - return AttenuatedDelayLineOut(&State->Late.Delay[index], - State->Offset - State->Late.Offset[index], - State->Late.Coeff[index]); -} - // Low-pass filter input/output routine for late reverb. static inline ALfloat LateLowPassInOut(ALreverbState *State, ALuint index, ALfloat in) { @@ -374,260 +361,296 @@ static inline ALfloat LateLowPassInOut(ALreverbState *State, ALuint index, ALflo // Given four decorrelated input samples, this function produces four-channel // output for the late reverb. -static inline ALvoid LateReverb(ALreverbState *State, const ALfloat *restrict in, ALfloat *restrict out) +static inline ALvoid LateReverb(ALreverbState *State, ALuint todo, ALfloat (*restrict out)[4]) { ALfloat d[4], f[4]; + ALuint i; - // Obtain the decayed results of the cyclical delay lines, and add the - // corresponding input channels. Then pass the results through the - // low-pass filters. + for(i = 0;i < todo;i++) + { + ALuint offset = State->Offset+i; - // This is where the feed-back cycles from line 0 to 1 to 3 to 2 and back - // to 0. - d[0] = LateLowPassInOut(State, 2, in[2] + LateDelayLineOut(State, 2)); - d[1] = LateLowPassInOut(State, 0, in[0] + LateDelayLineOut(State, 0)); - d[2] = LateLowPassInOut(State, 3, in[3] + LateDelayLineOut(State, 3)); - d[3] = LateLowPassInOut(State, 1, in[1] + LateDelayLineOut(State, 1)); + f[0] = DelayLineOut(&State->Decorrelator, offset); + f[1] = DelayLineOut(&State->Decorrelator, offset-State->DecoTap[0]); + f[2] = DelayLineOut(&State->Decorrelator, offset-State->DecoTap[1]); + f[3] = DelayLineOut(&State->Decorrelator, offset-State->DecoTap[2]); - // To help increase diffusion, run each line through an all-pass filter. - // When there is no diffusion, the shortest all-pass filter will feed the - // shortest delay line. - d[0] = LateAllPassInOut(State, 0, d[0]); - d[1] = LateAllPassInOut(State, 1, d[1]); - d[2] = LateAllPassInOut(State, 2, d[2]); - d[3] = LateAllPassInOut(State, 3, d[3]); + // Obtain the decayed results of the cyclical delay lines, and add the + // corresponding input channels. Then pass the results through the + // low-pass filters. + f[0] += DelayLineOut(&State->Late.Delay[0], offset-State->Late.Offset[0]) * State->Late.Coeff[0]; + f[1] += DelayLineOut(&State->Late.Delay[1], offset-State->Late.Offset[1]) * State->Late.Coeff[1]; + f[2] += DelayLineOut(&State->Late.Delay[2], offset-State->Late.Offset[2]) * State->Late.Coeff[2]; + f[3] += DelayLineOut(&State->Late.Delay[3], offset-State->Late.Offset[3]) * State->Late.Coeff[3]; - /* Late reverb is done with a modified feed-back delay network (FDN) - * topology. Four input lines are each fed through their own all-pass - * filter and then into the mixing matrix. The four outputs of the - * mixing matrix are then cycled back to the inputs. Each output feeds - * a different input to form a circlular feed cycle. - * - * The mixing matrix used is a 4D skew-symmetric rotation matrix derived - * using a single unitary rotational parameter: - * - * [ d, a, b, c ] 1 = a^2 + b^2 + c^2 + d^2 - * [ -a, d, c, -b ] - * [ -b, -c, d, a ] - * [ -c, b, -a, d ] - * - * The rotation is constructed from the effect's diffusion parameter, - * yielding: 1 = x^2 + 3 y^2; where a, b, and c are the coefficient y - * with differing signs, and d is the coefficient x. The matrix is thus: - * - * [ x, y, -y, y ] n = sqrt(matrix_order - 1) - * [ -y, x, y, y ] t = diffusion_parameter * atan(n) - * [ y, -y, x, y ] x = cos(t) - * [ -y, -y, -y, x ] y = sin(t) / n - * - * To reduce the number of multiplies, the x coefficient is applied with - * the cyclical delay line coefficients. Thus only the y coefficient is - * applied when mixing, and is modified to be: y / x. - */ - f[0] = d[0] + (State->Late.MixCoeff * ( d[1] + -d[2] + d[3])); - f[1] = d[1] + (State->Late.MixCoeff * (-d[0] + d[2] + d[3])); - f[2] = d[2] + (State->Late.MixCoeff * ( d[0] + -d[1] + d[3])); - f[3] = d[3] + (State->Late.MixCoeff * (-d[0] + -d[1] + -d[2] )); + // This is where the feed-back cycles from line 0 to 1 to 3 to 2 and + // back to 0. + d[0] = LateLowPassInOut(State, 2, f[2]); + d[1] = LateLowPassInOut(State, 0, f[0]); + d[2] = LateLowPassInOut(State, 3, f[3]); + d[3] = LateLowPassInOut(State, 1, f[1]); - // Output the results of the matrix for all four channels, attenuated by - // the late reverb gain (which is attenuated by the 'x' mix coefficient). - out[0] = State->Late.Gain * f[0]; - out[1] = State->Late.Gain * f[1]; - out[2] = State->Late.Gain * f[2]; - out[3] = State->Late.Gain * f[3]; + // To help increase diffusion, run each line through an all-pass filter. + // When there is no diffusion, the shortest all-pass filter will feed + // the shortest delay line. + d[0] = LateAllPassInOut(State, offset, 0, d[0]); + d[1] = LateAllPassInOut(State, offset, 1, d[1]); + d[2] = LateAllPassInOut(State, offset, 2, d[2]); + d[3] = LateAllPassInOut(State, offset, 3, d[3]); - // Re-feed the cyclical delay lines. - DelayLineIn(&State->Late.Delay[0], State->Offset, f[0]); - DelayLineIn(&State->Late.Delay[1], State->Offset, f[1]); - DelayLineIn(&State->Late.Delay[2], State->Offset, f[2]); - DelayLineIn(&State->Late.Delay[3], State->Offset, f[3]); + /* Late reverb is done with a modified feed-back delay network (FDN) + * topology. Four input lines are each fed through their own all-pass + * filter and then into the mixing matrix. The four outputs of the + * mixing matrix are then cycled back to the inputs. Each output feeds + * a different input to form a circlular feed cycle. + * + * The mixing matrix used is a 4D skew-symmetric rotation matrix + * derived using a single unitary rotational parameter: + * + * [ d, a, b, c ] 1 = a^2 + b^2 + c^2 + d^2 + * [ -a, d, c, -b ] + * [ -b, -c, d, a ] + * [ -c, b, -a, d ] + * + * The rotation is constructed from the effect's diffusion parameter, + * yielding: 1 = x^2 + 3 y^2; where a, b, and c are the coefficient y + * with differing signs, and d is the coefficient x. The matrix is + * thus: + * + * [ x, y, -y, y ] n = sqrt(matrix_order - 1) + * [ -y, x, y, y ] t = diffusion_parameter * atan(n) + * [ y, -y, x, y ] x = cos(t) + * [ -y, -y, -y, x ] y = sin(t) / n + * + * To reduce the number of multiplies, the x coefficient is applied + * with the cyclical delay line coefficients. Thus only the y + * coefficient is applied when mixing, and is modified to be: y / x. + */ + f[0] = d[0] + (State->Late.MixCoeff * ( d[1] + -d[2] + d[3])); + f[1] = d[1] + (State->Late.MixCoeff * (-d[0] + d[2] + d[3])); + f[2] = d[2] + (State->Late.MixCoeff * ( d[0] + -d[1] + d[3])); + f[3] = d[3] + (State->Late.MixCoeff * (-d[0] + -d[1] + -d[2] )); + + // Output the results of the matrix for all four channels, attenuated by + // the late reverb gain (which is attenuated by the 'x' mix coefficient). + // Mix early reflections and late reverb. + out[i][0] += State->Late.Gain * f[0]; + out[i][1] += State->Late.Gain * f[1]; + out[i][2] += State->Late.Gain * f[2]; + out[i][3] += State->Late.Gain * f[3]; + + // Re-feed the cyclical delay lines. + DelayLineIn(&State->Late.Delay[0], offset, f[0]); + DelayLineIn(&State->Late.Delay[1], offset, f[1]); + DelayLineIn(&State->Late.Delay[2], offset, f[2]); + DelayLineIn(&State->Late.Delay[3], offset, f[3]); + } } // Given an input sample, this function mixes echo into the four-channel late // reverb. -static inline ALvoid EAXEcho(ALreverbState *State, ALfloat in, ALfloat *restrict late) +static inline ALvoid EAXEcho(ALreverbState *State, ALuint todo, ALfloat (*restrict late)[4]) { ALfloat out, feed; + ALuint i; - // Get the latest attenuated echo sample for output. - feed = AttenuatedDelayLineOut(&State->Echo.Delay, - State->Offset - State->Echo.Offset, - State->Echo.Coeff); + for(i = 0;i < todo;i++) + { + ALuint offset = State->Offset+i; - // Mix the output into the late reverb channels. - out = State->Echo.MixCoeff[0] * feed; - late[0] = (State->Echo.MixCoeff[1] * late[0]) + out; - late[1] = (State->Echo.MixCoeff[1] * late[1]) + out; - late[2] = (State->Echo.MixCoeff[1] * late[2]) + out; - late[3] = (State->Echo.MixCoeff[1] * late[3]) + out; + // Get the latest attenuated echo sample for output. + feed = DelayLineOut(&State->Echo.Delay, offset-State->Echo.Offset) * + State->Echo.Coeff; - // Mix the energy-attenuated input with the output and pass it through - // the echo low-pass filter. - feed += State->Echo.DensityGain * in; - feed = lerp(feed, State->Echo.LpSample, State->Echo.LpCoeff); - State->Echo.LpSample = feed; + // Mix the output into the late reverb channels. + out = State->Echo.MixCoeff * feed; + late[i][0] += out; + late[i][1] += out; + late[i][2] += out; + late[i][3] += out; - // Then the echo all-pass filter. - feed = AllpassInOut(&State->Echo.ApDelay, - State->Offset - State->Echo.ApOffset, - State->Offset, feed, State->Echo.ApFeedCoeff, - State->Echo.ApCoeff); + // Mix the energy-attenuated input with the output and pass it through + // the echo low-pass filter. + feed += DelayLineOut(&State->Delay, offset-State->DelayTap[1]) * + State->Echo.DensityGain; + feed = lerp(feed, State->Echo.LpSample, State->Echo.LpCoeff); + State->Echo.LpSample = feed; - // Feed the delay with the mixed and filtered sample. - DelayLineIn(&State->Echo.Delay, State->Offset, feed); + // Then the echo all-pass filter. + feed = AllpassInOut(&State->Echo.ApDelay, offset-State->Echo.ApOffset, + offset, feed, State->Echo.ApFeedCoeff, + State->Echo.ApCoeff); + + // Feed the delay with the mixed and filtered sample. + DelayLineIn(&State->Echo.Delay, offset, feed); + } } // Perform the non-EAX reverb pass on a given input sample, resulting in // four-channel output. -static inline ALvoid VerbPass(ALreverbState *State, ALfloat in, ALfloat *restrict out) +static inline ALvoid VerbPass(ALreverbState *State, ALuint todo, const ALfloat *in, ALfloat (*restrict out)[4]) { - ALfloat feed, late[4], taps[4]; + ALuint i; - // Filter the incoming sample. - in = ALfilterState_processSingle(&State->LpFilter, in); - - // Feed the initial delay line. - DelayLineIn(&State->Delay, State->Offset, in); + // Low-pass filter the incoming samples. + for(i = 0;i < todo;i++) + DelayLineIn(&State->Delay, State->Offset+i, + ALfilterState_processSingle(&State->LpFilter, in[i]) + ); // Calculate the early reflection from the first delay tap. - in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[0]); - EarlyReflection(State, in, out); + EarlyReflection(State, todo, out); // Feed the decorrelator from the energy-attenuated output of the second // delay tap. - in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[1]); - feed = in * State->Late.DensityGain; - DelayLineIn(&State->Decorrelator, State->Offset, feed); + for(i = 0;i < todo;i++) + { + ALuint offset = State->Offset+i; + ALfloat sample = DelayLineOut(&State->Delay, offset - State->DelayTap[1]) * + State->Late.DensityGain; + DelayLineIn(&State->Decorrelator, offset, sample); + } // Calculate the late reverb from the decorrelator taps. - taps[0] = feed; - taps[1] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[0]); - taps[2] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[1]); - taps[3] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[2]); - LateReverb(State, taps, late); - - // Mix early reflections and late reverb. - out[0] += late[0]; - out[1] += late[1]; - out[2] += late[2]; - out[3] += late[3]; + LateReverb(State, todo, out); // Step all delays forward one sample. - State->Offset++; + State->Offset += todo; } // Perform the EAX reverb pass on a given input sample, resulting in four- // channel output. -static inline ALvoid EAXVerbPass(ALreverbState *State, ALfloat in, ALfloat *restrict early, ALfloat *restrict late) +static inline ALvoid EAXVerbPass(ALreverbState *State, ALuint todo, const ALfloat *input, ALfloat (*restrict early)[4], ALfloat (*restrict late)[4]) { - ALfloat feed, taps[4]; + ALuint i; - // Low-pass filter the incoming sample. - in = ALfilterState_processSingle(&State->LpFilter, in); - in = ALfilterState_processSingle(&State->HpFilter, in); + // Band-pass and modulate the incoming samples. + for(i = 0;i < todo;i++) + { + ALfloat sample = input[i]; + sample = ALfilterState_processSingle(&State->LpFilter, sample); + sample = ALfilterState_processSingle(&State->HpFilter, sample); - // Perform any modulation on the input. - in = EAXModulation(State, in); + // Perform any modulation on the input. + sample = EAXModulation(State, State->Offset+i, sample); - // Feed the initial delay line. - DelayLineIn(&State->Delay, State->Offset, in); + // Feed the initial delay line. + DelayLineIn(&State->Delay, State->Offset+i, sample); + } // Calculate the early reflection from the first delay tap. - in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[0]); - EarlyReflection(State, in, early); + EarlyReflection(State, todo, early); // Feed the decorrelator from the energy-attenuated output of the second // delay tap. - in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[1]); - feed = in * State->Late.DensityGain; - DelayLineIn(&State->Decorrelator, State->Offset, feed); + for(i = 0;i < todo;i++) + { + ALuint offset = State->Offset+i; + ALfloat sample = DelayLineOut(&State->Delay, offset - State->DelayTap[1]) * + State->Late.DensityGain; + DelayLineIn(&State->Decorrelator, offset, sample); + } // Calculate the late reverb from the decorrelator taps. - taps[0] = feed; - taps[1] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[0]); - taps[2] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[1]); - taps[3] = DelayLineOut(&State->Decorrelator, State->Offset - State->DecoTap[2]); - LateReverb(State, taps, late); + memset(late, 0, sizeof(*late)*todo); + LateReverb(State, todo, late); // Calculate and mix in any echo. - EAXEcho(State, in, late); + EAXEcho(State, todo, late); - // Step all delays forward one sample. - State->Offset++; + // Step all delays forward. + State->Offset += todo; } -static ALvoid ALreverbState_processStandard(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE]) +static ALvoid ALreverbState_processStandard(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { ALfloat (*restrict out)[4] = State->ReverbSamples; - ALuint index, c; + ALuint index, c, i, l; /* Process reverb for these samples. */ - for(index = 0;index < SamplesToDo;index++) - VerbPass(State, SamplesIn[index], out[index]); - - for(c = 0;c < MaxChannels;c++) + for(index = 0;index < SamplesToDo;) { - ALfloat gain = State->Gain[c]; - if(!(gain > GAIN_SILENCE_THRESHOLD)) - continue; + ALuint todo = minu(SamplesToDo-index, MAX_UPDATE_SAMPLES); - for(index = 0;index < SamplesToDo;index++) - SamplesOut[c][index] += gain * out[index][c&3]; + VerbPass(State, todo, &SamplesIn[index], out); + + for(l = 0;l < 4;l++) + { + for(c = 0;c < NumChannels;c++) + { + ALfloat gain = State->Gain[l][c]; + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + for(i = 0;i < todo;i++) + SamplesOut[c][index+i] += gain*out[i][l]; + } + } + + index += todo; } } -static ALvoid ALreverbState_processEax(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE]) +static ALvoid ALreverbState_processEax(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { ALfloat (*restrict early)[4] = State->EarlySamples; ALfloat (*restrict late)[4] = State->ReverbSamples; - ALuint index, c; + ALuint index, c, i, l; + ALfloat gain; /* Process reverb for these samples. */ - for(index = 0;index < SamplesToDo;index++) - EAXVerbPass(State, SamplesIn[index], early[index], late[index]); - - for(c = 0;c < MaxChannels;c++) + for(index = 0;index < SamplesToDo;) { - ALfloat earlyGain, lateGain; + ALuint todo = minu(SamplesToDo-index, MAX_UPDATE_SAMPLES); - earlyGain = State->Early.PanGain[c]; - if(earlyGain > GAIN_SILENCE_THRESHOLD) + EAXVerbPass(State, todo, &SamplesIn[index], early, late); + + for(l = 0;l < 4;l++) { - for(index = 0;index < SamplesToDo;index++) - SamplesOut[c][index] += earlyGain*early[index][c&3]; - } - lateGain = State->Late.PanGain[c]; - if(lateGain > GAIN_SILENCE_THRESHOLD) - { - for(index = 0;index < SamplesToDo;index++) - SamplesOut[c][index] += lateGain*late[index][c&3]; + for(c = 0;c < NumChannels;c++) + { + gain = State->Early.PanGain[l][c]; + if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) + { + for(i = 0;i < todo;i++) + SamplesOut[c][index+i] += gain*early[i][l]; + } + gain = State->Late.PanGain[l][c]; + if(fabsf(gain) > GAIN_SILENCE_THRESHOLD) + { + for(i = 0;i < todo;i++) + SamplesOut[c][index+i] += gain*late[i][l]; + } + } } + + index += todo; } } -static ALvoid ALreverbState_process(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE]) +static ALvoid ALreverbState_process(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) { if(State->IsEax) - ALreverbState_processEax(State, SamplesToDo, SamplesIn, SamplesOut); + ALreverbState_processEax(State, SamplesToDo, SamplesIn, SamplesOut, NumChannels); else - ALreverbState_processStandard(State, SamplesToDo, SamplesIn, SamplesOut); + ALreverbState_processStandard(State, SamplesToDo, SamplesIn, SamplesOut, NumChannels); } // Given the allocated sample buffer, this function updates each delay line // offset. static inline ALvoid RealizeLineOffset(ALfloat *sampleBuffer, DelayLine *Delay) { - Delay->Line = &sampleBuffer[(ALintptrEXT)Delay->Line]; + Delay->Line = &sampleBuffer[(ptrdiff_t)Delay->Line]; } // Calculate the length of a delay line and store its mask and offset. -static ALuint CalcLineLength(ALfloat length, ALintptrEXT offset, ALuint frequency, DelayLine *Delay) +static ALuint CalcLineLength(ALfloat length, ptrdiff_t offset, ALuint frequency, ALuint extra, DelayLine *Delay) { ALuint samples; // All line lengths are powers of 2, calculated from their lengths, with // an additional sample in case of rounding errors. - samples = NextPowerOf2(fastf2u(length * frequency) + 1); + samples = fastf2u(length*frequency) + extra; + samples = NextPowerOf2(samples + 1); // All lines share a single sample buffer. Delay->Mask = samples - 1; Delay->Line = (ALfloat*)offset; @@ -654,48 +677,49 @@ static ALboolean AllocLines(ALuint frequency, ALreverbState *State) * swing. An additional sample is added to keep it stable when there is no * modulation. */ - length = (AL_EAXREVERB_MAX_MODULATION_TIME*MODULATION_DEPTH_COEFF/2.0f) + - (1.0f / frequency); - totalSamples += CalcLineLength(length, totalSamples, frequency, + length = (AL_EAXREVERB_MAX_MODULATION_TIME*MODULATION_DEPTH_COEFF/2.0f); + totalSamples += CalcLineLength(length, totalSamples, frequency, 1, &State->Mod.Delay); // The initial delay is the sum of the reflections and late reverb - // delays. + // delays. This must include space for storing a loop update to feed the + // early reflections, decorrelator, and echo. length = AL_EAXREVERB_MAX_REFLECTIONS_DELAY + AL_EAXREVERB_MAX_LATE_REVERB_DELAY; totalSamples += CalcLineLength(length, totalSamples, frequency, - &State->Delay); + MAX_UPDATE_SAMPLES, &State->Delay); // The early reflection lines. for(index = 0;index < 4;index++) totalSamples += CalcLineLength(EARLY_LINE_LENGTH[index], totalSamples, - frequency, &State->Early.Delay[index]); + frequency, 0, &State->Early.Delay[index]); // The decorrelator line is calculated from the lowest reverb density (a - // parameter value of 1). + // parameter value of 1). This must include space for storing a loop update + // to feed the late reverb. length = (DECO_FRACTION * DECO_MULTIPLIER * DECO_MULTIPLIER) * LATE_LINE_LENGTH[0] * (1.0f + LATE_LINE_MULTIPLIER); - totalSamples += CalcLineLength(length, totalSamples, frequency, + totalSamples += CalcLineLength(length, totalSamples, frequency, MAX_UPDATE_SAMPLES, &State->Decorrelator); // The late all-pass lines. for(index = 0;index < 4;index++) totalSamples += CalcLineLength(ALLPASS_LINE_LENGTH[index], totalSamples, - frequency, &State->Late.ApDelay[index]); + frequency, 0, &State->Late.ApDelay[index]); // The late delay lines are calculated from the lowest reverb density. for(index = 0;index < 4;index++) { length = LATE_LINE_LENGTH[index] * (1.0f + LATE_LINE_MULTIPLIER); - totalSamples += CalcLineLength(length, totalSamples, frequency, + totalSamples += CalcLineLength(length, totalSamples, frequency, 0, &State->Late.Delay[index]); } // The echo all-pass and delay lines. totalSamples += CalcLineLength(ECHO_ALLPASS_LENGTH, totalSamples, - frequency, &State->Echo.ApDelay); + frequency, 0, &State->Echo.ApDelay); totalSamples += CalcLineLength(AL_EAXREVERB_MAX_ECHO_TIME, totalSamples, - frequency, &State->Echo.Delay); + frequency, 0, &State->Echo.Delay); if(totalSamples != State->TotalSamples) { @@ -939,7 +963,7 @@ static ALvoid UpdateDecorrelator(ALfloat density, ALuint frequency, ALreverbStat } // Update the late reverb gains, line lengths, and line coefficients. -static ALvoid UpdateLateLines(ALfloat reverbGain, ALfloat lateGain, ALfloat xMix, ALfloat density, ALfloat decayTime, ALfloat diffusion, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALreverbState *State) +static ALvoid UpdateLateLines(ALfloat reverbGain, ALfloat lateGain, ALfloat xMix, ALfloat density, ALfloat decayTime, ALfloat diffusion, ALfloat echoDepth, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALreverbState *State) { ALfloat length; ALuint index; @@ -947,9 +971,13 @@ static ALvoid UpdateLateLines(ALfloat reverbGain, ALfloat lateGain, ALfloat xMix /* Calculate the late reverb gain (from the master effect gain, and late * reverb gain parameters). Since the output is tapped prior to the * application of the next delay line coefficients, this gain needs to be - * attenuated by the 'x' mixing matrix coefficient as well. + * attenuated by the 'x' mixing matrix coefficient as well. Also attenuate + * the late reverb when echo depth is high and diffusion is low, so the + * echo is slightly stronger than the decorrelated echos in the reverb + * tail. */ - State->Late.Gain = reverbGain * lateGain * xMix; + State->Late.Gain = reverbGain * lateGain * xMix * + (1.0f - (echoDepth*0.5f*(1.0f - diffusion))); /* To compensate for changes in modal density and decay time of the late * reverb signal, the input is attenuated based on the maximal energy of @@ -962,8 +990,9 @@ static ALvoid UpdateLateLines(ALfloat reverbGain, ALfloat lateGain, ALfloat xMix length = (LATE_LINE_LENGTH[0] + LATE_LINE_LENGTH[1] + LATE_LINE_LENGTH[2] + LATE_LINE_LENGTH[3]) / 4.0f; length *= 1.0f + (density * LATE_LINE_MULTIPLIER); - State->Late.DensityGain = CalcDensityGain(CalcDecayCoeff(length, - decayTime)); + State->Late.DensityGain = CalcDensityGain( + CalcDecayCoeff(length, decayTime) + ); // Calculate the all-pass feed-back and feed-forward coefficient. State->Late.ApFeedCoeff = 0.5f * powf(diffusion, 2.0f); @@ -971,12 +1000,13 @@ static ALvoid UpdateLateLines(ALfloat reverbGain, ALfloat lateGain, ALfloat xMix for(index = 0;index < 4;index++) { // Calculate the gain (coefficient) for each all-pass line. - State->Late.ApCoeff[index] = CalcDecayCoeff(ALLPASS_LINE_LENGTH[index], - decayTime); + State->Late.ApCoeff[index] = CalcDecayCoeff( + ALLPASS_LINE_LENGTH[index], decayTime + ); // Calculate the length (in seconds) of each cyclical delay line. - length = LATE_LINE_LENGTH[index] * (1.0f + (density * - LATE_LINE_MULTIPLIER)); + length = LATE_LINE_LENGTH[index] * + (1.0f + (density * LATE_LINE_MULTIPLIER)); // Calculate the delay offset for each cyclical delay line. State->Late.Offset[index] = fastf2u(length * frequency); @@ -985,9 +1015,9 @@ static ALvoid UpdateLateLines(ALfloat reverbGain, ALfloat lateGain, ALfloat xMix State->Late.Coeff[index] = CalcDecayCoeff(length, decayTime); // Calculate the damping coefficient for each low-pass filter. - State->Late.LpCoeff[index] = - CalcDampingCoeff(hfRatio, length, decayTime, - State->Late.Coeff[index], cw); + State->Late.LpCoeff[index] = CalcDampingCoeff( + hfRatio, length, decayTime, State->Late.Coeff[index], cw + ); // Attenuate the cyclical line coefficients by the mixing coefficient // (x). @@ -1024,57 +1054,74 @@ static ALvoid UpdateEchoLine(ALfloat reverbGain, ALfloat lateGain, ALfloat echoT * echo depth is high and diffusion is low, so the echo is slightly * stronger than the decorrelated echos in the reverb tail. */ - State->Echo.MixCoeff[0] = reverbGain * lateGain * echoDepth; - State->Echo.MixCoeff[1] = 1.0f - (echoDepth * 0.5f * (1.0f - diffusion)); + State->Echo.MixCoeff = reverbGain * lateGain * echoDepth; } // Update the early and late 3D panning gains. static ALvoid Update3DPanning(const ALCdevice *Device, const ALfloat *ReflectionsPan, const ALfloat *LateReverbPan, ALfloat Gain, ALreverbState *State) { - ALfloat earlyPan[3] = { ReflectionsPan[0], ReflectionsPan[1], - ReflectionsPan[2] }; - ALfloat latePan[3] = { LateReverbPan[0], LateReverbPan[1], - LateReverbPan[2] }; - ALfloat ambientGain; - ALfloat dirGain; - ALfloat length; + static const ALfloat EarlyPanAngles[4] = { + DEG2RAD(0.0f), DEG2RAD(-90.0f), DEG2RAD(90.0f), DEG2RAD(180.0f) + }, LatePanAngles[4] = { + DEG2RAD(45.0f), DEG2RAD(-45.0f), DEG2RAD(135.0f), DEG2RAD(-135.0f) + }; + ALfloat length, ev, az; + ALuint i; - Gain *= ReverbBoost; - - /* Attenuate reverb according to its coverage (dirGain=0 will give - * Gain*ambientGain, and dirGain=1 will give Gain). */ - ambientGain = minf(sqrtf(2.0f/Device->NumChan), 1.0f); - - length = earlyPan[0]*earlyPan[0] + earlyPan[1]*earlyPan[1] + earlyPan[2]*earlyPan[2]; - if(length > 1.0f) + length = sqrtf(ReflectionsPan[0]*ReflectionsPan[0] + ReflectionsPan[1]*ReflectionsPan[1] + ReflectionsPan[2]*ReflectionsPan[2]); + if(!(length > FLT_EPSILON)) { - length = 1.0f / sqrtf(length); - earlyPan[0] *= length; - earlyPan[1] *= length; - earlyPan[2] *= length; + for(i = 0;i < 4;i++) + ComputeAngleGains(Device, EarlyPanAngles[i], 0.0f, Gain, State->Early.PanGain[i]); } - length = latePan[0]*latePan[0] + latePan[1]*latePan[1] + latePan[2]*latePan[2]; - if(length > 1.0f) + else { - length = 1.0f / sqrtf(length); - latePan[0] *= length; - latePan[1] *= length; - latePan[2] *= length; + ev = asinf(clampf(ReflectionsPan[1]/length, -1.0f, 1.0f)); + az = atan2f(ReflectionsPan[0], ReflectionsPan[2]); + + length = minf(length, 1.0f); + for(i = 0;i < 4;i++) + { + /* This is essentially just a lerp, but takes the shortest path + * with respect to circular wrapping. e.g. + * -135 -> +/-180 -> +135 + * instead of + * -135 -> 0 -> +135 */ + float offset, naz, nev; + naz = EarlyPanAngles[i] + (modff((az-EarlyPanAngles[i])*length/F_TAU + 1.5f, &offset)-0.5f)*F_TAU; + nev = (modff((ev )*length/F_TAU + 1.5f, &offset)-0.5f)*F_TAU; + ComputeAngleGains(Device, naz, nev, Gain, State->Early.PanGain[i]); + } } - dirGain = sqrtf(earlyPan[0]*earlyPan[0] + earlyPan[2]*earlyPan[2]); - ComputeAngleGains(Device, atan2f(earlyPan[0], earlyPan[2]), (1.0f-dirGain)*F_PI, - lerp(ambientGain, 1.0f, dirGain) * Gain, State->Early.PanGain); + length = sqrtf(LateReverbPan[0]*LateReverbPan[0] + LateReverbPan[1]*LateReverbPan[1] + LateReverbPan[2]*LateReverbPan[2]); + if(!(length > FLT_EPSILON)) + { + for(i = 0;i < 4;i++) + ComputeAngleGains(Device, LatePanAngles[i], 0.0f, Gain, State->Late.PanGain[i]); + } + else + { + ev = asinf(clampf(LateReverbPan[1]/length, -1.0f, 1.0f)); + az = atan2f(LateReverbPan[0], LateReverbPan[2]); - dirGain = sqrtf(latePan[0]*latePan[0] + latePan[2]*latePan[2]); - ComputeAngleGains(Device, atan2f(latePan[0], latePan[2]), (1.0f-dirGain)*F_PI, - lerp(ambientGain, 1.0f, dirGain) * Gain, State->Late.PanGain); + length = minf(length, 1.0f); + for(i = 0;i < 4;i++) + { + float offset, naz, nev; + naz = LatePanAngles[i] + (modff((az-LatePanAngles[i])*length/F_TAU + 1.5f, &offset)-0.5f)*F_TAU; + nev = (modff((ev )*length/F_TAU + 1.5f, &offset)-0.5f)*F_TAU; + ComputeAngleGains(Device, naz, nev, Gain, State->Late.PanGain[i]); + } + } } static ALvoid ALreverbState_update(ALreverbState *State, ALCdevice *Device, const ALeffectslot *Slot) { + const ALeffectProps *props = &Slot->EffectProps; ALuint frequency = Device->Frequency; ALfloat lfscale, hfscale, hfRatio; + ALfloat gainlf, gainhf; ALfloat cw, x, y; if(Slot->EffectType == AL_EFFECT_EAXREVERB && !EmulateEAXReverb) @@ -1082,85 +1129,60 @@ static ALvoid ALreverbState_update(ALreverbState *State, ALCdevice *Device, cons else if(Slot->EffectType == AL_EFFECT_REVERB || EmulateEAXReverb) State->IsEax = AL_FALSE; - // Calculate the master low-pass filter (from the master effect HF gain). - if(State->IsEax) - { - hfscale = Slot->EffectProps.Reverb.HFReference / frequency; - ALfilterState_setParams(&State->LpFilter, ALfilterType_HighShelf, - Slot->EffectProps.Reverb.GainHF, - hfscale, 0.0f); - lfscale = Slot->EffectProps.Reverb.LFReference / frequency; - ALfilterState_setParams(&State->HpFilter, ALfilterType_LowShelf, - Slot->EffectProps.Reverb.GainLF, - lfscale, 0.0f); - } - else - { - hfscale = LOWPASSFREQREF / frequency; - ALfilterState_setParams(&State->LpFilter, ALfilterType_HighShelf, - Slot->EffectProps.Reverb.GainHF, - hfscale, 0.0f); - } + // Calculate the master filters + hfscale = props->Reverb.HFReference / frequency; + gainhf = maxf(props->Reverb.GainHF, 0.0001f); + ALfilterState_setParams(&State->LpFilter, ALfilterType_HighShelf, + gainhf, hfscale, calc_rcpQ_from_slope(gainhf, 0.75f)); + lfscale = props->Reverb.LFReference / frequency; + gainlf = maxf(props->Reverb.GainLF, 0.0001f); + ALfilterState_setParams(&State->HpFilter, ALfilterType_LowShelf, + gainlf, lfscale, calc_rcpQ_from_slope(gainlf, 0.75f)); - if(State->IsEax) - { - // Update the modulator line. - UpdateModulator(Slot->EffectProps.Reverb.ModulationTime, - Slot->EffectProps.Reverb.ModulationDepth, - frequency, State); - } + // Update the modulator line. + UpdateModulator(props->Reverb.ModulationTime, props->Reverb.ModulationDepth, + frequency, State); // Update the initial effect delay. - UpdateDelayLine(Slot->EffectProps.Reverb.ReflectionsDelay, - Slot->EffectProps.Reverb.LateReverbDelay, + UpdateDelayLine(props->Reverb.ReflectionsDelay, props->Reverb.LateReverbDelay, frequency, State); // Update the early lines. - UpdateEarlyLines(Slot->EffectProps.Reverb.Gain, - Slot->EffectProps.Reverb.ReflectionsGain, - Slot->EffectProps.Reverb.LateReverbDelay, State); + UpdateEarlyLines(props->Reverb.Gain, props->Reverb.ReflectionsGain, + props->Reverb.LateReverbDelay, State); // Update the decorrelator. - UpdateDecorrelator(Slot->EffectProps.Reverb.Density, frequency, State); + UpdateDecorrelator(props->Reverb.Density, frequency, State); // Get the mixing matrix coefficients (x and y). - CalcMatrixCoeffs(Slot->EffectProps.Reverb.Diffusion, &x, &y); + CalcMatrixCoeffs(props->Reverb.Diffusion, &x, &y); // Then divide x into y to simplify the matrix calculation. State->Late.MixCoeff = y / x; // If the HF limit parameter is flagged, calculate an appropriate limit // based on the air absorption parameter. - hfRatio = Slot->EffectProps.Reverb.DecayHFRatio; - if(Slot->EffectProps.Reverb.DecayHFLimit && - Slot->EffectProps.Reverb.AirAbsorptionGainHF < 1.0f) - hfRatio = CalcLimitedHfRatio(hfRatio, - Slot->EffectProps.Reverb.AirAbsorptionGainHF, - Slot->EffectProps.Reverb.DecayTime); + hfRatio = props->Reverb.DecayHFRatio; + if(props->Reverb.DecayHFLimit && props->Reverb.AirAbsorptionGainHF < 1.0f) + hfRatio = CalcLimitedHfRatio(hfRatio, props->Reverb.AirAbsorptionGainHF, + props->Reverb.DecayTime); - cw = cosf(F_2PI * hfscale); + cw = cosf(F_TAU * hfscale); // Update the late lines. - UpdateLateLines(Slot->EffectProps.Reverb.Gain, Slot->EffectProps.Reverb.LateReverbGain, - x, Slot->EffectProps.Reverb.Density, Slot->EffectProps.Reverb.DecayTime, - Slot->EffectProps.Reverb.Diffusion, hfRatio, cw, frequency, State); + UpdateLateLines(props->Reverb.Gain, props->Reverb.LateReverbGain, x, + props->Reverb.Density, props->Reverb.DecayTime, + props->Reverb.Diffusion, props->Reverb.EchoDepth, + hfRatio, cw, frequency, State); - if(State->IsEax) - { - // Update the echo line. - UpdateEchoLine(Slot->EffectProps.Reverb.Gain, Slot->EffectProps.Reverb.LateReverbGain, - Slot->EffectProps.Reverb.EchoTime, Slot->EffectProps.Reverb.DecayTime, - Slot->EffectProps.Reverb.Diffusion, Slot->EffectProps.Reverb.EchoDepth, - hfRatio, cw, frequency, State); + // Update the echo line. + UpdateEchoLine(props->Reverb.Gain, props->Reverb.LateReverbGain, + props->Reverb.EchoTime, props->Reverb.DecayTime, + props->Reverb.Diffusion, props->Reverb.EchoDepth, + hfRatio, cw, frequency, State); - // Update early and late 3D panning. - Update3DPanning(Device, Slot->EffectProps.Reverb.ReflectionsPan, - Slot->EffectProps.Reverb.LateReverbPan, Slot->Gain, State); - } - else - { - /* Update channel gains */ - ALfloat gain = sqrtf(2.0f/Device->NumChan) * ReverbBoost * Slot->Gain; - SetGains(Device, gain, State->Gain); - } + // Update early and late 3D panning. + Update3DPanning(Device, props->Reverb.ReflectionsPan, + props->Reverb.LateReverbPan, + Slot->Gain * ReverbBoost, State); } @@ -1182,7 +1204,7 @@ typedef struct ALreverbStateFactory { static ALeffectState *ALreverbStateFactory_create(ALreverbStateFactory* UNUSED(factory)) { ALreverbState *state; - ALuint index; + ALuint index, l; state = ALreverbState_New(sizeof(*state)); if(!state) return NULL; @@ -1242,10 +1264,13 @@ static ALeffectState *ALreverbStateFactory_create(ALreverbStateFactory* UNUSED(f state->Late.LpSample[index] = 0.0f; } - for(index = 0;index < MaxChannels;index++) + for(l = 0;l < 4;l++) { - state->Early.PanGain[index] = 0.0f; - state->Late.PanGain[index] = 0.0f; + for(index = 0;index < MAX_OUTPUT_CHANNELS;index++) + { + state->Early.PanGain[l][index] = 0.0f; + state->Late.PanGain[l][index] = 0.0f; + } } state->Echo.DensityGain = 0.0f; @@ -1260,8 +1285,7 @@ static ALeffectState *ALreverbStateFactory_create(ALreverbStateFactory* UNUSED(f state->Echo.ApOffset = 0; state->Echo.LpCoeff = 0.0f; state->Echo.LpSample = 0.0f; - state->Echo.MixCoeff[0] = 0.0f; - state->Echo.MixCoeff[1] = 0.0f; + state->Echo.MixCoeff = 0.0f; state->Offset = 0; diff --git a/libs/openal-soft/Alc/helpers.c b/libs/openal-soft/Alc/helpers.c index fc879d95..7b9e58e0 100644 --- a/libs/openal-soft/Alc/helpers.c +++ b/libs/openal-soft/Alc/helpers.c @@ -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,6 +35,9 @@ #ifdef HAVE_MALLOC_H #include #endif +#ifdef HAVE_DIRENT_H +#include +#endif #ifndef AL_NO_UID_DEFS #if defined(HAVE_GUIDDEF_H) || defined(HAVE_INITGUID_H) @@ -55,10 +58,13 @@ DEFINE_GUID(CLSID_MMDeviceEnumerator, 0xbcde0395, 0xe52f, 0x467c, 0x8e,0x3d, 0xc DEFINE_GUID(IID_IMMDeviceEnumerator, 0xa95664d2, 0x9614, 0x4f35, 0xa7,0x46, 0xde,0x8d,0xb6,0x36,0x17,0xe6); DEFINE_GUID(IID_IAudioClient, 0x1cb9ad4c, 0xdbfa, 0x4c32, 0xb1,0x78, 0xc2,0xf5,0x68,0xa7,0x03,0xb2); DEFINE_GUID(IID_IAudioRenderClient, 0xf294acfc, 0x3146, 0x4483, 0xa7,0xbf, 0xad,0xdc,0xa7,0xc2,0x60,0xe2); +DEFINE_GUID(IID_IAudioCaptureClient, 0xc8adbd64, 0xe71e, 0x48a0, 0xa4,0xde, 0x18,0x5c,0x39,0x5c,0xd3,0x17); #ifdef HAVE_MMDEVAPI #include +#include DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14); +DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_FormFactor, 0x1da5d803, 0xd492, 0x4edd, 0x8c,0x23, 0xe0,0xc0,0xff,0xee,0x7f,0x0e, 0); #endif #endif #endif /* AL_NO_UID_DEFS */ @@ -82,7 +88,9 @@ DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, #include #endif -#ifdef _WIN32_IE +#ifndef _WIN32 +#include +#elif defined(_WIN32_IE) #include #endif @@ -144,8 +152,12 @@ void FillCPUCaps(ALuint capfilter) if((cpuinf[0].regs[3]&(1<<26))) { caps |= CPU_CAP_SSE2; - if((cpuinf[0].regs[2]&(1<<19))) - caps |= CPU_CAP_SSE4_1; + if((cpuinf[0].regs[2]&(1<<0))) + { + caps |= CPU_CAP_SSE3; + if((cpuinf[0].regs[2]&(1<<19))) + caps |= CPU_CAP_SSE4_1; + } } } } @@ -188,8 +200,12 @@ void FillCPUCaps(ALuint capfilter) if((cpuinf[0].regs[3]&(1<<26))) { caps |= CPU_CAP_SSE2; - if((cpuinf[0].regs[2]&(1<<19))) - caps |= CPU_CAP_SSE4_1; + if((cpuinf[0].regs[2]&(1<<0))) + { + caps |= CPU_CAP_SSE3; + if((cpuinf[0].regs[2]&(1<<19))) + caps |= CPU_CAP_SSE4_1; + } } } } @@ -198,13 +214,16 @@ void FillCPUCaps(ALuint capfilter) /* Assume support for whatever's supported if we can't check for it */ #if defined(HAVE_SSE4_1) #warning "Assuming SSE 4.1 run-time support!" - capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE4_1; + caps |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3 | CPU_CAP_SSE4_1; +#elif defined(HAVE_SSE3) +#warning "Assuming SSE 3 run-time support!" + caps |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3; #elif defined(HAVE_SSE2) #warning "Assuming SSE 2 run-time support!" - capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2; + caps |= CPU_CAP_SSE | CPU_CAP_SSE2; #elif defined(HAVE_SSE) #warning "Assuming SSE run-time support!" - capfilter |= CPU_CAP_SSE; + caps |= CPU_CAP_SSE; #endif #endif #ifdef HAVE_NEON @@ -212,9 +231,10 @@ void FillCPUCaps(ALuint capfilter) caps |= CPU_CAP_NEON; #endif - TRACE("Extensions:%s%s%s%s%s\n", + TRACE("Extensions:%s%s%s%s%s%s\n", ((capfilter&CPU_CAP_SSE) ? ((caps&CPU_CAP_SSE) ? " +SSE" : " -SSE") : ""), ((capfilter&CPU_CAP_SSE2) ? ((caps&CPU_CAP_SSE2) ? " +SSE2" : " -SSE2") : ""), + ((capfilter&CPU_CAP_SSE3) ? ((caps&CPU_CAP_SSE3) ? " +SSE3" : " -SSE3") : ""), ((capfilter&CPU_CAP_SSE4_1) ? ((caps&CPU_CAP_SSE4_1) ? " +SSE4.1" : " -SSE4.1") : ""), ((capfilter&CPU_CAP_NEON) ? ((caps&CPU_CAP_NEON) ? " +Neon" : " -Neon") : ""), ((!capfilter) ? " -none-" : "") @@ -240,7 +260,7 @@ void *al_malloc(size_t alignment, size_t size) if(ret != NULL) { *(ret++) = 0x00; - while(((ALintptrEXT)ret&(alignment-1)) != 0) + while(((ptrdiff_t)ret&(alignment-1)) != 0) *(ret++) = 0x55; } return ret; @@ -278,6 +298,8 @@ void SetMixerFPUMode(FPUCtl *ctl) #ifdef HAVE_FENV_H fegetenv(STATIC_CAST(fenv_t, ctl)); #if defined(__GNUC__) && defined(HAVE_SSE) + /* FIXME: Some fegetenv implementations can get the SSE environment too? + * How to tell when it does? */ if((CPUCapFlags&CPU_CAP_SSE)) __asm__ __volatile__("stmxcsr %0" : "=m" (*&ctl->sse_state)); #endif @@ -421,6 +443,390 @@ FILE *al_fopen(const char *fname, const char *mode) return file; } + +void al_print(const char *type, const char *func, const char *fmt, ...) +{ + char str[1024]; + WCHAR *wstr; + va_list ap; + + va_start(ap, fmt); + vsnprintf(str, sizeof(str), fmt, ap); + va_end(ap); + + str[sizeof(str)-1] = 0; + wstr = FromUTF8(str); + if(!wstr) + fprintf(LogFile, "AL lib: %s %s: %s", type, func, str); + else + { + fprintf(LogFile, "AL lib: %s %s: %ls", type, func, wstr); + free(wstr); + wstr = NULL; + } + fflush(LogFile); +} + + +static inline int is_slash(int c) +{ return (c == '\\' || c == '/'); } + +FILE *OpenDataFile(const char *fname, const char *subdir) +{ + static const int ids[2] = { CSIDL_APPDATA, CSIDL_COMMON_APPDATA }; + WCHAR *wname=NULL, *wsubdir=NULL; + FILE *f; + size_t i; + + wname = FromUTF8(fname); + if(!wname) + { + ERR("Failed to convert UTF-8 filename: \"%s\"\n", fname); + return NULL; + } + + /* If the path is absolute, open it directly. */ + if(wname[0] != '\0' && wname[1] == ':' && is_slash(wname[2])) + { + f = _wfopen(wname, L"rb"); + if(f) TRACE("Opened %s\n", fname); + else WARN("Could not open %s\n", fname); + free(wname); + return f; + } + + /* Try the current directory first before the data directories. */ + if((f=_wfopen(wname, L"rb")) != NULL) + { + TRACE("Opened %s\n", fname); + free(wname); + return f; + } + + wsubdir = FromUTF8(subdir); + if(!wsubdir) + { + ERR("Failed to convert UTF-8 subdir: \"%s\"\n", subdir); + free(wname); + return NULL; + } + + for(i = 0;i < COUNTOF(ids);i++) + { + WCHAR buffer[PATH_MAX]; + size_t len; + + if(SHGetSpecialFolderPathW(NULL, buffer, ids[i], FALSE) == FALSE) + continue; + + len = lstrlenW(buffer); + if(len > 0 && is_slash(buffer[len-1])) + buffer[--len] = '\0'; + _snwprintf(buffer+len, PATH_MAX-len, L"/%ls/%ls", wsubdir, wname); + len = lstrlenW(buffer); + while(len > 0) + { + --len; + if(buffer[len] == '/') + buffer[len] = '\\'; + } + + if((f=_wfopen(buffer, L"rb")) != NULL) + { + al_string filepath = AL_STRING_INIT_STATIC(); + al_string_copy_wcstr(&filepath, buffer); + TRACE("Opened %s\n", al_string_get_cstr(filepath)); + al_string_deinit(&filepath); + break; + } + } + free(wname); + free(wsubdir); + + if(f == NULL) + WARN("Could not open %s\\%s\n", subdir, fname); + return f; +} + + +static const WCHAR *strchrW(const WCHAR *str, WCHAR ch) +{ + for(;*str != 0;++str) + { + if(*str == ch) + return str; + } + return NULL; +} + +static const WCHAR *strrchrW(const WCHAR *str, WCHAR ch) +{ + const WCHAR *ret = NULL; + for(;*str != 0;++str) + { + if(*str == ch) + ret = str; + } + return ret; +} + +/* Compares the filename in the find data with the match string. The match + * string may contain the "%r" marker to signifiy a sample rate (really any + * positive integer), or "%%" to signify a single '%'. + */ +static int MatchFilter(const WCHAR *match, const WIN32_FIND_DATAW *fdata) +{ + const WCHAR *name = fdata->cFileName; + int ret = 1; + + do { + const WCHAR *p = strchrW(match, '%'); + if(!p) + ret = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, + match, -1, name, -1) == CSTR_EQUAL; + else + { + int len = p-match; + ret = lstrlenW(name) >= len; + if(ret) + ret = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, + match, len, name, len) == CSTR_EQUAL; + if(ret) + { + match += len; + name += len; + + ++p; + if(*p == 'r') + { + unsigned long l = 0; + while(*name >= '0' && *name <= '9') + { + l = l*10 + (*name-'0'); + ++name; + } + ret = l > 0; + ++p; + } + } + } + + match = p; + } while(ret && match && *match); + + return ret; +} + +static void RecurseDirectorySearch(const char *path, const WCHAR *match, vector_al_string *results) +{ + WIN32_FIND_DATAW fdata; + const WCHAR *sep, *p; + HANDLE hdl; + + if(!match[0]) + return; + + /* Find the last directory separator and the next '%' marker in the match + * string. */ + sep = strrchrW(match, '\\'); + p = strchrW(match, '%'); + + /* If there's no separator, test the files in the specified path against + * the match string, and add the results. */ + if(!sep) + { + al_string pathstr = AL_STRING_INIT_STATIC(); + WCHAR *wpath; + + TRACE("Searching %s for %ls\n", path, match); + + al_string_append_cstr(&pathstr, path); + al_string_append_cstr(&pathstr, "\\*.*"); + wpath = FromUTF8(al_string_get_cstr(pathstr)); + + hdl = FindFirstFileW(wpath, &fdata); + if(hdl != INVALID_HANDLE_VALUE) + { + do { + if(MatchFilter(match, &fdata)) + { + al_string str = AL_STRING_INIT_STATIC(); + al_string_copy_cstr(&str, path); + al_string_append_char(&str, '\\'); + al_string_append_wcstr(&str, fdata.cFileName); + TRACE("Got result %s\n", al_string_get_cstr(str)); + VECTOR_PUSH_BACK(*results, str); + } + } while(FindNextFileW(hdl, &fdata)); + FindClose(hdl); + } + + free(wpath); + al_string_deinit(&pathstr); + + return; + } + + /* If there's no '%' marker, or it's after the final separator, append the + * remaining directories to the path and recurse into it with the remaining + * filename portion. */ + if(!p || p-sep >= 0) + { + al_string npath = AL_STRING_INIT_STATIC(); + al_string_append_cstr(&npath, path); + al_string_append_char(&npath, '\\'); + al_string_append_wrange(&npath, match, sep); + + TRACE("Recursing into %s with %ls\n", al_string_get_cstr(npath), sep+1); + RecurseDirectorySearch(al_string_get_cstr(npath), sep+1, results); + + al_string_deinit(&npath); + return; + } + + /* Look for the last separator before the '%' marker, and the first + * separator after it. */ + sep = strchrW(match, '\\'); + if(sep-p >= 0) sep = NULL; + for(;;) + { + const WCHAR *next = strchrW(sep?sep+1:match, '\\'); + if(next-p < 0) + { + al_string npath = AL_STRING_INIT_STATIC(); + WCHAR *nwpath, *nwmatch; + + /* Append up to the last directory before the one with a '%'. */ + al_string_copy_cstr(&npath, path); + if(sep) + { + al_string_append_char(&npath, '\\'); + al_string_append_wrange(&npath, match, sep); + } + al_string_append_cstr(&npath, "\\*.*"); + nwpath = FromUTF8(al_string_get_cstr(npath)); + + /* Take the directory name containing a '%' as a new string to + * match against. */ + if(!sep) + { + nwmatch = calloc(2, next-match+1); + memcpy(nwmatch, match, (next-match)*2); + } + else + { + nwmatch = calloc(2, next-(sep+1)+1); + memcpy(nwmatch, sep+1, (next-(sep+1))*2); + } + + /* For each matching directory name, recurse into it with the + * remaining string. */ + TRACE("Searching %s for %ls\n", al_string_get_cstr(npath), nwmatch); + hdl = FindFirstFileW(nwpath, &fdata); + if(hdl != INVALID_HANDLE_VALUE) + { + do { + if(MatchFilter(nwmatch, &fdata)) + { + al_string ndir = AL_STRING_INIT_STATIC(); + al_string_copy(&ndir, npath); + al_string_append_char(&ndir, '\\'); + al_string_append_wcstr(&ndir, fdata.cFileName); + TRACE("Recursing %s with %ls\n", al_string_get_cstr(ndir), next+1); + RecurseDirectorySearch(al_string_get_cstr(ndir), next+1, results); + al_string_deinit(&ndir); + } + } while(FindNextFileW(hdl, &fdata)); + FindClose(hdl); + } + + free(nwmatch); + free(nwpath); + al_string_deinit(&npath); + break; + } + sep = next; + } +} + +vector_al_string SearchDataFiles(const char *match, const char *subdir) +{ + static const int ids[2] = { CSIDL_APPDATA, CSIDL_COMMON_APPDATA }; + static RefCount search_lock; + vector_al_string results = VECTOR_INIT_STATIC(); + WCHAR *wmatch; + size_t i; + + while(ATOMIC_EXCHANGE(uint, &search_lock, 1) == 1) + althrd_yield(); + + wmatch = FromUTF8(match); + if(!wmatch) + { + ERR("Failed to convert UTF-8 filename: \"%s\"\n", match); + return results; + } + for(i = 0;wmatch[i];++i) + { + if(wmatch[i] == '/') + wmatch[i] = '\\'; + } + + /* If the path is absolute, use it directly. */ + if(isalpha(wmatch[0]) && wmatch[1] == ':' && is_slash(wmatch[2])) + { + char drv[3] = { (char)wmatch[0], ':', 0 }; + RecurseDirectorySearch(drv, wmatch+3, &results); + } + else if(wmatch[0] == '\\' && wmatch[1] == '\\' && wmatch[2] == '?' && wmatch[3] == '\\') + RecurseDirectorySearch("\\\\?", wmatch+4, &results); + else + { + al_string path = AL_STRING_INIT_STATIC(); + WCHAR *cwdbuf; + + /* Search the CWD. */ + if(!(cwdbuf=_wgetcwd(NULL, 0))) + al_string_copy_cstr(&path, "."); + else + { + al_string_copy_wcstr(&path, cwdbuf); + if(is_slash(VECTOR_BACK(path))) + { + VECTOR_POP_BACK(path); + *VECTOR_ITER_END(path) = 0; + } + free(cwdbuf); + } + RecurseDirectorySearch(al_string_get_cstr(path), wmatch, &results); + + /* Search the local and global data dirs. */ + for(i = 0;i < COUNTOF(ids);i++) + { + WCHAR buffer[PATH_MAX]; + if(SHGetSpecialFolderPathW(NULL, buffer, ids[i], FALSE) != FALSE) + { + al_string_copy_wcstr(&path, buffer); + if(!is_slash(VECTOR_BACK(path))) + al_string_append_char(&path, '\\'); + al_string_append_cstr(&path, subdir); +#define FIX_SLASH(i) do { if(*(i) == '/') *(i) = '\\'; } while(0) + VECTOR_FOR_EACH(char, path, FIX_SLASH); +#undef FIX_SLASH + + RecurseDirectorySearch(al_string_get_cstr(path), wmatch, &results); + } + } + + al_string_deinit(&path); + } + + free(wmatch); + ATOMIC_STORE(&search_lock, 0); + + return results; +} + #else #ifdef HAVE_DLFCN_H @@ -453,9 +859,7 @@ void *GetSymbol(void *handle, const char *name) return sym; } -#endif -#endif - +#endif /* HAVE_DLFCN_H */ void al_print(const char *type, const char *func, const char *fmt, ...) { @@ -469,76 +873,7 @@ void al_print(const char *type, const char *func, const char *fmt, ...) fflush(LogFile); } -#ifdef _WIN32 -static inline int is_slash(int c) -{ return (c == '\\' || c == '/'); } -FILE *OpenDataFile(const char *fname, const char *subdir) -{ - static const int ids[2] = { CSIDL_APPDATA, CSIDL_COMMON_APPDATA }; - WCHAR *wname=NULL, *wsubdir=NULL; - FILE *f; - int i; - - /* If the path is absolute, open it directly. */ - if(fname[0] != '\0' && fname[1] == ':' && is_slash(fname[2])) - { - if((f=al_fopen(fname, "rb")) != NULL) - { - TRACE("Opened %s\n", fname); - return f; - } - WARN("Could not open %s\n", fname); - return NULL; - } - - /* If it's relative, try the current directory first before the data directories. */ - if((f=al_fopen(fname, "rb")) != NULL) - { - TRACE("Opened %s\n", fname); - return f; - } - WARN("Could not open %s\n", fname); - - wname = FromUTF8(fname); - wsubdir = FromUTF8(subdir); - if(!wname) - ERR("Failed to convert UTF-8 filename: \"%s\"\n", fname); - else if(!wsubdir) - ERR("Failed to convert UTF-8 subdir: \"%s\"\n", subdir); - else for(i = 0;i < 2;i++) - { - WCHAR buffer[PATH_MAX]; - size_t len; - - if(SHGetSpecialFolderPathW(NULL, buffer, ids[i], FALSE) == FALSE) - continue; - - len = lstrlenW(buffer); - if(len > 0 && is_slash(buffer[len-1])) - buffer[--len] = '\0'; - _snwprintf(buffer+len, PATH_MAX-len, L"/%ls/%ls", wsubdir, wname); - len = lstrlenW(buffer); - while(len > 0) - { - --len; - if(buffer[len] == '/') - buffer[len] = '\\'; - } - - if((f=_wfopen(buffer, L"rb")) != NULL) - { - TRACE("Opened %ls\n", buffer); - return f; - } - WARN("Could not open %ls\n", buffer); - } - free(wname); - free(wsubdir); - - return NULL; -} -#else FILE *OpenDataFile(const char *fname, const char *subdir) { char buffer[PATH_MAX] = ""; @@ -561,7 +896,6 @@ FILE *OpenDataFile(const char *fname, const char *subdir) TRACE("Opened %s\n", fname); return f; } - WARN("Could not open %s\n", fname); if((str=getenv("XDG_DATA_HOME")) != NULL && str[0] != '\0') snprintf(buffer, sizeof(buffer), "%s/%s/%s", str, subdir, fname); @@ -574,7 +908,6 @@ FILE *OpenDataFile(const char *fname, const char *subdir) TRACE("Opened %s\n", buffer); return f; } - WARN("Could not open %s\n", buffer); } if((str=getenv("XDG_DATA_DIRS")) == NULL || str[0] == '\0') @@ -605,11 +938,221 @@ FILE *OpenDataFile(const char *fname, const char *subdir) TRACE("Opened %s\n", buffer); return f; } - WARN("Could not open %s\n", buffer); } + WARN("Could not open %s/%s\n", subdir, fname); return NULL; } + + +static const char *MatchString; +static int MatchFilter(const struct dirent *dir) +{ + const char *match = MatchString; + const char *name = dir->d_name; + int ret = 1; + + do { + const char *p = strchr(match, '%'); + if(!p) + ret = strcmp(match, name) == 0; + else + { + size_t len = p-match; + ret = strncmp(match, name, len) == 0; + if(ret) + { + match += len; + name += len; + + ++p; + if(*p == 'r') + { + char *end; + ret = strtoul(name, &end, 10) > 0; + if(ret) name = end; + ++p; + } + } + } + + match = p; + } while(ret && match && *match); + + return ret; +} + +static void RecurseDirectorySearch(const char *path, const char *match, vector_al_string *results) +{ + struct dirent **namelist; + char *sep, *p; + int n, i; + + if(!match[0]) + return; + + sep = strrchr(match, '/'); + p = strchr(match, '%'); + + if(!sep) + { + MatchString = match; + TRACE("Searching %s for %s\n", path?path:"/", match); + n = scandir(path?path:"/", &namelist, MatchFilter, alphasort); + if(n >= 0) + { + for(i = 0;i < n;++i) + { + al_string str = AL_STRING_INIT_STATIC(); + if(path) al_string_copy_cstr(&str, path); + al_string_append_char(&str, '/'); + al_string_append_cstr(&str, namelist[i]->d_name); + TRACE("Got result %s\n", al_string_get_cstr(str)); + VECTOR_PUSH_BACK(*results, str); + free(namelist[i]); + } + free(namelist); + } + + return; + } + + if(!p || p-sep >= 0) + { + al_string npath = AL_STRING_INIT_STATIC(); + if(path) al_string_append_cstr(&npath, path); + al_string_append_char(&npath, '/'); + al_string_append_range(&npath, match, sep); + + TRACE("Recursing into %s with %s\n", al_string_get_cstr(npath), sep+1); + RecurseDirectorySearch(al_string_get_cstr(npath), sep+1, results); + + al_string_deinit(&npath); + return; + } + + sep = strchr(match, '/'); + if(sep-p >= 0) sep = NULL; + for(;;) + { + char *next = strchr(sep?sep+1:match, '/'); + if(next-p < 0) + { + al_string npath = AL_STRING_INIT_STATIC(); + al_string nmatch = AL_STRING_INIT_STATIC(); + + if(!sep) + { + al_string_append_cstr(&npath, path?path:"/."); + MatchString = match; + } + else + { + if(path) al_string_append_cstr(&npath, path); + al_string_append_char(&npath, '/'); + al_string_append_range(&npath, match, sep); + + al_string_append_range(&nmatch, sep+1, next); + MatchString = al_string_get_cstr(nmatch); + } + + TRACE("Searching %s for %s\n", al_string_get_cstr(npath), MatchString); + n = scandir(al_string_get_cstr(npath), &namelist, MatchFilter, alphasort); + if(n >= 0) + { + al_string ndir = AL_STRING_INIT_STATIC(); + for(i = 0;i < n;++i) + { + al_string_copy(&ndir, npath); + al_string_append_char(&ndir, '/'); + al_string_append_cstr(&ndir, namelist[i]->d_name); + free(namelist[i]); + TRACE("Recursing %s with %s\n", al_string_get_cstr(ndir), next+1); + RecurseDirectorySearch(al_string_get_cstr(ndir), next+1, results); + } + al_string_deinit(&ndir); + free(namelist); + } + + al_string_deinit(&nmatch); + al_string_deinit(&npath); + break; + } + + sep = next; + } +} + +vector_al_string SearchDataFiles(const char *match, const char *subdir) +{ + static RefCount search_lock; + vector_al_string results = VECTOR_INIT_STATIC(); + + while(ATOMIC_EXCHANGE(uint, &search_lock, 1) == 1) + althrd_yield(); + + if(match[0] == '/') + RecurseDirectorySearch(NULL, match+1, &results); + else + { + al_string path = AL_STRING_INIT_STATIC(); + const char *str, *next; + char cwdbuf[PATH_MAX]; + + // Search CWD + if(!getcwd(cwdbuf, sizeof(cwdbuf))) + strcpy(cwdbuf, "."); + RecurseDirectorySearch(cwdbuf, match, &results); + + // Search local data dir + if((str=getenv("XDG_DATA_HOME")) != NULL && str[0] != '\0') + { + al_string_append_cstr(&path, str); + al_string_append_char(&path, '/'); + al_string_append_cstr(&path, subdir); + } + else if((str=getenv("HOME")) != NULL && str[0] != '\0') + { + al_string_append_cstr(&path, str); + al_string_append_cstr(&path, "/.local/share/"); + al_string_append_cstr(&path, subdir); + } + if(!al_string_empty(path)) + RecurseDirectorySearch(al_string_get_cstr(path), match, &results); + + // Search global data dirs + if((str=getenv("XDG_DATA_DIRS")) == NULL || str[0] == '\0') + str = "/usr/local/share/:/usr/share/"; + + next = str; + while((str=next) != NULL && str[0] != '\0') + { + next = strchr(str, ':'); + if(!next) + al_string_copy_cstr(&path, str); + else + { + al_string_clear(&path); + al_string_append_range(&path, str, next); + ++next; + } + if(!al_string_empty(path)) + { + al_string_append_char(&path, '/'); + al_string_append_cstr(&path, subdir); + + RecurseDirectorySearch(al_string_get_cstr(path), match, &results); + } + } + + al_string_deinit(&path); + } + + ATOMIC_STORE(&search_lock, 0); + + return results; +} + #endif @@ -638,25 +1181,20 @@ void SetRTPriority(void) } -ALboolean vector_reserve(char *ptr, size_t base_size, size_t obj_size, ALsizei obj_count, ALboolean exact) +ALboolean vector_reserve(char *ptr, size_t base_size, size_t obj_size, size_t obj_count, ALboolean exact) { vector_ *vecptr = (vector_*)ptr; - if(obj_count < 0) - return AL_FALSE; if((*vecptr ? (*vecptr)->Capacity : 0) < obj_count) { - ALsizei old_size = (*vecptr ? (*vecptr)->Size : 0); + size_t old_size = (*vecptr ? (*vecptr)->Size : 0); void *temp; /* Use the next power-of-2 size if we don't need to allocate the exact * amount. This is preferred when regularly increasing the vector since * it means fewer reallocations. Though it means it also wastes some * memory. */ - if(exact == AL_FALSE) - { + if(exact == AL_FALSE && obj_count < INT_MAX) obj_count = NextPowerOf2((ALuint)obj_count); - if(obj_count < 0) return AL_FALSE; - } /* Need to be explicit with the caller type's base size, because it * could have extra padding before the start of the array (that is, @@ -671,11 +1209,9 @@ ALboolean vector_reserve(char *ptr, size_t base_size, size_t obj_size, ALsizei o return AL_TRUE; } -ALboolean vector_resize(char *ptr, size_t base_size, size_t obj_size, ALsizei obj_count) +ALboolean vector_resize(char *ptr, size_t base_size, size_t obj_size, size_t obj_count) { vector_ *vecptr = (vector_*)ptr; - if(obj_count < 0) - return AL_FALSE; if(*vecptr || obj_count > 0) { if(!vector_reserve((char*)vecptr, base_size, obj_size, obj_count, AL_TRUE)) @@ -696,12 +1232,12 @@ ALboolean vector_insert(char *ptr, size_t base_size, size_t obj_size, void *ins_ ptrdiff_t numins = ((const char*)datend - (const char*)datstart) / obj_size; assert(numins > 0); - if(INT_MAX-VECTOR_SIZE(*vecptr) <= numins || + if((size_t)numins + VECTOR_SIZE(*vecptr) < (size_t)numins || !vector_reserve((char*)vecptr, base_size, obj_size, VECTOR_SIZE(*vecptr)+numins, AL_TRUE)) return AL_FALSE; /* NOTE: ins_pos may have been invalidated if *vecptr moved. Use ins_elem instead. */ - if(ins_elem < (*vecptr)->Size) + if((size_t)ins_elem < (*vecptr)->Size) { memmove((char*)(*vecptr) + base_size + ((ins_elem+numins)*obj_size), (char*)(*vecptr) + base_size + ((ins_elem )*obj_size), @@ -709,14 +1245,14 @@ ALboolean vector_insert(char *ptr, size_t base_size, size_t obj_size, void *ins_ } memcpy((char*)(*vecptr) + base_size + (ins_elem*obj_size), datstart, numins*obj_size); - (*vecptr)->Size += (ALsizei)numins; + (*vecptr)->Size += numins; } return AL_TRUE; } extern inline void al_string_deinit(al_string *str); -extern inline ALsizei al_string_length(const_al_string str); +extern inline size_t al_string_length(const_al_string str); extern inline ALboolean al_string_empty(const_al_string str); extern inline const al_string_char_type *al_string_get_cstr(const_al_string str); @@ -730,10 +1266,10 @@ void al_string_clear(al_string *str) *VECTOR_ITER_END(*str) = 0; } -static inline int al_string_compare(const al_string_char_type *str1, ALsizei str1len, - const al_string_char_type *str2, ALsizei str2len) +static inline int al_string_compare(const al_string_char_type *str1, size_t str1len, + const al_string_char_type *str2, size_t str2len) { - ALsizei complen = mini(str1len, str2len); + size_t complen = (str1len < str2len) ? str1len : str2len; int ret = memcmp(str1, str2, complen); if(ret == 0) { @@ -750,12 +1286,12 @@ int al_string_cmp(const_al_string str1, const_al_string str2) int al_string_cmp_cstr(const_al_string str1, const al_string_char_type *str2) { return al_string_compare(&VECTOR_FRONT(str1), al_string_length(str1), - str2, (ALsizei)strlen(str2)); + str2, strlen(str2)); } void al_string_copy(al_string *str, const_al_string from) { - ALsizei len = VECTOR_SIZE(from); + size_t len = al_string_length(from); VECTOR_RESERVE(*str, len+1); VECTOR_RESIZE(*str, 0); VECTOR_INSERT(*str, VECTOR_ITER_END(*str), VECTOR_ITER_BEGIN(from), VECTOR_ITER_BEGIN(from)+len); @@ -811,4 +1347,30 @@ void al_string_copy_wcstr(al_string *str, const wchar_t *from) *VECTOR_ITER_END(*str) = 0; } } + +void al_string_append_wcstr(al_string *str, const wchar_t *from) +{ + int len; + if((len=WideCharToMultiByte(CP_UTF8, 0, from, -1, NULL, 0, NULL, NULL)) > 0) + { + size_t strlen = al_string_length(*str); + VECTOR_RESERVE(*str, strlen+len); + VECTOR_RESIZE(*str, strlen+len-1); + WideCharToMultiByte(CP_UTF8, 0, from, -1, &VECTOR_FRONT(*str) + strlen, len, NULL, NULL); + *VECTOR_ITER_END(*str) = 0; + } +} + +void al_string_append_wrange(al_string *str, const wchar_t *from, const wchar_t *to) +{ + int len; + if((len=WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), NULL, 0, NULL, NULL)) > 0) + { + size_t strlen = al_string_length(*str); + VECTOR_RESERVE(*str, strlen+len+1); + VECTOR_RESIZE(*str, strlen+len); + WideCharToMultiByte(CP_UTF8, 0, from, (int)(to-from), &VECTOR_FRONT(*str) + strlen, len+1, NULL, NULL); + *VECTOR_ITER_END(*str) = 0; + } +} #endif diff --git a/libs/openal-soft/Alc/hrtf.c b/libs/openal-soft/Alc/hrtf.c index 707655a0..71dd9d79 100644 --- a/libs/openal-soft/Alc/hrtf.c +++ b/libs/openal-soft/Alc/hrtf.c @@ -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 */ @@ -30,6 +30,8 @@ #include "alu.h" #include "hrtf.h" +#include "compat.h" + /* Current data set limits defined by the makehrtf utility. */ #define MIN_IR_SIZE (8) @@ -52,6 +54,7 @@ struct Hrtf { const ALshort *coeffs; const ALubyte *delays; + al_string filename; struct Hrtf *next; }; @@ -82,45 +85,12 @@ static void CalcEvIndices(ALuint evcount, ALfloat ev, ALuint *evidx, ALfloat *ev */ static void CalcAzIndices(ALuint azcount, ALfloat az, ALuint *azidx, ALfloat *azmu) { - az = (F_2PI + az) * azcount / (F_2PI); + az = (F_TAU + az) * azcount / F_TAU; azidx[0] = fastf2u(az) % azcount; azidx[1] = (azidx[0] + 1) % azcount; *azmu = az - floorf(az); } -/* Calculates the normalized HRTF transition factor (delta) from the changes - * in gain and listener to source angle between updates. The result is a - * normalized delta factor that can be used to calculate moving HRIR stepping - * values. - */ -ALfloat CalcHrtfDelta(ALfloat oldGain, ALfloat newGain, const ALfloat olddir[3], const ALfloat newdir[3]) -{ - ALfloat gainChange, angleChange, change; - - // Calculate the normalized dB gain change. - newGain = maxf(newGain, 0.0001f); - oldGain = maxf(oldGain, 0.0001f); - gainChange = fabsf(log10f(newGain / oldGain) / log10f(0.0001f)); - - // Calculate the angle change only when there is enough gain to notice it. - angleChange = 0.0f; - if(gainChange > 0.0001f || newGain > 0.0001f) - { - // No angle change when the directions are equal or degenerate (when - // both have zero length). - if(newdir[0] != olddir[0] || newdir[1] != olddir[1] || newdir[2] != olddir[2]) - { - ALfloat dotp = olddir[0]*newdir[0] + olddir[1]*newdir[1] + olddir[2]*newdir[2]; - angleChange = acosf(clampf(dotp, -1.0f, 1.0f)) / F_PI; - } - } - - // Use the largest of the two changes for the delta factor, and apply a - // significance shaping function to it. - change = maxf(angleChange * 25.0f, gainChange) * 2.0f; - return minf(change, 1.0f); -} - /* Calculates static HRIR coefficients and delays for the given polar * elevation and azimuth in radians. Linear interpolation is used to * increase the apparent resolution of the HRIR data set. The coefficients @@ -183,24 +153,22 @@ void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azi { ALfloat c; - gain *= 1.0f/32767.0f; - i = 0; c = (Hrtf->coeffs[lidx[0]+i]*blend[0] + Hrtf->coeffs[lidx[1]+i]*blend[1] + Hrtf->coeffs[lidx[2]+i]*blend[2] + Hrtf->coeffs[lidx[3]+i]*blend[3]); - coeffs[i][0] = lerp(PassthruCoeff, c, dirfact) * gain; + coeffs[i][0] = lerp(PassthruCoeff, c, dirfact) * gain * (1.0f/32767.0f); c = (Hrtf->coeffs[ridx[0]+i]*blend[0] + Hrtf->coeffs[ridx[1]+i]*blend[1] + Hrtf->coeffs[ridx[2]+i]*blend[2] + Hrtf->coeffs[ridx[3]+i]*blend[3]); - coeffs[i][1] = lerp(PassthruCoeff, c, dirfact) * gain; + coeffs[i][1] = lerp(PassthruCoeff, c, dirfact) * gain * (1.0f/32767.0f); for(i = 1;i < Hrtf->irSize;i++) { c = (Hrtf->coeffs[lidx[0]+i]*blend[0] + Hrtf->coeffs[lidx[1]+i]*blend[1] + Hrtf->coeffs[lidx[2]+i]*blend[2] + Hrtf->coeffs[lidx[3]+i]*blend[3]); - coeffs[i][0] = lerp(0.0f, c, dirfact) * gain; + coeffs[i][0] = lerp(0.0f, c, dirfact) * gain * (1.0f/32767.0f); c = (Hrtf->coeffs[ridx[0]+i]*blend[0] + Hrtf->coeffs[ridx[1]+i]*blend[1] + Hrtf->coeffs[ridx[2]+i]*blend[2] + Hrtf->coeffs[ridx[3]+i]*blend[3]); - coeffs[i][1] = lerp(0.0f, c, dirfact) * gain; + coeffs[i][1] = lerp(0.0f, c, dirfact) * gain * (1.0f/32767.0f); } } else @@ -225,7 +193,7 @@ ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat a ALuint evidx[2], lidx[4], ridx[4]; ALfloat mu[3], blend[4]; ALfloat left, right; - ALfloat step; + ALfloat steps; ALuint i; /* Claculate elevation indices and interpolation factor. */ @@ -248,8 +216,8 @@ ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat a } // Calculate the stepping parameters. - delta = maxf(floorf(delta*(Hrtf->sampleRate*0.015f) + 0.5f), 1.0f); - step = 1.0f / delta; + steps = maxf(floorf(delta*Hrtf->sampleRate + 0.5f), 1.0f); + delta = 1.0f / steps; /* Calculate 4 blending weights for 2D bilinear interpolation. */ blend[0] = (1.0f-mu[0]) * (1.0f-mu[2]); @@ -271,8 +239,8 @@ ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat a Hrtf->delays[ridx[2]]*blend[2] + Hrtf->delays[ridx[3]]*blend[3]) * dirfact + 0.5f) << HRTFDELAY_BITS; - delayStep[0] = fastf2i(step * (delays[0] - left)); - delayStep[1] = fastf2i(step * (delays[1] - right)); + delayStep[0] = fastf2i(delta * (delays[0] - left)); + delayStep[1] = fastf2i(delta * (delays[1] - right)); /* Calculate the sample offsets for the HRIR indices. */ lidx[0] *= Hrtf->irSize; @@ -294,21 +262,19 @@ ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat a { ALfloat c; - gain *= 1.0f/32767.0f; - i = 0; left = coeffs[i][0] - (coeffStep[i][0] * counter); right = coeffs[i][1] - (coeffStep[i][1] * counter); c = (Hrtf->coeffs[lidx[0]+i]*blend[0] + Hrtf->coeffs[lidx[1]+i]*blend[1] + Hrtf->coeffs[lidx[2]+i]*blend[2] + Hrtf->coeffs[lidx[3]+i]*blend[3]); - coeffs[i][0] = lerp(PassthruCoeff, c, dirfact) * gain; + coeffs[i][0] = lerp(PassthruCoeff, c, dirfact) * gain * (1.0f/32767.0f); c = (Hrtf->coeffs[ridx[0]+i]*blend[0] + Hrtf->coeffs[ridx[1]+i]*blend[1] + Hrtf->coeffs[ridx[2]+i]*blend[2] + Hrtf->coeffs[ridx[3]+i]*blend[3]); - coeffs[i][1] = lerp(PassthruCoeff, c, dirfact) * gain; + coeffs[i][1] = lerp(PassthruCoeff, c, dirfact) * gain * (1.0f/32767.0f); - coeffStep[i][0] = step * (coeffs[i][0] - left); - coeffStep[i][1] = step * (coeffs[i][1] - right); + coeffStep[i][0] = delta * (coeffs[i][0] - left); + coeffStep[i][1] = delta * (coeffs[i][1] - right); for(i = 1;i < Hrtf->irSize;i++) { @@ -317,13 +283,13 @@ ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat a c = (Hrtf->coeffs[lidx[0]+i]*blend[0] + Hrtf->coeffs[lidx[1]+i]*blend[1] + Hrtf->coeffs[lidx[2]+i]*blend[2] + Hrtf->coeffs[lidx[3]+i]*blend[3]); - coeffs[i][0] = lerp(0.0f, c, dirfact) * gain; + coeffs[i][0] = lerp(0.0f, c, dirfact) * gain * (1.0f/32767.0f); c = (Hrtf->coeffs[ridx[0]+i]*blend[0] + Hrtf->coeffs[ridx[1]+i]*blend[1] + Hrtf->coeffs[ridx[2]+i]*blend[2] + Hrtf->coeffs[ridx[3]+i]*blend[3]); - coeffs[i][1] = lerp(0.0f, c, dirfact) * gain; + coeffs[i][1] = lerp(0.0f, c, dirfact) * gain * (1.0f/32767.0f); - coeffStep[i][0] = step * (coeffs[i][0] - left); - coeffStep[i][1] = step * (coeffs[i][1] - right); + coeffStep[i][0] = delta * (coeffs[i][0] - left); + coeffStep[i][1] = delta * (coeffs[i][1] - right); } } else @@ -336,8 +302,8 @@ ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat a coeffs[i][0] = 0.0f; coeffs[i][1] = 0.0f; - coeffStep[i][0] = step * -left; - coeffStep[i][1] = step * -right; + coeffStep[i][0] = delta * -left; + coeffStep[i][1] = delta * -right; } } @@ -345,13 +311,118 @@ ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat a * complete its transition. The mixer will only apply stepping for this * many samples. */ - return fastf2u(delta); + return fastf2u(steps); } -static struct Hrtf *LoadHrtf00(FILE *f, ALuint deviceRate) +/* Calculates HRTF coefficients for B-Format channels (only up to first-order). + * Note that these will decode a B-Format output mix, which uses FuMa ordering + * and scaling, not N3D! + */ +void GetBFormatHrtfCoeffs(const struct Hrtf *Hrtf, const ALuint num_chans, ALfloat (**coeffs_list)[2], ALuint **delay_list) { - const ALubyte maxDelay = SRC_HISTORY_LENGTH-1; + ALuint elev_idx, azi_idx; + ALfloat scale; + ALuint i, c; + + assert(num_chans <= 4); + + for(c = 0;c < num_chans;c++) + { + ALfloat (*coeffs)[2] = coeffs_list[c]; + ALuint *delay = delay_list[c]; + + for(i = 0;i < Hrtf->irSize;i++) + { + coeffs[i][0] = 0.0f; + coeffs[i][1] = 0.0f; + } + delay[0] = 0; + delay[1] = 0; + } + + /* NOTE: HRTF coefficients are generated by combining all the HRIRs in the + * dataset, with each entry scaled according to how much it contributes to + * the given B-Format channel based on its direction (including negative + * contributions!). + */ + scale = 0.0f; + for(elev_idx = 0;elev_idx < Hrtf->evCount;elev_idx++) + { + ALfloat elev = (ALfloat)elev_idx/(ALfloat)(Hrtf->evCount-1)*F_PI - F_PI_2; + ALuint evoffset = Hrtf->evOffset[elev_idx]; + ALuint azcount = Hrtf->azCount[elev_idx]; + + scale += (ALfloat)azcount; + + for(azi_idx = 0;azi_idx < azcount;azi_idx++) + { + ALuint lidx, ridx; + ALfloat ambi_coeffs[4]; + ALfloat az, gain; + ALfloat x, y, z; + + lidx = evoffset + azi_idx; + ridx = evoffset + ((azcount-azi_idx) % azcount); + + az = (ALfloat)azi_idx / (ALfloat)azcount * F_TAU; + if(az > F_PI) az -= F_TAU; + + x = cosf(-az) * cosf(elev); + y = sinf(-az) * cosf(elev); + z = sinf(elev); + + ambi_coeffs[0] = 1.414213562f; + ambi_coeffs[1] = x; + ambi_coeffs[2] = y; + ambi_coeffs[3] = z; + + for(c = 0;c < num_chans;c++) + { + ALfloat (*coeffs)[2] = coeffs_list[c]; + ALuint *delay = delay_list[c]; + + /* NOTE: Always include the total delay average since the + * channels need to have matching delays. */ + delay[0] += Hrtf->delays[lidx]; + delay[1] += Hrtf->delays[ridx]; + + gain = ambi_coeffs[c]; + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + + for(i = 0;i < Hrtf->irSize;i++) + { + coeffs[i][0] += Hrtf->coeffs[lidx*Hrtf->irSize + i]*(1.0f/32767.0f) * gain; + coeffs[i][1] += Hrtf->coeffs[ridx*Hrtf->irSize + i]*(1.0f/32767.0f) * gain; + } + } + } + } + + scale = 1.0f/scale; + + for(c = 0;c < num_chans;c++) + { + ALfloat (*coeffs)[2] = coeffs_list[c]; + ALuint *delay = delay_list[c]; + + for(i = 0;i < Hrtf->irSize;i++) + { + coeffs[i][0] *= scale; + coeffs[i][1] *= scale; + } + delay[0] = minu((ALuint)((ALfloat)delay[0] * scale), HRTF_HISTORY_LENGTH-1); + delay[0] <<= HRTFDELAY_BITS; + delay[1] = minu((ALuint)((ALfloat)delay[1] * scale), HRTF_HISTORY_LENGTH-1); + delay[1] <<= HRTFDELAY_BITS; + } +} + + +static struct Hrtf *LoadHrtf00(FILE *f) +{ + const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1; struct Hrtf *Hrtf = NULL; ALboolean failed = AL_FALSE; ALuint rate = 0, irCount = 0; @@ -376,12 +447,6 @@ static struct Hrtf *LoadHrtf00(FILE *f, ALuint deviceRate) evCount = fgetc(f); - if(rate != deviceRate) - { - ERR("HRIR rate does not match device rate: rate=%d (%d)\n", - rate, deviceRate); - failed = AL_TRUE; - } if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE)) { ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n", @@ -504,6 +569,7 @@ static struct Hrtf *LoadHrtf00(FILE *f, ALuint deviceRate) Hrtf->evOffset = evOffset; Hrtf->coeffs = coeffs; Hrtf->delays = delays; + AL_STRING_INIT(Hrtf->filename); Hrtf->next = NULL; return Hrtf; } @@ -516,9 +582,9 @@ static struct Hrtf *LoadHrtf00(FILE *f, ALuint deviceRate) } -static struct Hrtf *LoadHrtf01(FILE *f, ALuint deviceRate) +static struct Hrtf *LoadHrtf01(FILE *f) { - const ALubyte maxDelay = SRC_HISTORY_LENGTH-1; + const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1; struct Hrtf *Hrtf = NULL; ALboolean failed = AL_FALSE; ALuint rate = 0, irCount = 0; @@ -538,12 +604,6 @@ static struct Hrtf *LoadHrtf01(FILE *f, ALuint deviceRate) evCount = fgetc(f); - if(rate != deviceRate) - { - ERR("HRIR rate does not match device rate: rate=%d (%d)\n", - rate, deviceRate); - failed = AL_TRUE; - } if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE)) { ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n", @@ -649,6 +709,7 @@ static struct Hrtf *LoadHrtf01(FILE *f, ALuint deviceRate) Hrtf->evOffset = evOffset; Hrtf->coeffs = coeffs; Hrtf->delays = delays; + AL_STRING_INIT(Hrtf->filename); Hrtf->next = NULL; return Hrtf; } @@ -661,144 +722,167 @@ static struct Hrtf *LoadHrtf01(FILE *f, ALuint deviceRate) } -static struct Hrtf *LoadHrtf(ALuint deviceRate) +static void AddFileEntry(vector_HrtfEntry *list, al_string *filename) { - const char *fnamelist = "default-%r.mhr"; + HrtfEntry entry = { AL_STRING_INIT_STATIC(), *filename, NULL }; + HrtfEntry *iter; + const char *name; + int i; - ConfigValueStr(NULL, "hrtf_tables", &fnamelist); - while(*fnamelist != '\0') + name = strrchr(al_string_get_cstr(entry.filename), '/'); + if(!name) name = strrchr(al_string_get_cstr(entry.filename), '\\'); + if(!name) name = al_string_get_cstr(entry.filename); + else ++name; + + entry.hrtf = LoadedHrtfs; + while(entry.hrtf) { - struct Hrtf *Hrtf = NULL; - char fname[PATH_MAX]; - const char *next; + if(al_string_cmp(entry.filename, entry.hrtf->filename) == 0) + break; + entry.hrtf = entry.hrtf->next; + } + + if(!entry.hrtf) + { + struct Hrtf *hrtf = NULL; ALchar magic[8]; - ALuint i; FILE *f; - i = 0; - while(isspace(*fnamelist) || *fnamelist == ',') - fnamelist++; - next = fnamelist; - while(*(fnamelist=next) != '\0' && *fnamelist != ',') - { - next = strpbrk(fnamelist, "%,"); - while(fnamelist != next && *fnamelist && i < sizeof(fname)) - fname[i++] = *(fnamelist++); - - if(!next || *next == ',') - break; - - /* *next == '%' */ - next++; - if(*next == 'r') - { - int wrote = snprintf(&fname[i], sizeof(fname)-i, "%u", deviceRate); - i += minu(wrote, sizeof(fname)-i); - next++; - } - else if(*next == '%') - { - if(i < sizeof(fname)) - fname[i++] = '%'; - next++; - } - else - ERR("Invalid marker '%%%c'\n", *next); - } - i = minu(i, sizeof(fname)-1); - fname[i] = '\0'; - while(i > 0 && isspace(fname[i-1])) - i--; - fname[i] = '\0'; - - if(fname[0] == '\0') - continue; - - TRACE("Loading %s...\n", fname); - f = OpenDataFile(fname, "openal/hrtf"); + TRACE("Loading %s...\n", al_string_get_cstr(entry.filename)); + f = al_fopen(al_string_get_cstr(entry.filename), "rb"); if(f == NULL) { - ERR("Could not open %s\n", fname); - continue; + ERR("Could not open %s\n", al_string_get_cstr(entry.filename)); + goto error; } if(fread(magic, 1, sizeof(magic), f) != sizeof(magic)) - ERR("Failed to read header from %s\n", fname); + ERR("Failed to read header from %s\n", al_string_get_cstr(entry.filename)); else { if(memcmp(magic, magicMarker00, sizeof(magicMarker00)) == 0) { TRACE("Detected data set format v0\n"); - Hrtf = LoadHrtf00(f, deviceRate); + hrtf = LoadHrtf00(f); } else if(memcmp(magic, magicMarker01, sizeof(magicMarker01)) == 0) { TRACE("Detected data set format v1\n"); - Hrtf = LoadHrtf01(f, deviceRate); + hrtf = LoadHrtf01(f); } else - ERR("Invalid header in %s: \"%.8s\"\n", fname, magic); + ERR("Invalid header in %s: \"%.8s\"\n", al_string_get_cstr(entry.filename), magic); } - fclose(f); - f = NULL; - if(Hrtf) + if(!hrtf) { - Hrtf->next = LoadedHrtfs; - LoadedHrtfs = Hrtf; - TRACE("Loaded HRTF support for format: %s %uhz\n", - DevFmtChannelsString(DevFmtStereo), Hrtf->sampleRate); - return Hrtf; + ERR("Failed to load %s\n", al_string_get_cstr(entry.filename)); + goto error; } - ERR("Failed to load %s\n", fname); + al_string_copy(&hrtf->filename, entry.filename); + hrtf->next = LoadedHrtfs; + LoadedHrtfs = hrtf; + TRACE("Loaded HRTF support for format: %s %uhz\n", + DevFmtChannelsString(DevFmtStereo), hrtf->sampleRate); + entry.hrtf = hrtf; } - return NULL; -} + /* TODO: Get a human-readable name from the HRTF data (possibly coming in a + * format update). */ -const struct Hrtf *GetHrtf(enum DevFmtChannels chans, ALCuint srate) -{ - if(chans == DevFmtStereo) - { - struct Hrtf *Hrtf = LoadedHrtfs; - while(Hrtf != NULL) + i = 0; + do { + al_string_copy_cstr(&entry.name, name); + if(i != 0) { - if(srate == Hrtf->sampleRate) - return Hrtf; - Hrtf = Hrtf->next; + char str[64]; + snprintf(str, sizeof(str), " #%d", i+1); + al_string_append_cstr(&entry.name, str); } + ++i; - Hrtf = LoadHrtf(srate); - if(Hrtf != NULL) - return Hrtf; - } - ERR("Incompatible format: %s %uhz\n", DevFmtChannelsString(chans), srate); - return NULL; +#define MATCH_NAME(i) (al_string_cmp(entry.name, (i)->name) == 0) + VECTOR_FIND_IF(iter, HrtfEntry, *list, MATCH_NAME); +#undef MATCH_NAME + } while(iter != VECTOR_ITER_END(*list)); + + TRACE("Adding entry \"%s\" from file \"%s\"\n", al_string_get_cstr(entry.name), + al_string_get_cstr(entry.filename)); + VECTOR_PUSH_BACK(*list, entry); + return; + +error: + al_string_deinit(&entry.filename); } -ALCboolean FindHrtfFormat(enum DevFmtChannels *chans, ALCuint *srate) +vector_HrtfEntry EnumerateHrtf(const_al_string devname) { - const struct Hrtf *hrtf = LoadedHrtfs; - while(hrtf != NULL) + vector_HrtfEntry list = VECTOR_INIT_STATIC(); + const char *fnamelist = "default-%r.mhr"; + + ConfigValueStr(al_string_get_cstr(devname), NULL, "hrtf_tables", &fnamelist); + while(fnamelist && *fnamelist) { - if(*srate == hrtf->sampleRate) - break; - hrtf = hrtf->next; + while(isspace(*fnamelist) || *fnamelist == ',') + fnamelist++; + if(*fnamelist != '\0') + { + const char *next, *end; + + next = strchr(fnamelist, ','); + if(!next) + end = fnamelist + strlen(fnamelist); + else + end = next++; + + while(end != fnamelist && isspace(*(end-1))) + --end; + if(end != fnamelist) + { + al_string fname = AL_STRING_INIT_STATIC(); + vector_al_string flist; + + al_string_append_range(&fname, fnamelist, end); + + flist = SearchDataFiles(al_string_get_cstr(fname), "openal/hrtf"); + VECTOR_FOR_EACH_PARAMS(al_string, flist, AddFileEntry, &list); + VECTOR_DEINIT(flist); + + al_string_deinit(&fname); + } + + fnamelist = next; + } } - if(hrtf == NULL) - { - hrtf = LoadHrtf(*srate); - if(hrtf == NULL) return ALC_FALSE; - } - - *chans = DevFmtStereo; - *srate = hrtf->sampleRate; - return ALC_TRUE; + return list; } +void FreeHrtfList(vector_HrtfEntry *list) +{ +#define CLEAR_ENTRY(i) do { \ + al_string_deinit(&(i)->name); \ + al_string_deinit(&(i)->filename); \ +} while(0) + VECTOR_FOR_EACH(HrtfEntry, *list, CLEAR_ENTRY); + VECTOR_DEINIT(*list); +#undef CLEAR_ENTRY +} + + +ALuint GetHrtfSampleRate(const struct Hrtf *Hrtf) +{ + return Hrtf->sampleRate; +} + +ALuint GetHrtfIrSize(const struct Hrtf *Hrtf) +{ + return Hrtf->irSize; +} + + void FreeHrtfs(void) { struct Hrtf *Hrtf = NULL; @@ -810,11 +894,7 @@ void FreeHrtfs(void) free((void*)Hrtf->evOffset); free((void*)Hrtf->coeffs); free((void*)Hrtf->delays); + al_string_deinit(&Hrtf->filename); free(Hrtf); } } - -ALuint GetHrtfIrSize (const struct Hrtf *Hrtf) -{ - return Hrtf->irSize; -} diff --git a/libs/openal-soft/Alc/hrtf.h b/libs/openal-soft/Alc/hrtf.h index 938bf552..6dcd6948 100644 --- a/libs/openal-soft/Alc/hrtf.h +++ b/libs/openal-soft/Alc/hrtf.h @@ -4,10 +4,20 @@ #include "AL/al.h" #include "AL/alc.h" +#include "alstring.h" + enum DevFmtChannels; struct Hrtf; +typedef struct HrtfEntry { + al_string name; + al_string filename; + + const struct Hrtf *hrtf; +} HrtfEntry; +TYPEDEF_VECTOR(HrtfEntry, vector_HrtfEntry) + #define HRIR_BITS (7) #define HRIR_LENGTH (1<>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE, + "MAX_PITCH and/or BUFFERSIZE are too large for FRACTIONBITS!"); + extern inline void InitiatePositionArrays(ALuint frac, ALuint increment, ALuint *frac_arr, ALuint *pos_arr, ALuint size); +alignas(16) union ResamplerCoeffs ResampleCoeffs; + + +enum Resampler { + PointResampler, + LinearResampler, + FIR4Resampler, + FIR8Resampler, + BSincResampler, + + ResamplerDefault = LinearResampler +}; + +/* FIR8 requires 3 extra samples before the current position, and 4 after. */ +static_assert(MAX_PRE_SAMPLES >= 3, "MAX_PRE_SAMPLES must be at least 3!"); +static_assert(MAX_POST_SAMPLES >= 4, "MAX_POST_SAMPLES must be at least 4!"); + + +static HrtfMixerFunc MixHrtfSamples = MixHrtf_C; +static MixerFunc MixSamples = Mix_C; +static ResamplerFunc ResampleSamples = Resample_point32_C; static inline HrtfMixerFunc SelectHrtfMixer(void) { @@ -69,11 +93,9 @@ static inline MixerFunc SelectMixer(void) return Mix_C; } -static inline ResamplerFunc SelectResampler(enum Resampler Resampler, ALuint increment) +static inline ResamplerFunc SelectResampler(enum Resampler resampler) { - if(increment == FRACTIONONE) - return Resample_copy32_C; - switch(Resampler) + switch(resampler) { case PointResampler: return Resample_point32_C; @@ -87,17 +109,181 @@ static inline ResamplerFunc SelectResampler(enum Resampler Resampler, ALuint inc return Resample_lerp32_SSE2; #endif return Resample_lerp32_C; - case CubicResampler: - return Resample_cubic32_C; - case ResamplerMax: - /* Shouldn't happen */ - break; + case FIR4Resampler: +#ifdef HAVE_SSE4_1 + if((CPUCapFlags&CPU_CAP_SSE4_1)) + return Resample_fir4_32_SSE41; +#endif +#ifdef HAVE_SSE3 + if((CPUCapFlags&CPU_CAP_SSE3)) + return Resample_fir4_32_SSE3; +#endif + return Resample_fir4_32_C; + case FIR8Resampler: +#ifdef HAVE_SSE4_1 + if((CPUCapFlags&CPU_CAP_SSE4_1)) + return Resample_fir8_32_SSE41; +#endif +#ifdef HAVE_SSE3 + if((CPUCapFlags&CPU_CAP_SSE3)) + return Resample_fir8_32_SSE3; +#endif + return Resample_fir8_32_C; + case BSincResampler: +#ifdef HAVE_SSE + if((CPUCapFlags&CPU_CAP_SSE)) + return Resample_bsinc32_SSE; +#endif + return Resample_bsinc32_C; } return Resample_point32_C; } +/* The sinc resampler makes use of a Kaiser window to limit the needed sample + * points to 4 and 8, respectively. + */ + +#ifndef M_PI +#define M_PI (3.14159265358979323846) +#endif +static inline double Sinc(double x) +{ + if(x == 0.0) return 1.0; + return sin(x*M_PI) / (x*M_PI); +} + +/* The zero-order modified Bessel function of the first kind, used for the + * Kaiser window. + * + * I_0(x) = sum_{k=0}^inf (1 / k!)^2 (x / 2)^(2 k) + * = sum_{k=0}^inf ((x / 2)^k / k!)^2 + */ +static double BesselI_0(double x) +{ + double term, sum, x2, y, last_sum; + int k; + + /* Start at k=1 since k=0 is trivial. */ + term = 1.0; + sum = 1.0; + x2 = x / 2.0; + k = 1; + + /* Let the integration converge until the term of the sum is no longer + * significant. + */ + do { + y = x2 / k; + k ++; + last_sum = sum; + term *= y * y; + sum += term; + } while(sum != last_sum); + return sum; +} + +/* Calculate a Kaiser window from the given beta value and a normalized k + * [-1, 1]. + * + * w(k) = { I_0(B sqrt(1 - k^2)) / I_0(B), -1 <= k <= 1 + * { 0, elsewhere. + * + * Where k can be calculated as: + * + * k = i / l, where -l <= i <= l. + * + * or: + * + * k = 2 i / M - 1, where 0 <= i <= M. + */ +static inline double Kaiser(double b, double k) +{ + if(k <= -1.0 || k >= 1.0) return 0.0; + return BesselI_0(b * sqrt(1.0 - (k*k))) / BesselI_0(b); +} + +static inline double CalcKaiserBeta(double rejection) +{ + if(rejection > 50.0) + return 0.1102 * (rejection - 8.7); + if(rejection >= 21.0) + return (0.5842 * pow(rejection - 21.0, 0.4)) + + (0.07886 * (rejection - 21.0)); + return 0.0; +} + +static float SincKaiser(double r, double x) +{ + /* Limit rippling to -60dB. */ + return (float)(Kaiser(CalcKaiserBeta(60.0), x / r) * Sinc(x)); +} + + +void aluInitMixer(void) +{ + enum Resampler resampler = ResamplerDefault; + const char *str; + ALuint i; + + if(ConfigValueStr(NULL, NULL, "resampler", &str)) + { + if(strcasecmp(str, "point") == 0 || strcasecmp(str, "none") == 0) + resampler = PointResampler; + else if(strcasecmp(str, "linear") == 0) + resampler = LinearResampler; + else if(strcasecmp(str, "sinc4") == 0) + resampler = FIR4Resampler; + else if(strcasecmp(str, "sinc8") == 0) + resampler = FIR8Resampler; + else if(strcasecmp(str, "bsinc") == 0) + resampler = BSincResampler; + else if(strcasecmp(str, "cubic") == 0) + { + WARN("Resampler option \"cubic\" is deprecated, using sinc4\n"); + resampler = FIR4Resampler; + } + else + { + char *end; + long n = strtol(str, &end, 0); + if(*end == '\0' && (n == PointResampler || n == LinearResampler || n == FIR4Resampler)) + resampler = n; + else + WARN("Invalid resampler: %s\n", str); + } + } + + if(resampler == FIR8Resampler) + for(i = 0;i < FRACTIONONE;i++) + { + ALdouble mu = (ALdouble)i / FRACTIONONE; + ResampleCoeffs.FIR8[i][0] = SincKaiser(4.0, mu - -3.0); + ResampleCoeffs.FIR8[i][1] = SincKaiser(4.0, mu - -2.0); + ResampleCoeffs.FIR8[i][2] = SincKaiser(4.0, mu - -1.0); + ResampleCoeffs.FIR8[i][3] = SincKaiser(4.0, mu - 0.0); + ResampleCoeffs.FIR8[i][4] = SincKaiser(4.0, mu - 1.0); + ResampleCoeffs.FIR8[i][5] = SincKaiser(4.0, mu - 2.0); + ResampleCoeffs.FIR8[i][6] = SincKaiser(4.0, mu - 3.0); + ResampleCoeffs.FIR8[i][7] = SincKaiser(4.0, mu - 4.0); + } + else if(resampler == FIR4Resampler) + for(i = 0;i < FRACTIONONE;i++) + { + ALdouble mu = (ALdouble)i / FRACTIONONE; + ResampleCoeffs.FIR4[i][0] = SincKaiser(2.0, mu - -1.0); + ResampleCoeffs.FIR4[i][1] = SincKaiser(2.0, mu - 0.0); + ResampleCoeffs.FIR4[i][2] = SincKaiser(2.0, mu - 1.0); + ResampleCoeffs.FIR4[i][3] = SincKaiser(2.0, mu - 2.0); + } + + MixHrtfSamples = SelectHrtfMixer(); + MixSamples = SelectMixer(); + ResampleSamples = SelectResampler(resampler); +} + + static inline ALfloat Sample_ALbyte(ALbyte val) { return val * (1.0f/127.0f); } @@ -108,7 +294,7 @@ static inline ALfloat Sample_ALfloat(ALfloat val) { return val; } #define DECL_TEMPLATE(T) \ -static void Load_##T(ALfloat *dst, const T *src, ALuint srcstep, ALuint samples)\ +static inline void Load_##T(ALfloat *dst, const T *src, ALuint srcstep, ALuint samples)\ { \ ALuint i; \ for(i = 0;i < samples;i++) \ @@ -137,7 +323,7 @@ static void LoadSamples(ALfloat *dst, const ALvoid *src, ALuint srcstep, enum Fm } } -static void SilenceSamples(ALfloat *dst, ALuint samples) +static inline void SilenceSamples(ALfloat *dst, ALuint samples) { ALuint i; for(i = 0;i < samples;i++) @@ -153,20 +339,24 @@ static const ALfloat *DoFilters(ALfilterState *lpfilter, ALfilterState *hpfilter switch(type) { case AF_None: + ALfilterState_processPassthru(lpfilter, src, numsamples); + ALfilterState_processPassthru(hpfilter, src, numsamples); break; case AF_LowPass: ALfilterState_process(lpfilter, dst, src, numsamples); + ALfilterState_processPassthru(hpfilter, dst, numsamples); return dst; case AF_HighPass: + ALfilterState_processPassthru(lpfilter, src, numsamples); ALfilterState_process(hpfilter, dst, src, numsamples); return dst; case AF_BandPass: for(i = 0;i < numsamples;) { - ALfloat temp[64]; - ALuint todo = minu(64, numsamples-i); + ALfloat temp[256]; + ALuint todo = minu(256, numsamples-i); ALfilterState_process(lpfilter, temp, src+i, todo); ALfilterState_process(hpfilter, dst+i, temp, todo); @@ -178,22 +368,19 @@ static const ALfloat *DoFilters(ALfilterState *lpfilter, ALfilterState *hpfilter } -ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo) +ALvoid MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALuint SamplesToDo) { - MixerFunc Mix; - HrtfMixerFunc HrtfMix; ResamplerFunc Resample; - ALsource *Source = src->Source; ALbufferlistitem *BufferListItem; ALuint DataPosInt, DataPosFrac; ALboolean Looping; ALuint increment; - enum Resampler Resampler; ALenum State; ALuint OutPos; ALuint NumChannels; ALuint SampleSize; ALint64 DataSize64; + ALuint IrSize; ALuint chan, j; /* Get source info */ @@ -202,19 +389,17 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo) DataPosInt = Source->position; DataPosFrac = Source->position_fraction; Looping = Source->Looping; - increment = src->Step; - Resampler = (increment==FRACTIONONE) ? PointResampler : Source->Resampler; NumChannels = Source->NumChannels; SampleSize = Source->SampleSize; + increment = voice->Step; - Mix = SelectMixer(); - HrtfMix = SelectHrtfMixer(); - Resample = SelectResampler(Resampler, increment); + IrSize = (Device->Hrtf ? GetHrtfIrSize(Device->Hrtf) : 0); + + Resample = ((increment == FRACTIONONE && DataPosFrac == 0) ? + Resample_copy32_C : ResampleSamples); OutPos = 0; do { - const ALuint BufferPrePadding = ResamplerPrePadding[Resampler]; - const ALuint BufferPadding = ResamplerPadding[Resampler]; ALuint SrcBufferSize, DstBufferSize; /* Figure out how many buffer samples will be needed */ @@ -222,13 +407,13 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo) DataSize64 *= increment; DataSize64 += DataPosFrac+FRACTIONMASK; DataSize64 >>= FRACTIONBITS; - DataSize64 += BufferPadding+BufferPrePadding; + DataSize64 += MAX_POST_SAMPLES+MAX_PRE_SAMPLES; SrcBufferSize = (ALuint)mini64(DataSize64, BUFFERSIZE); /* Figure out how many samples we can actually mix from this. */ DataSize64 = SrcBufferSize; - DataSize64 -= BufferPadding+BufferPrePadding; + DataSize64 -= MAX_POST_SAMPLES+MAX_PRE_SAMPLES; DataSize64 <<= FRACTIONBITS; DataSize64 -= DataPosFrac; @@ -244,7 +429,11 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo) { const ALfloat *ResampledData; ALfloat *SrcData = Device->SourceData; - ALuint SrcDataSize = 0; + ALuint SrcDataSize; + + /* Load the previous samples into the source data first. */ + memcpy(SrcData, voice->PrevSamples[chan], MAX_PRE_SAMPLES*sizeof(ALfloat)); + SrcDataSize = MAX_PRE_SAMPLES; if(Source->SourceType == AL_STATIC) { @@ -253,29 +442,20 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo) ALuint DataSize; ALuint pos; + /* Offset buffer data to current channel */ + Data += chan*SampleSize; + /* If current pos is beyond the loop range, do not loop */ if(Looping == AL_FALSE || DataPosInt >= (ALuint)ALBuffer->LoopEnd) { Looping = AL_FALSE; - if(DataPosInt >= BufferPrePadding) - pos = DataPosInt - BufferPrePadding; - else - { - DataSize = BufferPrePadding - DataPosInt; - DataSize = minu(SrcBufferSize - SrcDataSize, DataSize); - - SilenceSamples(&SrcData[SrcDataSize], DataSize); - SrcDataSize += DataSize; - - pos = 0; - } - - /* Copy what's left to play in the source buffer, and clear the - * rest of the temp buffer */ + /* Load what's left to play from the source buffer, and + * clear the rest of the temp buffer */ + pos = DataPosInt; DataSize = minu(SrcBufferSize - SrcDataSize, ALBuffer->SampleLen - pos); - LoadSamples(&SrcData[SrcDataSize], &Data[(pos*NumChannels + chan)*SampleSize], + LoadSamples(&SrcData[SrcDataSize], &Data[pos * NumChannels*SampleSize], NumChannels, ALBuffer->FmtType, DataSize); SrcDataSize += DataSize; @@ -287,33 +467,13 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo) ALuint LoopStart = ALBuffer->LoopStart; ALuint LoopEnd = ALBuffer->LoopEnd; - if(DataPosInt >= LoopStart) - { - pos = DataPosInt-LoopStart; - while(pos < BufferPrePadding) - pos += LoopEnd-LoopStart; - pos -= BufferPrePadding; - pos += LoopStart; - } - else if(DataPosInt >= BufferPrePadding) - pos = DataPosInt - BufferPrePadding; - else - { - DataSize = BufferPrePadding - DataPosInt; - DataSize = minu(SrcBufferSize - SrcDataSize, DataSize); - - SilenceSamples(&SrcData[SrcDataSize], DataSize); - SrcDataSize += DataSize; - - pos = 0; - } - - /* Copy what's left of this loop iteration, then copy repeats - * of the loop section */ + /* Load what's left of this loop iteration, then load + * repeats of the loop section */ + pos = DataPosInt; DataSize = LoopEnd - pos; DataSize = minu(SrcBufferSize - SrcDataSize, DataSize); - LoadSamples(&SrcData[SrcDataSize], &Data[(pos*NumChannels + chan)*SampleSize], + LoadSamples(&SrcData[SrcDataSize], &Data[pos * NumChannels*SampleSize], NumChannels, ALBuffer->FmtType, DataSize); SrcDataSize += DataSize; @@ -322,7 +482,7 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo) { DataSize = minu(SrcBufferSize - SrcDataSize, DataSize); - LoadSamples(&SrcData[SrcDataSize], &Data[(LoopStart*NumChannels + chan)*SampleSize], + LoadSamples(&SrcData[SrcDataSize], &Data[LoopStart * NumChannels*SampleSize], NumChannels, ALBuffer->FmtType, DataSize); SrcDataSize += DataSize; } @@ -332,45 +492,7 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo) { /* Crawl the buffer queue to fill in the temp buffer */ ALbufferlistitem *tmpiter = BufferListItem; - ALuint pos; - - if(DataPosInt >= BufferPrePadding) - pos = DataPosInt - BufferPrePadding; - else - { - pos = BufferPrePadding - DataPosInt; - while(pos > 0) - { - ALbufferlistitem *prev; - if((prev=tmpiter->prev) != NULL) - tmpiter = prev; - else if(Looping) - { - while(tmpiter->next) - tmpiter = tmpiter->next; - } - else - { - ALuint DataSize = minu(SrcBufferSize - SrcDataSize, pos); - - SilenceSamples(&SrcData[SrcDataSize], DataSize); - SrcDataSize += DataSize; - - pos = 0; - break; - } - - if(tmpiter->buffer) - { - if((ALuint)tmpiter->buffer->SampleLen > pos) - { - pos = tmpiter->buffer->SampleLen - pos; - break; - } - pos -= tmpiter->buffer->SampleLen; - } - } - } + ALuint pos = DataPosInt; while(tmpiter && SrcBufferSize > SrcDataSize) { @@ -406,13 +528,19 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo) } } + /* Store the last source samples used for next time. */ + memcpy(voice->PrevSamples[chan], + &SrcData[(increment*DstBufferSize + DataPosFrac)>>FRACTIONBITS], + MAX_PRE_SAMPLES*sizeof(ALfloat) + ); + /* Now resample, then filter and mix to the appropriate outputs. */ - ResampledData = Resample( - &SrcData[BufferPrePadding], DataPosFrac, increment, + ResampledData = Resample(&voice->SincState, + &SrcData[MAX_PRE_SAMPLES], DataPosFrac, increment, Device->ResampledData, DstBufferSize ); { - DirectParams *parms = &src->Direct; + DirectParams *parms = &voice->Direct; const ALfloat *samples; samples = DoFilters( @@ -420,18 +548,18 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo) Device->FilteredData, ResampledData, DstBufferSize, parms->Filters[chan].ActiveType ); - if(!src->IsHrtf) - Mix(samples, MaxChannels, parms->OutBuffer, parms->Mix.Gains[chan], - parms->Counter, OutPos, DstBufferSize); + if(!voice->IsHrtf) + MixSamples(samples, parms->OutChannels, parms->OutBuffer, parms->Gains[chan], + parms->Counter, OutPos, DstBufferSize); else - HrtfMix(parms->OutBuffer, samples, parms->Counter, src->Offset, - OutPos, parms->Mix.Hrtf.IrSize, &parms->Mix.Hrtf.Params[chan], - &parms->Mix.Hrtf.State[chan], DstBufferSize); + MixHrtfSamples(parms->OutBuffer, samples, parms->Counter, voice->Offset, + OutPos, IrSize, &parms->Hrtf[chan].Params, + &parms->Hrtf[chan].State, DstBufferSize); } for(j = 0;j < Device->NumAuxSends;j++) { - SendParams *parms = &src->Send[j]; + SendParams *parms = &voice->Send[j]; const ALfloat *samples; if(!parms->OutBuffer) @@ -442,8 +570,8 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo) Device->FilteredData, ResampledData, DstBufferSize, parms->Filters[chan].ActiveType ); - Mix(samples, 1, parms->OutBuffer, &parms->Gain, - parms->Counter, OutPos, DstBufferSize); + MixSamples(samples, 1, parms->OutBuffer, &parms->Gains[chan], + parms->Counter, OutPos, DstBufferSize); } } /* Update positions */ @@ -452,10 +580,10 @@ ALvoid MixSource(ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo) DataPosFrac &= FRACTIONMASK; OutPos += DstBufferSize; - src->Offset += DstBufferSize; - src->Direct.Counter = maxu(src->Direct.Counter, DstBufferSize) - DstBufferSize; + voice->Offset += DstBufferSize; + voice->Direct.Counter = maxu(voice->Direct.Counter, DstBufferSize) - DstBufferSize; for(j = 0;j < Device->NumAuxSends;j++) - src->Send[j].Counter = maxu(src->Send[j].Counter, DstBufferSize) - DstBufferSize; + voice->Send[j].Counter = maxu(voice->Send[j].Counter, DstBufferSize) - DstBufferSize; /* Handle looping sources */ while(1) diff --git a/libs/openal-soft/Alc/mixer_c.c b/libs/openal-soft/Alc/mixer_c.c index f3a229e5..ef37b730 100644 --- a/libs/openal-soft/Alc/mixer_c.c +++ b/libs/openal-soft/Alc/mixer_c.c @@ -12,13 +12,15 @@ static inline ALfloat point32(const ALfloat *vals, ALuint UNUSED(frac)) { return vals[0]; } static inline ALfloat lerp32(const ALfloat *vals, ALuint frac) { return lerp(vals[0], vals[1], frac * (1.0f/FRACTIONONE)); } -static inline ALfloat cubic32(const ALfloat *vals, ALuint frac) -{ return cubic(vals[-1], vals[0], vals[1], vals[2], frac * (1.0f/FRACTIONONE)); } +static inline ALfloat fir4_32(const ALfloat *vals, ALuint frac) +{ return resample_fir4(vals[-1], vals[0], vals[1], vals[2], frac); } +static inline ALfloat fir8_32(const ALfloat *vals, ALuint frac) +{ return resample_fir8(vals[-3], vals[-2], vals[-1], vals[0], vals[1], vals[2], vals[3], vals[4], frac); } -const ALfloat *Resample_copy32_C(const ALfloat *src, ALuint UNUSED(frac), - ALuint increment, ALfloat *restrict dst, ALuint numsamples) + +const ALfloat *Resample_copy32_C(const BsincState* UNUSED(state), const ALfloat *src, ALuint UNUSED(frac), + ALuint UNUSED(increment), ALfloat *restrict dst, ALuint numsamples) { - assert(increment==FRACTIONONE); #if defined(HAVE_SSE) || defined(HAVE_NEON) /* Avoid copying the source data if it's aligned like the destination. */ if((((intptr_t)src)&15) == (((intptr_t)dst)&15)) @@ -29,8 +31,9 @@ const ALfloat *Resample_copy32_C(const ALfloat *src, ALuint UNUSED(frac), } #define DECL_TEMPLATE(Sampler) \ -const ALfloat *Resample_##Sampler##_C(const ALfloat *src, ALuint frac, \ - ALuint increment, ALfloat *restrict dst, ALuint numsamples) \ +const ALfloat *Resample_##Sampler##_C(const BsincState* UNUSED(state), \ + const ALfloat *src, ALuint frac, ALuint increment, \ + ALfloat *restrict dst, ALuint numsamples) \ { \ ALuint i; \ for(i = 0;i < numsamples;i++) \ @@ -46,10 +49,49 @@ const ALfloat *Resample_##Sampler##_C(const ALfloat *src, ALuint frac, \ DECL_TEMPLATE(point32) DECL_TEMPLATE(lerp32) -DECL_TEMPLATE(cubic32) +DECL_TEMPLATE(fir4_32) +DECL_TEMPLATE(fir8_32) #undef DECL_TEMPLATE +const ALfloat *Resample_bsinc32_C(const BsincState *state, const ALfloat *src, ALuint frac, + ALuint increment, ALfloat *restrict dst, ALuint dstlen) +{ + const ALfloat *fil, *scd, *phd, *spd; + const ALfloat sf = state->sf; + const ALuint m = state->m; + const ALint l = state->l; + ALuint j_f, pi, i; + ALfloat pf, r; + ALint j_s; + + for(i = 0;i < dstlen;i++) + { + // Calculate the phase index and factor. +#define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) + pi = frac >> FRAC_PHASE_BITDIFF; + pf = (frac & ((1<coeffs[pi].filter; + scd = state->coeffs[pi].scDelta; + phd = state->coeffs[pi].phDelta; + spd = state->coeffs[pi].spDelta; + + // Apply the scale and phase interpolated filter. + r = 0.0f; + for(j_f = 0,j_s = l;j_f < m;j_f++,j_s++) + r += (fil[j_f] + sf*scd[j_f] + pf*(phd[j_f] + sf*spd[j_f])) * + src[j_s]; + dst[i] = r; + + frac += increment; + src += frac>>FRACTIONBITS; + frac &= FRACTIONMASK; + } + return dst; +} + void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *src, ALuint numsamples) { @@ -59,6 +101,18 @@ void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const } +static inline void SetupCoeffs(ALfloat (*restrict OutCoeffs)[2], + const HrtfParams *hrtfparams, + ALuint IrSize, ALuint Counter) +{ + ALuint c; + for(c = 0;c < IrSize;c++) + { + OutCoeffs[c][0] = hrtfparams->Coeffs[c][0] - (hrtfparams->CoeffStep[c][0]*Counter); + OutCoeffs[c][1] = hrtfparams->Coeffs[c][1] - (hrtfparams->CoeffStep[c][1]*Counter); + } +} + static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2], const ALuint IrSize, ALfloat (*restrict Coeffs)[2], @@ -90,9 +144,9 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2], } } -#define SUFFIX C +#define MixHrtf MixHrtf_C #include "mixer_inc.c" -#undef SUFFIX +#undef MixHrtf void Mix_C(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], @@ -106,19 +160,20 @@ void Mix_C(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[B ALuint pos = 0; gain = Gains[c].Current; step = Gains[c].Step; - if(step != 1.0f && Counter > 0) + if(step != 0.0f && Counter > 0) { - for(;pos < BufferSize && pos < Counter;pos++) + ALuint minsize = minu(BufferSize, Counter); + for(;pos < minsize;pos++) { OutBuffer[c][OutPos+pos] += data[pos]*gain; - gain *= step; + gain += step; } if(pos == Counter) gain = Gains[c].Target; Gains[c].Current = gain; } - if(!(gain > GAIN_SILENCE_THRESHOLD)) + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) continue; for(;pos < BufferSize;pos++) OutBuffer[c][OutPos+pos] += data[pos]*gain; diff --git a/libs/openal-soft/Alc/mixer_defs.h b/libs/openal-soft/Alc/mixer_defs.h index c1500ed2..3c32278b 100644 --- a/libs/openal-soft/Alc/mixer_defs.h +++ b/libs/openal-soft/Alc/mixer_defs.h @@ -12,10 +12,12 @@ struct HrtfParams; struct HrtfState; /* C resamplers */ -const ALfloat *Resample_copy32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen); -const ALfloat *Resample_point32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen); -const ALfloat *Resample_lerp32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen); -const ALfloat *Resample_cubic32_C(const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen); +const ALfloat *Resample_copy32_C(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen); +const ALfloat *Resample_point32_C(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen); +const ALfloat *Resample_lerp32_C(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen); +const ALfloat *Resample_fir4_32_C(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen); +const ALfloat *Resample_fir8_32_C(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen); +const ALfloat *Resample_bsinc32_C(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen); /* C mixers */ @@ -24,7 +26,7 @@ void MixHrtf_C(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data, const struct HrtfParams *hrtfparams, struct HrtfState *hrtfstate, ALuint BufferSize); void Mix_C(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], - struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize); + struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize); /* SSE mixers */ void MixHrtf_SSE(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data, @@ -49,11 +51,24 @@ inline void InitiatePositionArrays(ALuint frac, ALuint increment, ALuint *frac_a } } -const ALfloat *Resample_lerp32_SSE2(const ALfloat *src, ALuint frac, ALuint increment, +const ALfloat *Resample_bsinc32_SSE(const BsincState *state, const ALfloat *src, ALuint frac, + ALuint increment, ALfloat *restrict dst, ALuint dstlen); + +const ALfloat *Resample_lerp32_SSE2(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint numsamples); -const ALfloat *Resample_lerp32_SSE41(const ALfloat *src, ALuint frac, ALuint increment, +const ALfloat *Resample_lerp32_SSE41(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint numsamples); +const ALfloat *Resample_fir4_32_SSE3(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, + ALfloat *restrict dst, ALuint numsamples); +const ALfloat *Resample_fir4_32_SSE41(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, + ALfloat *restrict dst, ALuint numsamples); + +const ALfloat *Resample_fir8_32_SSE3(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, + ALfloat *restrict dst, ALuint numsamples); +const ALfloat *Resample_fir8_32_SSE41(const BsincState *state, const ALfloat *src, ALuint frac, ALuint increment, + ALfloat *restrict dst, ALuint numsamples); + /* Neon mixers */ void MixHrtf_Neon(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data, ALuint Counter, ALuint Offset, ALuint OutPos, const ALuint IrSize, diff --git a/libs/openal-soft/Alc/mixer_inc.c b/libs/openal-soft/Alc/mixer_inc.c index ab6f32c5..a82930cc 100644 --- a/libs/openal-soft/Alc/mixer_inc.c +++ b/libs/openal-soft/Alc/mixer_inc.c @@ -8,12 +8,9 @@ #include "align.h" -#define REAL_MERGE(a,b) a##b -#define MERGE(a,b) REAL_MERGE(a,b) - -#define MixHrtf MERGE(MixHrtf_,SUFFIX) - - +static inline void SetupCoeffs(ALfloat (*restrict OutCoeffs)[2], + const HrtfParams *hrtfparams, + ALuint IrSize, ALuint Counter); static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2], const ALuint irSize, ALfloat (*restrict Coeffs)[2], @@ -33,24 +30,20 @@ void MixHrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data, ALuint Delay[2]; ALfloat left, right; ALuint pos; - ALuint c; - for(c = 0;c < IrSize;c++) - { - Coeffs[c][0] = hrtfparams->Coeffs[c][0] - (hrtfparams->CoeffStep[c][0]*Counter); - Coeffs[c][1] = hrtfparams->Coeffs[c][1] - (hrtfparams->CoeffStep[c][1]*Counter); - } + SetupCoeffs(Coeffs, hrtfparams, IrSize, Counter); Delay[0] = hrtfparams->Delay[0] - (hrtfparams->DelayStep[0]*Counter); Delay[1] = hrtfparams->Delay[1] - (hrtfparams->DelayStep[1]*Counter); - for(pos = 0;pos < BufferSize && pos < Counter;pos++) + pos = 0; + for(;pos < BufferSize && pos < Counter;pos++) { - hrtfstate->History[Offset&SRC_HISTORY_MASK] = data[pos]; - left = lerp(hrtfstate->History[(Offset-(Delay[0]>>HRTFDELAY_BITS))&SRC_HISTORY_MASK], - hrtfstate->History[(Offset-(Delay[0]>>HRTFDELAY_BITS)-1)&SRC_HISTORY_MASK], + hrtfstate->History[Offset&HRTF_HISTORY_MASK] = data[pos]; + left = lerp(hrtfstate->History[(Offset-(Delay[0]>>HRTFDELAY_BITS))&HRTF_HISTORY_MASK], + hrtfstate->History[(Offset-(Delay[0]>>HRTFDELAY_BITS)-1)&HRTF_HISTORY_MASK], (Delay[0]&HRTFDELAY_MASK)*(1.0f/HRTFDELAY_FRACONE)); - right = lerp(hrtfstate->History[(Offset-(Delay[1]>>HRTFDELAY_BITS))&SRC_HISTORY_MASK], - hrtfstate->History[(Offset-(Delay[1]>>HRTFDELAY_BITS)-1)&SRC_HISTORY_MASK], + right = lerp(hrtfstate->History[(Offset-(Delay[1]>>HRTFDELAY_BITS))&HRTF_HISTORY_MASK], + hrtfstate->History[(Offset-(Delay[1]>>HRTFDELAY_BITS)-1)&HRTF_HISTORY_MASK], (Delay[1]&HRTFDELAY_MASK)*(1.0f/HRTFDELAY_FRACONE)); Delay[0] += hrtfparams->DelayStep[0]; @@ -61,8 +54,8 @@ void MixHrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data, Offset++; ApplyCoeffsStep(Offset, hrtfstate->Values, IrSize, Coeffs, hrtfparams->CoeffStep, left, right); - OutBuffer[FrontLeft][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][0]; - OutBuffer[FrontRight][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][1]; + OutBuffer[0][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][0]; + OutBuffer[1][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][1]; OutPos++; } @@ -70,24 +63,17 @@ void MixHrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data, Delay[1] >>= HRTFDELAY_BITS; for(;pos < BufferSize;pos++) { - hrtfstate->History[Offset&SRC_HISTORY_MASK] = data[pos]; - left = hrtfstate->History[(Offset-Delay[0])&SRC_HISTORY_MASK]; - right = hrtfstate->History[(Offset-Delay[1])&SRC_HISTORY_MASK]; + hrtfstate->History[Offset&HRTF_HISTORY_MASK] = data[pos]; + left = hrtfstate->History[(Offset-Delay[0])&HRTF_HISTORY_MASK]; + right = hrtfstate->History[(Offset-Delay[1])&HRTF_HISTORY_MASK]; hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f; hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f; Offset++; ApplyCoeffs(Offset, hrtfstate->Values, IrSize, Coeffs, left, right); - OutBuffer[FrontLeft][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][0]; - OutBuffer[FrontRight][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][1]; - + OutBuffer[0][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][0]; + OutBuffer[1][OutPos] += hrtfstate->Values[Offset&HRIR_MASK][1]; OutPos++; } } - - -#undef MixHrtf - -#undef MERGE -#undef REAL_MERGE diff --git a/libs/openal-soft/Alc/mixer_neon.c b/libs/openal-soft/Alc/mixer_neon.c index 7b6da2b9..a89caeae 100644 --- a/libs/openal-soft/Alc/mixer_neon.c +++ b/libs/openal-soft/Alc/mixer_neon.c @@ -9,6 +9,25 @@ #include "hrtf.h" +static inline void SetupCoeffs(ALfloat (*restrict OutCoeffs)[2], + const HrtfParams *hrtfparams, + ALuint IrSize, ALuint Counter) +{ + ALuint c; + float32x4_t counter4; + { + float32x2_t counter2 = vdup_n_f32(-(float)Counter); + counter4 = vcombine_f32(counter2, counter2); + } + for(c = 0;c < IrSize;c += 2) + { + float32x4_t step4 = vld1q_f32((float32_t*)hrtfparams->CoeffStep[c]); + float32x4_t coeffs = vld1q_f32((float32_t*)hrtfparams->Coeffs[c]); + coeffs = vmlaq_f32(coeffs, step4, counter4); + vst1q_f32((float32_t*)OutCoeffs[c], coeffs); + } +} + static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2], const ALuint IrSize, ALfloat (*restrict Coeffs)[2], @@ -69,14 +88,13 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2], } } - -#define SUFFIX Neon +#define MixHrtf MixHrtf_Neon #include "mixer_inc.c" -#undef SUFFIX +#undef MixHrtf -void MixDirect_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], - MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize) +void Mix_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], + MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize) { ALfloat gain, step; float32x4_t gain4; @@ -87,29 +105,32 @@ void MixDirect_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict Out ALuint pos = 0; gain = Gains[c].Current; step = Gains[c].Step; - if(step != 1.0f && Counter > 0) + if(step != 0.0f && Counter > 0) { - for(;pos < BufferSize && pos < Counter;pos++) + ALuint minsize = minu(BufferSize, Counter); + for(;pos < minsize;pos++) { OutBuffer[c][OutPos+pos] += data[pos]*gain; - gain *= step; + gain += step; } if(pos == Counter) gain = Gains[c].Target; Gains[c].Current = gain; + /* Mix until pos is aligned with 4 or the mix is done. */ - for(;pos < BufferSize && (pos&3) != 0;pos++) + minsize = minu(BufferSize, (pos+3)&~3); + for(;pos < minsize;pos++) OutBuffer[c][OutPos+pos] += data[pos]*gain; } - if(!(gain > GAIN_SILENCE_THRESHOLD)) + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) continue; gain4 = vdupq_n_f32(gain); for(;BufferSize-pos > 3;pos += 4) { const float32x4_t val4 = vld1q_f32(&data[pos]); float32x4_t dry4 = vld1q_f32(&OutBuffer[c][OutPos+pos]); - dry4 = vaddq_f32(dry4, vmulq_f32(val4, gain4)); + dry4 = vmlaq_f32(dry4, val4, gain4); vst1q_f32(&OutBuffer[c][OutPos+pos], dry4); } for(;pos < BufferSize;pos++) diff --git a/libs/openal-soft/Alc/mixer_sse.c b/libs/openal-soft/Alc/mixer_sse.c index 970619ec..090b7a5a 100644 --- a/libs/openal-soft/Alc/mixer_sse.c +++ b/libs/openal-soft/Alc/mixer_sse.c @@ -1,12 +1,5 @@ #include "config.h" -#ifdef IN_IDE_PARSER -/* KDevelop's parser won't recognize these defines that get added by the -msse - * switch used to compile this source. Without them, xmmintrin.h fails to - * declare anything. */ -#define __MMX__ -#define __SSE__ -#endif #include #include "AL/al.h" @@ -19,6 +12,82 @@ #include "mixer_defs.h" +const ALfloat *Resample_bsinc32_SSE(const BsincState *state, const ALfloat *src, ALuint frac, + ALuint increment, ALfloat *restrict dst, ALuint dstlen) +{ + const __m128 sf4 = _mm_set1_ps(state->sf); + const ALuint m = state->m; + const ALint l = state->l; + const ALfloat *fil, *scd, *phd, *spd; + ALuint pi, j_f, i; + ALfloat pf; + ALint j_s; + __m128 r4; + + for(i = 0;i < dstlen;i++) + { + // Calculate the phase index and factor. +#define FRAC_PHASE_BITDIFF (FRACTIONBITS-BSINC_PHASE_BITS) + pi = frac >> FRAC_PHASE_BITDIFF; + pf = (frac & ((1<coeffs[pi].filter; + scd = state->coeffs[pi].scDelta; + phd = state->coeffs[pi].phDelta; + spd = state->coeffs[pi].spDelta; + + // Apply the scale and phase interpolated filter. + r4 = _mm_setzero_ps(); + { + const __m128 pf4 = _mm_set1_ps(pf); + for(j_f = 0,j_s = l;j_f < m;j_f+=4,j_s+=4) + { + const __m128 f4 = _mm_add_ps( + _mm_add_ps( + _mm_load_ps(&fil[j_f]), + _mm_mul_ps(sf4, _mm_load_ps(&scd[j_f])) + ), + _mm_mul_ps( + pf4, + _mm_add_ps( + _mm_load_ps(&phd[j_f]), + _mm_mul_ps(sf4, _mm_load_ps(&spd[j_f])) + ) + ) + ); + r4 = _mm_add_ps(r4, _mm_mul_ps(f4, _mm_loadu_ps(&src[j_s]))); + } + } + r4 = _mm_add_ps(r4, _mm_shuffle_ps(r4, r4, _MM_SHUFFLE(0, 1, 2, 3))); + r4 = _mm_add_ps(r4, _mm_movehl_ps(r4, r4)); + dst[i] = _mm_cvtss_f32(r4); + + frac += increment; + src += frac>>FRACTIONBITS; + frac &= FRACTIONMASK; + } + return dst; +} + + +static inline void SetupCoeffs(ALfloat (*restrict OutCoeffs)[2], + const HrtfParams *hrtfparams, + ALuint IrSize, ALuint Counter) +{ + const __m128 counter4 = _mm_set1_ps((float)Counter); + __m128 coeffs, step4; + ALuint i; + + for(i = 0;i < IrSize;i += 2) + { + step4 = _mm_load_ps(&hrtfparams->CoeffStep[i][0]); + coeffs = _mm_load_ps(&hrtfparams->Coeffs[i][0]); + coeffs = _mm_sub_ps(coeffs, _mm_mul_ps(step4, counter4)); + _mm_store_ps(&OutCoeffs[i][0], coeffs); + } +} + static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2], const ALuint IrSize, ALfloat (*restrict Coeffs)[2], @@ -133,16 +202,16 @@ static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2], } } -#define SUFFIX SSE +#define MixHrtf MixHrtf_SSE #include "mixer_inc.c" -#undef SUFFIX +#undef MixHrtf void Mix_SSE(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize) { ALfloat gain, step; - __m128 gain4, step4; + __m128 gain4; ALuint c; for(c = 0;c < OutChans;c++) @@ -150,43 +219,51 @@ void Mix_SSE(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer) ALuint pos = 0; gain = Gains[c].Current; step = Gains[c].Step; - if(step != 1.0f && Counter > 0) + if(step != 0.0f && Counter > 0) { + ALuint minsize = minu(BufferSize, Counter); /* Mix with applying gain steps in aligned multiples of 4. */ - if(BufferSize-pos > 3 && Counter-pos > 3) + if(minsize-pos > 3) { + __m128 step4; gain4 = _mm_setr_ps( gain, - gain * step, - gain * step * step, - gain * step * step * step + gain + step, + gain + step + step, + gain + step + step + step ); - step4 = _mm_set1_ps(step * step * step * step); + step4 = _mm_set1_ps(step + step + step + step); do { const __m128 val4 = _mm_load_ps(&data[pos]); __m128 dry4 = _mm_load_ps(&OutBuffer[c][OutPos+pos]); dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain4)); - gain4 = _mm_mul_ps(gain4, step4); + gain4 = _mm_add_ps(gain4, step4); _mm_store_ps(&OutBuffer[c][OutPos+pos], dry4); pos += 4; - } while(BufferSize-pos > 3 && Counter-pos > 3); + } while(minsize-pos > 3); + /* NOTE: gain4 now represents the next four gains after the + * last four mixed samples, so the lowest element represents + * the next gain to apply. + */ gain = _mm_cvtss_f32(gain4); } /* Mix with applying left over gain steps that aren't aligned multiples of 4. */ - for(;pos < BufferSize && pos < Counter;pos++) + for(;pos < minsize;pos++) { OutBuffer[c][OutPos+pos] += data[pos]*gain; - gain *= step; + gain += step; } if(pos == Counter) gain = Gains[c].Target; Gains[c].Current = gain; + /* Mix until pos is aligned with 4 or the mix is done. */ - for(;pos < BufferSize && (pos&3) != 0;pos++) + minsize = minu(BufferSize, (pos+3)&~3); + for(;pos < minsize;pos++) OutBuffer[c][OutPos+pos] += data[pos]*gain; } - if(!(gain > GAIN_SILENCE_THRESHOLD)) + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) continue; gain4 = _mm_set1_ps(gain); for(;BufferSize-pos > 3;pos += 4) diff --git a/libs/openal-soft/Alc/mixer_sse2.c b/libs/openal-soft/Alc/mixer_sse2.c index 7670add3..32f29227 100644 --- a/libs/openal-soft/Alc/mixer_sse2.c +++ b/libs/openal-soft/Alc/mixer_sse2.c @@ -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 */ @@ -27,7 +27,7 @@ #include "mixer_defs.h" -const ALfloat *Resample_lerp32_SSE2(const ALfloat *src, ALuint frac, ALuint increment, +const ALfloat *Resample_lerp32_SSE2(const BsincState* UNUSED(state), const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint numsamples) { const __m128i increment4 = _mm_set1_epi32(increment*4); @@ -63,6 +63,9 @@ const ALfloat *Resample_lerp32_SSE2(const ALfloat *src, ALuint frac, ALuint incr _mm_store_ps(pos_.f, _mm_castsi128_ps(pos4)); } + /* NOTE: These four elements represent the position *after* the last four + * samples, so the lowest element is the next position to resample. + */ pos = pos_.i[0]; frac = _mm_cvtsi128_si32(frac4); diff --git a/libs/openal-soft/Alc/mixer_sse41.c b/libs/openal-soft/Alc/mixer_sse41.c index 8ce8cd90..e832e5df 100644 --- a/libs/openal-soft/Alc/mixer_sse41.c +++ b/libs/openal-soft/Alc/mixer_sse41.c @@ -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 */ @@ -28,7 +28,7 @@ #include "mixer_defs.h" -const ALfloat *Resample_lerp32_SSE41(const ALfloat *src, ALuint frac, ALuint increment, +const ALfloat *Resample_lerp32_SSE41(const BsincState* UNUSED(state), const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint numsamples) { const __m128i increment4 = _mm_set1_epi32(increment*4); @@ -67,6 +67,9 @@ const ALfloat *Resample_lerp32_SSE41(const ALfloat *src, ALuint frac, ALuint inc pos_.i[3] = _mm_extract_epi32(pos4, 3); } + /* NOTE: These four elements represent the position *after* the last four + * samples, so the lowest element is the next position to resample. + */ pos = pos_.i[0]; frac = _mm_cvtsi128_si32(frac4); @@ -80,3 +83,142 @@ const ALfloat *Resample_lerp32_SSE41(const ALfloat *src, ALuint frac, ALuint inc } return dst; } + +const ALfloat *Resample_fir4_32_SSE41(const BsincState* UNUSED(state), const ALfloat *src, ALuint frac, ALuint increment, + ALfloat *restrict dst, ALuint numsamples) +{ + const __m128i increment4 = _mm_set1_epi32(increment*4); + const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); + alignas(16) union { ALuint i[4]; float f[4]; } pos_; + alignas(16) union { ALuint i[4]; float f[4]; } frac_; + __m128i frac4, pos4; + ALuint pos; + ALuint i; + + InitiatePositionArrays(frac, increment, frac_.i, pos_.i, 4); + + frac4 = _mm_castps_si128(_mm_load_ps(frac_.f)); + pos4 = _mm_castps_si128(_mm_load_ps(pos_.f)); + + --src; + for(i = 0;numsamples-i > 3;i += 4) + { + const __m128 val0 = _mm_loadu_ps(&src[pos_.i[0]]); + const __m128 val1 = _mm_loadu_ps(&src[pos_.i[1]]); + const __m128 val2 = _mm_loadu_ps(&src[pos_.i[2]]); + const __m128 val3 = _mm_loadu_ps(&src[pos_.i[3]]); + __m128 k0 = _mm_load_ps(ResampleCoeffs.FIR4[frac_.i[0]]); + __m128 k1 = _mm_load_ps(ResampleCoeffs.FIR4[frac_.i[1]]); + __m128 k2 = _mm_load_ps(ResampleCoeffs.FIR4[frac_.i[2]]); + __m128 k3 = _mm_load_ps(ResampleCoeffs.FIR4[frac_.i[3]]); + __m128 out; + + k0 = _mm_mul_ps(k0, val0); + k1 = _mm_mul_ps(k1, val1); + k2 = _mm_mul_ps(k2, val2); + k3 = _mm_mul_ps(k3, val3); + k0 = _mm_hadd_ps(k0, k1); + k2 = _mm_hadd_ps(k2, k3); + out = _mm_hadd_ps(k0, k2); + + _mm_store_ps(&dst[i], out); + + frac4 = _mm_add_epi32(frac4, increment4); + pos4 = _mm_add_epi32(pos4, _mm_srli_epi32(frac4, FRACTIONBITS)); + frac4 = _mm_and_si128(frac4, fracMask4); + + pos_.i[0] = _mm_extract_epi32(pos4, 0); + pos_.i[1] = _mm_extract_epi32(pos4, 1); + pos_.i[2] = _mm_extract_epi32(pos4, 2); + pos_.i[3] = _mm_extract_epi32(pos4, 3); + frac_.i[0] = _mm_extract_epi32(frac4, 0); + frac_.i[1] = _mm_extract_epi32(frac4, 1); + frac_.i[2] = _mm_extract_epi32(frac4, 2); + frac_.i[3] = _mm_extract_epi32(frac4, 3); + } + + pos = pos_.i[0]; + frac = frac_.i[0]; + + for(;i < numsamples;i++) + { + dst[i] = resample_fir4(src[pos], src[pos+1], src[pos+2], src[pos+3], frac); + + frac += increment; + pos += frac>>FRACTIONBITS; + frac &= FRACTIONMASK; + } + return dst; +} + +const ALfloat *Resample_fir8_32_SSE41(const BsincState* UNUSED(state), const ALfloat *src, ALuint frac, ALuint increment, + ALfloat *restrict dst, ALuint numsamples) +{ + const __m128i increment4 = _mm_set1_epi32(increment*4); + const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); + alignas(16) union { ALuint i[4]; float f[4]; } pos_; + alignas(16) union { ALuint i[4]; float f[4]; } frac_; + __m128i frac4, pos4; + ALuint pos; + ALuint i, j; + + InitiatePositionArrays(frac, increment, frac_.i, pos_.i, 4); + + frac4 = _mm_castps_si128(_mm_load_ps(frac_.f)); + pos4 = _mm_castps_si128(_mm_load_ps(pos_.f)); + + src -= 3; + for(i = 0;numsamples-i > 3;i += 4) + { + __m128 out[2]; + for(j = 0;j < 8;j+=4) + { + const __m128 val0 = _mm_loadu_ps(&src[pos_.i[0]+j]); + const __m128 val1 = _mm_loadu_ps(&src[pos_.i[1]+j]); + const __m128 val2 = _mm_loadu_ps(&src[pos_.i[2]+j]); + const __m128 val3 = _mm_loadu_ps(&src[pos_.i[3]+j]); + __m128 k0 = _mm_load_ps(&ResampleCoeffs.FIR8[frac_.i[0]][j]); + __m128 k1 = _mm_load_ps(&ResampleCoeffs.FIR8[frac_.i[1]][j]); + __m128 k2 = _mm_load_ps(&ResampleCoeffs.FIR8[frac_.i[2]][j]); + __m128 k3 = _mm_load_ps(&ResampleCoeffs.FIR8[frac_.i[3]][j]); + + k0 = _mm_mul_ps(k0, val0); + k1 = _mm_mul_ps(k1, val1); + k2 = _mm_mul_ps(k2, val2); + k3 = _mm_mul_ps(k3, val3); + k0 = _mm_hadd_ps(k0, k1); + k2 = _mm_hadd_ps(k2, k3); + out[j>>2] = _mm_hadd_ps(k0, k2); + } + + out[0] = _mm_add_ps(out[0], out[1]); + _mm_store_ps(&dst[i], out[0]); + + frac4 = _mm_add_epi32(frac4, increment4); + pos4 = _mm_add_epi32(pos4, _mm_srli_epi32(frac4, FRACTIONBITS)); + frac4 = _mm_and_si128(frac4, fracMask4); + + pos_.i[0] = _mm_extract_epi32(pos4, 0); + pos_.i[1] = _mm_extract_epi32(pos4, 1); + pos_.i[2] = _mm_extract_epi32(pos4, 2); + pos_.i[3] = _mm_extract_epi32(pos4, 3); + frac_.i[0] = _mm_extract_epi32(frac4, 0); + frac_.i[1] = _mm_extract_epi32(frac4, 1); + frac_.i[2] = _mm_extract_epi32(frac4, 2); + frac_.i[3] = _mm_extract_epi32(frac4, 3); + } + + pos = pos_.i[0]; + frac = frac_.i[0]; + + for(;i < numsamples;i++) + { + dst[i] = resample_fir8(src[pos ], src[pos+1], src[pos+2], src[pos+3], + src[pos+4], src[pos+5], src[pos+6], src[pos+7], frac); + + frac += increment; + pos += frac>>FRACTIONBITS; + frac &= FRACTIONMASK; + } + return dst; +} diff --git a/libs/openal-soft/Alc/panning.c b/libs/openal-soft/Alc/panning.c index 30a1e571..6305bff7 100644 --- a/libs/openal-soft/Alc/panning.c +++ b/libs/openal-soft/Alc/panning.c @@ -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 */ @@ -30,421 +30,528 @@ #include "AL/al.h" #include "AL/alc.h" #include "alu.h" +#include "bool.h" -extern inline void SetGains(const ALCdevice *device, ALfloat ingain, ALfloat gains[MaxChannels]); -static void SetSpeakerArrangement(const char *name, ALfloat SpeakerAngle[MaxChannels], - enum Channel Speaker2Chan[MaxChannels], ALint chans) +#define ZERO_ORDER_SCALE 0.0f +#define FIRST_ORDER_SCALE 1.0f +#define SECOND_ORDER_SCALE (1.0f / 1.22474f) +#define THIRD_ORDER_SCALE (1.0f / 1.30657f) + + +static const ALuint FuMa2ACN[MAX_AMBI_COEFFS] = { + 0, /* W */ + 3, /* X */ + 1, /* Y */ + 2, /* Z */ + 6, /* R */ + 7, /* S */ + 5, /* T */ + 8, /* U */ + 4, /* V */ + 12, /* K */ + 13, /* L */ + 11, /* M */ + 14, /* N */ + 10, /* O */ + 15, /* P */ + 9, /* Q */ +}; + +/* NOTE: These are scale factors as applied to Ambisonics content. FuMa + * decoder coefficients should be divided by these values to get N3D decoder + * coefficients. + */ +static const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS] = { + 1.414213562f, /* ACN 0 (W), sqrt(2) */ + 1.732050808f, /* ACN 1 (Y), sqrt(3) */ + 1.732050808f, /* ACN 2 (Z), sqrt(3) */ + 1.732050808f, /* ACN 3 (X), sqrt(3) */ + 1.936491673f, /* ACN 4 (V), sqrt(15)/2 */ + 1.936491673f, /* ACN 5 (T), sqrt(15)/2 */ + 2.236067978f, /* ACN 6 (R), sqrt(5) */ + 1.936491673f, /* ACN 7 (S), sqrt(15)/2 */ + 1.936491673f, /* ACN 8 (U), sqrt(15)/2 */ + 2.091650066f, /* ACN 9 (Q), sqrt(35/8) */ + 1.972026594f, /* ACN 10 (O), sqrt(35)/3 */ + 2.231093404f, /* ACN 11 (M), sqrt(224/45) */ + 2.645751311f, /* ACN 12 (K), sqrt(7) */ + 2.231093404f, /* ACN 13 (L), sqrt(224/45) */ + 1.972026594f, /* ACN 14 (N), sqrt(35)/3 */ + 2.091650066f, /* ACN 15 (P), sqrt(35/8) */ +}; + + +void ComputeAmbientGains(const ALCdevice *device, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) { - char *confkey, *next; - char *layout_str; - char *sep, *end; - enum Channel val; - const char *str; - int i; + ALuint i; - if(!ConfigValueStr(NULL, name, &str) && !ConfigValueStr(NULL, "layout", &str)) - return; - - layout_str = strdup(str); - next = confkey = layout_str; - while(next && *next) + for(i = 0;i < device->NumChannels;i++) { - confkey = next; - next = strchr(confkey, ','); - if(next) - { - *next = 0; - do { - next++; - } while(isspace(*next) || *next == ','); - } + // The W coefficients are based on a mathematical average of the + // output. The square root of the base average provides for a more + // perceptual average volume, better suited to non-directional gains. + gains[i] = sqrtf(device->AmbiCoeffs[i][0]) * ingain; + } + for(;i < MAX_OUTPUT_CHANNELS;i++) + gains[i] = 0.0f; +} - sep = strchr(confkey, '='); - if(!sep || confkey == sep) +void ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat elevation, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +{ + ALfloat dir[3] = { + sinf(angle) * cosf(elevation), + sinf(elevation), + -cosf(angle) * cosf(elevation) + }; + ComputeDirectionalGains(device, dir, ingain, gains); +} + +void ComputeDirectionalGains(const ALCdevice *device, const ALfloat dir[3], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +{ + ALfloat coeffs[MAX_AMBI_COEFFS]; + ALuint i, j; + /* Convert from OpenAL coords to Ambisonics. */ + ALfloat x = -dir[2]; + ALfloat y = -dir[0]; + ALfloat z = dir[1]; + + /* Zeroth-order */ + coeffs[0] = 1.0f; /* ACN 0 = 1 */ + /* First-order */ + coeffs[1] = 1.732050808f * y; /* ACN 1 = sqrt(3) * Y */ + coeffs[2] = 1.732050808f * z; /* ACN 2 = sqrt(3) * Z */ + coeffs[3] = 1.732050808f * x; /* ACN 3 = sqrt(3) * X */ + /* Second-order */ + coeffs[4] = 3.872983346f * x * y; /* ACN 4 = sqrt(15) * X * Y */ + coeffs[5] = 3.872983346f * y * z; /* ACN 5 = sqrt(15) * Y * Z */ + coeffs[6] = 1.118033989f * (3.0f*z*z - 1.0f); /* ACN 6 = sqrt(5)/2 * (3*Z*Z - 1) */ + coeffs[7] = 3.872983346f * x * z; /* ACN 7 = sqrt(15) * X * Z */ + coeffs[8] = 1.936491673f * (x*x - y*y); /* ACN 8 = sqrt(15)/2 * (X*X - Y*Y) */ + /* Third-order */ + coeffs[9] = 2.091650066f * y * (3.0f*x*x - y*y); /* ACN 9 = sqrt(35/8) * Y * (3*X*X - Y*Y) */ + coeffs[10] = 10.246950766f * z * x * y; /* ACN 10 = sqrt(105) * Z * X * Y */ + coeffs[11] = 1.620185175f * y * (5.0f*z*z - 1.0f); /* ACN 11 = sqrt(21/8) * Y * (5*Z*Z - 1) */ + coeffs[12] = 1.322875656f * z * (5.0f*z*z - 3.0f); /* ACN 12 = sqrt(7)/2 * Z * (5*Z*Z - 3) */ + coeffs[13] = 1.620185175f * x * (5.0f*z*z - 1.0f); /* ACN 13 = sqrt(21/8) * X * (5*Z*Z - 1) */ + coeffs[14] = 5.123475383f * z * (x*x - y*y); /* ACN 14 = sqrt(105)/2 * Z * (X*X - Y*Y) */ + coeffs[15] = 2.091650066f * x * (x*x - 3.0f*y*y); /* ACN 15 = sqrt(35/8) * X * (X*X - 3*Y*Y) */ + + for(i = 0;i < device->NumChannels;i++) + { + float gain = 0.0f; + for(j = 0;j < MAX_AMBI_COEFFS;j++) + gain += device->AmbiCoeffs[i][j]*coeffs[j]; + gains[i] = gain * ingain; + } + for(;i < MAX_OUTPUT_CHANNELS;i++) + gains[i] = 0.0f; +} + +void ComputeBFormatGains(const ALCdevice *device, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS]) +{ + ALuint i, j; + + for(i = 0;i < device->NumChannels;i++) + { + float gain = 0.0f; + for(j = 0;j < 4;j++) + gain += device->AmbiCoeffs[i][j] * mtx[j]; + gains[i] = gain * ingain; + } + for(;i < MAX_OUTPUT_CHANNELS;i++) + gains[i] = 0.0f; +} + + +DECL_CONST static inline const char *GetLabelFromChannel(enum Channel channel) +{ + switch(channel) + { + case FrontLeft: return "front-left"; + case FrontRight: return "front-right"; + case FrontCenter: return "front-center"; + case LFE: return "lfe"; + case BackLeft: return "back-left"; + case BackRight: return "back-right"; + case BackCenter: return "back-center"; + case SideLeft: return "side-left"; + case SideRight: return "side-right"; + + case BFormatW: return "bformat-w"; + case BFormatX: return "bformat-x"; + case BFormatY: return "bformat-y"; + case BFormatZ: return "bformat-z"; + + case InvalidChannel: break; + } + return "(unknown)"; +} + + +typedef struct ChannelMap { + enum Channel ChanName; + ChannelConfig Config; +} ChannelMap; + +static void SetChannelMap(ALCdevice *device, const ChannelMap *chanmap, size_t count, ALfloat ambiscale, ALboolean isfuma) +{ + size_t j, k; + ALuint i; + + device->AmbiScale = ambiscale; + for(i = 0;i < MAX_OUTPUT_CHANNELS && device->ChannelName[i] != InvalidChannel;i++) + { + if(device->ChannelName[i] == LFE) { - ERR("Malformed speaker key: %s\n", confkey); + for(j = 0;j < MAX_AMBI_COEFFS;j++) + device->AmbiCoeffs[i][j] = 0.0f; continue; } - end = sep - 1; - while(isspace(*end) && end != confkey) - end--; - *(++end) = 0; - - if(strcmp(confkey, "fl") == 0 || strcmp(confkey, "front-left") == 0) - val = FrontLeft; - else if(strcmp(confkey, "fr") == 0 || strcmp(confkey, "front-right") == 0) - val = FrontRight; - else if(strcmp(confkey, "fc") == 0 || strcmp(confkey, "front-center") == 0) - val = FrontCenter; - else if(strcmp(confkey, "bl") == 0 || strcmp(confkey, "back-left") == 0) - val = BackLeft; - else if(strcmp(confkey, "br") == 0 || strcmp(confkey, "back-right") == 0) - val = BackRight; - else if(strcmp(confkey, "bc") == 0 || strcmp(confkey, "back-center") == 0) - val = BackCenter; - else if(strcmp(confkey, "sl") == 0 || strcmp(confkey, "side-left") == 0) - val = SideLeft; - else if(strcmp(confkey, "sr") == 0 || strcmp(confkey, "side-right") == 0) - val = SideRight; - else + for(j = 0;j < count;j++) { - ERR("Unknown speaker for %s: \"%s\"\n", name, confkey); - continue; - } - - *(sep++) = 0; - while(isspace(*sep)) - sep++; - - for(i = 0;i < chans;i++) - { - if(Speaker2Chan[i] == val) + if(device->ChannelName[i] == chanmap[j].ChanName) { - long angle = strtol(sep, NULL, 10); - if(angle >= -180 && angle <= 180) - SpeakerAngle[i] = DEG2RAD(angle); + if(isfuma) + { + /* Reformat FuMa -> ACN/N3D */ + for(k = 0;k < MAX_AMBI_COEFFS;++k) + { + ALuint acn = FuMa2ACN[k]; + device->AmbiCoeffs[i][acn] = chanmap[j].Config[k] / FuMa2N3DScale[acn]; + } + } else - ERR("Invalid angle for speaker \"%s\": %ld\n", confkey, angle); + { + for(k = 0;k < MAX_AMBI_COEFFS;++k) + device->AmbiCoeffs[i][k] = chanmap[j].Config[k]; + } break; } } + if(j == count) + ERR("Failed to match %s channel (%u) in config\n", GetLabelFromChannel(device->ChannelName[i]), i); } - free(layout_str); - layout_str = NULL; - - for(i = 0;i < chans;i++) - { - int min = i; - int i2; - - for(i2 = i+1;i2 < chans;i2++) - { - if(SpeakerAngle[i2] < SpeakerAngle[min]) - min = i2; - } - - if(min != i) - { - ALfloat tmpf; - enum Channel tmpc; - - tmpf = SpeakerAngle[i]; - SpeakerAngle[i] = SpeakerAngle[min]; - SpeakerAngle[min] = tmpf; - - tmpc = Speaker2Chan[i]; - Speaker2Chan[i] = Speaker2Chan[min]; - Speaker2Chan[min] = tmpc; - } - } + device->NumChannels = i; } - -void ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat hwidth, ALfloat ingain, ALfloat gains[MaxChannels]) +static bool LoadChannelSetup(ALCdevice *device) { - ALfloat tmpgains[MaxChannels] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; - enum Channel Speaker2Chan[MaxChannels]; - ALfloat SpeakerAngle[MaxChannels]; - ALfloat langle, rangle; - ALfloat a; - ALuint i; + static const enum Channel mono_chans[1] = { + FrontCenter + }, stereo_chans[2] = { + FrontLeft, FrontRight + }, quad_chans[4] = { + FrontLeft, FrontRight, + BackLeft, BackRight + }, surround51_chans[5] = { + FrontLeft, FrontRight, FrontCenter, + SideLeft, SideRight + }, surround51rear_chans[5] = { + FrontLeft, FrontRight, FrontCenter, + BackLeft, BackRight + }, surround61_chans[6] = { + FrontLeft, FrontRight, + FrontCenter, BackCenter, + SideLeft, SideRight + }, surround71_chans[7] = { + FrontLeft, FrontRight, FrontCenter, + BackLeft, BackRight, + SideLeft, SideRight + }; + ChannelMap chanmap[MAX_OUTPUT_CHANNELS]; + const enum Channel *channels = NULL; + const char *layout = NULL; + ALfloat ambiscale = 1.0f; + size_t count = 0; + int isfuma; + int order; + size_t i; - for(i = 0;i < device->NumChan;i++) - Speaker2Chan[i] = device->Speaker2Chan[i]; - for(i = 0;i < device->NumChan;i++) - SpeakerAngle[i] = device->SpeakerAngle[i]; - - /* Some easy special-cases first... */ - if(device->NumChan <= 1 || hwidth >= F_PI) - { - /* Full coverage for all speakers. */ - for(i = 0;i < MaxChannels;i++) - gains[i] = 0.0f; - for(i = 0;i < device->NumChan;i++) - { - enum Channel chan = Speaker2Chan[i]; - gains[chan] = ingain; - } - return; - } - if(hwidth <= 0.0f) - { - /* Infinitely small sound point. */ - for(i = 0;i < MaxChannels;i++) - gains[i] = 0.0f; - for(i = 0;i < device->NumChan-1;i++) - { - if(angle >= SpeakerAngle[i] && angle < SpeakerAngle[i+1]) - { - /* Sound is between speakers i and i+1 */ - a = (angle-SpeakerAngle[i]) / - (SpeakerAngle[i+1]-SpeakerAngle[i]); - gains[Speaker2Chan[i]] = sqrtf(1.0f-a) * ingain; - gains[Speaker2Chan[i+1]] = sqrtf( a) * ingain; - return; - } - } - /* Sound is between last and first speakers */ - if(angle < SpeakerAngle[0]) - angle += F_2PI; - a = (angle-SpeakerAngle[i]) / - (F_2PI + SpeakerAngle[0]-SpeakerAngle[i]); - gains[Speaker2Chan[i]] = sqrtf(1.0f-a) * ingain; - gains[Speaker2Chan[0]] = sqrtf( a) * ingain; - return; - } - - if(fabsf(angle)+hwidth > F_PI) - { - /* The coverage area would go outside of -pi...+pi. Instead, rotate the - * speaker angles so it would be as if angle=0, and keep them wrapped - * within -pi...+pi. */ - if(angle > 0.0f) - { - ALuint done; - ALuint i = 0; - while(i < device->NumChan && device->SpeakerAngle[i]-angle < -F_PI) - i++; - for(done = 0;i < device->NumChan;done++) - { - SpeakerAngle[done] = device->SpeakerAngle[i]-angle; - Speaker2Chan[done] = device->Speaker2Chan[i]; - i++; - } - for(i = 0;done < device->NumChan;i++) - { - SpeakerAngle[done] = device->SpeakerAngle[i]-angle + F_2PI; - Speaker2Chan[done] = device->Speaker2Chan[i]; - done++; - } - } - else - { - /* NOTE: '< device->NumChan' on the iterators is correct here since - * we need to handle index 0. Because the iterators are unsigned, - * they'll underflow and wrap to become 0xFFFFFFFF, which will - * break as expected. */ - ALuint done; - ALuint i = device->NumChan-1; - while(i < device->NumChan && device->SpeakerAngle[i]-angle > F_PI) - i--; - for(done = device->NumChan-1;i < device->NumChan;done--) - { - SpeakerAngle[done] = device->SpeakerAngle[i]-angle; - Speaker2Chan[done] = device->Speaker2Chan[i]; - i--; - } - for(i = device->NumChan-1;done < device->NumChan;i--) - { - SpeakerAngle[done] = device->SpeakerAngle[i]-angle - F_2PI; - Speaker2Chan[done] = device->Speaker2Chan[i]; - done--; - } - } - angle = 0.0f; - } - langle = angle - hwidth; - rangle = angle + hwidth; - - /* First speaker */ - i = 0; - do { - ALuint last = device->NumChan-1; - enum Channel chan = Speaker2Chan[i]; - - if(SpeakerAngle[i] >= langle && SpeakerAngle[i] <= rangle) - { - tmpgains[chan] = 1.0f; - continue; - } - - if(SpeakerAngle[i] < langle && SpeakerAngle[i+1] > langle) - { - a = (langle-SpeakerAngle[i]) / - (SpeakerAngle[i+1]-SpeakerAngle[i]); - tmpgains[chan] = lerp(tmpgains[chan], 1.0f, 1.0f-a); - } - if(SpeakerAngle[i] > rangle) - { - a = (F_2PI + rangle-SpeakerAngle[last]) / - (F_2PI + SpeakerAngle[i]-SpeakerAngle[last]); - tmpgains[chan] = lerp(tmpgains[chan], 1.0f, a); - } - else if(SpeakerAngle[last] < rangle) - { - a = (rangle-SpeakerAngle[last]) / - (F_2PI + SpeakerAngle[i]-SpeakerAngle[last]); - tmpgains[chan] = lerp(tmpgains[chan], 1.0f, a); - } - } while(0); - - for(i = 1;i < device->NumChan-1;i++) - { - enum Channel chan = Speaker2Chan[i]; - if(SpeakerAngle[i] >= langle && SpeakerAngle[i] <= rangle) - { - tmpgains[chan] = 1.0f; - continue; - } - - if(SpeakerAngle[i] < langle && SpeakerAngle[i+1] > langle) - { - a = (langle-SpeakerAngle[i]) / - (SpeakerAngle[i+1]-SpeakerAngle[i]); - tmpgains[chan] = lerp(tmpgains[chan], 1.0f, 1.0f-a); - } - if(SpeakerAngle[i] > rangle && SpeakerAngle[i-1] < rangle) - { - a = (rangle-SpeakerAngle[i-1]) / - (SpeakerAngle[i]-SpeakerAngle[i-1]); - tmpgains[chan] = lerp(tmpgains[chan], 1.0f, a); - } - } - - /* Last speaker */ - i = device->NumChan-1; - do { - enum Channel chan = Speaker2Chan[i]; - if(SpeakerAngle[i] >= langle && SpeakerAngle[i] <= rangle) - { - tmpgains[Speaker2Chan[i]] = 1.0f; - continue; - } - if(SpeakerAngle[i] > rangle && SpeakerAngle[i-1] < rangle) - { - a = (rangle-SpeakerAngle[i-1]) / - (SpeakerAngle[i]-SpeakerAngle[i-1]); - tmpgains[chan] = lerp(tmpgains[chan], 1.0f, a); - } - if(SpeakerAngle[i] < langle) - { - a = (langle-SpeakerAngle[i]) / - (F_2PI + SpeakerAngle[0]-SpeakerAngle[i]); - tmpgains[chan] = lerp(tmpgains[chan], 1.0f, 1.0f-a); - } - else if(SpeakerAngle[0] > langle) - { - a = (F_2PI + langle-SpeakerAngle[i]) / - (F_2PI + SpeakerAngle[0]-SpeakerAngle[i]); - tmpgains[chan] = lerp(tmpgains[chan], 1.0f, 1.0f-a); - } - } while(0); - - for(i = 0;i < device->NumChan;i++) - { - enum Channel chan = device->Speaker2Chan[i]; - gains[chan] = sqrtf(tmpgains[chan]) * ingain; - } -} - - -ALvoid aluInitPanning(ALCdevice *Device) -{ - const char *layoutname = NULL; - enum Channel *Speaker2Chan; - ALfloat *SpeakerAngle; - - Speaker2Chan = Device->Speaker2Chan; - SpeakerAngle = Device->SpeakerAngle; - switch(Device->FmtChans) + switch(device->FmtChans) { case DevFmtMono: - Device->NumChan = 1; - Speaker2Chan[0] = FrontCenter; - SpeakerAngle[0] = DEG2RAD(0.0f); - layoutname = NULL; + layout = "mono"; + channels = mono_chans; + count = COUNTOF(mono_chans); + break; + case DevFmtStereo: + layout = "stereo"; + channels = stereo_chans; + count = COUNTOF(stereo_chans); + break; + case DevFmtQuad: + layout = "quad"; + channels = quad_chans; + count = COUNTOF(quad_chans); + break; + case DevFmtX51: + layout = "surround51"; + channels = surround51_chans; + count = COUNTOF(surround51_chans); + break; + case DevFmtX51Rear: + layout = "surround51rear"; + channels = surround51rear_chans; + count = COUNTOF(surround51rear_chans); + break; + case DevFmtX61: + layout = "surround61"; + channels = surround61_chans; + count = COUNTOF(surround61_chans); + break; + case DevFmtX71: + layout = "surround71"; + channels = surround71_chans; + count = COUNTOF(surround71_chans); + break; + case DevFmtBFormat3D: + break; + } + + if(!layout) + return false; + else + { + char name[32] = {0}; + const char *type; + char eol; + + snprintf(name, sizeof(name), "%s/type", layout); + if(!ConfigValueStr(al_string_get_cstr(device->DeviceName), "layouts", name, &type)) + return false; + + if(sscanf(type, " %31[^: ] : %d%c", name, &order, &eol) != 2) + { + ERR("Invalid type value '%s' (expected name:order) for layout %s\n", type, layout); + return false; + } + + if(strcasecmp(name, "fuma") == 0) + isfuma = 1; + else if(strcasecmp(name, "n3d") == 0) + isfuma = 0; + else + { + ERR("Unhandled type name '%s' (expected FuMa or N3D) for layout %s\n", name, layout); + return false; + } + + if(order == 3) + ambiscale = THIRD_ORDER_SCALE; + else if(order == 2) + ambiscale = SECOND_ORDER_SCALE; + else if(order == 1) + ambiscale = FIRST_ORDER_SCALE; + else if(order == 0) + ambiscale = ZERO_ORDER_SCALE; + else + { + ERR("Unhandled type order %d (expected 0, 1, 2, or 3) for layout %s\n", order, layout); + return false; + } + } + + for(i = 0;i < count;i++) + { + float coeffs[MAX_AMBI_COEFFS] = {0.0f}; + const char *channame; + char chanlayout[32]; + const char *value; + int props = 0; + char eol = 0; + int j; + + chanmap[i].ChanName = channels[i]; + channame = GetLabelFromChannel(channels[i]); + + snprintf(chanlayout, sizeof(chanlayout), "%s/%s", layout, channame); + if(!ConfigValueStr(al_string_get_cstr(device->DeviceName), "layouts", chanlayout, &value)) + { + ERR("Missing channel %s\n", channame); + return false; + } + if(order == 3) + props = sscanf(value, " %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %c", + &coeffs[0], &coeffs[1], &coeffs[2], &coeffs[3], + &coeffs[4], &coeffs[5], &coeffs[6], &coeffs[7], + &coeffs[8], &coeffs[9], &coeffs[10], &coeffs[11], + &coeffs[12], &coeffs[13], &coeffs[14], &coeffs[15], + &eol + ); + else if(order == 2) + props = sscanf(value, " %f %f %f %f %f %f %f %f %f %c", + &coeffs[0], &coeffs[1], &coeffs[2], + &coeffs[3], &coeffs[4], &coeffs[5], + &coeffs[6], &coeffs[7], &coeffs[8], + &eol + ); + else if(order == 1) + props = sscanf(value, " %f %f %f %f %c", + &coeffs[0], &coeffs[1], + &coeffs[2], &coeffs[3], + &eol + ); + else if(order == 0) + props = sscanf(value, " %f %c", &coeffs[0], &eol); + if(props == 0) + { + ERR("Failed to parse option %s properties\n", chanlayout); + return false; + } + + if(props > (order+1)*(order+1)) + { + ERR("Excess elements in option %s (expected %d)\n", chanlayout, (order+1)*(order+1)); + return false; + } + + for(j = 0;j < MAX_AMBI_COEFFS;++j) + chanmap[i].Config[j] = coeffs[j]; + } + SetChannelMap(device, chanmap, count, ambiscale, isfuma); + return true; +} + +ALvoid aluInitPanning(ALCdevice *device) +{ + /* NOTE: These decoder coefficients are using FuMa channel ordering and + * normalization, since that's what was produced by the Ambisonic Decoder + * Toolbox. SetChannelMap will convert them to N3D. + */ + static const ChannelMap MonoCfg[1] = { + { FrontCenter, { 1.414213562f } }, + }, StereoCfg[2] = { + { FrontLeft, { 0.707106781f, 0.0f, 0.5f, 0.0f } }, + { FrontRight, { 0.707106781f, 0.0f, -0.5f, 0.0f } }, + }, QuadCfg[4] = { + { FrontLeft, { 0.353553f, 0.306184f, 0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.117186f } }, + { FrontRight, { 0.353553f, 0.306184f, -0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.117186f } }, + { BackLeft, { 0.353553f, -0.306184f, 0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.117186f } }, + { BackRight, { 0.353553f, -0.306184f, -0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.117186f } }, + }, X51SideCfg[5] = { + { FrontLeft, { 0.208954f, 0.212846f, 0.238350f, 0.0f, 0.0f, 0.0f, 0.0f, -0.017738f, 0.204014f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.051023f, 0.047490f } }, + { FrontRight, { 0.208954f, 0.212846f, -0.238350f, 0.0f, 0.0f, 0.0f, 0.0f, -0.017738f, -0.204014f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.051023f, -0.047490f } }, + { FrontCenter, { 0.109403f, 0.179490f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.142031f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.072024f, 0.000000f } }, + { SideLeft, { 0.470936f, -0.369626f, 0.349386f, 0.0f, 0.0f, 0.0f, 0.0f, -0.031375f, -0.058144f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.007119f, -0.043968f } }, + { SideRight, { 0.470936f, -0.369626f, -0.349386f, 0.0f, 0.0f, 0.0f, 0.0f, -0.031375f, 0.058144f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.007119f, 0.043968f } }, + }, X51RearCfg[5] = { + { FrontLeft, { 0.208954f, 0.212846f, 0.238350f, 0.0f, 0.0f, 0.0f, 0.0f, -0.017738f, 0.204014f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.051023f, 0.047490f } }, + { FrontRight, { 0.208954f, 0.212846f, -0.238350f, 0.0f, 0.0f, 0.0f, 0.0f, -0.017738f, -0.204014f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.051023f, -0.047490f } }, + { FrontCenter, { 0.109403f, 0.179490f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.142031f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.072024f, 0.000000f } }, + { BackLeft, { 0.470936f, -0.369626f, 0.349386f, 0.0f, 0.0f, 0.0f, 0.0f, -0.031375f, -0.058144f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.007119f, -0.043968f } }, + { BackRight, { 0.470936f, -0.369626f, -0.349386f, 0.0f, 0.0f, 0.0f, 0.0f, -0.031375f, 0.058144f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.007119f, 0.043968f } }, + }, X61Cfg[6] = { + { FrontLeft, { 0.167065f, 0.200583f, 0.172695f, 0.0f, 0.0f, 0.0f, 0.0f, 0.029855f, 0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f, 0.068910f } }, + { FrontRight, { 0.167065f, 0.200583f, -0.172695f, 0.0f, 0.0f, 0.0f, 0.0f, 0.029855f, -0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f, -0.068910f } }, + { FrontCenter, { 0.109403f, 0.179490f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.142031f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.072024f, 0.000000f } }, + { BackCenter, { 0.353556f, -0.461940f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.165723f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.000000f } }, + { SideLeft, { 0.289151f, -0.081301f, 0.401292f, 0.0f, 0.0f, 0.0f, 0.0f, -0.188208f, -0.071420f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.010099f, -0.032897f } }, + { SideRight, { 0.289151f, -0.081301f, -0.401292f, 0.0f, 0.0f, 0.0f, 0.0f, -0.188208f, 0.071420f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.010099f, 0.032897f } }, + }, X71Cfg[7] = { + { FrontLeft, { 0.167065f, 0.200583f, 0.172695f, 0.0f, 0.0f, 0.0f, 0.0f, 0.029855f, 0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f, 0.068910f } }, + { FrontRight, { 0.167065f, 0.200583f, -0.172695f, 0.0f, 0.0f, 0.0f, 0.0f, 0.029855f, -0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f, -0.068910f } }, + { FrontCenter, { 0.109403f, 0.179490f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.142031f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.072024f, 0.000000f } }, + { BackLeft, { 0.224752f, -0.295009f, 0.170325f, 0.0f, 0.0f, 0.0f, 0.0f, 0.105349f, -0.182473f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.065799f } }, + { BackRight, { 0.224752f, -0.295009f, -0.170325f, 0.0f, 0.0f, 0.0f, 0.0f, 0.105349f, 0.182473f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.065799f } }, + { SideLeft, { 0.224739f, 0.000000f, 0.340644f, 0.0f, 0.0f, 0.0f, 0.0f, -0.210697f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.065795f } }, + { SideRight, { 0.224739f, 0.000000f, -0.340644f, 0.0f, 0.0f, 0.0f, 0.0f, -0.210697f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.065795f } }, + }, BFormat3D[4] = { + { BFormatW, { 1.0f, 0.0f, 0.0f, 0.0f } }, + { BFormatX, { 0.0f, 1.0f, 0.0f, 0.0f } }, + { BFormatY, { 0.0f, 0.0f, 1.0f, 0.0f } }, + { BFormatZ, { 0.0f, 0.0f, 0.0f, 1.0f } }, + }; + const ChannelMap *chanmap = NULL; + ALfloat ambiscale = 1.0f; + size_t count = 0; + + device->AmbiScale = 1.0f; + memset(device->AmbiCoeffs, 0, sizeof(device->AmbiCoeffs)); + device->NumChannels = 0; + + if(device->Hrtf) + { + ALfloat (*coeffs_list[4])[2]; + ALuint *delay_list[4]; + ALuint i; + + count = COUNTOF(BFormat3D); + chanmap = BFormat3D; + ambiscale = 1.0f; + + for(i = 0;i < count;i++) + device->ChannelName[i] = chanmap[i].ChanName; + for(;i < MAX_OUTPUT_CHANNELS;i++) + device->ChannelName[i] = InvalidChannel; + SetChannelMap(device, chanmap, count, ambiscale, AL_TRUE); + + for(i = 0;i < 4;++i) + { + static const enum Channel inputs[4] = { BFormatW, BFormatX, BFormatY, BFormatZ }; + int chan = GetChannelIdxByName(device, inputs[i]); + coeffs_list[i] = device->Hrtf_Params[chan].Coeffs; + delay_list[i] = device->Hrtf_Params[chan].Delay; + } + GetBFormatHrtfCoeffs(device->Hrtf, 4, coeffs_list, delay_list); + + return; + } + + if(LoadChannelSetup(device)) + return; + + switch(device->FmtChans) + { + case DevFmtMono: + count = COUNTOF(MonoCfg); + chanmap = MonoCfg; + ambiscale = ZERO_ORDER_SCALE; break; case DevFmtStereo: - Device->NumChan = 2; - Speaker2Chan[0] = FrontLeft; - Speaker2Chan[1] = FrontRight; - SpeakerAngle[0] = DEG2RAD(-90.0f); - SpeakerAngle[1] = DEG2RAD( 90.0f); - layoutname = "layout_stereo"; + count = COUNTOF(StereoCfg); + chanmap = StereoCfg; + ambiscale = FIRST_ORDER_SCALE; break; case DevFmtQuad: - Device->NumChan = 4; - Speaker2Chan[0] = BackLeft; - Speaker2Chan[1] = FrontLeft; - Speaker2Chan[2] = FrontRight; - Speaker2Chan[3] = BackRight; - SpeakerAngle[0] = DEG2RAD(-135.0f); - SpeakerAngle[1] = DEG2RAD( -45.0f); - SpeakerAngle[2] = DEG2RAD( 45.0f); - SpeakerAngle[3] = DEG2RAD( 135.0f); - layoutname = "layout_quad"; + count = COUNTOF(QuadCfg); + chanmap = QuadCfg; + ambiscale = SECOND_ORDER_SCALE; break; case DevFmtX51: - Device->NumChan = 5; - Speaker2Chan[0] = BackLeft; - Speaker2Chan[1] = FrontLeft; - Speaker2Chan[2] = FrontCenter; - Speaker2Chan[3] = FrontRight; - Speaker2Chan[4] = BackRight; - SpeakerAngle[0] = DEG2RAD(-110.0f); - SpeakerAngle[1] = DEG2RAD( -30.0f); - SpeakerAngle[2] = DEG2RAD( 0.0f); - SpeakerAngle[3] = DEG2RAD( 30.0f); - SpeakerAngle[4] = DEG2RAD( 110.0f); - layoutname = "layout_surround51"; + count = COUNTOF(X51SideCfg); + chanmap = X51SideCfg; + ambiscale = THIRD_ORDER_SCALE; break; - case DevFmtX51Side: - Device->NumChan = 5; - Speaker2Chan[0] = SideLeft; - Speaker2Chan[1] = FrontLeft; - Speaker2Chan[2] = FrontCenter; - Speaker2Chan[3] = FrontRight; - Speaker2Chan[4] = SideRight; - SpeakerAngle[0] = DEG2RAD(-90.0f); - SpeakerAngle[1] = DEG2RAD(-30.0f); - SpeakerAngle[2] = DEG2RAD( 0.0f); - SpeakerAngle[3] = DEG2RAD( 30.0f); - SpeakerAngle[4] = DEG2RAD( 90.0f); - layoutname = "layout_side51"; + case DevFmtX51Rear: + count = COUNTOF(X51RearCfg); + chanmap = X51RearCfg; + ambiscale = THIRD_ORDER_SCALE; break; case DevFmtX61: - Device->NumChan = 6; - Speaker2Chan[0] = SideLeft; - Speaker2Chan[1] = FrontLeft; - Speaker2Chan[2] = FrontCenter; - Speaker2Chan[3] = FrontRight; - Speaker2Chan[4] = SideRight; - Speaker2Chan[5] = BackCenter; - SpeakerAngle[0] = DEG2RAD(-90.0f); - SpeakerAngle[1] = DEG2RAD(-30.0f); - SpeakerAngle[2] = DEG2RAD( 0.0f); - SpeakerAngle[3] = DEG2RAD( 30.0f); - SpeakerAngle[4] = DEG2RAD( 90.0f); - SpeakerAngle[5] = DEG2RAD(180.0f); - layoutname = "layout_surround61"; + count = COUNTOF(X61Cfg); + chanmap = X61Cfg; + ambiscale = THIRD_ORDER_SCALE; break; case DevFmtX71: - Device->NumChan = 7; - Speaker2Chan[0] = BackLeft; - Speaker2Chan[1] = SideLeft; - Speaker2Chan[2] = FrontLeft; - Speaker2Chan[3] = FrontCenter; - Speaker2Chan[4] = FrontRight; - Speaker2Chan[5] = SideRight; - Speaker2Chan[6] = BackRight; - SpeakerAngle[0] = DEG2RAD(-150.0f); - SpeakerAngle[1] = DEG2RAD( -90.0f); - SpeakerAngle[2] = DEG2RAD( -30.0f); - SpeakerAngle[3] = DEG2RAD( 0.0f); - SpeakerAngle[4] = DEG2RAD( 30.0f); - SpeakerAngle[5] = DEG2RAD( 90.0f); - SpeakerAngle[6] = DEG2RAD( 150.0f); - layoutname = "layout_surround71"; + count = COUNTOF(X71Cfg); + chanmap = X71Cfg; + ambiscale = THIRD_ORDER_SCALE; + break; + + case DevFmtBFormat3D: + count = COUNTOF(BFormat3D); + chanmap = BFormat3D; + ambiscale = 1.0f; break; } - if(layoutname && Device->Type != Loopback) - SetSpeakerArrangement(layoutname, SpeakerAngle, Speaker2Chan, Device->NumChan); + + SetChannelMap(device, chanmap, count, ambiscale, AL_TRUE); } diff --git a/libs/openal-soft/Alc/vector.h b/libs/openal-soft/Alc/vector.h index 9f28d0db..c1fc925d 100644 --- a/libs/openal-soft/Alc/vector.h +++ b/libs/openal-soft/Alc/vector.h @@ -7,21 +7,21 @@ /* "Base" vector type, designed to alias with the actual vector types. */ typedef struct vector__s { - ALsizei Capacity; - ALsizei Size; + size_t Capacity; + size_t Size; } *vector_; #define TYPEDEF_VECTOR(T, N) typedef struct { \ - ALsizei Capacity; \ - ALsizei Size; \ + size_t Capacity; \ + size_t Size; \ T Data[]; \ } _##N; \ typedef _##N* N; \ typedef const _##N* const_##N; #define VECTOR(T) struct { \ - ALsizei Capacity; \ - ALsizei Size; \ + size_t Capacity; \ + size_t Size; \ T Data[]; \ }* @@ -30,10 +30,10 @@ typedef const _##N* const_##N; #define VECTOR_DEINIT(_x) do { free((_x)); (_x) = NULL; } while(0) /* Helper to increase a vector's reserve. Do not call directly. */ -ALboolean vector_reserve(char *ptr, size_t base_size, size_t obj_size, ALsizei obj_count, ALboolean exact); +ALboolean vector_reserve(char *ptr, size_t base_size, size_t obj_size, size_t obj_count, ALboolean exact); #define VECTOR_RESERVE(_x, _c) (vector_reserve((char*)&(_x), sizeof(*(_x)), sizeof((_x)->Data[0]), (_c), AL_TRUE)) -ALboolean vector_resize(char *ptr, size_t base_size, size_t obj_size, ALsizei obj_count); +ALboolean vector_resize(char *ptr, size_t base_size, size_t obj_size, size_t obj_count); #define VECTOR_RESIZE(_x, _c) (vector_resize((char*)&(_x), sizeof(*(_x)), sizeof((_x)->Data[0]), (_c))) #define VECTOR_CAPACITY(_x) ((_x) ? (_x)->Capacity : 0) @@ -73,6 +73,13 @@ ALboolean vector_insert(char *ptr, size_t base_size, size_t obj_size, void *ins_ _f(_iter); \ } while(0) +#define VECTOR_FOR_EACH_PARAMS(_t, _x, _f, ...) do { \ + _t *_iter = VECTOR_ITER_BEGIN((_x)); \ + _t *_end = VECTOR_ITER_END((_x)); \ + for(;_iter != _end;++_iter) \ + _f(__VA_ARGS__, _iter); \ +} while(0) + #define VECTOR_FIND_IF(_i, _t, _x, _f) do { \ _t *_iter = VECTOR_ITER_BEGIN((_x)); \ _t *_end = VECTOR_ITER_END((_x)); \ @@ -84,4 +91,15 @@ ALboolean vector_insert(char *ptr, size_t base_size, size_t obj_size, void *ins_ (_i) = _iter; \ } while(0) +#define VECTOR_FIND_IF_PARMS(_i, _t, _x, _f, ...) do { \ + _t *_iter = VECTOR_ITER_BEGIN((_x)); \ + _t *_end = VECTOR_ITER_END((_x)); \ + for(;_iter != _end;++_iter) \ + { \ + if(_f(__VA_ARGS__, _iter)) \ + break; \ + } \ + (_i) = _iter; \ +} while(0) + #endif /* AL_VECTOR_H */ diff --git a/libs/openal-soft/CMakeLists.txt b/libs/openal-soft/CMakeLists.txt index 448a0fae..26587111 100644 --- a/libs/openal-soft/CMakeLists.txt +++ b/libs/openal-soft/CMakeLists.txt @@ -34,9 +34,11 @@ OPTION(ALSOFT_UTILS "Build and install utility programs" OFF) OPTION(ALSOFT_NO_CONFIG_UTIL "Disable building the alsoft-config utility" OFF) OPTION(ALSOFT_EXAMPLES "Build and install example programs" OFF) +OPTION(ALSOFT_TESTS "Build and install test programs" OFF) OPTION(ALSOFT_CONFIG "Install alsoft.conf sample configuration file" OFF) -OPTION(ALSOFT_HRTF_DEFS "Install HRTF definition files" ON) +OPTION(ALSOFT_HRTF_DEFS "Install HRTF definition files" OFF) +OPTION(ALSOFT_INSTALL "Install headers and libraries" ON) IF(WIN32) @@ -89,7 +91,7 @@ IF(NOT LIBTYPE) ENDIF() SET(LIB_MAJOR_VERSION "1") -SET(LIB_MINOR_VERSION "16") +SET(LIB_MINOR_VERSION "17") SET(LIB_REVISION "0") SET(LIB_VERSION "${LIB_MAJOR_VERSION}.${LIB_MINOR_VERSION}.${LIB_REVISION}") @@ -101,9 +103,14 @@ CHECK_TYPE_SIZE("long" SIZEOF_LONG) CHECK_TYPE_SIZE("long long" SIZEOF_LONG_LONG) -CHECK_C_COMPILER_FLAG(-std=c99 HAVE_STD_C99) -IF(HAVE_STD_C99) - SET(CMAKE_C_FLAGS "-std=c99 ${CMAKE_C_FLAGS}") +CHECK_C_COMPILER_FLAG(-std=c11 HAVE_STD_C11) +IF(HAVE_STD_C11) + SET(CMAKE_C_FLAGS "-std=c11 ${CMAKE_C_FLAGS}") +ELSE() + CHECK_C_COMPILER_FLAG(-std=c99 HAVE_STD_C99) + IF(HAVE_STD_C99) + SET(CMAKE_C_FLAGS "-std=c99 ${CMAKE_C_FLAGS}") + ENDIF() ENDIF() # MSVC may need workarounds for C99 restrict and inline @@ -188,7 +195,7 @@ HAVE_C11_ALIGNAS) # Check if we have C11 _Atomic CHECK_C_SOURCE_COMPILES( "#include - int _Atomic foo; + const int _Atomic foo = ATOMIC_VAR_INIT(~0); int main() { return atomic_load(&foo); @@ -216,11 +223,6 @@ IF(NOT CMAKE_DEBUG_POSTFIX) ENDIF() IF(MSVC) - # ??? - SET(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -D_DEBUG") - SET(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} -DNDEBUG") - SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -DNDEBUG") - SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG") ADD_DEFINITIONS(-D_CRT_SECURE_NO_WARNINGS) ADD_DEFINITIONS(-D_CRT_NONSTDC_NO_DEPRECATE) ADD_DEFINITIONS("/wd4098") @@ -232,9 +234,6 @@ IF(MSVC) ENDIF() IF(DXSDK_DIR) MESSAGE(STATUS "Using DirectX SDK directory: ${DXSDK_DIR}") - SET(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} "${DXSDK_DIR}/Include") - INCLUDE_DIRECTORIES("${DXSDK_DIR}/Include") - LINK_DIRECTORIES("${DXSDK_DIR}/Lib") ENDIF() OPTION(FORCE_STATIC_VCRT "Force /MT for static VC runtimes" OFF) @@ -258,27 +257,24 @@ ELSE() ADD_DEFINITIONS(-Werror) ENDIF() - # Force enable PIC if available. The static common library will be linked - # into the dynamic openal library, which requires all its code to be - # position-independent, and CMake doesn't automatically enable PIC for - # static library targets (Windows code is always position-independent). - CHECK_C_COMPILER_FLAG(-fPIC HAVE_FPIC_SWITCH) - IF(HAVE_FPIC_SWITCH AND NOT WIN32) - ADD_DEFINITIONS(-fPIC) + # Force enable -fPIC for CMake versions before 2.8.9 (later versions have + # the POSITION_INDEPENDENT_CODE target property). The static common library + # will be linked into the dynamic openal library, which requires all its + # code to be position-independent. + IF(CMAKE_VERSION VERSION_LESS "2.8.9" AND NOT WIN32) + CHECK_C_COMPILER_FLAG(-fPIC HAVE_FPIC_SWITCH) + IF(HAVE_FPIC_SWITCH) + ADD_DEFINITIONS(-fPIC) + ENDIF() ENDIF() - SET(CMAKE_C_FLAGS_RELWITHDEBINFO "-g -O2 -D_DEBUG" CACHE STRING - "Flags used by the compiler during Release with Debug Info builds." - FORCE) - SET(CMAKE_C_FLAGS_MINSIZEREL "-Os -DNDEBUG" CACHE STRING - "Flags used by the compiler during release minsize builds." - FORCE) - SET(CMAKE_C_FLAGS_RELEASE "-O2 -fomit-frame-pointer -DNDEBUG" CACHE STRING - "Flags used by the compiler during release builds" - FORCE) - SET(CMAKE_C_FLAGS_DEBUG "-g3 -D_DEBUG" CACHE STRING - "Flags used by the compiler during debug builds." - FORCE) + # We want RelWithDebInfo to actually include debug stuff (define _DEBUG + # instead of NDEBUG) + FOREACH(flag_var CMAKE_C_FLAGS_RELWITHDEBINFO CMAKE_CXX_FLAGS_RELWITHDEBINFO) + IF(${flag_var} MATCHES "-DNDEBUG") + STRING(REGEX REPLACE "-DNDEBUG" "-D_DEBUG" ${flag_var} "${${flag_var}}") + ENDIF() + ENDFOREACH() CHECK_C_SOURCE_COMPILES("int foo() __attribute__((destructor)); int main() {return 0;}" HAVE_GCC_DESTRUCTOR) @@ -337,6 +333,10 @@ IF(NOT MSVC) IF(HAVE_MSSE2_SWITCH) SET(SSE2_SWITCH "-msse2") ENDIF() + CHECK_C_COMPILER_FLAG(-msse3 HAVE_MSSE3_SWITCH) + IF(HAVE_MSSE3_SWITCH) + SET(SSE3_SWITCH "-msse3") + ENDIF() CHECK_C_COMPILER_FLAG(-msse4.1 HAVE_MSSE4_1_SWITCH) IF(HAVE_MSSE4_1_SWITCH) SET(SSE4_1_SWITCH "-msse4.1") @@ -349,7 +349,7 @@ CHECK_C_SOURCE_COMPILES("int foo(const char *str, ...) __attribute__((format(pri CHECK_INCLUDE_FILE(stdbool.h HAVE_STDBOOL_H) CHECK_INCLUDE_FILE(stdalign.h HAVE_STDALIGN_H) CHECK_INCLUDE_FILE(malloc.h HAVE_MALLOC_H) -CHECK_INCLUDE_FILE(ftw.h HAVE_FTW_H) +CHECK_INCLUDE_FILE(dirent.h HAVE_DIRENT_H) CHECK_INCLUDE_FILE(io.h HAVE_IO_H) CHECK_INCLUDE_FILE(strings.h HAVE_STRINGS_H) CHECK_INCLUDE_FILE(cpuid.h HAVE_CPUID_H) @@ -368,7 +368,7 @@ IF(HAVE_CPUID_H) int main() { unsigned int eax, ebx, ecx, edx; - return __get_cpuid(0, eax, ebx, ecx, edx); + return __get_cpuid(0, &eax, &ebx, &ecx, &edx); }" HAVE_GCC_GET_CPUID) ENDIF() @@ -394,6 +394,7 @@ CHECK_SYMBOL_EXISTS(aligned_alloc stdlib.h HAVE_ALIGNED_ALLOC) CHECK_SYMBOL_EXISTS(posix_memalign stdlib.h HAVE_POSIX_MEMALIGN) CHECK_SYMBOL_EXISTS(_aligned_malloc malloc.h HAVE__ALIGNED_MALLOC) CHECK_SYMBOL_EXISTS(lrintf math.h HAVE_LRINTF) +CHECK_SYMBOL_EXISTS(modff math.h HAVE_MODFF) IF(NOT HAVE_C99_VLA) CHECK_SYMBOL_EXISTS(alloca malloc.h HAVE_ALLOCA) IF(NOT HAVE_ALLOCA) @@ -405,12 +406,6 @@ IF(HAVE_FLOAT_H) CHECK_SYMBOL_EXISTS(_controlfp float.h HAVE__CONTROLFP) CHECK_SYMBOL_EXISTS(__control87_2 float.h HAVE___CONTROL87_2) ENDIF() -IF(HAVE_FTW_H) - CHECK_SYMBOL_EXISTS(ftw ftw.h HAVE_FTW) -ENDIF() -IF(HAVE_IO_H) - CHECK_SYMBOL_EXISTS(_wfindfirst io.h HAVE__WFINDFIRST) -ENDIF() CHECK_FUNCTION_EXISTS(strtof HAVE_STRTOF) CHECK_FUNCTION_EXISTS(stat HAVE_STAT) @@ -515,12 +510,18 @@ IF(NOT HAVE_WINDOWS_H) CHECK_SYMBOL_EXISTS(pthread_setschedparam pthread.h HAVE_PTHREAD_SETSCHEDPARAM) - CHECK_SYMBOL_EXISTS(pthread_setname_np pthread.h HAVE_PTHREAD_SETNAME_NP) - IF(NOT HAVE_PTHREAD_SETNAME_NP) - CHECK_SYMBOL_EXISTS(pthread_set_name_np pthread.h HAVE_PTHREAD_SET_NAME_NP) - ENDIF() IF(HAVE_PTHREAD_NP_H) + CHECK_SYMBOL_EXISTS(pthread_setname_np "pthread.h;pthread_np.h" HAVE_PTHREAD_SETNAME_NP) + IF(NOT HAVE_PTHREAD_SETNAME_NP) + CHECK_SYMBOL_EXISTS(pthread_set_name_np "pthread.h;pthread_np.h" HAVE_PTHREAD_SET_NAME_NP) + ENDIF() CHECK_SYMBOL_EXISTS(pthread_mutexattr_setkind_np "pthread.h;pthread_np.h" HAVE_PTHREAD_MUTEXATTR_SETKIND_NP) + ELSE() + CHECK_SYMBOL_EXISTS(pthread_setname_np pthread.h HAVE_PTHREAD_SETNAME_NP) + IF(NOT HAVE_PTHREAD_SETNAME_NP) + CHECK_SYMBOL_EXISTS(pthread_set_name_np pthread.h HAVE_PTHREAD_SET_NAME_NP) + ENDIF() + CHECK_SYMBOL_EXISTS(pthread_mutexattr_setkind_np pthread.h HAVE_PTHREAD_MUTEXATTR_SETKIND_NP) ENDIF() CHECK_SYMBOL_EXISTS(pthread_mutex_timedlock pthread.h HAVE_PTHREAD_MUTEX_TIMEDLOCK) @@ -561,11 +562,7 @@ SET(OPENAL_OBJS OpenAL32/alAuxEffectSlot.c OpenAL32/alError.c OpenAL32/alExtension.c OpenAL32/alFilter.c - OpenAL32/alFontsound.c OpenAL32/alListener.c - OpenAL32/alMidi.c - OpenAL32/alPreset.c - OpenAL32/alSoundfont.c OpenAL32/alSource.c OpenAL32/alState.c OpenAL32/alThunk.c @@ -588,6 +585,7 @@ SET(ALC_OBJS Alc/ALc.c Alc/effects/null.c Alc/effects/reverb.c Alc/helpers.c + Alc/bsinc.c Alc/hrtf.c Alc/panning.c Alc/mixer.c @@ -598,11 +596,10 @@ SET(ALC_OBJS Alc/ALc.c SET(CPU_EXTS "Default") SET(HAVE_SSE 0) SET(HAVE_SSE2 0) +SET(HAVE_SSE3 0) SET(HAVE_SSE4_1 0) SET(HAVE_NEON 0) -SET(HAVE_FLUIDSYNTH 0) - SET(HAVE_ALSA 0) SET(HAVE_OSS 0) SET(HAVE_SOLARIS 0) @@ -658,6 +655,26 @@ IF(ALSOFT_REQUIRE_SSE2 AND NOT HAVE_SSE2) MESSAGE(FATAL_ERROR "Failed to enable required SSE2 CPU extensions") ENDIF() +OPTION(ALSOFT_REQUIRE_SSE2 "Require SSE3 support" OFF) +CHECK_INCLUDE_FILE(pmmintrin.h HAVE_PMMINTRIN_H "${SSE3_SWITCH}") +IF(HAVE_EMMINTRIN_H) + OPTION(ALSOFT_CPUEXT_SSE3 "Enable SSE3 support" ON) + IF(HAVE_SSE2 AND ALSOFT_CPUEXT_SSE3) + IF(ALIGN_DECL OR HAVE_C11_ALIGNAS) + SET(HAVE_SSE3 1) + SET(ALC_OBJS ${ALC_OBJS} Alc/mixer_sse3.c) + IF(SSE2_SWITCH) + SET_SOURCE_FILES_PROPERTIES(Alc/mixer_sse3.c PROPERTIES + COMPILE_FLAGS "${SSE3_SWITCH}") + ENDIF() + SET(CPU_EXTS "${CPU_EXTS}, SSE3") + ENDIF() + ENDIF() +ENDIF() +IF(ALSOFT_REQUIRE_SSE3 AND NOT HAVE_SSE3) + MESSAGE(FATAL_ERROR "Failed to enable required SSE3 CPU extensions") +ENDIF() + OPTION(ALSOFT_REQUIRE_SSE4_1 "Require SSE4.1 support" OFF) CHECK_INCLUDE_FILE(smmintrin.h HAVE_SMMINTRIN_H "${SSE4_1_SWITCH}") IF(HAVE_SMMINTRIN_H) @@ -705,32 +722,6 @@ ELSE() ENDMACRO() ENDIF() -SET(ALC_OBJS ${ALC_OBJS} - Alc/midi/base.c - Alc/midi/sf2load.c - Alc/midi/dummy.c - Alc/midi/fluidsynth.c - Alc/midi/soft.c -) - -# Check for FluidSynth support -OPTION(ALSOFT_REQUIRE_FLUIDSYNTH "Require FluidSynth MIDI" OFF) -FIND_PACKAGE(FluidSynth) -IF(FLUIDSYNTH_FOUND) - OPTION(ALSOFT_MIDI_FLUIDSYNTH "Enable FluidSynth MIDI" ON) - IF(ALSOFT_MIDI_FLUIDSYNTH) - SET(HAVE_FLUIDSYNTH 1) - ADD_BACKEND_LIBS(${FLUIDSYNTH_LIBRARIES}) - IF(CMAKE_VERSION VERSION_LESS "2.8.8") - INCLUDE_DIRECTORIES(${FLUIDSYNTH_INCLUDE_DIR}) - ENDIF() - ENDIF() -ENDIF() -IF(ALSOFT_REQUIRE_FLUIDSYNTH AND NOT HAVE_FLUIDSYNTH) - MESSAGE(FATAL_ERROR "Failed to enabled required FluidSynth support") -ENDIF() - - SET(BACKENDS "") SET(ALC_OBJS ${ALC_OBJS} Alc/backends/base.c @@ -926,6 +917,25 @@ IF(ALSOFT_REQUIRE_PULSEAUDIO AND NOT HAVE_PULSEAUDIO) MESSAGE(FATAL_ERROR "Failed to enabled required PulseAudio backend") ENDIF() +# Check JACK backend +OPTION(ALSOFT_REQUIRE_JACK "Require JACK backend" OFF) +FIND_PACKAGE(JACK) +IF(JACK_FOUND) + OPTION(ALSOFT_BACKEND_JACK "Enable JACK backend" ON) + IF(ALSOFT_BACKEND_JACK) + SET(HAVE_JACK 1) + SET(BACKENDS "${BACKENDS} JACK${IS_LINKED},") + SET(ALC_OBJS ${ALC_OBJS} Alc/backends/jack.c) + ADD_BACKEND_LIBS(${PULSEAUDIO_LIBRARIES}) + IF(CMAKE_VERSION VERSION_LESS "2.8.8") + INCLUDE_DIRECTORIES(${JACK_INCLUDE_DIRS}) + ENDIF() + ENDIF() +ENDIF() +IF(ALSOFT_REQUIRE_JACK AND NOT HAVE_JACK) + MESSAGE(FATAL_ERROR "Failed to enabled required JACK backend") +ENDIF() + # Check CoreAudio backend OPTION(ALSOFT_REQUIRE_COREAUDIO "Require CoreAudio backend" OFF) FIND_LIBRARY(COREAUDIO_FRAMEWORK @@ -1030,17 +1040,21 @@ CONFIGURE_FILE( # Build a common library with reusable helpers ADD_LIBRARY(common STATIC ${COMMON_OBJS}) +IF(NOT LIBTYPE STREQUAL "STATIC") + SET_PROPERTY(TARGET common PROPERTY POSITION_INDEPENDENT_CODE TRUE) +ENDIF() # Build main library -ADD_LIBRARY(${LIBNAME} ${LIBTYPE} ${OPENAL_OBJS} ${ALC_OBJS}) +IF(LIBTYPE STREQUAL "STATIC") + ADD_LIBRARY(${LIBNAME} STATIC ${COMMON_OBJS} ${OPENAL_OBJS} ${ALC_OBJS}) +ELSE() + ADD_LIBRARY(${LIBNAME} SHARED ${OPENAL_OBJS} ${ALC_OBJS}) +ENDIF() SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY COMPILE_DEFINITIONS AL_BUILD_LIBRARY AL_ALEXT_PROTOTYPES) IF(WIN32 AND ALSOFT_NO_UID_DEFS) SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY COMPILE_DEFINITIONS AL_NO_UID_DEFS) ENDIF() SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY INCLUDE_DIRECTORIES "${OpenAL_SOURCE_DIR}/OpenAL32/Include" "${OpenAL_SOURCE_DIR}/Alc") -IF(FLUIDSYNTH_FOUND) - SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY INCLUDE_DIRECTORIES ${FLUIDSYNTH_INCLUDE_DIR}) -ENDIF() IF(HAVE_ALSA) SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY INCLUDE_DIRECTORIES ${ALSA_INCLUDE_DIRS}) ENDIF() @@ -1065,6 +1079,9 @@ ENDIF() IF(HAVE_PULSEAUDIO) SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY INCLUDE_DIRECTORIES ${PULSEAUDIO_INCLUDE_DIRS}) ENDIF() +IF(HAVE_JACK) + SET_PROPERTY(TARGET ${LIBNAME} APPEND PROPERTY INCLUDE_DIRECTORIES ${JACK_INCLUDE_DIRS}) +ENDIF() SET_TARGET_PROPERTIES(${LIBNAME} PROPERTIES VERSION ${LIB_VERSION} SOVERSION ${LIB_MAJOR_VERSION}) IF(WIN32 AND NOT LIBTYPE STREQUAL "STATIC") @@ -1096,25 +1113,28 @@ ENDIF() TARGET_LINK_LIBRARIES(${LIBNAME} common ${EXTRA_LIBS}) TARGET_INCLUDE_DIRECTORIES(${LIBNAME} PUBLIC include) -# Add an install target here -IF(NOT MEGA) -INSTALL(TARGETS ${LIBNAME} - RUNTIME DESTINATION bin - LIBRARY DESTINATION "lib${LIB_SUFFIX}" - ARCHIVE DESTINATION "lib${LIB_SUFFIX}" -) -INSTALL(FILES include/AL/al.h - include/AL/alc.h - include/AL/alext.h - include/AL/efx.h - include/AL/efx-creative.h - include/AL/efx-presets.h - DESTINATION include/AL -) -INSTALL(FILES "${OpenAL_BINARY_DIR}/openal.pc" - DESTINATION "lib${LIB_SUFFIX}/pkgconfig") +IF(ALSOFT_INSTALL) + # Add an install target here + IF(NOT MEGA) + INSTALL(TARGETS ${LIBNAME} + RUNTIME DESTINATION bin + LIBRARY DESTINATION "lib${LIB_SUFFIX}" + ARCHIVE DESTINATION "lib${LIB_SUFFIX}" + ) + INSTALL(FILES include/AL/al.h + include/AL/alc.h + include/AL/alext.h + include/AL/efx.h + include/AL/efx-creative.h + include/AL/efx-presets.h + DESTINATION include/AL + ) + INSTALL(FILES "${OpenAL_BINARY_DIR}/openal.pc" + DESTINATION "lib${LIB_SUFFIX}/pkgconfig") + ENDIF() ENDIF() + MESSAGE(STATUS "") MESSAGE(STATUS "Building OpenAL with support for the following backends:") MESSAGE(STATUS " ${BACKENDS}") @@ -1122,10 +1142,6 @@ MESSAGE(STATUS "") MESSAGE(STATUS "Building with support for CPU extensions:") MESSAGE(STATUS " ${CPU_EXTS}") MESSAGE(STATUS "") -IF(HAVE_FLUIDSYNTH) - MESSAGE(STATUS "FluidSynth support for ALC_SOFT_midi_interface enabled") - MESSAGE(STATUS "") -ENDIF() IF(WIN32) IF(NOT HAVE_DSOUND) @@ -1163,11 +1179,18 @@ IF(ALSOFT_UTILS) TARGET_LINK_LIBRARIES(makehrtf m) ENDIF() - INSTALL(TARGETS openal-info makehrtf - RUNTIME DESTINATION bin - LIBRARY DESTINATION "lib${LIB_SUFFIX}" - ARCHIVE DESTINATION "lib${LIB_SUFFIX}" - ) + ADD_EXECUTABLE(bsincgen utils/bsincgen.c) + IF(HAVE_LIBM) + TARGET_LINK_LIBRARIES(bsincgen m) + ENDIF() + + IF(ALSOFT_INSTALL) + INSTALL(TARGETS openal-info makehrtf bsincgen + RUNTIME DESTINATION bin + LIBRARY DESTINATION "lib${LIB_SUFFIX}" + ARCHIVE DESTINATION "lib${LIB_SUFFIX}" + ) + ENDIF() MESSAGE(STATUS "Building utility programs") IF(TARGET alsoft-config) @@ -1176,6 +1199,24 @@ IF(ALSOFT_UTILS) MESSAGE(STATUS "") ENDIF() +IF(ALSOFT_TESTS) + ADD_LIBRARY(test-common STATIC examples/common/alhelpers.c) + + ADD_EXECUTABLE(altonegen examples/altonegen.c) + TARGET_LINK_LIBRARIES(altonegen test-common ${LIBNAME}) + + IF(ALSOFT_INSTALL) + INSTALL(TARGETS altonegen + RUNTIME DESTINATION bin + LIBRARY DESTINATION "lib${LIB_SUFFIX}" + ARCHIVE DESTINATION "lib${LIB_SUFFIX}" + ) + ENDIF() + + MESSAGE(STATUS "Building test programs") + MESSAGE(STATUS "") +ENDIF() + IF(ALSOFT_EXAMPLES) IF(SDL2_FOUND AND SDL_SOUND_FOUND) ADD_LIBRARY(ex-common STATIC examples/common/alhelpers.c @@ -1203,11 +1244,18 @@ IF(ALSOFT_EXAMPLES) SET_PROPERTY(TARGET alloopback APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR}) - INSTALL(TARGETS alstream alreverb allatency alloopback - RUNTIME DESTINATION bin - LIBRARY DESTINATION "lib${LIB_SUFFIX}" - ARCHIVE DESTINATION "lib${LIB_SUFFIX}" - ) + ADD_EXECUTABLE(alhrtf examples/alhrtf.c) + TARGET_LINK_LIBRARIES(alhrtf ex-common ${SDL_SOUND_LIBRARIES} ${SDL2_LIBRARY} ${LIBNAME}) + SET_PROPERTY(TARGET alhrtf APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} + ${SDL_SOUND_INCLUDE_DIR}) + + IF(ALSOFT_INSTALL) + INSTALL(TARGETS alstream alreverb allatency alloopback + RUNTIME DESTINATION bin + LIBRARY DESTINATION "lib${LIB_SUFFIX}" + ARCHIVE DESTINATION "lib${LIB_SUFFIX}" + ) + ENDIF() SET(FFVER_OK FALSE) IF(FFMPEG_FOUND) @@ -1239,11 +1287,13 @@ IF(ALSOFT_EXAMPLES) SET_PROPERTY(TARGET alffplay APPEND PROPERTY INCLUDE_DIRECTORIES ${SDL2_INCLUDE_DIR} ${FFMPEG_INCLUDE_DIRS}) - INSTALL(TARGETS alffplay - RUNTIME DESTINATION bin - LIBRARY DESTINATION "lib${LIB_SUFFIX}" - ARCHIVE DESTINATION "lib${LIB_SUFFIX}" - ) + IF(ALSOFT_INSTALL) + INSTALL(TARGETS alffplay + RUNTIME DESTINATION bin + LIBRARY DESTINATION "lib${LIB_SUFFIX}" + ARCHIVE DESTINATION "lib${LIB_SUFFIX}" + ) + ENDIF() MESSAGE(STATUS "Building SDL and FFmpeg example programs") ELSE() MESSAGE(STATUS "Building SDL example programs") diff --git a/libs/openal-soft/COPYING b/libs/openal-soft/COPYING index d0c89786..5bc8fb2c 100644 --- a/libs/openal-soft/COPYING +++ b/libs/openal-soft/COPYING @@ -1,17 +1,15 @@ - - GNU LIBRARY GENERAL PUBLIC LICENSE - Version 2, June 1991 - + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 Copyright (C) 1991 Free Software Foundation, Inc. - 675 Mass Ave, Cambridge, MA 02139, USA + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the library GPL. It is numbered 2 because it goes with version 2 of the ordinary GPL.] - Preamble + Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public @@ -101,7 +99,7 @@ works together with the library. Note that it is possible for a library to be covered by the ordinary General Public License rather than by this special one. - GNU LIBRARY GENERAL PUBLIC LICENSE + GNU LIBRARY GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library which @@ -413,7 +411,7 @@ decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. - NO WARRANTY + NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. @@ -436,9 +434,9 @@ FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - END OF TERMS AND CONDITIONS + END OF TERMS AND CONDITIONS - Appendix: How to Apply These Terms to Your New Libraries + How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that @@ -465,8 +463,8 @@ convey the exclusion of warranty; and each file should have at least the Library General Public License for more details. You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. @@ -481,4 +479,3 @@ necessary. Here is a sample; alter the names: Ty Coon, President of Vice That's all there is to it! - diff --git a/libs/openal-soft/ChangeLog b/libs/openal-soft/ChangeLog index 8df50144..2f037254 100644 --- a/libs/openal-soft/ChangeLog +++ b/libs/openal-soft/ChangeLog @@ -1,3 +1,61 @@ +openal-soft-1.17.0: + + Implemented a JACK playback backend. + + Implemented the AL_EXT_BFORMAT and AL_EXT_MULAW_BFORMAT extensions. + + Implemented the ALC_SOFT_HRTF extension. + + Implemented C, SSE3, and SSE4.1 based 4- and 8-point Sinc resamplers. + + Implemented a C and SSE based band-limited Sinc resampler. This does 12- to + 24-point Sinc resampling, and performs anti-aliasing. + + Implemented B-Format output support for the wave file writer. This creates + FuMa-style first-order Ambisonics wave files (AMB format). + + Implemented a stereo-mode config option for treating stereo modes as either + speakers or headphones. + + Implemented per-device configuration options. + + Fixed handling of PulseAudio and MMDevAPI devices that have identical + descriptions. + + Fixed a potential lockup when stopping playback of suspended PulseAudio devices. + + Fixed logging of Unicode characters on Windows. + + Fixed 5.1 surround sound channels. By default it will now use the side + channels for the surround output. A configuration using rear channels is + still available. + + Fixed the QSA backend potentially altering the capture format. + + Fixed detecting MMDevAPI's default device. + + Fixed returning the default capture device name. + + Fixed mixing property calculations when deferring context updates. + + Altered the behavior of alcSuspendContext and alcProcessContext to better + match certain Windows drivers. + + Altered the panning algorithm, utilizing Ambisonics for better side and + back positioning cues with surround sound output. + + Improved support for certain older Windows apps. + + Improved the alffplay example to support surround sound streams. + + Improved support for building as a sub-project. + + Added an HRTF playback example. + + Added a tone generator output test. + + Added a toolchain to help with cross-compiling to Android. + openal-soft-1.16.0: Implemented EFX Chorus, Flanger, Distortion, Equalizer, and Compressor diff --git a/libs/openal-soft/OpenAL32/Include/alAuxEffectSlot.h b/libs/openal-soft/OpenAL32/Include/alAuxEffectSlot.h index 286aa95d..0f0d3ef8 100644 --- a/libs/openal-soft/OpenAL32/Include/alAuxEffectSlot.h +++ b/libs/openal-soft/OpenAL32/Include/alAuxEffectSlot.h @@ -22,7 +22,7 @@ struct ALeffectStateVtable { ALboolean (*const deviceUpdate)(ALeffectState *state, ALCdevice *device); void (*const update)(ALeffectState *state, ALCdevice *device, const struct ALeffectslot *slot); - void (*const process)(ALeffectState *state, ALuint samplesToDo, const ALfloat *restrict samplesIn, ALfloat (*restrict samplesOut)[BUFFERSIZE]); + void (*const process)(ALeffectState *state, ALuint samplesToDo, const ALfloat *restrict samplesIn, ALfloat (*restrict samplesOut)[BUFFERSIZE], ALuint numChannels); void (*const Delete)(void *ptr); }; @@ -31,7 +31,7 @@ struct ALeffectStateVtable { DECLARE_THUNK(T, ALeffectState, void, Destruct) \ DECLARE_THUNK1(T, ALeffectState, ALboolean, deviceUpdate, ALCdevice*) \ DECLARE_THUNK2(T, ALeffectState, void, update, ALCdevice*, const ALeffectslot*) \ -DECLARE_THUNK3(T, ALeffectState, void, process, ALuint, const ALfloat*restrict, ALfloatBUFFERSIZE*restrict) \ +DECLARE_THUNK4(T, ALeffectState, void, process, ALuint, const ALfloat*restrict, ALfloatBUFFERSIZE*restrict, ALuint) \ static void T##_ALeffectState_Delete(void *ptr) \ { return T##_Delete(STATIC_UPCAST(T, ALeffectState, (ALeffectState*)ptr)); } \ \ diff --git a/libs/openal-soft/OpenAL32/Include/alBuffer.h b/libs/openal-soft/OpenAL32/Include/alBuffer.h index 557f2282..dd046da8 100644 --- a/libs/openal-soft/OpenAL32/Include/alBuffer.h +++ b/libs/openal-soft/OpenAL32/Include/alBuffer.h @@ -32,6 +32,8 @@ enum UserFmtChannels { UserFmtX51 = AL_5POINT1_SOFT, /* (WFX order) */ UserFmtX61 = AL_6POINT1_SOFT, /* (WFX order) */ UserFmtX71 = AL_7POINT1_SOFT, /* (WFX order) */ + UserFmtBFormat2D = 0x10000000, /* WXY */ + UserFmtBFormat3D, /* WXYZ */ }; ALuint BytesFromUserFmt(enum UserFmtType type) DECL_CONST; @@ -56,6 +58,8 @@ enum FmtChannels { FmtX51 = UserFmtX51, FmtX61 = UserFmtX61, FmtX71 = UserFmtX71, + FmtBFormat2D = UserFmtBFormat2D, + FmtBFormat3D = UserFmtBFormat3D, }; #define MAX_INPUT_CHANNELS (8) @@ -85,8 +89,8 @@ typedef struct ALbuffer { ALsizei LoopStart; ALsizei LoopEnd; - ALsizei UnpackAlign; - ALsizei PackAlign; + ATOMIC(ALsizei) UnpackAlign; + ATOMIC(ALsizei) PackAlign; /* Number of times buffer was attached to a source (deletion can only occur when 0) */ RefCount ref; diff --git a/libs/openal-soft/OpenAL32/Include/alEffect.h b/libs/openal-soft/OpenAL32/Include/alEffect.h index f656c56a..91ee782f 100644 --- a/libs/openal-soft/OpenAL32/Include/alEffect.h +++ b/libs/openal-soft/OpenAL32/Include/alEffect.h @@ -132,7 +132,6 @@ typedef union ALeffectProps { } Echo; struct { - ALfloat Delay; ALfloat LowCutoff; ALfloat LowGain; ALfloat Mid1Center; diff --git a/libs/openal-soft/OpenAL32/Include/alFilter.h b/libs/openal-soft/OpenAL32/Include/alFilter.h index 62b5fda8..3c65fd9f 100644 --- a/libs/openal-soft/OpenAL32/Include/alFilter.h +++ b/libs/openal-soft/OpenAL32/Include/alFilter.h @@ -3,6 +3,8 @@ #include "alMain.h" +#include "math_defs.h" + #ifdef __cplusplus extern "C" { #endif @@ -11,23 +13,29 @@ extern "C" { #define HIGHPASSFREQREF (250.0f) -/* Filters implementation is based on the "Cookbook formulae for audio * - * EQ biquad filter coefficients" by Robert Bristow-Johnson * - * http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt */ +/* Filters implementation is based on the "Cookbook formulae for audio + * EQ biquad filter coefficients" by Robert Bristow-Johnson + * http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt + */ +/* Implementation note: For the shelf filters, the specified gain is for the + * reference frequency, which is the centerpoint of the transition band. This + * better matches EFX filter design. To set the gain for the shelf itself, use + * the square root of the desired linear gain (or halve the dB gain). + */ typedef enum ALfilterType { /** EFX-style low-pass filter, specifying a gain and reference frequency. */ ALfilterType_HighShelf, /** EFX-style high-pass filter, specifying a gain and reference frequency. */ ALfilterType_LowShelf, - /** Peaking filter, specifying a gain, reference frequency, and bandwidth. */ + /** Peaking filter, specifying a gain and reference frequency. */ ALfilterType_Peaking, - /** Low-pass cut-off filter, specifying a cut-off frequency and bandwidth. */ + /** Low-pass cut-off filter, specifying a cut-off frequency. */ ALfilterType_LowPass, - /** High-pass cut-off filter, specifying a cut-off frequency and bandwidth. */ + /** High-pass cut-off filter, specifying a cut-off frequency. */ ALfilterType_HighPass, - /** Band-pass filter, specifying a center frequency and bandwidth. */ + /** Band-pass filter, specifying a center frequency. */ ALfilterType_BandPass, } ALfilterType; @@ -41,8 +49,27 @@ typedef struct ALfilterState { } ALfilterState; #define ALfilterState_process(a, ...) ((a)->process((a), __VA_ARGS__)) +/* Calculates the rcpQ (i.e. 1/Q) coefficient for shelving filters, using the + * reference gain and shelf slope parameter. + * 0 < gain + * 0 < slope <= 1 + */ +inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope) +{ + return sqrtf((gain + 1.0f/gain)*(1.0f/slope - 1.0f) + 2.0f); +} +/* Calculates the rcpQ (i.e. 1/Q) coefficient for filters, using the frequency + * multiple (i.e. ref_freq / sampling_freq) and bandwidth. + * 0 < freq_mult < 0.5. + */ +inline ALfloat calc_rcpQ_from_bandwidth(ALfloat freq_mult, ALfloat bandwidth) +{ + ALfloat w0 = F_TAU * freq_mult; + return 2.0f*sinhf(logf(2.0f)/2.0f*bandwidth*w0/sinf(w0)); +} + void ALfilterState_clear(ALfilterState *filter); -void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat bandwidth); +void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat rcpQ); inline ALfloat ALfilterState_processSingle(ALfilterState *filter, ALfloat sample) { @@ -63,6 +90,8 @@ inline ALfloat ALfilterState_processSingle(ALfilterState *filter, ALfloat sample void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *src, ALuint numsamples); +void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *src, ALuint numsamples); + typedef struct ALfilter { // Filter type (AL_FILTER_NULL, ...) diff --git a/libs/openal-soft/OpenAL32/Include/alListener.h b/libs/openal-soft/OpenAL32/Include/alListener.h index ee07d87c..c9bd9be0 100644 --- a/libs/openal-soft/OpenAL32/Include/alListener.h +++ b/libs/openal-soft/OpenAL32/Include/alListener.h @@ -2,22 +2,23 @@ #define _AL_LISTENER_H_ #include "alMain.h" +#include "alu.h" #ifdef __cplusplus extern "C" { #endif typedef struct ALlistener { - volatile ALfloat Position[3]; - volatile ALfloat Velocity[3]; + aluVector Position; + aluVector Velocity; volatile ALfloat Forward[3]; volatile ALfloat Up[3]; volatile ALfloat Gain; volatile ALfloat MetersPerUnit; struct { - ALfloat Matrix[4][4]; - ALfloat Velocity[3]; + aluMatrixd Matrix; + aluVector Velocity; } Params; } ALlistener; diff --git a/libs/openal-soft/OpenAL32/Include/alMain.h b/libs/openal-soft/OpenAL32/Include/alMain.h index 111dde95..8f1fd956 100644 --- a/libs/openal-soft/OpenAL32/Include/alMain.h +++ b/libs/openal-soft/OpenAL32/Include/alMain.h @@ -37,209 +37,7 @@ #include "vector.h" #include "alstring.h" -#ifndef ALC_SOFT_HRTF -#define ALC_SOFT_HRTF 1 -#define ALC_HRTF_SOFT 0x1992 -#endif - -#ifndef ALC_SOFT_midi_interface -#define ALC_SOFT_midi_interface 1 -/* Global properties */ -#define AL_MIDI_CLOCK_SOFT 0x9999 -#define AL_MIDI_STATE_SOFT 0x9986 -#define AL_MIDI_GAIN_SOFT 0x9998 -#define AL_SOUNDFONTS_SIZE_SOFT 0x9995 -#define AL_SOUNDFONTS_SOFT 0x9994 - -/* Soundfont properties */ -#define AL_PRESETS_SIZE_SOFT 0x9993 -#define AL_PRESETS_SOFT 0x9992 - -/* Preset properties */ -#define AL_MIDI_PRESET_SOFT 0x9997 -#define AL_MIDI_BANK_SOFT 0x9996 -#define AL_FONTSOUNDS_SIZE_SOFT 0x9991 -#define AL_FONTSOUNDS_SOFT 0x9990 - -/* Fontsound properties */ -/* AL_BUFFER */ -#define AL_SAMPLE_START_SOFT 0x2000 -#define AL_SAMPLE_END_SOFT 0x2001 -#define AL_SAMPLE_LOOP_START_SOFT 0x2002 -#define AL_SAMPLE_LOOP_END_SOFT 0x2003 -#define AL_SAMPLE_RATE_SOFT 0x2004 -#define AL_BASE_KEY_SOFT 0x2005 -#define AL_KEY_CORRECTION_SOFT 0x2006 -#define AL_SAMPLE_TYPE_SOFT 0x2007 -#define AL_FONTSOUND_LINK_SOFT 0x2008 -#define AL_MOD_LFO_TO_PITCH_SOFT 0x0005 -#define AL_VIBRATO_LFO_TO_PITCH_SOFT 0x0006 -#define AL_MOD_ENV_TO_PITCH_SOFT 0x0007 -#define AL_FILTER_CUTOFF_SOFT 0x0008 -#define AL_FILTER_RESONANCE_SOFT 0x0009 -#define AL_MOD_LFO_TO_FILTER_CUTOFF_SOFT 0x000A -#define AL_MOD_ENV_TO_FILTER_CUTOFF_SOFT 0x000B -#define AL_MOD_LFO_TO_VOLUME_SOFT 0x000D -#define AL_CHORUS_SEND_SOFT 0x000F -#define AL_REVERB_SEND_SOFT 0x0010 -#define AL_PAN_SOFT 0x0011 -#define AL_MOD_LFO_DELAY_SOFT 0x0015 -#define AL_MOD_LFO_FREQUENCY_SOFT 0x0016 -#define AL_VIBRATO_LFO_DELAY_SOFT 0x0017 -#define AL_VIBRATO_LFO_FREQUENCY_SOFT 0x0018 -#define AL_MOD_ENV_DELAYTIME_SOFT 0x0019 -#define AL_MOD_ENV_ATTACKTIME_SOFT 0x001A -#define AL_MOD_ENV_HOLDTIME_SOFT 0x001B -#define AL_MOD_ENV_DECAYTIME_SOFT 0x001C -#define AL_MOD_ENV_SUSTAINVOLUME_SOFT 0x001D -#define AL_MOD_ENV_RELEASETIME_SOFT 0x002E -#define AL_MOD_ENV_KEY_TO_HOLDTIME_SOFT 0x001F -#define AL_MOD_ENV_KEY_TO_DECAYTIME_SOFT 0x0020 -#define AL_VOLUME_ENV_DELAYTIME_SOFT 0x0021 -#define AL_VOLUME_ENV_ATTACKTIME_SOFT 0x0022 -#define AL_VOLUME_ENV_HOLDTIME_SOFT 0x0023 -#define AL_VOLUME_ENV_DECAYTIME_SOFT 0x0024 -#define AL_VOLUME_ENV_SUSTAINVOLUME_SOFT 0x0025 -#define AL_VOLUME_ENV_RELEASETIME_SOFT 0x0026 -#define AL_VOLUME_ENV_KEY_TO_HOLDTIME_SOFT 0x0027 -#define AL_VOLUME_ENV_KEY_TO_DECAYTIME_SOFT 0x0028 -#define AL_KEY_RANGE_SOFT 0x002B -#define AL_VELOCITY_RANGE_SOFT 0x002C -#define AL_ATTENUATION_SOFT 0x0030 -#define AL_TUNING_COARSE_SOFT 0x0033 -#define AL_TUNING_FINE_SOFT 0x0034 -#define AL_LOOP_MODE_SOFT 0x0036 -#define AL_TUNING_SCALE_SOFT 0x0038 -#define AL_EXCLUSIVE_CLASS_SOFT 0x0039 - -/* Sample Types */ -/* AL_MONO_SOFT */ -#define AL_RIGHT_SOFT 0x0002 -#define AL_LEFT_SOFT 0x0004 - -/* Loop Modes */ -/* AL_NONE */ -#define AL_LOOP_CONTINUOUS_SOFT 0x0001 -#define AL_LOOP_UNTIL_RELEASE_SOFT 0x0003 - -/* Fontsound modulator stage properties */ -#define AL_SOURCE0_INPUT_SOFT 0x998F -#define AL_SOURCE0_TYPE_SOFT 0x998E -#define AL_SOURCE0_FORM_SOFT 0x998D -#define AL_SOURCE1_INPUT_SOFT 0x998C -#define AL_SOURCE1_TYPE_SOFT 0x998B -#define AL_SOURCE1_FORM_SOFT 0x998A -#define AL_AMOUNT_SOFT 0x9989 -#define AL_TRANSFORM_OP_SOFT 0x9988 -#define AL_DESTINATION_SOFT 0x9987 - -/* Sounce Inputs */ -#define AL_ONE_SOFT 0x0080 -#define AL_NOTEON_VELOCITY_SOFT 0x0082 -#define AL_NOTEON_KEY_SOFT 0x0083 -/* AL_KEYPRESSURE_SOFT */ -/* AL_CHANNELPRESSURE_SOFT */ -/* AL_PITCHBEND_SOFT */ -#define AL_PITCHBEND_SENSITIVITY_SOFT 0x0090 -/* CC 0...127 */ - -/* Source Types */ -#define AL_UNORM_SOFT 0x0000 -#define AL_UNORM_REV_SOFT 0x0100 -#define AL_SNORM_SOFT 0x0200 -#define AL_SNORM_REV_SOFT 0x0300 - -/* Source Forms */ -#define AL_LINEAR_SOFT 0x0000 -#define AL_CONCAVE_SOFT 0x0400 -#define AL_CONVEX_SOFT 0x0800 -#define AL_SWITCH_SOFT 0x0C00 - -/* Transform Ops */ -/* AL_LINEAR_SOFT */ -#define AL_ABSOLUTE_SOFT 0x0002 - -/* Events */ -#define AL_NOTEOFF_SOFT 0x0080 -#define AL_NOTEON_SOFT 0x0090 -#define AL_KEYPRESSURE_SOFT 0x00A0 -#define AL_CONTROLLERCHANGE_SOFT 0x00B0 -#define AL_PROGRAMCHANGE_SOFT 0x00C0 -#define AL_CHANNELPRESSURE_SOFT 0x00D0 -#define AL_PITCHBEND_SOFT 0x00E0 - -typedef void (AL_APIENTRY*LPALGENSOUNDFONTSSOFT)(ALsizei n, ALuint *ids); -typedef void (AL_APIENTRY*LPALDELETESOUNDFONTSSOFT)(ALsizei n, const ALuint *ids); -typedef ALboolean (AL_APIENTRY*LPALISSOUNDFONTSOFT)(ALuint id); -typedef void (AL_APIENTRY*LPALGETSOUNDFONTIVSOFT)(ALuint id, ALenum param, ALint *values); -typedef void (AL_APIENTRY*LPALSOUNDFONTPRESETSSOFT)(ALuint id, ALsizei count, const ALuint *pids); -typedef void (AL_APIENTRY*LPALGENPRESETSSOFT)(ALsizei n, ALuint *ids); -typedef void (AL_APIENTRY*LPALDELETEPRESETSSOFT)(ALsizei n, const ALuint *ids); -typedef ALboolean (AL_APIENTRY*LPALISPRESETSOFT)(ALuint id); -typedef void (AL_APIENTRY*LPALPRESETISOFT)(ALuint id, ALenum param, ALint value); -typedef void (AL_APIENTRY*LPALPRESETIVSOFT)(ALuint id, ALenum param, const ALint *values); -typedef void (AL_APIENTRY*LPALPRESETFONTSOUNDSSOFT)(ALuint id, ALsizei count, const ALuint *fsids); -typedef void (AL_APIENTRY*LPALGETPRESETIVSOFT)(ALuint id, ALenum param, ALint *values); -typedef void (AL_APIENTRY*LPALGENFONTSOUNDSSOFT)(ALsizei n, ALuint *ids); -typedef void (AL_APIENTRY*LPALDELETEFONTSOUNDSSOFT)(ALsizei n, const ALuint *ids); -typedef ALboolean (AL_APIENTRY*LPALISFONTSOUNDSOFT)(ALuint id); -typedef void (AL_APIENTRY*LPALFONTSOUNDISOFT)(ALuint id, ALenum param, ALint value); -typedef void (AL_APIENTRY*LPALFONTSOUND2ISOFT)(ALuint id, ALenum param, ALint value1, ALint value2); -typedef void (AL_APIENTRY*LPALFONTSOUNDIVSOFT)(ALuint id, ALenum param, const ALint *values); -typedef void (AL_APIENTRY*LPALGETFONTSOUNDIVSOFT)(ALuint id, ALenum param, ALint *values); -typedef void (AL_APIENTRY*LPALFONTSOUNDMOFULATORISOFT)(ALuint id, ALsizei stage, ALenum param, ALint value); -typedef void (AL_APIENTRY*LPALGETFONTSOUNDMODULATORIVSOFT)(ALuint id, ALsizei stage, ALenum param, ALint *values); -typedef void (AL_APIENTRY*LPALMIDISOUNDFONTSOFT)(ALuint id); -typedef void (AL_APIENTRY*LPALMIDISOUNDFONTVSOFT)(ALsizei count, const ALuint *ids); -typedef void (AL_APIENTRY*LPALMIDIEVENTSOFT)(ALuint64SOFT time, ALenum event, ALsizei channel, ALsizei param1, ALsizei param2); -typedef void (AL_APIENTRY*LPALMIDISYSEXSOFT)(ALuint64SOFT time, const ALbyte *data, ALsizei size); -typedef void (AL_APIENTRY*LPALMIDIPLAYSOFT)(void); -typedef void (AL_APIENTRY*LPALMIDIPAUSESOFT)(void); -typedef void (AL_APIENTRY*LPALMIDISTOPSOFT)(void); -typedef void (AL_APIENTRY*LPALMIDIRESETSOFT)(void); -typedef void (AL_APIENTRY*LPALMIDIGAINSOFT)(ALfloat value); -typedef ALint64SOFT (AL_APIENTRY*LPALGETINTEGER64SOFT)(ALenum pname); -typedef void (AL_APIENTRY*LPALGETINTEGER64VSOFT)(ALenum pname, ALint64SOFT *values); -typedef void (AL_APIENTRY*LPALLOADSOUNDFONTSOFT)(ALuint id, size_t(*cb)(ALvoid*,size_t,ALvoid*), ALvoid *user); -#ifdef AL_ALEXT_PROTOTYPES -AL_API void AL_APIENTRY alGenSoundfontsSOFT(ALsizei n, ALuint *ids); -AL_API void AL_APIENTRY alDeleteSoundfontsSOFT(ALsizei n, const ALuint *ids); -AL_API ALboolean AL_APIENTRY alIsSoundfontSOFT(ALuint id); -AL_API void AL_APIENTRY alGetSoundfontivSOFT(ALuint id, ALenum param, ALint *values); -AL_API void AL_APIENTRY alSoundfontPresetsSOFT(ALuint id, ALsizei count, const ALuint *pids); - -AL_API void AL_APIENTRY alGenPresetsSOFT(ALsizei n, ALuint *ids); -AL_API void AL_APIENTRY alDeletePresetsSOFT(ALsizei n, const ALuint *ids); -AL_API ALboolean AL_APIENTRY alIsPresetSOFT(ALuint id); -AL_API void AL_APIENTRY alPresetiSOFT(ALuint id, ALenum param, ALint value); -AL_API void AL_APIENTRY alPresetivSOFT(ALuint id, ALenum param, const ALint *values); -AL_API void AL_APIENTRY alGetPresetivSOFT(ALuint id, ALenum param, ALint *values); -AL_API void AL_APIENTRY alPresetFontsoundsSOFT(ALuint id, ALsizei count, const ALuint *fsids); - -AL_API void AL_APIENTRY alGenFontsoundsSOFT(ALsizei n, ALuint *ids); -AL_API void AL_APIENTRY alDeleteFontsoundsSOFT(ALsizei n, const ALuint *ids); -AL_API ALboolean AL_APIENTRY alIsFontsoundSOFT(ALuint id); -AL_API void AL_APIENTRY alFontsoundiSOFT(ALuint id, ALenum param, ALint value); -AL_API void AL_APIENTRY alFontsound2iSOFT(ALuint id, ALenum param, ALint value1, ALint value2); -AL_API void AL_APIENTRY alFontsoundivSOFT(ALuint id, ALenum param, const ALint *values); -AL_API void AL_APIENTRY alGetFontsoundivSOFT(ALuint id, ALenum param, ALint *values); -AL_API void AL_APIENTRY alFontsoundModulatoriSOFT(ALuint id, ALsizei stage, ALenum param, ALint value); -AL_API void AL_APIENTRY alGetFontsoundModulatorivSOFT(ALuint id, ALsizei stage, ALenum param, ALint *values); - -AL_API void AL_APIENTRY alMidiSoundfontSOFT(ALuint id); -AL_API void AL_APIENTRY alMidiSoundfontvSOFT(ALsizei count, const ALuint *ids); -AL_API void AL_APIENTRY alMidiEventSOFT(ALuint64SOFT time, ALenum event, ALsizei channel, ALsizei param1, ALsizei param2); -AL_API void AL_APIENTRY alMidiSysExSOFT(ALuint64SOFT time, const ALbyte *data, ALsizei size); -AL_API void AL_APIENTRY alMidiPlaySOFT(void); -AL_API void AL_APIENTRY alMidiPauseSOFT(void); -AL_API void AL_APIENTRY alMidiStopSOFT(void); -AL_API void AL_APIENTRY alMidiResetSOFT(void); -AL_API void AL_APIENTRY alMidiGainSOFT(ALfloat value); -AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname); -AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values); -AL_API void AL_APIENTRY alLoadSoundfontSOFT(ALuint id, size_t(*cb)(ALvoid*,size_t,ALvoid*), ALvoid *user); -#endif -#endif +#include "hrtf.h" #ifndef ALC_SOFT_device_clock #define ALC_SOFT_device_clock 1 @@ -253,19 +51,9 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, #endif -#ifdef IN_IDE_PARSER -/* KDevelop's parser doesn't recognize the C99-standard restrict keyword, but - * recent versions (at least 4.5.1) do recognize GCC's __restrict. */ -#define restrict __restrict -#endif - - typedef ALint64SOFT ALint64; typedef ALuint64SOFT ALuint64; -typedef ptrdiff_t ALintptrEXT; -typedef ptrdiff_t ALsizeiptrEXT; - #ifndef U64 #if defined(_MSC_VER) #define U64(x) ((ALuint64)(x##ui64)) @@ -385,9 +173,13 @@ static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b) \ static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b, argtype3 c) \ { return T1##_##func(STATIC_UPCAST(T1, T2, obj), a, b, c); } +#define DECLARE_THUNK4(T1, T2, rettype, func, argtype1, argtype2, argtype3, argtype4) \ +static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b, argtype3 c, argtype4 d) \ +{ return T1##_##func(STATIC_UPCAST(T1, T2, obj), a, b, c, d); } + #define DECLARE_DEFAULT_ALLOCATORS(T) \ -static void* T##_New(size_t size) { return malloc(size); } \ -static void T##_Delete(void *ptr) { free(ptr); } +static void* T##_New(size_t size) { return al_malloc(16, size); } \ +static void T##_Delete(void *ptr) { al_free(ptr); } /* Helper to extract an argument list for VCALL. Not used directly. */ #define EXTRACT_VCALL_ARGS(...) __VA_ARGS__)) @@ -406,6 +198,18 @@ static void T##_Delete(void *ptr) { free(ptr); } } while(0) +#define EXTRACT_NEW_ARGS(...) __VA_ARGS__); \ + } \ +} while(0) + +#define NEW_OBJ(_res, T) do { \ + _res = T##_New(sizeof(T)); \ + if(_res) \ + { \ + memset(_res, 0, sizeof(T)); \ + T##_Construct(_res, EXTRACT_NEW_ARGS + + #ifdef __cplusplus extern "C" { #endif @@ -472,25 +276,11 @@ typedef struct { void (*StopCapture)(ALCdevice*); ALCenum (*CaptureSamples)(ALCdevice*, void*, ALCuint); ALCuint (*AvailableSamples)(ALCdevice*); - - ALint64 (*GetLatency)(ALCdevice*); } BackendFuncs; -ALCboolean alc_solaris_init(BackendFuncs *func_list); -void alc_solaris_deinit(void); -void alc_solaris_probe(enum DevProbe type); ALCboolean alc_sndio_init(BackendFuncs *func_list); void alc_sndio_deinit(void); void alc_sndio_probe(enum DevProbe type); -ALCboolean alcWinMMInit(BackendFuncs *FuncList); -void alcWinMMDeinit(void); -void alcWinMMProbe(enum DevProbe type); -ALCboolean alc_pa_init(BackendFuncs *func_list); -void alc_pa_deinit(void); -void alc_pa_probe(enum DevProbe type); -ALCboolean alc_wave_init(BackendFuncs *func_list); -void alc_wave_deinit(void); -void alc_wave_probe(enum DevProbe type); ALCboolean alc_ca_init(BackendFuncs *func_list); void alc_ca_deinit(void); void alc_ca_probe(enum DevProbe type); @@ -516,14 +306,6 @@ enum DistanceModel { DefaultDistanceModel = InverseDistanceClamped }; -enum Resampler { - PointResampler, - LinearResampler, - CubicResampler, - - ResamplerMax, -}; - enum Channel { FrontLeft = 0, FrontRight, @@ -535,7 +317,12 @@ enum Channel { SideLeft, SideRight, - MaxChannels, + BFormatW, + BFormatX, + BFormatY, + BFormatZ, + + InvalidChannel }; @@ -559,11 +346,14 @@ enum DevFmtChannels { DevFmtX61 = ALC_6POINT1_SOFT, DevFmtX71 = ALC_7POINT1_SOFT, - /* Similar to 5.1, except using the side channels instead of back */ - DevFmtX51Side = 0x80000000, + /* Similar to 5.1, except using rear channels instead of sides */ + DevFmtX51Rear = 0x80000000, + + DevFmtBFormat3D, DevFmtChannelsDefault = DevFmtStereo }; +#define MAX_OUTPUT_CHANNELS (8) ALuint BytesFromDevFmt(enum DevFmtType type) DECL_CONST; ALuint ChannelsFromDevFmt(enum DevFmtChannels chans) DECL_CONST; @@ -588,6 +378,38 @@ enum DeviceType { }; +enum HrtfMode { + DisabledHrtf, + BasicHrtf, + FullHrtf +}; + + +/* The maximum number of Ambisonics coefficients. For a given order (o), the + * size needed will be (o+1)**2, thus zero-order has 1, first-order has 4, + * second-order has 9, and third-order has 16. */ +#define MAX_AMBI_COEFFS 16 + +typedef ALfloat ChannelConfig[MAX_AMBI_COEFFS]; + + +#define HRTF_HISTORY_BITS (6) +#define HRTF_HISTORY_LENGTH (1<Device); } @@ -810,15 +616,35 @@ ALsizei RingBufferSize(RingBuffer *ring); void WriteRingBuffer(RingBuffer *ring, const ALubyte *data, ALsizei len); void ReadRingBuffer(RingBuffer *ring, ALubyte *data, ALsizei len); +typedef struct ll_ringbuffer ll_ringbuffer_t; +typedef struct ll_ringbuffer_data { + char *buf; + size_t len; +} ll_ringbuffer_data_t; +ll_ringbuffer_t *ll_ringbuffer_create(size_t sz, size_t elem_sz); +void ll_ringbuffer_free(ll_ringbuffer_t *rb); +void ll_ringbuffer_get_read_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t *vec); +void ll_ringbuffer_get_write_vector(const ll_ringbuffer_t *rb, ll_ringbuffer_data_t *vec); +size_t ll_ringbuffer_read(ll_ringbuffer_t *rb, char *dest, size_t cnt); +size_t ll_ringbuffer_peek(ll_ringbuffer_t *rb, char *dest, size_t cnt); +void ll_ringbuffer_read_advance(ll_ringbuffer_t *rb, size_t cnt); +size_t ll_ringbuffer_read_space(const ll_ringbuffer_t *rb); +int ll_ringbuffer_mlock(ll_ringbuffer_t *rb); +void ll_ringbuffer_reset(ll_ringbuffer_t *rb); +size_t ll_ringbuffer_write(ll_ringbuffer_t *rb, const char *src, size_t cnt); +void ll_ringbuffer_write_advance(ll_ringbuffer_t *rb, size_t cnt); +size_t ll_ringbuffer_write_space(const ll_ringbuffer_t *rb); + void ReadALConfig(void); void FreeALConfig(void); -int ConfigValueExists(const char *blockName, const char *keyName); -const char *GetConfigValue(const char *blockName, const char *keyName, const char *def); -int GetConfigValueBool(const char *blockName, const char *keyName, int def); -int ConfigValueStr(const char *blockName, const char *keyName, const char **ret); -int ConfigValueInt(const char *blockName, const char *keyName, int *ret); -int ConfigValueUInt(const char *blockName, const char *keyName, unsigned int *ret); -int ConfigValueFloat(const char *blockName, const char *keyName, float *ret); +int ConfigValueExists(const char *devName, const char *blockName, const char *keyName); +const char *GetConfigValue(const char *devName, const char *blockName, const char *keyName, const char *def); +int GetConfigValueBool(const char *devName, const char *blockName, const char *keyName, int def); +int ConfigValueStr(const char *devName, const char *blockName, const char *keyName, const char **ret); +int ConfigValueInt(const char *devName, const char *blockName, const char *keyName, int *ret); +int ConfigValueUInt(const char *devName, const char *blockName, const char *keyName, unsigned int *ret); +int ConfigValueFloat(const char *devName, const char *blockName, const char *keyName, float *ret); +int ConfigValueBool(const char *devName, const char *blockName, const char *keyName, int *ret); void SetRTPriority(void); @@ -828,10 +654,27 @@ void SetDefaultWFXChannelOrder(ALCdevice *device); const ALCchar *DevFmtTypeString(enum DevFmtType type) DECL_CONST; const ALCchar *DevFmtChannelsString(enum DevFmtChannels chans) DECL_CONST; +/** + * GetChannelIdxByName + * + * Returns the device's channel index given a channel name (e.g. FrontCenter), + * or -1 if it doesn't exist. + */ +inline ALint GetChannelIdxByName(const ALCdevice *device, enum Channel chan) +{ + ALint i = 0; + for(i = 0;i < MAX_OUTPUT_CHANNELS;i++) + { + if(device->ChannelName[i] == chan) + return i; + } + return -1; +} + extern FILE *LogFile; -#if defined(__GNUC__) && !defined(IN_IDE_PARSER) +#if defined(__GNUC__) && !defined(_WIN32) && !defined(IN_IDE_PARSER) #define AL_PRINT(T, MSG, ...) fprintf(LogFile, "AL lib: %s %s: "MSG, T, __FUNCTION__ , ## __VA_ARGS__) #else void al_print(const char *type, const char *func, const char *fmt, ...) DECL_FORMAT(printf, 3,4); @@ -875,14 +718,17 @@ extern ALuint CPUCapFlags; enum { CPU_CAP_SSE = 1<<0, CPU_CAP_SSE2 = 1<<1, - CPU_CAP_SSE4_1 = 1<<2, - CPU_CAP_NEON = 1<<3, + CPU_CAP_SSE3 = 1<<2, + CPU_CAP_SSE4_1 = 1<<3, + CPU_CAP_NEON = 1<<4, }; void FillCPUCaps(ALuint capfilter); FILE *OpenDataFile(const char *fname, const char *subdir); +vector_al_string SearchDataFiles(const char *match, const char *subdir); + /* Small hack to use a pointer-to-array type as a normal argument type. * Shouldn't be used directly. */ typedef ALfloat ALfloatBUFFERSIZE[BUFFERSIZE]; diff --git a/libs/openal-soft/OpenAL32/Include/alSource.h b/libs/openal-soft/OpenAL32/Include/alSource.h index 8d74fc54..13596161 100644 --- a/libs/openal-soft/OpenAL32/Include/alSource.h +++ b/libs/openal-soft/OpenAL32/Include/alSource.h @@ -11,10 +11,8 @@ extern "C" { #endif -extern enum Resampler DefaultResampler; - -extern const ALsizei ResamplerPadding[ResamplerMax]; -extern const ALsizei ResamplerPrePadding[ResamplerMax]; +struct ALbuffer; +struct ALsource; typedef struct ALbufferlistitem { @@ -24,11 +22,11 @@ typedef struct ALbufferlistitem { } ALbufferlistitem; -typedef struct ALactivesource { - struct ALsource *Source; +typedef struct ALvoice { + struct ALsource *volatile Source; /** Method to update mixing parameters. */ - ALvoid (*Update)(struct ALactivesource *self, const ALCcontext *context); + ALvoid (*Update)(struct ALvoice *self, const struct ALsource *source, const ALCcontext *context); /** Current target parameters used for mixing. */ ALint Step; @@ -37,9 +35,13 @@ typedef struct ALactivesource { ALuint Offset; /* Number of output samples mixed since starting. */ + alignas(16) ALfloat PrevSamples[MAX_INPUT_CHANNELS][MAX_PRE_SAMPLES]; + + BsincState SincState; + DirectParams Direct; SendParams Send[MAX_SENDS]; -} ALactivesource; +} ALvoice; typedef struct ALsource { @@ -54,9 +56,10 @@ typedef struct ALsource { volatile ALfloat RefDistance; volatile ALfloat MaxDistance; volatile ALfloat RollOffFactor; - volatile ALfloat Position[3]; - volatile ALfloat Velocity[3]; - volatile ALfloat Orientation[3]; + aluVector Position; + aluVector Velocity; + aluVector Direction; + volatile ALfloat Orientation[2][3]; volatile ALboolean HeadRelative; volatile ALboolean Looping; volatile enum DistanceModel DistanceModel; @@ -73,8 +76,6 @@ typedef struct ALsource { volatile ALfloat Radius; - enum Resampler Resampler; - /** * Last user-specified offset, and the offset type (bytes, samples, or * seconds). diff --git a/libs/openal-soft/OpenAL32/Include/alu.h b/libs/openal-soft/OpenAL32/Include/alu.h index 7727c666..a309c4ab 100644 --- a/libs/openal-soft/OpenAL32/Include/alu.h +++ b/libs/openal-soft/OpenAL32/Include/alu.h @@ -16,31 +16,112 @@ #include "hrtf.h" #include "align.h" +#include "math_defs.h" -#define F_PI (3.14159265358979323846f) -#define F_PI_2 (1.57079632679489661923f) -#define F_2PI (6.28318530717958647692f) +#define MAX_PITCH (255) -#ifndef FLT_EPSILON -#define FLT_EPSILON (1.19209290e-07f) -#endif +/* Maximum number of buffer samples before the current pos needed for resampling. */ +#define MAX_PRE_SAMPLES 12 -#define DEG2RAD(x) ((ALfloat)(x) * (F_PI/180.0f)) -#define RAD2DEG(x) ((ALfloat)(x) * (180.0f/F_PI)) - - -#define SRC_HISTORY_BITS (6) -#define SRC_HISTORY_LENGTH (1<v[0] = x; + vector->v[1] = y; + vector->v[2] = z; + vector->v[3] = w; +} + + +typedef union aluMatrixf { + alignas(16) ALfloat m[4][4]; +} aluMatrixf; + +inline void aluMatrixfSetRow(aluMatrixf *matrix, ALuint row, + ALfloat m0, ALfloat m1, ALfloat m2, ALfloat m3) +{ + matrix->m[row][0] = m0; + matrix->m[row][1] = m1; + matrix->m[row][2] = m2; + matrix->m[row][3] = m3; +} + +inline void aluMatrixfSet(aluMatrixf *matrix, ALfloat m00, ALfloat m01, ALfloat m02, ALfloat m03, + ALfloat m10, ALfloat m11, ALfloat m12, ALfloat m13, + ALfloat m20, ALfloat m21, ALfloat m22, ALfloat m23, + ALfloat m30, ALfloat m31, ALfloat m32, ALfloat m33) +{ + aluMatrixfSetRow(matrix, 0, m00, m01, m02, m03); + aluMatrixfSetRow(matrix, 1, m10, m11, m12, m13); + aluMatrixfSetRow(matrix, 2, m20, m21, m22, m23); + aluMatrixfSetRow(matrix, 3, m30, m31, m32, m33); +} + + +typedef union aluMatrixd { + alignas(16) ALdouble m[4][4]; +} aluMatrixd; + +inline void aluMatrixdSetRow(aluMatrixd *matrix, ALuint row, + ALdouble m0, ALdouble m1, ALdouble m2, ALdouble m3) +{ + matrix->m[row][0] = m0; + matrix->m[row][1] = m1; + matrix->m[row][2] = m2; + matrix->m[row][3] = m3; +} + +inline void aluMatrixdSet(aluMatrixd *matrix, ALdouble m00, ALdouble m01, ALdouble m02, ALdouble m03, + ALdouble m10, ALdouble m11, ALdouble m12, ALdouble m13, + ALdouble m20, ALdouble m21, ALdouble m22, ALdouble m23, + ALdouble m30, ALdouble m31, ALdouble m32, ALdouble m33) +{ + aluMatrixdSetRow(matrix, 0, m00, m01, m02, m03); + aluMatrixdSetRow(matrix, 1, m10, m11, m12, m13); + aluMatrixdSetRow(matrix, 2, m20, m21, m22, m23); + aluMatrixdSetRow(matrix, 3, m30, m31, m32, m33); +} + + enum ActiveFilters { AF_None = 0, AF_LowPass = 1, @@ -49,19 +130,6 @@ enum ActiveFilters { }; -typedef struct HrtfState { - alignas(16) ALfloat History[SRC_HISTORY_LENGTH]; - alignas(16) ALfloat Values[HRIR_LENGTH][2]; -} HrtfState; - -typedef struct HrtfParams { - alignas(16) ALfloat Coeffs[HRIR_LENGTH][2]; - alignas(16) ALfloat CoeffStep[HRIR_LENGTH][2]; - ALuint Delay[2]; - ALint DelayStep[2]; -} HrtfParams; - - typedef struct MixGains { ALfloat Current; ALfloat Step; @@ -71,11 +139,15 @@ typedef struct MixGains { typedef struct DirectParams { ALfloat (*OutBuffer)[BUFFERSIZE]; + ALuint OutChannels; /* If not 'moving', gain/coefficients are set directly without fading. */ ALboolean Moving; /* Stepping counter for gain/coefficient fading. */ ALuint Counter; + /* Last direction (relative to listener) and gain of a moving source. */ + aluVector LastDir; + ALfloat LastGain; struct { enum ActiveFilters ActiveType; @@ -83,17 +155,11 @@ typedef struct DirectParams { ALfilterState HighPass; } Filters[MAX_INPUT_CHANNELS]; - union { - struct { - HrtfParams Params[MAX_INPUT_CHANNELS]; - HrtfState State[MAX_INPUT_CHANNELS]; - ALuint IrSize; - ALfloat Gain; - ALfloat Dir[3]; - } Hrtf; - - MixGains Gains[MAX_INPUT_CHANNELS][MaxChannels]; - } Mix; + struct { + HrtfParams Params; + HrtfState State; + } Hrtf[MAX_INPUT_CHANNELS]; + MixGains Gains[MAX_INPUT_CHANNELS][MAX_OUTPUT_CHANNELS]; } DirectParams; typedef struct SendParams { @@ -108,14 +174,15 @@ typedef struct SendParams { ALfilterState HighPass; } Filters[MAX_INPUT_CHANNELS]; - /* Gain control, which applies to all input channels to a single (mono) + /* Gain control, which applies to each input channel to a single (mono) * output buffer. */ - MixGains Gain; + MixGains Gains[MAX_INPUT_CHANNELS]; } SendParams; -typedef const ALfloat* (*ResamplerFunc)(const ALfloat *src, ALuint frac, ALuint increment, - ALfloat *restrict dst, ALuint dstlen); +typedef const ALfloat* (*ResamplerFunc)(const BsincState *state, + const ALfloat *src, ALuint frac, ALuint increment, ALfloat *restrict dst, ALuint dstlen +); typedef void (*MixerFunc)(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], struct MixGains *Gains, @@ -131,7 +198,7 @@ typedef void (*HrtfMixerFunc)(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const A #define SPEEDOFSOUNDMETRESPERSEC (343.3f) #define AIRABSORBGAINHF (0.99426f) /* -0.05dB */ -#define FRACTIONBITS (14) +#define FRACTIONBITS (12) #define FRACTIONONE (1<UnpackAlign; + align = ATOMIC_LOAD(&albuf->UnpackAlign); if(SanitizeAlignment(srctype, &align) == AL_FALSE) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); switch(srctype) @@ -189,6 +189,8 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi case UserFmtX51: newformat = AL_FORMAT_51CHN32; break; case UserFmtX61: newformat = AL_FORMAT_61CHN32; break; case UserFmtX71: newformat = AL_FORMAT_71CHN32; break; + case UserFmtBFormat2D: newformat = AL_FORMAT_BFORMAT2D_FLOAT32; break; + case UserFmtBFormat3D: newformat = AL_FORMAT_BFORMAT3D_FLOAT32; break; } err = LoadData(albuf, freq, newformat, size/framesize*align, srcchannels, srctype, data, align, AL_TRUE); @@ -211,6 +213,8 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi case UserFmtX51: newformat = AL_FORMAT_51CHN16; break; case UserFmtX61: newformat = AL_FORMAT_61CHN16; break; case UserFmtX71: newformat = AL_FORMAT_71CHN16; break; + case UserFmtBFormat2D: newformat = AL_FORMAT_BFORMAT2D_16; break; + case UserFmtBFormat3D: newformat = AL_FORMAT_BFORMAT3D_16; break; } err = LoadData(albuf, freq, newformat, size/framesize*align, srcchannels, srctype, data, align, AL_TRUE); @@ -233,6 +237,8 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi case UserFmtX51: newformat = AL_FORMAT_51CHN16; break; case UserFmtX61: newformat = AL_FORMAT_61CHN16; break; case UserFmtX71: newformat = AL_FORMAT_71CHN16; break; + case UserFmtBFormat2D: newformat = AL_FORMAT_BFORMAT2D_16; break; + case UserFmtBFormat3D: newformat = AL_FORMAT_BFORMAT3D_16; break; } err = LoadData(albuf, freq, newformat, size/framesize*align, srcchannels, srctype, data, align, AL_TRUE); @@ -255,6 +261,8 @@ AL_API ALvoid AL_APIENTRY alBufferData(ALuint buffer, ALenum format, const ALvoi case UserFmtX51: newformat = AL_FORMAT_51CHN16; break; case UserFmtX61: newformat = AL_FORMAT_61CHN16; break; case UserFmtX71: newformat = AL_FORMAT_71CHN16; break; + case UserFmtBFormat2D: newformat = AL_FORMAT_BFORMAT2D_16; break; + case UserFmtBFormat3D: newformat = AL_FORMAT_BFORMAT3D_16; break; } err = LoadData(albuf, freq, newformat, size/framesize*align, srcchannels, srctype, data, align, AL_TRUE); @@ -291,7 +299,7 @@ AL_API ALvoid AL_APIENTRY alBufferSubDataSOFT(ALuint buffer, ALenum format, cons SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); WriteLock(&albuf->lock); - align = albuf->UnpackAlign; + align = ATOMIC_LOAD(&albuf->UnpackAlign); if(SanitizeAlignment(srctype, &align) == AL_FALSE) { WriteUnlock(&albuf->lock); @@ -368,7 +376,7 @@ AL_API void AL_APIENTRY alBufferSamplesSOFT(ALuint buffer, if(IsValidType(type) == AL_FALSE || IsValidChannels(channels) == AL_FALSE) SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); - align = albuf->UnpackAlign; + align = ATOMIC_LOAD(&albuf->UnpackAlign); if(SanitizeAlignment(type, &align) == AL_FALSE) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); if((samples%align) != 0) @@ -404,7 +412,7 @@ AL_API void AL_APIENTRY alBufferSubSamplesSOFT(ALuint buffer, SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); WriteLock(&albuf->lock); - align = albuf->UnpackAlign; + align = ATOMIC_LOAD(&albuf->UnpackAlign); if(SanitizeAlignment(type, &align) == AL_FALSE) { WriteUnlock(&albuf->lock); @@ -457,7 +465,7 @@ AL_API void AL_APIENTRY alGetBufferSamplesSOFT(ALuint buffer, SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); ReadLock(&albuf->lock); - align = albuf->PackAlign; + align = ATOMIC_LOAD(&albuf->PackAlign); if(SanitizeAlignment(type, &align) == AL_FALSE) { ReadUnlock(&albuf->lock); @@ -596,13 +604,13 @@ AL_API void AL_APIENTRY alBufferi(ALuint buffer, ALenum param, ALint value) case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: if(!(value >= 0)) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - ExchangeInt(&albuf->UnpackAlign, value); + ATOMIC_STORE(&albuf->UnpackAlign, value); break; case AL_PACK_BLOCK_ALIGNMENT_SOFT: if(!(value >= 0)) SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - ExchangeInt(&albuf->PackAlign, value); + ATOMIC_STORE(&albuf->PackAlign, value); break; default: @@ -834,11 +842,11 @@ AL_API ALvoid AL_APIENTRY alGetBufferi(ALuint buffer, ALenum param, ALint *value break; case AL_UNPACK_BLOCK_ALIGNMENT_SOFT: - *value = albuf->UnpackAlign; + *value = ATOMIC_LOAD(&albuf->UnpackAlign); break; case AL_PACK_BLOCK_ALIGNMENT_SOFT: - *value = albuf->PackAlign; + *value = ATOMIC_LOAD(&albuf->PackAlign); break; default: @@ -1045,6 +1053,8 @@ ALuint ChannelsFromUserFmt(enum UserFmtChannels chans) case UserFmtX51: return 6; case UserFmtX61: return 7; case UserFmtX71: return 8; + case UserFmtBFormat2D: return 3; + case UserFmtBFormat3D: return 4; } return 0; } @@ -1101,6 +1111,16 @@ static ALboolean DecomposeUserFormat(ALenum format, enum UserFmtChannels *chans, { AL_FORMAT_71CHN16, UserFmtX71, UserFmtShort }, { AL_FORMAT_71CHN32, UserFmtX71, UserFmtFloat }, { AL_FORMAT_71CHN_MULAW, UserFmtX71, UserFmtMulaw }, + + { AL_FORMAT_BFORMAT2D_8, UserFmtBFormat2D, UserFmtUByte }, + { AL_FORMAT_BFORMAT2D_16, UserFmtBFormat2D, UserFmtShort }, + { AL_FORMAT_BFORMAT2D_FLOAT32, UserFmtBFormat2D, UserFmtFloat }, + { AL_FORMAT_BFORMAT2D_MULAW, UserFmtBFormat2D, UserFmtMulaw }, + + { AL_FORMAT_BFORMAT3D_8, UserFmtBFormat3D, UserFmtUByte }, + { AL_FORMAT_BFORMAT3D_16, UserFmtBFormat3D, UserFmtShort }, + { AL_FORMAT_BFORMAT3D_FLOAT32, UserFmtBFormat3D, UserFmtFloat }, + { AL_FORMAT_BFORMAT3D_MULAW, UserFmtBFormat3D, UserFmtMulaw }, }; ALuint i; @@ -1138,6 +1158,8 @@ ALuint ChannelsFromFmt(enum FmtChannels chans) case FmtX51: return 6; case FmtX61: return 7; case FmtX71: return 8; + case FmtBFormat2D: return 3; + case FmtBFormat3D: return 4; } return 0; } @@ -1178,6 +1200,14 @@ static ALboolean DecomposeFormat(ALenum format, enum FmtChannels *chans, enum Fm { AL_7POINT1_8_SOFT, FmtX71, FmtByte }, { AL_7POINT1_16_SOFT, FmtX71, FmtShort }, { AL_7POINT1_32F_SOFT, FmtX71, FmtFloat }, + + { AL_FORMAT_BFORMAT2D_8, FmtBFormat2D, FmtByte }, + { AL_FORMAT_BFORMAT2D_16, FmtBFormat2D, FmtShort }, + { AL_FORMAT_BFORMAT2D_FLOAT32, FmtBFormat2D, FmtFloat }, + + { AL_FORMAT_BFORMAT3D_8, FmtBFormat3D, FmtByte }, + { AL_FORMAT_BFORMAT3D_16, FmtBFormat3D, FmtShort }, + { AL_FORMAT_BFORMAT3D_FLOAT32, FmtBFormat3D, FmtFloat }, }; ALuint i; diff --git a/libs/openal-soft/OpenAL32/alEffect.c b/libs/openal-soft/OpenAL32/alEffect.c index c9e5928f..0bfe11b9 100644 --- a/libs/openal-soft/OpenAL32/alEffect.c +++ b/libs/openal-soft/OpenAL32/alEffect.c @@ -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 */ @@ -402,13 +402,27 @@ static void InitEffectParams(ALeffect *effect, ALenum type) effect->Props.Reverb.Diffusion = AL_REVERB_DEFAULT_DIFFUSION; effect->Props.Reverb.Gain = AL_REVERB_DEFAULT_GAIN; effect->Props.Reverb.GainHF = AL_REVERB_DEFAULT_GAINHF; + effect->Props.Reverb.GainLF = 1.0f; effect->Props.Reverb.DecayTime = AL_REVERB_DEFAULT_DECAY_TIME; effect->Props.Reverb.DecayHFRatio = AL_REVERB_DEFAULT_DECAY_HFRATIO; + effect->Props.Reverb.DecayLFRatio = 1.0f; effect->Props.Reverb.ReflectionsGain = AL_REVERB_DEFAULT_REFLECTIONS_GAIN; effect->Props.Reverb.ReflectionsDelay = AL_REVERB_DEFAULT_REFLECTIONS_DELAY; + effect->Props.Reverb.ReflectionsPan[0] = 0.0f; + effect->Props.Reverb.ReflectionsPan[1] = 0.0f; + effect->Props.Reverb.ReflectionsPan[2] = 0.0f; effect->Props.Reverb.LateReverbGain = AL_REVERB_DEFAULT_LATE_REVERB_GAIN; effect->Props.Reverb.LateReverbDelay = AL_REVERB_DEFAULT_LATE_REVERB_DELAY; + effect->Props.Reverb.LateReverbPan[0] = 0.0f; + effect->Props.Reverb.LateReverbPan[1] = 0.0f; + effect->Props.Reverb.LateReverbPan[2] = 0.0f; + effect->Props.Reverb.EchoTime = 0.25f; + effect->Props.Reverb.EchoDepth = 0.0f; + effect->Props.Reverb.ModulationTime = 0.25f; + effect->Props.Reverb.ModulationDepth = 0.0f; effect->Props.Reverb.AirAbsorptionGainHF = AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF; + effect->Props.Reverb.HFReference = 5000.0f; + effect->Props.Reverb.LFReference = 250.0f; effect->Props.Reverb.RoomRolloffFactor = AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR; effect->Props.Reverb.DecayHFLimit = AL_REVERB_DEFAULT_DECAY_HFLIMIT; SET_VTABLE1(ALreverb, effect); diff --git a/libs/openal-soft/OpenAL32/alError.c b/libs/openal-soft/OpenAL32/alError.c index 9369af56..b38d8dfe 100644 --- a/libs/openal-soft/OpenAL32/alError.c +++ b/libs/openal-soft/OpenAL32/alError.c @@ -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 */ diff --git a/libs/openal-soft/OpenAL32/alExtension.c b/libs/openal-soft/OpenAL32/alExtension.c index 29f21783..609cc969 100644 --- a/libs/openal-soft/OpenAL32/alExtension.c +++ b/libs/openal-soft/OpenAL32/alExtension.c @@ -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 */ diff --git a/libs/openal-soft/OpenAL32/alFilter.c b/libs/openal-soft/OpenAL32/alFilter.c index acfae8a6..3cf82c32 100644 --- a/libs/openal-soft/OpenAL32/alFilter.c +++ b/libs/openal-soft/OpenAL32/alFilter.c @@ -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 */ @@ -32,6 +32,8 @@ extern inline struct ALfilter *LookupFilter(ALCdevice *device, ALuint id); extern inline struct ALfilter *RemoveFilter(ALCdevice *device, ALuint id); extern inline ALfloat ALfilterState_processSingle(ALfilterState *filter, ALfloat sample); +extern inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope); +extern inline ALfloat calc_rcpQ_from_bandwidth(ALfloat freq_mult, ALfloat bandwidth); static void InitFilterParams(ALfilter *filter, ALenum type); @@ -336,72 +338,72 @@ void ALfilterState_clear(ALfilterState *filter) filter->y[1] = 0.0f; } -void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat bandwidth) +void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat rcpQ) { - ALfloat alpha; - ALfloat w0; + ALfloat alpha, sqrtgain_alpha_2; + ALfloat w0, sin_w0, cos_w0; // Limit gain to -100dB gain = maxf(gain, 0.00001f); - w0 = F_2PI * freq_mult; + w0 = F_TAU * freq_mult; + sin_w0 = sinf(w0); + cos_w0 = cosf(w0); + alpha = sin_w0/2.0f * rcpQ; /* Calculate filter coefficients depending on filter type */ switch(type) { case ALfilterType_HighShelf: - alpha = sinf(w0)/2.0f*sqrtf((gain + 1.0f/gain)*(1.0f/0.75f - 1.0f) + 2.0f); - filter->b[0] = gain*((gain+1.0f) + (gain-1.0f)*cosf(w0) + 2.0f*sqrtf(gain)*alpha); - filter->b[1] = -2.0f*gain*((gain-1.0f) + (gain+1.0f)*cosf(w0) ); - filter->b[2] = gain*((gain+1.0f) + (gain-1.0f)*cosf(w0) - 2.0f*sqrtf(gain)*alpha); - filter->a[0] = (gain+1.0f) - (gain-1.0f)*cosf(w0) + 2.0f*sqrtf(gain)*alpha; - filter->a[1] = 2.0f* ((gain-1.0f) - (gain+1.0f)*cosf(w0) ); - filter->a[2] = (gain+1.0f) - (gain-1.0f)*cosf(w0) - 2.0f*sqrtf(gain)*alpha; + sqrtgain_alpha_2 = 2.0f * sqrtf(gain) * alpha; + filter->b[0] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2); + filter->b[1] = -2.0f*gain*((gain-1.0f) + (gain+1.0f)*cos_w0 ); + filter->b[2] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2); + filter->a[0] = (gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2; + filter->a[1] = 2.0f* ((gain-1.0f) - (gain+1.0f)*cos_w0 ); + filter->a[2] = (gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2; break; case ALfilterType_LowShelf: - alpha = sinf(w0)/2.0f*sqrtf((gain + 1.0f/gain)*(1.0f/0.75f - 1.0f) + 2.0f); - filter->b[0] = gain*((gain+1.0f) - (gain-1.0f)*cosf(w0) + 2.0f*sqrtf(gain)*alpha); - filter->b[1] = 2.0f*gain*((gain-1.0f) - (gain+1.0f)*cosf(w0) ); - filter->b[2] = gain*((gain+1.0f) - (gain-1.0f)*cosf(w0) - 2.0f*sqrtf(gain)*alpha); - filter->a[0] = (gain+1.0f) + (gain-1.0f)*cosf(w0) + 2.0f*sqrtf(gain)*alpha; - filter->a[1] = -2.0f* ((gain-1.0f) + (gain+1.0f)*cosf(w0) ); - filter->a[2] = (gain+1.0f) + (gain-1.0f)*cosf(w0) - 2.0f*sqrtf(gain)*alpha; + sqrtgain_alpha_2 = 2.0f * sqrtf(gain) * alpha; + filter->b[0] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2); + filter->b[1] = 2.0f*gain*((gain-1.0f) - (gain+1.0f)*cos_w0 ); + filter->b[2] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2); + filter->a[0] = (gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2; + filter->a[1] = -2.0f* ((gain-1.0f) + (gain+1.0f)*cos_w0 ); + filter->a[2] = (gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2; break; case ALfilterType_Peaking: - alpha = sinf(w0) * sinhf(logf(2.0f) / 2.0f * bandwidth * w0 / sinf(w0)); + gain = sqrtf(gain); filter->b[0] = 1.0f + alpha * gain; - filter->b[1] = -2.0f * cosf(w0); + filter->b[1] = -2.0f * cos_w0; filter->b[2] = 1.0f - alpha * gain; filter->a[0] = 1.0f + alpha / gain; - filter->a[1] = -2.0f * cosf(w0); + filter->a[1] = -2.0f * cos_w0; filter->a[2] = 1.0f - alpha / gain; break; case ALfilterType_LowPass: - alpha = sinf(w0) * sinhf(logf(2.0f) / 2.0f * bandwidth * w0 / sinf(w0)); - filter->b[0] = (1.0f - cosf(w0)) / 2.0f; - filter->b[1] = 1.0f - cosf(w0); - filter->b[2] = (1.0f - cosf(w0)) / 2.0f; + filter->b[0] = (1.0f - cos_w0) / 2.0f; + filter->b[1] = 1.0f - cos_w0; + filter->b[2] = (1.0f - cos_w0) / 2.0f; filter->a[0] = 1.0f + alpha; - filter->a[1] = -2.0f * cosf(w0); + filter->a[1] = -2.0f * cos_w0; filter->a[2] = 1.0f - alpha; break; case ALfilterType_HighPass: - alpha = sinf(w0) * sinhf(logf(2.0f) / 2.0f * bandwidth * w0 / sinf(w0)); - filter->b[0] = (1.0f + cosf(w0)) / 2.0f; - filter->b[1] = 1.0f + cosf(w0); - filter->b[2] = (1.0f + cosf(w0)) / 2.0f; - filter->a[0] = 1.0f + alpha; - filter->a[1] = -2.0f * cosf(w0); - filter->a[2] = 1.0f - alpha; + filter->b[0] = (1.0f + cos_w0) / 2.0f; + filter->b[1] = -(1.0f + cos_w0); + filter->b[2] = (1.0f + cos_w0) / 2.0f; + filter->a[0] = 1.0f + alpha; + filter->a[1] = -2.0f * cos_w0; + filter->a[2] = 1.0f - alpha; break; case ALfilterType_BandPass: - alpha = sinf(w0) * sinhf(logf(2.0f) / 2.0f * bandwidth * w0 / sinf(w0)); filter->b[0] = alpha; filter->b[1] = 0; filter->b[2] = -alpha; filter->a[0] = 1.0f + alpha; - filter->a[1] = -2.0f * cosf(w0); + filter->a[1] = -2.0f * cos_w0; filter->a[2] = 1.0f - alpha; break; } @@ -416,6 +418,24 @@ void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat g filter->process = ALfilterState_processC; } +void ALfilterState_processPassthru(ALfilterState *filter, const ALfloat *src, ALuint numsamples) +{ + if(numsamples >= 2) + { + filter->x[1] = src[numsamples-2]; + filter->x[0] = src[numsamples-1]; + filter->y[1] = src[numsamples-2]; + filter->y[0] = src[numsamples-1]; + } + else if(numsamples == 1) + { + filter->x[1] = filter->x[0]; + filter->x[0] = src[0]; + filter->y[1] = filter->y[0]; + filter->y[0] = src[0]; + } +} + static void lp_SetParami(ALfilter *UNUSED(filter), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val)) { SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } diff --git a/libs/openal-soft/OpenAL32/alListener.c b/libs/openal-soft/OpenAL32/alListener.c index 0baae82e..66865473 100644 --- a/libs/openal-soft/OpenAL32/alListener.c +++ b/libs/openal-soft/OpenAL32/alListener.c @@ -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 */ @@ -74,9 +74,7 @@ AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat val SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); LockContext(context); - context->Listener->Position[0] = value1; - context->Listener->Position[1] = value2; - context->Listener->Position[2] = value3; + aluVectorSet(&context->Listener->Position, value1, value2, value3, 1.0f); ATOMIC_STORE(&context->UpdateSources, AL_TRUE); UnlockContext(context); break; @@ -86,9 +84,7 @@ AL_API ALvoid AL_APIENTRY alListener3f(ALenum param, ALfloat value1, ALfloat val SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); LockContext(context); - context->Listener->Velocity[0] = value1; - context->Listener->Velocity[1] = value2; - context->Listener->Velocity[2] = value3; + aluVectorSet(&context->Listener->Velocity, value1, value2, value3, 0.0f); ATOMIC_STORE(&context->UpdateSources, AL_TRUE); UnlockContext(context); break; @@ -282,17 +278,17 @@ AL_API ALvoid AL_APIENTRY alGetListener3f(ALenum param, ALfloat *value1, ALfloat { case AL_POSITION: LockContext(context); - *value1 = context->Listener->Position[0]; - *value2 = context->Listener->Position[1]; - *value3 = context->Listener->Position[2]; + *value1 = context->Listener->Position.v[0]; + *value2 = context->Listener->Position.v[1]; + *value3 = context->Listener->Position.v[2]; UnlockContext(context); break; case AL_VELOCITY: LockContext(context); - *value1 = context->Listener->Velocity[0]; - *value2 = context->Listener->Velocity[1]; - *value3 = context->Listener->Velocity[2]; + *value1 = context->Listener->Velocity.v[0]; + *value2 = context->Listener->Velocity.v[1]; + *value3 = context->Listener->Velocity.v[2]; UnlockContext(context); break; @@ -383,17 +379,17 @@ AL_API void AL_APIENTRY alGetListener3i(ALenum param, ALint *value1, ALint *valu { case AL_POSITION: LockContext(context); - *value1 = (ALint)context->Listener->Position[0]; - *value2 = (ALint)context->Listener->Position[1]; - *value3 = (ALint)context->Listener->Position[2]; + *value1 = (ALint)context->Listener->Position.v[0]; + *value2 = (ALint)context->Listener->Position.v[1]; + *value3 = (ALint)context->Listener->Position.v[2]; UnlockContext(context); break; case AL_VELOCITY: LockContext(context); - *value1 = (ALint)context->Listener->Velocity[0]; - *value2 = (ALint)context->Listener->Velocity[1]; - *value3 = (ALint)context->Listener->Velocity[2]; + *value1 = (ALint)context->Listener->Velocity.v[0]; + *value2 = (ALint)context->Listener->Velocity.v[1]; + *value3 = (ALint)context->Listener->Velocity.v[2]; UnlockContext(context); break; diff --git a/libs/openal-soft/OpenAL32/alSource.c b/libs/openal-soft/OpenAL32/alSource.c index 752e2e35..0d454882 100644 --- a/libs/openal-soft/OpenAL32/alSource.c +++ b/libs/openal-soft/OpenAL32/alSource.c @@ -13,14 +13,15 @@ * * 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 */ #include "config.h" #include +#include #include #include @@ -33,328 +34,331 @@ #include "alThunk.h" #include "alAuxEffectSlot.h" +#include "backends/base.h" + #include "threads.h" -enum Resampler DefaultResampler = LinearResampler; -const ALsizei ResamplerPadding[ResamplerMax] = { - 0, /* Point */ - 1, /* Linear */ - 2, /* Cubic */ -}; -const ALsizei ResamplerPrePadding[ResamplerMax] = { - 0, /* Point */ - 0, /* Linear */ - 1, /* Cubic */ -}; - - extern inline struct ALsource *LookupSource(ALCcontext *context, ALuint id); extern inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id); static ALvoid InitSourceParams(ALsource *Source); -static ALint64 GetSourceOffset(const ALsource *Source); -static ALdouble GetSourceSecOffset(const ALsource *Source); -static ALvoid GetSourceOffsets(const ALsource *Source, ALenum name, ALdouble *offsets, ALdouble updateLen); -static ALint GetSampleOffset(ALsource *Source); +static ALint64 GetSourceSampleOffset(ALsource *Source); +static ALdouble GetSourceSecOffset(ALsource *Source); +static ALvoid GetSourceOffsets(ALsource *Source, ALenum name, ALdouble *offsets, ALdouble updateLen); +static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac); -typedef enum SrcFloatProp { - sfPitch = AL_PITCH, - sfGain = AL_GAIN, - sfMinGain = AL_MIN_GAIN, - sfMaxGain = AL_MAX_GAIN, - sfMaxDistance = AL_MAX_DISTANCE, - sfRolloffFactor = AL_ROLLOFF_FACTOR, - sfDopplerFactor = AL_DOPPLER_FACTOR, - sfConeOuterGain = AL_CONE_OUTER_GAIN, - sfSecOffset = AL_SEC_OFFSET, - sfSampleOffset = AL_SAMPLE_OFFSET, - sfByteOffset = AL_BYTE_OFFSET, - sfConeInnerAngle = AL_CONE_INNER_ANGLE, - sfConeOuterAngle = AL_CONE_OUTER_ANGLE, - sfRefDistance = AL_REFERENCE_DISTANCE, +typedef enum SourceProp { + srcPitch = AL_PITCH, + srcGain = AL_GAIN, + srcMinGain = AL_MIN_GAIN, + srcMaxGain = AL_MAX_GAIN, + srcMaxDistance = AL_MAX_DISTANCE, + srcRolloffFactor = AL_ROLLOFF_FACTOR, + srcDopplerFactor = AL_DOPPLER_FACTOR, + srcConeOuterGain = AL_CONE_OUTER_GAIN, + srcSecOffset = AL_SEC_OFFSET, + srcSampleOffset = AL_SAMPLE_OFFSET, + srcByteOffset = AL_BYTE_OFFSET, + srcConeInnerAngle = AL_CONE_INNER_ANGLE, + srcConeOuterAngle = AL_CONE_OUTER_ANGLE, + srcRefDistance = AL_REFERENCE_DISTANCE, - sfPosition = AL_POSITION, - sfVelocity = AL_VELOCITY, - sfDirection = AL_DIRECTION, + srcPosition = AL_POSITION, + srcVelocity = AL_VELOCITY, + srcDirection = AL_DIRECTION, - sfSourceRelative = AL_SOURCE_RELATIVE, - sfLooping = AL_LOOPING, - sfBuffer = AL_BUFFER, - sfSourceState = AL_SOURCE_STATE, - sfBuffersQueued = AL_BUFFERS_QUEUED, - sfBuffersProcessed = AL_BUFFERS_PROCESSED, - sfSourceType = AL_SOURCE_TYPE, + srcSourceRelative = AL_SOURCE_RELATIVE, + srcLooping = AL_LOOPING, + srcBuffer = AL_BUFFER, + srcSourceState = AL_SOURCE_STATE, + srcBuffersQueued = AL_BUFFERS_QUEUED, + srcBuffersProcessed = AL_BUFFERS_PROCESSED, + srcSourceType = AL_SOURCE_TYPE, /* ALC_EXT_EFX */ - sfConeOuterGainHF = AL_CONE_OUTER_GAINHF, - sfAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR, - sfRoomRolloffFactor = AL_ROOM_ROLLOFF_FACTOR, - sfDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO, - sfAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO, - sfAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO, + srcConeOuterGainHF = AL_CONE_OUTER_GAINHF, + srcAirAbsorptionFactor = AL_AIR_ABSORPTION_FACTOR, + srcRoomRolloffFactor = AL_ROOM_ROLLOFF_FACTOR, + srcDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO, + srcAuxSendFilterGainAuto = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO, + srcAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO, + srcDirectFilter = AL_DIRECT_FILTER, + srcAuxSendFilter = AL_AUXILIARY_SEND_FILTER, /* AL_SOFT_direct_channels */ - sfDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT, + srcDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT, /* AL_EXT_source_distance_model */ - sfDistanceModel = AL_DISTANCE_MODEL, + srcDistanceModel = AL_DISTANCE_MODEL, - sfSecLength = AL_SEC_LENGTH_SOFT, + srcByteLengthSOFT = AL_BYTE_LENGTH_SOFT, + srcSampleLengthSOFT = AL_SAMPLE_LENGTH_SOFT, + srcSecLengthSOFT = AL_SEC_LENGTH_SOFT, /* AL_SOFT_buffer_sub_data / AL_SOFT_buffer_samples */ - sfSampleRWOffsetsSOFT = AL_SAMPLE_RW_OFFSETS_SOFT, - sfByteRWOffsetsSOFT = AL_BYTE_RW_OFFSETS_SOFT, + srcSampleRWOffsetsSOFT = AL_SAMPLE_RW_OFFSETS_SOFT, + srcByteRWOffsetsSOFT = AL_BYTE_RW_OFFSETS_SOFT, /* AL_SOFT_source_latency */ - sfSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT, -} SrcFloatProp; + srcSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT, + srcSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT, -typedef enum SrcIntProp { - siMaxDistance = AL_MAX_DISTANCE, - siRolloffFactor = AL_ROLLOFF_FACTOR, - siRefDistance = AL_REFERENCE_DISTANCE, - siSourceRelative = AL_SOURCE_RELATIVE, - siConeInnerAngle = AL_CONE_INNER_ANGLE, - siConeOuterAngle = AL_CONE_OUTER_ANGLE, - siLooping = AL_LOOPING, - siBuffer = AL_BUFFER, - siSourceState = AL_SOURCE_STATE, - siBuffersQueued = AL_BUFFERS_QUEUED, - siBuffersProcessed = AL_BUFFERS_PROCESSED, - siSourceType = AL_SOURCE_TYPE, - siSecOffset = AL_SEC_OFFSET, - siSampleOffset = AL_SAMPLE_OFFSET, - siByteOffset = AL_BYTE_OFFSET, - siDopplerFactor = AL_DOPPLER_FACTOR, - siPosition = AL_POSITION, - siVelocity = AL_VELOCITY, - siDirection = AL_DIRECTION, + /* AL_EXT_BFORMAT */ + srcOrientation = AL_ORIENTATION, +} SourceProp; - /* ALC_EXT_EFX */ - siDirectFilterGainHFAuto = AL_DIRECT_FILTER_GAINHF_AUTO, - siAuxSendFilterGainAutio = AL_AUXILIARY_SEND_FILTER_GAIN_AUTO, - siAuxSendFilterGainHFAuto = AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO, - siDirectFilter = AL_DIRECT_FILTER, - siAuxSendFilter = AL_AUXILIARY_SEND_FILTER, +static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values); +static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values); +static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values); - /* AL_SOFT_direct_channels */ - siDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT, - - /* AL_EXT_source_distance_model */ - siDistanceModel = AL_DISTANCE_MODEL, - - siByteLength = AL_BYTE_LENGTH_SOFT, - siSampleLength = AL_SAMPLE_LENGTH_SOFT, - - /* AL_SOFT_buffer_sub_data / AL_SOFT_buffer_samples */ - siSampleRWOffsetsSOFT = AL_SAMPLE_RW_OFFSETS_SOFT, - siByteRWOffsetsSOFT = AL_BYTE_RW_OFFSETS_SOFT, - - /* AL_SOFT_source_latency */ - siSampleOffsetLatencySOFT = AL_SAMPLE_OFFSET_LATENCY_SOFT, -} SrcIntProp; - -static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, const ALfloat *values); -static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint *values); -static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint64SOFT *values); - -static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, ALdouble *values); -static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint *values); -static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint64 *values); +static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values); +static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values); +static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values); static ALint FloatValsByProp(ALenum prop) { - if(prop != (ALenum)((SrcFloatProp)prop)) + if(prop != (ALenum)((SourceProp)prop)) return 0; - switch((SrcFloatProp)prop) + switch((SourceProp)prop) { - case sfPitch: - case sfGain: - case sfMinGain: - case sfMaxGain: - case sfMaxDistance: - case sfRolloffFactor: - case sfDopplerFactor: - case sfConeOuterGain: - case sfSecOffset: - case sfSampleOffset: - case sfByteOffset: - case sfConeInnerAngle: - case sfConeOuterAngle: - case sfRefDistance: - case sfConeOuterGainHF: - case sfAirAbsorptionFactor: - case sfRoomRolloffFactor: - case sfDirectFilterGainHFAuto: - case sfAuxSendFilterGainAuto: - case sfAuxSendFilterGainHFAuto: - case sfDirectChannelsSOFT: - case sfDistanceModel: - case sfSourceRelative: - case sfLooping: - case sfBuffer: - case sfSourceState: - case sfBuffersQueued: - case sfBuffersProcessed: - case sfSourceType: - case sfSecLength: + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_MAX_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_DOPPLER_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_REFERENCE_DISTANCE: + case AL_CONE_OUTER_GAINHF: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_DISTANCE_MODEL: + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_SOURCE_STATE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SOURCE_TYPE: + case AL_BYTE_LENGTH_SOFT: + case AL_SAMPLE_LENGTH_SOFT: + case AL_SEC_LENGTH_SOFT: return 1; - case sfSampleRWOffsetsSOFT: - case sfByteRWOffsetsSOFT: + case AL_SAMPLE_RW_OFFSETS_SOFT: + case AL_BYTE_RW_OFFSETS_SOFT: return 2; - case sfPosition: - case sfVelocity: - case sfDirection: + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: return 3; - case sfSecOffsetLatencySOFT: + case AL_ORIENTATION: + return 6; + + case AL_SEC_OFFSET_LATENCY_SOFT: break; /* Double only */ + + case AL_BUFFER: + case AL_DIRECT_FILTER: + case AL_AUXILIARY_SEND_FILTER: + break; /* i/i64 only */ + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + break; /* i64 only */ } return 0; } static ALint DoubleValsByProp(ALenum prop) { - if(prop != (ALenum)((SrcFloatProp)prop)) + if(prop != (ALenum)((SourceProp)prop)) return 0; - switch((SrcFloatProp)prop) + switch((SourceProp)prop) { - case sfPitch: - case sfGain: - case sfMinGain: - case sfMaxGain: - case sfMaxDistance: - case sfRolloffFactor: - case sfDopplerFactor: - case sfConeOuterGain: - case sfSecOffset: - case sfSampleOffset: - case sfByteOffset: - case sfConeInnerAngle: - case sfConeOuterAngle: - case sfRefDistance: - case sfConeOuterGainHF: - case sfAirAbsorptionFactor: - case sfRoomRolloffFactor: - case sfDirectFilterGainHFAuto: - case sfAuxSendFilterGainAuto: - case sfAuxSendFilterGainHFAuto: - case sfDirectChannelsSOFT: - case sfDistanceModel: - case sfSourceRelative: - case sfLooping: - case sfBuffer: - case sfSourceState: - case sfBuffersQueued: - case sfBuffersProcessed: - case sfSourceType: - case sfSecLength: + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_MAX_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_DOPPLER_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_REFERENCE_DISTANCE: + case AL_CONE_OUTER_GAINHF: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_DISTANCE_MODEL: + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_SOURCE_STATE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SOURCE_TYPE: + case AL_BYTE_LENGTH_SOFT: + case AL_SAMPLE_LENGTH_SOFT: + case AL_SEC_LENGTH_SOFT: return 1; - case sfSampleRWOffsetsSOFT: - case sfByteRWOffsetsSOFT: - case sfSecOffsetLatencySOFT: + case AL_SAMPLE_RW_OFFSETS_SOFT: + case AL_BYTE_RW_OFFSETS_SOFT: + case AL_SEC_OFFSET_LATENCY_SOFT: return 2; - case sfPosition: - case sfVelocity: - case sfDirection: + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: return 3; + + case AL_ORIENTATION: + return 6; + + case AL_BUFFER: + case AL_DIRECT_FILTER: + case AL_AUXILIARY_SEND_FILTER: + break; /* i/i64 only */ + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + break; /* i64 only */ } return 0; } static ALint IntValsByProp(ALenum prop) { - if(prop != (ALenum)((SrcIntProp)prop)) + if(prop != (ALenum)((SourceProp)prop)) return 0; - switch((SrcIntProp)prop) + switch((SourceProp)prop) { - case siMaxDistance: - case siRolloffFactor: - case siRefDistance: - case siSourceRelative: - case siConeInnerAngle: - case siConeOuterAngle: - case siLooping: - case siBuffer: - case siSourceState: - case siBuffersQueued: - case siBuffersProcessed: - case siSourceType: - case siSecOffset: - case siSampleOffset: - case siByteOffset: - case siDopplerFactor: - case siDirectFilterGainHFAuto: - case siAuxSendFilterGainAutio: - case siAuxSendFilterGainHFAuto: - case siDirectFilter: - case siDirectChannelsSOFT: - case siDistanceModel: - case siByteLength: - case siSampleLength: + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_MAX_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_DOPPLER_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_REFERENCE_DISTANCE: + case AL_CONE_OUTER_GAINHF: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_DISTANCE_MODEL: + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_BUFFER: + case AL_SOURCE_STATE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SOURCE_TYPE: + case AL_DIRECT_FILTER: + case AL_BYTE_LENGTH_SOFT: + case AL_SAMPLE_LENGTH_SOFT: + case AL_SEC_LENGTH_SOFT: return 1; - case siSampleRWOffsetsSOFT: - case siByteRWOffsetsSOFT: + case AL_SAMPLE_RW_OFFSETS_SOFT: + case AL_BYTE_RW_OFFSETS_SOFT: return 2; - case siPosition: - case siVelocity: - case siDirection: - case siAuxSendFilter: + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + case AL_AUXILIARY_SEND_FILTER: return 3; - case siSampleOffsetLatencySOFT: + case AL_ORIENTATION: + return 6; + + case AL_SAMPLE_OFFSET_LATENCY_SOFT: break; /* i64 only */ + case AL_SEC_OFFSET_LATENCY_SOFT: + break; /* Double only */ } return 0; } static ALint Int64ValsByProp(ALenum prop) { - if(prop != (ALenum)((SrcIntProp)prop)) + if(prop != (ALenum)((SourceProp)prop)) return 0; - switch((SrcIntProp)prop) + switch((SourceProp)prop) { - case siMaxDistance: - case siRolloffFactor: - case siRefDistance: - case siSourceRelative: - case siConeInnerAngle: - case siConeOuterAngle: - case siLooping: - case siBuffer: - case siSourceState: - case siBuffersQueued: - case siBuffersProcessed: - case siSourceType: - case siSecOffset: - case siSampleOffset: - case siByteOffset: - case siDopplerFactor: - case siDirectFilterGainHFAuto: - case siAuxSendFilterGainAutio: - case siAuxSendFilterGainHFAuto: - case siDirectFilter: - case siDirectChannelsSOFT: - case siDistanceModel: - case siByteLength: - case siSampleLength: + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_MAX_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_DOPPLER_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_SEC_OFFSET: + case AL_SAMPLE_OFFSET: + case AL_BYTE_OFFSET: + case AL_CONE_INNER_ANGLE: + case AL_CONE_OUTER_ANGLE: + case AL_REFERENCE_DISTANCE: + case AL_CONE_OUTER_GAINHF: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: + case AL_DISTANCE_MODEL: + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_BUFFER: + case AL_SOURCE_STATE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SOURCE_TYPE: + case AL_DIRECT_FILTER: + case AL_BYTE_LENGTH_SOFT: + case AL_SAMPLE_LENGTH_SOFT: + case AL_SEC_LENGTH_SOFT: return 1; - case siSampleRWOffsetsSOFT: - case siByteRWOffsetsSOFT: - case siSampleOffsetLatencySOFT: + case AL_SAMPLE_RW_OFFSETS_SOFT: + case AL_BYTE_RW_OFFSETS_SOFT: + case AL_SAMPLE_OFFSET_LATENCY_SOFT: return 2; - case siPosition: - case siVelocity: - case siDirection: - case siAuxSendFilter: + case AL_POSITION: + case AL_VELOCITY: + case AL_DIRECTION: + case AL_AUXILIARY_SEND_FILTER: return 3; + + case AL_ORIENTATION: + return 6; + + case AL_SEC_OFFSET_LATENCY_SOFT: + break; /* Double only */ } return 0; } @@ -365,12 +369,21 @@ static ALint Int64ValsByProp(ALenum prop) SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); \ } while(0) -static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, const ALfloat *values) +static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALfloat *values) { ALint ival; switch(prop) { + case AL_BYTE_RW_OFFSETS_SOFT: + case AL_SAMPLE_RW_OFFSETS_SOFT: + case AL_BYTE_LENGTH_SOFT: + case AL_SAMPLE_LENGTH_SOFT: + case AL_SEC_LENGTH_SOFT: + case AL_SEC_OFFSET_LATENCY_SOFT: + /* Query only */ + SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE); + case AL_PITCH: CHECKVAL(*values >= 0.0f); @@ -481,29 +494,24 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SrcFloatProp if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) && !Context->DeferUpdates) { + WriteLock(&Source->queue_lock); if(ApplyOffset(Source) == AL_FALSE) { + WriteUnlock(&Source->queue_lock); UnlockContext(Context); SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); } + WriteUnlock(&Source->queue_lock); } UnlockContext(Context); return AL_TRUE; - case sfSecLength: - case AL_SEC_OFFSET_LATENCY_SOFT: - /* Query only */ - SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE); - - case AL_POSITION: CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2])); LockContext(Context); - Source->Position[0] = values[0]; - Source->Position[1] = values[1]; - Source->Position[2] = values[2]; + aluVectorSet(&Source->Position, values[0], values[1], values[2], 1.0f); UnlockContext(Context); ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); return AL_TRUE; @@ -512,9 +520,7 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SrcFloatProp CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2])); LockContext(Context); - Source->Velocity[0] = values[0]; - Source->Velocity[1] = values[1]; - Source->Velocity[2] = values[2]; + aluVectorSet(&Source->Velocity, values[0], values[1], values[2], 0.0f); UnlockContext(Context); ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); return AL_TRUE; @@ -523,43 +529,56 @@ static ALboolean SetSourcefv(ALsource *Source, ALCcontext *Context, SrcFloatProp CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2])); LockContext(Context); - Source->Orientation[0] = values[0]; - Source->Orientation[1] = values[1]; - Source->Orientation[2] = values[2]; + aluVectorSet(&Source->Direction, values[0], values[1], values[2], 0.0f); + UnlockContext(Context); + ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); + return AL_TRUE; + + case AL_ORIENTATION: + CHECKVAL(isfinite(values[0]) && isfinite(values[1]) && isfinite(values[2]) && + isfinite(values[3]) && isfinite(values[4]) && isfinite(values[5])); + + LockContext(Context); + Source->Orientation[0][0] = values[0]; + Source->Orientation[0][1] = values[1]; + Source->Orientation[0][2] = values[2]; + Source->Orientation[1][0] = values[3]; + Source->Orientation[1][1] = values[4]; + Source->Orientation[1][2] = values[5]; UnlockContext(Context); ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); return AL_TRUE; - case sfSampleRWOffsetsSOFT: - case sfByteRWOffsetsSOFT: - SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE); - - - case sfSourceRelative: - case sfLooping: - case sfSourceState: - case sfSourceType: - case sfDistanceModel: - case sfDirectFilterGainHFAuto: - case sfAuxSendFilterGainAuto: - case sfAuxSendFilterGainHFAuto: - case sfDirectChannelsSOFT: + case AL_SOURCE_RELATIVE: + case AL_LOOPING: + case AL_SOURCE_STATE: + case AL_SOURCE_TYPE: + case AL_DISTANCE_MODEL: + case AL_DIRECT_FILTER_GAINHF_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: + case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: + case AL_DIRECT_CHANNELS_SOFT: ival = (ALint)values[0]; - return SetSourceiv(Source, Context, (SrcIntProp)prop, &ival); + return SetSourceiv(Source, Context, prop, &ival); - case sfBuffer: - case sfBuffersQueued: - case sfBuffersProcessed: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: ival = (ALint)((ALuint)values[0]); - return SetSourceiv(Source, Context, (SrcIntProp)prop, &ival); + return SetSourceiv(Source, Context, prop, &ival); + + case AL_BUFFER: + case AL_DIRECT_FILTER: + case AL_AUXILIARY_SEND_FILTER: + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + break; } ERR("Unexpected property: 0x%04x\n", prop); SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE); } -static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint *values) +static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint *values) { ALCdevice *device = Context->Device; ALbuffer *buffer = NULL; @@ -567,10 +586,22 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp p ALeffectslot *slot = NULL; ALbufferlistitem *oldlist; ALbufferlistitem *newlist; - ALfloat fvals[3]; + ALfloat fvals[6]; switch(prop) { + case AL_SOURCE_STATE: + case AL_SOURCE_TYPE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SAMPLE_RW_OFFSETS_SOFT: + case AL_BYTE_RW_OFFSETS_SOFT: + case AL_BYTE_LENGTH_SOFT: + case AL_SAMPLE_LENGTH_SOFT: + case AL_SEC_LENGTH_SOFT: + /* Query only */ + SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE); + case AL_SOURCE_RELATIVE: CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); @@ -633,13 +664,6 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp p } return AL_TRUE; - case siSourceState: - case siSourceType: - case siBuffersQueued: - case siBuffersProcessed: - /* Query only */ - SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE); - case AL_SEC_OFFSET: case AL_SAMPLE_OFFSET: case AL_BYTE_OFFSET: @@ -652,24 +676,18 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp p if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) && !Context->DeferUpdates) { + WriteLock(&Source->queue_lock); if(ApplyOffset(Source) == AL_FALSE) { + WriteUnlock(&Source->queue_lock); UnlockContext(Context); SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); } + WriteUnlock(&Source->queue_lock); } UnlockContext(Context); return AL_TRUE; - - case siByteLength: - case siSampleLength: - case siSampleRWOffsetsSOFT: - case siByteRWOffsetsSOFT: - /* Query only */ - SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE); - - case AL_DIRECT_FILTER: CHECKVAL(*values == 0 || (filter=LookupFilter(device, *values)) != NULL); @@ -774,15 +792,25 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp p return AL_TRUE; - case AL_MAX_DISTANCE: - case AL_ROLLOFF_FACTOR: + /* 1x float */ case AL_CONE_INNER_ANGLE: case AL_CONE_OUTER_ANGLE: + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: case AL_REFERENCE_DISTANCE: - case siDopplerFactor: + case AL_ROLLOFF_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_MAX_DISTANCE: + case AL_DOPPLER_FACTOR: + case AL_CONE_OUTER_GAINHF: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: fvals[0] = (ALfloat)*values; return SetSourcefv(Source, Context, (int)prop, fvals); + /* 3x float */ case AL_POSITION: case AL_VELOCITY: case AL_DIRECTION: @@ -791,8 +819,18 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp p fvals[2] = (ALfloat)values[2]; return SetSourcefv(Source, Context, (int)prop, fvals); - case siSampleOffsetLatencySOFT: - /* i64 only */ + /* 6x float */ + case AL_ORIENTATION: + fvals[0] = (ALfloat)values[0]; + fvals[1] = (ALfloat)values[1]; + fvals[2] = (ALfloat)values[2]; + fvals[3] = (ALfloat)values[3]; + fvals[4] = (ALfloat)values[4]; + fvals[5] = (ALfloat)values[5]; + return SetSourcefv(Source, Context, (int)prop, fvals); + + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_SEC_OFFSET_LATENCY_SOFT: break; } @@ -800,16 +838,23 @@ static ALboolean SetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp p SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE); } -static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint64SOFT *values) +static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, const ALint64SOFT *values) { - ALfloat fvals[3]; + ALfloat fvals[6]; ALint ivals[3]; switch(prop) { - case siSampleRWOffsetsSOFT: - case siByteRWOffsetsSOFT: - case siSampleOffsetLatencySOFT: + case AL_SOURCE_TYPE: + case AL_BUFFERS_QUEUED: + case AL_BUFFERS_PROCESSED: + case AL_SOURCE_STATE: + case AL_SAMPLE_RW_OFFSETS_SOFT: + case AL_BYTE_RW_OFFSETS_SOFT: + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + case AL_BYTE_LENGTH_SOFT: + case AL_SAMPLE_LENGTH_SOFT: + case AL_SEC_LENGTH_SOFT: /* Query only */ SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE); @@ -817,14 +862,9 @@ static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp /* 1x int */ case AL_SOURCE_RELATIVE: case AL_LOOPING: - case AL_SOURCE_STATE: - case AL_BYTE_OFFSET: + case AL_SEC_OFFSET: case AL_SAMPLE_OFFSET: - case siByteLength: - case siSampleLength: - case siSourceType: - case siBuffersQueued: - case siBuffersProcessed: + case AL_BYTE_OFFSET: case AL_DIRECT_FILTER_GAINHF_AUTO: case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: @@ -855,13 +895,20 @@ static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp return SetSourceiv(Source, Context, (int)prop, ivals); /* 1x float */ - case AL_MAX_DISTANCE: - case AL_ROLLOFF_FACTOR: case AL_CONE_INNER_ANGLE: case AL_CONE_OUTER_ANGLE: + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: case AL_REFERENCE_DISTANCE: - case AL_SEC_OFFSET: - case siDopplerFactor: + case AL_ROLLOFF_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_MAX_DISTANCE: + case AL_DOPPLER_FACTOR: + case AL_CONE_OUTER_GAINHF: + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: fvals[0] = (ALfloat)*values; return SetSourcefv(Source, Context, (int)prop, fvals); @@ -873,6 +920,19 @@ static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp fvals[1] = (ALfloat)values[1]; fvals[2] = (ALfloat)values[2]; return SetSourcefv(Source, Context, (int)prop, fvals); + + /* 6x float */ + case AL_ORIENTATION: + fvals[0] = (ALfloat)values[0]; + fvals[1] = (ALfloat)values[1]; + fvals[2] = (ALfloat)values[2]; + fvals[3] = (ALfloat)values[3]; + fvals[4] = (ALfloat)values[4]; + fvals[5] = (ALfloat)values[5]; + return SetSourcefv(Source, Context, (int)prop, fvals); + + case AL_SEC_OFFSET_LATENCY_SOFT: + break; } ERR("Unexpected property: 0x%04x\n", prop); @@ -882,8 +942,9 @@ static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp #undef CHECKVAL -static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, ALdouble *values) +static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALdouble *values) { + ALCdevice *device = Context->Device; ALbufferlistitem *BufferList; ALdouble offsets[2]; ALdouble updateLen; @@ -936,9 +997,7 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SrcFloatProp case AL_SAMPLE_OFFSET: case AL_BYTE_OFFSET: LockContext(Context); - ReadLock(&Source->queue_lock); GetSourceOffsets(Source, prop, offsets, 0.0); - ReadUnlock(&Source->queue_lock); UnlockContext(Context); *values = offsets[0]; return AL_TRUE; @@ -959,7 +1018,7 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SrcFloatProp *values = Source->DopplerFactor; return AL_TRUE; - case sfSecLength: + case AL_SEC_LENGTH_SOFT: ReadLock(&Source->queue_lock); if(!(BufferList=ATOMIC_LOAD(&Source->queue))) *values = 0; @@ -983,51 +1042,57 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SrcFloatProp case AL_SAMPLE_RW_OFFSETS_SOFT: case AL_BYTE_RW_OFFSETS_SOFT: LockContext(Context); - ReadLock(&Source->queue_lock); - updateLen = (ALdouble)Context->Device->UpdateSize / - Context->Device->Frequency; + updateLen = (ALdouble)device->UpdateSize / device->Frequency; GetSourceOffsets(Source, prop, values, updateLen); - ReadUnlock(&Source->queue_lock); UnlockContext(Context); return AL_TRUE; case AL_SEC_OFFSET_LATENCY_SOFT: LockContext(Context); - ReadLock(&Source->queue_lock); values[0] = GetSourceSecOffset(Source); - ReadUnlock(&Source->queue_lock); - values[1] = (ALdouble)ALCdevice_GetLatency(Context->Device) / + values[1] = (ALdouble)(V0(device->Backend,getLatency)()) / 1000000000.0; UnlockContext(Context); return AL_TRUE; case AL_POSITION: LockContext(Context); - values[0] = Source->Position[0]; - values[1] = Source->Position[1]; - values[2] = Source->Position[2]; + values[0] = Source->Position.v[0]; + values[1] = Source->Position.v[1]; + values[2] = Source->Position.v[2]; UnlockContext(Context); return AL_TRUE; case AL_VELOCITY: LockContext(Context); - values[0] = Source->Velocity[0]; - values[1] = Source->Velocity[1]; - values[2] = Source->Velocity[2]; + values[0] = Source->Velocity.v[0]; + values[1] = Source->Velocity.v[1]; + values[2] = Source->Velocity.v[2]; UnlockContext(Context); return AL_TRUE; case AL_DIRECTION: LockContext(Context); - values[0] = Source->Orientation[0]; - values[1] = Source->Orientation[1]; - values[2] = Source->Orientation[2]; + values[0] = Source->Direction.v[0]; + values[1] = Source->Direction.v[1]; + values[2] = Source->Direction.v[2]; UnlockContext(Context); return AL_TRUE; + case AL_ORIENTATION: + LockContext(Context); + values[0] = Source->Orientation[0][0]; + values[1] = Source->Orientation[0][1]; + values[2] = Source->Orientation[0][2]; + values[3] = Source->Orientation[1][0]; + values[4] = Source->Orientation[1][1]; + values[5] = Source->Orientation[1][2]; + UnlockContext(Context); + return AL_TRUE; + + /* 1x int */ case AL_SOURCE_RELATIVE: case AL_LOOPING: - case AL_BUFFER: case AL_SOURCE_STATE: case AL_BUFFERS_QUEUED: case AL_BUFFERS_PROCESSED: @@ -1036,20 +1101,28 @@ static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SrcFloatProp case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: case AL_DIRECT_CHANNELS_SOFT: + case AL_BYTE_LENGTH_SOFT: + case AL_SAMPLE_LENGTH_SOFT: case AL_DISTANCE_MODEL: if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE) *values = (ALdouble)ivals[0]; return err; + + case AL_BUFFER: + case AL_DIRECT_FILTER: + case AL_AUXILIARY_SEND_FILTER: + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + break; } ERR("Unexpected property: 0x%04x\n", prop); SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE); } -static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint *values) +static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint *values) { ALbufferlistitem *BufferList; - ALdouble dvals[3]; + ALdouble dvals[6]; ALboolean err; switch(prop) @@ -1074,7 +1147,7 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp p *values = Source->state; return AL_TRUE; - case siByteLength: + case AL_BYTE_LENGTH_SOFT: ReadLock(&Source->queue_lock); if(!(BufferList=ATOMIC_LOAD(&Source->queue))) *values = 0; @@ -1113,7 +1186,7 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp p ReadUnlock(&Source->queue_lock); return AL_TRUE; - case siSampleLength: + case AL_SAMPLE_LENGTH_SOFT: ReadLock(&Source->queue_lock); if(!(BufferList=ATOMIC_LOAD(&Source->queue))) *values = 0; @@ -1191,32 +1264,44 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp p *values = Source->DistanceModel; return AL_TRUE; - case AL_MAX_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_REFERENCE_DISTANCE: + /* 1x float/double */ case AL_CONE_INNER_ANGLE: case AL_CONE_OUTER_ANGLE: + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_REFERENCE_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_MAX_DISTANCE: case AL_SEC_OFFSET: case AL_SAMPLE_OFFSET: case AL_BYTE_OFFSET: case AL_DOPPLER_FACTOR: - if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE) + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_CONE_OUTER_GAINHF: + case AL_SEC_LENGTH_SOFT: + if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) *values = (ALint)dvals[0]; return err; + /* 2x float/double */ case AL_SAMPLE_RW_OFFSETS_SOFT: case AL_BYTE_RW_OFFSETS_SOFT: - if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE) + if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) { values[0] = (ALint)dvals[0]; values[1] = (ALint)dvals[1]; } return err; + /* 3x float/double */ case AL_POSITION: case AL_VELOCITY: case AL_DIRECTION: - if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE) + if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) { values[0] = (ALint)dvals[0]; values[1] = (ALint)dvals[1]; @@ -1224,23 +1309,37 @@ static ALboolean GetSourceiv(ALsource *Source, ALCcontext *Context, SrcIntProp p } return err; - case siSampleOffsetLatencySOFT: - /* i64 only */ - break; + /* 6x float/double */ + case AL_ORIENTATION: + if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) + { + values[0] = (ALint)dvals[0]; + values[1] = (ALint)dvals[1]; + values[2] = (ALint)dvals[2]; + values[3] = (ALint)dvals[3]; + values[4] = (ALint)dvals[4]; + values[5] = (ALint)dvals[5]; + } + return err; - case siDirectFilter: - case siAuxSendFilter: - /* ??? */ - break; + case AL_SAMPLE_OFFSET_LATENCY_SOFT: + break; /* i64 only */ + case AL_SEC_OFFSET_LATENCY_SOFT: + break; /* Double only */ + + case AL_DIRECT_FILTER: + case AL_AUXILIARY_SEND_FILTER: + break; /* ??? */ } ERR("Unexpected property: 0x%04x\n", prop); SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE); } -static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, ALint64 *values) +static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SourceProp prop, ALint64 *values) { - ALdouble dvals[3]; + ALCdevice *device = Context->Device; + ALdouble dvals[6]; ALint ivals[3]; ALboolean err; @@ -1248,39 +1347,49 @@ static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp { case AL_SAMPLE_OFFSET_LATENCY_SOFT: LockContext(Context); - ReadLock(&Source->queue_lock); - values[0] = GetSourceOffset(Source); - ReadUnlock(&Source->queue_lock); - values[1] = ALCdevice_GetLatency(Context->Device); + values[0] = GetSourceSampleOffset(Source); + values[1] = V0(device->Backend,getLatency)(); UnlockContext(Context); return AL_TRUE; - case AL_MAX_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_REFERENCE_DISTANCE: + /* 1x float/double */ case AL_CONE_INNER_ANGLE: case AL_CONE_OUTER_ANGLE: + case AL_PITCH: + case AL_GAIN: + case AL_MIN_GAIN: + case AL_MAX_GAIN: + case AL_REFERENCE_DISTANCE: + case AL_ROLLOFF_FACTOR: + case AL_CONE_OUTER_GAIN: + case AL_MAX_DISTANCE: case AL_SEC_OFFSET: case AL_SAMPLE_OFFSET: case AL_BYTE_OFFSET: case AL_DOPPLER_FACTOR: - if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE) + case AL_AIR_ABSORPTION_FACTOR: + case AL_ROOM_ROLLOFF_FACTOR: + case AL_CONE_OUTER_GAINHF: + case AL_SEC_LENGTH_SOFT: + if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) *values = (ALint64)dvals[0]; return err; + /* 2x float/double */ case AL_SAMPLE_RW_OFFSETS_SOFT: case AL_BYTE_RW_OFFSETS_SOFT: - if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE) + if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) { values[0] = (ALint64)dvals[0]; values[1] = (ALint64)dvals[1]; } return err; + /* 3x float/double */ case AL_POSITION: case AL_VELOCITY: case AL_DIRECTION: - if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE) + if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) { values[0] = (ALint64)dvals[0]; values[1] = (ALint64)dvals[1]; @@ -1288,37 +1397,56 @@ static ALboolean GetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp } return err; + /* 6x float/double */ + case AL_ORIENTATION: + if((err=GetSourcedv(Source, Context, prop, dvals)) != AL_FALSE) + { + values[0] = (ALint64)dvals[0]; + values[1] = (ALint64)dvals[1]; + values[2] = (ALint64)dvals[2]; + values[3] = (ALint64)dvals[3]; + values[4] = (ALint64)dvals[4]; + values[5] = (ALint64)dvals[5]; + } + return err; + + /* 1x int */ case AL_SOURCE_RELATIVE: case AL_LOOPING: case AL_SOURCE_STATE: case AL_BUFFERS_QUEUED: case AL_BUFFERS_PROCESSED: - case siByteLength: - case siSampleLength: + case AL_BYTE_LENGTH_SOFT: + case AL_SAMPLE_LENGTH_SOFT: case AL_SOURCE_TYPE: case AL_DIRECT_FILTER_GAINHF_AUTO: case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: case AL_DIRECT_CHANNELS_SOFT: case AL_DISTANCE_MODEL: - if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE) + if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) *values = ivals[0]; return err; - case siBuffer: - case siDirectFilter: - if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE) + /* 1x uint */ + case AL_BUFFER: + case AL_DIRECT_FILTER: + if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) *values = (ALuint)ivals[0]; return err; - case siAuxSendFilter: - if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE) + /* 3x uint */ + case AL_AUXILIARY_SEND_FILTER: + if((err=GetSourceiv(Source, Context, prop, ivals)) != AL_FALSE) { values[0] = (ALuint)ivals[0]; values[1] = (ALuint)ivals[1]; values[2] = (ALuint)ivals[2]; } return err; + + case AL_SEC_OFFSET_LATENCY_SOFT: + break; /* Double only */ } ERR("Unexpected property: 0x%04x\n", prop); @@ -1389,26 +1517,21 @@ AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources) } for(i = 0;i < n;i++) { - ALactivesource **srclist, **srclistend; + ALvoice *voice, *voice_end; if((Source=RemoveSource(context, sources[i])) == NULL) continue; FreeThunkEntry(Source->id); LockContext(context); - srclist = context->ActiveSources; - srclistend = srclist + context->ActiveSourceCount; - while(srclist != srclistend) + voice = context->Voices; + voice_end = voice + context->VoiceCount; + while(voice != voice_end) { - if((*srclist)->Source == Source) - { - ALactivesource *temp = *(--srclistend); - *srclistend = *srclist; - *srclist = temp; - --(context->ActiveSourceCount); + ALsource *old = Source; + if(COMPARE_EXCHANGE(&voice->Source, &old, NULL)) break; - } - srclist++; + voice++; } UnlockContext(context); @@ -1569,11 +1692,11 @@ AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdo alSetError(Context, AL_INVALID_NAME); else if(!values) alSetError(Context, AL_INVALID_VALUE); - else if(!((count=DoubleValsByProp(param)) > 0 && count <= 3)) + else if(!((count=DoubleValsByProp(param)) > 0 && count <= 6)) alSetError(Context, AL_INVALID_ENUM); else { - ALfloat fvals[3]; + ALfloat fvals[6]; ALint i; for(i = 0;i < count;i++) @@ -1772,11 +1895,11 @@ AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *va alSetError(Context, AL_INVALID_NAME); else if(!values) alSetError(Context, AL_INVALID_VALUE); - else if(!((count=FloatValsByProp(param)) > 0 && count <= 3)) + else if(!((count=FloatValsByProp(param)) > 0 && count <= 6)) alSetError(Context, AL_INVALID_ENUM); else { - ALdouble dvals[3]; + ALdouble dvals[6]; if(GetSourcedv(Source, Context, param, dvals)) { ALint i; @@ -2020,25 +2143,23 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) } LockContext(context); - while(n > context->MaxActiveSources-context->ActiveSourceCount) + while(n > context->MaxVoices-context->VoiceCount) { - ALactivesource **temp = NULL; + ALvoice *temp = NULL; ALsizei newcount; - newcount = context->MaxActiveSources << 1; + newcount = context->MaxVoices << 1; if(newcount > 0) - temp = realloc(context->ActiveSources, - newcount * sizeof(context->ActiveSources[0])); + temp = realloc(context->Voices, newcount * sizeof(context->Voices[0])); if(!temp) { UnlockContext(context); SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done); } - for(i = context->MaxActiveSources;i < newcount;i++) - temp[i] = NULL; + memset(&temp[context->MaxVoices], 0, (newcount-context->MaxVoices) * sizeof(temp[0])); - context->ActiveSources = temp; - context->MaxActiveSources = newcount; + context->Voices = temp; + context->MaxVoices = newcount; } for(i = 0;i < n;i++) @@ -2385,15 +2506,15 @@ static ALvoid InitSourceParams(ALsource *Source) Source->InnerAngle = 360.0f; Source->OuterAngle = 360.0f; Source->Pitch = 1.0f; - Source->Position[0] = 0.0f; - Source->Position[1] = 0.0f; - Source->Position[2] = 0.0f; - Source->Orientation[0] = 0.0f; - Source->Orientation[1] = 0.0f; - Source->Orientation[2] = 0.0f; - Source->Velocity[0] = 0.0f; - Source->Velocity[1] = 0.0f; - Source->Velocity[2] = 0.0f; + aluVectorSet(&Source->Position, 0.0f, 0.0f, 0.0f, 1.0f); + aluVectorSet(&Source->Velocity, 0.0f, 0.0f, 0.0f, 0.0f); + aluVectorSet(&Source->Direction, 0.0f, 0.0f, 0.0f, 0.0f); + Source->Orientation[0][0] = 0.0f; + Source->Orientation[0][1] = 0.0f; + Source->Orientation[0][2] = -1.0f; + Source->Orientation[1][0] = 0.0f; + Source->Orientation[1][1] = 1.0f; + Source->Orientation[1][2] = 0.0f; Source->RefDistance = 1.0f; Source->MaxDistance = FLT_MAX; Source->RollOffFactor = 1.0f; @@ -2416,8 +2537,6 @@ static ALvoid InitSourceParams(ALsource *Source) Source->DistanceModel = DefaultDistanceModel; - Source->Resampler = DefaultResampler; - Source->state = AL_INITIAL; Source->new_state = AL_NONE; Source->SourceType = AL_UNDETERMINED; @@ -2450,13 +2569,14 @@ static ALvoid InitSourceParams(ALsource *Source) */ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) { - ReadLock(&Source->queue_lock); + WriteLock(&Source->queue_lock); if(state == AL_PLAYING) { ALCdevice *device = Context->Device; ALbufferlistitem *BufferList; - ALactivesource *src = NULL; - ALsizei j, k; + ALboolean discontinuity; + ALvoice *voice = NULL; + ALsizei i; /* Check that there is a queue containing at least one valid, non zero * length Buffer. */ @@ -2475,67 +2595,77 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) Source->position = 0; Source->position_fraction = 0; ATOMIC_STORE(&Source->current_buffer, BufferList); + discontinuity = AL_TRUE; } else + { Source->state = AL_PLAYING; + discontinuity = AL_FALSE; + } // Check if an Offset has been set if(Source->Offset >= 0.0) + { ApplyOffset(Source); + /* discontinuity = AL_TRUE;??? */ + } /* If there's nothing to play, or device is disconnected, go right to * stopped */ if(!BufferList || !device->Connected) goto do_stop; - for(j = 0;j < Context->ActiveSourceCount;j++) + /* Make sure this source isn't already active, while looking for an + * unused active source slot to put it in. */ + for(i = 0;i < Context->VoiceCount;i++) { - if(Context->ActiveSources[j]->Source == Source) + ALsource *old = Source; + if(COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, NULL)) { - src = Context->ActiveSources[j]; + if(voice == NULL) + { + voice = &Context->Voices[i]; + voice->Source = Source; + } break; } + old = NULL; + if(voice == NULL && COMPARE_EXCHANGE(&Context->Voices[i].Source, &old, Source)) + voice = &Context->Voices[i]; } - if(src == NULL) + if(voice == NULL) { - src = Context->ActiveSources[Context->ActiveSourceCount]; - if(src == NULL) - { - src = al_malloc(16, sizeof(src[0])); - Context->ActiveSources[Context->ActiveSourceCount] = src; - } - memset(src, 0, sizeof(*src)); - Context->ActiveSourceCount++; - - src->Source = Source; + voice = &Context->Voices[Context->VoiceCount++]; + voice->Source = Source; } - else - { - ALuint i; - src->Direct.Moving = AL_FALSE; - src->Direct.Counter = 0; - for(j = 0;j < MAX_INPUT_CHANNELS;j++) + /* Clear previous samples if playback is discontinuous. */ + if(discontinuity) + memset(voice->PrevSamples, 0, sizeof(voice->PrevSamples)); + + voice->Direct.Moving = AL_FALSE; + voice->Direct.Counter = 0; + for(i = 0;i < MAX_INPUT_CHANNELS;i++) + { + ALsizei j; + for(j = 0;j < HRTF_HISTORY_LENGTH;j++) + voice->Direct.Hrtf[i].State.History[j] = 0.0f; + for(j = 0;j < HRIR_LENGTH;j++) { - for(k = 0;k < SRC_HISTORY_LENGTH;k++) - src->Direct.Mix.Hrtf.State[j].History[k] = 0.0f; - for(k = 0;k < HRIR_LENGTH;k++) - { - src->Direct.Mix.Hrtf.State[j].Values[k][0] = 0.0f; - src->Direct.Mix.Hrtf.State[j].Values[k][1] = 0.0f; - } - } - for(i = 0;i < device->NumAuxSends;i++) - { - src->Send[i].Counter = 0; - src->Send[i].Moving = AL_FALSE; + voice->Direct.Hrtf[i].State.Values[j][0] = 0.0f; + voice->Direct.Hrtf[i].State.Values[j][1] = 0.0f; } } + for(i = 0;i < (ALsizei)device->NumAuxSends;i++) + { + voice->Send[i].Moving = AL_FALSE; + voice->Send[i].Counter = 0; + } if(BufferList->buffer->FmtChannels == FmtMono) - src->Update = CalcSourceParams; + voice->Update = CalcSourceParams; else - src->Update = CalcNonAttnSourceParams; + voice->Update = CalcNonAttnSourceParams; ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); } @@ -2565,23 +2695,27 @@ ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) } Source->Offset = -1.0; } - ReadUnlock(&Source->queue_lock); + WriteUnlock(&Source->queue_lock); } -/* GetSourceOffset +/* GetSourceSampleOffset * * Gets the current read offset for the given Source, in 32.32 fixed-point * samples. The offset is relative to the start of the queue (not the start of * the current buffer). */ -static ALint64 GetSourceOffset(const ALsource *Source) +ALint64 GetSourceSampleOffset(ALsource *Source) { const ALbufferlistitem *BufferList; const ALbufferlistitem *Current; ALuint64 readPos; + ReadLock(&Source->queue_lock); if(Source->state != AL_PLAYING && Source->state != AL_PAUSED) + { + ReadUnlock(&Source->queue_lock); return 0; + } /* NOTE: This is the offset into the *current* buffer, so add the length of * any played buffers */ @@ -2596,6 +2730,7 @@ static ALint64 GetSourceOffset(const ALsource *Source) BufferList = BufferList->next; } + ReadUnlock(&Source->queue_lock); return (ALint64)minu64(readPos, U64(0x7fffffffffffffff)); } @@ -2604,15 +2739,19 @@ static ALint64 GetSourceOffset(const ALsource *Source) * Gets the current read offset for the given Source, in seconds. The offset is * relative to the start of the queue (not the start of the current buffer). */ -static ALdouble GetSourceSecOffset(const ALsource *Source) +static ALdouble GetSourceSecOffset(ALsource *Source) { const ALbufferlistitem *BufferList; const ALbufferlistitem *Current; const ALbuffer *Buffer = NULL; ALuint64 readPos; + ReadLock(&Source->queue_lock); if(Source->state != AL_PLAYING && Source->state != AL_PAUSED) + { + ReadUnlock(&Source->queue_lock); return 0.0; + } /* NOTE: This is the offset into the *current* buffer, so add the length of * any played buffers */ @@ -2638,6 +2777,7 @@ static ALdouble GetSourceSecOffset(const ALsource *Source) } assert(Buffer != NULL); + ReadUnlock(&Source->queue_lock); return (ALdouble)readPos / (ALdouble)FRACTIONONE / (ALdouble)Buffer->Frequency; } @@ -2647,19 +2787,21 @@ static ALdouble GetSourceSecOffset(const ALsource *Source) * appropriate format (Bytes, Samples or Seconds). The offsets are relative to * the start of the queue (not the start of the current buffer). */ -static ALvoid GetSourceOffsets(const ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen) +static ALvoid GetSourceOffsets(ALsource *Source, ALenum name, ALdouble *offset, ALdouble updateLen) { const ALbufferlistitem *BufferList; const ALbufferlistitem *Current; const ALbuffer *Buffer = NULL; ALboolean readFin = AL_FALSE; - ALuint readPos, writePos; + ALuint readPos, readPosFrac, writePos; ALuint totalBufferLen; + ReadLock(&Source->queue_lock); if(Source->state != AL_PLAYING && Source->state != AL_PAUSED) { offset[0] = 0.0; offset[1] = 0.0; + ReadUnlock(&Source->queue_lock); return; } @@ -2670,6 +2812,7 @@ static ALvoid GetSourceOffsets(const ALsource *Source, ALenum name, ALdouble *of * any played buffers */ totalBufferLen = 0; readPos = Source->position; + readPosFrac = Source->position_fraction; BufferList = ATOMIC_LOAD(&Source->queue); Current = ATOMIC_LOAD(&Source->current_buffer); while(BufferList != NULL) @@ -2687,7 +2830,7 @@ static ALvoid GetSourceOffsets(const ALsource *Source, ALenum name, ALdouble *of assert(Buffer != NULL); if(Source->state == AL_PLAYING) - writePos = readPos + (ALuint)(updateLen*Buffer->Frequency); + writePos = readPos + (ALuint)(updateLen*Buffer->Frequency + 0.5f); else writePos = readPos; @@ -2700,7 +2843,7 @@ static ALvoid GetSourceOffsets(const ALsource *Source, ALenum name, ALdouble *of { /* Wrap positions back to 0 */ if(readPos >= totalBufferLen) - readPos = 0; + readPos = readPosFrac = 0; if(writePos >= totalBufferLen) writePos = 0; } @@ -2708,13 +2851,13 @@ static ALvoid GetSourceOffsets(const ALsource *Source, ALenum name, ALdouble *of switch(name) { case AL_SEC_OFFSET: - offset[0] = (ALdouble)readPos / Buffer->Frequency; - offset[1] = (ALdouble)writePos / Buffer->Frequency; + offset[0] = (readPos + (ALdouble)readPosFrac/FRACTIONONE)/Buffer->Frequency; + offset[1] = (ALdouble)writePos/Buffer->Frequency; break; case AL_SAMPLE_OFFSET: case AL_SAMPLE_RW_OFFSETS_SOFT: - offset[0] = (ALdouble)readPos; + offset[0] = readPos + (ALdouble)readPosFrac/FRACTIONONE; offset[1] = (ALdouble)writePos; break; @@ -2762,6 +2905,8 @@ static ALvoid GetSourceOffsets(const ALsource *Source, ALenum name, ALdouble *of } break; } + + ReadUnlock(&Source->queue_lock); } @@ -2774,12 +2919,11 @@ ALboolean ApplyOffset(ALsource *Source) { ALbufferlistitem *BufferList; const ALbuffer *Buffer; - ALint bufferLen, totalBufferLen; - ALint offset; + ALuint bufferLen, totalBufferLen; + ALuint offset=0, frac=0; /* Get sample frame offset */ - offset = GetSampleOffset(Source); - if(offset == -1) + if(!GetSampleOffset(Source, &offset, &frac)) return AL_FALSE; totalBufferLen = 0; @@ -2795,7 +2939,7 @@ ALboolean ApplyOffset(ALsource *Source) ATOMIC_STORE(&Source->current_buffer, BufferList); Source->position = offset - totalBufferLen; - Source->position_fraction = 0; + Source->position_fraction = frac; return AL_TRUE; } @@ -2811,15 +2955,15 @@ ALboolean ApplyOffset(ALsource *Source) /* GetSampleOffset * - * Returns the sample offset into the Source's queue (from the Sample, Byte or - * Second offset supplied by the application). This takes into account the fact - * that the buffer format may have been modifed since. + * Retrieves the sample offset into the Source's queue (from the Sample, Byte + * or Second offset supplied by the application). This takes into account the + * fact that the buffer format may have been modifed since. */ -static ALint GetSampleOffset(ALsource *Source) +static ALboolean GetSampleOffset(ALsource *Source, ALuint *offset, ALuint *frac) { const ALbuffer *Buffer = NULL; const ALbufferlistitem *BufferList; - ALint Offset = -1; + ALdouble dbloff, dblfrac; /* Find the first valid Buffer in the Queue */ BufferList = ATOMIC_LOAD(&Source->queue); @@ -2832,45 +2976,49 @@ static ALint GetSampleOffset(ALsource *Source) } BufferList = BufferList->next; } - if(!Buffer) { Source->Offset = -1.0; - return -1; + return AL_FALSE; } switch(Source->OffsetType) { case AL_BYTE_OFFSET: /* Determine the ByteOffset (and ensure it is block aligned) */ - Offset = (ALint)Source->Offset; + *offset = (ALuint)Source->Offset; if(Buffer->OriginalType == UserFmtIMA4) { ALsizei align = (Buffer->OriginalAlign-1)/2 + 4; - Offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels); - Offset *= Buffer->OriginalAlign; + *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels); + *offset *= Buffer->OriginalAlign; } else if(Buffer->OriginalType == UserFmtMSADPCM) { ALsizei align = (Buffer->OriginalAlign-2)/2 + 7; - Offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels); - Offset *= Buffer->OriginalAlign; + *offset /= align * ChannelsFromUserFmt(Buffer->OriginalChannels); + *offset *= Buffer->OriginalAlign; } else - Offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType); + *offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType); + *frac = 0; break; case AL_SAMPLE_OFFSET: - Offset = (ALint)Source->Offset; + dblfrac = modf(Source->Offset, &dbloff); + *offset = (ALuint)mind(dbloff, UINT_MAX); + *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0); break; case AL_SEC_OFFSET: - Offset = (ALint)(Source->Offset * Buffer->Frequency); + dblfrac = modf(Source->Offset*Buffer->Frequency, &dbloff); + *offset = (ALuint)mind(dbloff, UINT_MAX); + *frac = (ALuint)mind(dblfrac*FRACTIONONE, FRACTIONONE-1.0); break; } Source->Offset = -1.0; - return Offset; + return AL_TRUE; } diff --git a/libs/openal-soft/OpenAL32/alState.c b/libs/openal-soft/OpenAL32/alState.c index d48c268b..dca41363 100644 --- a/libs/openal-soft/OpenAL32/alState.c +++ b/libs/openal-soft/OpenAL32/alState.c @@ -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 */ @@ -28,9 +28,8 @@ #include "alError.h" #include "alSource.h" #include "alAuxEffectSlot.h" -#include "alMidi.h" -#include "midi/base.h" +#include "backends/base.h" static const ALchar alVendor[] = "OpenAL Community"; @@ -159,7 +158,6 @@ done: AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname) { - ALCdevice *device; ALCcontext *context; ALdouble value = 0.0; @@ -188,16 +186,6 @@ AL_API ALdouble AL_APIENTRY alGetDouble(ALenum pname) value = (ALdouble)context->DeferUpdates; break; - case AL_MIDI_GAIN_SOFT: - device = context->Device; - value = (ALdouble)MidiSynth_getGain(device->Synth); - break; - - case AL_MIDI_STATE_SOFT: - device = context->Device; - value = (ALdouble)MidiSynth_getState(device->Synth); - break; - default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } @@ -210,7 +198,6 @@ done: AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname) { - ALCdevice *device; ALCcontext *context; ALfloat value = 0.0f; @@ -239,16 +226,6 @@ AL_API ALfloat AL_APIENTRY alGetFloat(ALenum pname) value = (ALfloat)context->DeferUpdates; break; - case AL_MIDI_GAIN_SOFT: - device = context->Device; - value = MidiSynth_getGain(device->Synth); - break; - - case AL_MIDI_STATE_SOFT: - device = context->Device; - value = (ALfloat)MidiSynth_getState(device->Synth); - break; - default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } @@ -262,8 +239,6 @@ done: AL_API ALint AL_APIENTRY alGetInteger(ALenum pname) { ALCcontext *context; - ALCdevice *device; - MidiSynth *synth; ALint value = 0; context = GetContextRef(); @@ -291,17 +266,6 @@ AL_API ALint AL_APIENTRY alGetInteger(ALenum pname) value = (ALint)context->DeferUpdates; break; - case AL_SOUNDFONTS_SIZE_SOFT: - device = context->Device; - synth = device->Synth; - value = synth->NumSoundfonts; - break; - - case AL_MIDI_STATE_SOFT: - device = context->Device; - value = MidiSynth_getState(device->Synth); - break; - default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } @@ -315,8 +279,6 @@ done: AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname) { ALCcontext *context; - ALCdevice *device; - MidiSynth *synth; ALint64SOFT value = 0; context = GetContextRef(); @@ -344,24 +306,6 @@ AL_API ALint64SOFT AL_APIENTRY alGetInteger64SOFT(ALenum pname) value = (ALint64SOFT)context->DeferUpdates; break; - case AL_MIDI_CLOCK_SOFT: - device = context->Device; - ALCdevice_Lock(device); - value = MidiSynth_getTime(device->Synth); - ALCdevice_Unlock(device); - break; - - case AL_SOUNDFONTS_SIZE_SOFT: - device = context->Device; - synth = device->Synth; - value = (ALint64SOFT)synth->NumSoundfonts; - break; - - case AL_MIDI_STATE_SOFT: - device = context->Device; - value = (ALint64SOFT)MidiSynth_getState(device->Synth); - break; - default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } @@ -418,8 +362,6 @@ AL_API ALvoid AL_APIENTRY alGetDoublev(ALenum pname, ALdouble *values) case AL_DISTANCE_MODEL: case AL_SPEED_OF_SOUND: case AL_DEFERRED_UPDATES_SOFT: - case AL_MIDI_GAIN_SOFT: - case AL_MIDI_STATE_SOFT: values[0] = alGetDouble(pname); return; } @@ -453,8 +395,6 @@ AL_API ALvoid AL_APIENTRY alGetFloatv(ALenum pname, ALfloat *values) case AL_DISTANCE_MODEL: case AL_SPEED_OF_SOUND: case AL_DEFERRED_UPDATES_SOFT: - case AL_MIDI_GAIN_SOFT: - case AL_MIDI_STATE_SOFT: values[0] = alGetFloat(pname); return; } @@ -478,9 +418,6 @@ done: AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values) { ALCcontext *context; - ALCdevice *device; - MidiSynth *synth; - ALsizei i; if(values) { @@ -491,8 +428,6 @@ AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values) case AL_DISTANCE_MODEL: case AL_SPEED_OF_SOUND: case AL_DEFERRED_UPDATES_SOFT: - case AL_SOUNDFONTS_SIZE_SOFT: - case AL_MIDI_STATE_SOFT: values[0] = alGetInteger(pname); return; } @@ -503,18 +438,6 @@ AL_API ALvoid AL_APIENTRY alGetIntegerv(ALenum pname, ALint *values) switch(pname) { - case AL_SOUNDFONTS_SOFT: - device = context->Device; - synth = device->Synth; - if(synth->NumSoundfonts > 0) - { - if(!(values)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - for(i = 0;i < synth->NumSoundfonts;i++) - values[i] = synth->Soundfonts[i]->id; - } - break; - default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } @@ -526,9 +449,6 @@ done: AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values) { ALCcontext *context; - ALCdevice *device; - MidiSynth *synth; - ALsizei i; if(values) { @@ -539,9 +459,6 @@ AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values) case AL_DISTANCE_MODEL: case AL_SPEED_OF_SOUND: case AL_DEFERRED_UPDATES_SOFT: - case AL_MIDI_CLOCK_SOFT: - case AL_SOUNDFONTS_SIZE_SOFT: - case AL_MIDI_STATE_SOFT: values[0] = alGetInteger64SOFT(pname); return; } @@ -552,18 +469,6 @@ AL_API void AL_APIENTRY alGetInteger64vSOFT(ALenum pname, ALint64SOFT *values) switch(pname) { - case AL_SOUNDFONTS_SOFT: - device = context->Device; - synth = device->Synth; - if(synth->NumSoundfonts > 0) - { - if(!(values)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - for(i = 0;i < synth->NumSoundfonts;i++) - values[i] = (ALint64SOFT)synth->Soundfonts[i]->id; - } - break; - default: SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); } @@ -712,54 +617,7 @@ AL_API ALvoid AL_APIENTRY alDeferUpdatesSOFT(void) context = GetContextRef(); if(!context) return; - if(!context->DeferUpdates) - { - ALboolean UpdateSources; - ALactivesource **src, **src_end; - ALeffectslot **slot, **slot_end; - FPUCtl oldMode; - - SetMixerFPUMode(&oldMode); - - LockContext(context); - context->DeferUpdates = AL_TRUE; - - /* Make sure all pending updates are performed */ - UpdateSources = ATOMIC_EXCHANGE(ALenum, &context->UpdateSources, AL_FALSE); - - src = context->ActiveSources; - src_end = src + context->ActiveSourceCount; - while(src != src_end) - { - ALsource *source = (*src)->Source; - - if(source->state != AL_PLAYING && source->state != AL_PAUSED) - { - ALactivesource *temp = *(--src_end); - *src_end = *src; - *src = temp; - --(context->ActiveSourceCount); - continue; - } - - if(ATOMIC_EXCHANGE(ALenum, &source->NeedsUpdate, AL_FALSE) || UpdateSources) - (*src)->Update(*src, context); - - src++; - } - - slot = VECTOR_ITER_BEGIN(context->ActiveAuxSlots); - slot_end = VECTOR_ITER_END(context->ActiveAuxSlots); - while(slot != slot_end) - { - if(ATOMIC_EXCHANGE(ALenum, &(*slot)->NeedsUpdate, AL_FALSE)) - V((*slot)->EffectState,update)(context->Device, *slot); - slot++; - } - - UnlockContext(context); - RestoreFPUMode(&oldMode); - } + ALCcontext_DeferUpdates(context); ALCcontext_DecRef(context); } @@ -771,32 +629,7 @@ AL_API ALvoid AL_APIENTRY alProcessUpdatesSOFT(void) context = GetContextRef(); if(!context) return; - if(ExchangeInt(&context->DeferUpdates, AL_FALSE)) - { - ALsizei pos; - - LockContext(context); - 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) - { - ReadLock(&Source->queue_lock); - ApplyOffset(Source); - ReadUnlock(&Source->queue_lock); - } - - new_state = ExchangeInt(&Source->new_state, AL_NONE); - if(new_state) - SetSourceState(Source, context, new_state); - } - UnlockUIntMapRead(&context->SourceMap); - UnlockContext(context); - } + ALCcontext_ProcessUpdates(context); ALCcontext_DecRef(context); } diff --git a/libs/openal-soft/OpenAL32/alThunk.c b/libs/openal-soft/OpenAL32/alThunk.c index c4b3b92b..0cebad42 100644 --- a/libs/openal-soft/OpenAL32/alThunk.c +++ b/libs/openal-soft/OpenAL32/alThunk.c @@ -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 */ @@ -26,33 +26,33 @@ #include "alThunk.h" -static ALenum *ThunkArray; -static ALuint ThunkArraySize; -static RWLock ThunkLock; +static ATOMIC(ALenum) *ThunkArray; +static ALuint ThunkArraySize; +static RWLock ThunkLock; void ThunkInit(void) { RWLockInit(&ThunkLock); ThunkArraySize = 1; - ThunkArray = calloc(1, ThunkArraySize * sizeof(*ThunkArray)); + ThunkArray = al_calloc(16, ThunkArraySize * sizeof(*ThunkArray)); } void ThunkExit(void) { - free(ThunkArray); + al_free(ThunkArray); ThunkArray = NULL; ThunkArraySize = 0; } ALenum NewThunkEntry(ALuint *index) { - ALenum *NewList; + void *NewList; ALuint i; ReadLock(&ThunkLock); for(i = 0;i < ThunkArraySize;i++) { - if(ExchangeInt(&ThunkArray[i], AL_TRUE) == AL_FALSE) + if(ATOMIC_EXCHANGE(ALenum, &ThunkArray[i], AL_TRUE) == AL_FALSE) { ReadUnlock(&ThunkLock); *index = i+1; @@ -62,18 +62,32 @@ ALenum NewThunkEntry(ALuint *index) ReadUnlock(&ThunkLock); WriteLock(&ThunkLock); - NewList = realloc(ThunkArray, ThunkArraySize*2 * sizeof(*ThunkArray)); + /* Double-check that there's still no free entries, in case another + * invocation just came through and increased the size of the array. + */ + for(;i < ThunkArraySize;i++) + { + if(ATOMIC_EXCHANGE(ALenum, &ThunkArray[i], AL_TRUE) == AL_FALSE) + { + WriteUnlock(&ThunkLock); + *index = i+1; + return AL_NO_ERROR; + } + } + + NewList = al_calloc(16, ThunkArraySize*2 * sizeof(*ThunkArray)); if(!NewList) { WriteUnlock(&ThunkLock); ERR("Realloc failed to increase to %u entries!\n", ThunkArraySize*2); return AL_OUT_OF_MEMORY; } - memset(&NewList[ThunkArraySize], 0, ThunkArraySize*sizeof(*ThunkArray)); - ThunkArraySize *= 2; + memcpy(NewList, ThunkArray, ThunkArraySize*sizeof(*ThunkArray)); + al_free(ThunkArray); ThunkArray = NewList; + ThunkArraySize *= 2; - ThunkArray[i] = AL_TRUE; + ATOMIC_STORE(&ThunkArray[i], AL_TRUE); WriteUnlock(&ThunkLock); *index = i+1; @@ -84,6 +98,6 @@ void FreeThunkEntry(ALuint index) { ReadLock(&ThunkLock); if(index > 0 && index <= ThunkArraySize) - ExchangeInt(&ThunkArray[index-1], AL_FALSE); + ATOMIC_STORE(&ThunkArray[index-1], AL_FALSE); ReadUnlock(&ThunkLock); } diff --git a/libs/openal-soft/README b/libs/openal-soft/README index ebca8f91..a0178ae5 100644 --- a/libs/openal-soft/README +++ b/libs/openal-soft/README @@ -45,9 +45,11 @@ Special thanks go to: Creative Labs for the original source code this is based off of. Christopher Fitzgerald for the current reverb effect implementation, and -helping with the low-pass filter. +helping with the low-pass and HRTF filters. -Christian Borss for the 3D panning code the current implementation is heavilly -based on. +Christian Borss for the 3D panning code previous versions used as a base. -Ben Davis for the idea behind the current click-removal code. +Ben Davis for the idea behind a previous version of the click-removal code. + +Richard Furse for helping with my understanding of Ambisonics that is used by +the various parts of the library. diff --git a/libs/openal-soft/XCompile.txt b/libs/openal-soft/XCompile.txt index 035f1e21..32706bc1 100644 --- a/libs/openal-soft/XCompile.txt +++ b/libs/openal-soft/XCompile.txt @@ -1,7 +1,6 @@ -# Cross-compiling requires CMake 2.6 or newer. To use it from build/, call it -# like this: -# cmake .. -DCMAKE_TOOLCHAIN_FILE=../XCompile.txt -DHOST=i686-pc-mingw32 -# Where 'i686-pc-mingw32' is the host prefix for your cross-compiler. If you +# Cross-compiling requires CMake 2.6 or newer. Example: +# cmake .. -DCMAKE_TOOLCHAIN_FILE=../XCompile.txt -DHOST=i686-w64-mingw32 +# Where 'i686-w64-mingw32' is the host prefix for your cross-compiler. If you # already have a toolchain file setup, you may use that instead of this file. # the name of the target operating system @@ -10,12 +9,13 @@ SET(CMAKE_SYSTEM_NAME Windows) # which compilers to use for C and C++ SET(CMAKE_C_COMPILER "${HOST}-gcc") SET(CMAKE_CXX_COMPILER "${HOST}-g++") +SET(CMAKE_RC_COMPILER "${HOST}-windres") # here is the target environment located SET(CMAKE_FIND_ROOT_PATH "/usr/${HOST}") # here is where stuff gets installed to -SET(CMAKE_INSTALL_PREFIX "${CMAKE_FIND_ROOT_PATH}/usr" CACHE STRING "Install path prefix, prepended onto install directories." FORCE) +SET(CMAKE_INSTALL_PREFIX "${CMAKE_FIND_ROOT_PATH}" CACHE STRING "Install path prefix, prepended onto install directories." FORCE) # adjust the default behaviour of the FIND_XXX() commands: # search headers and libraries in the target environment, search @@ -28,3 +28,10 @@ set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) # .pc files (as there seems to be no way to force using ${HOST}-pkg-config) set(ENV{PKG_CONFIG_LIBDIR} "${CMAKE_INSTALL_PREFIX}/lib/pkgconfig") set(ENV{PKG_CONFIG_PATH} "") + +# Qt4 tools +SET(QT_QMAKE_EXECUTABLE ${HOST}-qmake) +SET(QT_MOC_EXECUTABLE ${HOST}-moc) +SET(QT_RCC_EXECUTABLE ${HOST}-rcc) +SET(QT_UIC_EXECUTABLE ${HOST}-uic) +SET(QT_LRELEASE_EXECUTABLE ${HOST}-lrelease) diff --git a/libs/openal-soft/alsoftrc.sample b/libs/openal-soft/alsoftrc.sample index 2e6dd92a..eccc88b5 100644 --- a/libs/openal-soft/alsoftrc.sample +++ b/libs/openal-soft/alsoftrc.sample @@ -8,12 +8,18 @@ # specifying "$HOME/file.ext" would typically result in something like # "/home/user/file.ext". To specify an actual "$" character, use "$$". # +# Device-specific values may be specified by including the device name in the +# block name, with "general" replaced by the device name. That is, general +# options for the device "Name of Device" would be in the [Name of Device] +# block, while ALSA options would be in the [alsa/Name of Device] block. +# Options marked as "(global)" are not influenced by the device. +# # The system-wide settings can be put in /etc/openal/alsoft.conf and user- # specific override settings in $HOME/.alsoftrc. # For Windows, these settings should go into $AppData\alsoft.ini # -# Option and block names are case-insenstive. The supplied values are only -# hints and may not be honored (though generally it'll try to get as close as +# Option and block names are case-senstive. The supplied values are only hints +# and may not be honored (though generally it'll try to get as close as # possible). Note: options that are left unset may default to app- or system- # specified values. These are the current available settings: @@ -22,18 +28,27 @@ ## [general] -## disable-cpu-exts: +## disable-cpu-exts: (global) # Disables use of specialized methods that use specific CPU intrinsics. # Certain methods may utilize CPU extensions for improved performance, and # this option is useful for preventing some or all of those methods from being -# used. The available extensions are: sse, sse2, sse4.1, and neon. Specifying -# 'all' disables use of all such specialized methods. +# used. The available extensions are: sse, sse2, sse3, sse4.1, and neon. +# Specifying 'all' disables use of all such specialized methods. #disable-cpu-exts = +## drivers: (global) +# Sets the backend driver list order, comma-seperated. Unknown backends and +# duplicated names are ignored. Unlisted backends won't be considered for use +# unless the list is ended with a comma (e.g. 'oss,' will try OSS first before +# other backends, while 'oss' will try OSS only). Backends prepended with - +# won't be considered for use (e.g. '-oss,' will try all available backends +# except OSS). An empty list means to try all backends. +#drivers = + ## channels: # Sets the output channel configuration. If left unspecified, one will try to # be detected from the system, and defaulting to stereo. The available values -# are: mono, stereo, quad, surround51, surround61, surround71 +# are: mono, stereo, quad, surround51, surround51rear, surround61, surround71 #channels = ## sample-type: @@ -48,14 +63,40 @@ # float32 - 32-bit float #sample-type = float32 -## hrtf: -# Enables HRTF filters. These filters provide for better sound spatialization -# while using headphones. The default filter will only work when output is -# 44100hz stereo. While HRTF is active, the cf_level option is disabled. -# Default is disabled since stereo speaker output quality may suffer. -#hrtf = false +## frequency: +# Sets the output frequency. If left unspecified it will try to detect a +# default from the system, otherwise it will default to 44100. +#frequency = -## hrtf_tables +## period_size: +# Sets the update period size, in frames. This is the number of frames needed +# for each mixing update. Acceptable values range between 64 and 8192. +#period_size = 1024 + +## periods: +# Sets the number of update periods. Higher values create a larger mix ahead, +# which helps protect against skips when the CPU is under load, but increases +# the delay between a sound getting mixed and being heard. Acceptable values +# range between 2 and 16. +#periods = 4 + +## stereo-mode: +# Specifies if stereo output is treated as being headphones or speakers. With +# headphones, HRTF or crossfeed filters may be used for better audio quality. +# Valid settings are auto, speakers, and headphones. +#stereo-mode = auto + +## hrtf: +# Controls HRTF processing. These filters provide better spatialization of +# sounds while using headphones, but do require a bit more CPU power. The +# default filters will only work with 44100hz or 48000hz stereo output. While +# HRTF is used, the cf_level option is ignored. Setting this to auto (default) +# will allow HRTF to be used when headphones are detected or the app requests +# it, while setting true or false will forcefully enable or disable HRTF +# respectively. +#hrtf = auto + +## hrtf_tables: # Specifies a comma-separated list of files containing HRTF data sets. The # format of the files are described in hrtf.txt. The filenames may contain # these markers, which will be replaced as needed: @@ -84,28 +125,18 @@ # stereo modes. #cf_level = 0 -## wide-stereo: -# Specifies that stereo sources are given a width of about 120 degrees on each -# channel, centering on -90 (left) and +90 (right), as opposed to being points -# placed at -30 (left) and +30 (right). This can be useful for surround-sound -# to give stereo sources a more encompassing sound. Note that the sound's -# overall volume will be slightly reduced to account for the extra output. -#wide-stereo = false - -## frequency: -# Sets the output frequency. If left unspecified it will try to detect a -# default from the system, otherwise it will default to 44100. -#frequency = - -## resampler: +## resampler: (global) # Selects the resampler used when mixing sources. Valid values are: # point - nearest sample, no interpolation # linear - extrapolates samples using a linear slope between samples -# cubic - extrapolates samples using a Catmull-Rom spline +# sinc4 - extrapolates samples using a 4-point Sinc filter +# sinc8 - extrapolates samples using an 8-point Sinc filter +# bsinc - extrapolates samples using a band-limited Sinc filter (varying +# between 12 and 24 points, with anti-aliasing) # Specifying other values will result in using the default (linear). #resampler = linear -## rt-prio: +## rt-prio: (global) # Sets real-time priority for the mixing thread. Not all drivers may use this # (eg. PortAudio) as they already control the priority of the mixing thread. # 0 and negative values will disable it. Note that this may constitute a @@ -114,39 +145,11 @@ # disabled. #rt-prio = 0 -## period_size: -# Sets the update period size, in frames. This is the number of frames needed -# for each mixing update. Acceptable values range between 64 and 8192. -#period_size = 1024 - -## periods: -# Sets the number of update periods. Higher values create a larger mix ahead, -# which helps protect against skips when the CPU is under load, but increases -# the delay between a sound getting mixed and being heard. Acceptable values -# range between 2 and 16. -#periods = 4 - ## sources: # Sets the maximum number of allocatable sources. Lower values may help for # systems with apps that try to play more sounds than the CPU can handle. #sources = 256 -## drivers: -# Sets the backend driver list order, comma-seperated. Unknown backends and -# duplicated names are ignored. Unlisted backends won't be considered for use -# unless the list is ended with a comma (e.g. 'oss,' will try OSS first before -# other backends, while 'oss' will try OSS only). Backends prepended with - -# won't be considered for use (e.g. '-oss,' will try all available backends -# except OSS). An empty list means to try all backends. -#drivers = - -## excludefx: -# Sets which effects to exclude, preventing apps from using them. This can -# help for apps that try to use effects which are too CPU intensive for the -# system to handle. Available effects are: eaxreverb,reverb,autowah,chorus, -# compressor,distortion,echo,equalizer,flanger,modulator,dedicated -#excludefx = - ## slots: # Sets the maximum number of Auxiliary Effect Slots an app can create. A slot # can use a non-negligible amount of CPU time if an effect is set on it even @@ -160,26 +163,14 @@ # possible is 4. #sends = -## layout: -# Sets the virtual speaker layout. Values are specified in degrees, where 0 is -# straight in front, negative goes left, and positive goes right. Unspecified -# speakers will remain at their default positions (which are dependant on the -# output format). Available speakers are back-left(bl), side-left(sl), front- -# left(fl), front-center(fc), front-right(fr), side-right(sr), back-right(br), -# and back-center(bc). -#layout = +## excludefx: (global) +# Sets which effects to exclude, preventing apps from using them. This can +# help for apps that try to use effects which are too CPU intensive for the +# system to handle. Available effects are: eaxreverb,reverb,chorus,compressor, +# distortion,echo,equalizer,flanger,modulator,dedicated +#excludefx = -## layout_*: -# Channel-specific layouts may be specified to override the layout option. The -# same speakers as the layout option are available, and the default settings -# are shown below. -#layout_stereo = fl=-90, fr=90 -#layout_quad = fl=-45, fr=45, bl=-135, br=135 -#layout_surround51 = fl=-30, fr=30, fc=0, bl=-110, br=110 -#layout_surround61 = fl=-30, fr=30, fc=0, sl=-90, sr=90, bc=180 -#layout_surround71 = fl=-30, fr=30, fc=0, sl=-90, sr=90, bl=-150, br=150 - -## default-reverb: +## default-reverb: (global) # A reverb preset that applies by default to all sources on send 0 # (applications that set their own slots on send 0 will override this). # Available presets are: None, Generic, PaddedCell, Room, Bathroom, @@ -188,54 +179,31 @@ # Quarry, Plain, ParkingLot, SewerPipe, Underwater, Drugged, Dizzy, Psychotic. #default-reverb = -## trap-alc-error: +## trap-alc-error: (global) # Generates a SIGTRAP signal when an ALC device error is generated, on systems # that support it. This helps when debugging, while trying to find the cause # of a device error. On Windows, a breakpoint exception is generated. #trap-alc-error = false -## trap-al-error: +## trap-al-error: (global) # Generates a SIGTRAP signal when an AL context error is generated, on systems # that support it. This helps when debugging, while trying to find the cause # of a context error. On Windows, a breakpoint exception is generated. #trap-al-error = false -## -## MIDI stuff (EXPERIMENTAL) -## -[midi] - -## soundfont: -# A default soundfont (sf2 format). Used when an app requests the system -# default. The listed file is relative to system-dependant data directories. -# On Windows this is: -# $AppData\openal\soundfonts -# And on other systems, it's (in order): -# $XDG_DATA_HOME/openal/soundfonts -# $XDG_DATA_DIRS/openal/soundfonts -# An absolute path may also be specified, if the given file is elsewhere. -#soundfont = - -## volume: -# Additional attenuation applied to MIDI output, expressed in decibels. This -# is used to help keep the mix from clipping, and so must be 0 or less. The -# value is logarithmic, so -6 will be about half amplitude, and -12 about -# 1/4th. The default is roughly -13.9794 (0.2, or 1/5th). -#volume = - ## ## Reverb effect stuff (includes EAX reverb) ## [reverb] -## boost: +## boost: (global) # A global amplification for reverb output, expressed in decibels. The value # is logarithmic, so +6 will be a scale of (approximately) 2x, +12 will be a # scale of 4x, etc. Similarly, -6 will be about half, and -12 about 1/4th. A # value of 0 means no change. #boost = 0 -## emulate-eax: +## emulate-eax: (global) # Allows the standard reverb effect to be used in place of EAX reverb. EAX # reverb processing is a bit more CPU intensive than standard, so this option # allows a simpler effect to be used at the loss of some quality. @@ -246,52 +214,59 @@ ## [pulse] -## spawn-server: +## spawn-server: (global) # Attempts to autospawn a PulseAudio server whenever needed (initializing the # backend, enumerating devices, etc). Setting autospawn to false in Pulse's # client.conf will still prevent autospawning even if this is set to true. #spawn-server = true -## allow-moves: +## allow-moves: (global) # Allows PulseAudio to move active streams to different devices. Note that the # device specifier (seen by applications) will not be updated when this # occurs, and neither will the AL device configuration (sample rate, format, # etc). #allow-moves = false +## fix-rate: +# Specifies whether to match the playback stream's sample rate to the device's +# sample rate. Enabling this forces OpenAL Soft to mix sources and effects +# directly to the actual output rate, avoiding a second resample pass by the +# PulseAudio server. +#fix-rate = false + ## ## ALSA backend stuff ## [alsa] -## device: +## device: (global) # Sets the device name for the default playback device. #device = default -## device-prefix: +## device-prefix: (global) # Sets the prefix used by the discovered (non-default) playback devices. This # will be appended with "CARD=c,DEV=d", where c is the card id and d is the # device index for the requested device name. #device-prefix = plughw: -## device-prefix-*: +## device-prefix-*: (global) # Card- and device-specific prefixes may be used to override the device-prefix # option. The option may specify the card id (eg, device-prefix-NVidia), or # the card id and device index (eg, device-prefix-NVidia-0). The card id is # case-sensitive. #device-prefix- = -## capture: +## capture: (global) # Sets the device name for the default capture device. #capture = default -## capture-prefix: +## capture-prefix: (global) # Sets the prefix used by the discovered (non-default) capture devices. This # will be appended with "CARD=c,DEV=d", where c is the card id and d is the # device number for the requested device name. #capture-prefix = plughw: -## capture-prefix-*: +## capture-prefix-*: (global) # Card- and device-specific prefixes may be used to override the # capture-prefix option. The option may specify the card id (eg, # capture-prefix-NVidia), or the card id and device index (eg, @@ -305,16 +280,23 @@ # and anything else will force mmap off. #mmap = true +## allow-resampler: +# Specifies whether to allow ALSA's built-in resampler. Enabling this will +# allow the playback device to be set to a different sample rate than the +# actual output, causing ALSA to apply its own resampling pass after OpenAL +# Soft resamples and mixes the sources and effects for output. +#allow-resampler = false + ## ## OSS backend stuff ## [oss] -## device: +## device: (global) # Sets the device name for OSS output. #device = /dev/dsp -## capture: +## capture: (global) # Sets the device name for OSS capture. #capture = /dev/dsp @@ -323,7 +305,7 @@ ## [solaris] -## device: +## device: (global) # Sets the device name for Solaris output. #device = /dev/audio @@ -332,13 +314,24 @@ ## [qsa] -## device: -# Sets the device name for the default playback device. -#device = default +## +## JACK backend stuff +## +[jack] -## capture: -# Sets the device name for the default capture device. -#capture = default +## spawn-server: (global) +# Attempts to autospawn a JACK server whenever needed (initializing the +# backend, opening devices, etc). +#spawn-server = false + +## buffer-size: +# Sets the update buffer size, in samples, that the backend will keep buffered +# to handle the server's real-time processing requests. This value must be a +# power of 2, or else it will be rounded up to the next power of 2. If it is +# less than JACK's buffer update size, it will be clamped. This option may +# be useful in case the server's update size is too small and doesn't give the +# mixer time to keep enough audio available for the processing requests. +#buffer-size = 0 ## ## MMDevApi backend stuff @@ -360,12 +353,12 @@ ## [port] -## device: +## device: (global) # Sets the device index for output. Negative values will use the default as # given by PortAudio itself. #device = -1 -## capture: +## capture: (global) # Sets the device index for capture. Negative values will use the default as # given by PortAudio itself. #capture = -1 @@ -375,8 +368,13 @@ ## [wave] -## file: +## file: (global) # Sets the filename of the wave file to write to. An empty name prevents the # backend from opening, even when explicitly requested. # THIS WILL OVERWRITE EXISTING FILES WITHOUT QUESTION! #file = + +## bformat: (global) +# Creates AMB format files using first-order ambisonics instead of a standard +# single- or multi-channel .wav file. +#bformat = false diff --git a/libs/openal-soft/cmake/CheckFileOffsetBits.cmake b/libs/openal-soft/cmake/CheckFileOffsetBits.cmake index 76148403..1dc154e4 100644 --- a/libs/openal-soft/cmake/CheckFileOffsetBits.cmake +++ b/libs/openal-soft/cmake/CheckFileOffsetBits.cmake @@ -17,12 +17,12 @@ MACRO(CHECK_FILE_OFFSET_BITS) IF(NOT DEFINED _FILE_OFFSET_BITS) MESSAGE(STATUS "Checking _FILE_OFFSET_BITS for large files") TRY_COMPILE(__WITHOUT_FILE_OFFSET_BITS_64 - ${CMAKE_BINARY_DIR} + ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/CheckFileOffsetBits.c COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}) IF(NOT __WITHOUT_FILE_OFFSET_BITS_64) TRY_COMPILE(__WITH_FILE_OFFSET_BITS_64 - ${CMAKE_BINARY_DIR} + ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/CheckFileOffsetBits.c COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} -D_FILE_OFFSET_BITS=64) ENDIF(NOT __WITHOUT_FILE_OFFSET_BITS_64) diff --git a/libs/openal-soft/cmake/CheckSharedFunctionExists.cmake b/libs/openal-soft/cmake/CheckSharedFunctionExists.cmake index 4980effa..7975f233 100644 --- a/libs/openal-soft/cmake/CheckSharedFunctionExists.cmake +++ b/libs/openal-soft/cmake/CheckSharedFunctionExists.cmake @@ -58,12 +58,12 @@ MACRO(CHECK_SHARED_FUNCTION_EXISTS SYMBOL FILES LIBRARY LOCATION VARIABLE) "${CMAKE_CONFIGURABLE_FILE_CONTENT}\nvoid cmakeRequireSymbol(int dummy,...){(void)dummy;}\nint main()\n{\n cmakeRequireSymbol(0,&${SYMBOL});\n return 0;\n}\n") CONFIGURE_FILE("${CMAKE_ROOT}/Modules/CMakeConfigurableFile.in" - "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c" @ONLY) + "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c" @ONLY) MESSAGE(STATUS "Looking for ${SYMBOL} in ${LIBRARY}") TRY_COMPILE(${VARIABLE} - ${CMAKE_BINARY_DIR} - ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_SYMBOL_EXISTS_FLAGS} @@ -74,18 +74,18 @@ MACRO(CHECK_SHARED_FUNCTION_EXISTS SYMBOL FILES LIBRARY LOCATION VARIABLE) IF(${VARIABLE}) MESSAGE(STATUS "Looking for ${SYMBOL} in ${LIBRARY} - found") SET(${VARIABLE} 1 CACHE INTERNAL "Have symbol ${SYMBOL} in ${LIBRARY}") - FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log + FILE(APPEND ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log "Determining if the ${SYMBOL} " "exist in ${LIBRARY} passed with the following output:\n" - "${OUTPUT}\nFile ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c:\n" + "${OUTPUT}\nFile ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c:\n" "${CMAKE_CONFIGURABLE_FILE_CONTENT}\n") ELSE(${VARIABLE}) MESSAGE(STATUS "Looking for ${SYMBOL} in ${LIBRARY} - not found.") SET(${VARIABLE} "" CACHE INTERNAL "Have symbol ${SYMBOL} in ${LIBRARY}") - FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log + FILE(APPEND ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log "Determining if the ${SYMBOL} " "exist in ${LIBRARY} failed with the following output:\n" - "${OUTPUT}\nFile ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c:\n" + "${OUTPUT}\nFile ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/CheckSymbolExists.c:\n" "${CMAKE_CONFIGURABLE_FILE_CONTENT}\n") ENDIF(${VARIABLE}) ENDIF("${VARIABLE}" MATCHES "^${VARIABLE}$") diff --git a/libs/openal-soft/cmake/FindDSound.cmake b/libs/openal-soft/cmake/FindDSound.cmake index 36cdf4b5..0ddf98aa 100644 --- a/libs/openal-soft/cmake/FindDSound.cmake +++ b/libs/openal-soft/cmake/FindDSound.cmake @@ -9,14 +9,16 @@ # find_path(DSOUND_INCLUDE_DIR - PATHS "${DXSDK_DIR}/include" NAMES dsound.h + PATHS "${DXSDK_DIR}" + PATH_SUFFIXES include DOC "The DirectSound include directory" ) find_library(DSOUND_LIBRARY - PATHS "${DXSDK_DIR}/lib" NAMES dsound + PATHS "${DXSDK_DIR}" + PATH_SUFFIXES lib lib/x86 lib/x64 DOC "The DirectSound library" ) diff --git a/libs/openal-soft/cmake/FindSDL_sound.cmake b/libs/openal-soft/cmake/FindSDL_sound.cmake index 2dab1a1c..5557b55b 100644 --- a/libs/openal-soft/cmake/FindSDL_sound.cmake +++ b/libs/openal-soft/cmake/FindSDL_sound.cmake @@ -146,197 +146,152 @@ if(SDL2_FOUND OR SDL_FOUND) # The ;-framework Cocoa seems to be confusing CMake once the OS X # framework support was added. I was told that breaking up the list # would fix the problem. - set(TMP_TRY_LIBS) + set(TMP_LIBS "") if(SDL2_FOUND) + set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARY} ${SDL2_LIBRARY}) foreach(lib ${SDL_SOUND_LIBRARY} ${SDL2_LIBRARY}) - set(TMP_TRY_LIBS "${TMP_TRY_LIBS} \"${lib}\"") + set(TMP_LIBS "${TMP_LIBS} \"${lib}\"") endforeach() set(TMP_INCLUDE_DIRS ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR}) else() + set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARY} ${SDL_LIBRARY}) foreach(lib ${SDL_SOUND_LIBRARY} ${SDL_LIBRARY}) - set(TMP_TRY_LIBS "${TMP_TRY_LIBS} \"${lib}\"") + set(TMP_LIBS "${TMP_LIBS} \"${lib}\"") endforeach() set(TMP_INCLUDE_DIRS ${SDL_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR}) endif() - # message("TMP_TRY_LIBS ${TMP_TRY_LIBS}") + # Keep trying to build a temp project until we find all missing libs. + set(TRY_AGAIN TRUE) + WHILE(TRY_AGAIN) + set(TRY_AGAIN FALSE) + # message("TMP_TRY_LIBS ${TMP_TRY_LIBS}") - # Write the CMakeLists.txt and test project - # Weird, this is still sketchy. If I don't quote the variables - # in the TARGET_LINK_LIBRARIES, I seem to loose everything - # in the SDL2_LIBRARY string after the "-framework". - # But if I quote the stuff in INCLUDE_DIRECTORIES, it doesn't work. - file(WRITE ${PROJECT_BINARY_DIR}/CMakeTmp/CMakeLists.txt - "cmake_minimum_required(VERSION 2.8) - project(DetermineSoundLibs C) - include_directories(${TMP_INCLUDE_DIRS}) - add_executable(DetermineSoundLibs DetermineSoundLibs.c) - target_link_libraries(DetermineSoundLibs ${TMP_TRY_LIBS})" - ) - unset(TMP_INCLUDE_DIRS) - unset(TMP_TRY_LIBS) + # Write the CMakeLists.txt and test project + # Weird, this is still sketchy. If I don't quote the variables + # in the TARGET_LINK_LIBRARIES, I seem to loose everything + # in the SDL2_LIBRARY string after the "-framework". + # But if I quote the stuff in INCLUDE_DIRECTORIES, it doesn't work. + file(WRITE ${PROJECT_BINARY_DIR}/CMakeTmp/CMakeLists.txt + "cmake_minimum_required(VERSION 2.8) + project(DetermineSoundLibs C) + include_directories(${TMP_INCLUDE_DIRS}) + add_executable(DetermineSoundLibs DetermineSoundLibs.c) + target_link_libraries(DetermineSoundLibs ${TMP_LIBS})" + ) - try_compile( - MY_RESULT - ${PROJECT_BINARY_DIR}/CMakeTmp - ${PROJECT_BINARY_DIR}/CMakeTmp - DetermineSoundLibs - OUTPUT_VARIABLE MY_OUTPUT - ) - # message("${MY_RESULT}") - # message(${MY_OUTPUT}) + try_compile( + MY_RESULT + ${PROJECT_BINARY_DIR}/CMakeTmp + ${PROJECT_BINARY_DIR}/CMakeTmp + DetermineSoundLibs + OUTPUT_VARIABLE MY_OUTPUT + ) + # message("${MY_RESULT}") + # message(${MY_OUTPUT}) - if(NOT MY_RESULT) - # I expect that MPGLIB, VOC, WAV, AIFF, and SHN are compiled in statically. - # I think Timidity is also compiled in statically. - # I've never had to explcitly link against Quicktime, so I'll skip that for now. + if(NOT MY_RESULT) + # I expect that MPGLIB, VOC, WAV, AIFF, and SHN are compiled in statically. + # I think Timidity is also compiled in statically. + # I've never had to explcitly link against Quicktime, so I'll skip that for now. - set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARY}) + # Find libmath + if("${MY_OUTPUT}" MATCHES "cos@@GLIBC") + find_library(MATH_LIBRARY NAMES m) + if(MATH_LIBRARY) + set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${MATH_LIBRARY}) + set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${MATH_LIBRARY}\"") + set(TRY_AGAIN TRUE) + endif(MATH_LIBRARY) + endif("${MY_OUTPUT}" MATCHES "cos@@GLIBC") - # Find MikMod - if("${MY_OUTPUT}" MATCHES "MikMod_") - find_library(MIKMOD_LIBRARY - NAMES libmikmod-coreaudio mikmod - PATHS - ENV MIKMODDIR - ENV SDLSOUNDDIR - ENV SDLDIR - /sw - /opt/local - /opt/csw - /opt - PATH_SUFFIXES lib - ) - if(MIKMOD_LIBRARY) - set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${MIKMOD_LIBRARY}) - endif(MIKMOD_LIBRARY) - endif("${MY_OUTPUT}" MATCHES "MikMod_") + # Find MikMod + if("${MY_OUTPUT}" MATCHES "MikMod_") + find_library(MIKMOD_LIBRARY + NAMES libmikmod-coreaudio mikmod + PATHS + ENV MIKMODDIR + ENV SDLSOUNDDIR + ENV SDLDIR + /sw + /opt/local + /opt/csw + /opt + PATH_SUFFIXES lib + ) + if(MIKMOD_LIBRARY) + set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${MIKMOD_LIBRARY}) + set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${MIKMOD_LIBRARY}\"") + set(TRY_AGAIN TRUE) + endif(MIKMOD_LIBRARY) + endif("${MY_OUTPUT}" MATCHES "MikMod_") - # Find ModPlug - if("${MY_OUTPUT}" MATCHES "MODPLUG_") - find_library(MODPLUG_LIBRARY - NAMES modplug - PATHS - ENV MODPLUGDIR - ENV SDLSOUNDDIR - ENV SDLDIR - /sw - /opt/local - /opt/csw - /opt - PATH_SUFFIXES lib - ) - if(MODPLUG_LIBRARY) - set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${MODPLUG_LIBRARY}) - endif() - endif() - - # Find Ogg and Vorbis - if("${MY_OUTPUT}" MATCHES "ov_") - find_library(VORBIS_LIBRARY - NAMES vorbis Vorbis VORBIS - PATHS - ENV VORBISDIR - ENV OGGDIR - ENV SDLSOUNDDIR - ENV SDLDIR - /sw - /opt/local - /opt/csw - /opt - PATH_SUFFIXES lib - ) - if(VORBIS_LIBRARY) - set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${VORBIS_LIBRARY}) - endif() - find_library(OGG_LIBRARY - NAMES ogg Ogg OGG - PATHS - ENV OGGDIR - ENV VORBISDIR - ENV SDLSOUNDDIR - ENV SDLDIR - /sw - /opt/local - /opt/csw - /opt - PATH_SUFFIXES lib - ) - if(OGG_LIBRARY) - set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${OGG_LIBRARY}) - endif() - endif() - - # Find SMPEG - if("${MY_OUTPUT}" MATCHES "SMPEG_") - find_library(SMPEG_LIBRARY - NAMES smpeg SMPEG Smpeg SMpeg - PATHS - ENV SMPEGDIR - ENV SDLSOUNDDIR - ENV SDLDIR - /sw - /opt/local - /opt/csw - /opt - PATH_SUFFIXES lib - ) - if(SMPEG_LIBRARY) - set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${SMPEG_LIBRARY}) - endif() - endif() - - - # Find FLAC - if("${MY_OUTPUT}" MATCHES "FLAC_") - find_library(FLAC_LIBRARY - NAMES flac FLAC - PATHS - ENV FLACDIR - ENV SDLSOUNDDIR - ENV SDLDIR - /sw - /opt/local - /opt/csw - /opt - PATH_SUFFIXES lib - ) - if(FLAC_LIBRARY) - set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${FLAC_LIBRARY}) - endif() - endif() - - - # Hmmm...Speex seems to depend on Ogg. This might be a problem if - # the TRY_COMPILE attempt gets blocked at SPEEX before it can pull - # in the Ogg symbols. I'm not sure if I should duplicate the ogg stuff - # above for here or if two ogg entries will screw up things. - if("${MY_OUTPUT}" MATCHES "speex_") - find_library(SPEEX_LIBRARY - NAMES speex SPEEX - PATHS - ENV SPEEXDIR - ENV SDLSOUNDDIR - ENV SDLDIR - /sw - /opt/local - /opt/csw - /opt - PATH_SUFFIXES lib - ) - if(SPEEX_LIBRARY) - set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${SPEEX_LIBRARY}) + # Find ModPlug + if("${MY_OUTPUT}" MATCHES "MODPLUG_") + find_library(MODPLUG_LIBRARY + NAMES modplug + PATHS + ENV MODPLUGDIR + ENV SDLSOUNDDIR + ENV SDLDIR + /sw + /opt/local + /opt/csw + /opt + PATH_SUFFIXES lib + ) + if(MODPLUG_LIBRARY) + set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${MODPLUG_LIBRARY}) + set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${MODPLUG_LIBRARY}\"") + set(TRY_AGAIN TRUE) + endif() endif() - # Find OGG (needed for Speex) - # We might have already found Ogg for Vorbis, so skip it if so. - if(NOT OGG_LIBRARY) + # Find Ogg and Vorbis + if("${MY_OUTPUT}" MATCHES "ov_") + find_library(VORBISFILE_LIBRARY + NAMES vorbisfile VorbisFile VORBISFILE + PATHS + ENV VORBISDIR + ENV OGGDIR + ENV SDLSOUNDDIR + ENV SDLDIR + /sw + /opt/local + /opt/csw + /opt + PATH_SUFFIXES lib + ) + if(VORBISFILE_LIBRARY) + set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${VORBISFILE_LIBRARY}) + set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${VORBISFILE_LIBRARY}\"") + set(TRY_AGAIN TRUE) + endif() + + find_library(VORBIS_LIBRARY + NAMES vorbis Vorbis VORBIS + PATHS + ENV OGGDIR + ENV VORBISDIR + ENV SDLSOUNDDIR + ENV SDLDIR + /sw + /opt/local + /opt/csw + /opt + PATH_SUFFIXES lib + ) + if(VORBIS_LIBRARY) + set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${VORBIS_LIBRARY}) + set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${VORBIS_LIBRARY}\"") + set(TRY_AGAIN TRUE) + endif() + find_library(OGG_LIBRARY NAMES ogg Ogg OGG PATHS ENV OGGDIR ENV VORBISDIR - ENV SPEEXDIR ENV SDLSOUNDDIR ENV SDLDIR /sw @@ -347,14 +302,108 @@ if(SDL2_FOUND OR SDL_FOUND) ) if(OGG_LIBRARY) set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${OGG_LIBRARY}) + set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${OGG_LIBRARY}\"") + set(TRY_AGAIN TRUE) + endif() + endif() + + # Find SMPEG + if("${MY_OUTPUT}" MATCHES "SMPEG_") + find_library(SMPEG_LIBRARY + NAMES smpeg SMPEG Smpeg SMpeg + PATHS + ENV SMPEGDIR + ENV SDLSOUNDDIR + ENV SDLDIR + /sw + /opt/local + /opt/csw + /opt + PATH_SUFFIXES lib + ) + if(SMPEG_LIBRARY) + set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${SMPEG_LIBRARY}) + set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${SMPEG_LIBRARY}\"") + set(TRY_AGAIN TRUE) + endif() + endif() + + + # Find FLAC + if("${MY_OUTPUT}" MATCHES "FLAC_") + find_library(FLAC_LIBRARY + NAMES flac FLAC + PATHS + ENV FLACDIR + ENV SDLSOUNDDIR + ENV SDLDIR + /sw + /opt/local + /opt/csw + /opt + PATH_SUFFIXES lib + ) + if(FLAC_LIBRARY) + set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${FLAC_LIBRARY}) + set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${FLAC_LIBRARY}\"") + set(TRY_AGAIN TRUE) + endif() + endif() + + + # Hmmm...Speex seems to depend on Ogg. This might be a problem if + # the TRY_COMPILE attempt gets blocked at SPEEX before it can pull + # in the Ogg symbols. I'm not sure if I should duplicate the ogg stuff + # above for here or if two ogg entries will screw up things. + if("${MY_OUTPUT}" MATCHES "speex_") + find_library(SPEEX_LIBRARY + NAMES speex SPEEX + PATHS + ENV SPEEXDIR + ENV SDLSOUNDDIR + ENV SDLDIR + /sw + /opt/local + /opt/csw + /opt + PATH_SUFFIXES lib + ) + if(SPEEX_LIBRARY) + set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${SPEEX_LIBRARY}) + set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${SPEEX_LIBRARY}\"") + set(TRY_AGAIN TRUE) + endif() + + # Find OGG (needed for Speex) + # We might have already found Ogg for Vorbis, so skip it if so. + if(NOT OGG_LIBRARY) + find_library(OGG_LIBRARY + NAMES ogg Ogg OGG + PATHS + ENV OGGDIR + ENV VORBISDIR + ENV SPEEXDIR + ENV SDLSOUNDDIR + ENV SDLDIR + /sw + /opt/local + /opt/csw + /opt + PATH_SUFFIXES lib + ) + if(OGG_LIBRARY) + set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARIES_TMP} ${OGG_LIBRARY}) + set(TMP_LIBS "${SDL_SOUND_LIBRARIES_TMP} \"${OGG_LIBRARY}\"") + set(TRY_AGAIN TRUE) + endif() endif() endif() endif() + ENDWHILE() + unset(TMP_INCLUDE_DIRS) + unset(TMP_LIBS) - set(SDL_SOUND_LIBRARIES ${SDL_SOUND_EXTRAS} ${SDL_SOUND_LIBRARIES_TMP} CACHE INTERNAL "SDL_sound and dependent libraries") - else() - set(SDL_SOUND_LIBRARIES ${SDL_SOUND_EXTRAS} ${SDL_SOUND_LIBRARY} CACHE INTERNAL "SDL_sound and dependent libraries") - endif() + set(SDL_SOUND_LIBRARIES ${SDL_SOUND_EXTRAS} ${SDL_SOUND_LIBRARIES_TMP} CACHE INTERNAL "SDL_sound and dependent libraries") endif() endif() diff --git a/libs/openal-soft/common/threads.c b/libs/openal-soft/common/threads.c index cd9f6755..71fa6ab9 100644 --- a/libs/openal-soft/common/threads.c +++ b/libs/openal-soft/common/threads.c @@ -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 */ @@ -733,11 +733,11 @@ int altimespec_get(struct timespec *ts, int base) #endif -void al_nssleep(time_t sec, long nsec) +void al_nssleep(unsigned long nsec) { struct timespec ts, rem; - ts.tv_sec = sec; - ts.tv_nsec = nsec; + ts.tv_sec = nsec / 1000000000ul; + ts.tv_nsec = nsec % 1000000000ul; while(althrd_sleep(&ts, &rem) == -1) ts = rem; diff --git a/libs/openal-soft/config.h.in b/libs/openal-soft/config.h.in index af0d8bfd..e66b1fe8 100644 --- a/libs/openal-soft/config.h.in +++ b/libs/openal-soft/config.h.in @@ -9,7 +9,7 @@ /* KDevelop's parser doesn't recognize the C99-standard restrict keyword, but * recent versions (at least 4.5.1) do recognize GCC's __restrict. */ #define restrict __restrict -#endif +#endif /* Define any available alignment declaration */ #define ALIGN(x) ${ALIGN_DECL} @@ -26,14 +26,12 @@ /* Define if we have SSE CPU extensions */ #cmakedefine HAVE_SSE #cmakedefine HAVE_SSE2 +#cmakedefine HAVE_SSE3 #cmakedefine HAVE_SSE4_1 /* Define if we have ARM Neon CPU extensions */ #cmakedefine HAVE_NEON -/* Define if we have FluidSynth support */ -#cmakedefine HAVE_FLUIDSYNTH - /* Define if we have the ALSA backend */ #cmakedefine HAVE_ALSA @@ -64,6 +62,9 @@ /* Define if we have the PulseAudio backend */ #cmakedefine HAVE_PULSEAUDIO +/* Define if we have the JACK backend */ +#cmakedefine HAVE_JACK + /* Define if we have the CoreAudio backend */ #cmakedefine HAVE_COREAUDIO @@ -79,6 +80,9 @@ /* Define if we have the lrintf function */ #cmakedefine HAVE_LRINTF +/* Define if we have the modff function */ +#cmakedefine HAVE_MODFF + /* Define if we have the strtof function */ #cmakedefine HAVE_STRTOF @@ -136,8 +140,8 @@ /* Define if we have malloc.h */ #cmakedefine HAVE_MALLOC_H -/* Define if we have ftw.h */ -#cmakedefine HAVE_FTW_H +/* Define if we have dirent.h */ +#cmakedefine HAVE_DIRENT_H /* Define if we have io.h */ #cmakedefine HAVE_IO_H @@ -181,12 +185,6 @@ /* Define if we have __control87_2() */ #cmakedefine HAVE___CONTROL87_2 -/* Define if we have ftw() */ -#cmakedefine HAVE_FTW - -/* Define if we have _wfindfirst() */ -#cmakedefine HAVE__WFINDFIRST - /* Define if we have pthread_setschedparam() */ #cmakedefine HAVE_PTHREAD_SETSCHEDPARAM diff --git a/libs/openal-soft/env-vars.txt b/libs/openal-soft/env-vars.txt index 47dce032..b2268643 100644 --- a/libs/openal-soft/env-vars.txt +++ b/libs/openal-soft/env-vars.txt @@ -69,3 +69,13 @@ sound (i.e., sounds that are supposed to be behind you sound like they're in front, and vice-versa). Setting this to "true" or "1" will negate the localized Z coordinate to attempt to fix output for apps that have incorrect front/back panning. + +__ALSOFT_SUSPEND_CONTEXT +Due to the OpenAL spec not being very clear about them, behavior of the +alcSuspendContext and alcProcessContext methods has varied, and because of +that, previous versions of OpenAL Soft had them no-op. Creative's hardware +drivers and the Rapture3D driver, however, use these methods to batch changes, +which some applications make use of to protect against partial updates. In an +attempt to standardize on that behavior, OpenAL Soft has changed those methods +accordingly. Setting this to "ignore" restores the previous no-op behavior for +applications that interact poorly with the new behavior. diff --git a/libs/openal-soft/examples/alffplay.c b/libs/openal-soft/examples/alffplay.c index d8ef0e57..17f6d3bc 100644 --- a/libs/openal-soft/examples/alffplay.c +++ b/libs/openal-soft/examples/alffplay.c @@ -548,6 +548,7 @@ static int audio_thread(void *userdata) MovieState *movState = (MovieState*)userdata; uint8_t *samples = NULL; ALsizei buffer_len; + ALenum fmt; alGenBuffers(AUDIO_BUFFER_QUEUE_SIZE, movState->audio.buffer); alGenSources(1, &movState->audio.source); @@ -557,56 +558,107 @@ static int audio_thread(void *userdata) av_new_packet(&movState->audio.pkt, 0); - /* Find a suitable format for OpenAL. Currently does not handle surround - * sound (everything non-mono becomes stereo). */ + /* Find a suitable format for OpenAL. */ + movState->audio.format = AL_NONE; if(movState->audio.st->codec->sample_fmt == AV_SAMPLE_FMT_U8 || movState->audio.st->codec->sample_fmt == AV_SAMPLE_FMT_U8P) { movState->audio.dst_sample_fmt = AV_SAMPLE_FMT_U8; movState->audio.frame_size = 1; + if(movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_7POINT1 && + alIsExtensionPresent("AL_EXT_MCFORMATS") && + (fmt=alGetEnumValue("AL_FORMAT_71CHN8")) != AL_NONE && fmt != -1) + { + movState->audio.dst_ch_layout = movState->audio.st->codec->channel_layout; + movState->audio.frame_size *= 8; + movState->audio.format = fmt; + } + if((movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_5POINT1 || + movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_5POINT1_BACK) && + alIsExtensionPresent("AL_EXT_MCFORMATS") && + (fmt=alGetEnumValue("AL_FORMAT_51CHN8")) != AL_NONE && fmt != -1) + { + movState->audio.dst_ch_layout = movState->audio.st->codec->channel_layout; + movState->audio.frame_size *= 6; + movState->audio.format = fmt; + } if(movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_MONO) { movState->audio.dst_ch_layout = AV_CH_LAYOUT_MONO; movState->audio.frame_size *= 1; movState->audio.format = AL_FORMAT_MONO8; } - else + if(movState->audio.format == AL_NONE) { movState->audio.dst_ch_layout = AV_CH_LAYOUT_STEREO; movState->audio.frame_size *= 2; movState->audio.format = AL_FORMAT_STEREO8; } } - else if((movState->audio.st->codec->sample_fmt == AV_SAMPLE_FMT_FLT || - movState->audio.st->codec->sample_fmt == AV_SAMPLE_FMT_FLTP) && - alIsExtensionPresent("AL_EXT_FLOAT32")) + if((movState->audio.st->codec->sample_fmt == AV_SAMPLE_FMT_FLT || + movState->audio.st->codec->sample_fmt == AV_SAMPLE_FMT_FLTP) && + alIsExtensionPresent("AL_EXT_FLOAT32")) { movState->audio.dst_sample_fmt = AV_SAMPLE_FMT_FLT; movState->audio.frame_size = 4; + if(movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_7POINT1 && + alIsExtensionPresent("AL_EXT_MCFORMATS") && + (fmt=alGetEnumValue("AL_FORMAT_71CHN32")) != AL_NONE && fmt != -1) + { + movState->audio.dst_ch_layout = movState->audio.st->codec->channel_layout; + movState->audio.frame_size *= 8; + movState->audio.format = fmt; + } + if((movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_5POINT1 || + movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_5POINT1_BACK) && + alIsExtensionPresent("AL_EXT_MCFORMATS") && + (fmt=alGetEnumValue("AL_FORMAT_51CHN32")) != AL_NONE && fmt != -1) + { + movState->audio.dst_ch_layout = movState->audio.st->codec->channel_layout; + movState->audio.frame_size *= 6; + movState->audio.format = fmt; + } if(movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_MONO) { movState->audio.dst_ch_layout = AV_CH_LAYOUT_MONO; movState->audio.frame_size *= 1; movState->audio.format = AL_FORMAT_MONO_FLOAT32; } - else + if(movState->audio.format == AL_NONE) { movState->audio.dst_ch_layout = AV_CH_LAYOUT_STEREO; movState->audio.frame_size *= 2; movState->audio.format = AL_FORMAT_STEREO_FLOAT32; } } - else + if(movState->audio.format == AL_NONE) { movState->audio.dst_sample_fmt = AV_SAMPLE_FMT_S16; movState->audio.frame_size = 2; + if(movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_7POINT1 && + alIsExtensionPresent("AL_EXT_MCFORMATS") && + (fmt=alGetEnumValue("AL_FORMAT_71CHN16")) != AL_NONE && fmt != -1) + { + movState->audio.dst_ch_layout = movState->audio.st->codec->channel_layout; + movState->audio.frame_size *= 8; + movState->audio.format = fmt; + } + if((movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_5POINT1 || + movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_5POINT1_BACK) && + alIsExtensionPresent("AL_EXT_MCFORMATS") && + (fmt=alGetEnumValue("AL_FORMAT_51CHN16")) != AL_NONE && fmt != -1) + { + movState->audio.dst_ch_layout = movState->audio.st->codec->channel_layout; + movState->audio.frame_size *= 6; + movState->audio.format = fmt; + } if(movState->audio.st->codec->channel_layout == AV_CH_LAYOUT_MONO) { movState->audio.dst_ch_layout = AV_CH_LAYOUT_MONO; movState->audio.frame_size *= 1; movState->audio.format = AL_FORMAT_MONO16; } - else + if(movState->audio.format == AL_NONE) { movState->audio.dst_ch_layout = AV_CH_LAYOUT_STEREO; movState->audio.frame_size *= 2; @@ -632,7 +684,9 @@ static int audio_thread(void *userdata) movState->audio.dst_ch_layout, movState->audio.dst_sample_fmt, movState->audio.st->codec->sample_rate, - movState->audio.st->codec->channel_layout, + movState->audio.st->codec->channel_layout ? + movState->audio.st->codec->channel_layout : + av_get_default_channel_layout(movState->audio.st->codec->channels), movState->audio.st->codec->sample_fmt, movState->audio.st->codec->sample_rate, 0, NULL diff --git a/libs/openal-soft/examples/alloopback.c b/libs/openal-soft/examples/alloopback.c index 2361ada1..04c92818 100644 --- a/libs/openal-soft/examples/alloopback.c +++ b/libs/openal-soft/examples/alloopback.c @@ -65,13 +65,13 @@ void SDLCALL RenderSDLSamples(void *userdata, Uint8 *stream, int len) * buffer ID. */ static ALuint CreateSineWave(void) { - ALshort data[44100]; + ALshort data[44100*4]; ALuint buffer; ALenum err; ALuint i; - for(i = 0;i < 44100;i++) - data[i] = (ALshort)(sin(i * 441.0 / 44100.0 * 2.0*M_PI)*32767.0); + for(i = 0;i < 44100*4;i++) + data[i] = (ALshort)(sin(i/44100.0 * 1000.0 * 2.0*M_PI) * 32767.0); /* Buffer the audio data into a new buffer object. */ buffer = 0; diff --git a/libs/openal-soft/hrtf.txt b/libs/openal-soft/hrtf.txt index e19fb0b8..37a329d2 100644 --- a/libs/openal-soft/hrtf.txt +++ b/libs/openal-soft/hrtf.txt @@ -14,7 +14,7 @@ sides. The default data set is based on the KEMAR HRTF data provided by MIT, which can be found at . It's only -available when using 44100hz playback. +available when using 44100hz or 48000hz playback. Custom HRTF Data Sets diff --git a/libs/openal-soft/include/AL/alext.h b/libs/openal-soft/include/AL/alext.h index 7d2a9527..6af581aa 100644 --- a/libs/openal-soft/include/AL/alext.h +++ b/libs/openal-soft/include/AL/alext.h @@ -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 */ @@ -393,6 +393,44 @@ ALC_API void ALC_APIENTRY alcDeviceResumeSOFT(ALCdevice *device); #endif #endif +#ifndef AL_EXT_BFORMAT +#define AL_EXT_BFORMAT 1 +#define AL_FORMAT_BFORMAT2D_8 0x20021 +#define AL_FORMAT_BFORMAT2D_16 0x20022 +#define AL_FORMAT_BFORMAT2D_FLOAT32 0x20023 +#define AL_FORMAT_BFORMAT3D_8 0x20031 +#define AL_FORMAT_BFORMAT3D_16 0x20032 +#define AL_FORMAT_BFORMAT3D_FLOAT32 0x20033 +#endif + +#ifndef AL_EXT_MULAW_BFORMAT +#define AL_EXT_MULAW_BFORMAT 1 +#define AL_FORMAT_BFORMAT2D_MULAW 0x10031 +#define AL_FORMAT_BFORMAT3D_MULAW 0x10032 +#endif + +#ifndef ALC_SOFT_HRTF +#define ALC_SOFT_HRTF 1 +#define ALC_HRTF_SOFT 0x1992 +#define ALC_DONT_CARE_SOFT 0x0002 +#define ALC_HRTF_STATUS_SOFT 0x1993 +#define ALC_HRTF_DISABLED_SOFT 0x0000 +#define ALC_HRTF_ENABLED_SOFT 0x0001 +#define ALC_HRTF_DENIED_SOFT 0x0002 +#define ALC_HRTF_REQUIRED_SOFT 0x0003 +#define ALC_HRTF_HEADPHONES_DETECTED_SOFT 0x0004 +#define ALC_HRTF_UNSUPPORTED_FORMAT_SOFT 0x0005 +#define ALC_NUM_HRTF_SPECIFIERS_SOFT 0x1994 +#define ALC_HRTF_SPECIFIER_SOFT 0x1995 +#define ALC_HRTF_ID_SOFT 0x1996 +typedef const ALCchar* (ALC_APIENTRY*LPALCGETSTRINGISOFT)(ALCdevice *device, ALCenum paramName, ALCsizei index); +typedef ALCboolean (ALC_APIENTRY*LPALCRESETDEVICESOFT)(ALCdevice *device, const ALCint *attribs); +#ifdef AL_ALEXT_PROTOTYPES +ALC_API const ALCchar* ALC_APIENTRY alcGetStringiSOFT(ALCdevice *device, ALCenum paramName, ALCsizei index); +ALC_API ALCboolean ALC_APIENTRY alcResetDeviceSOFT(ALCdevice *device, const ALCint *attribs); +#endif +#endif + #ifdef __cplusplus } #endif diff --git a/libs/openal-soft/include/AL/efx-presets.h b/libs/openal-soft/include/AL/efx-presets.h index 86dcbda2..8539fd51 100644 --- a/libs/openal-soft/include/AL/efx-presets.h +++ b/libs/openal-soft/include/AL/efx-presets.h @@ -345,7 +345,7 @@ typedef struct { /* Driving Presets */ #define EFX_REVERB_PRESET_DRIVING_COMMENTATOR \ - { 1.0000f, 0.0000f, 3.1623f, 0.5623f, 0.5012f, 2.4200f, 0.8800f, 0.6800f, 0.1995f, 0.0930f, { 0.0000f, 0.0000f, 0.0000f }, 0.2512f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9886f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } + { 1.0000f, 0.0000f, 0.3162f, 0.5623f, 0.5012f, 2.4200f, 0.8800f, 0.6800f, 0.1995f, 0.0930f, { 0.0000f, 0.0000f, 0.0000f }, 0.2512f, 0.0170f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 1.0000f, 0.2500f, 0.0000f, 0.9886f, 5000.0000f, 250.0000f, 0.0000f, 0x1 } #define EFX_REVERB_PRESET_DRIVING_PITGARAGE \ { 0.4287f, 0.5900f, 0.3162f, 0.7079f, 0.5623f, 1.7200f, 0.9300f, 0.8700f, 0.5623f, 0.0000f, { 0.0000f, 0.0000f, 0.0000f }, 1.2589f, 0.0160f, { 0.0000f, 0.0000f, 0.0000f }, 0.2500f, 0.1100f, 0.2500f, 0.0000f, 0.9943f, 5000.0000f, 250.0000f, 0.0000f, 0x0 } diff --git a/libs/openal-soft/include/align.h b/libs/openal-soft/include/align.h index babd4106..e2dc81df 100644 --- a/libs/openal-soft/include/align.h +++ b/libs/openal-soft/include/align.h @@ -1,16 +1,16 @@ #ifndef AL_ALIGN_H #define AL_ALIGN_H -#ifdef HAVE_STDALIGN_H +#if defined(HAVE_STDALIGN_H) && defined(HAVE_C11_ALIGNAS) #include #endif #ifndef alignas -#ifdef HAVE_C11_ALIGNAS -#define alignas _Alignas -#elif defined(IN_IDE_PARSER) +#if defined(IN_IDE_PARSER) /* KDevelop has problems with our align macro, so just use nothing for parsing. */ #define alignas(x) +#elif defined(HAVE_C11_ALIGNAS) +#define alignas _Alignas #else /* NOTE: Our custom ALIGN macro can't take a type name like alignas can. For * maximum compatibility, only provide constant integer values to alignas. */ diff --git a/libs/openal-soft/include/atomic.h b/libs/openal-soft/include/atomic.h index d761890e..8eb6820b 100644 --- a/libs/openal-soft/include/atomic.h +++ b/libs/openal-soft/include/atomic.h @@ -8,74 +8,81 @@ extern "C" { #endif -typedef void *volatile XchgPtr; - /* Atomics using C11 */ #ifdef HAVE_C11_ATOMIC #include -inline int ExchangeInt(volatile int *ptr, int newval) -{ return atomic_exchange(ptr, newval); } -inline void *ExchangePtr(XchgPtr *ptr, void *newval) -{ return atomic_exchange(ptr, newval); } +#define almemory_order memory_order +#define almemory_order_relaxed memory_order_relaxed +#define almemory_order_consume memory_order_consume +#define almemory_order_acquire memory_order_acquire +#define almemory_order_release memory_order_release +#define almemory_order_acq_rel memory_order_acq_rel +#define almemory_order_seq_cst memory_order_seq_cst +#define ATOMIC(T) T _Atomic -#define ATOMIC(T) struct { T _Atomic value; } +#define ATOMIC_INIT(_val, _newval) atomic_init((_val), (_newval)) +#define ATOMIC_INIT_STATIC(_newval) ATOMIC_VAR_INIT(_newval) -#define ATOMIC_INIT(_val, _newval) atomic_init(&(_val)->value, (_newval)) -#define ATOMIC_INIT_STATIC(_newval) {ATOMIC_VAR_INIT(_newval)} +#define PARAM2(f, a, b, ...) (f((a), (b))) +#define PARAM3(f, a, b, c, ...) (f((a), (b), (c))) +#define PARAM5(f, a, b, c, d, e, ...) (f((a), (b), (c), (d), (e))) -#define ATOMIC_LOAD(_val) atomic_load(&(_val)->value) -#define ATOMIC_STORE(_val, _newval) atomic_store(&(_val)->value, (_newval)) +#define ATOMIC_LOAD(...) PARAM2(atomic_load_explicit, __VA_ARGS__, memory_order_seq_cst) +#define ATOMIC_STORE(...) PARAM3(atomic_store_explicit, __VA_ARGS__, memory_order_seq_cst) -#define ATOMIC_ADD(T, _val, _incr) atomic_fetch_add(&(_val)->value, (_incr)) -#define ATOMIC_SUB(T, _val, _decr) atomic_fetch_sub(&(_val)->value, (_decr)) +#define ATOMIC_ADD(T, ...) PARAM3(atomic_fetch_add_explicit, __VA_ARGS__, memory_order_seq_cst) +#define ATOMIC_SUB(T, ...) PARAM3(atomic_fetch_sub_explicit, __VA_ARGS__, memory_order_seq_cst) -#define ATOMIC_EXCHANGE(T, _val, _newval) atomic_exchange(&(_val)->value, (_newval)) -#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval) \ - atomic_compare_exchange_strong(&(_val)->value, (_oldval), (_newval)) -#define ATOMIC_COMPARE_EXCHANGE_WEAK(T, _val, _oldval, _newval) \ - atomic_compare_exchange_weak(&(_val)->value, (_oldval), (_newval)) +#define ATOMIC_EXCHANGE(T, ...) PARAM3(atomic_exchange_explicit, __VA_ARGS__, memory_order_seq_cst) +#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, ...) \ + PARAM5(atomic_compare_exchange_strong_explicit, __VA_ARGS__, memory_order_seq_cst, memory_order_seq_cst) +#define ATOMIC_COMPARE_EXCHANGE_WEAK(T, ...) \ + PARAM5(atomic_compare_exchange_weak_explicit, __VA_ARGS__, memory_order_seq_cst, memory_order_seq_cst) /* Atomics using GCC intrinsics */ #elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) && !defined(__QNXNTO__) -inline int ExchangeInt(volatile int *ptr, int newval) -{ return __sync_lock_test_and_set(ptr, newval); } -inline void *ExchangePtr(XchgPtr *ptr, void *newval) -{ return __sync_lock_test_and_set(ptr, newval); } - +enum almemory_order { + almemory_order_relaxed, + almemory_order_consume, + almemory_order_acquire, + almemory_order_release, + almemory_order_acq_rel, + almemory_order_seq_cst +}; #define ATOMIC(T) struct { T volatile value; } #define ATOMIC_INIT(_val, _newval) do { (_val)->value = (_newval); } while(0) #define ATOMIC_INIT_STATIC(_newval) {(_newval)} -#define ATOMIC_LOAD(_val) __extension__({ \ +#define ATOMIC_LOAD(_val, ...) __extension__({ \ __typeof((_val)->value) _r = (_val)->value; \ __asm__ __volatile__("" ::: "memory"); \ _r; \ }) -#define ATOMIC_STORE(_val, _newval) do { \ - __asm__ __volatile__("" ::: "memory"); \ - (_val)->value = (_newval); \ +#define ATOMIC_STORE(_val, _newval, ...) do { \ + __asm__ __volatile__("" ::: "memory"); \ + (_val)->value = (_newval); \ } while(0) -#define ATOMIC_ADD(T, _val, _incr) __extension__({ \ +#define ATOMIC_ADD(T, _val, _incr, ...) __extension__({ \ static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \ __sync_fetch_and_add(&(_val)->value, (_incr)); \ }) -#define ATOMIC_SUB(T, _val, _decr) __extension__({ \ +#define ATOMIC_SUB(T, _val, _decr, ...) __extension__({ \ static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \ __sync_fetch_and_sub(&(_val)->value, (_decr)); \ }) -#define ATOMIC_EXCHANGE(T, _val, _newval) __extension__({ \ +#define ATOMIC_EXCHANGE(T, _val, _newval, ...) __extension__({ \ static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \ __sync_lock_test_and_set(&(_val)->value, (_newval)); \ }) -#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval) __extension__({ \ +#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval, ...) __extension__({ \ static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \ T _o = *(_oldval); \ *(_oldval) = __sync_val_compare_and_swap(&(_val)->value, _o, (_newval)); \ @@ -112,41 +119,38 @@ inline void *ExchangePtr(XchgPtr *ptr, void *newval) ) -inline int ExchangeInt(volatile int *dest, int newval) -{ int ret; WRAP_XCHG("l", ret, dest, newval); return ret; } - -#ifdef __i386__ -inline void *ExchangePtr(XchgPtr *dest, void *newval) -{ void *ret; WRAP_XCHG("l", ret, dest, newval); return ret; } -#else -inline void *ExchangePtr(XchgPtr *dest, void *newval) -{ void *ret; WRAP_XCHG("q", ret, dest, newval); return ret; } -#endif - +enum almemory_order { + almemory_order_relaxed, + almemory_order_consume, + almemory_order_acquire, + almemory_order_release, + almemory_order_acq_rel, + almemory_order_seq_cst +}; #define ATOMIC(T) struct { T volatile value; } #define ATOMIC_INIT(_val, _newval) do { (_val)->value = (_newval); } while(0) #define ATOMIC_INIT_STATIC(_newval) {(_newval)} -#define ATOMIC_LOAD(_val) __extension__({ \ +#define ATOMIC_LOAD(_val, ...) __extension__({ \ __typeof((_val)->value) _r = (_val)->value; \ __asm__ __volatile__("" ::: "memory"); \ _r; \ }) -#define ATOMIC_STORE(_val, _newval) do { \ - __asm__ __volatile__("" ::: "memory"); \ - (_val)->value = (_newval); \ +#define ATOMIC_STORE(_val, _newval, ...) do { \ + __asm__ __volatile__("" ::: "memory"); \ + (_val)->value = (_newval); \ } while(0) -#define ATOMIC_ADD(T, _val, _incr) __extension__({ \ +#define ATOMIC_ADD(T, _val, _incr, ...) __extension__({ \ static_assert(sizeof(T)==4, "Type "#T" has incorrect size!"); \ static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \ T _r; \ WRAP_ADD(_r, &(_val)->value, (T)(_incr)); \ _r; \ }) -#define ATOMIC_SUB(T, _val, _decr) __extension__({ \ +#define ATOMIC_SUB(T, _val, _decr, ...) __extension__({ \ static_assert(sizeof(T)==4, "Type "#T" has incorrect size!"); \ static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \ T _r; \ @@ -154,7 +158,7 @@ inline void *ExchangePtr(XchgPtr *dest, void *newval) _r; \ }) -#define ATOMIC_EXCHANGE(T, _val, _newval) __extension__({ \ +#define ATOMIC_EXCHANGE(T, _val, _newval, ...) __extension__({ \ static_assert(sizeof(T)==4 || sizeof(T)==8, "Type "#T" has incorrect size!"); \ static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \ T _r; \ @@ -162,7 +166,7 @@ inline void *ExchangePtr(XchgPtr *dest, void *newval) else if(sizeof(T) == 8) WRAP_XCHG("q", _r, &(_val)->value, (T)(_newval)); \ _r; \ }) -#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval) __extension__({ \ +#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval, ...) __extension__({ \ static_assert(sizeof(T)==4 || sizeof(T)==8, "Type "#T" has incorrect size!"); \ static_assert(sizeof(T)==sizeof((_val)->value), "Type "#T" has incorrect size!"); \ T _old = *(_oldval); \ @@ -222,42 +226,40 @@ inline bool CompareAndSwap64(volatile LONGLONG *dest, LONGLONG newval, LONGLONG #define WRAP_XCHG(T, _func, _ptr, _newval) ((T(*)(T volatile*,T))_func)((_ptr), (_newval)) #define WRAP_CMPXCHG(T, _func, _ptr, _newval, _oldval) ((bool(*)(T volatile*,T,T*))_func)((_ptr), (_newval), (_oldval)) -inline int ExchangeInt(volatile int *ptr, int newval) -{ return WRAP_XCHG(int,AtomicSwap32,ptr,newval); } - -#ifdef _WIN64 -inline void *ExchangePtr(XchgPtr *ptr, void *newval) -{ return WRAP_XCHG(void*,AtomicSwap64,ptr,newval); } -#else -inline void *ExchangePtr(XchgPtr *ptr, void *newval) -{ return WRAP_XCHG(void*,AtomicSwap32,ptr,newval); } -#endif +enum almemory_order { + almemory_order_relaxed, + almemory_order_consume, + almemory_order_acquire, + almemory_order_release, + almemory_order_acq_rel, + almemory_order_seq_cst +}; #define ATOMIC(T) struct { T volatile value; } #define ATOMIC_INIT(_val, _newval) do { (_val)->value = (_newval); } while(0) #define ATOMIC_INIT_STATIC(_newval) {(_newval)} -#define ATOMIC_LOAD(_val) ((_val)->value) -#define ATOMIC_STORE(_val, _newval) do { \ - (_val)->value = (_newval); \ +#define ATOMIC_LOAD(_val, ...) ((_val)->value) +#define ATOMIC_STORE(_val, _newval, ...) do { \ + (_val)->value = (_newval); \ } while(0) int _al_invalid_atomic_size(); /* not defined */ -#define ATOMIC_ADD(T, _val, _incr) \ +#define ATOMIC_ADD(T, _val, _incr, ...) \ ((sizeof(T)==4) ? WRAP_ADDSUB(T, AtomicAdd32, &(_val)->value, (_incr)) : \ (T)_al_invalid_atomic_size()) -#define ATOMIC_SUB(T, _val, _decr) \ +#define ATOMIC_SUB(T, _val, _decr, ...) \ ((sizeof(T)==4) ? WRAP_ADDSUB(T, AtomicSub32, &(_val)->value, (_decr)) : \ (T)_al_invalid_atomic_size()) -#define ATOMIC_EXCHANGE(T, _val, _newval) \ +#define ATOMIC_EXCHANGE(T, _val, _newval, ...) \ ((sizeof(T)==4) ? WRAP_XCHG(T, AtomicSwap32, &(_val)->value, (_newval)) : \ (sizeof(T)==8) ? WRAP_XCHG(T, AtomicSwap64, &(_val)->value, (_newval)) : \ (T)_al_invalid_atomic_size()) -#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval) \ +#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval, ...) \ ((sizeof(T)==4) ? WRAP_CMPXCHG(T, CompareAndSwap32, &(_val)->value, (_newval), (_oldval)) : \ (sizeof(T)==8) ? WRAP_CMPXCHG(T, CompareAndSwap64, &(_val)->value, (_newval), (_oldval)) : \ (bool)_al_invalid_atomic_size()) @@ -273,26 +275,22 @@ int _al_invalid_atomic_size(); /* not defined */ #define ATOMIC_LOAD_UNSAFE(_val) (0) #define ATOMIC_STORE_UNSAFE(_val, _newval) ((void)0) -#define ATOMIC_LOAD(_val) (0) -#define ATOMIC_STORE(_val, _newval) ((void)0) +#define ATOMIC_LOAD(_val, ...) (0) +#define ATOMIC_STORE(_val, _newval, ...) ((void)0) -#define ATOMIC_ADD(T, _val, _incr) (0) -#define ATOMIC_SUB(T, _val, _decr) (0) +#define ATOMIC_ADD(T, _val, _incr, ...) (0) +#define ATOMIC_SUB(T, _val, _decr, ...) (0) -#define ATOMIC_EXCHANGE(T, _val, _newval) (0) -#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval) (0) +#define ATOMIC_EXCHANGE(T, _val, _newval, ...) (0) +#define ATOMIC_COMPARE_EXCHANGE_STRONG(T, _val, _oldval, _newval, ...) (0) #endif /* If no weak cmpxchg is provided (not all systems will have one), substitute a * strong cmpxchg. */ #ifndef ATOMIC_COMPARE_EXCHANGE_WEAK -#define ATOMIC_COMPARE_EXCHANGE_WEAK(a, b, c, d) ATOMIC_COMPARE_EXCHANGE_STRONG(a, b, c, d) +#define ATOMIC_COMPARE_EXCHANGE_WEAK ATOMIC_COMPARE_EXCHANGE_STRONG #endif -/* This is *NOT* atomic, but is a handy utility macro to compare-and-swap non- - * atomic variables. */ -#define COMPARE_EXCHANGE(_val, _oldval, _newval) ((*(_val) == *(_oldval)) ? ((*(_val)=(_newval)),true) : ((*(_oldval)=*(_val)),false)) - typedef unsigned int uint; typedef ATOMIC(uint) RefCount; @@ -306,6 +304,29 @@ inline uint IncrementRef(RefCount *ptr) inline uint DecrementRef(RefCount *ptr) { return ATOMIC_SUB(uint, ptr, 1)-1; } + +/* NOTE: Not atomic! */ +inline int ExchangeInt(volatile int *ptr, int newval) +{ + int old = *ptr; + *ptr = newval; + return old; +} + +typedef void *volatile XchgPtr; +/* NOTE: Not atomic! */ +inline void *ExchangePtr(XchgPtr *ptr, void *newval) +{ + void *old = *ptr; + *ptr = newval; + return old; +} + +/* This is *NOT* atomic, but is a handy utility macro to compare-and-swap non- + * atomic variables. */ +#define COMPARE_EXCHANGE(_val, _oldval, _newval) ((*(_val) == *(_oldval)) ? ((*(_val)=(_newval)),true) : ((*(_oldval)=*(_val)),false)) + + #ifdef __cplusplus } #endif diff --git a/libs/openal-soft/include/static_assert.h b/libs/openal-soft/include/static_assert.h index 65283cf0..bf0ce065 100644 --- a/libs/openal-soft/include/static_assert.h +++ b/libs/openal-soft/include/static_assert.h @@ -10,7 +10,11 @@ #else #define CTASTR2(_pre,_post) _pre##_post #define CTASTR(_pre,_post) CTASTR2(_pre,_post) +#if defined(__COUNTER__) #define static_assert(_cond, _msg) typedef struct { int CTASTR(static_assert_failed_at_line_,__LINE__) : !!(_cond); } CTASTR(static_assertion_,__COUNTER__) +#else +#define static_assert(_cond, _msg) struct { int CTASTR(static_assert_failed_at_line_,__LINE__) : !!(_cond); } +#endif #endif #endif diff --git a/libs/openal-soft/include/threads.h b/libs/openal-soft/include/threads.h index 9dfb242d..a11405f7 100644 --- a/libs/openal-soft/include/threads.h +++ b/libs/openal-soft/include/threads.h @@ -234,7 +234,7 @@ void altss_delete(altss_t tss_id); int altimespec_get(struct timespec *ts, int base); -void al_nssleep(time_t sec, long nsec); +void al_nssleep(unsigned long nsec); #ifdef __cplusplus } diff --git a/libs/openal-soft/utils/alsoft-config/mainwindow.cpp b/libs/openal-soft/utils/alsoft-config/mainwindow.cpp index 1d5a3dcd..01f59e4b 100644 --- a/libs/openal-soft/utils/alsoft-config/mainwindow.cpp +++ b/libs/openal-soft/utils/alsoft-config/mainwindow.cpp @@ -1,3 +1,6 @@ + +#include "config.h" + #include #include #include @@ -10,26 +13,92 @@ static const struct { char backend_name[16]; char menu_string[32]; } backendMenuList[] = { -#ifdef Q_OS_WIN32 - { "mmdevapi", "Add MMDevAPI" }, - { "dsound", "Add DirectSound" }, - { "winmm", "Add Windows Multimedia" }, +#ifdef HAVE_JACK + { "jack", "Add JACK" }, #endif -#ifdef Q_OS_MAC +#ifdef HAVE_PULSEAUDIO + { "pulse", "Add PulseAudio" }, +#endif +#ifdef HAVE_ALSA + { "alsa", "Add ALSA" }, +#endif +#ifdef HAVE_COREAUDIO { "core", "Add CoreAudio" }, #endif - { "pulse", "Add PulseAudio" }, -#ifdef Q_OS_UNIX - { "alsa", "Add ALSA" }, +#ifdef HAVE_OSS { "oss", "Add OSS" }, +#endif +#ifdef HAVE_SOLARIS { "solaris", "Add Solaris" }, +#endif +#ifdef HAVE_SNDIO { "sndio", "Add SndIO" }, +#endif +#ifdef HAVE_QSA { "qsa", "Add QSA" }, #endif +#ifdef HAVE_MMDEVAPI + { "mmdevapi", "Add MMDevAPI" }, +#endif +#ifdef HAVE_DSOUND + { "dsound", "Add DirectSound" }, +#endif +#ifdef HAVE_WINMM + { "winmm", "Add Windows Multimedia" }, +#endif +#ifdef HAVE_PORTAUDIO { "port", "Add PortAudio" }, +#endif +#ifdef HAVE_OPENSL { "opensl", "Add OpenSL" }, +#endif + { "null", "Add Null Output" }, +#ifdef HAVE_WAVE { "wave", "Add Wave Writer" }, +#endif + { "", "" } +}; + +static const struct { + const char name[64]; + const char value[16]; +} speakerModeList[] = { + { "Autodetect", "" }, + { "Mono", "mono" }, + { "Stereo", "stereo" }, + { "Quadrophonic", "quad" }, + { "5.1 Surround (Side)", "surround51" }, + { "5.1 Surround (Rear)", "surround51rear" }, + { "6.1 Surround", "surround61" }, + { "7.1 Surround", "surround71" }, + + { "", "" } +}, sampleTypeList[] = { + { "Autodetect", "" }, + { "8-bit int", "int8" }, + { "8-bit uint", "uint8" }, + { "16-bit int", "int16" }, + { "16-bit uint", "uint16" }, + { "32-bit int", "int32" }, + { "32-bit uint", "uint32" }, + { "32-bit float", "float32" }, + + { "", "" } +}, resamplerList[] = { + { "Default", "" }, + { "Point (low quality, very fast)", "point" }, + { "Linear (basic quality, fast)", "linear" }, + { "4-Point Sinc (good quality)", "sinc4" }, + { "8-Point Sinc (high quality, slow)", "sinc8" }, + { "Band-limited Sinc (very high quality, very slow)", "bsinc" }, + + { "", "" } +}, stereoModeList[] = { + { "Autodetect", "" }, + { "Speakers", "speakers" }, + { "Headphones", "headphones" }, + { "", "" } }; @@ -104,11 +173,65 @@ MainWindow::MainWindow(QWidget *parent) : mSourceCountValidator(NULL), mEffectSlotValidator(NULL), mSourceSendValidator(NULL), - mSampleRateValidator(NULL), - mReverbBoostValidator(NULL) + mSampleRateValidator(NULL) { ui->setupUi(this); + for(int i = 0;speakerModeList[i].name[0];i++) + ui->channelConfigCombo->addItem(speakerModeList[i].name); + ui->channelConfigCombo->adjustSize(); + for(int i = 0;sampleTypeList[i].name[0];i++) + ui->sampleFormatCombo->addItem(sampleTypeList[i].name); + ui->sampleFormatCombo->adjustSize(); + for(int i = 0;resamplerList[i].name[0];i++) + ui->resamplerComboBox->addItem(resamplerList[i].name); + ui->resamplerComboBox->adjustSize(); + for(int i = 0;stereoModeList[i].name[0];i++) + ui->stereoModeCombo->addItem(stereoModeList[i].name); + ui->stereoModeCombo->adjustSize(); + + ui->hrtfStateComboBox->adjustSize(); + +#if !defined(HAVE_NEON) && !defined(HAVE_SSE) + ui->cpuExtDisabledLabel->move(ui->cpuExtDisabledLabel->x(), ui->cpuExtDisabledLabel->y() - 60); +#else + ui->cpuExtDisabledLabel->setVisible(false); +#endif + +#ifndef HAVE_NEON + +#ifndef HAVE_SSE4_1 +#ifndef HAVE_SSE3 +#ifndef HAVE_SSE2 +#ifndef HAVE_SSE + ui->enableSSECheckBox->setVisible(false); +#endif /* !SSE */ + ui->enableSSE2CheckBox->setVisible(false); +#endif /* !SSE2 */ + ui->enableSSE3CheckBox->setVisible(false); +#endif /* !SSE3 */ + ui->enableSSE41CheckBox->setVisible(false); +#endif /* !SSE4.1 */ + ui->enableNeonCheckBox->setVisible(false); + +#else /* !Neon */ + +#ifndef HAVE_SSE4_1 +#ifndef HAVE_SSE3 +#ifndef HAVE_SSE2 +#ifndef HAVE_SSE + ui->enableNeonCheckBox->move(ui->enableNeonCheckBox->x(), ui->enableNeonCheckBox->y() - 30); + ui->enableSSECheckBox->setVisible(false); +#endif /* !SSE */ + ui->enableSSE2CheckBox->setVisible(false); +#endif /* !SSE2 */ + ui->enableSSE3CheckBox->setVisible(false); +#endif /* !SSE3 */ + ui->enableSSE41CheckBox->setVisible(false); +#endif /* !SSE4.1 */ + +#endif + mPeriodSizeValidator = new QIntValidator(64, 8192, this); ui->periodSizeEdit->setValidator(mPeriodSizeValidator); mPeriodCountValidator = new QIntValidator(2, 16, this); @@ -123,9 +246,6 @@ MainWindow::MainWindow(QWidget *parent) : mSampleRateValidator = new QIntValidator(8000, 192000, this); ui->sampleRateCombo->lineEdit()->setValidator(mSampleRateValidator); - mReverbBoostValidator = new QDoubleValidator(-12.0, +12.0, 1, this); - ui->reverbBoostEdit->setValidator(mReverbBoostValidator); - connect(ui->actionLoad, SIGNAL(triggered()), this, SLOT(loadConfigFromFile())); connect(ui->actionSave_As, SIGNAL(triggered()), this, SLOT(saveConfigAsFile())); @@ -146,9 +266,6 @@ MainWindow::MainWindow(QWidget *parent) : ui->disabledBackendList->setContextMenuPolicy(Qt::CustomContextMenu); connect(ui->disabledBackendList, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showDisabledBackendMenu(QPoint))); - connect(ui->reverbBoostSlider, SIGNAL(valueChanged(int)), this, SLOT(updateReverbBoostEdit(int))); - connect(ui->reverbBoostEdit, SIGNAL(textEdited(QString)), this, SLOT(updateReverbBoostSlider(QString))); - loadConfig(getDefaultConfigName()); } @@ -161,7 +278,6 @@ MainWindow::~MainWindow() delete mEffectSlotValidator; delete mSourceSendValidator; delete mSampleRateValidator; - delete mReverbBoostValidator; } void MainWindow::loadConfigFromFile() @@ -179,12 +295,19 @@ void MainWindow::loadConfig(const QString &fname) ui->sampleFormatCombo->setCurrentIndex(0); if(sampletype.isEmpty() == false) { - for(int i = 1;i < ui->sampleFormatCombo->count();i++) + for(int i = 0;sampleTypeList[i].name[i];i++) { - QString item = ui->sampleFormatCombo->itemText(i); - if(item.startsWith(sampletype)) + if(sampletype == sampleTypeList[i].value) { - ui->sampleFormatCombo->setCurrentIndex(i); + for(int j = 1;j < ui->sampleFormatCombo->count();j++) + { + QString item = ui->sampleFormatCombo->itemText(j); + if(item == sampleTypeList[i].name) + { + ui->sampleFormatCombo->setCurrentIndex(j); + break; + } + } break; } } @@ -194,12 +317,19 @@ void MainWindow::loadConfig(const QString &fname) ui->channelConfigCombo->setCurrentIndex(0); if(channelconfig.isEmpty() == false) { - for(int i = 1;i < ui->channelConfigCombo->count();i++) + for(int i = 0;speakerModeList[i].name[i];i++) { - QString item = ui->channelConfigCombo->itemText(i); - if(item.startsWith(channelconfig)) + if(channelconfig == speakerModeList[i].value) { - ui->channelConfigCombo->setCurrentIndex(i); + for(int j = 1;j < ui->channelConfigCombo->count();j++) + { + QString item = ui->channelConfigCombo->itemText(j); + if(item == speakerModeList[i].name) + { + ui->channelConfigCombo->setCurrentIndex(j); + break; + } + } break; } } @@ -222,18 +352,49 @@ void MainWindow::loadConfig(const QString &fname) ui->srcSendLineEdit->insert(settings.value("sends").toString()); QString resampler = settings.value("resampler").toString().trimmed(); - if(resampler.isEmpty()) - ui->resamplerComboBox->setCurrentIndex(0); - else + ui->resamplerComboBox->setCurrentIndex(0); + if(resampler.isEmpty() == false) { - for(int i = 1;i < ui->resamplerComboBox->count();i++) + /* The "cubic" resampler is no longer supported. It's been replaced by + * "sinc4". */ + if(resampler == "cubic") + resampler = "sinc4"; + + for(int i = 0;resamplerList[i].name[i];i++) { - QString item = ui->resamplerComboBox->itemText(i); - int end = item.indexOf(' '); - if(end < 0) end = item.size(); - if(resampler.size() == end && resampler.compare(item.leftRef(end), Qt::CaseInsensitive) == 0) + if(resampler == resamplerList[i].value) { - ui->resamplerComboBox->setCurrentIndex(i); + for(int j = 1;j < ui->resamplerComboBox->count();j++) + { + QString item = ui->resamplerComboBox->itemText(j); + if(item == resamplerList[i].name) + { + ui->resamplerComboBox->setCurrentIndex(j); + break; + } + } + break; + } + } + } + + QString stereomode = settings.value("stereo-mode").toString().trimmed(); + ui->stereoModeCombo->setCurrentIndex(0); + if(stereomode.isEmpty() == false) + { + for(int i = 0;stereoModeList[i].name[i];i++) + { + if(stereomode == stereoModeList[i].value) + { + for(int j = 1;j < ui->stereoModeCombo->count();j++) + { + QString item = ui->stereoModeCombo->itemText(j); + if(item == stereoModeList[i].name) + { + ui->stereoModeCombo->setCurrentIndex(j); + break; + } + } break; } } @@ -262,17 +423,18 @@ void MainWindow::loadConfig(const QString &fname) disabledCpuExts.begin(), std::mem_fun_ref(&QString::trimmed)); ui->enableSSECheckBox->setChecked(!disabledCpuExts.contains("sse", Qt::CaseInsensitive)); ui->enableSSE2CheckBox->setChecked(!disabledCpuExts.contains("sse2", Qt::CaseInsensitive)); + ui->enableSSE3CheckBox->setChecked(!disabledCpuExts.contains("sse3", Qt::CaseInsensitive)); ui->enableSSE41CheckBox->setChecked(!disabledCpuExts.contains("sse4.1", Qt::CaseInsensitive)); ui->enableNeonCheckBox->setChecked(!disabledCpuExts.contains("neon", Qt::CaseInsensitive)); if(settings.value("hrtf").toString() == QString()) - ui->hrtfEnableButton->setChecked(true); + ui->hrtfStateComboBox->setCurrentIndex(0); else { if(settings.value("hrtf", true).toBool()) - ui->hrtfForceButton->setChecked(true); + ui->hrtfStateComboBox->setCurrentIndex(1); else - ui->hrtfDisableButton->setChecked(true); + ui->hrtfStateComboBox->setCurrentIndex(2); } QStringList hrtf_tables = settings.value("hrtf_tables").toStringList(); @@ -323,8 +485,6 @@ void MainWindow::loadConfig(const QString &fname) } ui->emulateEaxCheckBox->setChecked(settings.value("reverb/emulate-eax", false).toBool()); - ui->reverbBoostEdit->clear(); - ui->reverbBoostEdit->insert(settings.value("reverb/boost").toString()); QStringList excludefx = settings.value("excludefx").toStringList(); if(excludefx.size() == 1) @@ -371,15 +531,27 @@ void MainWindow::saveConfig(const QString &fname) const } QString str = ui->sampleFormatCombo->currentText(); - str.truncate(str.indexOf('-')); - settings.setValue("sample-type", str.trimmed()); + for(int i = 0;sampleTypeList[i].name[0];i++) + { + if(str == sampleTypeList[i].name) + { + settings.setValue("sample-type", sampleTypeList[i].value); + break; + } + } str = ui->channelConfigCombo->currentText(); - str.truncate(str.indexOf('-')); - settings.setValue("channels", str.trimmed()); + for(int i = 0;speakerModeList[i].name[0];i++) + { + if(str == speakerModeList[i].name) + { + settings.setValue("channels", speakerModeList[i].value); + break; + } + } uint rate = ui->sampleRateCombo->currentText().toUInt(); - if(rate == 0) + if(!(rate > 0)) settings.setValue("frequency", QString()); else settings.setValue("frequency", rate); @@ -390,12 +562,24 @@ void MainWindow::saveConfig(const QString &fname) const settings.setValue("sources", ui->srcCountLineEdit->text()); settings.setValue("slots", ui->effectSlotLineEdit->text()); - if(ui->resamplerComboBox->currentIndex() == 0) - settings.setValue("resampler", QString()); - else + str = ui->resamplerComboBox->currentText(); + for(int i = 0;resamplerList[i].name[0];i++) { - str = ui->resamplerComboBox->currentText(); - settings.setValue("resampler", str.split(' ').first().toLower()); + if(str == resamplerList[i].name) + { + settings.setValue("resampler", resamplerList[i].value); + break; + } + } + + str = ui->stereoModeCombo->currentText(); + for(int i = 0;stereoModeList[i].name[0];i++) + { + if(str == stereoModeList[i].name) + { + settings.setValue("stereo-mode", stereoModeList[i].value); + break; + } } QStringList strlist; @@ -403,15 +587,17 @@ void MainWindow::saveConfig(const QString &fname) const strlist.append("sse"); if(!ui->enableSSE2CheckBox->isChecked()) strlist.append("sse2"); + if(!ui->enableSSE3CheckBox->isChecked()) + strlist.append("sse3"); if(!ui->enableSSE41CheckBox->isChecked()) strlist.append("sse4.1"); if(!ui->enableNeonCheckBox->isChecked()) strlist.append("neon"); settings.setValue("disable-cpu-exts", strlist.join(QChar(','))); - if(ui->hrtfForceButton->isChecked()) + if(ui->hrtfStateComboBox->currentIndex() == 1) settings.setValue("hrtf", "true"); - else if(ui->hrtfDisableButton->isChecked()) + else if(ui->hrtfStateComboBox->currentIndex() == 2) settings.setValue("hrtf", "false"); else settings.setValue("hrtf", QString()); @@ -449,12 +635,6 @@ void MainWindow::saveConfig(const QString &fname) const else settings.setValue("reverb/emulate-eax", QString()/*"false"*/); - // TODO: Remove check when we can properly match global values. - if(ui->reverbBoostSlider->sliderPosition() == 0) - settings.setValue("reverb/boost", QString()); - else - settings.setValue("reverb/boost", ui->reverbBoostEdit->text()); - strlist.clear(); if(!ui->enableEaxReverbCheck->isChecked()) strlist.append("eaxreverb"); @@ -645,16 +825,3 @@ void MainWindow::showDisabledBackendMenu(QPoint pt) ui->disabledBackendList->addItem(iter.value()); } } - -void MainWindow::updateReverbBoostEdit(int value) -{ - ui->reverbBoostEdit->clear(); - if(value != 0) - ui->reverbBoostEdit->insert(QString::number(value/10.0, 'f', 1)); -} - -void MainWindow::updateReverbBoostSlider(QString value) -{ - int pos = int(value.toFloat()*10.0f); - ui->reverbBoostSlider->setSliderPosition(pos); -} diff --git a/libs/openal-soft/utils/alsoft-config/mainwindow.h b/libs/openal-soft/utils/alsoft-config/mainwindow.h index 0421aabb..b5a1ae7c 100644 --- a/libs/openal-soft/utils/alsoft-config/mainwindow.h +++ b/libs/openal-soft/utils/alsoft-config/mainwindow.h @@ -35,9 +35,6 @@ private slots: void showEnabledBackendMenu(QPoint pt); void showDisabledBackendMenu(QPoint pt); - void updateReverbBoostEdit(int size); - void updateReverbBoostSlider(QString value); - private: Ui::MainWindow *ui; @@ -47,7 +44,6 @@ private: QValidator *mEffectSlotValidator; QValidator *mSourceSendValidator; QValidator *mSampleRateValidator; - QValidator *mReverbBoostValidator; void loadConfig(const QString &fname); void saveConfig(const QString &fname) const; diff --git a/libs/openal-soft/utils/alsoft-config/mainwindow.ui b/libs/openal-soft/utils/alsoft-config/mainwindow.ui index 3c92abf6..78564ada 100644 --- a/libs/openal-soft/utils/alsoft-config/mainwindow.ui +++ b/libs/openal-soft/utils/alsoft-config/mainwindow.ui @@ -57,8 +57,8 @@ 120 - 20 - 188 + 50 + 78 22 @@ -69,52 +69,12 @@ float and converted to the output sample type as needed. QComboBox::AdjustToContents - - - - Autodetect - - - - - - int8 - signed 8-bit int - - - - - uint8 - unsigned 8-bit int - - - - - int16 - signed 16-bit int - - - - - uint16 - unsigned 16-bit int - - - - - int32 - signed 32-bit int - - - - - uint32 - unsigned 32-bit int - - - - - float32 - 32-bit float - - 10 - 20 + 50 101 21 @@ -130,7 +90,7 @@ float and converted to the output sample type as needed. 10 - 50 + 20 101 21 @@ -146,8 +106,8 @@ float and converted to the output sample type as needed. 120 - 50 - 227 + 20 + 78 22 @@ -159,48 +119,13 @@ to stereo output. QComboBox::AdjustToContents - - - - Autodetect - - - - - - mono - 1-channel Mono - - - - - stereo - 2-channel Stereo - - - - - quad - 4-channel Quadraphonic - - - - - surround51 - 5.1 Surround Sound - - - - - surround61 - 6.1 Surround Sound - - - - - surround71 - 7.1 Surround Sound - - - 120 - 80 - 111 + 370 + 20 + 96 22 @@ -218,37 +143,12 @@ to stereo output. - - Autodetect - + Autodetect - 96000 - - - - - 48000 - - - - - 44100 - - - - - 32000 - - - - - 22050 - - - - - 16000 + 8000 @@ -258,16 +158,36 @@ to stereo output. - 8000 + 16000 + + + + + 22050 + + + + + 32000 + + + + + 44100 + + + + + 48000 - 10 - 80 - 101 + 280 + 20 + 81 21 @@ -282,73 +202,20 @@ to stereo output. 10 - 200 + 180 511 - 161 + 191 HRTF (Stereo only) - - - - 20 - 30 - 71 - 21 - - - - Allows applications to request HRTF mixing. - - - Enable - - - true - - - - - - 20 - 50 - 71 - 21 - - - - Does not allow HRTF mixing, even when requested. - - - Disable - - - - - - 20 - 70 - 71 - 21 - - - - Attempts to force HRTF mixing, even if applications request not -to do it. This may override the channel configuration and -sample rate. - - - Force - - - 110 + 20 30 - 301 + 391 121 @@ -378,7 +245,7 @@ contain these markers, which will be replaced as needed: - 419 + 420 30 81 25 @@ -399,7 +266,7 @@ contain these markers, which will be replaced as needed: - 419 + 420 60 81 25 @@ -414,12 +281,56 @@ contain these markers, which will be replaced as needed: + + + + 110 + 160 + 161 + 22 + + + + QComboBox::AdjustToContentsOnFirstShow + + + + Application preference + + + + + Force on + + + + + Force off + + + + + + + 30 + 160 + 71 + 21 + + + + HRTF Mode: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + 10 - 110 + 90 511 91 @@ -590,6 +501,37 @@ frames needed for each mixing update. + + + + 280 + 50 + 81 + 21 + + + + Stereo Mode: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 370 + 50 + 78 + 22 + + + + How to treat stereo output. As headphones, HRTF or crossfeed +filters may be used to improve binaural quality, which may not +otherwise be suitable for speakers. + + @@ -737,7 +679,7 @@ value currently possible is 4. 110 120 - 185 + 78 22 @@ -747,34 +689,14 @@ value currently possible is 4. QComboBox::AdjustToContents - - - - Default - - - - - - Point (low quality, fast) - - - - - Linear (basic quality, fast) - - - - - Cubic Spline (good quality) - - - + 10 150 511 - 91 + 121 @@ -788,7 +710,7 @@ be useful for preventing those extensions from being used. - 180 + 100 20 71 31 @@ -805,7 +727,7 @@ be useful for preventing those extensions from being used. 180 - 50 + 20 71 31 @@ -820,7 +742,7 @@ be useful for preventing those extensions from being used. - 260 + 100 50 71 31 @@ -836,7 +758,7 @@ be useful for preventing those extensions from being used. - 260 + 340 20 71 31 @@ -849,6 +771,35 @@ be useful for preventing those extensions from being used. true + + + + 260 + 20 + 71 + 31 + + + + SSE3 + + + true + + + + + + 101 + 80 + 311 + 31 + + + + <html><head/><body><p align="center"><span style=" font-style:italic;">No support enabled for CPU Extensions</span></p></body></html> + + @@ -956,87 +907,11 @@ some quality. Emulate EAX Reverb: - - - - 10 - 100 - 511 - 61 - - - - Global amplification for reverb output, expressed in decibels. -+6 will be a scale of (approximately) 2x, +12 will be a scale of -4x, etc. Similarly, -6 will be about half, and -12 about 1/4th. A -value of 0 means no change. - - - Reverb Boost - - - - - 10 - 30 - 391 - 23 - - - - - - - -120 - - - 120 - - - Qt::Horizontal - - - QSlider::TicksBelow - - - 10 - - - - - - 410 - 30 - 51 - 22 - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 0.0 - - - - - - 460 - 30 - 31 - 21 - - - - dB - - - 10 - 170 + 100 511 191 diff --git a/libs/openal-soft/utils/makehrtf.c b/libs/openal-soft/utils/makehrtf.c index 0a1bd043..57d8a91a 100644 --- a/libs/openal-soft/utils/makehrtf.c +++ b/libs/openal-soft/utils/makehrtf.c @@ -227,8 +227,7 @@ enum HeadModelT { // Desired output format from the command line. enum OutputFormatT { OF_NONE = 0, - OF_MHR , // OpenAL Soft MHR data set file. - OF_TABLE // OpenAL Soft built-in table file (used when compiling). + OF_MHR // OpenAL Soft MHR data set file. }; // Unsigned integer type. @@ -2089,84 +2088,6 @@ static int StoreMhr (const HrirDataT * hData, const char * filename) { return (1); } -// Store the OpenAL Soft built-in table. -static int StoreTable (const HrirDataT * hData, const char * filename) { - FILE * fp = NULL; - uint step, end, n, j, i; - int hpHist, v; - char text [128 + 1]; - - if ((fp = fopen (filename, "wb")) == NULL) { - fprintf (stderr, "Error: Could not open table file '%s'.\n", filename); - return (0); - } - snprintf (text, 128, "/* Elevation metrics */\n" - "static const ALubyte defaultAzCount[%u] = { ", hData -> mEvCount); - if (! WriteAscii (text, fp, filename)) - return (0); - for (i = 0; i < hData -> mEvCount; i ++) { - snprintf (text, 128, "%u, ", hData -> mAzCount [i]); - if (! WriteAscii (text, fp, filename)) - return (0); - } - snprintf (text, 128, "};\n" - "static const ALushort defaultEvOffset[%u] = { ", hData -> mEvCount); - if (! WriteAscii (text, fp, filename)) - return (0); - for (i = 0; i < hData -> mEvCount; i ++) { - snprintf (text, 128, "%u, ", hData -> mEvOffset [i]); - if (! WriteAscii (text, fp, filename)) - return (0); - } - step = hData -> mIrSize; - end = hData -> mIrCount * step; - n = hData -> mIrPoints; - snprintf (text, 128, "};\n\n" - "/* HRIR Coefficients */\n" - "static const ALshort defaultCoeffs[%u] =\n{\n", hData -> mIrCount * n); - if (! WriteAscii (text, fp, filename)) - return (0); - srand (0x31DF840C); - for (j = 0; j < end; j += step) { - if (! WriteAscii (" ", fp, filename)) - return (0); - hpHist = 0; - for (i = 0; i < n; i ++) { - v = HpTpdfDither (32767.0 * hData -> mHrirs [j + i], & hpHist); - snprintf (text, 128, " %+d,", v); - if (! WriteAscii (text, fp, filename)) - return (0); - } - if (! WriteAscii ("\n", fp, filename)) - return (0); - } - snprintf (text, 128, "};\n\n" - "/* HRIR Delays */\n" - "static const ALubyte defaultDelays[%u] =\n{\n" - " ", hData -> mIrCount); - if (! WriteAscii (text, fp, filename)) - return (0); - for (j = 0; j < hData -> mIrCount; j ++) { - v = (int) fmin (round (hData -> mIrRate * hData -> mHrtds [j]), MAX_HRTD); - snprintf (text, 128, " %d,", v); - if (! WriteAscii (text, fp, filename)) - return (0); - } - if (! WriteAscii ("\n};\n\n" - "/* Default HRTF Definition */\n", fp, filename)) - return (0); - snprintf (text, 128, "static const struct Hrtf DefaultHrtf = {\n" - " %u, %u, %u, defaultAzCount, defaultEvOffset,\n", - hData -> mIrRate, hData -> mIrPoints, hData -> mEvCount); - if (! WriteAscii (text, fp, filename)) - return (0); - if (! WriteAscii (" defaultCoeffs, defaultDelays, NULL\n" - "};\n", fp, filename)) - return (0); - fclose (fp); - return (1); -} - // Process the data set definition to read and validate the data set metrics. static int ProcessMetrics (TokenReaderT * tr, const uint fftSize, const uint truncSize, HrirDataT * hData) { char ident [MAX_IDENT_LEN + 1]; @@ -2583,11 +2504,6 @@ static int ProcessDefinition (const char * inName, const uint outRate, const uin if (! StoreMhr (& hData, expName)) return (0); break; - case OF_TABLE : - fprintf (stderr, "Creating OpenAL Soft table file...\n"); - if (! StoreTable (& hData, expName)) - return (0); - break; default : break; } @@ -2619,8 +2535,6 @@ int main (const int argc, const char * argv []) { fprintf (stdout, "Commands:\n"); fprintf (stdout, " -m, --make-mhr Makes an OpenAL Soft compatible HRTF data set.\n"); fprintf (stdout, " Defaults output to: ./oalsoft_hrtf_%%r.mhr\n"); - fprintf (stdout, " -t, --make-tab Makes the built-in table used when compiling OpenAL Soft.\n"); - fprintf (stdout, " Defaults output to: ./hrtf_tables.inc\n"); fprintf (stdout, " -h, --help Displays this help information.\n\n"); fprintf (stdout, "Options:\n"); fprintf (stdout, " -r= Change the data set sample rate to the specified value and\n"); @@ -2647,12 +2561,6 @@ int main (const int argc, const char * argv []) { else outName = "./oalsoft_hrtf_%r.mhr"; outFormat = OF_MHR; - } else if ((strcmp (argv [1], "--make-tab") == 0) || (strcmp (argv [1], "-t") == 0)) { - if (argc > 3) - outName = argv [3]; - else - outName = "./hrtf_tables.inc"; - outFormat = OF_TABLE; } else { fprintf (stderr, "Error: Invalid command '%s'.\n", argv [1]); return (-1); diff --git a/libs/openal-soft/utils/openal-info.c b/libs/openal-soft/utils/openal-info.c index 61af00f0..5b45ceef 100644 --- a/libs/openal-soft/utils/openal-info.c +++ b/libs/openal-soft/utils/openal-info.c @@ -147,6 +147,35 @@ static void printALCInfo(ALCdevice *device) } } +static void printHRTFInfo(ALCdevice *device) +{ + LPALCGETSTRINGISOFT alcGetStringiSOFT; + ALCint num_hrtfs; + + if(alcIsExtensionPresent(device, "ALC_SOFT_HRTF") == ALC_FALSE) + { + printf("HRTF extension not available\n"); + return; + } + + alcGetStringiSOFT = alcGetProcAddress(device, "alcGetStringiSOFT"); + + alcGetIntegerv(device, ALC_NUM_HRTF_SPECIFIERS_SOFT, 1, &num_hrtfs); + if(!num_hrtfs) + printf("No HRTFs found\n"); + else + { + ALCint i; + printf("Available HRTFs:\n"); + for(i = 0;i < num_hrtfs;++i) + { + const ALCchar *name = alcGetStringiSOFT(device, ALC_HRTF_SPECIFIER_SOFT, i); + printf(" %s\n", name); + } + } + checkALCErrors(device); +} + static void printALInfo(void) { printf("OpenAL vendor string: %s\n", alGetString(AL_VENDOR)); @@ -287,6 +316,7 @@ int main(int argc, char *argv[]) return 1; } printALCInfo(device); + printHRTFInfo(device); context = alcCreateContext(device, NULL); if(!context || alcMakeContextCurrent(context) == ALC_FALSE)