From f40577c9cbf01d640c0a8b77813c95ac477a8a4a Mon Sep 17 00:00:00 2001 From: Martin Felis Date: Thu, 1 Feb 2018 15:53:05 +0100 Subject: [PATCH] Upgraded OpenAL-Soft to 0.18.2 --- love/src/jni/love/Android.mk | 4 +- love/src/jni/openal-soft-1.17.0/Alc/ALu.c | 1321 ----- love/src/jni/openal-soft-1.17.0/Alc/alcRing.c | 129 - .../src/jni/openal-soft-1.17.0/Alc/alstring.h | 45 - .../openal-soft-1.17.0/Alc/backends/base.c | 232 - .../openal-soft-1.17.0/Alc/backends/opensl.c | 424 -- .../Alc/backends/portaudio.c | 469 -- .../openal-soft-1.17.0/Alc/backends/sndio.c | 295 - .../openal-soft-1.17.0/Alc/backends/solaris.c | 288 - .../openal-soft-1.17.0/Alc/backends/wave.c | 377 -- .../openal-soft-1.17.0/Alc/backends/winmm.c | 716 --- .../openal-soft-1.17.0/Alc/effects/autowah.c | 272 - .../openal-soft-1.17.0/Alc/effects/reverb.c | 1779 ------ .../src/jni/openal-soft-1.17.0/Alc/evtqueue.h | 31 - love/src/jni/openal-soft-1.17.0/Alc/helpers.c | 814 --- love/src/jni/openal-soft-1.17.0/Alc/hrtf.c | 820 --- love/src/jni/openal-soft-1.17.0/Alc/hrtf.h | 28 - .../jni/openal-soft-1.17.0/Alc/midi/base.c | 244 - .../jni/openal-soft-1.17.0/Alc/midi/base.h | 133 - .../jni/openal-soft-1.17.0/Alc/midi/dummy.c | 76 - .../openal-soft-1.17.0/Alc/midi/fluidsynth.c | 930 --- .../jni/openal-soft-1.17.0/Alc/midi/sf2load.c | 1377 ----- .../jni/openal-soft-1.17.0/Alc/midi/soft.c | 140 - love/src/jni/openal-soft-1.17.0/Alc/mixer.c | 510 -- love/src/jni/openal-soft-1.17.0/Alc/mixer_c.c | 126 - .../jni/openal-soft-1.17.0/Alc/mixer_defs.h | 65 - .../jni/openal-soft-1.17.0/Alc/mixer_inc.c | 93 - .../jni/openal-soft-1.17.0/Alc/mixer_neon.c | 118 - .../jni/openal-soft-1.17.0/Alc/mixer_sse.c | 202 - .../jni/openal-soft-1.17.0/Alc/mixer_sse41.c | 82 - love/src/jni/openal-soft-1.17.0/Alc/panning.c | 450 -- love/src/jni/openal-soft-1.17.0/Alc/vector.h | 87 - .../OpenAL32/Include/alFilter.h | 112 - .../OpenAL32/Include/alListener.h | 28 - .../OpenAL32/Include/alMain.h | 895 --- .../OpenAL32/Include/alMidi.h | 172 - .../OpenAL32/Include/alSource.h | 147 - .../openal-soft-1.17.0/OpenAL32/Include/alu.h | 236 - .../openal-soft-1.17.0/OpenAL32/alFontsound.c | 1008 ---- .../jni/openal-soft-1.17.0/OpenAL32/alMidi.c | 217 - .../openal-soft-1.17.0/OpenAL32/alPreset.c | 339 -- .../openal-soft-1.17.0/OpenAL32/alSoundfont.c | 454 -- .../openal-soft-1.17.0/OpenAL32/alSource.c | 2912 ---------- love/src/jni/openal-soft-1.17.0/build/.empty | 0 .../openal-soft-1.17.0/cmake/FindDSound.cmake | 33 - .../cmake/FindFluidSynth.cmake | 19 - .../cmake/FindSDL_sound.cmake | 380 -- .../jni/openal-soft-1.17.0/common/uintmap.c | 144 - .../openal-soft-1.17.0/examples/alffplay.c | 1479 ----- .../examples/common/alhelpers.c | 327 -- .../examples/common/alhelpers.h | 51 - .../examples/common/sdl_sound.c | 164 - .../examples/common/sdl_sound.h | 43 - .../openal-soft-1.17.0/hrtf/default-44100.mhr | Bin 53853 -> 0 bytes .../openal-soft-1.17.0/hrtf/default-48000.mhr | Bin 53853 -> 0 bytes .../jni/openal-soft-1.17.0/include/atomic.h | 313 - .../utils/alsoft-config/CMakeLists.txt | 29 - .../utils/alsoft-config/mainwindow.cpp | 660 --- .../utils/alsoft-config/mainwindow.ui | 1464 ----- .../jni/openal-soft-1.17.0/utils/makehrtf.c | 2749 --------- love/src/jni/openal-soft-1.18.2/.gitignore | 7 + love/src/jni/openal-soft-1.18.2/.travis.yml | 70 + .../Alc/ALc.c | 2821 +++++---- love/src/jni/openal-soft-1.18.2/Alc/ALu.c | 1830 ++++++ .../Alc/alcConfig.c | 209 +- love/src/jni/openal-soft-1.18.2/Alc/alcRing.c | 317 + .../src/jni/openal-soft-1.18.2/Alc/alstring.h | 49 + love/src/jni/openal-soft-1.18.2/Alc/ambdec.c | 566 ++ love/src/jni/openal-soft-1.18.2/Alc/ambdec.h | 46 + .../Alc/backends/alsa.c | 234 +- .../openal-soft-1.18.2/Alc/backends/base.c | 81 + .../Alc/backends/base.h | 34 +- .../Alc/backends/coreaudio.c | 511 +- .../Alc/backends/dsound.c | 294 +- .../openal-soft-1.18.2/Alc/backends/jack.c | 640 +++ .../Alc/backends/loopback.c | 15 +- .../Alc/backends/mmdevapi.c | 1059 +++- .../Alc/backends/null.c | 19 +- .../openal-soft-1.18.2/Alc/backends/opensl.c | 1135 ++++ .../Alc/backends/oss.c | 514 +- .../Alc/backends/portaudio.c | 575 ++ .../Alc/backends/pulseaudio.c | 558 +- .../Alc/backends/qsa.c | 804 ++- .../openal-soft-1.18.2/Alc/backends/sndio.c | 346 ++ .../openal-soft-1.18.2/Alc/backends/solaris.c | 363 ++ .../openal-soft-1.18.2/Alc/backends/wave.c | 453 ++ .../openal-soft-1.18.2/Alc/backends/winmm.c | 803 +++ .../jni/openal-soft-1.18.2/Alc/bformatdec.c | 612 ++ .../jni/openal-soft-1.18.2/Alc/bformatdec.h | 75 + .../Alc/bs2b.c | 80 +- love/src/jni/openal-soft-1.18.2/Alc/bsinc.c | 5081 +++++++++++++++++ .../Alc/compat.h | 25 + .../jni/openal-soft-1.18.2/Alc/converter.c | 466 ++ .../jni/openal-soft-1.18.2/Alc/converter.h | 55 + .../Alc/effects/chorus.c | 231 +- .../Alc/effects/compressor.c | 124 +- .../Alc/effects/dedicated.c | 97 +- .../Alc/effects/distortion.c | 180 +- .../Alc/effects/echo.c | 285 +- .../Alc/effects/equalizer.c | 166 +- .../Alc/effects/flanger.c | 232 +- .../Alc/effects/modulator.c | 198 +- .../Alc/effects/null.c | 50 +- .../openal-soft-1.18.2/Alc/effects/reverb.c | 2407 ++++++++ love/src/jni/openal-soft-1.18.2/Alc/helpers.c | 1165 ++++ love/src/jni/openal-soft-1.18.2/Alc/hrtf.c | 1154 ++++ love/src/jni/openal-soft-1.18.2/Alc/hrtf.h | 52 + .../jni/openal-soft-1.18.2/Alc/mastering.c | 255 + love/src/jni/openal-soft-1.18.2/Alc/mixer.c | 671 +++ love/src/jni/openal-soft-1.18.2/Alc/mixer_c.c | 208 + .../jni/openal-soft-1.18.2/Alc/mixer_defs.h | 129 + .../jni/openal-soft-1.18.2/Alc/mixer_inc.c | 114 + .../jni/openal-soft-1.18.2/Alc/mixer_neon.c | 331 ++ .../jni/openal-soft-1.18.2/Alc/mixer_sse.c | 230 + .../Alc/mixer_sse2.c | 20 +- .../jni/openal-soft-1.18.2/Alc/mixer_sse3.c | 97 + .../jni/openal-soft-1.18.2/Alc/mixer_sse41.c | 154 + .../jni/openal-soft-1.18.2/Alc/nfcfilter.c | 418 ++ .../jni/openal-soft-1.18.2/Alc/nfcfilter.h | 37 + love/src/jni/openal-soft-1.18.2/Alc/panning.c | 1271 +++++ .../jni/openal-soft-1.18.2/Alc/uhjfilter.c | 134 + .../jni/openal-soft-1.18.2/Alc/uhjfilter.h | 49 + love/src/jni/openal-soft-1.18.2/Alc/vector.h | 93 + .../Android.mk | 2 + .../CMakeLists.txt | 970 ++-- .../COPYING | 23 +- love/src/jni/openal-soft-1.18.2/ChangeLog | 305 + .../OpenAL32/Include/alAuxEffectSlot.h | 101 +- .../OpenAL32/Include/alBuffer.h | 58 +- .../OpenAL32/Include/alEffect.h | 43 +- .../OpenAL32/Include/alError.h | 0 .../OpenAL32/Include/alFilter.h | 164 + .../OpenAL32/Include/alListener.h | 66 + .../OpenAL32/Include/alMain.h | 1085 ++++ .../OpenAL32/Include/alSource.h | 128 + .../OpenAL32/Include/alThunk.h | 0 .../openal-soft-1.18.2/OpenAL32/Include/alu.h | 516 ++ .../OpenAL32/Include/bs2b.h | 52 +- .../OpenAL32/Include/sample_cvt.h | 0 .../OpenAL32/alAuxEffectSlot.c | 393 +- .../OpenAL32/alBuffer.c | 188 +- .../OpenAL32/alEffect.c | 70 +- .../OpenAL32/alError.c | 13 +- .../OpenAL32/alExtension.c | 29 +- .../OpenAL32/alFilter.c | 166 +- .../OpenAL32/alListener.c | 124 +- .../openal-soft-1.18.2/OpenAL32/alSource.c | 3527 ++++++++++++ .../OpenAL32/alState.c | 307 +- .../OpenAL32/alThunk.c | 55 +- .../OpenAL32/sample_cvt.c | 495 +- .../README | 10 +- .../openal-soft-1.18.2/XCompile-Android.txt | 39 + .../XCompile.txt | 17 +- .../alsoftrc.sample | 367 +- love/src/jni/openal-soft-1.18.2/appveyor.yml | 19 + .../cmake/CheckFileOffsetBits.c | 0 .../cmake/CheckFileOffsetBits.cmake | 8 +- .../cmake/CheckSharedFunctionExists.cmake | 18 +- .../cmake/FindALSA.cmake | 0 .../cmake/FindAudioIO.cmake | 0 .../openal-soft-1.18.2/cmake/FindDSound.cmake | 41 + .../cmake/FindFFmpeg.cmake | 6 + .../openal-soft-1.18.2/cmake/FindJACK.cmake | 60 + .../cmake/FindOSS.cmake | 14 +- .../cmake/FindPortAudio.cmake | 0 .../cmake/FindPulseAudio.cmake | 0 .../cmake/FindQSA.cmake | 0 .../cmake/FindSDL2.cmake | 0 .../cmake/FindSDL_sound.cmake | 429 ++ .../cmake/FindSoundIO.cmake | 0 .../cmake/FindWindowsSDK.cmake | 626 ++ .../common}/align.h | 8 +- .../jni/openal-soft-1.18.2/common/almalloc.c | 62 + .../jni/openal-soft-1.18.2/common/almalloc.h | 21 + .../common/atomic.c | 3 - .../jni/openal-soft-1.18.2/common/atomic.h | 425 ++ .../common}/bool.h | 0 .../jni/openal-soft-1.18.2/common/math_defs.h | 35 + .../common/rwlock.c | 20 +- .../common}/rwlock.h | 9 +- .../common}/static_assert.h | 4 + .../common/threads.c | 143 +- .../common}/threads.h | 10 +- .../jni/openal-soft-1.18.2/common/uintmap.c | 319 ++ .../common}/uintmap.h | 18 +- .../config.h | 32 +- .../config.h.in | 50 +- .../src/jni/openal-soft-1.18.2/docs/3D7.1.txt | 82 + .../jni/openal-soft-1.18.2/docs/ambdec.txt | 189 + .../openal-soft-1.18.2/docs/ambisonics.txt | 126 + .../docs}/env-vars.txt | 10 + .../docs}/hrtf.txt | 2 +- .../openal-soft-1.18.2/examples/alffplay.cpp | 1570 +++++ .../jni/openal-soft-1.18.2/examples/alhrtf.c | 294 + .../examples/allatency.c | 100 +- .../examples/alloopback.c | 46 +- .../openal-soft-1.18.2/examples/alrecord.c | 386 ++ .../examples/alreverb.c | 102 +- .../examples/alstream.c | 136 +- .../openal-soft-1.18.2/examples/altonegen.c | 306 + .../examples/common/alhelpers.c | 116 + .../examples/common/alhelpers.h | 25 + .../openal-soft-1.18.2/hrtf/default-44100.mhr | Bin 0 -> 53853 bytes .../openal-soft-1.18.2/hrtf/default-48000.mhr | Bin 0 -> 53853 bytes .../include/AL/al.h | 0 .../include/AL/alc.h | 0 .../include/AL/alext.h | 70 +- .../include/AL/efx-creative.h | 0 .../include/AL/efx-presets.h | 2 +- .../include/AL/efx.h | 0 .../native-tools/CMakeLists.txt | 8 + .../openal-soft-1.18.2/native-tools/bin2h.c | 100 + .../openal.pc.in | 0 .../openal-soft-1.18.2/presets/3D7.1.ambdec | 43 + .../openal-soft-1.18.2/presets/hexagon.ambdec | 51 + .../presets/itu5.1-nocenter.ambdec | 46 + .../openal-soft-1.18.2/presets/itu5.1.ambdec | 48 + .../openal-soft-1.18.2/presets/presets.txt | 42 + .../presets/rectangle.ambdec | 45 + .../openal-soft-1.18.2/presets/square.ambdec | 45 + love/src/jni/openal-soft-1.18.2/router/al.c | 132 + love/src/jni/openal-soft-1.18.2/router/alc.c | 956 ++++ .../jni/openal-soft-1.18.2/router/router.c | 512 ++ .../jni/openal-soft-1.18.2/router/router.h | 196 + .../utils/CIAIR.def | 0 .../utils/IRC_1005.def | 0 .../utils/MIT_KEMAR.def | 0 .../utils/alsoft-config/CMakeLists.txt | 56 + .../utils/alsoft-config/main.cpp | 0 .../utils/alsoft-config/mainwindow.cpp | 1364 +++++ .../utils/alsoft-config/mainwindow.h | 34 +- .../utils/alsoft-config/mainwindow.ui | 2423 ++++++++ .../jni/openal-soft-1.18.2/utils/bsincgen.c | 412 ++ .../jni/openal-soft-1.18.2/utils/makehrtf.c | 2960 ++++++++++ .../utils/openal-info.c | 128 + love/src/jni/openal-soft-1.18.2/version.cmake | 11 + love/src/jni/openal-soft-1.18.2/version.h | 8 + love/src/jni/openal-soft-1.18.2/version.h.in | 8 + 238 files changed, 51375 insertions(+), 31859 deletions(-) delete mode 100644 love/src/jni/openal-soft-1.17.0/Alc/ALu.c delete mode 100644 love/src/jni/openal-soft-1.17.0/Alc/alcRing.c delete mode 100644 love/src/jni/openal-soft-1.17.0/Alc/alstring.h delete mode 100644 love/src/jni/openal-soft-1.17.0/Alc/backends/base.c delete mode 100644 love/src/jni/openal-soft-1.17.0/Alc/backends/opensl.c delete mode 100644 love/src/jni/openal-soft-1.17.0/Alc/backends/portaudio.c delete mode 100644 love/src/jni/openal-soft-1.17.0/Alc/backends/sndio.c delete mode 100644 love/src/jni/openal-soft-1.17.0/Alc/backends/solaris.c delete mode 100644 love/src/jni/openal-soft-1.17.0/Alc/backends/wave.c delete mode 100644 love/src/jni/openal-soft-1.17.0/Alc/backends/winmm.c delete mode 100644 love/src/jni/openal-soft-1.17.0/Alc/effects/autowah.c delete mode 100644 love/src/jni/openal-soft-1.17.0/Alc/effects/reverb.c delete mode 100644 love/src/jni/openal-soft-1.17.0/Alc/evtqueue.h delete mode 100644 love/src/jni/openal-soft-1.17.0/Alc/helpers.c delete mode 100644 love/src/jni/openal-soft-1.17.0/Alc/hrtf.c delete mode 100644 love/src/jni/openal-soft-1.17.0/Alc/hrtf.h delete mode 100644 love/src/jni/openal-soft-1.17.0/Alc/midi/base.c delete mode 100644 love/src/jni/openal-soft-1.17.0/Alc/midi/base.h delete mode 100644 love/src/jni/openal-soft-1.17.0/Alc/midi/dummy.c delete mode 100644 love/src/jni/openal-soft-1.17.0/Alc/midi/fluidsynth.c delete mode 100644 love/src/jni/openal-soft-1.17.0/Alc/midi/sf2load.c delete mode 100644 love/src/jni/openal-soft-1.17.0/Alc/midi/soft.c delete mode 100644 love/src/jni/openal-soft-1.17.0/Alc/mixer.c delete mode 100644 love/src/jni/openal-soft-1.17.0/Alc/mixer_c.c delete mode 100644 love/src/jni/openal-soft-1.17.0/Alc/mixer_defs.h delete mode 100644 love/src/jni/openal-soft-1.17.0/Alc/mixer_inc.c delete mode 100644 love/src/jni/openal-soft-1.17.0/Alc/mixer_neon.c delete mode 100644 love/src/jni/openal-soft-1.17.0/Alc/mixer_sse.c delete mode 100644 love/src/jni/openal-soft-1.17.0/Alc/mixer_sse41.c delete mode 100644 love/src/jni/openal-soft-1.17.0/Alc/panning.c delete mode 100644 love/src/jni/openal-soft-1.17.0/Alc/vector.h delete mode 100644 love/src/jni/openal-soft-1.17.0/OpenAL32/Include/alFilter.h delete mode 100644 love/src/jni/openal-soft-1.17.0/OpenAL32/Include/alListener.h delete mode 100644 love/src/jni/openal-soft-1.17.0/OpenAL32/Include/alMain.h delete mode 100644 love/src/jni/openal-soft-1.17.0/OpenAL32/Include/alMidi.h delete mode 100644 love/src/jni/openal-soft-1.17.0/OpenAL32/Include/alSource.h delete mode 100644 love/src/jni/openal-soft-1.17.0/OpenAL32/Include/alu.h delete mode 100644 love/src/jni/openal-soft-1.17.0/OpenAL32/alFontsound.c delete mode 100644 love/src/jni/openal-soft-1.17.0/OpenAL32/alMidi.c delete mode 100644 love/src/jni/openal-soft-1.17.0/OpenAL32/alPreset.c delete mode 100644 love/src/jni/openal-soft-1.17.0/OpenAL32/alSoundfont.c delete mode 100644 love/src/jni/openal-soft-1.17.0/OpenAL32/alSource.c delete mode 100644 love/src/jni/openal-soft-1.17.0/build/.empty delete mode 100644 love/src/jni/openal-soft-1.17.0/cmake/FindDSound.cmake delete mode 100644 love/src/jni/openal-soft-1.17.0/cmake/FindFluidSynth.cmake delete mode 100644 love/src/jni/openal-soft-1.17.0/cmake/FindSDL_sound.cmake delete mode 100644 love/src/jni/openal-soft-1.17.0/common/uintmap.c delete mode 100644 love/src/jni/openal-soft-1.17.0/examples/alffplay.c delete mode 100644 love/src/jni/openal-soft-1.17.0/examples/common/alhelpers.c delete mode 100644 love/src/jni/openal-soft-1.17.0/examples/common/alhelpers.h delete mode 100644 love/src/jni/openal-soft-1.17.0/examples/common/sdl_sound.c delete mode 100644 love/src/jni/openal-soft-1.17.0/examples/common/sdl_sound.h delete mode 100644 love/src/jni/openal-soft-1.17.0/hrtf/default-44100.mhr delete mode 100644 love/src/jni/openal-soft-1.17.0/hrtf/default-48000.mhr delete mode 100644 love/src/jni/openal-soft-1.17.0/include/atomic.h delete mode 100644 love/src/jni/openal-soft-1.17.0/utils/alsoft-config/CMakeLists.txt delete mode 100644 love/src/jni/openal-soft-1.17.0/utils/alsoft-config/mainwindow.cpp delete mode 100644 love/src/jni/openal-soft-1.17.0/utils/alsoft-config/mainwindow.ui delete mode 100644 love/src/jni/openal-soft-1.17.0/utils/makehrtf.c create mode 100644 love/src/jni/openal-soft-1.18.2/.gitignore create mode 100644 love/src/jni/openal-soft-1.18.2/.travis.yml rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/Alc/ALc.c (51%) create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/ALu.c rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/Alc/alcConfig.c (61%) create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/alcRing.c create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/alstring.h create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/ambdec.c create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/ambdec.h rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/Alc/backends/alsa.c (87%) create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/backends/base.c rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/Alc/backends/base.h (82%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/Alc/backends/coreaudio.c (53%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/Alc/backends/dsound.c (81%) create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/backends/jack.c rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/Alc/backends/loopback.c (91%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/Alc/backends/mmdevapi.c (50%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/Alc/backends/null.c (94%) create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/backends/opensl.c rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/Alc/backends/oss.c (56%) create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/backends/portaudio.c rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/Alc/backends/pulseaudio.c (76%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/Alc/backends/qsa.c (53%) create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/backends/sndio.c create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/backends/solaris.c create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/backends/wave.c create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/backends/winmm.c create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/bformatdec.c create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/bformatdec.h rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/Alc/bs2b.c (60%) create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/bsinc.c rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/Alc/compat.h (53%) create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/converter.c create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/converter.h rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/Alc/effects/chorus.c (58%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/Alc/effects/compressor.c (62%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/Alc/effects/dedicated.c (57%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/Alc/effects/distortion.c (61%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/Alc/effects/echo.c (66%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/Alc/effects/equalizer.c (68%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/Alc/effects/flanger.c (58%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/Alc/effects/modulator.c (57%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/Alc/effects/null.c (69%) create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/effects/reverb.c create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/helpers.c create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/hrtf.c create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/hrtf.h create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/mastering.c create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/mixer.c create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/mixer_c.c create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/mixer_defs.h create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/mixer_inc.c create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/mixer_neon.c create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/mixer_sse.c rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/Alc/mixer_sse2.c (80%) create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/mixer_sse3.c create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/mixer_sse41.c create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/nfcfilter.c create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/nfcfilter.h create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/panning.c create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/uhjfilter.c create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/uhjfilter.h create mode 100644 love/src/jni/openal-soft-1.18.2/Alc/vector.h rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/Android.mk (95%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/CMakeLists.txt (56%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/COPYING (97%) create mode 100644 love/src/jni/openal-soft-1.18.2/ChangeLog rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/OpenAL32/Include/alAuxEffectSlot.h (52%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/OpenAL32/Include/alBuffer.h (56%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/OpenAL32/Include/alEffect.h (86%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/OpenAL32/Include/alError.h (100%) create mode 100644 love/src/jni/openal-soft-1.18.2/OpenAL32/Include/alFilter.h create mode 100644 love/src/jni/openal-soft-1.18.2/OpenAL32/Include/alListener.h create mode 100644 love/src/jni/openal-soft-1.18.2/OpenAL32/Include/alMain.h create mode 100644 love/src/jni/openal-soft-1.18.2/OpenAL32/Include/alSource.h rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/OpenAL32/Include/alThunk.h (100%) create mode 100644 love/src/jni/openal-soft-1.18.2/OpenAL32/Include/alu.h rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/OpenAL32/Include/bs2b.h (63%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/OpenAL32/Include/sample_cvt.h (100%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/OpenAL32/alAuxEffectSlot.c (54%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/OpenAL32/alBuffer.c (86%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/OpenAL32/alEffect.c (91%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/OpenAL32/alError.c (79%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/OpenAL32/alExtension.c (66%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/OpenAL32/alFilter.c (82%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/OpenAL32/alListener.c (74%) create mode 100644 love/src/jni/openal-soft-1.18.2/OpenAL32/alSource.c rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/OpenAL32/alState.c (70%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/OpenAL32/alThunk.c (55%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/OpenAL32/sample_cvt.c (72%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/README (82%) create mode 100644 love/src/jni/openal-soft-1.18.2/XCompile-Android.txt rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/XCompile.txt (61%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/alsoftrc.sample (50%) create mode 100644 love/src/jni/openal-soft-1.18.2/appveyor.yml rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/cmake/CheckFileOffsetBits.c (100%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/cmake/CheckFileOffsetBits.cmake (89%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/cmake/CheckSharedFunctionExists.cmake (83%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/cmake/FindALSA.cmake (100%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/cmake/FindAudioIO.cmake (100%) create mode 100644 love/src/jni/openal-soft-1.18.2/cmake/FindDSound.cmake rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/cmake/FindFFmpeg.cmake (97%) create mode 100644 love/src/jni/openal-soft-1.18.2/cmake/FindJACK.cmake rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/cmake/FindOSS.cmake (56%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/cmake/FindPortAudio.cmake (100%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/cmake/FindPulseAudio.cmake (100%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/cmake/FindQSA.cmake (100%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/cmake/FindSDL2.cmake (100%) create mode 100644 love/src/jni/openal-soft-1.18.2/cmake/FindSDL_sound.cmake rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/cmake/FindSoundIO.cmake (100%) create mode 100644 love/src/jni/openal-soft-1.18.2/cmake/FindWindowsSDK.cmake rename love/src/jni/{openal-soft-1.17.0/include => openal-soft-1.18.2/common}/align.h (79%) create mode 100644 love/src/jni/openal-soft-1.18.2/common/almalloc.c create mode 100644 love/src/jni/openal-soft-1.18.2/common/almalloc.h rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/common/atomic.c (65%) create mode 100644 love/src/jni/openal-soft-1.18.2/common/atomic.h rename love/src/jni/{openal-soft-1.17.0/include => openal-soft-1.18.2/common}/bool.h (100%) create mode 100644 love/src/jni/openal-soft-1.18.2/common/math_defs.h rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/common/rwlock.c (56%) rename love/src/jni/{openal-soft-1.17.0/include => openal-soft-1.18.2/common}/rwlock.h (67%) rename love/src/jni/{openal-soft-1.17.0/include => openal-soft-1.18.2/common}/static_assert.h (75%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/common/threads.c (85%) rename love/src/jni/{openal-soft-1.17.0/include => openal-soft-1.18.2/common}/threads.h (96%) create mode 100644 love/src/jni/openal-soft-1.18.2/common/uintmap.c rename love/src/jni/{openal-soft-1.17.0/include => openal-soft-1.18.2/common}/uintmap.h (61%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/config.h (88%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/config.h.in (85%) create mode 100644 love/src/jni/openal-soft-1.18.2/docs/3D7.1.txt create mode 100644 love/src/jni/openal-soft-1.18.2/docs/ambdec.txt create mode 100644 love/src/jni/openal-soft-1.18.2/docs/ambisonics.txt rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2/docs}/env-vars.txt (83%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2/docs}/hrtf.txt (98%) create mode 100644 love/src/jni/openal-soft-1.18.2/examples/alffplay.cpp create mode 100644 love/src/jni/openal-soft-1.18.2/examples/alhrtf.c rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/examples/allatency.c (71%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/examples/alloopback.c (85%) create mode 100644 love/src/jni/openal-soft-1.18.2/examples/alrecord.c rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/examples/alreverb.c (84%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/examples/alstream.c (72%) create mode 100644 love/src/jni/openal-soft-1.18.2/examples/altonegen.c create mode 100644 love/src/jni/openal-soft-1.18.2/examples/common/alhelpers.c create mode 100644 love/src/jni/openal-soft-1.18.2/examples/common/alhelpers.h create mode 100644 love/src/jni/openal-soft-1.18.2/hrtf/default-44100.mhr create mode 100644 love/src/jni/openal-soft-1.18.2/hrtf/default-48000.mhr rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/include/AL/al.h (100%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/include/AL/alc.h (100%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/include/AL/alext.h (85%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/include/AL/efx-creative.h (100%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/include/AL/efx-presets.h (99%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/include/AL/efx.h (100%) create mode 100644 love/src/jni/openal-soft-1.18.2/native-tools/CMakeLists.txt create mode 100644 love/src/jni/openal-soft-1.18.2/native-tools/bin2h.c rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/openal.pc.in (100%) create mode 100644 love/src/jni/openal-soft-1.18.2/presets/3D7.1.ambdec create mode 100644 love/src/jni/openal-soft-1.18.2/presets/hexagon.ambdec create mode 100644 love/src/jni/openal-soft-1.18.2/presets/itu5.1-nocenter.ambdec create mode 100644 love/src/jni/openal-soft-1.18.2/presets/itu5.1.ambdec create mode 100644 love/src/jni/openal-soft-1.18.2/presets/presets.txt create mode 100644 love/src/jni/openal-soft-1.18.2/presets/rectangle.ambdec create mode 100644 love/src/jni/openal-soft-1.18.2/presets/square.ambdec create mode 100644 love/src/jni/openal-soft-1.18.2/router/al.c create mode 100644 love/src/jni/openal-soft-1.18.2/router/alc.c create mode 100644 love/src/jni/openal-soft-1.18.2/router/router.c create mode 100644 love/src/jni/openal-soft-1.18.2/router/router.h rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/utils/CIAIR.def (100%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/utils/IRC_1005.def (100%) rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/utils/MIT_KEMAR.def (100%) create mode 100644 love/src/jni/openal-soft-1.18.2/utils/alsoft-config/CMakeLists.txt rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/utils/alsoft-config/main.cpp (100%) create mode 100644 love/src/jni/openal-soft-1.18.2/utils/alsoft-config/mainwindow.cpp rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/utils/alsoft-config/mainwindow.h (61%) create mode 100644 love/src/jni/openal-soft-1.18.2/utils/alsoft-config/mainwindow.ui create mode 100644 love/src/jni/openal-soft-1.18.2/utils/bsincgen.c create mode 100644 love/src/jni/openal-soft-1.18.2/utils/makehrtf.c rename love/src/jni/{openal-soft-1.17.0 => openal-soft-1.18.2}/utils/openal-info.c (75%) create mode 100644 love/src/jni/openal-soft-1.18.2/version.cmake create mode 100644 love/src/jni/openal-soft-1.18.2/version.h create mode 100644 love/src/jni/openal-soft-1.18.2/version.h.in diff --git a/love/src/jni/love/Android.mk b/love/src/jni/love/Android.mk index 5cfb6f31..f44bcbc4 100644 --- a/love/src/jni/love/Android.mk +++ b/love/src/jni/love/Android.mk @@ -21,8 +21,8 @@ LOCAL_C_INCLUDES := \ ${LOCAL_PATH}/../libmng-1.0.10/ \ ${LOCAL_PATH}/../lcms2-2.5/include \ ${LOCAL_PATH}/../tiff-3.9.5/libtiff \ - ${LOCAL_PATH}/../openal-soft-1.17.0/include \ - ${LOCAL_PATH}/../openal-soft-1.17.0/OpenAL32/Include \ + ${LOCAL_PATH}/../openal-soft-1.18.2/include \ + ${LOCAL_PATH}/../openal-soft-1.18.2/OpenAL32/Include \ ${LOCAL_PATH}/../freetype2-android/include \ ${LOCAL_PATH}/../freetype2-android/src \ ${LOCAL_PATH}/../physfs-3.0.1/src \ diff --git a/love/src/jni/openal-soft-1.17.0/Alc/ALu.c b/love/src/jni/openal-soft-1.17.0/Alc/ALu.c deleted file mode 100644 index a85e1aa0..00000000 --- a/love/src/jni/openal-soft-1.17.0/Alc/ALu.c +++ /dev/null @@ -1,1321 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 1999-2007 by authors. - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#include "alMain.h" -#include "alSource.h" -#include "alBuffer.h" -#include "alListener.h" -#include "alAuxEffectSlot.h" -#include "alu.h" -#include "bs2b.h" -#include "hrtf.h" -#include "static_assert.h" - -#include "midi/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; -}; - -/* Cone scalar */ -ALfloat ConeScale = 1.0f; - -/* Localized Z scalar for mono sources */ -ALfloat ZScale = 1.0f; - -extern inline ALfloat minf(ALfloat a, ALfloat b); -extern inline ALfloat maxf(ALfloat a, ALfloat b); -extern inline ALfloat clampf(ALfloat val, ALfloat min, ALfloat max); - -extern inline ALdouble mind(ALdouble a, ALdouble b); -extern inline ALdouble maxd(ALdouble a, ALdouble b); -extern inline ALdouble clampd(ALdouble val, ALdouble min, ALdouble max); - -extern inline ALuint minu(ALuint a, ALuint b); -extern inline ALuint maxu(ALuint a, ALuint b); -extern inline ALuint clampu(ALuint val, ALuint min, ALuint max); - -extern inline ALint mini(ALint a, ALint b); -extern inline ALint maxi(ALint a, ALint b); -extern inline ALint clampi(ALint val, ALint min, ALint max); - -extern inline ALint64 mini64(ALint64 a, ALint64 b); -extern inline ALint64 maxi64(ALint64 a, ALint64 b); -extern inline ALint64 clampi64(ALint64 val, ALint64 min, ALint64 max); - -extern inline ALuint64 minu64(ALuint64 a, ALuint64 b); -extern inline ALuint64 maxu64(ALuint64 a, ALuint64 b); -extern inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max); - -extern inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu); -extern inline ALfloat cubic(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALfloat mu); - - -static inline void aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVector2, ALfloat *outVector) -{ - outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1]; - outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2]; - outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0]; -} - -static inline ALfloat aluDotproduct(const ALfloat *inVector1, const ALfloat *inVector2) -{ - return inVector1[0]*inVector2[0] + inVector1[1]*inVector2[1] + - inVector1[2]*inVector2[2]; -} - -static inline void aluNormalize(ALfloat *inVector) -{ - ALfloat lengthsqr = aluDotproduct(inVector, inVector); - if(lengthsqr > 0.0f) - { - ALfloat inv_length = 1.0f/sqrtf(lengthsqr); - inVector[0] *= inv_length; - inVector[1] *= inv_length; - inVector[2] *= inv_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 ALvoid CalcListenerParams(ALlistener *Listener) -{ - ALfloat 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); - V[0] = Listener->Up[0]; - V[1] = Listener->Up[1]; - V[2] = Listener->Up[2]; - aluNormalize(V); - /* Build and normalize right-vector */ - aluCrossproduct(N, V, U); - aluNormalize(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; - - 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]; - - 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); -} - -ALvoid CalcNonAttnSourceParams(ALactivesource *src, 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) } - }; - - ALCdevice *Device = ALContext->Device; - const ALsource *ALSource = src->Source; - ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume; - ALbufferlistitem *BufferListItem; - enum FmtChannels Channels; - ALfloat DryGain, DryGainHF, DryGainLF; - ALfloat WetGain[MAX_SENDS]; - ALfloat WetGainHF[MAX_SENDS]; - ALfloat WetGainLF[MAX_SENDS]; - ALint NumSends, Frequency; - const struct ChanMap *chans = NULL; - ALint num_channels = 0; - ALboolean DirectChannels; - ALfloat hwidth = 0.0f; - ALfloat Pitch; - ALint i, j, c; - - /* Get device properties */ - NumSends = Device->NumAuxSends; - Frequency = Device->Frequency; - - /* Get listener properties */ - ListenerGain = ALContext->Listener->Gain; - - /* Get source properties */ - SourceVolume = ALSource->Gain; - MinVolume = ALSource->MinGain; - MaxVolume = ALSource->MaxGain; - Pitch = ALSource->Pitch; - DirectChannels = ALSource->DirectChannels; - - src->Direct.OutBuffer = Device->DryBuffer; - 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; - else - src->Send[i].OutBuffer = Slot->WetBuffer; - } - - /* Calculate the stepping value */ - Channels = FmtMono; - BufferListItem = ATOMIC_LOAD(&ALSource->queue); - while(BufferListItem != NULL) - { - ALbuffer *ALBuffer; - if((ALBuffer=BufferListItem->buffer) != NULL) - { - Pitch = Pitch * ALBuffer->Frequency / Frequency; - if(Pitch > (ALfloat)MAX_PITCH) - src->Step = MAX_PITCH<Step = fastf2i(Pitch*FRACTIONONE); - if(src->Step == 0) - src->Step = 1; - } - - Channels = ALBuffer->FmtChannels; - break; - } - BufferListItem = BufferListItem->next; - } - - /* Calculate gains */ - DryGain = clampf(SourceVolume, MinVolume, MaxVolume); - DryGain *= ALSource->Direct.Gain * ListenerGain; - DryGainHF = ALSource->Direct.GainHF; - DryGainLF = ALSource->Direct.GainLF; - for(i = 0;i < NumSends;i++) - { - WetGain[i] = clampf(SourceVolume, MinVolume, MaxVolume); - WetGain[i] *= ALSource->Send[i].Gain * ListenerGain; - WetGainHF[i] = ALSource->Send[i].GainHF; - WetGainLF[i] = ALSource->Send[i].GainLF; - } - - switch(Channels) - { - case FmtMono: - chans = MonoMap; - num_channels = 1; - 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 - { - chans = StereoWideMap; - hwidth = DEG2RAD(60.0f); - } - num_channels = 2; - break; - - case FmtRear: - chans = RearMap; - num_channels = 2; - break; - - case FmtQuad: - chans = QuadMap; - num_channels = 4; - break; - - case FmtX51: - chans = X51Map; - num_channels = 6; - break; - - case FmtX61: - chans = X61Map; - num_channels = 7; - break; - - case FmtX71: - chans = X71Map; - num_channels = 8; - break; - } - - if(DirectChannels != AL_FALSE) - { - for(c = 0;c < num_channels;c++) - { - MixGains *gains = src->Direct.Mix.Gains[c]; - for(j = 0;j < MaxChannels;j++) - gains[j].Target = 0.0f; - } - - 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; - } - } - } - - 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; - } - - 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); - - src->IsHrtf = AL_TRUE; - } - else - { - for(i = 0;i < num_channels;i++) - { - 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) - { - 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++) - { - 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 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; - } - - 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; - } - 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; - } - } - - { - ALfloat gainhf = maxf(0.01f, DryGainHF); - ALfloat gainlf = maxf(0.01f, DryGainLF); - ALfloat hfscale = ALSource->Direct.HFReference / Frequency; - ALfloat lfscale = ALSource->Direct.LFReference / Frequency; - 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; - ALfilterState_setParams( - &src->Direct.Filters[c].LowPass, ALfilterType_HighShelf, gainhf, - hfscale, 0.0f - ); - ALfilterState_setParams( - &src->Direct.Filters[c].HighPass, ALfilterType_LowShelf, gainlf, - lfscale, 0.0f - ); - } - } - 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; - 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; - ALfilterState_setParams( - &src->Send[i].Filters[c].LowPass, ALfilterType_HighShelf, gainhf, - hfscale, 0.0f - ); - ALfilterState_setParams( - &src->Send[i].Filters[c].HighPass, ALfilterType_LowShelf, gainlf, - lfscale, 0.0f - ); - } - } -} - -ALvoid CalcSourceParams(ALactivesource *src, const ALCcontext *ALContext) -{ - ALCdevice *Device = ALContext->Device; - const ALsource *ALSource = src->Source; - ALfloat Velocity[3],Direction[3],Position[3],SourceToListener[3]; - ALfloat InnerAngle,OuterAngle,Angle,Distance,ClampedDist; - ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff; - ALfloat ConeVolume,ConeHF,SourceVolume,ListenerGain; - ALfloat DopplerFactor, SpeedOfSound; - ALfloat AirAbsorptionFactor; - ALfloat RoomAirAbsorption[MAX_SENDS]; - ALbufferlistitem *BufferListItem; - ALfloat Attenuation; - ALfloat RoomAttenuation[MAX_SENDS]; - ALfloat MetersPerUnit; - ALfloat RoomRolloffBase; - ALfloat RoomRolloff[MAX_SENDS]; - ALfloat DecayDistance[MAX_SENDS]; - ALfloat DryGain; - ALfloat DryGainHF; - ALfloat DryGainLF; - ALboolean DryGainHFAuto; - ALfloat WetGain[MAX_SENDS]; - ALfloat WetGainHF[MAX_SENDS]; - ALfloat WetGainLF[MAX_SENDS]; - ALboolean WetGainAuto; - ALboolean WetGainHFAuto; - ALfloat Pitch; - ALuint Frequency; - ALint NumSends; - ALint i, j; - - DryGainHF = 1.0f; - DryGainLF = 1.0f; - for(i = 0;i < MAX_SENDS;i++) - { - WetGainHF[i] = 1.0f; - WetGainLF[i] = 1.0f; - } - - /* Get context/device properties */ - DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor; - SpeedOfSound = ALContext->SpeedOfSound * ALContext->DopplerVelocity; - NumSends = Device->NumAuxSends; - Frequency = Device->Frequency; - - /* Get listener properties */ - ListenerGain = ALContext->Listener->Gain; - MetersPerUnit = ALContext->Listener->MetersPerUnit; - - /* Get source properties */ - SourceVolume = ALSource->Gain; - 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]; - MinDist = ALSource->RefDistance; - MaxDist = ALSource->MaxDistance; - Rolloff = ALSource->RollOffFactor; - InnerAngle = ALSource->InnerAngle; - OuterAngle = ALSource->OuterAngle; - AirAbsorptionFactor = ALSource->AirAbsorptionFactor; - DryGainHFAuto = ALSource->DryGainHFAuto; - WetGainAuto = ALSource->WetGainAuto; - WetGainHFAuto = ALSource->WetGainHFAuto; - RoomRolloffBase = ALSource->RoomRolloffFactor; - - src->Direct.OutBuffer = Device->DryBuffer; - 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) - { - Slot = NULL; - RoomRolloff[i] = 0.0f; - DecayDistance[i] = 0.0f; - RoomAirAbsorption[i] = 1.0f; - } - else if(Slot->AuxSendAuto) - { - RoomRolloff[i] = RoomRolloffBase; - if(IsReverbEffect(Slot->EffectType)) - { - RoomRolloff[i] += Slot->EffectProps.Reverb.RoomRolloffFactor; - DecayDistance[i] = Slot->EffectProps.Reverb.DecayTime * - SPEEDOFSOUNDMETRESPERSEC; - RoomAirAbsorption[i] = Slot->EffectProps.Reverb.AirAbsorptionGainHF; - } - else - { - DecayDistance[i] = 0.0f; - RoomAirAbsorption[i] = 1.0f; - } - } - else - { - /* If the slot's auxiliary send auto is off, the data sent to the - * effect slot is the same as the dry path, sans filter effects */ - RoomRolloff[i] = Rolloff; - DecayDistance[i] = 0.0f; - RoomAirAbsorption[i] = AIRABSORBGAINHF; - } - - if(!Slot || Slot->EffectType == AL_EFFECT_NULL) - src->Send[i].OutBuffer = NULL; - else - src->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; - /* Transform source vectors */ - aluMatrixVector(Position, 1.0f, Matrix); - aluMatrixVector(Direction, 0.0f, Matrix); - aluMatrixVector(Velocity, 0.0f, Matrix); - } - else - { - const ALfloat *ListenerVel = 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]; - } - - SourceToListener[0] = -Position[0]; - SourceToListener[1] = -Position[1]; - SourceToListener[2] = -Position[2]; - aluNormalize(SourceToListener); - aluNormalize(Direction); - - /* Calculate distance attenuation */ - Distance = sqrtf(aluDotproduct(Position, Position)); - ClampedDist = Distance; - - Attenuation = 1.0f; - for(i = 0;i < NumSends;i++) - RoomAttenuation[i] = 1.0f; - switch(ALContext->SourceDistanceModel ? ALSource->DistanceModel : - ALContext->DistanceModel) - { - case InverseDistanceClamped: - ClampedDist = clampf(ClampedDist, MinDist, MaxDist); - if(MaxDist < MinDist) - break; - /*fall-through*/ - case InverseDistance: - if(MinDist > 0.0f) - { - if((MinDist + (Rolloff * (ClampedDist - MinDist))) > 0.0f) - Attenuation = MinDist / (MinDist + (Rolloff * (ClampedDist - MinDist))); - for(i = 0;i < NumSends;i++) - { - if((MinDist + (RoomRolloff[i] * (ClampedDist - MinDist))) > 0.0f) - RoomAttenuation[i] = MinDist / (MinDist + (RoomRolloff[i] * (ClampedDist - MinDist))); - } - } - break; - - case LinearDistanceClamped: - ClampedDist = clampf(ClampedDist, MinDist, MaxDist); - if(MaxDist < MinDist) - break; - /*fall-through*/ - case LinearDistance: - if(MaxDist != MinDist) - { - Attenuation = 1.0f - (Rolloff*(ClampedDist-MinDist)/(MaxDist - MinDist)); - Attenuation = maxf(Attenuation, 0.0f); - for(i = 0;i < NumSends;i++) - { - RoomAttenuation[i] = 1.0f - (RoomRolloff[i]*(ClampedDist-MinDist)/(MaxDist - MinDist)); - RoomAttenuation[i] = maxf(RoomAttenuation[i], 0.0f); - } - } - break; - - case ExponentDistanceClamped: - ClampedDist = clampf(ClampedDist, MinDist, MaxDist); - if(MaxDist < MinDist) - break; - /*fall-through*/ - case ExponentDistance: - if(ClampedDist > 0.0f && MinDist > 0.0f) - { - Attenuation = powf(ClampedDist/MinDist, -Rolloff); - for(i = 0;i < NumSends;i++) - RoomAttenuation[i] = powf(ClampedDist/MinDist, -RoomRolloff[i]); - } - break; - - case DisableDistance: - ClampedDist = MinDist; - break; - } - - /* Source Gain + Attenuation */ - DryGain = SourceVolume * Attenuation; - for(i = 0;i < NumSends;i++) - WetGain[i] = SourceVolume * RoomAttenuation[i]; - - /* Distance-based air absorption */ - if(AirAbsorptionFactor > 0.0f && ClampedDist > MinDist) - { - ALfloat meters = maxf(ClampedDist-MinDist, 0.0f) * MetersPerUnit; - DryGainHF *= powf(AIRABSORBGAINHF, AirAbsorptionFactor*meters); - for(i = 0;i < NumSends;i++) - WetGainHF[i] *= powf(RoomAirAbsorption[i], AirAbsorptionFactor*meters); - } - - if(WetGainAuto) - { - ALfloat ApparentDist = 1.0f/maxf(Attenuation, 0.00001f) - 1.0f; - - /* Apply a decay-time transformation to the wet path, based on the - * attenuation of the dry path. - * - * Using the apparent distance, based on the distance attenuation, the - * initial decay of the reverb effect is calculated and applied to the - * wet path. - */ - for(i = 0;i < NumSends;i++) - { - if(DecayDistance[i] > 0.0f) - WetGain[i] *= powf(0.001f/*-60dB*/, ApparentDist/DecayDistance[i]); - } - } - - /* Calculate directional soundcones */ - Angle = RAD2DEG(acosf(aluDotproduct(Direction,SourceToListener)) * ConeScale) * 2.0f; - if(Angle > InnerAngle && Angle <= OuterAngle) - { - ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle); - ConeVolume = lerp(1.0f, ALSource->OuterGain, scale); - ConeHF = lerp(1.0f, ALSource->OuterGainHF, scale); - } - else if(Angle > OuterAngle) - { - ConeVolume = ALSource->OuterGain; - ConeHF = ALSource->OuterGainHF; - } - else - { - ConeVolume = 1.0f; - ConeHF = 1.0f; - } - - DryGain *= ConeVolume; - if(WetGainAuto) - { - for(i = 0;i < NumSends;i++) - WetGain[i] *= ConeVolume; - } - if(DryGainHFAuto) - DryGainHF *= ConeHF; - if(WetGainHFAuto) - { - for(i = 0;i < NumSends;i++) - WetGainHF[i] *= ConeHF; - } - - /* Clamp to Min/Max Gain */ - DryGain = clampf(DryGain, MinVolume, MaxVolume); - for(i = 0;i < NumSends;i++) - WetGain[i] = clampf(WetGain[i], MinVolume, MaxVolume); - - /* Apply gain and frequency filters */ - DryGain *= ALSource->Direct.Gain * ListenerGain; - DryGainHF *= ALSource->Direct.GainHF; - DryGainLF *= ALSource->Direct.GainLF; - for(i = 0;i < NumSends;i++) - { - WetGain[i] *= ALSource->Send[i].Gain * ListenerGain; - WetGainHF[i] *= ALSource->Send[i].GainHF; - WetGainLF[i] *= ALSource->Send[i].GainLF; - } - - /* Calculate velocity-based doppler effect */ - if(DopplerFactor > 0.0f) - { - const ALfloat *ListenerVel = ALContext->Listener->Params.Velocity; - ALfloat VSS, VLS; - - if(SpeedOfSound < 1.0f) - { - DopplerFactor *= 1.0f/SpeedOfSound; - SpeedOfSound = 1.0f; - } - - VSS = aluDotproduct(Velocity, SourceToListener) * DopplerFactor; - VLS = aluDotproduct(ListenerVel, SourceToListener) * DopplerFactor; - - Pitch *= clampf(SpeedOfSound-VLS, 1.0f, SpeedOfSound*2.0f - 1.0f) / - clampf(SpeedOfSound-VSS, 1.0f, SpeedOfSound*2.0f - 1.0f); - } - - BufferListItem = ATOMIC_LOAD(&ALSource->queue); - while(BufferListItem != NULL) - { - ALbuffer *ALBuffer; - if((ALBuffer=BufferListItem->buffer) != NULL) - { - /* Calculate fixed-point stepping value, based on the pitch, buffer - * frequency, and output frequency. */ - Pitch = Pitch * ALBuffer->Frequency / Frequency; - if(Pitch > (ALfloat)MAX_PITCH) - src->Step = MAX_PITCH<Step = fastf2i(Pitch*FRACTIONONE); - if(src->Step == 0) - src->Step = 1; - } - - break; - } - BufferListItem = BufferListItem->next; - } - - if(Device->Hrtf) - { - /* Use a binaural HRTF algorithm for stereo headphone playback */ - ALfloat delta, ev = 0.0f, az = 0.0f; - ALfloat radius = ALSource->Radius; - ALfloat dirfact = 1.0f; - - if(Distance > FLT_EPSILON) - { - ALfloat invlen = 1.0f/Distance; - Position[0] *= invlen; - Position[1] *= invlen; - Position[2] *= invlen; - - /* 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); - } - if(radius > Distance) - dirfact *= Distance / radius; - - /* Check to see if the HRIR is already moving. */ - if(src->Direct.Moving) - { - /* Calculate the normalized HRTF transition factor (delta). */ - delta = CalcHrtfDelta(src->Direct.Mix.Hrtf.Gain, DryGain, - src->Direct.Mix.Hrtf.Dir, Position); - /* If the delta is large enough, get the moving HRIR target - * coefficients, target delays, steppping values, and counter. */ - if(delta > 0.001f) - { - 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 - ); - 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]; - } - } - 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]; - } - src->Direct.Mix.Hrtf.IrSize = GetHrtfIrSize(Device->Hrtf); - - src->IsHrtf = AL_TRUE; - } - else - { - MixGains *gains = src->Direct.Mix.Gains[0]; - ALfloat DirGain = 0.0f; - ALfloat AmbientGain; - - for(j = 0;j < MaxChannels;j++) - gains[j].Target = 0.0f; - - /* Normalize the length, 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]; - } - - /* 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++) - { - enum Channel chan = Device->Speaker2Chan[i]; - gains[chan].Target = maxf(gains[chan].Target, AmbientGain); - } - - 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; - } - - 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; - } - 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; - } - } - - { - 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; - ALfilterState_setParams( - &src->Direct.Filters[0].LowPass, ALfilterType_HighShelf, gainhf, - hfscale, 0.0f - ); - ALfilterState_setParams( - &src->Direct.Filters[0].HighPass, ALfilterType_LowShelf, gainlf, - lfscale, 0.0f - ); - } - 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; - ALfilterState_setParams( - &src->Send[i].Filters[0].LowPass, ALfilterType_HighShelf, gainhf, - hfscale, 0.0f - ); - ALfilterState_setParams( - &src->Send[i].Filters[0].HighPass, ALfilterType_LowShelf, gainlf, - lfscale, 0.0f - ); - } -} - - -static inline ALint aluF2I25(ALfloat val) -{ - /* 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); -} - -static inline ALfloat aluF2F(ALfloat val) -{ return val; } -static inline ALint aluF2I(ALfloat val) -{ return aluF2I25(val)<<7; } -static inline ALuint aluF2UI(ALfloat val) -{ return aluF2I(val)+2147483648u; } -static inline ALshort aluF2S(ALfloat val) -{ return aluF2I25(val)>>9; } -static inline ALushort aluF2US(ALfloat val) -{ return aluF2S(val)+32768; } -static inline ALbyte aluF2B(ALfloat val) -{ return aluF2I25(val)>>17; } -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) \ -{ \ - 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++) \ - { \ - T *restrict out; \ - \ - if(offsets[j] == INVALID_OFFSET) \ - continue; \ - \ - out = (T*)(*buffer) + offsets[j]; \ - for(i = 0;i < SamplesToDo;i++) \ - out[i*numchans] = func(DryBuffer[j][i]); \ - } \ - *buffer = (char*)(*buffer) + SamplesToDo*numchans*sizeof(T); \ -} - -DECL_TEMPLATE(ALfloat, aluF2F) -DECL_TEMPLATE(ALuint, aluF2UI) -DECL_TEMPLATE(ALint, aluF2I) -DECL_TEMPLATE(ALushort, aluF2US) -DECL_TEMPLATE(ALshort, aluF2S) -DECL_TEMPLATE(ALubyte, aluF2UB) -DECL_TEMPLATE(ALbyte, aluF2B) - -#undef DECL_TEMPLATE - - -ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size) -{ - ALuint SamplesToDo; - ALeffectslot **slot, **slot_end; - ALactivesource **src, **src_end; - ALCcontext *ctx; - FPUCtl oldMode; - ALuint i, c; - - SetMixerFPUMode(&oldMode); - - while(size > 0) - { - IncrementRef(&device->MixCount); - - SamplesToDo = minu(size, BUFFERSIZE); - for(c = 0;c < MaxChannels;c++) - memset(device->DryBuffer[c], 0, SamplesToDo*sizeof(ALfloat)); - - ALCdevice_Lock(device); - V(device->Synth,process)(SamplesToDo, device->DryBuffer); - - 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); - - /* source processing */ - src = ctx->ActiveSources; - src_end = src + ctx->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; - --(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++; - } - - /* 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++; - } - - 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; - } - - /* Increment the clock time. Every second's worth of samples is - * converted and added to clock base so that large sample counts don't - * overflow during conversion. This also guarantees an exact, stable - * conversion. */ - device->SamplesDone += SamplesToDo; - device->ClockBase += (device->SamplesDone/device->Frequency) * DEVICE_CLOCK_RES; - device->SamplesDone %= device->Frequency; - ALCdevice_Unlock(device); - - 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]; - bs2b_cross_feed(device->Bs2b, samples); - device->DryBuffer[FrontLeft][i] = samples[0]; - device->DryBuffer[FrontRight][i] = samples[1]; - } - } - - if(buffer) - { - switch(device->FmtType) - { - case DevFmtByte: - Write_ALbyte(device, &buffer, SamplesToDo); - break; - case DevFmtUByte: - Write_ALubyte(device, &buffer, SamplesToDo); - break; - case DevFmtShort: - Write_ALshort(device, &buffer, SamplesToDo); - break; - case DevFmtUShort: - Write_ALushort(device, &buffer, SamplesToDo); - break; - case DevFmtInt: - Write_ALint(device, &buffer, SamplesToDo); - break; - case DevFmtUInt: - Write_ALuint(device, &buffer, SamplesToDo); - break; - case DevFmtFloat: - Write_ALfloat(device, &buffer, SamplesToDo); - break; - } - } - - size -= SamplesToDo; - IncrementRef(&device->MixCount); - } - - RestoreFPUMode(&oldMode); -} - - -ALvoid aluHandleDisconnect(ALCdevice *device) -{ - ALCcontext *Context; - - device->Connected = ALC_FALSE; - - Context = ATOMIC_LOAD(&device->ContextList); - while(Context) - { - ALactivesource **src, **src_end; - - src = Context->ActiveSources; - src_end = src + Context->ActiveSourceCount; - while(src != src_end) - { - ALsource *source = (*src)->Source; - if(source->state == AL_PLAYING) - { - source->state = AL_STOPPED; - ATOMIC_STORE(&source->current_buffer, NULL); - source->position = 0; - source->position_fraction = 0; - } - src++; - } - Context->ActiveSourceCount = 0; - - Context = Context->next; - } -} diff --git a/love/src/jni/openal-soft-1.17.0/Alc/alcRing.c b/love/src/jni/openal-soft-1.17.0/Alc/alcRing.c deleted file mode 100644 index 9b5d8214..00000000 --- a/love/src/jni/openal-soft-1.17.0/Alc/alcRing.c +++ /dev/null @@ -1,129 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 1999-2007 by authors. - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include - -#include "alMain.h" -#include "threads.h" -#include "compat.h" - - -struct RingBuffer { - ALubyte *mem; - - ALsizei frame_size; - ALsizei length; - ALint read_pos; - ALint write_pos; - - almtx_t mtx; -}; - - -RingBuffer *CreateRingBuffer(ALsizei frame_size, ALsizei length) -{ - RingBuffer *ring = calloc(1, sizeof(*ring) + ((length+1) * frame_size)); - if(ring) - { - ring->mem = (ALubyte*)(ring+1); - - ring->frame_size = frame_size; - ring->length = length+1; - ring->read_pos = 0; - ring->write_pos = 0; - - almtx_init(&ring->mtx, almtx_plain); - } - return ring; -} - -void DestroyRingBuffer(RingBuffer *ring) -{ - if(ring) - { - almtx_destroy(&ring->mtx); - free(ring); - } -} - -ALsizei RingBufferSize(RingBuffer *ring) -{ - ALsizei s; - - almtx_lock(&ring->mtx); - s = (ring->write_pos-ring->read_pos+ring->length) % ring->length; - almtx_unlock(&ring->mtx); - - return s; -} - -void WriteRingBuffer(RingBuffer *ring, const ALubyte *data, ALsizei len) -{ - int remain; - - almtx_lock(&ring->mtx); - - remain = (ring->read_pos-ring->write_pos-1+ring->length) % ring->length; - if(remain < len) len = remain; - - if(len > 0) - { - remain = ring->length - ring->write_pos; - if(remain < len) - { - memcpy(ring->mem+(ring->write_pos*ring->frame_size), data, - remain*ring->frame_size); - memcpy(ring->mem, data+(remain*ring->frame_size), - (len-remain)*ring->frame_size); - } - else - memcpy(ring->mem+(ring->write_pos*ring->frame_size), data, - len*ring->frame_size); - - ring->write_pos += len; - ring->write_pos %= ring->length; - } - - almtx_unlock(&ring->mtx); -} - -void ReadRingBuffer(RingBuffer *ring, ALubyte *data, ALsizei len) -{ - int remain; - - almtx_lock(&ring->mtx); - - remain = ring->length - ring->read_pos; - if(remain < len) - { - memcpy(data, ring->mem+(ring->read_pos*ring->frame_size), remain*ring->frame_size); - memcpy(data+(remain*ring->frame_size), ring->mem, (len-remain)*ring->frame_size); - } - else - memcpy(data, ring->mem+(ring->read_pos*ring->frame_size), len*ring->frame_size); - - ring->read_pos += len; - ring->read_pos %= ring->length; - - almtx_unlock(&ring->mtx); -} diff --git a/love/src/jni/openal-soft-1.17.0/Alc/alstring.h b/love/src/jni/openal-soft-1.17.0/Alc/alstring.h deleted file mode 100644 index 32f4280a..00000000 --- a/love/src/jni/openal-soft-1.17.0/Alc/alstring.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef ALSTRING_H -#define ALSTRING_H - -#include - -#include "vector.h" - - -typedef char al_string_char_type; -TYPEDEF_VECTOR(al_string_char_type, al_string) - -inline void al_string_deinit(al_string *str) -{ VECTOR_DEINIT(*str); } -#define AL_STRING_INIT(_x) do { (_x) = (al_string)NULL; } while(0) -#define AL_STRING_INIT_STATIC() ((al_string)NULL) -#define AL_STRING_DEINIT(_x) al_string_deinit(&(_x)) - -inline ALsizei al_string_length(const_al_string str) -{ return VECTOR_SIZE(str); } - -inline ALboolean al_string_empty(const_al_string str) -{ return al_string_length(str) == 0; } - -inline const al_string_char_type *al_string_get_cstr(const_al_string str) -{ return str ? &VECTOR_FRONT(str) : ""; } - -void al_string_clear(al_string *str); - -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); - -void al_string_copy(al_string *str, const_al_string from); -void al_string_copy_cstr(al_string *str, const al_string_char_type *from); - -void al_string_append_char(al_string *str, const al_string_char_type c); -void al_string_append_cstr(al_string *str, const al_string_char_type *from); -void al_string_append_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to); - -#ifdef _WIN32 -#include -/* Windows-only methods to deal with WideChar strings. */ -void al_string_copy_wcstr(al_string *str, const wchar_t *from); -#endif - -#endif /* ALSTRING_H */ diff --git a/love/src/jni/openal-soft-1.17.0/Alc/backends/base.c b/love/src/jni/openal-soft-1.17.0/Alc/backends/base.c deleted file mode 100644 index 37e4ccc9..00000000 --- a/love/src/jni/openal-soft-1.17.0/Alc/backends/base.c +++ /dev/null @@ -1,232 +0,0 @@ - -#include "config.h" - -#include - -#include "alMain.h" - -#include "backends/base.h" - - -/* Base ALCbackend method implementations. */ -void ALCbackend_Construct(ALCbackend *self, ALCdevice *device) -{ - int ret; - self->mDevice = device; - ret = almtx_init(&self->mMutex, almtx_recursive); - assert(ret == althrd_success); -} - -void ALCbackend_Destruct(ALCbackend *self) -{ - almtx_destroy(&self->mMutex); -} - -ALCboolean ALCbackend_reset(ALCbackend* UNUSED(self)) -{ - return ALC_FALSE; -} - -ALCenum ALCbackend_captureSamples(ALCbackend* UNUSED(self), void* UNUSED(buffer), ALCuint UNUSED(samples)) -{ - return ALC_INVALID_DEVICE; -} - -ALCuint ALCbackend_availableSamples(ALCbackend* UNUSED(self)) -{ - return 0; -} - -ALint64 ALCbackend_getLatency(ALCbackend* UNUSED(self)) -{ - return 0; -} - -void ALCbackend_lock(ALCbackend *self) -{ - int ret = almtx_lock(&self->mMutex); - assert(ret == althrd_success); -} - -void ALCbackend_unlock(ALCbackend *self) -{ - int ret = almtx_unlock(&self->mMutex); - assert(ret == althrd_success); -} - - -/* Base ALCbackendFactory method implementations. */ -void ALCbackendFactory_deinit(ALCbackendFactory* UNUSED(self)) -{ -} - - -/* Wrappers to use an old-style backend with the new interface. */ -typedef struct PlaybackWrapper { - DERIVE_FROM_TYPE(ALCbackend); - - const BackendFuncs *Funcs; -} PlaybackWrapper; - -static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device, const BackendFuncs *funcs); -static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, Destruct) -static ALCenum PlaybackWrapper_open(PlaybackWrapper *self, const ALCchar *name); -static void PlaybackWrapper_close(PlaybackWrapper *self); -static ALCboolean PlaybackWrapper_reset(PlaybackWrapper *self); -static ALCboolean PlaybackWrapper_start(PlaybackWrapper *self); -static void PlaybackWrapper_stop(PlaybackWrapper *self); -static DECLARE_FORWARD2(PlaybackWrapper, ALCbackend, ALCenum, captureSamples, void*, ALCuint) -static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, ALCuint, availableSamples) -static ALint64 PlaybackWrapper_getLatency(PlaybackWrapper *self); -static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, lock) -static DECLARE_FORWARD(PlaybackWrapper, ALCbackend, void, unlock) -DECLARE_DEFAULT_ALLOCATORS(PlaybackWrapper) -DEFINE_ALCBACKEND_VTABLE(PlaybackWrapper); - -static void PlaybackWrapper_Construct(PlaybackWrapper *self, ALCdevice *device, const BackendFuncs *funcs) -{ - ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device); - SET_VTABLE2(PlaybackWrapper, ALCbackend, self); - - self->Funcs = funcs; -} - -static ALCenum PlaybackWrapper_open(PlaybackWrapper *self, const ALCchar *name) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - return self->Funcs->OpenPlayback(device, name); -} - -static void PlaybackWrapper_close(PlaybackWrapper *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - self->Funcs->ClosePlayback(device); -} - -static ALCboolean PlaybackWrapper_reset(PlaybackWrapper *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - return self->Funcs->ResetPlayback(device); -} - -static ALCboolean PlaybackWrapper_start(PlaybackWrapper *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - return self->Funcs->StartPlayback(device); -} - -static void PlaybackWrapper_stop(PlaybackWrapper *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - 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); - - const BackendFuncs *Funcs; -} CaptureWrapper; - -static void CaptureWrapper_Construct(CaptureWrapper *self, ALCdevice *device, const BackendFuncs *funcs); -static DECLARE_FORWARD(CaptureWrapper, ALCbackend, void, Destruct) -static ALCenum CaptureWrapper_open(CaptureWrapper *self, const ALCchar *name); -static void CaptureWrapper_close(CaptureWrapper *self); -static DECLARE_FORWARD(CaptureWrapper, ALCbackend, ALCboolean, reset) -static ALCboolean CaptureWrapper_start(CaptureWrapper *self); -static void CaptureWrapper_stop(CaptureWrapper *self); -static ALCenum CaptureWrapper_captureSamples(CaptureWrapper *self, void *buffer, ALCuint samples); -static ALCuint CaptureWrapper_availableSamples(CaptureWrapper *self); -static ALint64 CaptureWrapper_getLatency(CaptureWrapper *self); -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); - SET_VTABLE2(CaptureWrapper, ALCbackend, self); - - self->Funcs = funcs; -} - -static ALCenum CaptureWrapper_open(CaptureWrapper *self, const ALCchar *name) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - return self->Funcs->OpenCapture(device, name); -} - -static void CaptureWrapper_close(CaptureWrapper *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - self->Funcs->CloseCapture(device); -} - -static ALCboolean CaptureWrapper_start(CaptureWrapper *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - self->Funcs->StartCapture(device); - return ALC_TRUE; -} - -static void CaptureWrapper_stop(CaptureWrapper *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - self->Funcs->StopCapture(device); -} - -static ALCenum CaptureWrapper_captureSamples(CaptureWrapper *self, void *buffer, ALCuint samples) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - return self->Funcs->CaptureSamples(device, buffer, samples); -} - -static ALCuint CaptureWrapper_availableSamples(CaptureWrapper *self) -{ - ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; - 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) -{ - if(type == ALCbackend_Playback) - { - PlaybackWrapper *backend; - - backend = PlaybackWrapper_New(sizeof(*backend)); - if(!backend) return NULL; - - PlaybackWrapper_Construct(backend, device, funcs); - - return STATIC_CAST(ALCbackend, backend); - } - - if(type == ALCbackend_Capture) - { - CaptureWrapper *backend; - - backend = CaptureWrapper_New(sizeof(*backend)); - if(!backend) return NULL; - - CaptureWrapper_Construct(backend, device, funcs); - - return STATIC_CAST(ALCbackend, backend); - } - - return NULL; -} diff --git a/love/src/jni/openal-soft-1.17.0/Alc/backends/opensl.c b/love/src/jni/openal-soft-1.17.0/Alc/backends/opensl.c deleted file mode 100644 index 220e6e5c..00000000 --- a/love/src/jni/openal-soft-1.17.0/Alc/backends/opensl.c +++ /dev/null @@ -1,424 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* This is an OpenAL backend for Android using the native audio APIs based on - * OpenSL ES 1.0.1. It is based on source code for the native-audio sample app - * bundled with NDK. - */ - -#include "config.h" - -#include - -#include "alMain.h" -#include "alu.h" - - -#include -#include - -/* Helper macros */ -#define VCALL(obj, func) ((*(obj))->func((obj), EXTRACT_VCALL_ARGS -#define VCALL0(obj, func) ((*(obj))->func((obj) EXTRACT_VCALL_ARGS - - -typedef struct { - /* engine interfaces */ - SLObjectItf engineObject; - SLEngineItf engine; - - /* output mix interfaces */ - SLObjectItf outputMix; - - /* buffer queue player interfaces */ - SLObjectItf bufferQueueObject; - - void *buffer; - ALuint bufferSize; - ALuint curBuffer; - - ALuint frameSize; -} osl_data; - - -static const ALCchar opensl_device[] = "OpenSL"; - - -static SLuint32 GetChannelMask(enum DevFmtChannels chans) -{ - switch(chans) - { - case DevFmtMono: return SL_SPEAKER_FRONT_CENTER; - case DevFmtStereo: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT; - case DevFmtQuad: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| - SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT; - case DevFmtX51: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| - SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| - SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT; - case DevFmtX61: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| - SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| - SL_SPEAKER_BACK_CENTER| - SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT; - case DevFmtX71: return SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT| - SL_SPEAKER_FRONT_CENTER|SL_SPEAKER_LOW_FREQUENCY| - SL_SPEAKER_BACK_LEFT|SL_SPEAKER_BACK_RIGHT| - SL_SPEAKER_SIDE_LEFT|SL_SPEAKER_SIDE_RIGHT; - case 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; - } - return 0; -} - -static const char *res_str(SLresult result) -{ - switch(result) - { - case SL_RESULT_SUCCESS: return "Success"; - case SL_RESULT_PRECONDITIONS_VIOLATED: return "Preconditions violated"; - case SL_RESULT_PARAMETER_INVALID: return "Parameter invalid"; - case SL_RESULT_MEMORY_FAILURE: return "Memory failure"; - case SL_RESULT_RESOURCE_ERROR: return "Resource error"; - case SL_RESULT_RESOURCE_LOST: return "Resource lost"; - case SL_RESULT_IO_ERROR: return "I/O error"; - case SL_RESULT_BUFFER_INSUFFICIENT: return "Buffer insufficient"; - case SL_RESULT_CONTENT_CORRUPTED: return "Content corrupted"; - case SL_RESULT_CONTENT_UNSUPPORTED: return "Content unsupported"; - case SL_RESULT_CONTENT_NOT_FOUND: return "Content not found"; - case SL_RESULT_PERMISSION_DENIED: return "Permission denied"; - case SL_RESULT_FEATURE_UNSUPPORTED: return "Feature unsupported"; - case SL_RESULT_INTERNAL_ERROR: return "Internal error"; - case SL_RESULT_UNKNOWN_ERROR: return "Unknown error"; - case SL_RESULT_OPERATION_ABORTED: return "Operation aborted"; - case SL_RESULT_CONTROL_LOST: return "Control lost"; -#ifdef SL_RESULT_READONLY - case SL_RESULT_READONLY: return "ReadOnly"; -#endif -#ifdef SL_RESULT_ENGINEOPTION_UNSUPPORTED - case SL_RESULT_ENGINEOPTION_UNSUPPORTED: return "Engine option unsupported"; -#endif -#ifdef SL_RESULT_SOURCE_SINK_INCOMPATIBLE - case SL_RESULT_SOURCE_SINK_INCOMPATIBLE: return "Source/Sink incompatible"; -#endif - } - return "Unknown error code"; -} - -#define PRINTERR(x, s) do { \ - if((x) != SL_RESULT_SUCCESS) \ - ERR("%s: %s\n", (s), res_str((x))); \ -} while(0) - -/* this callback handler is called every time a buffer finishes playing */ -static void opensl_callback(SLAndroidSimpleBufferQueueItf bq, void *context) -{ - ALCdevice *Device = context; - osl_data *data = Device->ExtraData; - ALvoid *buf; - SLresult result; - - buf = (ALbyte*)data->buffer + data->curBuffer*data->bufferSize; - aluMixData(Device, buf, data->bufferSize/data->frameSize); - - result = VCALL(bq,Enqueue)(buf, data->bufferSize); - PRINTERR(result, "bq->Enqueue"); - - data->curBuffer = (data->curBuffer+1) % Device->NumUpdates; -} - - -static ALCenum opensl_open_playback(ALCdevice *Device, const ALCchar *deviceName) -{ - osl_data *data = NULL; - SLresult result; - - if(!deviceName) - deviceName = opensl_device; - else if(strcmp(deviceName, opensl_device) != 0) - return ALC_INVALID_VALUE; - - data = calloc(1, sizeof(*data)); - if(!data) - return ALC_OUT_OF_MEMORY; - - // create engine - result = slCreateEngine(&data->engineObject, 0, NULL, 0, NULL, NULL); - PRINTERR(result, "slCreateEngine"); - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(data->engineObject,Realize)(SL_BOOLEAN_FALSE); - PRINTERR(result, "engine->Realize"); - } - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(data->engineObject,GetInterface)(SL_IID_ENGINE, &data->engine); - PRINTERR(result, "engine->GetInterface"); - } - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(data->engine,CreateOutputMix)(&data->outputMix, 0, NULL, NULL); - PRINTERR(result, "engine->CreateOutputMix"); - } - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(data->outputMix,Realize)(SL_BOOLEAN_FALSE); - PRINTERR(result, "outputMix->Realize"); - } - - if(SL_RESULT_SUCCESS != result) - { - if(data->outputMix != NULL) - VCALL0(data->outputMix,Destroy)(); - data->outputMix = NULL; - - if(data->engineObject != NULL) - VCALL0(data->engineObject,Destroy)(); - data->engineObject = NULL; - data->engine = NULL; - - free(data); - return ALC_INVALID_VALUE; - } - - al_string_copy_cstr(&Device->DeviceName, deviceName); - Device->ExtraData = data; - - return ALC_NO_ERROR; -} - - -static void opensl_close_playback(ALCdevice *Device) -{ - osl_data *data = Device->ExtraData; - - if(data->bufferQueueObject != NULL) - VCALL0(data->bufferQueueObject,Destroy)(); - data->bufferQueueObject = NULL; - - VCALL0(data->outputMix,Destroy)(); - data->outputMix = NULL; - - VCALL0(data->engineObject,Destroy)(); - data->engineObject = NULL; - data->engine = NULL; - - free(data); - Device->ExtraData = NULL; -} - -static ALCboolean opensl_reset_playback(ALCdevice *Device) -{ - osl_data *data = Device->ExtraData; - SLDataLocator_AndroidSimpleBufferQueue loc_bufq; - SLDataLocator_OutputMix loc_outmix; - SLDataFormat_PCM format_pcm; - SLDataSource audioSrc; - SLDataSink audioSnk; - SLInterfaceID id; - SLboolean req; - SLresult result; - - - Device->UpdateSize = (ALuint64)Device->UpdateSize * 44100 / Device->Frequency; - Device->UpdateSize = Device->UpdateSize * Device->NumUpdates / 2; - Device->NumUpdates = 2; - - Device->Frequency = 44100; - Device->FmtChans = DevFmtStereo; - Device->FmtType = DevFmtShort; - - SetDefaultWFXChannelOrder(Device); - - - id = SL_IID_ANDROIDSIMPLEBUFFERQUEUE; - req = SL_BOOLEAN_TRUE; - - loc_bufq.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; - loc_bufq.numBuffers = Device->NumUpdates; - - format_pcm.formatType = SL_DATAFORMAT_PCM; - format_pcm.numChannels = ChannelsFromDevFmt(Device->FmtChans); - format_pcm.samplesPerSec = Device->Frequency * 1000; - format_pcm.bitsPerSample = BytesFromDevFmt(Device->FmtType) * 8; - format_pcm.containerSize = format_pcm.bitsPerSample; - format_pcm.channelMask = GetChannelMask(Device->FmtChans); - format_pcm.endianness = IS_LITTLE_ENDIAN ? SL_BYTEORDER_LITTLEENDIAN : - SL_BYTEORDER_BIGENDIAN; - - audioSrc.pLocator = &loc_bufq; - audioSrc.pFormat = &format_pcm; - - loc_outmix.locatorType = SL_DATALOCATOR_OUTPUTMIX; - loc_outmix.outputMix = data->outputMix; - audioSnk.pLocator = &loc_outmix; - audioSnk.pFormat = NULL; - - - if(data->bufferQueueObject != NULL) - VCALL0(data->bufferQueueObject,Destroy)(); - data->bufferQueueObject = NULL; - - result = VCALL(data->engine,CreateAudioPlayer)(&data->bufferQueueObject, &audioSrc, &audioSnk, 1, &id, &req); - PRINTERR(result, "engine->CreateAudioPlayer"); - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(data->bufferQueueObject,Realize)(SL_BOOLEAN_FALSE); - PRINTERR(result, "bufferQueue->Realize"); - } - - if(SL_RESULT_SUCCESS != result) - { - if(data->bufferQueueObject != NULL) - VCALL0(data->bufferQueueObject,Destroy)(); - data->bufferQueueObject = NULL; - - return ALC_FALSE; - } - - return ALC_TRUE; -} - -static ALCboolean opensl_start_playback(ALCdevice *Device) -{ - osl_data *data = Device->ExtraData; - SLAndroidSimpleBufferQueueItf bufferQueue; - SLPlayItf player; - SLresult result; - ALuint i; - - result = VCALL(data->bufferQueueObject,GetInterface)(SL_IID_BUFFERQUEUE, &bufferQueue); - PRINTERR(result, "bufferQueue->GetInterface"); - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(bufferQueue,RegisterCallback)(opensl_callback, Device); - PRINTERR(result, "bufferQueue->RegisterCallback"); - } - if(SL_RESULT_SUCCESS == result) - { - data->frameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType); - data->bufferSize = Device->UpdateSize * data->frameSize; - data->buffer = calloc(Device->NumUpdates, data->bufferSize); - if(!data->buffer) - { - result = SL_RESULT_MEMORY_FAILURE; - PRINTERR(result, "calloc"); - } - } - /* enqueue the first buffer to kick off the callbacks */ - for(i = 0;i < Device->NumUpdates;i++) - { - if(SL_RESULT_SUCCESS == result) - { - ALvoid *buf = (ALbyte*)data->buffer + i*data->bufferSize; - result = VCALL(bufferQueue,Enqueue)(buf, data->bufferSize); - PRINTERR(result, "bufferQueue->Enqueue"); - } - } - data->curBuffer = 0; - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(data->bufferQueueObject,GetInterface)(SL_IID_PLAY, &player); - PRINTERR(result, "bufferQueue->GetInterface"); - } - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(player,SetPlayState)(SL_PLAYSTATE_PLAYING); - PRINTERR(result, "player->SetPlayState"); - } - - if(SL_RESULT_SUCCESS != result) - { - if(data->bufferQueueObject != NULL) - VCALL0(data->bufferQueueObject,Destroy)(); - data->bufferQueueObject = NULL; - - free(data->buffer); - data->buffer = NULL; - data->bufferSize = 0; - - return ALC_FALSE; - } - - return ALC_TRUE; -} - - -static void opensl_stop_playback(ALCdevice *Device) -{ - osl_data *data = Device->ExtraData; - SLPlayItf player; - SLAndroidSimpleBufferQueueItf bufferQueue; - SLresult result; - - result = VCALL(data->bufferQueueObject,GetInterface)(SL_IID_PLAY, &player); - PRINTERR(result, "bufferQueue->GetInterface"); - if(SL_RESULT_SUCCESS == result) - { - result = VCALL(player,SetPlayState)(SL_PLAYSTATE_STOPPED); - PRINTERR(result, "player->SetPlayState"); - } - - result = VCALL(data->bufferQueueObject,GetInterface)(SL_IID_BUFFERQUEUE, &bufferQueue); - PRINTERR(result, "bufferQueue->GetInterface"); - if(SL_RESULT_SUCCESS == result) - { - result = VCALL0(bufferQueue,Clear)(); - PRINTERR(result, "bufferQueue->Clear"); - } - - free(data->buffer); - data->buffer = NULL; - data->bufferSize = 0; -} - - -static const BackendFuncs opensl_funcs = { - opensl_open_playback, - opensl_close_playback, - opensl_reset_playback, - opensl_start_playback, - opensl_stop_playback, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - ALCdevice_GetLatencyDefault -}; - - -ALCboolean alc_opensl_init(BackendFuncs *func_list) -{ - *func_list = opensl_funcs; - return ALC_TRUE; -} - -void alc_opensl_deinit(void) -{ -} - -void alc_opensl_probe(enum DevProbe type) -{ - switch(type) - { - case ALL_DEVICE_PROBE: - AppendAllDevicesList(opensl_device); - break; - case CAPTURE_DEVICE_PROBE: - break; - } -} diff --git a/love/src/jni/openal-soft-1.17.0/Alc/backends/portaudio.c b/love/src/jni/openal-soft-1.17.0/Alc/backends/portaudio.c deleted file mode 100644 index 5f11526d..00000000 --- a/love/src/jni/openal-soft-1.17.0/Alc/backends/portaudio.c +++ /dev/null @@ -1,469 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 1999-2007 by authors. - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include - -#include "alMain.h" -#include "alu.h" -#include "compat.h" - -#include - - -static const ALCchar pa_device[] = "PortAudio Default"; - - -#ifdef HAVE_DYNLOAD -static void *pa_handle; -#define MAKE_FUNC(x) static __typeof(x) * p##x -MAKE_FUNC(Pa_Initialize); -MAKE_FUNC(Pa_Terminate); -MAKE_FUNC(Pa_GetErrorText); -MAKE_FUNC(Pa_StartStream); -MAKE_FUNC(Pa_StopStream); -MAKE_FUNC(Pa_OpenStream); -MAKE_FUNC(Pa_CloseStream); -MAKE_FUNC(Pa_GetDefaultOutputDevice); -MAKE_FUNC(Pa_GetDefaultInputDevice); -MAKE_FUNC(Pa_GetStreamInfo); -#undef MAKE_FUNC - -#define Pa_Initialize pPa_Initialize -#define Pa_Terminate pPa_Terminate -#define Pa_GetErrorText pPa_GetErrorText -#define Pa_StartStream pPa_StartStream -#define Pa_StopStream pPa_StopStream -#define Pa_OpenStream pPa_OpenStream -#define Pa_CloseStream pPa_CloseStream -#define Pa_GetDefaultOutputDevice pPa_GetDefaultOutputDevice -#define Pa_GetDefaultInputDevice pPa_GetDefaultInputDevice -#define Pa_GetStreamInfo pPa_GetStreamInfo -#endif - -static ALCboolean pa_load(void) -{ - PaError err; - -#ifdef HAVE_DYNLOAD - if(!pa_handle) - { -#ifdef _WIN32 -# define PALIB "portaudio.dll" -#elif defined(__APPLE__) && defined(__MACH__) -# define PALIB "libportaudio.2.dylib" -#elif defined(__OpenBSD__) -# define PALIB "libportaudio.so" -#else -# define PALIB "libportaudio.so.2" -#endif - - pa_handle = LoadLib(PALIB); - if(!pa_handle) - return ALC_FALSE; - -#define LOAD_FUNC(f) do { \ - p##f = GetSymbol(pa_handle, #f); \ - if(p##f == NULL) \ - { \ - CloseLib(pa_handle); \ - pa_handle = NULL; \ - return ALC_FALSE; \ - } \ -} while(0) - LOAD_FUNC(Pa_Initialize); - LOAD_FUNC(Pa_Terminate); - LOAD_FUNC(Pa_GetErrorText); - LOAD_FUNC(Pa_StartStream); - LOAD_FUNC(Pa_StopStream); - LOAD_FUNC(Pa_OpenStream); - LOAD_FUNC(Pa_CloseStream); - LOAD_FUNC(Pa_GetDefaultOutputDevice); - LOAD_FUNC(Pa_GetDefaultInputDevice); - LOAD_FUNC(Pa_GetStreamInfo); -#undef LOAD_FUNC - - if((err=Pa_Initialize()) != paNoError) - { - ERR("Pa_Initialize() returned an error: %s\n", Pa_GetErrorText(err)); - CloseLib(pa_handle); - pa_handle = NULL; - return ALC_FALSE; - } - } -#else - if((err=Pa_Initialize()) != paNoError) - { - ERR("Pa_Initialize() returned an error: %s\n", Pa_GetErrorText(err)); - return ALC_FALSE; - } -#endif - return ALC_TRUE; -} - - -typedef struct { - PaStream *stream; - PaStreamParameters params; - ALuint update_size; - - RingBuffer *ring; -} pa_data; - - -static int pa_callback(const void *UNUSED(inputBuffer), void *outputBuffer, - unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo), - const PaStreamCallbackFlags UNUSED(statusFlags), void *userData) -{ - ALCdevice *device = (ALCdevice*)userData; - - aluMixData(device, outputBuffer, framesPerBuffer); - return 0; -} - -static int pa_capture_cb(const void *inputBuffer, void *UNUSED(outputBuffer), - unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo *UNUSED(timeInfo), - const PaStreamCallbackFlags UNUSED(statusFlags), void *userData) -{ - ALCdevice *device = (ALCdevice*)userData; - pa_data *data = (pa_data*)device->ExtraData; - - WriteRingBuffer(data->ring, inputBuffer, framesPerBuffer); - return 0; -} - - -static ALCenum pa_open_playback(ALCdevice *device, const ALCchar *deviceName) -{ - pa_data *data; - PaError err; - - if(!deviceName) - deviceName = pa_device; - else if(strcmp(deviceName, pa_device) != 0) - return ALC_INVALID_VALUE; - - data = (pa_data*)calloc(1, sizeof(pa_data)); - data->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) / - (float)device->Frequency; - data->params.hostApiSpecificStreamInfo = NULL; - - data->params.channelCount = ((device->FmtChans == DevFmtMono) ? 1 : 2); - - switch(device->FmtType) - { - case DevFmtByte: - data->params.sampleFormat = paInt8; - break; - case DevFmtUByte: - data->params.sampleFormat = paUInt8; - break; - case DevFmtUShort: - /* fall-through */ - case DevFmtShort: - data->params.sampleFormat = paInt16; - break; - case DevFmtUInt: - /* fall-through */ - case DevFmtInt: - data->params.sampleFormat = paInt32; - break; - case DevFmtFloat: - data->params.sampleFormat = paFloat32; - break; - } - -retry_open: - err = Pa_OpenStream(&data->stream, NULL, &data->params, device->Frequency, - device->UpdateSize, paNoFlag, pa_callback, device); - if(err != paNoError) - { - if(data->params.sampleFormat == paFloat32) - { - data->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); - - return ALC_NO_ERROR; -} - -static void pa_close_playback(ALCdevice *device) -{ - pa_data *data = (pa_data*)device->ExtraData; - PaError err; - - err = Pa_CloseStream(data->stream); - if(err != paNoError) - ERR("Error closing stream: %s\n", Pa_GetErrorText(err)); - - free(data); - device->ExtraData = NULL; -} - -static ALCboolean pa_reset_playback(ALCdevice *device) -{ - pa_data *data = (pa_data*)device->ExtraData; - const PaStreamInfo *streamInfo; - - streamInfo = Pa_GetStreamInfo(data->stream); - device->Frequency = streamInfo->sampleRate; - device->UpdateSize = data->update_size; - - if(data->params.sampleFormat == paInt8) - device->FmtType = DevFmtByte; - else if(data->params.sampleFormat == paUInt8) - device->FmtType = DevFmtUByte; - else if(data->params.sampleFormat == paInt16) - device->FmtType = DevFmtShort; - else if(data->params.sampleFormat == paInt32) - device->FmtType = DevFmtInt; - else if(data->params.sampleFormat == paFloat32) - device->FmtType = DevFmtFloat; - else - { - ERR("Unexpected sample format: 0x%lx\n", data->params.sampleFormat); - return ALC_FALSE; - } - - if(data->params.channelCount == 2) - device->FmtChans = DevFmtStereo; - else if(data->params.channelCount == 1) - device->FmtChans = DevFmtMono; - else - { - ERR("Unexpected channel count: %u\n", data->params.channelCount); - return ALC_FALSE; - } - SetDefaultChannelOrder(device); - - return ALC_TRUE; -} - -static ALCboolean pa_start_playback(ALCdevice *device) -{ - pa_data *data = (pa_data*)device->ExtraData; - PaError err; - - err = Pa_StartStream(data->stream); - if(err != paNoError) - { - ERR("Pa_StartStream() returned an error: %s\n", Pa_GetErrorText(err)); - return ALC_FALSE; - } - - return ALC_TRUE; -} - -static void pa_stop_playback(ALCdevice *device) -{ - pa_data *data = (pa_data*)device->ExtraData; - PaError err; - - err = Pa_StopStream(data->stream); - if(err != paNoError) - ERR("Error stopping stream: %s\n", Pa_GetErrorText(err)); -} - - -static ALCenum pa_open_capture(ALCdevice *device, const ALCchar *deviceName) -{ - ALuint frame_size; - pa_data *data; - PaError err; - - if(!deviceName) - deviceName = pa_device; - else if(strcmp(deviceName, pa_device) != 0) - return ALC_INVALID_VALUE; - - data = (pa_data*)calloc(1, sizeof(pa_data)); - if(data == NULL) - return ALC_OUT_OF_MEMORY; - - 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; - - switch(device->FmtType) - { - case DevFmtByte: - data->params.sampleFormat = paInt8; - break; - case DevFmtUByte: - data->params.sampleFormat = paUInt8; - break; - case DevFmtShort: - data->params.sampleFormat = paInt16; - break; - case DevFmtInt: - data->params.sampleFormat = paInt32; - break; - case DevFmtFloat: - data->params.sampleFormat = paFloat32; - break; - case DevFmtUInt: - case DevFmtUShort: - ERR("%s samples not supported\n", DevFmtTypeString(device->FmtType)); - goto error; - } - data->params.channelCount = ChannelsFromDevFmt(device->FmtChans); - - err = Pa_OpenStream(&data->stream, &data->params, NULL, device->Frequency, - paFramesPerBufferUnspecified, paNoFlag, pa_capture_cb, device); - if(err != paNoError) - { - ERR("Pa_OpenStream() returned an error: %s\n", Pa_GetErrorText(err)); - goto error; - } - - al_string_copy_cstr(&device->DeviceName, deviceName); - - device->ExtraData = data; - return ALC_NO_ERROR; - -error: - DestroyRingBuffer(data->ring); - free(data); - return ALC_INVALID_VALUE; -} - -static void pa_close_capture(ALCdevice *device) -{ - pa_data *data = (pa_data*)device->ExtraData; - PaError err; - - err = Pa_CloseStream(data->stream); - if(err != paNoError) - ERR("Error closing stream: %s\n", Pa_GetErrorText(err)); - - DestroyRingBuffer(data->ring); - data->ring = NULL; - - free(data); - device->ExtraData = NULL; -} - -static void pa_start_capture(ALCdevice *device) -{ - pa_data *data = device->ExtraData; - PaError err; - - err = Pa_StartStream(data->stream); - if(err != paNoError) - ERR("Error starting stream: %s\n", Pa_GetErrorText(err)); -} - -static void pa_stop_capture(ALCdevice *device) -{ - pa_data *data = (pa_data*)device->ExtraData; - PaError err; - - err = Pa_StopStream(data->stream); - if(err != paNoError) - ERR("Error stopping stream: %s\n", Pa_GetErrorText(err)); -} - -static ALCenum pa_capture_samples(ALCdevice *device, ALCvoid *buffer, ALCuint samples) -{ - pa_data *data = device->ExtraData; - ReadRingBuffer(data->ring, buffer, samples); - return ALC_NO_ERROR; -} - -static ALCuint pa_available_samples(ALCdevice *device) -{ - pa_data *data = device->ExtraData; - return RingBufferSize(data->ring); -} - - -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) -{ - if(!pa_load()) - return ALC_FALSE; - *func_list = pa_funcs; - return ALC_TRUE; -} - -void alc_pa_deinit(void) -{ -#ifdef HAVE_DYNLOAD - if(pa_handle) - { - Pa_Terminate(); - CloseLib(pa_handle); - pa_handle = NULL; - } -#else - Pa_Terminate(); -#endif -} - -void alc_pa_probe(enum DevProbe type) -{ - switch(type) - { - case ALL_DEVICE_PROBE: - AppendAllDevicesList(pa_device); - break; - case CAPTURE_DEVICE_PROBE: - AppendCaptureDeviceList(pa_device); - break; - } -} diff --git a/love/src/jni/openal-soft-1.17.0/Alc/backends/sndio.c b/love/src/jni/openal-soft-1.17.0/Alc/backends/sndio.c deleted file mode 100644 index 7152b2d6..00000000 --- a/love/src/jni/openal-soft-1.17.0/Alc/backends/sndio.c +++ /dev/null @@ -1,295 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 1999-2007 by authors. - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include - -#include "alMain.h" -#include "alu.h" -#include "threads.h" - -#include - - -static const ALCchar sndio_device[] = "SndIO Default"; - - -static ALCboolean sndio_load(void) -{ - return ALC_TRUE; -} - - -typedef struct { - struct sio_hdl *sndHandle; - - ALvoid *mix_data; - ALsizei data_size; - - volatile int killNow; - althrd_t thread; -} sndio_data; - - -static int sndio_proc(void *ptr) -{ - ALCdevice *device = ptr; - sndio_data *data = device->ExtraData; - ALsizei frameSize; - size_t wrote; - - SetRTPriority(); - althrd_setname(althrd_current(), MIXER_THREAD_NAME); - - frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); - - while(!data->killNow && device->Connected) - { - ALsizei len = data->data_size; - ALubyte *WritePtr = data->mix_data; - - aluMixData(device, WritePtr, len/frameSize); - while(len > 0 && !data->killNow) - { - wrote = sio_write(data->sndHandle, WritePtr, len); - if(wrote == 0) - { - ERR("sio_write failed\n"); - ALCdevice_Lock(device); - aluHandleDisconnect(device); - ALCdevice_Unlock(device); - break; - } - - len -= wrote; - WritePtr += wrote; - } - } - - return 0; -} - - - -static ALCenum sndio_open_playback(ALCdevice *device, const ALCchar *deviceName) -{ - sndio_data *data; - - if(!deviceName) - deviceName = sndio_device; - else if(strcmp(deviceName, sndio_device) != 0) - return ALC_INVALID_VALUE; - - data = calloc(1, sizeof(*data)); - data->killNow = 0; - - data->sndHandle = sio_open(NULL, SIO_PLAY, 0); - if(data->sndHandle == NULL) - { - free(data); - ERR("Could not open device\n"); - return ALC_INVALID_VALUE; - } - - al_string_copy_cstr(&device->DeviceName, deviceName); - device->ExtraData = data; - - return ALC_NO_ERROR; -} - -static void sndio_close_playback(ALCdevice *device) -{ - sndio_data *data = device->ExtraData; - - sio_close(data->sndHandle); - free(data); - device->ExtraData = NULL; -} - -static ALCboolean sndio_reset_playback(ALCdevice *device) -{ - sndio_data *data = device->ExtraData; - struct sio_par par; - - sio_initpar(&par); - - par.rate = device->Frequency; - par.pchan = ((device->FmtChans != DevFmtMono) ? 2 : 1); - - switch(device->FmtType) - { - case DevFmtByte: - par.bits = 8; - par.sig = 1; - break; - case DevFmtUByte: - par.bits = 8; - par.sig = 0; - break; - case DevFmtFloat: - case DevFmtShort: - par.bits = 16; - par.sig = 1; - break; - case DevFmtUShort: - par.bits = 16; - par.sig = 0; - break; - case DevFmtInt: - par.bits = 32; - par.sig = 1; - break; - case DevFmtUInt: - par.bits = 32; - par.sig = 0; - break; - } - par.le = SIO_LE_NATIVE; - - par.round = device->UpdateSize; - par.appbufsz = device->UpdateSize * (device->NumUpdates-1); - if(!par.appbufsz) par.appbufsz = device->UpdateSize; - - if(!sio_setpar(data->sndHandle, &par) || !sio_getpar(data->sndHandle, &par)) - { - ERR("Failed to set device parameters\n"); - return ALC_FALSE; - } - - if(par.bits != par.bps*8) - { - ERR("Padded samples not supported (%u of %u bits)\n", par.bits, par.bps*8); - return ALC_FALSE; - } - - device->Frequency = par.rate; - device->FmtChans = ((par.pchan==1) ? DevFmtMono : DevFmtStereo); - - if(par.bits == 8 && par.sig == 1) - device->FmtType = DevFmtByte; - else if(par.bits == 8 && par.sig == 0) - device->FmtType = DevFmtUByte; - else if(par.bits == 16 && par.sig == 1) - device->FmtType = DevFmtShort; - else if(par.bits == 16 && par.sig == 0) - device->FmtType = DevFmtUShort; - else if(par.bits == 32 && par.sig == 1) - device->FmtType = DevFmtInt; - else if(par.bits == 32 && par.sig == 0) - device->FmtType = DevFmtUInt; - else - { - ERR("Unhandled sample format: %s %u-bit\n", (par.sig?"signed":"unsigned"), par.bits); - return ALC_FALSE; - } - - device->UpdateSize = par.round; - device->NumUpdates = (par.bufsz/par.round) + 1; - - SetDefaultChannelOrder(device); - - return ALC_TRUE; -} - -static ALCboolean sndio_start_playback(ALCdevice *device) -{ - sndio_data *data = device->ExtraData; - - if(!sio_start(data->sndHandle)) - { - ERR("Error starting playback\n"); - return ALC_FALSE; - } - - 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, sndio_proc, device) != althrd_success) - { - sio_stop(data->sndHandle); - free(data->mix_data); - data->mix_data = NULL; - return ALC_FALSE; - } - - return ALC_TRUE; -} - -static void sndio_stop_playback(ALCdevice *device) -{ - sndio_data *data = device->ExtraData; - int res; - - if(data->killNow) - return; - - data->killNow = 1; - althrd_join(data->thread, &res); - - if(!sio_stop(data->sndHandle)) - ERR("Error stopping device\n"); - - free(data->mix_data); - data->mix_data = NULL; -} - - -static const BackendFuncs sndio_funcs = { - sndio_open_playback, - sndio_close_playback, - sndio_reset_playback, - sndio_start_playback, - sndio_stop_playback, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - ALCdevice_GetLatencyDefault -}; - -ALCboolean alc_sndio_init(BackendFuncs *func_list) -{ - if(!sndio_load()) - return ALC_FALSE; - *func_list = sndio_funcs; - return ALC_TRUE; -} - -void alc_sndio_deinit(void) -{ -} - -void alc_sndio_probe(enum DevProbe type) -{ - switch(type) - { - case ALL_DEVICE_PROBE: - AppendAllDevicesList(sndio_device); - break; - case CAPTURE_DEVICE_PROBE: - break; - } -} diff --git a/love/src/jni/openal-soft-1.17.0/Alc/backends/solaris.c b/love/src/jni/openal-soft-1.17.0/Alc/backends/solaris.c deleted file mode 100644 index 20d861d2..00000000 --- a/love/src/jni/openal-soft-1.17.0/Alc/backends/solaris.c +++ /dev/null @@ -1,288 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 1999-2007 by authors. - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "alMain.h" -#include "alu.h" -#include "threads.h" -#include "compat.h" - -#include - - -static const ALCchar solaris_device[] = "Solaris Default"; - -static const char *solaris_driver = "/dev/audio"; - -typedef struct { - int fd; - - ALubyte *mix_data; - int data_size; - - volatile int killNow; - althrd_t thread; -} solaris_data; - - -static int SolarisProc(void *ptr) -{ - ALCdevice *Device = (ALCdevice*)ptr; - solaris_data *data = (solaris_data*)Device->ExtraData; - ALint frameSize; - int wrote; - - SetRTPriority(); - althrd_setname(althrd_current(), MIXER_THREAD_NAME); - - frameSize = FrameSizeFromDevFmt(Device->FmtChans, Device->FmtType); - - while(!data->killNow && Device->Connected) - { - ALint len = data->data_size; - ALubyte *WritePtr = data->mix_data; - - aluMixData(Device, WritePtr, len/frameSize); - while(len > 0 && !data->killNow) - { - wrote = write(data->fd, WritePtr, len); - if(wrote < 0) - { - if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) - { - ERR("write failed: %s\n", strerror(errno)); - ALCdevice_Lock(Device); - aluHandleDisconnect(Device); - ALCdevice_Unlock(Device); - break; - } - - al_nssleep(0, 1000000); - continue; - } - - len -= wrote; - WritePtr += wrote; - } - } - - return 0; -} - - -static ALCenum solaris_open_playback(ALCdevice *device, const ALCchar *deviceName) -{ - solaris_data *data; - - if(!deviceName) - deviceName = solaris_device; - else if(strcmp(deviceName, 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) - { - 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; - return ALC_NO_ERROR; -} - -static void solaris_close_playback(ALCdevice *device) -{ - solaris_data *data = (solaris_data*)device->ExtraData; - - close(data->fd); - free(data); - device->ExtraData = NULL; -} - -static ALCboolean solaris_reset_playback(ALCdevice *device) -{ - solaris_data *data = (solaris_data*)device->ExtraData; - audio_info_t info; - ALuint frameSize; - int numChannels; - - AUDIO_INITINFO(&info); - - info.play.sample_rate = device->Frequency; - - if(device->FmtChans != DevFmtMono) - device->FmtChans = DevFmtStereo; - numChannels = ChannelsFromDevFmt(device->FmtChans); - info.play.channels = numChannels; - - switch(device->FmtType) - { - case DevFmtByte: - info.play.precision = 8; - info.play.encoding = AUDIO_ENCODING_LINEAR; - break; - case DevFmtUByte: - info.play.precision = 8; - info.play.encoding = AUDIO_ENCODING_LINEAR8; - break; - case DevFmtUShort: - case DevFmtInt: - case DevFmtUInt: - case DevFmtFloat: - device->FmtType = DevFmtShort; - /* fall-through */ - case DevFmtShort: - info.play.precision = 16; - info.play.encoding = AUDIO_ENCODING_LINEAR; - break; - } - - frameSize = numChannels * BytesFromDevFmt(device->FmtType); - info.play.buffer_size = device->UpdateSize*device->NumUpdates * frameSize; - - if(ioctl(data->fd, AUDIO_SETINFO, &info) < 0) - { - ERR("ioctl failed: %s\n", strerror(errno)); - return ALC_FALSE; - } - - if(ChannelsFromDevFmt(device->FmtChans) != info.play.channels) - { - ERR("Could not set %d channels, got %d instead\n", ChannelsFromDevFmt(device->FmtChans), info.play.channels); - return ALC_FALSE; - } - - if(!((info.play.precision == 8 && info.play.encoding == AUDIO_ENCODING_LINEAR8 && device->FmtType == DevFmtUByte) || - (info.play.precision == 8 && info.play.encoding == AUDIO_ENCODING_LINEAR && device->FmtType == DevFmtByte) || - (info.play.precision == 16 && info.play.encoding == AUDIO_ENCODING_LINEAR && device->FmtType == DevFmtShort) || - (info.play.precision == 32 && info.play.encoding == AUDIO_ENCODING_LINEAR && device->FmtType == DevFmtInt))) - { - ERR("Could not set %s samples, got %d (0x%x)\n", DevFmtTypeString(device->FmtType), - info.play.precision, info.play.encoding); - return ALC_FALSE; - } - - device->Frequency = info.play.sample_rate; - device->UpdateSize = (info.play.buffer_size/device->NumUpdates) + 1; - - SetDefaultChannelOrder(device); - - return ALC_TRUE; -} - -static ALCboolean solaris_start_playback(ALCdevice *device) -{ - 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; - return ALC_FALSE; - } - - return ALC_TRUE; -} - -static void solaris_stop_playback(ALCdevice *device) -{ - solaris_data *data = (solaris_data*)device->ExtraData; - int res; - - if(data->killNow) - return; - - data->killNow = 1; - althrd_join(data->thread, &res); - - if(ioctl(data->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 -}; - -ALCboolean alc_solaris_init(BackendFuncs *func_list) -{ - ConfigValueStr("solaris", "device", &solaris_driver); - - *func_list = solaris_funcs; - return ALC_TRUE; -} - -void alc_solaris_deinit(void) -{ -} - -void alc_solaris_probe(enum DevProbe type) -{ - switch(type) - { - case ALL_DEVICE_PROBE: - { -#ifdef HAVE_STAT - struct stat buf; - if(stat(solaris_driver, &buf) == 0) -#endif - AppendAllDevicesList(solaris_device); - } - break; - - case CAPTURE_DEVICE_PROBE: - break; - } -} diff --git a/love/src/jni/openal-soft-1.17.0/Alc/backends/wave.c b/love/src/jni/openal-soft-1.17.0/Alc/backends/wave.c deleted file mode 100644 index 421ca5d7..00000000 --- a/love/src/jni/openal-soft-1.17.0/Alc/backends/wave.c +++ /dev/null @@ -1,377 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 1999-2007 by authors. - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#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; - - -static const ALCchar waveDevice[] = "Wave File Writer"; - -static const ALubyte SUBTYPE_PCM[] = { - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, - 0x00, 0x38, 0x9b, 0x71 -}; -static const ALubyte SUBTYPE_FLOAT[] = { - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0xaa, - 0x00, 0x38, 0x9b, 0x71 -}; - -static const 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 void fwrite16le(ALushort val, FILE *f) -{ - fputc(val&0xff, f); - fputc((val>>8)&0xff, f); -} - -static void fwrite32le(ALuint val, FILE *f) -{ - fputc(val&0xff, f); - fputc((val>>8)&0xff, f); - fputc((val>>16)&0xff, f); - fputc((val>>24)&0xff, f); -} - - -static int WaveProc(void *ptr) -{ - ALCdevice *device = (ALCdevice*)ptr; - wave_data *data = (wave_data*)device->ExtraData; - struct timespec now, start; - ALint64 avail, done; - ALuint frameSize; - size_t fs; - const long restTime = (long)((ALuint64)device->UpdateSize * 1000000000 / - device->Frequency / 2); - - althrd_setname(althrd_current(), MIXER_THREAD_NAME); - - frameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType); - - done = 0; - if(altimespec_get(&start, AL_TIME_UTC) != AL_TIME_UTC) - { - ERR("Failed to get starting time\n"); - return 1; - } - while(!data->killNow && device->Connected) - { - if(altimespec_get(&now, AL_TIME_UTC) != AL_TIME_UTC) - { - ERR("Failed to get current time\n"); - return 1; - } - - avail = (now.tv_sec - start.tv_sec) * device->Frequency; - avail += (ALint64)(now.tv_nsec - start.tv_nsec) * device->Frequency / 1000000000; - if(avail < done) - { - /* Oops, time skipped backwards. Reset the number of samples done - * with one update available since we (likely) just came back from - * sleeping. */ - done = avail - device->UpdateSize; - } - - if(avail-done < device->UpdateSize) - al_nssleep(0, restTime); - else while(avail-done >= device->UpdateSize) - { - aluMixData(device, data->buffer, device->UpdateSize); - done += device->UpdateSize; - - if(!IS_LITTLE_ENDIAN) - { - ALuint bytesize = BytesFromDevFmt(device->FmtType); - ALubyte *bytes = data->buffer; - ALuint i; - - if(bytesize == 1) - { - for(i = 0;i < data->size;i++) - fputc(bytes[i], data->f); - } - else if(bytesize == 2) - { - for(i = 0;i < data->size;i++) - fputc(bytes[i^1], data->f); - } - else if(bytesize == 4) - { - for(i = 0;i < data->size;i++) - fputc(bytes[i^3], data->f); - } - } - else - { - fs = fwrite(data->buffer, frameSize, device->UpdateSize, - data->f); - (void)fs; - } - if(ferror(data->f)) - { - ERR("Error writing to file\n"); - ALCdevice_Lock(device); - aluHandleDisconnect(device); - ALCdevice_Unlock(device); - break; - } - } - } - - return 0; -} - -static ALCenum wave_open_playback(ALCdevice *device, const ALCchar *deviceName) -{ - wave_data *data; - const char *fname; - - fname = GetConfigValue("wave", "file", ""); - if(!fname[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) - { - 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; - return ALC_NO_ERROR; -} - -static void wave_close_playback(ALCdevice *device) -{ - wave_data *data = (wave_data*)device->ExtraData; - - fclose(data->f); - free(data); - device->ExtraData = NULL; -} - -static ALCboolean wave_reset_playback(ALCdevice *device) -{ - wave_data *data = (wave_data*)device->ExtraData; - ALuint channels=0, bits=0; - size_t val; - - fseek(data->f, 0, SEEK_SET); - clearerr(data->f); - - switch(device->FmtType) - { - case DevFmtByte: - device->FmtType = DevFmtUByte; - break; - case DevFmtUShort: - device->FmtType = DevFmtShort; - break; - case DevFmtUInt: - device->FmtType = DevFmtInt; - break; - case DevFmtUByte: - case DevFmtShort: - case DevFmtInt: - case DevFmtFloat: - break; - } - 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(data->f, "WAVE"); - - fprintf(data->f, "fmt "); - fwrite32le(40, data->f); // 'fmt ' header len; 40 bytes for EXTENSIBLE - - // 16-bit val, format type id (extensible: 0xFFFE) - fwrite16le(0xFFFE, data->f); - // 16-bit val, channel count - fwrite16le(channels, data->f); - // 32-bit val, frequency - fwrite32le(device->Frequency, data->f); - // 32-bit val, bytes per second - fwrite32le(device->Frequency * channels * bits / 8, data->f); - // 16-bit val, frame size - fwrite16le(channels * bits / 8, data->f); - // 16-bit val, bits per sample - fwrite16le(bits, data->f); - // 16-bit val, extra byte count - fwrite16le(22, data->f); - // 16-bit val, valid bits per sample - fwrite16le(bits, data->f); - // 32-bit val, channel mask - fwrite32le(channel_masks[channels], data->f); - // 16 byte GUID, sub-type format - val = fwrite(((bits==32) ? SUBTYPE_FLOAT : SUBTYPE_PCM), 1, 16, data->f); - (void)val; - - fprintf(data->f, "data"); - fwrite32le(0xFFFFFFFF, data->f); // 'data' header len; filled in at close - - if(ferror(data->f)) - { - ERR("Error writing header: %s\n", strerror(errno)); - return ALC_FALSE; - } - data->DataStart = ftell(data->f); - - SetDefaultWFXChannelOrder(device); - - return ALC_TRUE; -} - -static ALCboolean wave_start_playback(ALCdevice *device) -{ - wave_data *data = (wave_data*)device->ExtraData; - - data->size = device->UpdateSize * FrameSizeFromDevFmt(device->FmtChans, device->FmtType); - data->buffer = malloc(data->size); - if(!data->buffer) - { - ERR("Buffer malloc failed\n"); - return ALC_FALSE; - } - - data->killNow = 0; - if(althrd_create(&data->thread, WaveProc, device) != althrd_success) - { - free(data->buffer); - data->buffer = NULL; - return ALC_FALSE; - } - - return ALC_TRUE; -} - -static void wave_stop_playback(ALCdevice *device) -{ - wave_data *data = (wave_data*)device->ExtraData; - ALuint dataLen; - long size; - int res; - - if(data->killNow) - return; - - data->killNow = 1; - althrd_join(data->thread, &res); - - free(data->buffer); - data->buffer = NULL; - - size = ftell(data->f); - 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 - } -} - - -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 -}; - -ALCboolean alc_wave_init(BackendFuncs *func_list) -{ - *func_list = wave_funcs; - return ALC_TRUE; -} - -void alc_wave_deinit(void) -{ -} - -void alc_wave_probe(enum DevProbe type) -{ - if(!ConfigValueExists("wave", "file")) - return; - - switch(type) - { - case ALL_DEVICE_PROBE: - AppendAllDevicesList(waveDevice); - break; - case CAPTURE_DEVICE_PROBE: - break; - } -} diff --git a/love/src/jni/openal-soft-1.17.0/Alc/backends/winmm.c b/love/src/jni/openal-soft-1.17.0/Alc/backends/winmm.c deleted file mode 100644 index cad66470..00000000 --- a/love/src/jni/openal-soft-1.17.0/Alc/backends/winmm.c +++ /dev/null @@ -1,716 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 1999-2007 by authors. - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include - -#include -#include - -#include "alMain.h" -#include "alu.h" -#include "threads.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; - - -TYPEDEF_VECTOR(al_string, vector_al_string) -static vector_al_string PlaybackDevices; -static vector_al_string CaptureDevices; - -static void clear_devlist(vector_al_string *list) -{ - VECTOR_FOR_EACH(al_string, *list, al_string_deinit); - VECTOR_RESIZE(*list, 0); -} - - -static void ProbePlaybackDevices(void) -{ - al_string *iter, *end; - ALuint numdevs; - ALuint i; - - clear_devlist(&PlaybackDevices); - - numdevs = waveOutGetNumDevs(); - VECTOR_RESERVE(PlaybackDevices, numdevs); - for(i = 0;i < numdevs;i++) - { - WAVEOUTCAPSW WaveCaps; - al_string dname; - - AL_STRING_INIT(dname); - if(waveOutGetDevCapsW(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR) - { - ALuint count = 0; - do { - al_string_copy_wcstr(&dname, WaveCaps.szPname); - if(count != 0) - { - char str[64]; - snprintf(str, sizeof(str), " #%d", 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); - - TRACE("Got device \"%s\", ID %u\n", al_string_get_cstr(dname), i); - } - VECTOR_PUSH_BACK(PlaybackDevices, dname); - } -} - -static void ProbeCaptureDevices(void) -{ - al_string *iter, *end; - ALuint numdevs; - ALuint i; - - clear_devlist(&CaptureDevices); - - numdevs = waveInGetNumDevs(); - VECTOR_RESERVE(CaptureDevices, numdevs); - for(i = 0;i < numdevs;i++) - { - WAVEINCAPSW WaveCaps; - al_string dname; - - AL_STRING_INIT(dname); - if(waveInGetDevCapsW(i, &WaveCaps, sizeof(WaveCaps)) == MMSYSERR_NOERROR) - { - ALuint count = 0; - do { - al_string_copy_wcstr(&dname, WaveCaps.szPname); - if(count != 0) - { - char str[64]; - snprintf(str, sizeof(str), " #%d", 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); - - TRACE("Got device \"%s\", ID %u\n", al_string_get_cstr(dname), i); - } - VECTOR_PUSH_BACK(CaptureDevices, dname); - } -} - - -/* - WaveOutProc - - 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)) -{ - ALCdevice *Device = (ALCdevice*)instance; - WinMMData *data = Device->ExtraData; - - if(msg != WOM_DONE) - return; - - DecrementRef(&data->WaveBuffersCommitted); - PostThreadMessage(data->thread, msg, 0, param1); -} - -FORCE_ALIGN static int PlaybackThreadProc(void *arg) -{ - ALCdevice *Device = (ALCdevice*)arg; - WinMMData *data = Device->ExtraData; - WAVEHDR *WaveHdr; - MSG msg; - - SetRTPriority(); - althrd_setname(althrd_current(), MIXER_THREAD_NAME); - - while(GetMessage(&msg, NULL, 0, 0)) - { - if(msg.message != WOM_DONE) - continue; - - if(data->killNow) - { - if(ReadRef(&data->WaveBuffersCommitted) == 0) - break; - continue; - } - - WaveHdr = ((WAVEHDR*)msg.lParam); - aluMixData(Device, WaveHdr->lpData, WaveHdr->dwBufferLength / - data->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); - } - - return 0; -} - - -static ALCenum WinMMOpenPlayback(ALCdevice *Device, const ALCchar *deviceName) -{ - WinMMData *data = NULL; - const al_string *iter, *end; - UINT DeviceID; - MMRESULT res; - - if(VECTOR_SIZE(PlaybackDevices) == 0) - 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) - return ALC_INVALID_VALUE; - - data = calloc(1, sizeof(*data)); - if(!data) - return ALC_OUT_OF_MEMORY; - Device->ExtraData = data; - -retry_open: - memset(&data->Format, 0, sizeof(WAVEFORMATEX)); - if(Device->FmtType == DevFmtFloat) - { - data->Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; - data->Format.wBitsPerSample = 32; - } - else - { - data->Format.wFormatTag = WAVE_FORMAT_PCM; - if(Device->FmtType == DevFmtUByte || Device->FmtType == DevFmtByte) - data->Format.wBitsPerSample = 8; - else - data->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; - - if((res=waveOutOpen(&data->WaveHandle.Out, DeviceID, &data->Format, (DWORD_PTR)&WaveOutProc, (DWORD_PTR)Device, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR) - { - if(Device->FmtType == DevFmtFloat) - { - Device->FmtType = DevFmtShort; - goto retry_open; - } - ERR("waveOutOpen failed: %u\n", res); - goto failure; - } - - al_string_copy(&Device->DeviceName, VECTOR_ELEM(PlaybackDevices, DeviceID)); - return ALC_NO_ERROR; - -failure: - if(data->WaveHandle.Out) - waveOutClose(data->WaveHandle.Out); - - free(data); - Device->ExtraData = NULL; - return ALC_INVALID_VALUE; -} - -static void WinMMClosePlayback(ALCdevice *device) -{ - 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; - - device->UpdateSize = (ALuint)((ALuint64)device->UpdateSize * - data->Format.nSamplesPerSec / - device->Frequency); - device->UpdateSize = (device->UpdateSize*device->NumUpdates + 3) / 4; - device->NumUpdates = 4; - device->Frequency = data->Format.nSamplesPerSec; - - if(data->Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT) - { - if(data->Format.wBitsPerSample == 32) - device->FmtType = DevFmtFloat; - else - { - ERR("Unhandled IEEE float sample depth: %d\n", data->Format.wBitsPerSample); - return ALC_FALSE; - } - } - else if(data->Format.wFormatTag == WAVE_FORMAT_PCM) - { - if(data->Format.wBitsPerSample == 16) - device->FmtType = DevFmtShort; - else if(data->Format.wBitsPerSample == 8) - device->FmtType = DevFmtUByte; - else - { - ERR("Unhandled PCM sample depth: %d\n", data->Format.wBitsPerSample); - return ALC_FALSE; - } - } - else - { - ERR("Unhandled format tag: 0x%04x\n", data->Format.wFormatTag); - return ALC_FALSE; - } - - if(data->Format.nChannels == 2) - device->FmtChans = DevFmtStereo; - else if(data->Format.nChannels == 1) - device->FmtChans = DevFmtMono; - else - { - ERR("Unhandled channel count: %d\n", data->Format.nChannels); - return ALC_FALSE; - } - SetDefaultWFXChannelOrder(device); - - return ALC_TRUE; -} - -static ALCboolean WinMMStartPlayback(ALCdevice *device) -{ - WinMMData *data = (WinMMData*)device->ExtraData; - ALbyte *BufferData; - ALint BufferSize; - ALuint i; - - data->killNow = AL_FALSE; - if(althrd_create(&data->thread, PlaybackThreadProc, device) != althrd_success) - return ALC_FALSE; - - InitRef(&data->WaveBuffersCommitted, 0); - - // Create 4 Buffers - BufferSize = device->UpdateSize*device->NumUpdates / 4; - BufferSize *= FrameSizeFromDevFmt(device->FmtChans, device->FmtType); - - 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); - } - - return ALC_TRUE; -} - -static void WinMMStopPlayback(ALCdevice *device) -{ - WinMMData *data = (WinMMData*)device->ExtraData; - void *buffer = NULL; - int i; - - if(data->killNow) - return; - - // Set flag to stop processing headers - data->killNow = AL_TRUE; - althrd_join(data->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; - } - free(buffer); -} - - -static ALCenum WinMMOpenCapture(ALCdevice *Device, const ALCchar *deviceName) -{ - const al_string *iter, *end; - ALbyte *BufferData = NULL; - DWORD CapturedDataSize; - WinMMData *data = NULL; - ALint BufferSize; - UINT DeviceID; - MMRESULT res; - ALuint i; - - if(VECTOR_SIZE(CaptureDevices) == 0) - 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) - return ALC_INVALID_VALUE; - - switch(Device->FmtChans) - { - case DevFmtMono: - case DevFmtStereo: - break; - - case DevFmtQuad: - case DevFmtX51: - case DevFmtX51Side: - case DevFmtX61: - case DevFmtX71: - return ALC_INVALID_ENUM; - } - - switch(Device->FmtType) - { - case DevFmtUByte: - case DevFmtShort: - case DevFmtInt: - case DevFmtFloat: - break; - - case DevFmtByte: - case DevFmtUShort: - case DevFmtUInt: - return ALC_INVALID_ENUM; - } - - 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) ? - 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; - - if((res=waveInOpen(&data->WaveHandle.In, DeviceID, &data->Format, (DWORD_PTR)&WaveInProc, (DWORD_PTR)Device, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR) - { - ERR("waveInOpen failed: %u\n", res); - goto failure; - } - - // Allocate circular memory buffer for the captured audio - CapturedDataSize = Device->UpdateSize*Device->NumUpdates; - - // Make sure circular buffer is at least 100ms in size - if(CapturedDataSize < (data->Format.nSamplesPerSec / 10)) - CapturedDataSize = data->Format.nSamplesPerSec / 10; - - data->Ring = CreateRingBuffer(data->Format.nBlockAlign, CapturedDataSize); - if(!data->Ring) - goto failure; - - InitRef(&data->WaveBuffersCommitted, 0); - - // Create 4 Buffers of 50ms each - BufferSize = data->Format.nAvgBytesPerSec / 20; - BufferSize -= (BufferSize % data->Format.nBlockAlign); - - BufferData = calloc(4, BufferSize); - 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); - } - - if(althrd_create(&data->thread, CaptureThreadProc, Device) != althrd_success) - goto failure; - - 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)); - free(BufferData); - } - - if(data->Ring) - DestroyRingBuffer(data->Ring); - - if(data->WaveHandle.In) - waveInClose(data->WaveHandle.In); - - free(data); - Device->ExtraData = NULL; - return ALC_INVALID_VALUE; -} - -static void WinMMCloseCapture(ALCdevice *Device) -{ - 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); - - althrd_join(data->thread, &i); - - /* Make sure capture is stopped and all pending buffers are flushed. */ - waveInReset(data->WaveHandle.In); - - // 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; - } - free(buffer); - - DestroyRingBuffer(data->Ring); - data->Ring = NULL; - - // Close the Wave device - waveInClose(data->WaveHandle.In); - data->WaveHandle.In = 0; - - free(data); - Device->ExtraData = NULL; -} - -static void WinMMStartCapture(ALCdevice *Device) -{ - WinMMData *data = (WinMMData*)Device->ExtraData; - waveInStart(data->WaveHandle.In); -} - -static void WinMMStopCapture(ALCdevice *Device) -{ - WinMMData *data = (WinMMData*)Device->ExtraData; - waveInStop(data->WaveHandle.In); -} - -static ALCenum WinMMCaptureSamples(ALCdevice *Device, ALCvoid *Buffer, ALCuint Samples) -{ - WinMMData *data = (WinMMData*)Device->ExtraData; - ReadRingBuffer(data->Ring, Buffer, Samples); - return ALC_NO_ERROR; -} - -static ALCuint WinMMAvailableSamples(ALCdevice *Device) -{ - WinMMData *data = (WinMMData*)Device->ExtraData; - return RingBufferSize(data->Ring); -} - - -static inline void AppendAllDevicesList2(const al_string *name) -{ - if(!al_string_empty(*name)) - AppendAllDevicesList(al_string_get_cstr(*name)); -} -static inline void AppendCaptureDeviceList2(const al_string *name) -{ - if(!al_string_empty(*name)) - AppendCaptureDeviceList(al_string_get_cstr(*name)); -} - -static const BackendFuncs WinMMFuncs = { - WinMMOpenPlayback, - WinMMClosePlayback, - WinMMResetPlayback, - WinMMStartPlayback, - WinMMStopPlayback, - WinMMOpenCapture, - WinMMCloseCapture, - WinMMStartCapture, - WinMMStopCapture, - WinMMCaptureSamples, - WinMMAvailableSamples, - ALCdevice_GetLatencyDefault -}; - -ALCboolean alcWinMMInit(BackendFuncs *FuncList) -{ - VECTOR_INIT(PlaybackDevices); - VECTOR_INIT(CaptureDevices); - - *FuncList = WinMMFuncs; - return ALC_TRUE; -} - -void alcWinMMDeinit() -{ - clear_devlist(&PlaybackDevices); - VECTOR_DEINIT(PlaybackDevices); - - clear_devlist(&CaptureDevices); - VECTOR_DEINIT(CaptureDevices); -} - -void alcWinMMProbe(enum DevProbe type) -{ - switch(type) - { - case ALL_DEVICE_PROBE: - ProbePlaybackDevices(); - VECTOR_FOR_EACH(const al_string, PlaybackDevices, AppendAllDevicesList2); - break; - - case CAPTURE_DEVICE_PROBE: - ProbeCaptureDevices(); - VECTOR_FOR_EACH(const al_string, CaptureDevices, AppendCaptureDeviceList2); - break; - } -} diff --git a/love/src/jni/openal-soft-1.17.0/Alc/effects/autowah.c b/love/src/jni/openal-soft-1.17.0/Alc/effects/autowah.c deleted file mode 100644 index c8317c8b..00000000 --- a/love/src/jni/openal-soft-1.17.0/Alc/effects/autowah.c +++ /dev/null @@ -1,272 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2013 by Anis A. Hireche, Nasca Octavian Paul - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include - -#include "config.h" -#include "alu.h" -#include "alFilter.h" -#include "alError.h" -#include "alMain.h" -#include "alAuxEffectSlot.h" - - -/* 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. - */ - -typedef struct ALautowahState { - DERIVE_FROM_TYPE(ALeffectState); - - /* Effect gains for each channel */ - ALfloat Gain[MaxChannels]; - - /* Effect parameters */ - ALfloat AttackRate; - ALfloat ReleaseRate; - ALfloat Resonance; - ALfloat PeakGain; - ALfloat GainCtrl; - ALfloat Frequency; - - /* Samples processing */ - ALfilterState LowPass; -} ALautowahState; - -static ALvoid ALautowahState_Destruct(ALautowahState *UNUSED(state)) -{ -} - -static ALboolean ALautowahState_deviceUpdate(ALautowahState *state, ALCdevice *device) -{ - state->Frequency = (ALfloat)device->Frequency; - return AL_TRUE; -} - -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; - - state->AttackRate = powf(1.0f/GAIN_SILENCE_THRESHOLD, 1.0f/attackTime); - state->ReleaseRate = powf(GAIN_SILENCE_THRESHOLD/1.0f, 1.0f/releaseTime); - 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); -} - -static ALvoid ALautowahState_process(ALautowahState *state, ALuint SamplesToDo, const ALfloat *SamplesIn, ALfloat (*SamplesOut)[BUFFERSIZE]) -{ - ALuint it, kt; - ALuint base; - - for(base = 0;base < SamplesToDo;) - { - ALfloat temps[64]; - ALuint td = minu(SamplesToDo-base, 64); - ALfloat gain = state->GainCtrl; - - for(it = 0;it < td;it++) - { - ALfloat smp = SamplesIn[it+base]; - ALfloat alpha, w0; - ALfloat amplitude; - ALfloat cutoff; - - /* Similar to compressor, we get the current amplitude of the - * incoming signal, and attack or release to reach it. */ - amplitude = fabsf(smp); - if(amplitude > gain) - gain = minf(gain*state->AttackRate, amplitude); - else if(amplitude < gain) - gain = maxf(gain*state->ReleaseRate, amplitude); - gain = maxf(gain, GAIN_SILENCE_THRESHOLD); - - /* FIXME: What range does the filter cover? */ - cutoff = lerp(20.0f, 20000.0f, minf(gain/state->PeakGain, 1.0f)); - - /* The code below is like calling ALfilterState_setParams with - * 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; - - /* FIXME: Resonance controls the resonant peak, or Q. How? Not sure - * that Q = resonance*0.1. */ - alpha = sinf(w0) / (2.0f * state->Resonance*0.1f); - state->LowPass.b[0] = (1.0f - cosf(w0)) / 2.0f; - state->LowPass.b[1] = 1.0f - cosf(w0); - state->LowPass.b[2] = (1.0f - cosf(w0)) / 2.0f; - state->LowPass.a[0] = 1.0f + alpha; - state->LowPass.a[1] = -2.0f * cosf(w0); - state->LowPass.a[2] = 1.0f - alpha; - - state->LowPass.b[2] /= state->LowPass.a[0]; - state->LowPass.b[1] /= state->LowPass.a[0]; - state->LowPass.b[0] /= state->LowPass.a[0]; - state->LowPass.a[2] /= state->LowPass.a[0]; - state->LowPass.a[1] /= state->LowPass.a[0]; - state->LowPass.a[0] /= state->LowPass.a[0]; - - temps[it] = ALfilterState_processSingle(&state->LowPass, smp); - } - state->GainCtrl = gain; - - for(kt = 0;kt < MaxChannels;kt++) - { - ALfloat gain = state->Gain[kt]; - if(!(gain > GAIN_SILENCE_THRESHOLD)) - continue; - - for(it = 0;it < td;it++) - SamplesOut[kt][base+it] += gain * temps[it]; - } - - base += td; - } -} - -DECLARE_DEFAULT_ALLOCATORS(ALautowahState) - -DEFINE_ALEFFECTSTATE_VTABLE(ALautowahState); - - -typedef struct ALautowahStateFactory { - DERIVE_FROM_TYPE(ALeffectStateFactory); -} ALautowahStateFactory; - -static ALeffectState *ALautowahStateFactory_create(ALautowahStateFactory *UNUSED(factory)) -{ - ALautowahState *state; - - state = ALautowahState_New(sizeof(*state)); - if(!state) return NULL; - SET_VTABLE2(ALautowahState, ALeffectState, state); - - state->AttackRate = 1.0f; - state->ReleaseRate = 1.0f; - state->Resonance = 2.0f; - state->PeakGain = 1.0f; - state->GainCtrl = 1.0f; - - ALfilterState_clear(&state->LowPass); - - return STATIC_CAST(ALeffectState, state); -} - -DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALautowahStateFactory); - -ALeffectStateFactory *ALautowahStateFactory_getFactory(void) -{ - static ALautowahStateFactory AutowahFactory = { { GET_VTABLE2(ALautowahStateFactory, ALeffectStateFactory) } }; - - return STATIC_CAST(ALeffectStateFactory, &AutowahFactory); -} - - -void ALautowah_setParami(ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint UNUSED(val)) -{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } -void ALautowah_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) -{ - ALautowah_setParami(effect, context, param, vals[0]); -} -void ALautowah_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) -{ - ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_AUTOWAH_ATTACK_TIME: - if(!(val >= AL_AUTOWAH_MIN_ATTACK_TIME && val <= AL_AUTOWAH_MAX_ATTACK_TIME)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Autowah.AttackTime = val; - break; - - case AL_AUTOWAH_RELEASE_TIME: - if(!(val >= AL_AUTOWAH_MIN_RELEASE_TIME && val <= AL_AUTOWAH_MAX_RELEASE_TIME)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Autowah.ReleaseTime = val; - break; - - case AL_AUTOWAH_RESONANCE: - if(!(val >= AL_AUTOWAH_MIN_RESONANCE && val <= AL_AUTOWAH_MAX_RESONANCE)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Autowah.Resonance = val; - break; - - case AL_AUTOWAH_PEAK_GAIN: - if(!(val >= AL_AUTOWAH_MIN_PEAK_GAIN && val <= AL_AUTOWAH_MAX_PEAK_GAIN)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Autowah.PeakGain = val; - break; - - default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); - } -} -void ALautowah_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) -{ - ALautowah_setParamf(effect, context, param, vals[0]); -} - -void ALautowah_getParami(const ALeffect *UNUSED(effect), ALCcontext *context, ALenum UNUSED(param), ALint *UNUSED(val)) -{ SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); } -void ALautowah_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) -{ - ALautowah_getParami(effect, context, param, vals); -} -void ALautowah_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) -{ - const ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_AUTOWAH_ATTACK_TIME: - *val = props->Autowah.AttackTime; - break; - - case AL_AUTOWAH_RELEASE_TIME: - *val = props->Autowah.ReleaseTime; - break; - - case AL_AUTOWAH_RESONANCE: - *val = props->Autowah.Resonance; - break; - - case AL_AUTOWAH_PEAK_GAIN: - *val = props->Autowah.PeakGain; - break; - - default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); - } -} -void ALautowah_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) -{ - ALautowah_getParamf(effect, context, param, vals); -} - -DEFINE_ALEFFECT_VTABLE(ALautowah); diff --git a/love/src/jni/openal-soft-1.17.0/Alc/effects/reverb.c b/love/src/jni/openal-soft-1.17.0/Alc/effects/reverb.c deleted file mode 100644 index 245aed41..00000000 --- a/love/src/jni/openal-soft-1.17.0/Alc/effects/reverb.c +++ /dev/null @@ -1,1779 +0,0 @@ -/** - * Reverb for the OpenAL cross platform audio library - * Copyright (C) 2008-2009 by Christopher Fitzgerald. - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include - -#include "alMain.h" -#include "alu.h" -#include "alAuxEffectSlot.h" -#include "alEffect.h" -#include "alFilter.h" -#include "alError.h" - - -typedef struct DelayLine -{ - // The delay lines use sample lengths that are powers of 2 to allow the - // use of bit-masking instead of a modulus for wrapping. - ALuint Mask; - ALfloat *Line; -} DelayLine; - -typedef struct ALreverbState { - DERIVE_FROM_TYPE(ALeffectState); - - ALboolean IsEax; - - // All delay lines are allocated as a single buffer to reduce memory - // fragmentation and management code. - ALfloat *SampleBuffer; - ALuint TotalSamples; - - // Master effect filters - ALfilterState LpFilter; - ALfilterState HpFilter; // EAX only - - struct { - // Modulator delay line. - DelayLine Delay; - - // The vibrato time is tracked with an index over a modulus-wrapped - // range (in samples). - ALuint Index; - ALuint Range; - - // The depth of frequency change (also in samples) and its filter. - ALfloat Depth; - ALfloat Coeff; - ALfloat Filter; - } Mod; - - // Initial effect delay. - DelayLine Delay; - // The tap points for the initial delay. First tap goes to early - // reflections, the last to late reverb. - ALuint DelayTap[2]; - - struct { - // Output gain for early reflections. - ALfloat Gain; - - // Early reflections are done with 4 delay lines. - ALfloat Coeff[4]; - DelayLine Delay[4]; - ALuint Offset[4]; - - // The gain for each output channel based on 3D panning (only for the - // EAX path). - ALfloat PanGain[MaxChannels]; - } Early; - - // Decorrelator delay line. - DelayLine Decorrelator; - // There are actually 4 decorrelator taps, but the first occurs at the - // initial sample. - ALuint DecoTap[3]; - - struct { - // Output gain for late reverb. - ALfloat Gain; - - // Attenuation to compensate for the modal density and decay rate of - // the late lines. - ALfloat DensityGain; - - // The feed-back and feed-forward all-pass coefficient. - ALfloat ApFeedCoeff; - - // Mixing matrix coefficient. - ALfloat MixCoeff; - - // Late reverb has 4 parallel all-pass filters. - ALfloat ApCoeff[4]; - DelayLine ApDelay[4]; - ALuint ApOffset[4]; - - // In addition to 4 cyclical delay lines. - ALfloat Coeff[4]; - DelayLine Delay[4]; - ALuint Offset[4]; - - // The cyclical delay lines are 1-pole low-pass filtered. - ALfloat LpCoeff[4]; - ALfloat LpSample[4]; - - // The gain for each output channel based on 3D panning (only for the - // EAX path). - ALfloat PanGain[MaxChannels]; - } Late; - - struct { - // Attenuation to compensate for the modal density and decay rate of - // the echo line. - ALfloat DensityGain; - - // Echo delay and all-pass lines. - DelayLine Delay; - DelayLine ApDelay; - - ALfloat Coeff; - ALfloat ApFeedCoeff; - ALfloat ApCoeff; - - ALuint Offset; - ALuint ApOffset; - - // The echo line is 1-pole low-pass filtered. - ALfloat LpCoeff; - ALfloat LpSample; - - // Echo mixing coefficients. - ALfloat MixCoeff[2]; - } Echo; - - // The current read offset for all delay lines. - ALuint Offset; - - // The gain for each output channel (non-EAX path only; aliased from - // Late.PanGain) - ALfloat *Gain; - - /* Temporary storage used when processing, before deinterlacing. */ - ALfloat ReverbSamples[BUFFERSIZE][4]; - ALfloat EarlySamples[BUFFERSIZE][4]; -} ALreverbState; - -/* This is a user config option for modifying the overall output of the reverb - * effect. - */ -ALfloat ReverbBoost = 1.0f; - -/* Specifies whether to use a standard reverb effect in place of EAX reverb */ -ALboolean EmulateEAXReverb = AL_FALSE; - -/* This coefficient is used to define the maximum frequency range controlled - * by the modulation depth. The current value of 0.1 will allow it to swing - * from 0.9x to 1.1x. This value must be below 1. At 1 it will cause the - * sampler to stall on the downswing, and above 1 it will cause it to sample - * backwards. - */ -static const ALfloat MODULATION_DEPTH_COEFF = 0.1f; - -/* A filter is used to avoid the terrible distortion caused by changing - * modulation time and/or depth. To be consistent across different sample - * rates, the coefficient must be raised to a constant divided by the sample - * rate: coeff^(constant / rate). - */ -static const ALfloat MODULATION_FILTER_COEFF = 0.048f; -static const ALfloat MODULATION_FILTER_CONST = 100000.0f; - -// When diffusion is above 0, an all-pass filter is used to take the edge off -// the echo effect. It uses the following line length (in seconds). -static const ALfloat ECHO_ALLPASS_LENGTH = 0.0133f; - -// Input into the late reverb is decorrelated between four channels. Their -// timings are dependent on a fraction and multiplier. See the -// UpdateDecorrelator() routine for the calculations involved. -static const ALfloat DECO_FRACTION = 0.15f; -static const ALfloat DECO_MULTIPLIER = 2.0f; - -// All delay line lengths are specified in seconds. - -// The lengths of the early delay lines. -static const ALfloat EARLY_LINE_LENGTH[4] = -{ - 0.0015f, 0.0045f, 0.0135f, 0.0405f -}; - -// The lengths of the late all-pass delay lines. -static const ALfloat ALLPASS_LINE_LENGTH[4] = -{ - 0.0151f, 0.0167f, 0.0183f, 0.0200f, -}; - -// The lengths of the late cyclical delay lines. -static const ALfloat LATE_LINE_LENGTH[4] = -{ - 0.0211f, 0.0311f, 0.0461f, 0.0680f -}; - -// The late cyclical delay lines have a variable length dependent on the -// effect's density parameter (inverted for some reason) and this multiplier. -static const ALfloat LATE_LINE_MULTIPLIER = 4.0f; - - -// Basic delay line input/output routines. -static inline ALfloat DelayLineOut(DelayLine *Delay, ALuint offset) -{ - return Delay->Line[offset&Delay->Mask]; -} - -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) -{ - return coeff * Delay->Line[offset&Delay->Mask]; -} - -// Basic attenuated all-pass input/output routine. -static inline ALfloat AllpassInOut(DelayLine *Delay, ALuint outOffset, ALuint inOffset, ALfloat in, ALfloat feedCoeff, ALfloat coeff) -{ - ALfloat out, feed; - - out = DelayLineOut(Delay, outOffset); - feed = feedCoeff * in; - DelayLineIn(Delay, inOffset, (feedCoeff * (out - feed)) + in); - - // The time-based attenuation is only applied to the delay output to - // keep it from affecting the feed-back path (which is already controlled - // by the all-pass feed coefficient). - 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) -{ - return AllpassInOut(&State->Late.ApDelay[index], - State->Offset - State->Late.ApOffset[index], - State->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) -{ - in = lerp(in, State->Late.LpSample[index], State->Late.LpCoeff[index]); - State->Late.LpSample[index] = in; - return in; -} - -// 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) -{ - ALfloat d[4], f[4]; - - // Obtain the decayed results of the cyclical delay lines, and add the - // corresponding input channels. Then pass the results through the - // low-pass filters. - - // 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)); - - // 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]); - - /* 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). - 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]; - - // 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]); -} - -// 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) -{ - ALfloat out, feed; - - // Get the latest attenuated echo sample for output. - feed = AttenuatedDelayLineOut(&State->Echo.Delay, - State->Offset - State->Echo.Offset, - State->Echo.Coeff); - - // 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; - - // 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; - - // 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); - - // Feed the delay with the mixed and filtered sample. - DelayLineIn(&State->Echo.Delay, State->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) -{ - ALfloat feed, late[4], taps[4]; - - // Filter the incoming sample. - in = ALfilterState_processSingle(&State->LpFilter, in); - - // Feed the initial delay line. - DelayLineIn(&State->Delay, State->Offset, in); - - // Calculate the early reflection from the first delay tap. - in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[0]); - EarlyReflection(State, in, 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); - - // 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]; - - // Step all delays forward one sample. - State->Offset++; -} - -// 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) -{ - ALfloat feed, taps[4]; - - // Low-pass filter the incoming sample. - in = ALfilterState_processSingle(&State->LpFilter, in); - in = ALfilterState_processSingle(&State->HpFilter, in); - - // Perform any modulation on the input. - in = EAXModulation(State, in); - - // Feed the initial delay line. - DelayLineIn(&State->Delay, State->Offset, in); - - // Calculate the early reflection from the first delay tap. - in = DelayLineOut(&State->Delay, State->Offset - State->DelayTap[0]); - EarlyReflection(State, in, 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); - - // 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); - - // Calculate and mix in any echo. - EAXEcho(State, in, late); - - // Step all delays forward one sample. - State->Offset++; -} - -static ALvoid ALreverbState_processStandard(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE]) -{ - ALfloat (*restrict out)[4] = State->ReverbSamples; - ALuint index, c; - - /* Process reverb for these samples. */ - for(index = 0;index < SamplesToDo;index++) - VerbPass(State, SamplesIn[index], out[index]); - - for(c = 0;c < MaxChannels;c++) - { - ALfloat gain = State->Gain[c]; - if(!(gain > GAIN_SILENCE_THRESHOLD)) - continue; - - for(index = 0;index < SamplesToDo;index++) - SamplesOut[c][index] += gain * out[index][c&3]; - } -} - -static ALvoid ALreverbState_processEax(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE]) -{ - ALfloat (*restrict early)[4] = State->EarlySamples; - ALfloat (*restrict late)[4] = State->ReverbSamples; - ALuint index, c; - - /* 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++) - { - ALfloat earlyGain, lateGain; - - earlyGain = State->Early.PanGain[c]; - if(earlyGain > GAIN_SILENCE_THRESHOLD) - { - 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]; - } - } -} - -static ALvoid ALreverbState_process(ALreverbState *State, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE]) -{ - if(State->IsEax) - ALreverbState_processEax(State, SamplesToDo, SamplesIn, SamplesOut); - else - ALreverbState_processStandard(State, SamplesToDo, SamplesIn, SamplesOut); -} - -// 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]; -} - -// Calculate the length of a delay line and store its mask and offset. -static ALuint CalcLineLength(ALfloat length, ALintptrEXT offset, ALuint frequency, 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); - // All lines share a single sample buffer. - Delay->Mask = samples - 1; - Delay->Line = (ALfloat*)offset; - // Return the sample count for accumulation. - return samples; -} - -/* Calculates the delay line metrics and allocates the shared sample buffer - * for all lines given the sample rate (frequency). If an allocation failure - * occurs, it returns AL_FALSE. - */ -static ALboolean AllocLines(ALuint frequency, ALreverbState *State) -{ - ALuint totalSamples, index; - ALfloat length; - ALfloat *newBuffer = NULL; - - // All delay line lengths are calculated to accomodate the full range of - // lengths given their respective paramters. - totalSamples = 0; - - /* The modulator's line length is calculated from the maximum modulation - * time and depth coefficient, and halfed for the low-to-high frequency - * 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, - &State->Mod.Delay); - - // The initial delay is the sum of the reflections and late reverb - // delays. - length = AL_EAXREVERB_MAX_REFLECTIONS_DELAY + - AL_EAXREVERB_MAX_LATE_REVERB_DELAY; - totalSamples += CalcLineLength(length, totalSamples, frequency, - &State->Delay); - - // The early reflection lines. - for(index = 0;index < 4;index++) - totalSamples += CalcLineLength(EARLY_LINE_LENGTH[index], totalSamples, - frequency, &State->Early.Delay[index]); - - // The decorrelator line is calculated from the lowest reverb density (a - // parameter value of 1). - length = (DECO_FRACTION * DECO_MULTIPLIER * DECO_MULTIPLIER) * - LATE_LINE_LENGTH[0] * (1.0f + LATE_LINE_MULTIPLIER); - totalSamples += CalcLineLength(length, totalSamples, frequency, - &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]); - - // 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, - &State->Late.Delay[index]); - } - - // The echo all-pass and delay lines. - totalSamples += CalcLineLength(ECHO_ALLPASS_LENGTH, totalSamples, - frequency, &State->Echo.ApDelay); - totalSamples += CalcLineLength(AL_EAXREVERB_MAX_ECHO_TIME, totalSamples, - frequency, &State->Echo.Delay); - - if(totalSamples != State->TotalSamples) - { - TRACE("New reverb buffer length: %u samples (%f sec)\n", totalSamples, totalSamples/(float)frequency); - newBuffer = realloc(State->SampleBuffer, sizeof(ALfloat) * totalSamples); - if(newBuffer == NULL) - return AL_FALSE; - State->SampleBuffer = newBuffer; - State->TotalSamples = totalSamples; - } - - // Update all delays to reflect the new sample buffer. - RealizeLineOffset(State->SampleBuffer, &State->Delay); - RealizeLineOffset(State->SampleBuffer, &State->Decorrelator); - for(index = 0;index < 4;index++) - { - RealizeLineOffset(State->SampleBuffer, &State->Early.Delay[index]); - RealizeLineOffset(State->SampleBuffer, &State->Late.ApDelay[index]); - RealizeLineOffset(State->SampleBuffer, &State->Late.Delay[index]); - } - RealizeLineOffset(State->SampleBuffer, &State->Mod.Delay); - RealizeLineOffset(State->SampleBuffer, &State->Echo.ApDelay); - RealizeLineOffset(State->SampleBuffer, &State->Echo.Delay); - - // Clear the sample buffer. - for(index = 0;index < State->TotalSamples;index++) - State->SampleBuffer[index] = 0.0f; - - return AL_TRUE; -} - -static ALboolean ALreverbState_deviceUpdate(ALreverbState *State, ALCdevice *Device) -{ - ALuint frequency = Device->Frequency, index; - - // Allocate the delay lines. - if(!AllocLines(frequency, State)) - return AL_FALSE; - - // Calculate the modulation filter coefficient. Notice that the exponent - // is calculated given the current sample rate. This ensures that the - // resulting filter response over time is consistent across all sample - // rates. - State->Mod.Coeff = powf(MODULATION_FILTER_COEFF, - MODULATION_FILTER_CONST / frequency); - - // The early reflection and late all-pass filter line lengths are static, - // so their offsets only need to be calculated once. - for(index = 0;index < 4;index++) - { - State->Early.Offset[index] = fastf2u(EARLY_LINE_LENGTH[index] * - frequency); - State->Late.ApOffset[index] = fastf2u(ALLPASS_LINE_LENGTH[index] * - frequency); - } - - // The echo all-pass filter line length is static, so its offset only - // needs to be calculated once. - State->Echo.ApOffset = fastf2u(ECHO_ALLPASS_LENGTH * frequency); - - return AL_TRUE; -} - -// Calculate a decay coefficient given the length of each cycle and the time -// until the decay reaches -60 dB. -static inline ALfloat CalcDecayCoeff(ALfloat length, ALfloat decayTime) -{ - return powf(0.001f/*-60 dB*/, length/decayTime); -} - -// Calculate a decay length from a coefficient and the time until the decay -// reaches -60 dB. -static inline ALfloat CalcDecayLength(ALfloat coeff, ALfloat decayTime) -{ - return log10f(coeff) * decayTime / log10f(0.001f)/*-60 dB*/; -} - -// Calculate an attenuation to be applied to the input of any echo models to -// compensate for modal density and decay time. -static inline ALfloat CalcDensityGain(ALfloat a) -{ - /* The energy of a signal can be obtained by finding the area under the - * squared signal. This takes the form of Sum(x_n^2), where x is the - * amplitude for the sample n. - * - * Decaying feedback matches exponential decay of the form Sum(a^n), - * where a is the attenuation coefficient, and n is the sample. The area - * under this decay curve can be calculated as: 1 / (1 - a). - * - * Modifying the above equation to find the squared area under the curve - * (for energy) yields: 1 / (1 - a^2). Input attenuation can then be - * calculated by inverting the square root of this approximation, - * yielding: 1 / sqrt(1 / (1 - a^2)), simplified to: sqrt(1 - a^2). - */ - return sqrtf(1.0f - (a * a)); -} - -// Calculate the mixing matrix coefficients given a diffusion factor. -static inline ALvoid CalcMatrixCoeffs(ALfloat diffusion, ALfloat *x, ALfloat *y) -{ - ALfloat n, t; - - // The matrix is of order 4, so n is sqrt (4 - 1). - n = sqrtf(3.0f); - t = diffusion * atanf(n); - - // Calculate the first mixing matrix coefficient. - *x = cosf(t); - // Calculate the second mixing matrix coefficient. - *y = sinf(t) / n; -} - -// Calculate the limited HF ratio for use with the late reverb low-pass -// filters. -static ALfloat CalcLimitedHfRatio(ALfloat hfRatio, ALfloat airAbsorptionGainHF, ALfloat decayTime) -{ - ALfloat limitRatio; - - /* Find the attenuation due to air absorption in dB (converting delay - * time to meters using the speed of sound). Then reversing the decay - * equation, solve for HF ratio. The delay length is cancelled out of - * the equation, so it can be calculated once for all lines. - */ - limitRatio = 1.0f / (CalcDecayLength(airAbsorptionGainHF, decayTime) * - SPEEDOFSOUNDMETRESPERSEC); - /* Using the limit calculated above, apply the upper bound to the HF - * ratio. Also need to limit the result to a minimum of 0.1, just like the - * HF ratio parameter. */ - return clampf(limitRatio, 0.1f, hfRatio); -} - -// Calculate the coefficient for a HF (and eventually LF) decay damping -// filter. -static inline ALfloat CalcDampingCoeff(ALfloat hfRatio, ALfloat length, ALfloat decayTime, ALfloat decayCoeff, ALfloat cw) -{ - ALfloat coeff, g; - - // Eventually this should boost the high frequencies when the ratio - // exceeds 1. - coeff = 0.0f; - if (hfRatio < 1.0f) - { - // Calculate the low-pass coefficient by dividing the HF decay - // coefficient by the full decay coefficient. - g = CalcDecayCoeff(length, decayTime * hfRatio) / decayCoeff; - - // Damping is done with a 1-pole filter, so g needs to be squared. - g *= g; - if(g < 0.9999f) /* 1-epsilon */ - { - /* Be careful with gains < 0.001, as that causes the coefficient - * head towards 1, which will flatten the signal. */ - g = maxf(g, 0.001f); - coeff = (1 - g*cw - sqrtf(2*g*(1-cw) - g*g*(1 - cw*cw))) / - (1 - g); - } - - // Very low decay times will produce minimal output, so apply an - // upper bound to the coefficient. - coeff = minf(coeff, 0.98f); - } - return coeff; -} - -// Update the EAX modulation index, range, and depth. Keep in mind that this -// kind of vibrato is additive and not multiplicative as one may expect. The -// downswing will sound stronger than the upswing. -static ALvoid UpdateModulator(ALfloat modTime, ALfloat modDepth, ALuint frequency, ALreverbState *State) -{ - ALuint range; - - /* Modulation is calculated in two parts. - * - * The modulation time effects the sinus applied to the change in - * frequency. An index out of the current time range (both in samples) - * is incremented each sample. The range is bound to a reasonable - * minimum (1 sample) and when the timing changes, the index is rescaled - * to the new range (to keep the sinus consistent). - */ - range = maxu(fastf2u(modTime*frequency), 1); - State->Mod.Index = (ALuint)(State->Mod.Index * (ALuint64)range / - State->Mod.Range); - State->Mod.Range = range; - - /* The modulation depth effects the amount of frequency change over the - * range of the sinus. It needs to be scaled by the modulation time so - * that a given depth produces a consistent change in frequency over all - * ranges of time. Since the depth is applied to a sinus value, it needs - * to be halfed once for the sinus range and again for the sinus swing - * in time (half of it is spent decreasing the frequency, half is spent - * increasing it). - */ - State->Mod.Depth = modDepth * MODULATION_DEPTH_COEFF * modTime / 2.0f / - 2.0f * frequency; -} - -// Update the offsets for the initial effect delay line. -static ALvoid UpdateDelayLine(ALfloat earlyDelay, ALfloat lateDelay, ALuint frequency, ALreverbState *State) -{ - // Calculate the initial delay taps. - State->DelayTap[0] = fastf2u(earlyDelay * frequency); - State->DelayTap[1] = fastf2u((earlyDelay + lateDelay) * frequency); -} - -// Update the early reflections gain and line coefficients. -static ALvoid UpdateEarlyLines(ALfloat reverbGain, ALfloat earlyGain, ALfloat lateDelay, ALreverbState *State) -{ - ALuint index; - - // Calculate the early reflections gain (from the master effect gain, and - // reflections gain parameters) with a constant attenuation of 0.5. - State->Early.Gain = 0.5f * reverbGain * earlyGain; - - // Calculate the gain (coefficient) for each early delay line using the - // late delay time. This expands the early reflections to the start of - // the late reverb. - for(index = 0;index < 4;index++) - State->Early.Coeff[index] = CalcDecayCoeff(EARLY_LINE_LENGTH[index], - lateDelay); -} - -// Update the offsets for the decorrelator line. -static ALvoid UpdateDecorrelator(ALfloat density, ALuint frequency, ALreverbState *State) -{ - ALuint index; - ALfloat length; - - /* The late reverb inputs are decorrelated to smooth the reverb tail and - * reduce harsh echos. The first tap occurs immediately, while the - * remaining taps are delayed by multiples of a fraction of the smallest - * cyclical delay time. - * - * offset[index] = (FRACTION (MULTIPLIER^index)) smallest_delay - */ - for(index = 0;index < 3;index++) - { - length = (DECO_FRACTION * powf(DECO_MULTIPLIER, (ALfloat)index)) * - LATE_LINE_LENGTH[0] * (1.0f + (density * LATE_LINE_MULTIPLIER)); - State->DecoTap[index] = fastf2u(length * frequency); - } -} - -// 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) -{ - ALfloat length; - ALuint index; - - /* 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. - */ - State->Late.Gain = reverbGain * lateGain * xMix; - - /* To compensate for changes in modal density and decay time of the late - * reverb signal, the input is attenuated based on the maximal energy of - * the outgoing signal. This approximation is used to keep the apparent - * energy of the signal equal for all ranges of density and decay time. - * - * The average length of the cyclcical delay lines is used to calculate - * the attenuation coefficient. - */ - 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)); - - // Calculate the all-pass feed-back and feed-forward coefficient. - State->Late.ApFeedCoeff = 0.5f * powf(diffusion, 2.0f); - - 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); - - // Calculate the length (in seconds) of each cyclical delay line. - 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); - - // Calculate the gain (coefficient) for each cyclical line. - 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); - - // Attenuate the cyclical line coefficients by the mixing coefficient - // (x). - State->Late.Coeff[index] *= xMix; - } -} - -// Update the echo gain, line offset, line coefficients, and mixing -// coefficients. -static ALvoid UpdateEchoLine(ALfloat reverbGain, ALfloat lateGain, ALfloat echoTime, ALfloat decayTime, ALfloat diffusion, ALfloat echoDepth, ALfloat hfRatio, ALfloat cw, ALuint frequency, ALreverbState *State) -{ - // Update the offset and coefficient for the echo delay line. - State->Echo.Offset = fastf2u(echoTime * frequency); - - // Calculate the decay coefficient for the echo line. - State->Echo.Coeff = CalcDecayCoeff(echoTime, decayTime); - - // Calculate the energy-based attenuation coefficient for the echo delay - // line. - State->Echo.DensityGain = CalcDensityGain(State->Echo.Coeff); - - // Calculate the echo all-pass feed coefficient. - State->Echo.ApFeedCoeff = 0.5f * powf(diffusion, 2.0f); - - // Calculate the echo all-pass attenuation coefficient. - State->Echo.ApCoeff = CalcDecayCoeff(ECHO_ALLPASS_LENGTH, decayTime); - - // Calculate the damping coefficient for each low-pass filter. - State->Echo.LpCoeff = CalcDampingCoeff(hfRatio, echoTime, decayTime, - State->Echo.Coeff, cw); - - /* Calculate the echo mixing coefficients. The first is applied to the - * echo itself. The second is used to 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->Echo.MixCoeff[0] = reverbGain * lateGain * echoDepth; - State->Echo.MixCoeff[1] = 1.0f - (echoDepth * 0.5f * (1.0f - diffusion)); -} - -// 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; - - 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 = 1.0f / sqrtf(length); - earlyPan[0] *= length; - earlyPan[1] *= length; - earlyPan[2] *= length; - } - length = latePan[0]*latePan[0] + latePan[1]*latePan[1] + latePan[2]*latePan[2]; - if(length > 1.0f) - { - length = 1.0f / sqrtf(length); - latePan[0] *= length; - latePan[1] *= length; - latePan[2] *= length; - } - - 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); - - 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); -} - -static ALvoid ALreverbState_update(ALreverbState *State, ALCdevice *Device, const ALeffectslot *Slot) -{ - ALuint frequency = Device->Frequency; - ALfloat lfscale, hfscale, hfRatio; - ALfloat cw, x, y; - - if(Slot->EffectType == AL_EFFECT_EAXREVERB && !EmulateEAXReverb) - State->IsEax = AL_TRUE; - 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); - } - - if(State->IsEax) - { - // Update the modulator line. - UpdateModulator(Slot->EffectProps.Reverb.ModulationTime, - Slot->EffectProps.Reverb.ModulationDepth, - frequency, State); - } - - // Update the initial effect delay. - UpdateDelayLine(Slot->EffectProps.Reverb.ReflectionsDelay, - Slot->EffectProps.Reverb.LateReverbDelay, - frequency, State); - - // Update the early lines. - UpdateEarlyLines(Slot->EffectProps.Reverb.Gain, - Slot->EffectProps.Reverb.ReflectionsGain, - Slot->EffectProps.Reverb.LateReverbDelay, State); - - // Update the decorrelator. - UpdateDecorrelator(Slot->EffectProps.Reverb.Density, frequency, State); - - // Get the mixing matrix coefficients (x and y). - CalcMatrixCoeffs(Slot->EffectProps.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); - - cw = cosf(F_2PI * 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); - - 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 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); - } -} - - -static ALvoid ALreverbState_Destruct(ALreverbState *State) -{ - free(State->SampleBuffer); - State->SampleBuffer = NULL; -} - -DECLARE_DEFAULT_ALLOCATORS(ALreverbState) - -DEFINE_ALEFFECTSTATE_VTABLE(ALreverbState); - - -typedef struct ALreverbStateFactory { - DERIVE_FROM_TYPE(ALeffectStateFactory); -} ALreverbStateFactory; - -static ALeffectState *ALreverbStateFactory_create(ALreverbStateFactory* UNUSED(factory)) -{ - ALreverbState *state; - ALuint index; - - state = ALreverbState_New(sizeof(*state)); - if(!state) return NULL; - SET_VTABLE2(ALreverbState, ALeffectState, state); - - state->TotalSamples = 0; - state->SampleBuffer = NULL; - - ALfilterState_clear(&state->LpFilter); - ALfilterState_clear(&state->HpFilter); - - state->Mod.Delay.Mask = 0; - state->Mod.Delay.Line = NULL; - state->Mod.Index = 0; - state->Mod.Range = 1; - state->Mod.Depth = 0.0f; - state->Mod.Coeff = 0.0f; - state->Mod.Filter = 0.0f; - - state->Delay.Mask = 0; - state->Delay.Line = NULL; - state->DelayTap[0] = 0; - state->DelayTap[1] = 0; - - state->Early.Gain = 0.0f; - for(index = 0;index < 4;index++) - { - state->Early.Coeff[index] = 0.0f; - state->Early.Delay[index].Mask = 0; - state->Early.Delay[index].Line = NULL; - state->Early.Offset[index] = 0; - } - - state->Decorrelator.Mask = 0; - state->Decorrelator.Line = NULL; - state->DecoTap[0] = 0; - state->DecoTap[1] = 0; - state->DecoTap[2] = 0; - - state->Late.Gain = 0.0f; - state->Late.DensityGain = 0.0f; - state->Late.ApFeedCoeff = 0.0f; - state->Late.MixCoeff = 0.0f; - for(index = 0;index < 4;index++) - { - state->Late.ApCoeff[index] = 0.0f; - state->Late.ApDelay[index].Mask = 0; - state->Late.ApDelay[index].Line = NULL; - state->Late.ApOffset[index] = 0; - - state->Late.Coeff[index] = 0.0f; - state->Late.Delay[index].Mask = 0; - state->Late.Delay[index].Line = NULL; - state->Late.Offset[index] = 0; - - state->Late.LpCoeff[index] = 0.0f; - state->Late.LpSample[index] = 0.0f; - } - - for(index = 0;index < MaxChannels;index++) - { - state->Early.PanGain[index] = 0.0f; - state->Late.PanGain[index] = 0.0f; - } - - state->Echo.DensityGain = 0.0f; - state->Echo.Delay.Mask = 0; - state->Echo.Delay.Line = NULL; - state->Echo.ApDelay.Mask = 0; - state->Echo.ApDelay.Line = NULL; - state->Echo.Coeff = 0.0f; - state->Echo.ApFeedCoeff = 0.0f; - state->Echo.ApCoeff = 0.0f; - state->Echo.Offset = 0; - 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->Offset = 0; - - state->Gain = state->Late.PanGain; - - return STATIC_CAST(ALeffectState, state); -} - -DEFINE_ALEFFECTSTATEFACTORY_VTABLE(ALreverbStateFactory); - -ALeffectStateFactory *ALreverbStateFactory_getFactory(void) -{ - static ALreverbStateFactory ReverbFactory = { { GET_VTABLE2(ALreverbStateFactory, ALeffectStateFactory) } }; - - return STATIC_CAST(ALeffectStateFactory, &ReverbFactory); -} - - -void ALeaxreverb_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) -{ - ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_EAXREVERB_DECAY_HFLIMIT: - if(!(val >= AL_EAXREVERB_MIN_DECAY_HFLIMIT && val <= AL_EAXREVERB_MAX_DECAY_HFLIMIT)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Reverb.DecayHFLimit = val; - break; - - default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); - } -} -void ALeaxreverb_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) -{ - ALeaxreverb_setParami(effect, context, param, vals[0]); -} -void ALeaxreverb_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) -{ - ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_EAXREVERB_DENSITY: - if(!(val >= AL_EAXREVERB_MIN_DENSITY && val <= AL_EAXREVERB_MAX_DENSITY)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Reverb.Density = val; - break; - - case AL_EAXREVERB_DIFFUSION: - if(!(val >= AL_EAXREVERB_MIN_DIFFUSION && val <= AL_EAXREVERB_MAX_DIFFUSION)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Reverb.Diffusion = val; - break; - - case AL_EAXREVERB_GAIN: - if(!(val >= AL_EAXREVERB_MIN_GAIN && val <= AL_EAXREVERB_MAX_GAIN)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Reverb.Gain = val; - break; - - case AL_EAXREVERB_GAINHF: - if(!(val >= AL_EAXREVERB_MIN_GAINHF && val <= AL_EAXREVERB_MAX_GAINHF)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Reverb.GainHF = val; - break; - - case AL_EAXREVERB_GAINLF: - if(!(val >= AL_EAXREVERB_MIN_GAINLF && val <= AL_EAXREVERB_MAX_GAINLF)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Reverb.GainLF = val; - break; - - case AL_EAXREVERB_DECAY_TIME: - if(!(val >= AL_EAXREVERB_MIN_DECAY_TIME && val <= AL_EAXREVERB_MAX_DECAY_TIME)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Reverb.DecayTime = val; - break; - - case AL_EAXREVERB_DECAY_HFRATIO: - if(!(val >= AL_EAXREVERB_MIN_DECAY_HFRATIO && val <= AL_EAXREVERB_MAX_DECAY_HFRATIO)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Reverb.DecayHFRatio = val; - break; - - case AL_EAXREVERB_DECAY_LFRATIO: - if(!(val >= AL_EAXREVERB_MIN_DECAY_LFRATIO && val <= AL_EAXREVERB_MAX_DECAY_LFRATIO)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Reverb.DecayLFRatio = val; - break; - - case AL_EAXREVERB_REFLECTIONS_GAIN: - if(!(val >= AL_EAXREVERB_MIN_REFLECTIONS_GAIN && val <= AL_EAXREVERB_MAX_REFLECTIONS_GAIN)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Reverb.ReflectionsGain = val; - break; - - case AL_EAXREVERB_REFLECTIONS_DELAY: - if(!(val >= AL_EAXREVERB_MIN_REFLECTIONS_DELAY && val <= AL_EAXREVERB_MAX_REFLECTIONS_DELAY)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Reverb.ReflectionsDelay = val; - break; - - case AL_EAXREVERB_LATE_REVERB_GAIN: - if(!(val >= AL_EAXREVERB_MIN_LATE_REVERB_GAIN && val <= AL_EAXREVERB_MAX_LATE_REVERB_GAIN)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Reverb.LateReverbGain = val; - break; - - case AL_EAXREVERB_LATE_REVERB_DELAY: - if(!(val >= AL_EAXREVERB_MIN_LATE_REVERB_DELAY && val <= AL_EAXREVERB_MAX_LATE_REVERB_DELAY)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Reverb.LateReverbDelay = val; - break; - - case AL_EAXREVERB_AIR_ABSORPTION_GAINHF: - if(!(val >= AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF && val <= AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Reverb.AirAbsorptionGainHF = val; - break; - - case AL_EAXREVERB_ECHO_TIME: - if(!(val >= AL_EAXREVERB_MIN_ECHO_TIME && val <= AL_EAXREVERB_MAX_ECHO_TIME)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Reverb.EchoTime = val; - break; - - case AL_EAXREVERB_ECHO_DEPTH: - if(!(val >= AL_EAXREVERB_MIN_ECHO_DEPTH && val <= AL_EAXREVERB_MAX_ECHO_DEPTH)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Reverb.EchoDepth = val; - break; - - case AL_EAXREVERB_MODULATION_TIME: - if(!(val >= AL_EAXREVERB_MIN_MODULATION_TIME && val <= AL_EAXREVERB_MAX_MODULATION_TIME)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Reverb.ModulationTime = val; - break; - - case AL_EAXREVERB_MODULATION_DEPTH: - if(!(val >= AL_EAXREVERB_MIN_MODULATION_DEPTH && val <= AL_EAXREVERB_MAX_MODULATION_DEPTH)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Reverb.ModulationDepth = val; - break; - - case AL_EAXREVERB_HFREFERENCE: - if(!(val >= AL_EAXREVERB_MIN_HFREFERENCE && val <= AL_EAXREVERB_MAX_HFREFERENCE)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Reverb.HFReference = val; - break; - - case AL_EAXREVERB_LFREFERENCE: - if(!(val >= AL_EAXREVERB_MIN_LFREFERENCE && val <= AL_EAXREVERB_MAX_LFREFERENCE)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Reverb.LFReference = val; - break; - - case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR: - if(!(val >= AL_EAXREVERB_MIN_ROOM_ROLLOFF_FACTOR && val <= AL_EAXREVERB_MAX_ROOM_ROLLOFF_FACTOR)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Reverb.RoomRolloffFactor = val; - break; - - default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); - } -} -void ALeaxreverb_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) -{ - ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_EAXREVERB_REFLECTIONS_PAN: - if(!(isfinite(vals[0]) && isfinite(vals[1]) && isfinite(vals[2]))) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - LockContext(context); - props->Reverb.ReflectionsPan[0] = vals[0]; - props->Reverb.ReflectionsPan[1] = vals[1]; - props->Reverb.ReflectionsPan[2] = vals[2]; - UnlockContext(context); - break; - case AL_EAXREVERB_LATE_REVERB_PAN: - if(!(isfinite(vals[0]) && isfinite(vals[1]) && isfinite(vals[2]))) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - LockContext(context); - props->Reverb.LateReverbPan[0] = vals[0]; - props->Reverb.LateReverbPan[1] = vals[1]; - props->Reverb.LateReverbPan[2] = vals[2]; - UnlockContext(context); - break; - - default: - ALeaxreverb_setParamf(effect, context, param, vals[0]); - break; - } -} - -void ALeaxreverb_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) -{ - const ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_EAXREVERB_DECAY_HFLIMIT: - *val = props->Reverb.DecayHFLimit; - break; - - default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); - } -} -void ALeaxreverb_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) -{ - ALeaxreverb_getParami(effect, context, param, vals); -} -void ALeaxreverb_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) -{ - const ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_EAXREVERB_DENSITY: - *val = props->Reverb.Density; - break; - - case AL_EAXREVERB_DIFFUSION: - *val = props->Reverb.Diffusion; - break; - - case AL_EAXREVERB_GAIN: - *val = props->Reverb.Gain; - break; - - case AL_EAXREVERB_GAINHF: - *val = props->Reverb.GainHF; - break; - - case AL_EAXREVERB_GAINLF: - *val = props->Reverb.GainLF; - break; - - case AL_EAXREVERB_DECAY_TIME: - *val = props->Reverb.DecayTime; - break; - - case AL_EAXREVERB_DECAY_HFRATIO: - *val = props->Reverb.DecayHFRatio; - break; - - case AL_EAXREVERB_DECAY_LFRATIO: - *val = props->Reverb.DecayLFRatio; - break; - - case AL_EAXREVERB_REFLECTIONS_GAIN: - *val = props->Reverb.ReflectionsGain; - break; - - case AL_EAXREVERB_REFLECTIONS_DELAY: - *val = props->Reverb.ReflectionsDelay; - break; - - case AL_EAXREVERB_LATE_REVERB_GAIN: - *val = props->Reverb.LateReverbGain; - break; - - case AL_EAXREVERB_LATE_REVERB_DELAY: - *val = props->Reverb.LateReverbDelay; - break; - - case AL_EAXREVERB_AIR_ABSORPTION_GAINHF: - *val = props->Reverb.AirAbsorptionGainHF; - break; - - case AL_EAXREVERB_ECHO_TIME: - *val = props->Reverb.EchoTime; - break; - - case AL_EAXREVERB_ECHO_DEPTH: - *val = props->Reverb.EchoDepth; - break; - - case AL_EAXREVERB_MODULATION_TIME: - *val = props->Reverb.ModulationTime; - break; - - case AL_EAXREVERB_MODULATION_DEPTH: - *val = props->Reverb.ModulationDepth; - break; - - case AL_EAXREVERB_HFREFERENCE: - *val = props->Reverb.HFReference; - break; - - case AL_EAXREVERB_LFREFERENCE: - *val = props->Reverb.LFReference; - break; - - case AL_EAXREVERB_ROOM_ROLLOFF_FACTOR: - *val = props->Reverb.RoomRolloffFactor; - break; - - default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); - } -} -void ALeaxreverb_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) -{ - const ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_EAXREVERB_REFLECTIONS_PAN: - LockContext(context); - vals[0] = props->Reverb.ReflectionsPan[0]; - vals[1] = props->Reverb.ReflectionsPan[1]; - vals[2] = props->Reverb.ReflectionsPan[2]; - UnlockContext(context); - break; - case AL_EAXREVERB_LATE_REVERB_PAN: - LockContext(context); - vals[0] = props->Reverb.LateReverbPan[0]; - vals[1] = props->Reverb.LateReverbPan[1]; - vals[2] = props->Reverb.LateReverbPan[2]; - UnlockContext(context); - break; - - default: - ALeaxreverb_getParamf(effect, context, param, vals); - break; - } -} - -DEFINE_ALEFFECT_VTABLE(ALeaxreverb); - -void ALreverb_setParami(ALeffect *effect, ALCcontext *context, ALenum param, ALint val) -{ - ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_REVERB_DECAY_HFLIMIT: - if(!(val >= AL_REVERB_MIN_DECAY_HFLIMIT && val <= AL_REVERB_MAX_DECAY_HFLIMIT)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Reverb.DecayHFLimit = val; - break; - - default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); - } -} -void ALreverb_setParamiv(ALeffect *effect, ALCcontext *context, ALenum param, const ALint *vals) -{ - ALreverb_setParami(effect, context, param, vals[0]); -} -void ALreverb_setParamf(ALeffect *effect, ALCcontext *context, ALenum param, ALfloat val) -{ - ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_REVERB_DENSITY: - if(!(val >= AL_REVERB_MIN_DENSITY && val <= AL_REVERB_MAX_DENSITY)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Reverb.Density = val; - break; - - case AL_REVERB_DIFFUSION: - if(!(val >= AL_REVERB_MIN_DIFFUSION && val <= AL_REVERB_MAX_DIFFUSION)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Reverb.Diffusion = val; - break; - - case AL_REVERB_GAIN: - if(!(val >= AL_REVERB_MIN_GAIN && val <= AL_REVERB_MAX_GAIN)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Reverb.Gain = val; - break; - - case AL_REVERB_GAINHF: - if(!(val >= AL_REVERB_MIN_GAINHF && val <= AL_REVERB_MAX_GAINHF)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Reverb.GainHF = val; - break; - - case AL_REVERB_DECAY_TIME: - if(!(val >= AL_REVERB_MIN_DECAY_TIME && val <= AL_REVERB_MAX_DECAY_TIME)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Reverb.DecayTime = val; - break; - - case AL_REVERB_DECAY_HFRATIO: - if(!(val >= AL_REVERB_MIN_DECAY_HFRATIO && val <= AL_REVERB_MAX_DECAY_HFRATIO)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Reverb.DecayHFRatio = val; - break; - - case AL_REVERB_REFLECTIONS_GAIN: - if(!(val >= AL_REVERB_MIN_REFLECTIONS_GAIN && val <= AL_REVERB_MAX_REFLECTIONS_GAIN)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Reverb.ReflectionsGain = val; - break; - - case AL_REVERB_REFLECTIONS_DELAY: - if(!(val >= AL_REVERB_MIN_REFLECTIONS_DELAY && val <= AL_REVERB_MAX_REFLECTIONS_DELAY)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Reverb.ReflectionsDelay = val; - break; - - case AL_REVERB_LATE_REVERB_GAIN: - if(!(val >= AL_REVERB_MIN_LATE_REVERB_GAIN && val <= AL_REVERB_MAX_LATE_REVERB_GAIN)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Reverb.LateReverbGain = val; - break; - - case AL_REVERB_LATE_REVERB_DELAY: - if(!(val >= AL_REVERB_MIN_LATE_REVERB_DELAY && val <= AL_REVERB_MAX_LATE_REVERB_DELAY)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Reverb.LateReverbDelay = val; - break; - - case AL_REVERB_AIR_ABSORPTION_GAINHF: - if(!(val >= AL_REVERB_MIN_AIR_ABSORPTION_GAINHF && val <= AL_REVERB_MAX_AIR_ABSORPTION_GAINHF)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Reverb.AirAbsorptionGainHF = val; - break; - - case AL_REVERB_ROOM_ROLLOFF_FACTOR: - if(!(val >= AL_REVERB_MIN_ROOM_ROLLOFF_FACTOR && val <= AL_REVERB_MAX_ROOM_ROLLOFF_FACTOR)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - props->Reverb.RoomRolloffFactor = val; - break; - - default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); - } -} -void ALreverb_setParamfv(ALeffect *effect, ALCcontext *context, ALenum param, const ALfloat *vals) -{ - ALreverb_setParamf(effect, context, param, vals[0]); -} - -void ALreverb_getParami(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *val) -{ - const ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_REVERB_DECAY_HFLIMIT: - *val = props->Reverb.DecayHFLimit; - break; - - default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); - } -} -void ALreverb_getParamiv(const ALeffect *effect, ALCcontext *context, ALenum param, ALint *vals) -{ - ALreverb_getParami(effect, context, param, vals); -} -void ALreverb_getParamf(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *val) -{ - const ALeffectProps *props = &effect->Props; - switch(param) - { - case AL_REVERB_DENSITY: - *val = props->Reverb.Density; - break; - - case AL_REVERB_DIFFUSION: - *val = props->Reverb.Diffusion; - break; - - case AL_REVERB_GAIN: - *val = props->Reverb.Gain; - break; - - case AL_REVERB_GAINHF: - *val = props->Reverb.GainHF; - break; - - case AL_REVERB_DECAY_TIME: - *val = props->Reverb.DecayTime; - break; - - case AL_REVERB_DECAY_HFRATIO: - *val = props->Reverb.DecayHFRatio; - break; - - case AL_REVERB_REFLECTIONS_GAIN: - *val = props->Reverb.ReflectionsGain; - break; - - case AL_REVERB_REFLECTIONS_DELAY: - *val = props->Reverb.ReflectionsDelay; - break; - - case AL_REVERB_LATE_REVERB_GAIN: - *val = props->Reverb.LateReverbGain; - break; - - case AL_REVERB_LATE_REVERB_DELAY: - *val = props->Reverb.LateReverbDelay; - break; - - case AL_REVERB_AIR_ABSORPTION_GAINHF: - *val = props->Reverb.AirAbsorptionGainHF; - break; - - case AL_REVERB_ROOM_ROLLOFF_FACTOR: - *val = props->Reverb.RoomRolloffFactor; - break; - - default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); - } -} -void ALreverb_getParamfv(const ALeffect *effect, ALCcontext *context, ALenum param, ALfloat *vals) -{ - ALreverb_getParamf(effect, context, param, vals); -} - -DEFINE_ALEFFECT_VTABLE(ALreverb); diff --git a/love/src/jni/openal-soft-1.17.0/Alc/evtqueue.h b/love/src/jni/openal-soft-1.17.0/Alc/evtqueue.h deleted file mode 100644 index 95702d79..00000000 --- a/love/src/jni/openal-soft-1.17.0/Alc/evtqueue.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef AL_EVTQUEUE_H -#define AL_EVTQUEUE_H - -#include "AL/al.h" - -#include "alMain.h" - -typedef struct MidiEvent { - ALuint64 time; - ALuint event; - union { - ALuint val[2]; - struct { - ALvoid *data; - ALsizei size; - } sysex; - } param; -} MidiEvent; - -typedef struct EvtQueue { - MidiEvent *events; - ALsizei pos; - ALsizei size; - ALsizei maxsize; -} EvtQueue; - -void InitEvtQueue(EvtQueue *queue); -void ResetEvtQueue(EvtQueue *queue); -ALenum InsertEvtQueue(EvtQueue *queue, const MidiEvent *evt); - -#endif /* AL_EVTQUEUE_H */ diff --git a/love/src/jni/openal-soft-1.17.0/Alc/helpers.c b/love/src/jni/openal-soft-1.17.0/Alc/helpers.c deleted file mode 100644 index fc879d95..00000000 --- a/love/src/jni/openal-soft-1.17.0/Alc/helpers.c +++ /dev/null @@ -1,814 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2011 by authors. - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#ifdef _WIN32 -#ifdef __MINGW32__ -#define _WIN32_IE 0x501 -#else -#define _WIN32_IE 0x400 -#endif -#endif - -#include "config.h" - -#include -#include -#include -#include -#ifdef HAVE_MALLOC_H -#include -#endif - -#ifndef AL_NO_UID_DEFS -#if defined(HAVE_GUIDDEF_H) || defined(HAVE_INITGUID_H) -#define INITGUID -#include -#ifdef HAVE_GUIDDEF_H -#include -#else -#include -#endif - -DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80,0x00, 0x00,0xaa,0x00,0x38,0x9b,0x71); -DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80,0x00, 0x00,0xaa,0x00,0x38,0x9b,0x71); - -DEFINE_GUID(IID_IDirectSoundNotify, 0xb0210783, 0x89cd, 0x11d0, 0xaf,0x08, 0x00,0xa0,0xc9,0x25,0xcd,0x16); - -DEFINE_GUID(CLSID_MMDeviceEnumerator, 0xbcde0395, 0xe52f, 0x467c, 0x8e,0x3d, 0xc4,0x57,0x92,0x91,0x69,0x2e); -DEFINE_GUID(IID_IMMDeviceEnumerator, 0xa95664d2, 0x9614, 0x4f35, 0xa7,0x46, 0xde,0x8d,0xb6,0x36,0x17,0xe6); -DEFINE_GUID(IID_IAudioClient, 0x1cb9ad4c, 0xdbfa, 0x4c32, 0xb1,0x78, 0xc2,0xf5,0x68,0xa7,0x03,0xb2); -DEFINE_GUID(IID_IAudioRenderClient, 0xf294acfc, 0x3146, 0x4483, 0xa7,0xbf, 0xad,0xdc,0xa7,0xc2,0x60,0xe2); - -#ifdef HAVE_MMDEVAPI -#include -DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14); -#endif -#endif -#endif /* AL_NO_UID_DEFS */ - -#ifdef HAVE_DLFCN_H -#include -#endif -#ifdef HAVE_INTRIN_H -#include -#endif -#ifdef HAVE_CPUID_H -#include -#endif -#ifdef HAVE_SYS_SYSCONF_H -#include -#endif -#ifdef HAVE_FLOAT_H -#include -#endif -#ifdef HAVE_IEEEFP_H -#include -#endif - -#ifdef _WIN32_IE -#include -#endif - -#include "alMain.h" -#include "alu.h" -#include "atomic.h" -#include "uintmap.h" -#include "vector.h" -#include "alstring.h" -#include "compat.h" -#include "threads.h" - - -extern inline ALuint NextPowerOf2(ALuint value); -extern inline ALint fastf2i(ALfloat f); -extern inline ALuint fastf2u(ALfloat f); - - -ALuint CPUCapFlags = 0; - - -void FillCPUCaps(ALuint capfilter) -{ - ALuint caps = 0; - -/* FIXME: We really should get this for all available CPUs in case different - * CPUs have different caps (is that possible on one machine?). */ -#if defined(HAVE_GCC_GET_CPUID) && (defined(__i386__) || defined(__x86_64__) || \ - defined(_M_IX86) || defined(_M_X64)) - union { - unsigned int regs[4]; - char str[sizeof(unsigned int[4])]; - } cpuinf[3]; - - if(!__get_cpuid(0, &cpuinf[0].regs[0], &cpuinf[0].regs[1], &cpuinf[0].regs[2], &cpuinf[0].regs[3])) - ERR("Failed to get CPUID\n"); - else - { - unsigned int maxfunc = cpuinf[0].regs[0]; - unsigned int maxextfunc = 0; - - if(__get_cpuid(0x80000000, &cpuinf[0].regs[0], &cpuinf[0].regs[1], &cpuinf[0].regs[2], &cpuinf[0].regs[3])) - maxextfunc = cpuinf[0].regs[0]; - TRACE("Detected max CPUID function: 0x%x (ext. 0x%x)\n", maxfunc, maxextfunc); - - TRACE("Vendor ID: \"%.4s%.4s%.4s\"\n", cpuinf[0].str+4, cpuinf[0].str+12, cpuinf[0].str+8); - if(maxextfunc >= 0x80000004 && - __get_cpuid(0x80000002, &cpuinf[0].regs[0], &cpuinf[0].regs[1], &cpuinf[0].regs[2], &cpuinf[0].regs[3]) && - __get_cpuid(0x80000003, &cpuinf[1].regs[0], &cpuinf[1].regs[1], &cpuinf[1].regs[2], &cpuinf[1].regs[3]) && - __get_cpuid(0x80000004, &cpuinf[2].regs[0], &cpuinf[2].regs[1], &cpuinf[2].regs[2], &cpuinf[2].regs[3])) - TRACE("Name: \"%.16s%.16s%.16s\"\n", cpuinf[0].str, cpuinf[1].str, cpuinf[2].str); - - if(maxfunc >= 1 && - __get_cpuid(1, &cpuinf[0].regs[0], &cpuinf[0].regs[1], &cpuinf[0].regs[2], &cpuinf[0].regs[3])) - { - if((cpuinf[0].regs[3]&(1<<25))) - { - caps |= CPU_CAP_SSE; - if((cpuinf[0].regs[3]&(1<<26))) - { - caps |= CPU_CAP_SSE2; - if((cpuinf[0].regs[2]&(1<<19))) - caps |= CPU_CAP_SSE4_1; - } - } - } - } -#elif defined(HAVE_CPUID_INTRINSIC) && (defined(__i386__) || defined(__x86_64__) || \ - defined(_M_IX86) || defined(_M_X64)) - union { - int regs[4]; - char str[sizeof(int[4])]; - } cpuinf[3]; - - (__cpuid)(cpuinf[0].regs, 0); - if(cpuinf[0].regs[0] == 0) - ERR("Failed to get CPUID\n"); - else - { - unsigned int maxfunc = cpuinf[0].regs[0]; - unsigned int maxextfunc; - - (__cpuid)(cpuinf[0].regs, 0x80000000); - maxextfunc = cpuinf[0].regs[0]; - - TRACE("Detected max CPUID function: 0x%x (ext. 0x%x)\n", maxfunc, maxextfunc); - - TRACE("Vendor ID: \"%.4s%.4s%.4s\"\n", cpuinf[0].str+4, cpuinf[0].str+12, cpuinf[0].str+8); - if(maxextfunc >= 0x80000004) - { - (__cpuid)(cpuinf[0].regs, 0x80000002); - (__cpuid)(cpuinf[1].regs, 0x80000003); - (__cpuid)(cpuinf[2].regs, 0x80000004); - TRACE("Name: \"%.16s%.16s%.16s\"\n", cpuinf[0].str, cpuinf[1].str, cpuinf[2].str); - } - - if(maxfunc >= 1) - { - (__cpuid)(cpuinf[0].regs, 1); - if((cpuinf[0].regs[3]&(1<<25))) - { - caps |= CPU_CAP_SSE; - if((cpuinf[0].regs[3]&(1<<26))) - { - caps |= CPU_CAP_SSE2; - if((cpuinf[0].regs[2]&(1<<19))) - caps |= CPU_CAP_SSE4_1; - } - } - } - } -#else - /* Assume support for whatever's supported if we can't check for it */ -#if defined(HAVE_SSE4_1) -#warning "Assuming SSE 4.1 run-time support!" - capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE4_1; -#elif defined(HAVE_SSE2) -#warning "Assuming SSE 2 run-time support!" - capfilter |= CPU_CAP_SSE | CPU_CAP_SSE2; -#elif defined(HAVE_SSE) -#warning "Assuming SSE run-time support!" - capfilter |= CPU_CAP_SSE; -#endif -#endif -#ifdef HAVE_NEON - /* Assume Neon support if compiled with it */ - caps |= CPU_CAP_NEON; -#endif - - TRACE("Extensions:%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_SSE4_1) ? ((caps&CPU_CAP_SSE4_1) ? " +SSE4.1" : " -SSE4.1") : ""), - ((capfilter&CPU_CAP_NEON) ? ((caps&CPU_CAP_NEON) ? " +Neon" : " -Neon") : ""), - ((!capfilter) ? " -none-" : "") - ); - CPUCapFlags = caps & capfilter; -} - - -void *al_malloc(size_t alignment, size_t size) -{ -#if defined(HAVE_ALIGNED_ALLOC) - size = (size+(alignment-1))&~(alignment-1); - return aligned_alloc(alignment, size); -#elif defined(HAVE_POSIX_MEMALIGN) - void *ret; - if(posix_memalign(&ret, alignment, size) == 0) - return ret; - return NULL; -#elif defined(HAVE__ALIGNED_MALLOC) - return _aligned_malloc(size, alignment); -#else - char *ret = malloc(size+alignment); - if(ret != NULL) - { - *(ret++) = 0x00; - while(((ALintptrEXT)ret&(alignment-1)) != 0) - *(ret++) = 0x55; - } - return ret; -#endif -} - -void *al_calloc(size_t alignment, size_t size) -{ - void *ret = al_malloc(alignment, size); - if(ret) memset(ret, 0, size); - return ret; -} - -void al_free(void *ptr) -{ -#if defined(HAVE_ALIGNED_ALLOC) || defined(HAVE_POSIX_MEMALIGN) - free(ptr); -#elif defined(HAVE__ALIGNED_MALLOC) - _aligned_free(ptr); -#else - if(ptr != NULL) - { - char *finder = ptr; - do { - --finder; - } while(*finder == 0x55); - free(finder); - } -#endif -} - - -void SetMixerFPUMode(FPUCtl *ctl) -{ -#ifdef HAVE_FENV_H - fegetenv(STATIC_CAST(fenv_t, ctl)); -#if defined(__GNUC__) && defined(HAVE_SSE) - if((CPUCapFlags&CPU_CAP_SSE)) - __asm__ __volatile__("stmxcsr %0" : "=m" (*&ctl->sse_state)); -#endif - -#ifdef FE_TOWARDZERO - fesetround(FE_TOWARDZERO); -#endif -#if defined(__GNUC__) && defined(HAVE_SSE) - if((CPUCapFlags&CPU_CAP_SSE)) - { - int sseState = ctl->sse_state; - sseState |= 0x6000; /* set round-to-zero */ - sseState |= 0x8000; /* set flush-to-zero */ - if((CPUCapFlags&CPU_CAP_SSE2)) - sseState |= 0x0040; /* set denormals-are-zero */ - __asm__ __volatile__("ldmxcsr %0" : : "m" (*&sseState)); - } -#endif - -#elif defined(HAVE___CONTROL87_2) - - int mode; - __control87_2(0, 0, &ctl->state, NULL); - __control87_2(_RC_CHOP, _MCW_RC, &mode, NULL); -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - { - __control87_2(0, 0, NULL, &ctl->sse_state); - __control87_2(_RC_CHOP|_DN_FLUSH, _MCW_RC|_MCW_DN, NULL, &mode); - } -#endif - -#elif defined(HAVE__CONTROLFP) - - ctl->state = _controlfp(0, 0); - (void)_controlfp(_RC_CHOP, _MCW_RC); -#endif -} - -void RestoreFPUMode(const FPUCtl *ctl) -{ -#ifdef HAVE_FENV_H - fesetenv(STATIC_CAST(fenv_t, ctl)); -#if defined(__GNUC__) && defined(HAVE_SSE) - if((CPUCapFlags&CPU_CAP_SSE)) - __asm__ __volatile__("ldmxcsr %0" : : "m" (*&ctl->sse_state)); -#endif - -#elif defined(HAVE___CONTROL87_2) - - int mode; - __control87_2(ctl->state, _MCW_RC, &mode, NULL); -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - __control87_2(ctl->sse_state, _MCW_RC|_MCW_DN, NULL, &mode); -#endif - -#elif defined(HAVE__CONTROLFP) - - _controlfp(ctl->state, _MCW_RC); -#endif -} - - -#ifdef _WIN32 - -static WCHAR *FromUTF8(const char *str) -{ - WCHAR *out = NULL; - int len; - - if((len=MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0)) > 0) - { - out = calloc(sizeof(WCHAR), len); - MultiByteToWideChar(CP_UTF8, 0, str, -1, out, len); - } - return out; -} - - -void *LoadLib(const char *name) -{ - HANDLE hdl = NULL; - WCHAR *wname; - - wname = FromUTF8(name); - if(!wname) - ERR("Failed to convert UTF-8 filename: \"%s\"\n", name); - else - { - hdl = LoadLibraryW(wname); - free(wname); - } - return hdl; -} -void CloseLib(void *handle) -{ FreeLibrary((HANDLE)handle); } -void *GetSymbol(void *handle, const char *name) -{ - void *ret; - - ret = (void*)GetProcAddress((HANDLE)handle, name); - if(ret == NULL) - ERR("Failed to load %s\n", name); - return ret; -} - -WCHAR *strdupW(const WCHAR *str) -{ - const WCHAR *n; - WCHAR *ret; - size_t len; - - n = str; - while(*n) n++; - len = n - str; - - ret = calloc(sizeof(WCHAR), len+1); - if(ret != NULL) - memcpy(ret, str, sizeof(WCHAR)*len); - return ret; -} - -FILE *al_fopen(const char *fname, const char *mode) -{ - WCHAR *wname=NULL, *wmode=NULL; - FILE *file = NULL; - - wname = FromUTF8(fname); - wmode = FromUTF8(mode); - if(!wname) - ERR("Failed to convert UTF-8 filename: \"%s\"\n", fname); - else if(!wmode) - ERR("Failed to convert UTF-8 mode: \"%s\"\n", mode); - else - file = _wfopen(wname, wmode); - - free(wname); - free(wmode); - - return file; -} - -#else - -#ifdef HAVE_DLFCN_H - -void *LoadLib(const char *name) -{ - const char *err; - void *handle; - - dlerror(); - handle = dlopen(name, RTLD_NOW); - if((err=dlerror()) != NULL) - handle = NULL; - return handle; -} -void CloseLib(void *handle) -{ dlclose(handle); } -void *GetSymbol(void *handle, const char *name) -{ - const char *err; - void *sym; - - dlerror(); - sym = dlsym(handle, name); - if((err=dlerror()) != NULL) - { - WARN("Failed to load %s: %s\n", name, err); - sym = NULL; - } - return sym; -} - -#endif -#endif - - -void al_print(const char *type, const char *func, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - fprintf(LogFile, "AL lib: %s %s: ", type, func); - vfprintf(LogFile, fmt, ap); - va_end(ap); - - fflush(LogFile); -} - -#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] = ""; - const char *str, *next; - FILE *f; - - if(fname[0] == '/') - { - if((f=al_fopen(fname, "rb")) != NULL) - { - TRACE("Opened %s\n", fname); - return f; - } - WARN("Could not open %s\n", fname); - return NULL; - } - - if((f=al_fopen(fname, "rb")) != NULL) - { - 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); - else if((str=getenv("HOME")) != NULL && str[0] != '\0') - snprintf(buffer, sizeof(buffer), "%s/.local/share/%s/%s", str, subdir, fname); - if(buffer[0]) - { - if((f=al_fopen(buffer, "rb")) != NULL) - { - TRACE("Opened %s\n", buffer); - return f; - } - WARN("Could not open %s\n", buffer); - } - - 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') - { - size_t len; - next = strchr(str, ':'); - - if(!next) - len = strlen(str); - else - { - len = next - str; - next++; - } - - if(len > sizeof(buffer)-1) - len = sizeof(buffer)-1; - strncpy(buffer, str, len); - buffer[len] = '\0'; - snprintf(buffer+len, sizeof(buffer)-len, "/%s/%s", subdir, fname); - - if((f=al_fopen(buffer, "rb")) != NULL) - { - TRACE("Opened %s\n", buffer); - return f; - } - WARN("Could not open %s\n", buffer); - } - - return NULL; -} -#endif - - -void SetRTPriority(void) -{ - ALboolean failed = AL_FALSE; - -#ifdef _WIN32 - if(RTPrioLevel > 0) - failed = !SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); -#elif defined(HAVE_PTHREAD_SETSCHEDPARAM) && !defined(__OpenBSD__) - if(RTPrioLevel > 0) - { - struct sched_param param; - /* Use the minimum real-time priority possible for now (on Linux this - * should be 1 for SCHED_RR) */ - param.sched_priority = sched_get_priority_min(SCHED_RR); - failed = !!pthread_setschedparam(pthread_self(), SCHED_RR, ¶m); - } -#else - /* Real-time priority not available */ - failed = (RTPrioLevel>0); -#endif - if(failed) - ERR("Failed to set priority level for thread\n"); -} - - -ALboolean vector_reserve(char *ptr, size_t base_size, size_t obj_size, ALsizei 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); - 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) - { - 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, - * sizeof(*vector_) may not equal base_size). */ - temp = realloc(*vecptr, base_size + obj_size*obj_count); - if(temp == NULL) return AL_FALSE; - - *vecptr = temp; - (*vecptr)->Capacity = obj_count; - (*vecptr)->Size = old_size; - } - return AL_TRUE; -} - -ALboolean vector_resize(char *ptr, size_t base_size, size_t obj_size, ALsizei 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)) - return AL_FALSE; - (*vecptr)->Size = obj_count; - } - return AL_TRUE; -} - -ALboolean vector_insert(char *ptr, size_t base_size, size_t obj_size, void *ins_pos, const void *datstart, const void *datend) -{ - vector_ *vecptr = (vector_*)ptr; - if(datstart != datend) - { - ptrdiff_t ins_elem = (*vecptr ? ((char*)ins_pos - ((char*)(*vecptr) + base_size)) : - ((char*)ins_pos - (char*)NULL)) / - obj_size; - ptrdiff_t numins = ((const char*)datend - (const char*)datstart) / obj_size; - - assert(numins > 0); - if(INT_MAX-VECTOR_SIZE(*vecptr) <= 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) - { - memmove((char*)(*vecptr) + base_size + ((ins_elem+numins)*obj_size), - (char*)(*vecptr) + base_size + ((ins_elem )*obj_size), - ((*vecptr)->Size-ins_elem)*obj_size); - } - memcpy((char*)(*vecptr) + base_size + (ins_elem*obj_size), - datstart, numins*obj_size); - (*vecptr)->Size += (ALsizei)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 ALboolean al_string_empty(const_al_string str); -extern inline const al_string_char_type *al_string_get_cstr(const_al_string str); - -void al_string_clear(al_string *str) -{ - /* Reserve one more character than the total size of the string. This is to - * ensure we have space to add a null terminator in the string data so it - * can be used as a C-style string. */ - VECTOR_RESERVE(*str, 1); - VECTOR_RESIZE(*str, 0); - *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) -{ - ALsizei complen = mini(str1len, str2len); - int ret = memcmp(str1, str2, complen); - if(ret == 0) - { - if(str1len > str2len) return 1; - if(str1len < str2len) return -1; - } - return ret; -} -int al_string_cmp(const_al_string str1, const_al_string str2) -{ - return al_string_compare(&VECTOR_FRONT(str1), al_string_length(str1), - &VECTOR_FRONT(str2), al_string_length(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)); -} - -void al_string_copy(al_string *str, const_al_string from) -{ - ALsizei len = VECTOR_SIZE(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); - *VECTOR_ITER_END(*str) = 0; -} - -void al_string_copy_cstr(al_string *str, const al_string_char_type *from) -{ - size_t len = strlen(from); - VECTOR_RESERVE(*str, len+1); - VECTOR_RESIZE(*str, 0); - VECTOR_INSERT(*str, VECTOR_ITER_END(*str), from, from+len); - *VECTOR_ITER_END(*str) = 0; -} - -void al_string_append_char(al_string *str, const al_string_char_type c) -{ - VECTOR_RESERVE(*str, al_string_length(*str)+2); - VECTOR_PUSH_BACK(*str, c); - *VECTOR_ITER_END(*str) = 0; -} - -void al_string_append_cstr(al_string *str, const al_string_char_type *from) -{ - size_t len = strlen(from); - if(len != 0) - { - VECTOR_RESERVE(*str, al_string_length(*str)+len+1); - VECTOR_INSERT(*str, VECTOR_ITER_END(*str), from, from+len); - *VECTOR_ITER_END(*str) = 0; - } -} - -void al_string_append_range(al_string *str, const al_string_char_type *from, const al_string_char_type *to) -{ - if(to != from) - { - VECTOR_RESERVE(*str, al_string_length(*str)+(to-from)+1); - VECTOR_INSERT(*str, VECTOR_ITER_END(*str), from, to); - *VECTOR_ITER_END(*str) = 0; - } -} - -#ifdef _WIN32 -void al_string_copy_wcstr(al_string *str, const wchar_t *from) -{ - int len; - if((len=WideCharToMultiByte(CP_UTF8, 0, from, -1, NULL, 0, NULL, NULL)) > 0) - { - VECTOR_RESERVE(*str, len); - VECTOR_RESIZE(*str, len-1); - WideCharToMultiByte(CP_UTF8, 0, from, -1, &VECTOR_FRONT(*str), len, NULL, NULL); - *VECTOR_ITER_END(*str) = 0; - } -} -#endif diff --git a/love/src/jni/openal-soft-1.17.0/Alc/hrtf.c b/love/src/jni/openal-soft-1.17.0/Alc/hrtf.c deleted file mode 100644 index 707655a0..00000000 --- a/love/src/jni/openal-soft-1.17.0/Alc/hrtf.c +++ /dev/null @@ -1,820 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2011 by Chris Robinson - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" -#include "alMain.h" -#include "alSource.h" -#include "alu.h" -#include "hrtf.h" - - -/* Current data set limits defined by the makehrtf utility. */ -#define MIN_IR_SIZE (8) -#define MAX_IR_SIZE (128) -#define MOD_IR_SIZE (8) - -#define MIN_EV_COUNT (5) -#define MAX_EV_COUNT (128) - -#define MIN_AZ_COUNT (1) -#define MAX_AZ_COUNT (128) - -struct Hrtf { - ALuint sampleRate; - ALuint irSize; - ALubyte evCount; - - const ALubyte *azCount; - const ALushort *evOffset; - const ALshort *coeffs; - const ALubyte *delays; - - struct Hrtf *next; -}; - -static const ALchar magicMarker00[8] = "MinPHR00"; -static const ALchar magicMarker01[8] = "MinPHR01"; - -/* First value for pass-through coefficients (remaining are 0), used for omni- - * directional sounds. */ -static const ALfloat PassthruCoeff = 32767.0f * 0.707106781187f/*sqrt(0.5)*/; - -static struct Hrtf *LoadedHrtfs = NULL; - -/* Calculate the elevation indices given the polar elevation in radians. - * This will return two indices between 0 and (evcount - 1) and an - * interpolation factor between 0.0 and 1.0. - */ -static void CalcEvIndices(ALuint evcount, ALfloat ev, ALuint *evidx, ALfloat *evmu) -{ - ev = (F_PI_2 + ev) * (evcount-1) / F_PI; - evidx[0] = fastf2u(ev); - evidx[1] = minu(evidx[0] + 1, evcount-1); - *evmu = ev - evidx[0]; -} - -/* Calculate the azimuth indices given the polar azimuth in radians. This - * will return two indices between 0 and (azcount - 1) and an interpolation - * factor between 0.0 and 1.0. - */ -static void CalcAzIndices(ALuint azcount, ALfloat az, ALuint *azidx, ALfloat *azmu) -{ - az = (F_2PI + az) * azcount / (F_2PI); - 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 - * are also normalized and attenuated by the specified gain. - */ -void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat dirfact, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays) -{ - ALuint evidx[2], lidx[4], ridx[4]; - ALfloat mu[3], blend[4]; - ALuint i; - - /* Claculate elevation indices and interpolation factor. */ - CalcEvIndices(Hrtf->evCount, elevation, evidx, &mu[2]); - - for(i = 0;i < 2;i++) - { - ALuint azcount = Hrtf->azCount[evidx[i]]; - ALuint evoffset = Hrtf->evOffset[evidx[i]]; - ALuint azidx[2]; - - /* Calculate azimuth indices and interpolation factor for this elevation. */ - CalcAzIndices(azcount, azimuth, azidx, &mu[i]); - - /* Calculate a set of linear HRIR indices for left and right channels. */ - lidx[i*2 + 0] = evoffset + azidx[0]; - lidx[i*2 + 1] = evoffset + azidx[1]; - ridx[i*2 + 0] = evoffset + ((azcount-azidx[0]) % azcount); - ridx[i*2 + 1] = evoffset + ((azcount-azidx[1]) % azcount); - } - - /* Calculate 4 blending weights for 2D bilinear interpolation. */ - blend[0] = (1.0f-mu[0]) * (1.0f-mu[2]); - blend[1] = ( mu[0]) * (1.0f-mu[2]); - blend[2] = (1.0f-mu[1]) * ( mu[2]); - blend[3] = ( mu[1]) * ( mu[2]); - - /* Calculate the HRIR delays using linear interpolation. */ - delays[0] = fastf2u((Hrtf->delays[lidx[0]]*blend[0] + Hrtf->delays[lidx[1]]*blend[1] + - Hrtf->delays[lidx[2]]*blend[2] + Hrtf->delays[lidx[3]]*blend[3]) * - dirfact + 0.5f) << HRTFDELAY_BITS; - delays[1] = fastf2u((Hrtf->delays[ridx[0]]*blend[0] + Hrtf->delays[ridx[1]]*blend[1] + - Hrtf->delays[ridx[2]]*blend[2] + Hrtf->delays[ridx[3]]*blend[3]) * - dirfact + 0.5f) << HRTFDELAY_BITS; - - /* Calculate the sample offsets for the HRIR indices. */ - lidx[0] *= Hrtf->irSize; - lidx[1] *= Hrtf->irSize; - lidx[2] *= Hrtf->irSize; - lidx[3] *= Hrtf->irSize; - ridx[0] *= Hrtf->irSize; - ridx[1] *= Hrtf->irSize; - ridx[2] *= Hrtf->irSize; - ridx[3] *= Hrtf->irSize; - - /* Calculate the normalized and attenuated HRIR coefficients using linear - * interpolation when there is enough gain to warrant it. Zero the - * coefficients if gain is too low. - */ - if(gain > 0.0001f) - { - 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; - 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; - - 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; - 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; - } - } - else - { - for(i = 0;i < Hrtf->irSize;i++) - { - coeffs[i][0] = 0.0f; - coeffs[i][1] = 0.0f; - } - } -} - -/* Calculates the moving HRIR target coefficients, target delays, and - * stepping values 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 are also normalized and attenuated by the - * specified gain. Stepping resolution and count is determined using the - * given delta factor between 0.0 and 1.0. - */ -ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat dirfact, ALfloat gain, ALfloat delta, ALint counter, ALfloat (*coeffs)[2], ALuint *delays, ALfloat (*coeffStep)[2], ALint *delayStep) -{ - ALuint evidx[2], lidx[4], ridx[4]; - ALfloat mu[3], blend[4]; - ALfloat left, right; - ALfloat step; - ALuint i; - - /* Claculate elevation indices and interpolation factor. */ - CalcEvIndices(Hrtf->evCount, elevation, evidx, &mu[2]); - - for(i = 0;i < 2;i++) - { - ALuint azcount = Hrtf->azCount[evidx[i]]; - ALuint evoffset = Hrtf->evOffset[evidx[i]]; - ALuint azidx[2]; - - /* Calculate azimuth indices and interpolation factor for this elevation. */ - CalcAzIndices(azcount, azimuth, azidx, &mu[i]); - - /* Calculate a set of linear HRIR indices for left and right channels. */ - lidx[i*2 + 0] = evoffset + azidx[0]; - lidx[i*2 + 1] = evoffset + azidx[1]; - ridx[i*2 + 0] = evoffset + ((azcount-azidx[0]) % azcount); - ridx[i*2 + 1] = evoffset + ((azcount-azidx[1]) % azcount); - } - - // Calculate the stepping parameters. - delta = maxf(floorf(delta*(Hrtf->sampleRate*0.015f) + 0.5f), 1.0f); - step = 1.0f / delta; - - /* Calculate 4 blending weights for 2D bilinear interpolation. */ - blend[0] = (1.0f-mu[0]) * (1.0f-mu[2]); - blend[1] = ( mu[0]) * (1.0f-mu[2]); - blend[2] = (1.0f-mu[1]) * ( mu[2]); - blend[3] = ( mu[1]) * ( mu[2]); - - /* Calculate the HRIR delays using linear interpolation. Then calculate - * the delay stepping values using the target and previous running - * delays. - */ - left = (ALfloat)(delays[0] - (delayStep[0] * counter)); - right = (ALfloat)(delays[1] - (delayStep[1] * counter)); - - delays[0] = fastf2u((Hrtf->delays[lidx[0]]*blend[0] + Hrtf->delays[lidx[1]]*blend[1] + - Hrtf->delays[lidx[2]]*blend[2] + Hrtf->delays[lidx[3]]*blend[3]) * - dirfact + 0.5f) << HRTFDELAY_BITS; - delays[1] = fastf2u((Hrtf->delays[ridx[0]]*blend[0] + Hrtf->delays[ridx[1]]*blend[1] + - 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)); - - /* Calculate the sample offsets for the HRIR indices. */ - lidx[0] *= Hrtf->irSize; - lidx[1] *= Hrtf->irSize; - lidx[2] *= Hrtf->irSize; - lidx[3] *= Hrtf->irSize; - ridx[0] *= Hrtf->irSize; - ridx[1] *= Hrtf->irSize; - ridx[2] *= Hrtf->irSize; - ridx[3] *= Hrtf->irSize; - - /* Calculate the normalized and attenuated target HRIR coefficients using - * linear interpolation when there is enough gain to warrant it. Zero - * the target coefficients if gain is too low. Then calculate the - * coefficient stepping values using the target and previous running - * coefficients. - */ - if(gain > 0.0001f) - { - 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; - 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; - - coeffStep[i][0] = step * (coeffs[i][0] - left); - coeffStep[i][1] = step * (coeffs[i][1] - right); - - for(i = 1;i < Hrtf->irSize;i++) - { - 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(0.0f, c, dirfact) * gain; - 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; - - coeffStep[i][0] = step * (coeffs[i][0] - left); - coeffStep[i][1] = step * (coeffs[i][1] - right); - } - } - else - { - for(i = 0;i < Hrtf->irSize;i++) - { - left = coeffs[i][0] - (coeffStep[i][0] * counter); - right = coeffs[i][1] - (coeffStep[i][1] * counter); - - coeffs[i][0] = 0.0f; - coeffs[i][1] = 0.0f; - - coeffStep[i][0] = step * -left; - coeffStep[i][1] = step * -right; - } - } - - /* The stepping count is the number of samples necessary for the HRIR to - * complete its transition. The mixer will only apply stepping for this - * many samples. - */ - return fastf2u(delta); -} - - -static struct Hrtf *LoadHrtf00(FILE *f, ALuint deviceRate) -{ - const ALubyte maxDelay = SRC_HISTORY_LENGTH-1; - struct Hrtf *Hrtf = NULL; - ALboolean failed = AL_FALSE; - ALuint rate = 0, irCount = 0; - ALushort irSize = 0; - ALubyte evCount = 0; - ALubyte *azCount = NULL; - ALushort *evOffset = NULL; - ALshort *coeffs = NULL; - ALubyte *delays = NULL; - ALuint i, j; - - rate = fgetc(f); - rate |= fgetc(f)<<8; - rate |= fgetc(f)<<16; - rate |= fgetc(f)<<24; - - irCount = fgetc(f); - irCount |= fgetc(f)<<8; - - irSize = fgetc(f); - irSize |= fgetc(f)<<8; - - 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", - irSize, MIN_IR_SIZE, MAX_IR_SIZE, MOD_IR_SIZE); - failed = AL_TRUE; - } - if(evCount < MIN_EV_COUNT || evCount > MAX_EV_COUNT) - { - ERR("Unsupported elevation count: evCount=%d (%d to %d)\n", - evCount, MIN_EV_COUNT, MAX_EV_COUNT); - failed = AL_TRUE; - } - - if(failed) - return NULL; - - azCount = malloc(sizeof(azCount[0])*evCount); - evOffset = malloc(sizeof(evOffset[0])*evCount); - if(azCount == NULL || evOffset == NULL) - { - ERR("Out of memory.\n"); - failed = AL_TRUE; - } - - if(!failed) - { - evOffset[0] = fgetc(f); - evOffset[0] |= fgetc(f)<<8; - for(i = 1;i < evCount;i++) - { - evOffset[i] = fgetc(f); - evOffset[i] |= fgetc(f)<<8; - if(evOffset[i] <= evOffset[i-1]) - { - ERR("Invalid evOffset: evOffset[%d]=%d (last=%d)\n", - i, evOffset[i], evOffset[i-1]); - failed = AL_TRUE; - } - - azCount[i-1] = evOffset[i] - evOffset[i-1]; - if(azCount[i-1] < MIN_AZ_COUNT || azCount[i-1] > MAX_AZ_COUNT) - { - ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n", - i-1, azCount[i-1], MIN_AZ_COUNT, MAX_AZ_COUNT); - failed = AL_TRUE; - } - } - if(irCount <= evOffset[i-1]) - { - ERR("Invalid evOffset: evOffset[%d]=%d (irCount=%d)\n", - i-1, evOffset[i-1], irCount); - failed = AL_TRUE; - } - - azCount[i-1] = irCount - evOffset[i-1]; - if(azCount[i-1] < MIN_AZ_COUNT || azCount[i-1] > MAX_AZ_COUNT) - { - ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n", - i-1, azCount[i-1], MIN_AZ_COUNT, MAX_AZ_COUNT); - failed = AL_TRUE; - } - } - - if(!failed) - { - coeffs = malloc(sizeof(coeffs[0])*irSize*irCount); - delays = malloc(sizeof(delays[0])*irCount); - if(coeffs == NULL || delays == NULL) - { - ERR("Out of memory.\n"); - failed = AL_TRUE; - } - } - - if(!failed) - { - for(i = 0;i < irCount*irSize;i+=irSize) - { - for(j = 0;j < irSize;j++) - { - ALshort coeff; - coeff = fgetc(f); - coeff |= fgetc(f)<<8; - coeffs[i+j] = coeff; - } - } - for(i = 0;i < irCount;i++) - { - delays[i] = fgetc(f); - if(delays[i] > maxDelay) - { - ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i], maxDelay); - failed = AL_TRUE; - } - } - - if(feof(f)) - { - ERR("Premature end of data\n"); - failed = AL_TRUE; - } - } - - if(!failed) - { - Hrtf = malloc(sizeof(struct Hrtf)); - if(Hrtf == NULL) - { - ERR("Out of memory.\n"); - failed = AL_TRUE; - } - } - - if(!failed) - { - Hrtf->sampleRate = rate; - Hrtf->irSize = irSize; - Hrtf->evCount = evCount; - Hrtf->azCount = azCount; - Hrtf->evOffset = evOffset; - Hrtf->coeffs = coeffs; - Hrtf->delays = delays; - Hrtf->next = NULL; - return Hrtf; - } - - free(azCount); - free(evOffset); - free(coeffs); - free(delays); - return NULL; -} - - -static struct Hrtf *LoadHrtf01(FILE *f, ALuint deviceRate) -{ - const ALubyte maxDelay = SRC_HISTORY_LENGTH-1; - struct Hrtf *Hrtf = NULL; - ALboolean failed = AL_FALSE; - ALuint rate = 0, irCount = 0; - ALubyte irSize = 0, evCount = 0; - ALubyte *azCount = NULL; - ALushort *evOffset = NULL; - ALshort *coeffs = NULL; - ALubyte *delays = NULL; - ALuint i, j; - - rate = fgetc(f); - rate |= fgetc(f)<<8; - rate |= fgetc(f)<<16; - rate |= fgetc(f)<<24; - - irSize = fgetc(f); - - 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", - irSize, MIN_IR_SIZE, MAX_IR_SIZE, MOD_IR_SIZE); - failed = AL_TRUE; - } - if(evCount < MIN_EV_COUNT || evCount > MAX_EV_COUNT) - { - ERR("Unsupported elevation count: evCount=%d (%d to %d)\n", - evCount, MIN_EV_COUNT, MAX_EV_COUNT); - failed = AL_TRUE; - } - - if(failed) - return NULL; - - azCount = malloc(sizeof(azCount[0])*evCount); - evOffset = malloc(sizeof(evOffset[0])*evCount); - if(azCount == NULL || evOffset == NULL) - { - ERR("Out of memory.\n"); - failed = AL_TRUE; - } - - if(!failed) - { - for(i = 0;i < evCount;i++) - { - azCount[i] = fgetc(f); - if(azCount[i] < MIN_AZ_COUNT || azCount[i] > MAX_AZ_COUNT) - { - ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n", - i, azCount[i], MIN_AZ_COUNT, MAX_AZ_COUNT); - failed = AL_TRUE; - } - } - } - - if(!failed) - { - evOffset[0] = 0; - irCount = azCount[0]; - for(i = 1;i < evCount;i++) - { - evOffset[i] = evOffset[i-1] + azCount[i-1]; - irCount += azCount[i]; - } - - coeffs = malloc(sizeof(coeffs[0])*irSize*irCount); - delays = malloc(sizeof(delays[0])*irCount); - if(coeffs == NULL || delays == NULL) - { - ERR("Out of memory.\n"); - failed = AL_TRUE; - } - } - - if(!failed) - { - for(i = 0;i < irCount*irSize;i+=irSize) - { - for(j = 0;j < irSize;j++) - { - ALshort coeff; - coeff = fgetc(f); - coeff |= fgetc(f)<<8; - coeffs[i+j] = coeff; - } - } - for(i = 0;i < irCount;i++) - { - delays[i] = fgetc(f); - if(delays[i] > maxDelay) - { - ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i], maxDelay); - failed = AL_TRUE; - } - } - - if(feof(f)) - { - ERR("Premature end of data\n"); - failed = AL_TRUE; - } - } - - if(!failed) - { - Hrtf = malloc(sizeof(struct Hrtf)); - if(Hrtf == NULL) - { - ERR("Out of memory.\n"); - failed = AL_TRUE; - } - } - - if(!failed) - { - Hrtf->sampleRate = rate; - Hrtf->irSize = irSize; - Hrtf->evCount = evCount; - Hrtf->azCount = azCount; - Hrtf->evOffset = evOffset; - Hrtf->coeffs = coeffs; - Hrtf->delays = delays; - Hrtf->next = NULL; - return Hrtf; - } - - free(azCount); - free(evOffset); - free(coeffs); - free(delays); - return NULL; -} - - -static struct Hrtf *LoadHrtf(ALuint deviceRate) -{ - const char *fnamelist = "default-%r.mhr"; - - ConfigValueStr(NULL, "hrtf_tables", &fnamelist); - while(*fnamelist != '\0') - { - struct Hrtf *Hrtf = NULL; - char fname[PATH_MAX]; - const char *next; - 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"); - if(f == NULL) - { - ERR("Could not open %s\n", fname); - continue; - } - - if(fread(magic, 1, sizeof(magic), f) != sizeof(magic)) - ERR("Failed to read header from %s\n", fname); - else - { - if(memcmp(magic, magicMarker00, sizeof(magicMarker00)) == 0) - { - TRACE("Detected data set format v0\n"); - Hrtf = LoadHrtf00(f, deviceRate); - } - else if(memcmp(magic, magicMarker01, sizeof(magicMarker01)) == 0) - { - TRACE("Detected data set format v1\n"); - Hrtf = LoadHrtf01(f, deviceRate); - } - else - ERR("Invalid header in %s: \"%.8s\"\n", fname, magic); - } - - fclose(f); - f = NULL; - - 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", fname); - } - - return NULL; -} - -const struct Hrtf *GetHrtf(enum DevFmtChannels chans, ALCuint srate) -{ - if(chans == DevFmtStereo) - { - struct Hrtf *Hrtf = LoadedHrtfs; - while(Hrtf != NULL) - { - if(srate == Hrtf->sampleRate) - return Hrtf; - Hrtf = Hrtf->next; - } - - Hrtf = LoadHrtf(srate); - if(Hrtf != NULL) - return Hrtf; - } - ERR("Incompatible format: %s %uhz\n", DevFmtChannelsString(chans), srate); - return NULL; -} - -ALCboolean FindHrtfFormat(enum DevFmtChannels *chans, ALCuint *srate) -{ - const struct Hrtf *hrtf = LoadedHrtfs; - while(hrtf != NULL) - { - if(*srate == hrtf->sampleRate) - break; - hrtf = hrtf->next; - } - - if(hrtf == NULL) - { - hrtf = LoadHrtf(*srate); - if(hrtf == NULL) return ALC_FALSE; - } - - *chans = DevFmtStereo; - *srate = hrtf->sampleRate; - return ALC_TRUE; -} - -void FreeHrtfs(void) -{ - struct Hrtf *Hrtf = NULL; - - while((Hrtf=LoadedHrtfs) != NULL) - { - LoadedHrtfs = Hrtf->next; - free((void*)Hrtf->azCount); - free((void*)Hrtf->evOffset); - free((void*)Hrtf->coeffs); - free((void*)Hrtf->delays); - free(Hrtf); - } -} - -ALuint GetHrtfIrSize (const struct Hrtf *Hrtf) -{ - return Hrtf->irSize; -} diff --git a/love/src/jni/openal-soft-1.17.0/Alc/hrtf.h b/love/src/jni/openal-soft-1.17.0/Alc/hrtf.h deleted file mode 100644 index 938bf552..00000000 --- a/love/src/jni/openal-soft-1.17.0/Alc/hrtf.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef ALC_HRTF_H -#define ALC_HRTF_H - -#include "AL/al.h" -#include "AL/alc.h" - -enum DevFmtChannels; - -struct Hrtf; - -#define HRIR_BITS (7) -#define HRIR_LENGTH (1< -#include -#include - -#include "midi/base.h" - -#include "alMidi.h" -#include "alMain.h" -#include "alError.h" -#include "alThunk.h" -#include "evtqueue.h" -#include "rwlock.h" -#include "alu.h" - - -extern inline ALboolean IsValidCtrlInput(int cc); - -extern inline size_t Reader_read(Reader *self, void *buf, size_t len); - - -/* MIDI events */ -#define SYSEX_EVENT (0xF0) - - -void InitEvtQueue(EvtQueue *queue) -{ - queue->events = NULL; - queue->maxsize = 0; - queue->size = 0; - queue->pos = 0; -} - -void ResetEvtQueue(EvtQueue *queue) -{ - ALsizei i; - for(i = 0;i < queue->size;i++) - { - if(queue->events[i].event == SYSEX_EVENT) - { - free(queue->events[i].param.sysex.data); - queue->events[i].param.sysex.data = NULL; - } - } - - free(queue->events); - queue->events = NULL; - queue->maxsize = 0; - queue->size = 0; - queue->pos = 0; -} - -ALenum InsertEvtQueue(EvtQueue *queue, const MidiEvent *evt) -{ - ALsizei pos; - - if(queue->maxsize == queue->size) - { - if(queue->pos > 0) - { - /* Queue has some stale entries, remove them to make space for more - * events. */ - for(pos = 0;pos < queue->pos;pos++) - { - if(queue->events[pos].event == SYSEX_EVENT) - { - free(queue->events[pos].param.sysex.data); - queue->events[pos].param.sysex.data = NULL; - } - } - memmove(&queue->events[0], &queue->events[queue->pos], - (queue->size-queue->pos)*sizeof(queue->events[0])); - queue->size -= queue->pos; - queue->pos = 0; - } - else - { - /* Queue is full, double the allocated space. */ - void *temp = NULL; - ALsizei newsize; - - newsize = (queue->maxsize ? (queue->maxsize<<1) : 16); - if(newsize > queue->maxsize) - temp = realloc(queue->events, newsize * sizeof(queue->events[0])); - if(!temp) - return AL_OUT_OF_MEMORY; - - queue->events = temp; - queue->maxsize = newsize; - } - } - - pos = queue->pos; - if(queue->size > 0) - { - ALsizei high = queue->size - 1; - while(pos < high) - { - ALsizei mid = pos + (high-pos)/2; - if(queue->events[mid].time < evt->time) - pos = mid + 1; - else - high = mid; - } - while(pos < queue->size && queue->events[pos].time <= evt->time) - pos++; - - if(pos < queue->size) - memmove(&queue->events[pos+1], &queue->events[pos], - (queue->size-pos)*sizeof(queue->events[0])); - } - - queue->events[pos] = *evt; - queue->size++; - - return AL_NO_ERROR; -} - - -void MidiSynth_Construct(MidiSynth *self, ALCdevice *device) -{ - InitEvtQueue(&self->EventQueue); - - RWLockInit(&self->Lock); - - self->Soundfonts = NULL; - self->NumSoundfonts = 0; - - self->Gain = 1.0f; - self->State = AL_INITIAL; - - self->ClockBase = 0; - self->SamplesDone = 0; - self->SampleRate = device->Frequency; -} - -void MidiSynth_Destruct(MidiSynth *self) -{ - ALsizei i; - - for(i = 0;i < self->NumSoundfonts;i++) - DecrementRef(&self->Soundfonts[i]->ref); - free(self->Soundfonts); - self->Soundfonts = NULL; - self->NumSoundfonts = 0; - - ResetEvtQueue(&self->EventQueue); -} - - -ALenum MidiSynth_selectSoundfonts(MidiSynth *self, ALCcontext *context, ALsizei count, const ALuint *ids) -{ - ALCdevice *device = context->Device; - ALsoundfont **sfonts; - ALsizei i; - - if(self->State != AL_INITIAL && self->State != AL_STOPPED) - return AL_INVALID_OPERATION; - - sfonts = calloc(1, count * sizeof(sfonts[0])); - if(!sfonts) return AL_OUT_OF_MEMORY; - - for(i = 0;i < count;i++) - { - if(ids[i] == 0) - sfonts[i] = ALsoundfont_getDefSoundfont(context); - else if(!(sfonts[i]=LookupSfont(device, ids[i]))) - { - free(sfonts); - return AL_INVALID_VALUE; - } - } - - for(i = 0;i < count;i++) - IncrementRef(&sfonts[i]->ref); - sfonts = ExchangePtr((XchgPtr*)&self->Soundfonts, sfonts); - count = ExchangeInt(&self->NumSoundfonts, count); - - for(i = 0;i < count;i++) - DecrementRef(&sfonts[i]->ref); - free(sfonts); - - return AL_NO_ERROR; -} - -extern inline void MidiSynth_setGain(MidiSynth *self, ALfloat gain); -extern inline ALfloat MidiSynth_getGain(const MidiSynth *self); -extern inline void MidiSynth_setState(MidiSynth *self, ALenum state); -extern inline ALenum MidiSynth_getState(const MidiSynth *self); - -void MidiSynth_stop(MidiSynth *self) -{ - ResetEvtQueue(&self->EventQueue); - - self->ClockBase = 0; - self->SamplesDone = 0; -} - -extern inline void MidiSynth_reset(MidiSynth *self); -extern inline ALuint64 MidiSynth_getTime(const MidiSynth *self); -extern inline ALuint64 MidiSynth_getNextEvtTime(const MidiSynth *self); - -void MidiSynth_setSampleRate(MidiSynth *self, ALuint srate) -{ - if(self->SampleRate != srate) - { - self->ClockBase += self->SamplesDone * MIDI_CLOCK_RES / self->SampleRate; - self->SamplesDone = 0; - self->SampleRate = srate; - } -} - -extern inline void MidiSynth_update(MidiSynth *self, ALCdevice *device); - -ALenum MidiSynth_insertEvent(MidiSynth *self, ALuint64 time, ALuint event, ALsizei param1, ALsizei param2) -{ - MidiEvent entry; - entry.time = time; - entry.event = event; - entry.param.val[0] = param1; - entry.param.val[1] = param2; - return InsertEvtQueue(&self->EventQueue, &entry); -} - -ALenum MidiSynth_insertSysExEvent(MidiSynth *self, ALuint64 time, const ALbyte *data, ALsizei size) -{ - MidiEvent entry; - ALenum err; - - entry.time = time; - entry.event = SYSEX_EVENT; - entry.param.sysex.size = size; - entry.param.sysex.data = malloc(size); - if(!entry.param.sysex.data) - return AL_OUT_OF_MEMORY; - memcpy(entry.param.sysex.data, data, size); - - err = InsertEvtQueue(&self->EventQueue, &entry); - if(err != AL_NO_ERROR) - free(entry.param.sysex.data); - return err; -} diff --git a/love/src/jni/openal-soft-1.17.0/Alc/midi/base.h b/love/src/jni/openal-soft-1.17.0/Alc/midi/base.h deleted file mode 100644 index 157f2399..00000000 --- a/love/src/jni/openal-soft-1.17.0/Alc/midi/base.h +++ /dev/null @@ -1,133 +0,0 @@ -#ifndef AL_MIDI_BASE_H -#define AL_MIDI_BASE_H - -#include "alMain.h" -#include "atomic.h" -#include "evtqueue.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct ALsoundfont; - -typedef size_t (*ReaderCb)(void *ptr, size_t size, void *stream); -typedef struct Reader { - ReaderCb cb; - void *ptr; - int error; -} Reader; -inline size_t Reader_read(Reader *self, void *buf, size_t len) -{ - size_t got = (!self->error) ? self->cb(buf, len, self->ptr) : 0; - if(got < len) self->error = 1; - return got; -} -#define READERR(x_) ((x_)->error) - -ALboolean loadSf2(Reader *stream, struct ALsoundfont *sfont, ALCcontext *context); - - -#define MIDI_CLOCK_RES U64(1000000000) - - -struct MidiSynthVtable; - -typedef struct MidiSynth { - EvtQueue EventQueue; - - ALuint64 ClockBase; - ALuint SamplesDone; - ALuint SampleRate; - - /* NOTE: This rwlock is for the state and soundfont. The EventQueue and - * related must instead use the device lock as they're used in the mixer - * thread. - */ - RWLock Lock; - - struct ALsoundfont **Soundfonts; - ALsizei NumSoundfonts; - - volatile ALfloat Gain; - volatile ALenum State; - - const struct MidiSynthVtable *vtbl; -} MidiSynth; - -void MidiSynth_Construct(MidiSynth *self, ALCdevice *device); -void MidiSynth_Destruct(MidiSynth *self); -ALenum MidiSynth_selectSoundfonts(MidiSynth *self, ALCcontext *context, ALsizei count, const ALuint *ids); -inline void MidiSynth_setGain(MidiSynth *self, ALfloat gain) { self->Gain = gain; } -inline ALfloat MidiSynth_getGain(const MidiSynth *self) { return self->Gain; } -inline void MidiSynth_setState(MidiSynth *self, ALenum state) { ExchangeInt(&self->State, state); } -inline ALenum MidiSynth_getState(const MidiSynth *self) { return self->State; } -void MidiSynth_stop(MidiSynth *self); -inline void MidiSynth_reset(MidiSynth *self) { MidiSynth_stop(self); } -inline ALuint64 MidiSynth_getTime(const MidiSynth *self) -{ return self->ClockBase + (self->SamplesDone*MIDI_CLOCK_RES/self->SampleRate); } -inline ALuint64 MidiSynth_getNextEvtTime(const MidiSynth *self) -{ - if(self->EventQueue.pos == self->EventQueue.size) - return UINT64_MAX; - return self->EventQueue.events[self->EventQueue.pos].time; -} -void MidiSynth_setSampleRate(MidiSynth *self, ALuint srate); -inline void MidiSynth_update(MidiSynth *self, ALCdevice *device) -{ MidiSynth_setSampleRate(self, device->Frequency); } -ALenum MidiSynth_insertEvent(MidiSynth *self, ALuint64 time, ALuint event, ALsizei param1, ALsizei param2); -ALenum MidiSynth_insertSysExEvent(MidiSynth *self, ALuint64 time, const ALbyte *data, ALsizei size); - - -struct MidiSynthVtable { - void (*const Destruct)(MidiSynth *self); - - ALenum (*const selectSoundfonts)(MidiSynth *self, ALCcontext *context, ALsizei count, const ALuint *ids); - - void (*const setGain)(MidiSynth *self, ALfloat gain); - - void (*const stop)(MidiSynth *self); - void (*const reset)(MidiSynth *self); - - void (*const update)(MidiSynth *self, ALCdevice *device); - void (*const process)(MidiSynth *self, ALuint samples, ALfloat (*restrict DryBuffer)[BUFFERSIZE]); - - void (*const Delete)(void *ptr); -}; - -#define DEFINE_MIDISYNTH_VTABLE(T) \ -DECLARE_THUNK(T, MidiSynth, void, Destruct) \ -DECLARE_THUNK3(T, MidiSynth, ALenum, selectSoundfonts, ALCcontext*, ALsizei, const ALuint*) \ -DECLARE_THUNK1(T, MidiSynth, void, setGain, ALfloat) \ -DECLARE_THUNK(T, MidiSynth, void, stop) \ -DECLARE_THUNK(T, MidiSynth, void, reset) \ -DECLARE_THUNK1(T, MidiSynth, void, update, ALCdevice*) \ -DECLARE_THUNK2(T, MidiSynth, void, process, ALuint, ALfloatBUFFERSIZE*restrict) \ -static void T##_MidiSynth_Delete(void *ptr) \ -{ T##_Delete(STATIC_UPCAST(T, MidiSynth, (MidiSynth*)ptr)); } \ - \ -static const struct MidiSynthVtable T##_MidiSynth_vtable = { \ - T##_MidiSynth_Destruct, \ - \ - T##_MidiSynth_selectSoundfonts, \ - T##_MidiSynth_setGain, \ - T##_MidiSynth_stop, \ - T##_MidiSynth_reset, \ - T##_MidiSynth_update, \ - T##_MidiSynth_process, \ - \ - T##_MidiSynth_Delete, \ -} - - -MidiSynth *SSynth_create(ALCdevice *device); -MidiSynth *FSynth_create(ALCdevice *device); -MidiSynth *DSynth_create(ALCdevice *device); - -MidiSynth *SynthCreate(ALCdevice *device); - -#ifdef __cplusplus -} -#endif - -#endif /* AL_MIDI_BASE_H */ diff --git a/love/src/jni/openal-soft-1.17.0/Alc/midi/dummy.c b/love/src/jni/openal-soft-1.17.0/Alc/midi/dummy.c deleted file mode 100644 index d50b8fef..00000000 --- a/love/src/jni/openal-soft-1.17.0/Alc/midi/dummy.c +++ /dev/null @@ -1,76 +0,0 @@ - -#include "config.h" - -#include -#include -#include -#include - -#include "alMain.h" -#include "alError.h" -#include "evtqueue.h" -#include "rwlock.h" -#include "alu.h" - -#include "midi/base.h" - -typedef struct DSynth { - DERIVE_FROM_TYPE(MidiSynth); -} DSynth; - -static void DSynth_Construct(DSynth *self, ALCdevice *device); -static DECLARE_FORWARD(DSynth, MidiSynth, void, Destruct) -static DECLARE_FORWARD3(DSynth, MidiSynth, ALenum, selectSoundfonts, ALCcontext*, ALsizei, const ALuint*) -static DECLARE_FORWARD1(DSynth, MidiSynth, void, setGain, ALfloat) -static DECLARE_FORWARD(DSynth, MidiSynth, void, stop) -static DECLARE_FORWARD(DSynth, MidiSynth, void, reset) -static DECLARE_FORWARD1(DSynth, MidiSynth, void, update, ALCdevice*) -static void DSynth_process(DSynth *self, ALuint SamplesToDo, ALfloat (*restrict DryBuffer)[BUFFERSIZE]); -DECLARE_DEFAULT_ALLOCATORS(DSynth) -DEFINE_MIDISYNTH_VTABLE(DSynth); - - -static void DSynth_Construct(DSynth *self, ALCdevice *device) -{ - MidiSynth_Construct(STATIC_CAST(MidiSynth, self), device); - SET_VTABLE2(DSynth, MidiSynth, self); -} - - -static void DSynth_processQueue(DSynth *self, ALuint64 time) -{ - EvtQueue *queue = &STATIC_CAST(MidiSynth, self)->EventQueue; - - while(queue->pos < queue->size && queue->events[queue->pos].time <= time) - queue->pos++; -} - -static void DSynth_process(DSynth *self, ALuint SamplesToDo, ALfloatBUFFERSIZE*restrict UNUSED(DryBuffer)) -{ - MidiSynth *synth = STATIC_CAST(MidiSynth, self); - ALuint64 curtime; - - if(synth->State != AL_PLAYING) - return; - - synth->SamplesDone += SamplesToDo; - synth->ClockBase += (synth->SamplesDone/synth->SampleRate) * MIDI_CLOCK_RES; - synth->SamplesDone %= synth->SampleRate; - - curtime = MidiSynth_getTime(synth); - DSynth_processQueue(self, maxi64(curtime-1, 0)); -} - - -MidiSynth *DSynth_create(ALCdevice *device) -{ - DSynth *synth = DSynth_New(sizeof(*synth)); - if(!synth) - { - ERR("Failed to allocate DSynth\n"); - return NULL; - } - memset(synth, 0, sizeof(*synth)); - DSynth_Construct(synth, device); - return STATIC_CAST(MidiSynth, synth); -} diff --git a/love/src/jni/openal-soft-1.17.0/Alc/midi/fluidsynth.c b/love/src/jni/openal-soft-1.17.0/Alc/midi/fluidsynth.c deleted file mode 100644 index 82159127..00000000 --- a/love/src/jni/openal-soft-1.17.0/Alc/midi/fluidsynth.c +++ /dev/null @@ -1,930 +0,0 @@ - -#include "config.h" - -#include -#include -#include - -#include "midi/base.h" - -#include "alMain.h" -#include "alError.h" -#include "alMidi.h" -#include "alu.h" -#include "compat.h" -#include "evtqueue.h" -#include "rwlock.h" - -#ifdef HAVE_FLUIDSYNTH - -#include - - -#ifdef HAVE_DYNLOAD -#define FLUID_FUNCS(MAGIC) \ - MAGIC(new_fluid_synth); \ - MAGIC(delete_fluid_synth); \ - MAGIC(new_fluid_settings); \ - MAGIC(delete_fluid_settings); \ - MAGIC(fluid_settings_setint); \ - MAGIC(fluid_settings_setnum); \ - MAGIC(fluid_synth_noteon); \ - MAGIC(fluid_synth_noteoff); \ - MAGIC(fluid_synth_program_change); \ - MAGIC(fluid_synth_pitch_bend); \ - MAGIC(fluid_synth_channel_pressure); \ - MAGIC(fluid_synth_cc); \ - MAGIC(fluid_synth_sysex); \ - MAGIC(fluid_synth_bank_select); \ - MAGIC(fluid_synth_set_channel_type); \ - MAGIC(fluid_synth_all_sounds_off); \ - MAGIC(fluid_synth_system_reset); \ - MAGIC(fluid_synth_set_gain); \ - MAGIC(fluid_synth_set_sample_rate); \ - MAGIC(fluid_synth_write_float); \ - MAGIC(fluid_synth_add_sfloader); \ - MAGIC(fluid_synth_sfload); \ - MAGIC(fluid_synth_sfunload); \ - MAGIC(fluid_synth_alloc_voice); \ - MAGIC(fluid_synth_start_voice); \ - MAGIC(fluid_voice_gen_set); \ - MAGIC(fluid_voice_add_mod); \ - MAGIC(fluid_mod_set_source1); \ - MAGIC(fluid_mod_set_source2); \ - MAGIC(fluid_mod_set_amount); \ - MAGIC(fluid_mod_set_dest); - -void *fsynth_handle = NULL; -#define DECL_FUNC(x) __typeof(x) *p##x -FLUID_FUNCS(DECL_FUNC) -#undef DECL_FUNC - -#define new_fluid_synth pnew_fluid_synth -#define delete_fluid_synth pdelete_fluid_synth -#define new_fluid_settings pnew_fluid_settings -#define delete_fluid_settings pdelete_fluid_settings -#define fluid_settings_setint pfluid_settings_setint -#define fluid_settings_setnum pfluid_settings_setnum -#define fluid_synth_noteon pfluid_synth_noteon -#define fluid_synth_noteoff pfluid_synth_noteoff -#define fluid_synth_program_change pfluid_synth_program_change -#define fluid_synth_pitch_bend pfluid_synth_pitch_bend -#define fluid_synth_channel_pressure pfluid_synth_channel_pressure -#define fluid_synth_cc pfluid_synth_cc -#define fluid_synth_sysex pfluid_synth_sysex -#define fluid_synth_bank_select pfluid_synth_bank_select -#define fluid_synth_set_channel_type pfluid_synth_set_channel_type -#define fluid_synth_all_sounds_off pfluid_synth_all_sounds_off -#define fluid_synth_system_reset pfluid_synth_system_reset -#define fluid_synth_set_gain pfluid_synth_set_gain -#define fluid_synth_set_sample_rate pfluid_synth_set_sample_rate -#define fluid_synth_write_float pfluid_synth_write_float -#define fluid_synth_add_sfloader pfluid_synth_add_sfloader -#define fluid_synth_sfload pfluid_synth_sfload -#define fluid_synth_sfunload pfluid_synth_sfunload -#define fluid_synth_alloc_voice pfluid_synth_alloc_voice -#define fluid_synth_start_voice pfluid_synth_start_voice -#define fluid_voice_gen_set pfluid_voice_gen_set -#define fluid_voice_add_mod pfluid_voice_add_mod -#define fluid_mod_set_source1 pfluid_mod_set_source1 -#define fluid_mod_set_source2 pfluid_mod_set_source2 -#define fluid_mod_set_amount pfluid_mod_set_amount -#define fluid_mod_set_dest pfluid_mod_set_dest - -static ALboolean LoadFSynth(void) -{ - ALboolean ret = AL_TRUE; - if(!fsynth_handle) - { - fsynth_handle = LoadLib("libfluidsynth.so.1"); - if(!fsynth_handle) return AL_FALSE; - -#define LOAD_FUNC(x) do { \ - p##x = GetSymbol(fsynth_handle, #x); \ - if(!p##x) ret = AL_FALSE; \ -} while(0) - FLUID_FUNCS(LOAD_FUNC) -#undef LOAD_FUNC - - if(ret == AL_FALSE) - { - CloseLib(fsynth_handle); - fsynth_handle = NULL; - } - } - return ret; -} -#else -static inline ALboolean LoadFSynth(void) { return AL_TRUE; } -#endif - - -/* MIDI events */ -#define SYSEX_EVENT (0xF0) - -/* MIDI controllers */ -#define CTRL_BANKSELECT_MSB (0) -#define CTRL_BANKSELECT_LSB (32) -#define CTRL_ALLNOTESOFF (123) - - -static int getModInput(ALenum input) -{ - switch(input) - { - case AL_ONE_SOFT: return FLUID_MOD_NONE; - case AL_NOTEON_VELOCITY_SOFT: return FLUID_MOD_VELOCITY; - case AL_NOTEON_KEY_SOFT: return FLUID_MOD_KEY; - case AL_KEYPRESSURE_SOFT: return FLUID_MOD_KEYPRESSURE; - case AL_CHANNELPRESSURE_SOFT: return FLUID_MOD_CHANNELPRESSURE; - case AL_PITCHBEND_SOFT: return FLUID_MOD_PITCHWHEEL; - case AL_PITCHBEND_SENSITIVITY_SOFT: return FLUID_MOD_PITCHWHEELSENS; - } - return input&0x7F; -} - -static int getModFlags(ALenum input, ALenum type, ALenum form) -{ - int ret = 0; - - switch(type) - { - case AL_UNORM_SOFT: ret |= FLUID_MOD_UNIPOLAR | FLUID_MOD_POSITIVE; break; - case AL_UNORM_REV_SOFT: ret |= FLUID_MOD_UNIPOLAR | FLUID_MOD_NEGATIVE; break; - case AL_SNORM_SOFT: ret |= FLUID_MOD_BIPOLAR | FLUID_MOD_POSITIVE; break; - case AL_SNORM_REV_SOFT: ret |= FLUID_MOD_BIPOLAR | FLUID_MOD_NEGATIVE; break; - } - switch(form) - { - case AL_LINEAR_SOFT: ret |= FLUID_MOD_LINEAR; break; - case AL_CONCAVE_SOFT: ret |= FLUID_MOD_CONCAVE; break; - case AL_CONVEX_SOFT: ret |= FLUID_MOD_CONVEX; break; - case AL_SWITCH_SOFT: ret |= FLUID_MOD_SWITCH; break; - } - /* Source input values less than 128 correspond to a MIDI continuous - * controller. Otherwise, it's a general controller. */ - if(input < 128) ret |= FLUID_MOD_CC; - else ret |= FLUID_MOD_GC; - - return ret; -} - -static enum fluid_gen_type getModDest(ALenum gen) -{ - switch(gen) - { - case AL_MOD_LFO_TO_PITCH_SOFT: return GEN_MODLFOTOPITCH; - case AL_VIBRATO_LFO_TO_PITCH_SOFT: return GEN_VIBLFOTOPITCH; - case AL_MOD_ENV_TO_PITCH_SOFT: return GEN_MODENVTOPITCH; - case AL_FILTER_CUTOFF_SOFT: return GEN_FILTERFC; - case AL_FILTER_RESONANCE_SOFT: return GEN_FILTERQ; - case AL_MOD_LFO_TO_FILTER_CUTOFF_SOFT: return GEN_MODLFOTOFILTERFC; - case AL_MOD_ENV_TO_FILTER_CUTOFF_SOFT: return GEN_MODENVTOFILTERFC; - case AL_MOD_LFO_TO_VOLUME_SOFT: return GEN_MODLFOTOVOL; - case AL_CHORUS_SEND_SOFT: return GEN_CHORUSSEND; - case AL_REVERB_SEND_SOFT: return GEN_REVERBSEND; - case AL_PAN_SOFT: return GEN_PAN; - case AL_MOD_LFO_DELAY_SOFT: return GEN_MODLFODELAY; - case AL_MOD_LFO_FREQUENCY_SOFT: return GEN_MODLFOFREQ; - case AL_VIBRATO_LFO_DELAY_SOFT: return GEN_VIBLFODELAY; - case AL_VIBRATO_LFO_FREQUENCY_SOFT: return GEN_VIBLFOFREQ; - case AL_MOD_ENV_DELAYTIME_SOFT: return GEN_MODENVDELAY; - case AL_MOD_ENV_ATTACKTIME_SOFT: return GEN_MODENVATTACK; - case AL_MOD_ENV_HOLDTIME_SOFT: return GEN_MODENVHOLD; - case AL_MOD_ENV_DECAYTIME_SOFT: return GEN_MODENVDECAY; - case AL_MOD_ENV_SUSTAINVOLUME_SOFT: return GEN_MODENVSUSTAIN; - case AL_MOD_ENV_RELEASETIME_SOFT: return GEN_MODENVRELEASE; - case AL_MOD_ENV_KEY_TO_HOLDTIME_SOFT: return GEN_KEYTOMODENVHOLD; - case AL_MOD_ENV_KEY_TO_DECAYTIME_SOFT: return GEN_KEYTOMODENVDECAY; - case AL_VOLUME_ENV_DELAYTIME_SOFT: return GEN_VOLENVDELAY; - case AL_VOLUME_ENV_ATTACKTIME_SOFT: return GEN_VOLENVATTACK; - case AL_VOLUME_ENV_HOLDTIME_SOFT: return GEN_VOLENVHOLD; - case AL_VOLUME_ENV_DECAYTIME_SOFT: return GEN_VOLENVDECAY; - case AL_VOLUME_ENV_SUSTAINVOLUME_SOFT: return GEN_VOLENVSUSTAIN; - case AL_VOLUME_ENV_RELEASETIME_SOFT: return GEN_VOLENVRELEASE; - case AL_VOLUME_ENV_KEY_TO_HOLDTIME_SOFT: return GEN_KEYTOVOLENVHOLD; - case AL_VOLUME_ENV_KEY_TO_DECAYTIME_SOFT: return GEN_KEYTOVOLENVDECAY; - case AL_ATTENUATION_SOFT: return GEN_ATTENUATION; - case AL_TUNING_COARSE_SOFT: return GEN_COARSETUNE; - case AL_TUNING_FINE_SOFT: return GEN_FINETUNE; - case AL_TUNING_SCALE_SOFT: return GEN_SCALETUNE; - } - ERR("Unhandled generator: 0x%04x\n", gen); - return 0; -} - -static int getSf2LoopMode(ALenum mode) -{ - switch(mode) - { - case AL_NONE: return 0; - case AL_LOOP_CONTINUOUS_SOFT: return 1; - case AL_LOOP_UNTIL_RELEASE_SOFT: return 3; - } - return 0; -} - -static int getSampleType(ALenum type) -{ - switch(type) - { - case AL_MONO_SOFT: return FLUID_SAMPLETYPE_MONO; - case AL_RIGHT_SOFT: return FLUID_SAMPLETYPE_RIGHT; - case AL_LEFT_SOFT: return FLUID_SAMPLETYPE_LEFT; - } - return FLUID_SAMPLETYPE_MONO; -} - -typedef struct FSample { - DERIVE_FROM_TYPE(fluid_sample_t); - - ALfontsound *Sound; - - fluid_mod_t *Mods; - ALsizei NumMods; -} FSample; - -static void FSample_Construct(FSample *self, ALfontsound *sound) -{ - fluid_sample_t *sample = STATIC_CAST(fluid_sample_t, self); - memset(sample->name, 0, sizeof(sample->name)); - sample->start = sound->Start; - sample->end = sound->End; - sample->loopstart = sound->LoopStart; - sample->loopend = sound->LoopEnd; - sample->samplerate = sound->SampleRate; - sample->origpitch = sound->PitchKey; - sample->pitchadj = sound->PitchCorrection; - sample->sampletype = getSampleType(sound->SampleType); - sample->valid = !!sound->Buffer; - sample->data = sound->Buffer ? sound->Buffer->data : NULL; - - sample->amplitude_that_reaches_noise_floor_is_valid = 0; - sample->amplitude_that_reaches_noise_floor = 0.0; - - sample->refcount = 0; - - sample->notify = NULL; - - sample->userdata = self; - - self->Sound = sound; - - self->NumMods = 0; - self->Mods = calloc(sound->ModulatorMap.size*4, sizeof(fluid_mod_t[4])); - if(self->Mods) - { - ALsizei i, j, k; - - for(i = j = 0;i < sound->ModulatorMap.size;i++) - { - ALsfmodulator *mod = sound->ModulatorMap.array[i].value; - for(k = 0;k < 4;k++,mod++) - { - if(mod->Dest == AL_NONE) - continue; - fluid_mod_set_source1(&self->Mods[j], getModInput(mod->Source[0].Input), - getModFlags(mod->Source[0].Input, mod->Source[0].Type, - mod->Source[0].Form)); - fluid_mod_set_source2(&self->Mods[j], getModInput(mod->Source[1].Input), - getModFlags(mod->Source[1].Input, mod->Source[1].Type, - mod->Source[1].Form)); - fluid_mod_set_amount(&self->Mods[j], mod->Amount); - fluid_mod_set_dest(&self->Mods[j], getModDest(mod->Dest)); - self->Mods[j++].next = NULL; - } - } - self->NumMods = j; - } -} - -static void FSample_Destruct(FSample *self) -{ - free(self->Mods); - self->Mods = NULL; - self->NumMods = 0; -} - - -typedef struct FPreset { - DERIVE_FROM_TYPE(fluid_preset_t); - - char Name[16]; - - int Preset; - int Bank; - - FSample *Samples; - ALsizei NumSamples; -} FPreset; - -static char* FPreset_getName(fluid_preset_t *preset); -static int FPreset_getPreset(fluid_preset_t *preset); -static int FPreset_getBank(fluid_preset_t *preset); -static int FPreset_noteOn(fluid_preset_t *preset, fluid_synth_t *synth, int channel, int key, int velocity); - -static void FPreset_Construct(FPreset *self, ALsfpreset *preset, fluid_sfont_t *parent) -{ - STATIC_CAST(fluid_preset_t, self)->data = self; - STATIC_CAST(fluid_preset_t, self)->sfont = parent; - STATIC_CAST(fluid_preset_t, self)->free = NULL; - STATIC_CAST(fluid_preset_t, self)->get_name = FPreset_getName; - STATIC_CAST(fluid_preset_t, self)->get_banknum = FPreset_getBank; - STATIC_CAST(fluid_preset_t, self)->get_num = FPreset_getPreset; - STATIC_CAST(fluid_preset_t, self)->noteon = FPreset_noteOn; - STATIC_CAST(fluid_preset_t, self)->notify = NULL; - - memset(self->Name, 0, sizeof(self->Name)); - self->Preset = preset->Preset; - self->Bank = preset->Bank; - - self->NumSamples = 0; - self->Samples = calloc(1, preset->NumSounds * sizeof(self->Samples[0])); - if(self->Samples) - { - ALsizei i; - self->NumSamples = preset->NumSounds; - for(i = 0;i < self->NumSamples;i++) - FSample_Construct(&self->Samples[i], preset->Sounds[i]); - } -} - -static void FPreset_Destruct(FPreset *self) -{ - ALsizei i; - - for(i = 0;i < self->NumSamples;i++) - FSample_Destruct(&self->Samples[i]); - free(self->Samples); - self->Samples = NULL; - self->NumSamples = 0; -} - -static ALboolean FPreset_canDelete(FPreset *self) -{ - ALsizei i; - for(i = 0;i < self->NumSamples;i++) - { - if(fluid_sample_refcount(STATIC_CAST(fluid_sample_t, &self->Samples[i])) != 0) - return AL_FALSE; - } - return AL_TRUE; -} - -static char* FPreset_getName(fluid_preset_t *preset) -{ - return ((FPreset*)preset->data)->Name; -} - -static int FPreset_getPreset(fluid_preset_t *preset) -{ - return ((FPreset*)preset->data)->Preset; -} - -static int FPreset_getBank(fluid_preset_t *preset) -{ - return ((FPreset*)preset->data)->Bank; -} - -static int FPreset_noteOn(fluid_preset_t *preset, fluid_synth_t *synth, int channel, int key, int vel) -{ - FPreset *self = ((FPreset*)preset->data); - ALsizei i; - - for(i = 0;i < self->NumSamples;i++) - { - FSample *sample = &self->Samples[i]; - ALfontsound *sound = sample->Sound; - fluid_voice_t *voice; - ALsizei m; - - if(!(key >= sound->MinKey && key <= sound->MaxKey && vel >= sound->MinVelocity && vel <= sound->MaxVelocity)) - continue; - - voice = fluid_synth_alloc_voice(synth, STATIC_CAST(fluid_sample_t, sample), channel, key, vel); - if(voice == NULL) return FLUID_FAILED; - - fluid_voice_gen_set(voice, GEN_MODLFOTOPITCH, sound->ModLfoToPitch); - fluid_voice_gen_set(voice, GEN_VIBLFOTOPITCH, sound->VibratoLfoToPitch); - fluid_voice_gen_set(voice, GEN_MODENVTOPITCH, sound->ModEnvToPitch); - fluid_voice_gen_set(voice, GEN_FILTERFC, sound->FilterCutoff); - fluid_voice_gen_set(voice, GEN_FILTERQ, sound->FilterQ); - fluid_voice_gen_set(voice, GEN_MODLFOTOFILTERFC, sound->ModLfoToFilterCutoff); - fluid_voice_gen_set(voice, GEN_MODENVTOFILTERFC, sound->ModEnvToFilterCutoff); - fluid_voice_gen_set(voice, GEN_MODLFOTOVOL, sound->ModLfoToVolume); - fluid_voice_gen_set(voice, GEN_CHORUSSEND, sound->ChorusSend); - fluid_voice_gen_set(voice, GEN_REVERBSEND, sound->ReverbSend); - fluid_voice_gen_set(voice, GEN_PAN, sound->Pan); - fluid_voice_gen_set(voice, GEN_MODLFODELAY, sound->ModLfo.Delay); - fluid_voice_gen_set(voice, GEN_MODLFOFREQ, sound->ModLfo.Frequency); - fluid_voice_gen_set(voice, GEN_VIBLFODELAY, sound->VibratoLfo.Delay); - fluid_voice_gen_set(voice, GEN_VIBLFOFREQ, sound->VibratoLfo.Frequency); - fluid_voice_gen_set(voice, GEN_MODENVDELAY, sound->ModEnv.DelayTime); - fluid_voice_gen_set(voice, GEN_MODENVATTACK, sound->ModEnv.AttackTime); - fluid_voice_gen_set(voice, GEN_MODENVHOLD, sound->ModEnv.HoldTime); - fluid_voice_gen_set(voice, GEN_MODENVDECAY, sound->ModEnv.DecayTime); - fluid_voice_gen_set(voice, GEN_MODENVSUSTAIN, sound->ModEnv.SustainAttn); - fluid_voice_gen_set(voice, GEN_MODENVRELEASE, sound->ModEnv.ReleaseTime); - fluid_voice_gen_set(voice, GEN_KEYTOMODENVHOLD, sound->ModEnv.KeyToHoldTime); - fluid_voice_gen_set(voice, GEN_KEYTOMODENVDECAY, sound->ModEnv.KeyToDecayTime); - fluid_voice_gen_set(voice, GEN_VOLENVDELAY, sound->VolEnv.DelayTime); - fluid_voice_gen_set(voice, GEN_VOLENVATTACK, sound->VolEnv.AttackTime); - fluid_voice_gen_set(voice, GEN_VOLENVHOLD, sound->VolEnv.HoldTime); - fluid_voice_gen_set(voice, GEN_VOLENVDECAY, sound->VolEnv.DecayTime); - fluid_voice_gen_set(voice, GEN_VOLENVSUSTAIN, sound->VolEnv.SustainAttn); - fluid_voice_gen_set(voice, GEN_VOLENVRELEASE, sound->VolEnv.ReleaseTime); - fluid_voice_gen_set(voice, GEN_KEYTOVOLENVHOLD, sound->VolEnv.KeyToHoldTime); - fluid_voice_gen_set(voice, GEN_KEYTOVOLENVDECAY, sound->VolEnv.KeyToDecayTime); - fluid_voice_gen_set(voice, GEN_ATTENUATION, sound->Attenuation); - fluid_voice_gen_set(voice, GEN_COARSETUNE, sound->CoarseTuning); - fluid_voice_gen_set(voice, GEN_FINETUNE, sound->FineTuning); - fluid_voice_gen_set(voice, GEN_SAMPLEMODE, getSf2LoopMode(sound->LoopMode)); - fluid_voice_gen_set(voice, GEN_SCALETUNE, sound->TuningScale); - fluid_voice_gen_set(voice, GEN_EXCLUSIVECLASS, sound->ExclusiveClass); - for(m = 0;m < sample->NumMods;m++) - fluid_voice_add_mod(voice, &sample->Mods[m], FLUID_VOICE_OVERWRITE); - - fluid_synth_start_voice(synth, voice); - } - - return FLUID_OK; -} - - -typedef struct FSfont { - DERIVE_FROM_TYPE(fluid_sfont_t); - - char Name[16]; - - FPreset *Presets; - ALsizei NumPresets; - - ALsizei CurrentPos; -} FSfont; - -static int FSfont_free(fluid_sfont_t *sfont); -static char* FSfont_getName(fluid_sfont_t *sfont); -static fluid_preset_t* FSfont_getPreset(fluid_sfont_t *sfont, unsigned int bank, unsigned int prenum); -static void FSfont_iterStart(fluid_sfont_t *sfont); -static int FSfont_iterNext(fluid_sfont_t *sfont, fluid_preset_t *preset); - -static void FSfont_Construct(FSfont *self, ALsoundfont *sfont) -{ - STATIC_CAST(fluid_sfont_t, self)->data = self; - STATIC_CAST(fluid_sfont_t, self)->id = FLUID_FAILED; - STATIC_CAST(fluid_sfont_t, self)->free = FSfont_free; - STATIC_CAST(fluid_sfont_t, self)->get_name = FSfont_getName; - STATIC_CAST(fluid_sfont_t, self)->get_preset = FSfont_getPreset; - STATIC_CAST(fluid_sfont_t, self)->iteration_start = FSfont_iterStart; - STATIC_CAST(fluid_sfont_t, self)->iteration_next = FSfont_iterNext; - - memset(self->Name, 0, sizeof(self->Name)); - self->CurrentPos = 0; - self->NumPresets = 0; - self->Presets = calloc(1, sfont->NumPresets * sizeof(self->Presets[0])); - if(self->Presets) - { - ALsizei i; - self->NumPresets = sfont->NumPresets; - for(i = 0;i < self->NumPresets;i++) - FPreset_Construct(&self->Presets[i], sfont->Presets[i], STATIC_CAST(fluid_sfont_t, self)); - } -} - -static void FSfont_Destruct(FSfont *self) -{ - ALsizei i; - - for(i = 0;i < self->NumPresets;i++) - FPreset_Destruct(&self->Presets[i]); - free(self->Presets); - self->Presets = NULL; - self->NumPresets = 0; - self->CurrentPos = 0; -} - -static int FSfont_free(fluid_sfont_t *sfont) -{ - FSfont *self = STATIC_UPCAST(FSfont, fluid_sfont_t, sfont); - ALsizei i; - - for(i = 0;i < self->NumPresets;i++) - { - if(!FPreset_canDelete(&self->Presets[i])) - return 1; - } - - FSfont_Destruct(self); - free(self); - return 0; -} - -static char* FSfont_getName(fluid_sfont_t *sfont) -{ - return STATIC_UPCAST(FSfont, fluid_sfont_t, sfont)->Name; -} - -static fluid_preset_t *FSfont_getPreset(fluid_sfont_t *sfont, unsigned int bank, unsigned int prenum) -{ - FSfont *self = STATIC_UPCAST(FSfont, fluid_sfont_t, sfont); - ALsizei i; - - for(i = 0;i < self->NumPresets;i++) - { - FPreset *preset = &self->Presets[i]; - if(preset->Bank == (int)bank && preset->Preset == (int)prenum) - return STATIC_CAST(fluid_preset_t, preset); - } - - return NULL; -} - -static void FSfont_iterStart(fluid_sfont_t *sfont) -{ - STATIC_UPCAST(FSfont, fluid_sfont_t, sfont)->CurrentPos = 0; -} - -static int FSfont_iterNext(fluid_sfont_t *sfont, fluid_preset_t *preset) -{ - FSfont *self = STATIC_UPCAST(FSfont, fluid_sfont_t, sfont); - if(self->CurrentPos >= self->NumPresets) - return 0; - *preset = *STATIC_CAST(fluid_preset_t, &self->Presets[self->CurrentPos++]); - preset->free = NULL; - return 1; -} - - -typedef struct FSynth { - DERIVE_FROM_TYPE(MidiSynth); - DERIVE_FROM_TYPE(fluid_sfloader_t); - - fluid_settings_t *Settings; - fluid_synth_t *Synth; - int *FontIDs; - ALsizei NumFontIDs; - - ALboolean ForceGM2BankSelect; - ALfloat GainScale; -} FSynth; - -static void FSynth_Construct(FSynth *self, ALCdevice *device); -static void FSynth_Destruct(FSynth *self); -static ALboolean FSynth_init(FSynth *self, ALCdevice *device); -static ALenum FSynth_selectSoundfonts(FSynth *self, ALCcontext *context, ALsizei count, const ALuint *ids); -static void FSynth_setGain(FSynth *self, ALfloat gain); -static void FSynth_stop(FSynth *self); -static void FSynth_reset(FSynth *self); -static void FSynth_update(FSynth *self, ALCdevice *device); -static void FSynth_processQueue(FSynth *self, ALuint64 time); -static void FSynth_process(FSynth *self, ALuint SamplesToDo, ALfloat (*restrict DryBuffer)[BUFFERSIZE]); -DECLARE_DEFAULT_ALLOCATORS(FSynth) -DEFINE_MIDISYNTH_VTABLE(FSynth); - -static fluid_sfont_t *FSynth_loadSfont(fluid_sfloader_t *loader, const char *filename); - - -static void FSynth_Construct(FSynth *self, ALCdevice *device) -{ - MidiSynth_Construct(STATIC_CAST(MidiSynth, self), device); - SET_VTABLE2(FSynth, MidiSynth, self); - - STATIC_CAST(fluid_sfloader_t, self)->data = self; - STATIC_CAST(fluid_sfloader_t, self)->free = NULL; - STATIC_CAST(fluid_sfloader_t, self)->load = FSynth_loadSfont; - - self->Settings = NULL; - self->Synth = NULL; - self->FontIDs = NULL; - self->NumFontIDs = 0; - self->ForceGM2BankSelect = AL_FALSE; - self->GainScale = 0.2f; -} - -static void FSynth_Destruct(FSynth *self) -{ - ALsizei i; - - for(i = 0;i < self->NumFontIDs;i++) - fluid_synth_sfunload(self->Synth, self->FontIDs[i], 0); - free(self->FontIDs); - self->FontIDs = NULL; - self->NumFontIDs = 0; - - if(self->Synth != NULL) - delete_fluid_synth(self->Synth); - self->Synth = NULL; - - if(self->Settings != NULL) - delete_fluid_settings(self->Settings); - self->Settings = NULL; - - MidiSynth_Destruct(STATIC_CAST(MidiSynth, self)); -} - -static ALboolean FSynth_init(FSynth *self, ALCdevice *device) -{ - ALfloat vol; - - if(ConfigValueFloat("midi", "volume", &vol)) - { - if(!(vol <= 0.0f)) - { - ERR("MIDI volume %f clamped to 0\n", vol); - vol = 0.0f; - } - self->GainScale = powf(10.0f, vol / 20.0f); - } - - self->Settings = new_fluid_settings(); - if(!self->Settings) - { - ERR("Failed to create FluidSettings\n"); - return AL_FALSE; - } - - fluid_settings_setint(self->Settings, "synth.polyphony", 256); - fluid_settings_setnum(self->Settings, "synth.gain", self->GainScale); - fluid_settings_setnum(self->Settings, "synth.sample-rate", device->Frequency); - - self->Synth = new_fluid_synth(self->Settings); - if(!self->Synth) - { - ERR("Failed to create FluidSynth\n"); - return AL_FALSE; - } - - fluid_synth_add_sfloader(self->Synth, STATIC_CAST(fluid_sfloader_t, self)); - - return AL_TRUE; -} - - -static fluid_sfont_t *FSynth_loadSfont(fluid_sfloader_t *loader, const char *filename) -{ - FSynth *self = STATIC_UPCAST(FSynth, fluid_sfloader_t, loader); - FSfont *sfont; - int idx; - - if(!filename || sscanf(filename, "_al_internal %d", &idx) != 1) - return NULL; - if(idx < 0 || idx >= STATIC_CAST(MidiSynth, self)->NumSoundfonts) - { - ERR("Received invalid soundfont index %d (max: %d)\n", idx, STATIC_CAST(MidiSynth, self)->NumSoundfonts); - return NULL; - } - - sfont = calloc(1, sizeof(sfont[0])); - if(!sfont) return NULL; - - FSfont_Construct(sfont, STATIC_CAST(MidiSynth, self)->Soundfonts[idx]); - return STATIC_CAST(fluid_sfont_t, sfont); -} - -static ALenum FSynth_selectSoundfonts(FSynth *self, ALCcontext *context, ALsizei count, const ALuint *ids) -{ - int *fontid; - ALenum ret; - ALsizei i; - - ret = MidiSynth_selectSoundfonts(STATIC_CAST(MidiSynth, self), context, count, ids); - if(ret != AL_NO_ERROR) return ret; - - ALCdevice_Lock(context->Device); - for(i = 0;i < 16;i++) - fluid_synth_all_sounds_off(self->Synth, i); - ALCdevice_Unlock(context->Device); - - fontid = malloc(count * sizeof(fontid[0])); - if(fontid) - { - for(i = 0;i < STATIC_CAST(MidiSynth, self)->NumSoundfonts;i++) - { - char name[16]; - snprintf(name, sizeof(name), "_al_internal %d", i); - - fontid[i] = fluid_synth_sfload(self->Synth, name, 0); - if(fontid[i] == FLUID_FAILED) - ERR("Failed to load selected soundfont %d\n", i); - } - - fontid = ExchangePtr((XchgPtr*)&self->FontIDs, fontid); - count = ExchangeInt(&self->NumFontIDs, count); - } - else - { - ERR("Failed to allocate space for %d font IDs!\n", count); - fontid = ExchangePtr((XchgPtr*)&self->FontIDs, NULL); - count = ExchangeInt(&self->NumFontIDs, 0); - } - - for(i = 0;i < count;i++) - fluid_synth_sfunload(self->Synth, fontid[i], 0); - free(fontid); - - return ret; -} - - -static void FSynth_setGain(FSynth *self, ALfloat gain) -{ - fluid_settings_setnum(self->Settings, "synth.gain", self->GainScale * gain); - fluid_synth_set_gain(self->Synth, self->GainScale * gain); - MidiSynth_setGain(STATIC_CAST(MidiSynth, self), gain); -} - - -static void FSynth_stop(FSynth *self) -{ - MidiSynth *synth = STATIC_CAST(MidiSynth, self); - ALuint64 curtime; - ALsizei chan; - - /* Make sure all pending events are processed. */ - curtime = MidiSynth_getTime(synth); - FSynth_processQueue(self, curtime); - - /* All notes off */ - for(chan = 0;chan < 16;chan++) - fluid_synth_cc(self->Synth, chan, CTRL_ALLNOTESOFF, 0); - - MidiSynth_stop(STATIC_CAST(MidiSynth, self)); -} - -static void FSynth_reset(FSynth *self) -{ - /* Reset to power-up status. */ - fluid_synth_system_reset(self->Synth); - - MidiSynth_reset(STATIC_CAST(MidiSynth, self)); -} - - -static void FSynth_update(FSynth *self, ALCdevice *device) -{ - fluid_settings_setnum(self->Settings, "synth.sample-rate", device->Frequency); - fluid_synth_set_sample_rate(self->Synth, device->Frequency); - MidiSynth_update(STATIC_CAST(MidiSynth, self), device); -} - - -static void FSynth_processQueue(FSynth *self, ALuint64 time) -{ - EvtQueue *queue = &STATIC_CAST(MidiSynth, self)->EventQueue; - - while(queue->pos < queue->size && queue->events[queue->pos].time <= time) - { - const MidiEvent *evt = &queue->events[queue->pos]; - - if(evt->event == SYSEX_EVENT) - { - static const ALbyte gm2_on[] = { 0x7E, 0x7F, 0x09, 0x03 }; - static const ALbyte gm2_off[] = { 0x7E, 0x7F, 0x09, 0x02 }; - int handled = 0; - - fluid_synth_sysex(self->Synth, evt->param.sysex.data, evt->param.sysex.size, NULL, NULL, &handled, 0); - if(!handled && evt->param.sysex.size >= (ALsizei)sizeof(gm2_on)) - { - if(memcmp(evt->param.sysex.data, gm2_on, sizeof(gm2_on)) == 0) - self->ForceGM2BankSelect = AL_TRUE; - else if(memcmp(evt->param.sysex.data, gm2_off, sizeof(gm2_off)) == 0) - self->ForceGM2BankSelect = AL_FALSE; - } - } - else switch((evt->event&0xF0)) - { - case AL_NOTEOFF_SOFT: - fluid_synth_noteoff(self->Synth, (evt->event&0x0F), evt->param.val[0]); - break; - case AL_NOTEON_SOFT: - fluid_synth_noteon(self->Synth, (evt->event&0x0F), evt->param.val[0], evt->param.val[1]); - break; - case AL_KEYPRESSURE_SOFT: - break; - - case AL_CONTROLLERCHANGE_SOFT: - if(self->ForceGM2BankSelect) - { - int chan = (evt->event&0x0F); - if(evt->param.val[0] == CTRL_BANKSELECT_MSB) - { - if(evt->param.val[1] == 120 && (chan == 9 || chan == 10)) - fluid_synth_set_channel_type(self->Synth, chan, CHANNEL_TYPE_DRUM); - else if(evt->param.val[1] == 121) - fluid_synth_set_channel_type(self->Synth, chan, CHANNEL_TYPE_MELODIC); - break; - } - if(evt->param.val[0] == CTRL_BANKSELECT_LSB) - { - fluid_synth_bank_select(self->Synth, chan, evt->param.val[1]); - break; - } - } - fluid_synth_cc(self->Synth, (evt->event&0x0F), evt->param.val[0], evt->param.val[1]); - break; - case AL_PROGRAMCHANGE_SOFT: - fluid_synth_program_change(self->Synth, (evt->event&0x0F), evt->param.val[0]); - break; - - case AL_CHANNELPRESSURE_SOFT: - fluid_synth_channel_pressure(self->Synth, (evt->event&0x0F), evt->param.val[0]); - break; - - case AL_PITCHBEND_SOFT: - fluid_synth_pitch_bend(self->Synth, (evt->event&0x0F), (evt->param.val[0]&0x7F) | - ((evt->param.val[1]&0x7F)<<7)); - break; - } - - queue->pos++; - } -} - -static void FSynth_process(FSynth *self, ALuint SamplesToDo, ALfloat (*restrict DryBuffer)[BUFFERSIZE]) -{ - MidiSynth *synth = STATIC_CAST(MidiSynth, self); - ALenum state = synth->State; - ALuint64 curtime; - ALuint total = 0; - - if(state == AL_INITIAL) - return; - if(state != AL_PLAYING) - { - fluid_synth_write_float(self->Synth, SamplesToDo, DryBuffer[FrontLeft], 0, 1, - DryBuffer[FrontRight], 0, 1); - return; - } - - curtime = MidiSynth_getTime(synth); - while(total < SamplesToDo) - { - ALuint64 time, diff; - ALint tonext; - - time = MidiSynth_getNextEvtTime(synth); - diff = maxu64(time, curtime) - curtime; - if(diff >= MIDI_CLOCK_RES || time == UINT64_MAX) - { - /* If there's no pending event, or if it's more than 1 second - * away, do as many samples as we can. */ - tonext = INT_MAX; - } - else - { - /* Figure out how many samples until the next event. */ - tonext = (ALint)((diff*synth->SampleRate + (MIDI_CLOCK_RES-1)) / MIDI_CLOCK_RES); - tonext -= total; - } - - if(tonext > 0) - { - ALuint todo = minu(tonext, SamplesToDo-total); - fluid_synth_write_float(self->Synth, todo, DryBuffer[FrontLeft], total, 1, - DryBuffer[FrontRight], total, 1); - total += todo; - tonext -= todo; - } - if(total < SamplesToDo && tonext <= 0) - FSynth_processQueue(self, time); - } - - synth->SamplesDone += SamplesToDo; - synth->ClockBase += (synth->SamplesDone/synth->SampleRate) * MIDI_CLOCK_RES; - synth->SamplesDone %= synth->SampleRate; -} - - -MidiSynth *FSynth_create(ALCdevice *device) -{ - FSynth *synth; - - if(!LoadFSynth()) - return NULL; - - synth = FSynth_New(sizeof(*synth)); - if(!synth) - { - ERR("Failed to allocate FSynth\n"); - return NULL; - } - memset(synth, 0, sizeof(*synth)); - FSynth_Construct(synth, device); - - if(FSynth_init(synth, device) == AL_FALSE) - { - DELETE_OBJ(STATIC_CAST(MidiSynth, synth)); - return NULL; - } - - return STATIC_CAST(MidiSynth, synth); -} - -#else - -MidiSynth *FSynth_create(ALCdevice* UNUSED(device)) -{ - return NULL; -} - -#endif diff --git a/love/src/jni/openal-soft-1.17.0/Alc/midi/sf2load.c b/love/src/jni/openal-soft-1.17.0/Alc/midi/sf2load.c deleted file mode 100644 index 233f7983..00000000 --- a/love/src/jni/openal-soft-1.17.0/Alc/midi/sf2load.c +++ /dev/null @@ -1,1377 +0,0 @@ - -#include "config.h" - -#include -#include - -#include "alMain.h" -#include "alMidi.h" -#include "alError.h" -#include "alu.h" - -#include "midi/base.h" - - -static ALuint read_le32(Reader *stream) -{ - ALubyte buf[4]; - if(Reader_read(stream, buf, 4) != 4) - return 0; - return (buf[3]<<24) | (buf[2]<<16) | (buf[1]<<8) | buf[0]; -} -static ALushort read_le16(Reader *stream) -{ - ALubyte buf[2]; - if(Reader_read(stream, buf, 2) != 2) - return 0; - return (buf[1]<<8) | buf[0]; -} -static ALubyte read_8(Reader *stream) -{ - ALubyte buf[1]; - if(Reader_read(stream, buf, 1) != 1) - return 0; - return buf[0]; -} -static void skip(Reader *stream, ALuint amt) -{ - while(amt > 0 && !READERR(stream)) - { - char buf[4096]; - amt -= Reader_read(stream, buf, minu(sizeof(buf), amt)); - } -} - -typedef struct Generator { - ALushort mGenerator; - ALushort mAmount; -} Generator; -static void Generator_read(Generator *self, Reader *stream) -{ - self->mGenerator = read_le16(stream); - self->mAmount = read_le16(stream); -} - -static const ALint DefaultGenValue[60] = { - 0, /* 0 - startAddrOffset */ - 0, /* 1 - endAddrOffset */ - 0, /* 2 - startloopAddrOffset */ - 0, /* 3 - endloopAddrOffset */ - 0, /* 4 - startAddrCoarseOffset */ - 0, /* 5 - modLfoToPitch */ - 0, /* 6 - vibLfoToPitch */ - 0, /* 7 - modEnvToPitch */ - 13500, /* 8 - initialFilterFc */ - 0, /* 9 - initialFilterQ */ - 0, /* 10 - modLfoToFilterFc */ - 0, /* 11 - modEnvToFilterFc */ - 0, /* 12 - endAddrCoarseOffset */ - 0, /* 13 - modLfoToVolume */ - 0, /* 14 - */ - 0, /* 15 - chorusEffectsSend */ - 0, /* 16 - reverbEffectsSend */ - 0, /* 17 - pan */ - 0, /* 18 - */ - 0, /* 19 - */ - 0, /* 20 - */ - -12000, /* 21 - delayModLFO */ - 0, /* 22 - freqModLFO */ - -12000, /* 23 - delayVibLFO */ - 0, /* 24 - freqVibLFO */ - -12000, /* 25 - delayModEnv */ - -12000, /* 26 - attackModEnv */ - -12000, /* 27 - holdModEnv */ - -12000, /* 28 - decayModEnv */ - 0, /* 29 - sustainModEnv */ - -12000, /* 30 - releaseModEnv */ - 0, /* 31 - keynumToModEnvHold */ - 0, /* 32 - keynumToModEnvDecay */ - -12000, /* 33 - delayVolEnv */ - -12000, /* 34 - attackVolEnv */ - -12000, /* 35 - holdVolEnv */ - -12000, /* 36 - decayVolEnv */ - 0, /* 37 - sustainVolEnv */ - -12000, /* 38 - releaseVolEnv */ - 0, /* 39 - keynumToVolEnvHold */ - 0, /* 40 - keynumToVolEnvDecay */ - 0, /* 41 - */ - 0, /* 42 - */ - 0, /* 43 - keyRange */ - 0, /* 44 - velRange */ - 0, /* 45 - startloopAddrCoarseOffset */ - 0, /* 46 - keynum */ - 0, /* 47 - velocity */ - 0, /* 48 - initialAttenuation */ - 0, /* 49 - */ - 0, /* 50 - endloopAddrCoarseOffset */ - 0, /* 51 - corseTune */ - 0, /* 52 - fineTune */ - 0, /* 53 - */ - 0, /* 54 - sampleModes */ - 0, /* 55 - */ - 100, /* 56 - scaleTuning */ - 0, /* 57 - exclusiveClass */ - 0, /* 58 - overridingRootKey */ - 0, /* 59 - */ -}; - -typedef struct Modulator { - ALushort mSrcOp; - ALushort mDstOp; - ALshort mAmount; - ALushort mAmtSrcOp; - ALushort mTransOp; -} Modulator; -static void Modulator_read(Modulator *self, Reader *stream) -{ - self->mSrcOp = read_le16(stream); - self->mDstOp = read_le16(stream); - self->mAmount = read_le16(stream); - self->mAmtSrcOp = read_le16(stream); - self->mTransOp = read_le16(stream); -} - -typedef struct Zone { - ALushort mGenIdx; - ALushort mModIdx; -} Zone; -static void Zone_read(Zone *self, Reader *stream) -{ - self->mGenIdx = read_le16(stream); - self->mModIdx = read_le16(stream); -} - -typedef struct PresetHeader { - ALchar mName[20]; - ALushort mPreset; /* MIDI program number */ - ALushort mBank; - ALushort mZoneIdx; - ALuint mLibrary; - ALuint mGenre; - ALuint mMorphology; -} PresetHeader; -static void PresetHeader_read(PresetHeader *self, Reader *stream) -{ - Reader_read(stream, self->mName, sizeof(self->mName)); - self->mPreset = read_le16(stream); - self->mBank = read_le16(stream); - self->mZoneIdx = read_le16(stream); - self->mLibrary = read_le32(stream); - self->mGenre = read_le32(stream); - self->mMorphology = read_le32(stream); -} - -typedef struct InstrumentHeader { - ALchar mName[20]; - ALushort mZoneIdx; -} InstrumentHeader; -static void InstrumentHeader_read(InstrumentHeader *self, Reader *stream) -{ - Reader_read(stream, self->mName, sizeof(self->mName)); - self->mZoneIdx = read_le16(stream); -} - -typedef struct SampleHeader { - ALchar mName[20]; - ALuint mStart; - ALuint mEnd; - ALuint mStartloop; - ALuint mEndloop; - ALuint mSampleRate; - ALubyte mOriginalKey; - ALbyte mCorrection; - ALushort mSampleLink; - ALushort mSampleType; -} SampleHeader; -static void SampleHeader_read(SampleHeader *self, Reader *stream) -{ - Reader_read(stream, self->mName, sizeof(self->mName)); - self->mStart = read_le32(stream); - self->mEnd = read_le32(stream); - self->mStartloop = read_le32(stream); - self->mEndloop = read_le32(stream); - self->mSampleRate = read_le32(stream); - self->mOriginalKey = read_8(stream); - self->mCorrection = read_8(stream); - self->mSampleLink = read_le16(stream); - self->mSampleType = read_le16(stream); -} - - -typedef struct Soundfont { - ALuint ifil; - ALchar *irom; - - PresetHeader *phdr; - ALsizei phdr_size; - - Zone *pbag; - ALsizei pbag_size; - Modulator *pmod; - ALsizei pmod_size; - Generator *pgen; - ALsizei pgen_size; - - InstrumentHeader *inst; - ALsizei inst_size; - - Zone *ibag; - ALsizei ibag_size; - Modulator *imod; - ALsizei imod_size; - Generator *igen; - ALsizei igen_size; - - SampleHeader *shdr; - ALsizei shdr_size; -} Soundfont; - -static void Soundfont_Construct(Soundfont *self) -{ - self->ifil = 0; - self->irom = NULL; - - self->phdr = NULL; - self->phdr_size = 0; - - self->pbag = NULL; - self->pbag_size = 0; - self->pmod = NULL; - self->pmod_size = 0; - self->pgen = NULL; - self->pgen_size = 0; - - self->inst = NULL; - self->inst_size = 0; - - self->ibag = NULL; - self->ibag_size = 0; - self->imod = NULL; - self->imod_size = 0; - self->igen = NULL; - self->igen_size = 0; - - self->shdr = NULL; - self->shdr_size = 0; -} - -static void Soundfont_Destruct(Soundfont *self) -{ - free(self->irom); - self->irom = NULL; - - free(self->phdr); - self->phdr = NULL; - self->phdr_size = 0; - - free(self->pbag); - self->pbag = NULL; - self->pbag_size = 0; - free(self->pmod); - self->pmod = NULL; - self->pmod_size = 0; - free(self->pgen); - self->pgen = NULL; - self->pgen_size = 0; - - free(self->inst); - self->inst = NULL; - self->inst_size = 0; - - free(self->ibag); - self->ibag = NULL; - self->ibag_size = 0; - free(self->imod); - self->imod = NULL; - self->imod_size = 0; - free(self->igen); - self->igen = NULL; - self->igen_size = 0; - - free(self->shdr); - self->shdr = NULL; - self->shdr_size = 0; -} - - -#define FOURCC(a,b,c,d) ((a) | ((b)<<8) | ((c)<<16) | ((d)<<24)) -#define FOURCCFMT "%c%c%c%c" -#define FOURCCARGS(x) (char)((x)&0xff), (char)(((x)>>8)&0xff), (char)(((x)>>16)&0xff), (char)(((x)>>24)&0xff) -typedef struct RiffHdr { - ALuint mCode; - ALuint mSize; -} RiffHdr; -static void RiffHdr_read(RiffHdr *self, Reader *stream) -{ - self->mCode = read_le32(stream); - self->mSize = read_le32(stream); -} - - -typedef struct GenModList { - VECTOR(Generator) gens; - VECTOR(Modulator) mods; -} GenModList; - -static void GenModList_Construct(GenModList *self) -{ - VECTOR_INIT(self->gens); - VECTOR_INIT(self->mods); -} - -static void GenModList_Destruct(GenModList *self) -{ - VECTOR_DEINIT(self->mods); - VECTOR_DEINIT(self->gens); -} - -static GenModList GenModList_clone(const GenModList *self) -{ - GenModList ret; - - GenModList_Construct(&ret); - - VECTOR_INSERT(ret.gens, VECTOR_ITER_END(ret.gens), - VECTOR_ITER_BEGIN(self->gens), VECTOR_ITER_END(self->gens) - ); - VECTOR_INSERT(ret.mods, VECTOR_ITER_END(ret.mods), - VECTOR_ITER_BEGIN(self->mods), VECTOR_ITER_END(self->mods) - ); - - return ret; -} - -static void GenModList_insertGen(GenModList *self, const Generator *gen, ALboolean ispreset) -{ - Generator *i = VECTOR_ITER_BEGIN(self->gens); - Generator *end = VECTOR_ITER_END(self->gens); - for(;i != end;i++) - { - if(i->mGenerator == gen->mGenerator) - { - i->mAmount = gen->mAmount; - return; - } - } - - if(ispreset && - (gen->mGenerator == 0 || gen->mGenerator == 1 || gen->mGenerator == 2 || - gen->mGenerator == 3 || gen->mGenerator == 4 || gen->mGenerator == 12 || - gen->mGenerator == 45 || gen->mGenerator == 46 || gen->mGenerator == 47 || - gen->mGenerator == 50 || gen->mGenerator == 54 || gen->mGenerator == 57 || - gen->mGenerator == 58)) - return; - - if(VECTOR_PUSH_BACK(self->gens, *gen) == AL_FALSE) - { - ERR("Failed to insert generator (from %d elements)\n", VECTOR_SIZE(self->gens)); - return; - } -} -static void GenModList_accumGen(GenModList *self, const Generator *gen) -{ - Generator *i = VECTOR_ITER_BEGIN(self->gens); - Generator *end = VECTOR_ITER_END(self->gens); - for(;i != end;i++) - { - if(i->mGenerator == gen->mGenerator) - { - if(gen->mGenerator == 43 || gen->mGenerator == 44) - { - /* Range generators accumulate by taking the intersection of - * the two ranges. - */ - ALushort low = maxu(i->mAmount&0x00ff, gen->mAmount&0x00ff); - ALushort high = minu(i->mAmount&0xff00, gen->mAmount&0xff00); - i->mAmount = low | high; - } - else - i->mAmount += gen->mAmount; - return; - } - } - - if(VECTOR_PUSH_BACK(self->gens, *gen) == AL_FALSE) - { - ERR("Failed to insert generator (from %d elements)\n", VECTOR_SIZE(self->gens)); - return; - } - if(gen->mGenerator < 60) - VECTOR_BACK(self->gens).mAmount += DefaultGenValue[gen->mGenerator]; -} - -static void GenModList_insertMod(GenModList *self, const Modulator *mod) -{ - Modulator *i = VECTOR_ITER_BEGIN(self->mods); - Modulator *end = VECTOR_ITER_END(self->mods); - for(;i != end;i++) - { - if(i->mDstOp == mod->mDstOp && i->mSrcOp == mod->mSrcOp && - i->mAmtSrcOp == mod->mAmtSrcOp && i->mTransOp == mod->mTransOp) - { - i->mAmount = mod->mAmount; - return; - } - } - - if(VECTOR_PUSH_BACK(self->mods, *mod) == AL_FALSE) - { - ERR("Failed to insert modulator (from %d elements)\n", VECTOR_SIZE(self->mods)); - return; - } -} -static void GenModList_accumMod(GenModList *self, const Modulator *mod) -{ - Modulator *i = VECTOR_ITER_BEGIN(self->mods); - Modulator *end = VECTOR_ITER_END(self->mods); - for(;i != end;i++) - { - if(i->mDstOp == mod->mDstOp && i->mSrcOp == mod->mSrcOp && - i->mAmtSrcOp == mod->mAmtSrcOp && i->mTransOp == mod->mTransOp) - { - i->mAmount += mod->mAmount; - return; - } - } - - if(VECTOR_PUSH_BACK(self->mods, *mod) == AL_FALSE) - { - ERR("Failed to insert modulator (from %d elements)\n", VECTOR_SIZE(self->mods)); - return; - } - - if(mod->mSrcOp == 0x0502 && mod->mDstOp == 48 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0) - VECTOR_BACK(self->mods).mAmount += 960; - else if(mod->mSrcOp == 0x0102 && mod->mDstOp == 8 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0) - VECTOR_BACK(self->mods).mAmount += -2400; - else if(mod->mSrcOp == 0x000D && mod->mDstOp == 6 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0) - VECTOR_BACK(self->mods).mAmount += 50; - else if(mod->mSrcOp == 0x0081 && mod->mDstOp == 6 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0) - VECTOR_BACK(self->mods).mAmount += 50; - else if(mod->mSrcOp == 0x0582 && mod->mDstOp == 48 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0) - VECTOR_BACK(self->mods).mAmount += 960; - else if(mod->mSrcOp == 0x028A && mod->mDstOp == 17 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0) - VECTOR_BACK(self->mods).mAmount += 1000; - else if(mod->mSrcOp == 0x058B && mod->mDstOp == 48 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0) - VECTOR_BACK(self->mods).mAmount += 960; - else if(mod->mSrcOp == 0x00DB && mod->mDstOp == 16 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0) - VECTOR_BACK(self->mods).mAmount += 200; - else if(mod->mSrcOp == 0x00DD && mod->mDstOp == 15 && mod->mAmtSrcOp == 0 && mod->mTransOp == 0) - VECTOR_BACK(self->mods).mAmount += 200; - /*else if(mod->mSrcOp == 0x020E && mod->mDstOp == ?initialpitch? && mod->mAmtSrcOp == 0x0010 && mod->mTransOp == 0) - VECTOR_BACK(self->mods).mAmount += 12700;*/ -} - - -#define ERROR_GOTO(lbl_, ...) do { \ - ERR(__VA_ARGS__); \ - goto lbl_; \ -} while(0) - -static ALboolean ensureFontSanity(const Soundfont *sfont) -{ - ALsizei i; - - for(i = 0;i < sfont->phdr_size;i++) - { - if(sfont->phdr[i].mZoneIdx >= sfont->pbag_size) - { - WARN("Preset %d has invalid zone index %d (max: %d)\n", i, - sfont->phdr[i].mZoneIdx, sfont->pbag_size); - return AL_FALSE; - } - if(i+1 < sfont->phdr_size && sfont->phdr[i+1].mZoneIdx < sfont->phdr[i].mZoneIdx) - { - WARN("Preset %d has invalid zone index (%d does not follow %d)\n", i+1, - sfont->phdr[i+1].mZoneIdx, sfont->phdr[i].mZoneIdx); - return AL_FALSE; - } - } - - for(i = 0;i < sfont->pbag_size;i++) - { - if(sfont->pbag[i].mGenIdx >= sfont->pgen_size) - { - WARN("Preset zone %d has invalid generator index %d (max: %d)\n", i, - sfont->pbag[i].mGenIdx, sfont->pgen_size); - return AL_FALSE; - } - if(i+1 < sfont->pbag_size && sfont->pbag[i+1].mGenIdx < sfont->pbag[i].mGenIdx) - { - WARN("Preset zone %d has invalid generator index (%d does not follow %d)\n", i+1, - sfont->pbag[i+1].mGenIdx, sfont->pbag[i].mGenIdx); - return AL_FALSE; - } - if(sfont->pbag[i].mModIdx >= sfont->pmod_size) - { - WARN("Preset zone %d has invalid modulator index %d (max: %d)\n", i, - sfont->pbag[i].mModIdx, sfont->pmod_size); - return AL_FALSE; - } - if(i+1 < sfont->pbag_size && sfont->pbag[i+1].mModIdx < sfont->pbag[i].mModIdx) - { - WARN("Preset zone %d has invalid modulator index (%d does not follow %d)\n", i+1, - sfont->pbag[i+1].mModIdx, sfont->pbag[i].mModIdx); - return AL_FALSE; - } - } - - - for(i = 0;i < sfont->inst_size;i++) - { - if(sfont->inst[i].mZoneIdx >= sfont->ibag_size) - { - WARN("Instrument %d has invalid zone index %d (max: %d)\n", i, - sfont->inst[i].mZoneIdx, sfont->ibag_size); - return AL_FALSE; - } - if(i+1 < sfont->inst_size && sfont->inst[i+1].mZoneIdx < sfont->inst[i].mZoneIdx) - { - WARN("Instrument %d has invalid zone index (%d does not follow %d)\n", i+1, - sfont->inst[i+1].mZoneIdx, sfont->inst[i].mZoneIdx); - return AL_FALSE; - } - } - - for(i = 0;i < sfont->ibag_size;i++) - { - if(sfont->ibag[i].mGenIdx >= sfont->igen_size) - { - WARN("Instrument zone %d has invalid generator index %d (max: %d)\n", i, - sfont->ibag[i].mGenIdx, sfont->igen_size); - return AL_FALSE; - } - if(i+1 < sfont->ibag_size && sfont->ibag[i+1].mGenIdx < sfont->ibag[i].mGenIdx) - { - WARN("Instrument zone %d has invalid generator index (%d does not follow %d)\n", i+1, - sfont->ibag[i+1].mGenIdx, sfont->ibag[i].mGenIdx); - return AL_FALSE; - } - if(sfont->ibag[i].mModIdx >= sfont->imod_size) - { - WARN("Instrument zone %d has invalid modulator index %d (max: %d)\n", i, - sfont->ibag[i].mModIdx, sfont->imod_size); - return AL_FALSE; - } - if(i+1 < sfont->ibag_size && sfont->ibag[i+1].mModIdx < sfont->ibag[i].mModIdx) - { - WARN("Instrument zone %d has invalid modulator index (%d does not follow %d)\n", i+1, - sfont->ibag[i+1].mModIdx, sfont->ibag[i].mModIdx); - return AL_FALSE; - } - } - - - for(i = 0;i < sfont->shdr_size-1;i++) - { - if((sfont->shdr[i].mSampleType&0x8000) && sfont->irom == NULL) - { - WARN("Sample header %d has ROM sample type without an irom sub-chunk\n", i); - return AL_FALSE; - } - } - - - return AL_TRUE; -} - -static ALboolean checkZone(const GenModList *zone, const PresetHeader *preset, const InstrumentHeader *inst, const SampleHeader *samp) -{ - Generator *gen = VECTOR_ITER_BEGIN(zone->gens); - Generator *gen_end = VECTOR_ITER_END(zone->gens); - for(;gen != gen_end;gen++) - { - if(gen->mGenerator == 43 || gen->mGenerator == 44) - { - int high = gen->mAmount>>8; - int low = gen->mAmount&0xff; - - if(!(low >= 0 && high <= 127 && high >= low)) - { - TRACE("Preset \"%s\", inst \"%s\", sample \"%s\": invalid %s range %d...%d\n", - preset->mName, inst->mName, samp->mName, - (gen->mGenerator == 43) ? "key" : - (gen->mGenerator == 44) ? "velocity" : "(unknown)", - low, high); - return AL_FALSE; - } - } - } - - return AL_TRUE; -} - -static ALenum getModSrcInput(int input) -{ - if(input == 0) return AL_ONE_SOFT; - if(input == 2) return AL_NOTEON_VELOCITY_SOFT; - if(input == 3) return AL_NOTEON_KEY_SOFT; - if(input == 10) return AL_KEYPRESSURE_SOFT; - if(input == 13) return AL_CHANNELPRESSURE_SOFT; - if(input == 14) return AL_PITCHBEND_SOFT; - if(input == 16) return AL_PITCHBEND_SENSITIVITY_SOFT; - if((input&0x80)) - { - if(IsValidCtrlInput(input^0x80)) - return input^0x80; - } - ERR("Unhandled modulator source input: 0x%02x\n", input); - return AL_INVALID; -} - -static ALenum getModSrcType(int type) -{ - if(type == 0x0000) return AL_UNORM_SOFT; - if(type == 0x0100) return AL_UNORM_REV_SOFT; - if(type == 0x0200) return AL_SNORM_SOFT; - if(type == 0x0300) return AL_SNORM_REV_SOFT; - ERR("Unhandled modulator source type: 0x%04x\n", type); - return AL_INVALID; -} - -static ALenum getModSrcForm(int form) -{ - if(form == 0x0000) return AL_LINEAR_SOFT; - if(form == 0x0400) return AL_CONCAVE_SOFT; - if(form == 0x0800) return AL_CONVEX_SOFT; - if(form == 0x0C00) return AL_SWITCH_SOFT; - ERR("Unhandled modulator source form: 0x%04x\n", form); - return AL_INVALID; -} - -static ALenum getModTransOp(int op) -{ - if(op == 0) return AL_LINEAR_SOFT; - if(op == 2) return AL_ABSOLUTE_SOFT; - ERR("Unhandled modulator transform op: 0x%04x\n", op); - return AL_INVALID; -} - -static ALenum getLoopMode(int mode) -{ - if(mode == 0) return AL_NONE; - if(mode == 1) return AL_LOOP_CONTINUOUS_SOFT; - if(mode == 3) return AL_LOOP_UNTIL_RELEASE_SOFT; - ERR("Unhandled loop mode: %d\n", mode); - return AL_NONE; -} - -static ALenum getSampleType(int type) -{ - if(type == 1) return AL_MONO_SOFT; - if(type == 2) return AL_RIGHT_SOFT; - if(type == 4) return AL_LEFT_SOFT; - if(type == 8) - { - WARN("Sample type \"linked\" ignored; pretending mono\n"); - return AL_MONO_SOFT; - } - ERR("Unhandled sample type: 0x%04x\n", type); - return AL_MONO_SOFT; -} - -static void fillZone(ALfontsound *sound, ALCcontext *context, const GenModList *zone) -{ - static const ALenum Gen2Param[60] = { - 0, /* 0 - startAddrOffset */ - 0, /* 1 - endAddrOffset */ - 0, /* 2 - startloopAddrOffset */ - 0, /* 3 - endloopAddrOffset */ - 0, /* 4 - startAddrCoarseOffset */ - AL_MOD_LFO_TO_PITCH_SOFT, /* 5 - modLfoToPitch */ - AL_VIBRATO_LFO_TO_PITCH_SOFT, /* 6 - vibLfoToPitch */ - AL_MOD_ENV_TO_PITCH_SOFT, /* 7 - modEnvToPitch */ - AL_FILTER_CUTOFF_SOFT, /* 8 - initialFilterFc */ - AL_FILTER_RESONANCE_SOFT, /* 9 - initialFilterQ */ - AL_MOD_LFO_TO_FILTER_CUTOFF_SOFT, /* 10 - modLfoToFilterFc */ - AL_MOD_ENV_TO_FILTER_CUTOFF_SOFT, /* 11 - modEnvToFilterFc */ - 0, /* 12 - endAddrCoarseOffset */ - AL_MOD_LFO_TO_VOLUME_SOFT, /* 13 - modLfoToVolume */ - 0, /* 14 - */ - AL_CHORUS_SEND_SOFT, /* 15 - chorusEffectsSend */ - AL_REVERB_SEND_SOFT, /* 16 - reverbEffectsSend */ - AL_PAN_SOFT, /* 17 - pan */ - 0, /* 18 - */ - 0, /* 19 - */ - 0, /* 20 - */ - AL_MOD_LFO_DELAY_SOFT, /* 21 - delayModLFO */ - AL_MOD_LFO_FREQUENCY_SOFT, /* 22 - freqModLFO */ - AL_VIBRATO_LFO_DELAY_SOFT, /* 23 - delayVibLFO */ - AL_VIBRATO_LFO_FREQUENCY_SOFT, /* 24 - freqVibLFO */ - AL_MOD_ENV_DELAYTIME_SOFT, /* 25 - delayModEnv */ - AL_MOD_ENV_ATTACKTIME_SOFT, /* 26 - attackModEnv */ - AL_MOD_ENV_HOLDTIME_SOFT, /* 27 - holdModEnv */ - AL_MOD_ENV_DECAYTIME_SOFT, /* 28 - decayModEnv */ - AL_MOD_ENV_SUSTAINVOLUME_SOFT, /* 29 - sustainModEnv */ - AL_MOD_ENV_RELEASETIME_SOFT, /* 30 - releaseModEnv */ - AL_MOD_ENV_KEY_TO_HOLDTIME_SOFT, /* 31 - keynumToModEnvHold */ - AL_MOD_ENV_KEY_TO_DECAYTIME_SOFT, /* 32 - keynumToModEnvDecay */ - AL_VOLUME_ENV_DELAYTIME_SOFT, /* 33 - delayVolEnv */ - AL_VOLUME_ENV_ATTACKTIME_SOFT, /* 34 - attackVolEnv */ - AL_VOLUME_ENV_HOLDTIME_SOFT, /* 35 - holdVolEnv */ - AL_VOLUME_ENV_DECAYTIME_SOFT, /* 36 - decayVolEnv */ - AL_VOLUME_ENV_SUSTAINVOLUME_SOFT, /* 37 - sustainVolEnv */ - AL_VOLUME_ENV_RELEASETIME_SOFT, /* 38 - releaseVolEnv */ - AL_VOLUME_ENV_KEY_TO_HOLDTIME_SOFT, /* 39 - keynumToVolEnvHold */ - AL_VOLUME_ENV_KEY_TO_DECAYTIME_SOFT, /* 40 - keynumToVolEnvDecay */ - 0, /* 41 - */ - 0, /* 42 - */ - AL_KEY_RANGE_SOFT, /* 43 - keyRange */ - AL_VELOCITY_RANGE_SOFT, /* 44 - velRange */ - 0, /* 45 - startloopAddrCoarseOffset */ - 0, /* 46 - keynum */ - 0, /* 47 - velocity */ - AL_ATTENUATION_SOFT, /* 48 - initialAttenuation */ - 0, /* 49 - */ - 0, /* 50 - endloopAddrCoarseOffset */ - AL_TUNING_COARSE_SOFT, /* 51 - corseTune */ - AL_TUNING_FINE_SOFT, /* 52 - fineTune */ - 0, /* 53 - */ - AL_LOOP_MODE_SOFT, /* 54 - sampleModes */ - 0, /* 55 - */ - AL_TUNING_SCALE_SOFT, /* 56 - scaleTuning */ - AL_EXCLUSIVE_CLASS_SOFT, /* 57 - exclusiveClass */ - AL_BASE_KEY_SOFT, /* 58 - overridingRootKey */ - 0, /* 59 - */ - }; - const Generator *gen, *gen_end; - const Modulator *mod, *mod_end; - - mod = VECTOR_ITER_BEGIN(zone->mods); - mod_end = VECTOR_ITER_END(zone->mods); - for(;mod != mod_end;mod++) - { - ALenum src0in = getModSrcInput(mod->mSrcOp&0xFF); - ALenum src0type = getModSrcType(mod->mSrcOp&0x0300); - ALenum src0form = getModSrcForm(mod->mSrcOp&0xFC00); - ALenum src1in = getModSrcInput(mod->mAmtSrcOp&0xFF); - ALenum src1type = getModSrcType(mod->mAmtSrcOp&0x0300); - ALenum src1form = getModSrcForm(mod->mAmtSrcOp&0xFC00); - ALenum trans = getModTransOp(mod->mTransOp); - ALenum dst = (mod->mDstOp < 60) ? Gen2Param[mod->mDstOp] : 0; - if(!dst || dst == AL_KEY_RANGE_SOFT || dst == AL_VELOCITY_RANGE_SOFT || - dst == AL_LOOP_MODE_SOFT || dst == AL_EXCLUSIVE_CLASS_SOFT || - dst == AL_BASE_KEY_SOFT) - ERR("Unhandled modulator destination: %d\n", mod->mDstOp); - else if(src0in != AL_INVALID && src0form != AL_INVALID && src0type != AL_INVALID && - src1in != AL_INVALID && src1form != AL_INVALID && src0type != AL_INVALID && - trans != AL_INVALID) - { - ALsizei idx = (ALsizei)(mod - VECTOR_ITER_BEGIN(zone->mods)); - ALfontsound_setModStagei(sound, context, idx, AL_SOURCE0_INPUT_SOFT, src0in); - ALfontsound_setModStagei(sound, context, idx, AL_SOURCE0_TYPE_SOFT, src0type); - ALfontsound_setModStagei(sound, context, idx, AL_SOURCE0_FORM_SOFT, src0form); - ALfontsound_setModStagei(sound, context, idx, AL_SOURCE1_INPUT_SOFT, src1in); - ALfontsound_setModStagei(sound, context, idx, AL_SOURCE1_TYPE_SOFT, src1type); - ALfontsound_setModStagei(sound, context, idx, AL_SOURCE1_FORM_SOFT, src1form); - ALfontsound_setModStagei(sound, context, idx, AL_AMOUNT_SOFT, mod->mAmount); - ALfontsound_setModStagei(sound, context, idx, AL_TRANSFORM_OP_SOFT, trans); - ALfontsound_setModStagei(sound, context, idx, AL_DESTINATION_SOFT, dst); - } - } - - gen = VECTOR_ITER_BEGIN(zone->gens); - gen_end = VECTOR_ITER_END(zone->gens); - for(;gen != gen_end;gen++) - { - ALint value = (ALshort)gen->mAmount; - if(gen->mGenerator == 0) - sound->Start += value; - else if(gen->mGenerator == 1) - sound->End += value; - else if(gen->mGenerator == 2) - sound->LoopStart += value; - else if(gen->mGenerator == 3) - sound->LoopEnd += value; - else if(gen->mGenerator == 4) - sound->Start += value<<15; - else if(gen->mGenerator == 12) - sound->End += value<<15; - else if(gen->mGenerator == 45) - sound->LoopStart += value<<15; - else if(gen->mGenerator == 50) - sound->LoopEnd += value<<15; - else if(gen->mGenerator == 43) - { - sound->MinKey = mini((value&0xff), 127); - sound->MaxKey = mini(((value>>8)&0xff), 127); - } - else if(gen->mGenerator == 44) - { - sound->MinVelocity = mini((value&0xff), 127); - sound->MaxVelocity = mini(((value>>8)&0xff), 127); - } - else - { - ALenum param = 0; - if(gen->mGenerator < 60) - param = Gen2Param[gen->mGenerator]; - if(param) - { - if(param == AL_BASE_KEY_SOFT) - { - if(!(value >= 0 && value <= 127)) - { - if(value != -1) - WARN("Invalid overridingRootKey generator value %d\n", value); - continue; - } - } - if(param == AL_FILTER_RESONANCE_SOFT || param == AL_ATTENUATION_SOFT) - value = maxi(0, value); - else if(param == AL_CHORUS_SEND_SOFT || param == AL_REVERB_SEND_SOFT) - value = clampi(value, 0, 1000); - else if(param == AL_LOOP_MODE_SOFT) - value = getLoopMode(value); - ALfontsound_setPropi(sound, context, param, value); - } - else - { - static ALuint warned[65536/32]; - if(!(warned[gen->mGenerator/32]&(1<<(gen->mGenerator&31)))) - { - warned[gen->mGenerator/32] |= 1<<(gen->mGenerator&31); - ERR("Unhandled generator %d\n", gen->mGenerator); - } - } - } - } -} - -static void processInstrument(ALfontsound ***sounds, ALsizei *sounds_size, ALCcontext *context, ALbuffer *buffer, InstrumentHeader *inst, const PresetHeader *preset, const Soundfont *sfont, const GenModList *pzone) -{ - const Generator *gen, *gen_end; - const Modulator *mod, *mod_end; - const Zone *zone, *zone_end; - GenModList gzone; - ALvoid *temp; - - if((inst+1)->mZoneIdx == inst->mZoneIdx) - ERR("Instrument with no zones!"); - - GenModList_Construct(&gzone); - zone = sfont->ibag + inst->mZoneIdx; - zone_end = sfont->ibag + (inst+1)->mZoneIdx; - if(zone_end-zone > 1) - { - gen = sfont->igen + zone->mGenIdx; - gen_end = sfont->igen + (zone+1)->mGenIdx; - - // If no generators, or last generator is not a sample, this is a global zone - for(;gen != gen_end;gen++) - { - if(gen->mGenerator == 53) - break; - } - - if(gen == gen_end) - { - gen = sfont->igen + zone->mGenIdx; - gen_end = sfont->igen + (zone+1)->mGenIdx; - for(;gen != gen_end;gen++) - GenModList_insertGen(&gzone, gen, AL_FALSE); - - mod = sfont->imod + zone->mModIdx; - mod_end = sfont->imod + (zone+1)->mModIdx; - for(;mod != mod_end;mod++) - GenModList_insertMod(&gzone, mod); - - zone++; - } - } - - temp = realloc(*sounds, (zone_end-zone + *sounds_size)*sizeof((*sounds)[0])); - if(!temp) - { - ERR("Failed reallocating fontsound storage to %d elements (from %d)\n", - (ALsizei)(zone_end-zone) + *sounds_size, *sounds_size); - return; - } - *sounds = temp; - for(;zone != zone_end;zone++) - { - GenModList lzone = GenModList_clone(&gzone); - mod = sfont->imod + zone->mModIdx; - mod_end = sfont->imod + (zone+1)->mModIdx; - for(;mod != mod_end;mod++) - GenModList_insertMod(&lzone, mod); - - gen = sfont->igen + zone->mGenIdx; - gen_end = sfont->igen + (zone+1)->mGenIdx; - for(;gen != gen_end;gen++) - { - if(gen->mGenerator == 53) - { - const SampleHeader *samp; - ALfontsound *sound; - - if(gen->mAmount >= sfont->shdr_size-1) - { - ERR("Generator %ld has invalid sample ID (%d of %d)\n", - (long)(gen-sfont->igen), gen->mAmount, sfont->shdr_size-1); - break; - } - samp = &sfont->shdr[gen->mAmount]; - - gen = VECTOR_ITER_BEGIN(pzone->gens); - gen_end = VECTOR_ITER_END(pzone->gens); - for(;gen != gen_end;gen++) - GenModList_accumGen(&lzone, gen); - - mod = VECTOR_ITER_BEGIN(pzone->mods); - mod_end = VECTOR_ITER_END(pzone->mods); - for(;mod != mod_end;mod++) - GenModList_accumMod(&lzone, mod); - - if(!checkZone(&lzone, preset, inst, samp)) - break; - /* Ignore ROM samples for now. */ - if((samp->mSampleType&0x8000)) - break; - - sound = NewFontsound(context); - (*sounds)[(*sounds_size)++] = sound; - ALfontsound_setPropi(sound, context, AL_BUFFER, buffer->id); - ALfontsound_setPropi(sound, context, AL_SAMPLE_START_SOFT, samp->mStart); - ALfontsound_setPropi(sound, context, AL_SAMPLE_END_SOFT, samp->mEnd); - ALfontsound_setPropi(sound, context, AL_SAMPLE_LOOP_START_SOFT, samp->mStartloop); - ALfontsound_setPropi(sound, context, AL_SAMPLE_LOOP_END_SOFT, samp->mEndloop); - ALfontsound_setPropi(sound, context, AL_SAMPLE_RATE_SOFT, samp->mSampleRate); - ALfontsound_setPropi(sound, context, AL_BASE_KEY_SOFT, (samp->mOriginalKey <= 127) ? samp->mOriginalKey : 60); - ALfontsound_setPropi(sound, context, AL_KEY_CORRECTION_SOFT, samp->mCorrection); - ALfontsound_setPropi(sound, context, AL_SAMPLE_TYPE_SOFT, getSampleType(samp->mSampleType&0x7fff)); - fillZone(sound, context, &lzone); - - break; - } - GenModList_insertGen(&lzone, gen, AL_FALSE); - } - - GenModList_Destruct(&lzone); - } - - GenModList_Destruct(&gzone); -} - -static size_t printStringChunk(Reader *stream, const RiffHdr *chnk, const char *title) -{ - size_t len = 0; - if(chnk->mSize == 0 || (chnk->mSize&1)) - ERR("Invalid "FOURCCFMT" size: %d\n", FOURCCARGS(chnk->mCode), chnk->mSize); - else - { - char *str = calloc(1, chnk->mSize+1); - len = Reader_read(stream, str, chnk->mSize); - - TRACE("%s: %s\n", title, str); - free(str); - } - return len; -} - -ALboolean loadSf2(Reader *stream, ALsoundfont *soundfont, ALCcontext *context) -{ - ALsfpreset **presets = NULL; - ALsizei presets_size = 0; - ALbuffer *buffer = NULL; - ALuint ltype; - Soundfont sfont; - RiffHdr riff; - RiffHdr list; - ALsizei i; - - Soundfont_Construct(&sfont); - - RiffHdr_read(&riff, stream); - if(riff.mCode != FOURCC('R','I','F','F')) - ERROR_GOTO(error, "Invalid Format, expected RIFF got '"FOURCCFMT"'\n", FOURCCARGS(riff.mCode)); - if((ltype=read_le32(stream)) != FOURCC('s','f','b','k')) - ERROR_GOTO(error, "Invalid Format, expected sfbk got '"FOURCCFMT"'\n", FOURCCARGS(ltype)); - - if(READERR(stream) != 0) - ERROR_GOTO(error, "Error reading file header\n"); - - RiffHdr_read(&list, stream); - if(list.mCode != FOURCC('L','I','S','T')) - ERROR_GOTO(error, "Invalid Format, expected LIST (INFO) got '"FOURCCFMT"'\n", FOURCCARGS(list.mCode)); - if((ltype=read_le32(stream)) != FOURCC('I','N','F','O')) - ERROR_GOTO(error, "Invalid Format, expected INFO got '"FOURCCFMT"'\n", FOURCCARGS(ltype)); - list.mSize -= 4; - while(list.mSize > 0 && !READERR(stream)) - { - RiffHdr chnk; - - if(list.mSize < 8) - { - WARN("Unexpected end of INFO list (%u extra bytes)\n", list.mSize); - skip(stream, list.mSize); - list.mSize = 0; - break; - } - - RiffHdr_read(&chnk, stream); - list.mSize -= 8; - if(list.mSize < chnk.mSize) - { - WARN("INFO sub-chunk '"FOURCCFMT"' has %u bytes, but only %u bytes remain\n", - FOURCCARGS(chnk.mCode), chnk.mSize, list.mSize); - skip(stream, list.mSize); - list.mSize = 0; - break; - } - list.mSize -= chnk.mSize; - - if(chnk.mCode == FOURCC('i','f','i','l')) - { - if(chnk.mSize != 4) - ERR("Invalid ifil chunk size: %d\n", chnk.mSize); - else - { - ALushort major = read_le16(stream); - ALushort minor = read_le16(stream); - chnk.mSize -= 4; - - if(major != 2) - ERROR_GOTO(error, "Unsupported SF2 format version: %d.%02d\n", major, minor); - TRACE("SF2 format version: %d.%02d\n", major, minor); - - sfont.ifil = (major<<16) | minor; - } - } - else if(chnk.mCode == FOURCC('i','r','o','m')) - { - if(chnk.mSize == 0 || (chnk.mSize&1)) - ERR("Invalid irom size: %d\n", chnk.mSize); - else - { - free(sfont.irom); - sfont.irom = calloc(1, chnk.mSize+1); - chnk.mSize -= Reader_read(stream, sfont.irom, chnk.mSize); - - TRACE("SF2 ROM ID: %s\n", sfont.irom); - } - } - else - { - static const struct { - ALuint code; - char title[16]; - } listinfos[] = { - { FOURCC('i','s','n','g'), "Engine ID" }, - { FOURCC('I','N','A','M'), "Name" }, - { FOURCC('I','C','R','D'), "Creation Date" }, - { FOURCC('I','E','N','G'), "Creator" }, - { FOURCC('I','P','R','D'), "Product ID" }, - { FOURCC('I','C','O','P'), "Copyright" }, - { FOURCC('I','C','M','T'), "Comment" }, - { FOURCC('I','S','F','T'), "Created With" }, - { 0, "" }, - }; - - for(i = 0;listinfos[i].code;i++) - { - if(listinfos[i].code == chnk.mCode) - { - chnk.mSize -= printStringChunk(stream, &chnk, listinfos[i].title); - break; - } - } - if(!listinfos[i].code) - TRACE("Skipping INFO sub-chunk '"FOURCCFMT"' (%u bytes)\n", FOURCCARGS(chnk.mCode), chnk.mSize); - } - skip(stream, chnk.mSize); - } - - if(READERR(stream) != 0) - ERROR_GOTO(error, "Error reading INFO chunk\n"); - if(sfont.ifil == 0) - ERROR_GOTO(error, "Missing ifil sub-chunk\n"); - - RiffHdr_read(&list, stream); - if(list.mCode != FOURCC('L','I','S','T')) - ERROR_GOTO(error, "Invalid Format, expected LIST (sdta) got '"FOURCCFMT"'\n", FOURCCARGS(list.mCode)); - if((ltype=read_le32(stream)) != FOURCC('s','d','t','a')) - ERROR_GOTO(error, "Invalid Format, expected sdta got '"FOURCCFMT"'\n", FOURCCARGS(ltype)); - list.mSize -= 4; - { - ALbyte *ptr; - RiffHdr smpl; - ALenum err; - - RiffHdr_read(&smpl, stream); - if(smpl.mCode != FOURCC('s','m','p','l')) - ERROR_GOTO(error, "Invalid Format, expected smpl got '"FOURCCFMT"'\n", FOURCCARGS(smpl.mCode)); - list.mSize -= 8; - - if(smpl.mSize > list.mSize) - ERROR_GOTO(error, "Invalid Format, sample chunk size mismatch\n"); - list.mSize -= smpl.mSize; - - buffer = NewBuffer(context); - if(!buffer) - SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, error); - /* Sample rate is unimportant, the individual fontsounds will specify it. */ - if((err=LoadData(buffer, 22050, AL_MONO16_SOFT, smpl.mSize/2, UserFmtMono, UserFmtShort, NULL, 1, AL_FALSE)) != AL_NO_ERROR) - SET_ERROR_AND_GOTO(context, err, error); - - ptr = buffer->data; - if(IS_LITTLE_ENDIAN) - smpl.mSize -= Reader_read(stream, ptr, smpl.mSize); - else - { - ALuint total = 0; - while(total < smpl.mSize && !READERR(stream)) - { - ALbyte buf[4096]; - ALuint todo = minu(smpl.mSize-total, sizeof(buf)); - ALuint i; - - smpl.mSize -= Reader_read(stream, buf, todo); - for(i = 0;i < todo;i++) - ptr[total+i] = buf[i^1]; - - total += todo; - } - } - - skip(stream, list.mSize); - } - - if(READERR(stream) != 0) - ERROR_GOTO(error, "Error reading sdta chunk\n"); - - RiffHdr_read(&list, stream); - if(list.mCode != FOURCC('L','I','S','T')) - ERROR_GOTO(error, "Invalid Format, expected LIST (pdta) got '"FOURCCFMT"'\n", FOURCCARGS(list.mCode)); - if((ltype=read_le32(stream)) != FOURCC('p','d','t','a')) - ERROR_GOTO(error, "Invalid Format, expected pdta got '"FOURCCFMT"'\n", FOURCCARGS(ltype)); - - // - RiffHdr_read(&list, stream); - if(list.mCode != FOURCC('p','h','d','r')) - ERROR_GOTO(error, "Invalid Format, expected phdr got '"FOURCCFMT"'\n", FOURCCARGS(list.mCode)); - if((list.mSize%38) != 0 || list.mSize == 0) - ERROR_GOTO(error, "Invalid Format, bad phdr size: %u\n", list.mSize); - sfont.phdr_size = list.mSize/38; - sfont.phdr = calloc(sfont.phdr_size, sizeof(sfont.phdr[0])); - for(i = 0;i < sfont.phdr_size;i++) - PresetHeader_read(&sfont.phdr[i], stream); - - RiffHdr_read(&list, stream); - if(list.mCode != FOURCC('p','b','a','g')) - ERROR_GOTO(error, "Invalid Format, expected pbag got '"FOURCCFMT"'\n", FOURCCARGS(list.mCode)); - if((list.mSize%4) != 0 || list.mSize == 0) - ERROR_GOTO(error, "Invalid Format, bad pbag size: %u\n", list.mSize); - sfont.pbag_size = list.mSize/4; - sfont.pbag = calloc(sfont.pbag_size, sizeof(sfont.pbag[0])); - for(i = 0;i < sfont.pbag_size;i++) - Zone_read(&sfont.pbag[i], stream); - - RiffHdr_read(&list, stream); - if(list.mCode != FOURCC('p','m','o','d')) - ERROR_GOTO(error, "Invalid Format, expected pmod got '"FOURCCFMT"'\n", FOURCCARGS(list.mCode)); - if((list.mSize%10) != 0 || list.mSize == 0) - ERROR_GOTO(error, "Invalid Format, bad pmod size: %u\n", list.mSize); - sfont.pmod_size = list.mSize/10; - sfont.pmod = calloc(sfont.pmod_size, sizeof(sfont.pmod[0])); - for(i = 0;i < sfont.pmod_size;i++) - Modulator_read(&sfont.pmod[i], stream); - - RiffHdr_read(&list, stream); - if(list.mCode != FOURCC('p','g','e','n')) - ERROR_GOTO(error, "Invalid Format, expected pgen got '"FOURCCFMT"'\n", FOURCCARGS(list.mCode)); - if((list.mSize%4) != 0 || list.mSize == 0) - ERROR_GOTO(error, "Invalid Format, bad pgen size: %u\n", list.mSize); - sfont.pgen_size = list.mSize/4; - sfont.pgen = calloc(sfont.pgen_size, sizeof(sfont.pgen[0])); - for(i = 0;i < sfont.pgen_size;i++) - Generator_read(&sfont.pgen[i], stream); - - // - RiffHdr_read(&list, stream); - if(list.mCode != FOURCC('i','n','s','t')) - ERROR_GOTO(error, "Invalid Format, expected inst got '"FOURCCFMT"'\n", FOURCCARGS(list.mCode)); - if((list.mSize%22) != 0 || list.mSize == 0) - ERROR_GOTO(error, "Invalid Format, bad inst size: %u\n", list.mSize); - sfont.inst_size = list.mSize/22; - sfont.inst = calloc(sfont.inst_size, sizeof(sfont.inst[0])); - for(i = 0;i < sfont.inst_size;i++) - InstrumentHeader_read(&sfont.inst[i], stream); - - RiffHdr_read(&list, stream); - if(list.mCode != FOURCC('i','b','a','g')) - ERROR_GOTO(error, "Invalid Format, expected ibag got '"FOURCCFMT"'\n", FOURCCARGS(list.mCode)); - if((list.mSize%4) != 0 || list.mSize == 0) - ERROR_GOTO(error, "Invalid Format, bad ibag size: %u\n", list.mSize); - sfont.ibag_size = list.mSize/4; - sfont.ibag = calloc(sfont.ibag_size, sizeof(sfont.ibag[0])); - for(i = 0;i < sfont.ibag_size;i++) - Zone_read(&sfont.ibag[i], stream); - - RiffHdr_read(&list, stream); - if(list.mCode != FOURCC('i','m','o','d')) - ERROR_GOTO(error, "Invalid Format, expected imod got '"FOURCCFMT"'\n", FOURCCARGS(list.mCode)); - if((list.mSize%10) != 0 || list.mSize == 0) - ERROR_GOTO(error, "Invalid Format, bad imod size: %u\n", list.mSize); - sfont.imod_size = list.mSize/10; - sfont.imod = calloc(sfont.imod_size, sizeof(sfont.imod[0])); - for(i = 0;i < sfont.imod_size;i++) - Modulator_read(&sfont.imod[i], stream); - - RiffHdr_read(&list, stream); - if(list.mCode != FOURCC('i','g','e','n')) - ERROR_GOTO(error, "Invalid Format, expected igen got '"FOURCCFMT"'\n", FOURCCARGS(list.mCode)); - if((list.mSize%4) != 0 || list.mSize == 0) - ERROR_GOTO(error, "Invalid Format, bad igen size: %u\n", list.mSize); - sfont.igen_size = list.mSize/4; - sfont.igen = calloc(sfont.igen_size, sizeof(sfont.igen[0])); - for(i = 0;i < sfont.igen_size;i++) - Generator_read(&sfont.igen[i], stream); - - // - RiffHdr_read(&list, stream); - if(list.mCode != FOURCC('s','h','d','r')) - ERROR_GOTO(error, "Invalid Format, expected shdr got '"FOURCCFMT"'\n", FOURCCARGS(list.mCode)); - if((list.mSize%46) != 0 || list.mSize == 0) - ERROR_GOTO(error, "Invalid Format, bad shdr size: %u\n", list.mSize); - sfont.shdr_size = list.mSize/46; - sfont.shdr = calloc(sfont.shdr_size, sizeof(sfont.shdr[0])); - for(i = 0;i < sfont.shdr_size;i++) - SampleHeader_read(&sfont.shdr[i], stream); - - if(READERR(stream) != 0) - ERROR_GOTO(error, "Error reading pdta chunk\n"); - - if(!ensureFontSanity(&sfont)) - goto error; - - presets = calloc(1, (soundfont->NumPresets+sfont.phdr_size-1)*sizeof(presets[0])); - if(!presets) - ERROR_GOTO(error, "Error allocating presets\n"); - memcpy(presets, soundfont->Presets, soundfont->NumPresets*sizeof(presets[0])); - presets_size = soundfont->NumPresets; - - for(i = 0;i < sfont.phdr_size-1;i++) - { - const Generator *gen, *gen_end; - const Modulator *mod, *mod_end; - const Zone *zone, *zone_end; - ALfontsound **sounds = NULL; - ALsizei sounds_size = 0; - GenModList gzone; - - if(sfont.phdr[i+1].mZoneIdx == sfont.phdr[i].mZoneIdx) - continue; - - GenModList_Construct(&gzone); - zone = sfont.pbag + sfont.phdr[i].mZoneIdx; - zone_end = sfont.pbag + sfont.phdr[i+1].mZoneIdx; - if(zone_end-zone > 1) - { - gen = sfont.pgen + zone->mGenIdx; - gen_end = sfont.pgen + (zone+1)->mGenIdx; - - // If no generators, or last generator is not an instrument, this is a global zone - for(;gen != gen_end;gen++) - { - if(gen->mGenerator == 41) - break; - } - - if(gen == gen_end) - { - gen = sfont.pgen + zone->mGenIdx; - gen_end = sfont.pgen + (zone+1)->mGenIdx; - for(;gen != gen_end;gen++) - GenModList_insertGen(&gzone, gen, AL_TRUE); - - mod = sfont.pmod + zone->mModIdx; - mod_end = sfont.pmod + (zone+1)->mModIdx; - for(;mod != mod_end;mod++) - GenModList_insertMod(&gzone, mod); - - zone++; - } - } - - for(;zone != zone_end;zone++) - { - GenModList lzone = GenModList_clone(&gzone); - - mod = sfont.pmod + zone->mModIdx; - mod_end = sfont.pmod + (zone+1)->mModIdx; - for(;mod != mod_end;mod++) - GenModList_insertMod(&lzone, mod); - - gen = sfont.pgen + zone->mGenIdx; - gen_end = sfont.pgen + (zone+1)->mGenIdx; - for(;gen != gen_end;gen++) - { - if(gen->mGenerator == 41) - { - if(gen->mAmount >= sfont.inst_size-1) - ERR("Generator %ld has invalid instrument ID (%d of %d)\n", - (long)(gen-sfont.pgen), gen->mAmount, sfont.inst_size-1); - else - processInstrument( - &sounds, &sounds_size, context, buffer, &sfont.inst[gen->mAmount], - &sfont.phdr[i], &sfont, &lzone - ); - break; - } - GenModList_insertGen(&lzone, gen, AL_TRUE); - } - GenModList_Destruct(&lzone); - } - - if(sounds_size > 0) - { - ALsizei j; - - presets[presets_size] = NewPreset(context); - presets[presets_size]->Preset = sfont.phdr[i].mPreset; - presets[presets_size]->Bank = sfont.phdr[i].mBank; - - for(j = 0;j < sounds_size;j++) - IncrementRef(&sounds[j]->ref); - sounds = ExchangePtr((XchgPtr*)&presets[presets_size]->Sounds, sounds); - ExchangeInt(&presets[presets_size]->NumSounds, sounds_size); - presets_size++; - } - free(sounds); - - GenModList_Destruct(&gzone); - } - - for(i = soundfont->NumPresets;i < presets_size;i++) - IncrementRef(&presets[i]->ref); - presets = ExchangePtr((XchgPtr*)&soundfont->Presets, presets); - ExchangeInt(&soundfont->NumPresets, presets_size); - - free(presets); - - Soundfont_Destruct(&sfont); - /* If the buffer ends up unused, delete it. */ - if(ReadRef(&buffer->ref) == 0) - { - TRACE("Deleting unused buffer...\n"); - DeleteBuffer(context->Device, buffer); - } - - return AL_TRUE; - -error: - if(presets) - { - ALCdevice *device = context->Device; - for(i = soundfont->NumPresets;i < presets_size;i++) - DeletePreset(device, presets[i]); - free(presets); - } - - Soundfont_Destruct(&sfont); - if(buffer) - DeleteBuffer(context->Device, buffer); - - return AL_FALSE; -} diff --git a/love/src/jni/openal-soft-1.17.0/Alc/midi/soft.c b/love/src/jni/openal-soft-1.17.0/Alc/midi/soft.c deleted file mode 100644 index 6566b411..00000000 --- a/love/src/jni/openal-soft-1.17.0/Alc/midi/soft.c +++ /dev/null @@ -1,140 +0,0 @@ - -#include "config.h" - -#include -#include -#include -#include - -#include "alMain.h" -#include "alError.h" -#include "evtqueue.h" -#include "alu.h" - -#include "midi/base.h" - - -typedef struct SSynth { - DERIVE_FROM_TYPE(MidiSynth); -} SSynth; - -static void SSynth_mixSamples(SSynth *self, ALuint SamplesToDo, ALfloat (*restrict DryBuffer)[BUFFERSIZE]); - -static void SSynth_Construct(SSynth *self, ALCdevice *device); -static void SSynth_Destruct(SSynth *self); -static DECLARE_FORWARD3(SSynth, MidiSynth, ALenum, selectSoundfonts, ALCcontext*, ALsizei, const ALuint*) -static DECLARE_FORWARD1(SSynth, MidiSynth, void, setGain, ALfloat) -static DECLARE_FORWARD(SSynth, MidiSynth, void, stop) -static DECLARE_FORWARD(SSynth, MidiSynth, void, reset) -static void SSynth_update(SSynth *self, ALCdevice *device); -static void SSynth_process(SSynth *self, ALuint SamplesToDo, ALfloat (*restrict DryBuffer)[BUFFERSIZE]); -DECLARE_DEFAULT_ALLOCATORS(SSynth) -DEFINE_MIDISYNTH_VTABLE(SSynth); - - -static void SSynth_Construct(SSynth *self, ALCdevice *device) -{ - MidiSynth_Construct(STATIC_CAST(MidiSynth, self), device); - SET_VTABLE2(SSynth, MidiSynth, self); -} - -static void SSynth_Destruct(SSynth* UNUSED(self)) -{ -} - - -static void SSynth_update(SSynth* UNUSED(self), ALCdevice* UNUSED(device)) -{ -} - - -static void SSynth_mixSamples(SSynth* UNUSED(self), ALuint UNUSED(SamplesToDo), ALfloatBUFFERSIZE *restrict UNUSED(DryBuffer)) -{ -} - - -static void SSynth_processQueue(SSynth *self, ALuint64 time) -{ - EvtQueue *queue = &STATIC_CAST(MidiSynth, self)->EventQueue; - - while(queue->pos < queue->size && queue->events[queue->pos].time <= time) - queue->pos++; -} - -static void SSynth_process(SSynth *self, ALuint SamplesToDo, ALfloat (*restrict DryBuffer)[BUFFERSIZE]) -{ - MidiSynth *synth = STATIC_CAST(MidiSynth, self); - ALenum state = synth->State; - ALuint64 curtime; - ALuint total = 0; - - if(state == AL_INITIAL) - return; - if(state != AL_PLAYING) - { - SSynth_mixSamples(self, SamplesToDo, DryBuffer); - return; - } - - curtime = MidiSynth_getTime(synth); - while(total < SamplesToDo) - { - ALuint64 time, diff; - ALint tonext; - - time = MidiSynth_getNextEvtTime(synth); - diff = maxu64(time, curtime) - curtime; - if(diff >= MIDI_CLOCK_RES || time == UINT64_MAX) - { - /* If there's no pending event, or if it's more than 1 second - * away, do as many samples as we can. */ - tonext = INT_MAX; - } - else - { - /* Figure out how many samples until the next event. */ - tonext = (ALint)((diff*synth->SampleRate + (MIDI_CLOCK_RES-1)) / MIDI_CLOCK_RES); - tonext -= total; - /* For efficiency reasons, try to mix a multiple of 64 samples - * (~1ms @ 44.1khz) before processing the next event. */ - tonext = (tonext+63) & ~63; - } - - if(tonext > 0) - { - ALuint todo = mini(tonext, SamplesToDo-total); - SSynth_mixSamples(self, todo, DryBuffer); - total += todo; - tonext -= todo; - } - if(total < SamplesToDo && tonext <= 0) - SSynth_processQueue(self, time); - } - - synth->SamplesDone += SamplesToDo; - synth->ClockBase += (synth->SamplesDone/synth->SampleRate) * MIDI_CLOCK_RES; - synth->SamplesDone %= synth->SampleRate; -} - - -MidiSynth *SSynth_create(ALCdevice *device) -{ - SSynth *synth; - - /* This option is temporary. Once this synth is in a more usable state, a - * more generic selector should be used. */ - if(!GetConfigValueBool("midi", "internal-synth", 0)) - { - TRACE("Not using internal MIDI synth\n"); - return NULL; - } - - synth = SSynth_New(sizeof(*synth)); - if(!synth) - { - ERR("Failed to allocate SSynth\n"); - return NULL; - } - SSynth_Construct(synth, device); - return STATIC_CAST(MidiSynth, synth); -} diff --git a/love/src/jni/openal-soft-1.17.0/Alc/mixer.c b/love/src/jni/openal-soft-1.17.0/Alc/mixer.c deleted file mode 100644 index f3b8f599..00000000 --- a/love/src/jni/openal-soft-1.17.0/Alc/mixer.c +++ /dev/null @@ -1,510 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 1999-2007 by authors. - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#include "alMain.h" -#include "AL/al.h" -#include "AL/alc.h" -#include "alSource.h" -#include "alBuffer.h" -#include "alListener.h" -#include "alAuxEffectSlot.h" -#include "alu.h" - -#include "mixer_defs.h" - - -extern inline void InitiatePositionArrays(ALuint frac, ALuint increment, ALuint *frac_arr, ALuint *pos_arr, ALuint size); - - -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 MixerFunc SelectMixer(void) -{ -#ifdef HAVE_SSE - if((CPUCapFlags&CPU_CAP_SSE)) - return Mix_SSE; -#endif -#ifdef HAVE_NEON - if((CPUCapFlags&CPU_CAP_NEON)) - return Mix_Neon; -#endif - - return Mix_C; -} - -static inline ResamplerFunc SelectResampler(enum Resampler Resampler, ALuint increment) -{ - if(increment == FRACTIONONE) - return Resample_copy32_C; - switch(Resampler) - { - case PointResampler: - return Resample_point32_C; - case LinearResampler: -#ifdef HAVE_SSE4_1 - if((CPUCapFlags&CPU_CAP_SSE4_1)) - return Resample_lerp32_SSE41; -#endif -#ifdef HAVE_SSE2 - if((CPUCapFlags&CPU_CAP_SSE2)) - return Resample_lerp32_SSE2; -#endif - return Resample_lerp32_C; - case CubicResampler: - return Resample_cubic32_C; - case ResamplerMax: - /* Shouldn't happen */ - break; - } - - return Resample_point32_C; -} - - -static inline ALfloat Sample_ALbyte(ALbyte val) -{ return val * (1.0f/127.0f); } - -static inline ALfloat Sample_ALshort(ALshort val) -{ return val * (1.0f/32767.0f); } - -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)\ -{ \ - ALuint i; \ - for(i = 0;i < samples;i++) \ - dst[i] = Sample_##T(src[i*srcstep]); \ -} - -DECL_TEMPLATE(ALbyte) -DECL_TEMPLATE(ALshort) -DECL_TEMPLATE(ALfloat) - -#undef DECL_TEMPLATE - -static void LoadSamples(ALfloat *dst, const ALvoid *src, ALuint srcstep, enum FmtType srctype, ALuint samples) -{ - switch(srctype) - { - case FmtByte: - Load_ALbyte(dst, src, srcstep, samples); - break; - case FmtShort: - Load_ALshort(dst, src, srcstep, samples); - break; - case FmtFloat: - Load_ALfloat(dst, src, srcstep, samples); - break; - } -} - -static void SilenceSamples(ALfloat *dst, ALuint samples) -{ - ALuint i; - for(i = 0;i < samples;i++) - dst[i] = 0.0f; -} - - -static const ALfloat *DoFilters(ALfilterState *lpfilter, ALfilterState *hpfilter, - ALfloat *restrict dst, const ALfloat *restrict src, - ALuint numsamples, enum ActiveFilters type) -{ - ALuint i; - switch(type) - { - case AF_None: - break; - - case AF_LowPass: - ALfilterState_process(lpfilter, dst, src, numsamples); - return dst; - case AF_HighPass: - 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); - - ALfilterState_process(lpfilter, temp, src+i, todo); - ALfilterState_process(hpfilter, dst+i, temp, todo); - i += todo; - } - return dst; - } - return src; -} - - -ALvoid MixSource(ALactivesource *src, 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 chan, j; - - /* Get source info */ - State = Source->state; - BufferListItem = ATOMIC_LOAD(&Source->current_buffer); - 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; - - Mix = SelectMixer(); - HrtfMix = SelectHrtfMixer(); - Resample = SelectResampler(Resampler, increment); - - 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 */ - DataSize64 = SamplesToDo-OutPos; - DataSize64 *= increment; - DataSize64 += DataPosFrac+FRACTIONMASK; - DataSize64 >>= FRACTIONBITS; - DataSize64 += BufferPadding+BufferPrePadding; - - SrcBufferSize = (ALuint)mini64(DataSize64, BUFFERSIZE); - - /* Figure out how many samples we can actually mix from this. */ - DataSize64 = SrcBufferSize; - DataSize64 -= BufferPadding+BufferPrePadding; - DataSize64 <<= FRACTIONBITS; - DataSize64 -= DataPosFrac; - - DstBufferSize = (ALuint)((DataSize64+(increment-1)) / increment); - DstBufferSize = minu(DstBufferSize, (SamplesToDo-OutPos)); - - /* Some mixers like having a multiple of 4, so try to give that unless - * this is the last update. */ - if(OutPos+DstBufferSize < SamplesToDo) - DstBufferSize &= ~3; - - for(chan = 0;chan < NumChannels;chan++) - { - const ALfloat *ResampledData; - ALfloat *SrcData = Device->SourceData; - ALuint SrcDataSize = 0; - - if(Source->SourceType == AL_STATIC) - { - const ALbuffer *ALBuffer = BufferListItem->buffer; - const ALubyte *Data = ALBuffer->data; - ALuint DataSize; - ALuint pos; - - /* 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 */ - DataSize = minu(SrcBufferSize - SrcDataSize, ALBuffer->SampleLen - pos); - - LoadSamples(&SrcData[SrcDataSize], &Data[(pos*NumChannels + chan)*SampleSize], - NumChannels, ALBuffer->FmtType, DataSize); - SrcDataSize += DataSize; - - SilenceSamples(&SrcData[SrcDataSize], SrcBufferSize - SrcDataSize); - SrcDataSize += SrcBufferSize - SrcDataSize; - } - else - { - 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 */ - DataSize = LoopEnd - pos; - DataSize = minu(SrcBufferSize - SrcDataSize, DataSize); - - LoadSamples(&SrcData[SrcDataSize], &Data[(pos*NumChannels + chan)*SampleSize], - NumChannels, ALBuffer->FmtType, DataSize); - SrcDataSize += DataSize; - - DataSize = LoopEnd-LoopStart; - while(SrcBufferSize > SrcDataSize) - { - DataSize = minu(SrcBufferSize - SrcDataSize, DataSize); - - LoadSamples(&SrcData[SrcDataSize], &Data[(LoopStart*NumChannels + chan)*SampleSize], - NumChannels, ALBuffer->FmtType, DataSize); - SrcDataSize += DataSize; - } - } - } - else - { - /* 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; - } - } - } - - while(tmpiter && SrcBufferSize > SrcDataSize) - { - const ALbuffer *ALBuffer; - if((ALBuffer=tmpiter->buffer) != NULL) - { - const ALubyte *Data = ALBuffer->data; - ALuint DataSize = ALBuffer->SampleLen; - - /* Skip the data already played */ - if(DataSize <= pos) - pos -= DataSize; - else - { - Data += (pos*NumChannels + chan)*SampleSize; - DataSize -= pos; - pos -= pos; - - DataSize = minu(SrcBufferSize - SrcDataSize, DataSize); - LoadSamples(&SrcData[SrcDataSize], Data, NumChannels, - ALBuffer->FmtType, DataSize); - SrcDataSize += DataSize; - } - } - tmpiter = tmpiter->next; - if(!tmpiter && Looping) - tmpiter = ATOMIC_LOAD(&Source->queue); - else if(!tmpiter) - { - SilenceSamples(&SrcData[SrcDataSize], SrcBufferSize - SrcDataSize); - SrcDataSize += SrcBufferSize - SrcDataSize; - } - } - } - - /* Now resample, then filter and mix to the appropriate outputs. */ - ResampledData = Resample( - &SrcData[BufferPrePadding], DataPosFrac, increment, - Device->ResampledData, DstBufferSize - ); - { - DirectParams *parms = &src->Direct; - const ALfloat *samples; - - samples = DoFilters( - &parms->Filters[chan].LowPass, &parms->Filters[chan].HighPass, - Device->FilteredData, ResampledData, DstBufferSize, - parms->Filters[chan].ActiveType - ); - if(!src->IsHrtf) - Mix(samples, MaxChannels, parms->OutBuffer, parms->Mix.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); - } - - for(j = 0;j < Device->NumAuxSends;j++) - { - SendParams *parms = &src->Send[j]; - const ALfloat *samples; - - if(!parms->OutBuffer) - continue; - - samples = DoFilters( - &parms->Filters[chan].LowPass, &parms->Filters[chan].HighPass, - Device->FilteredData, ResampledData, DstBufferSize, - parms->Filters[chan].ActiveType - ); - Mix(samples, 1, parms->OutBuffer, &parms->Gain, - parms->Counter, OutPos, DstBufferSize); - } - } - /* Update positions */ - DataPosFrac += increment*DstBufferSize; - DataPosInt += DataPosFrac>>FRACTIONBITS; - DataPosFrac &= FRACTIONMASK; - - OutPos += DstBufferSize; - src->Offset += DstBufferSize; - src->Direct.Counter = maxu(src->Direct.Counter, DstBufferSize) - DstBufferSize; - for(j = 0;j < Device->NumAuxSends;j++) - src->Send[j].Counter = maxu(src->Send[j].Counter, DstBufferSize) - DstBufferSize; - - /* Handle looping sources */ - while(1) - { - const ALbuffer *ALBuffer; - ALuint DataSize = 0; - ALuint LoopStart = 0; - ALuint LoopEnd = 0; - - if((ALBuffer=BufferListItem->buffer) != NULL) - { - DataSize = ALBuffer->SampleLen; - LoopStart = ALBuffer->LoopStart; - LoopEnd = ALBuffer->LoopEnd; - if(LoopEnd > DataPosInt) - break; - } - - if(Looping && Source->SourceType == AL_STATIC) - { - assert(LoopEnd > LoopStart); - DataPosInt = ((DataPosInt-LoopStart)%(LoopEnd-LoopStart)) + LoopStart; - break; - } - - if(DataSize > DataPosInt) - break; - - if(!(BufferListItem=BufferListItem->next)) - { - if(Looping) - BufferListItem = ATOMIC_LOAD(&Source->queue); - else - { - State = AL_STOPPED; - BufferListItem = NULL; - DataPosInt = 0; - DataPosFrac = 0; - break; - } - } - - DataPosInt -= DataSize; - } - } while(State == AL_PLAYING && OutPos < SamplesToDo); - - /* Update source info */ - Source->state = State; - ATOMIC_STORE(&Source->current_buffer, BufferListItem); - Source->position = DataPosInt; - Source->position_fraction = DataPosFrac; -} diff --git a/love/src/jni/openal-soft-1.17.0/Alc/mixer_c.c b/love/src/jni/openal-soft-1.17.0/Alc/mixer_c.c deleted file mode 100644 index f3a229e5..00000000 --- a/love/src/jni/openal-soft-1.17.0/Alc/mixer_c.c +++ /dev/null @@ -1,126 +0,0 @@ -#include "config.h" - -#include - -#include "alMain.h" -#include "alu.h" -#include "alSource.h" -#include "alAuxEffectSlot.h" - - -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)); } - -const ALfloat *Resample_copy32_C(const ALfloat *src, ALuint UNUSED(frac), - ALuint 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)) - return src; -#endif - memcpy(dst, src, numsamples*sizeof(ALfloat)); - return dst; -} - -#define DECL_TEMPLATE(Sampler) \ -const ALfloat *Resample_##Sampler##_C(const ALfloat *src, ALuint frac, \ - ALuint increment, ALfloat *restrict dst, ALuint numsamples) \ -{ \ - ALuint i; \ - for(i = 0;i < numsamples;i++) \ - { \ - dst[i] = Sampler(src, frac); \ - \ - frac += increment; \ - src += frac>>FRACTIONBITS; \ - frac &= FRACTIONMASK; \ - } \ - return dst; \ -} - -DECL_TEMPLATE(point32) -DECL_TEMPLATE(lerp32) -DECL_TEMPLATE(cubic32) - -#undef DECL_TEMPLATE - - -void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *src, ALuint numsamples) -{ - ALuint i; - for(i = 0;i < numsamples;i++) - *(dst++) = ALfilterState_processSingle(filter, *(src++)); -} - - -static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2], - const ALuint IrSize, - ALfloat (*restrict Coeffs)[2], - const ALfloat (*restrict CoeffStep)[2], - ALfloat left, ALfloat right) -{ - ALuint c; - for(c = 0;c < IrSize;c++) - { - const ALuint off = (Offset+c)&HRIR_MASK; - Values[off][0] += Coeffs[c][0] * left; - Values[off][1] += Coeffs[c][1] * right; - Coeffs[c][0] += CoeffStep[c][0]; - Coeffs[c][1] += CoeffStep[c][1]; - } -} - -static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2], - const ALuint IrSize, - ALfloat (*restrict Coeffs)[2], - ALfloat left, ALfloat right) -{ - ALuint c; - for(c = 0;c < IrSize;c++) - { - const ALuint off = (Offset+c)&HRIR_MASK; - Values[off][0] += Coeffs[c][0] * left; - Values[off][1] += Coeffs[c][1] * right; - } -} - -#define SUFFIX C -#include "mixer_inc.c" -#undef SUFFIX - - -void Mix_C(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], - MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize) -{ - ALfloat gain, step; - ALuint c; - - for(c = 0;c < OutChans;c++) - { - ALuint pos = 0; - gain = Gains[c].Current; - step = Gains[c].Step; - if(step != 1.0f && Counter > 0) - { - for(;pos < BufferSize && pos < Counter;pos++) - { - OutBuffer[c][OutPos+pos] += data[pos]*gain; - gain *= step; - } - if(pos == Counter) - gain = Gains[c].Target; - Gains[c].Current = gain; - } - - if(!(gain > GAIN_SILENCE_THRESHOLD)) - continue; - for(;pos < BufferSize;pos++) - OutBuffer[c][OutPos+pos] += data[pos]*gain; - } -} diff --git a/love/src/jni/openal-soft-1.17.0/Alc/mixer_defs.h b/love/src/jni/openal-soft-1.17.0/Alc/mixer_defs.h deleted file mode 100644 index c1500ed2..00000000 --- a/love/src/jni/openal-soft-1.17.0/Alc/mixer_defs.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef MIXER_DEFS_H -#define MIXER_DEFS_H - -#include "AL/alc.h" -#include "AL/al.h" -#include "alMain.h" -#include "alu.h" - -struct MixGains; - -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); - - -/* C mixers */ -void MixHrtf_C(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data, - ALuint Counter, ALuint Offset, ALuint OutPos, const ALuint IrSize, - 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); - -/* SSE mixers */ -void MixHrtf_SSE(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data, - ALuint Counter, ALuint Offset, ALuint OutPos, const ALuint IrSize, - const struct HrtfParams *hrtfparams, struct HrtfState *hrtfstate, - ALuint BufferSize); -void Mix_SSE(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], - struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize); - -/* SSE resamplers */ -inline void InitiatePositionArrays(ALuint frac, ALuint increment, ALuint *frac_arr, ALuint *pos_arr, ALuint size) -{ - ALuint i; - - pos_arr[0] = 0; - frac_arr[0] = frac; - for(i = 1;i < size;i++) - { - ALuint frac_tmp = frac_arr[i-1] + increment; - pos_arr[i] = pos_arr[i-1] + (frac_tmp>>FRACTIONBITS); - frac_arr[i] = frac_tmp&FRACTIONMASK; - } -} - -const ALfloat *Resample_lerp32_SSE2(const ALfloat *src, ALuint frac, ALuint increment, - ALfloat *restrict dst, ALuint numsamples); -const ALfloat *Resample_lerp32_SSE41(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, - const struct HrtfParams *hrtfparams, struct HrtfState *hrtfstate, - ALuint BufferSize); -void Mix_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], - struct MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize); - -#endif /* MIXER_DEFS_H */ diff --git a/love/src/jni/openal-soft-1.17.0/Alc/mixer_inc.c b/love/src/jni/openal-soft-1.17.0/Alc/mixer_inc.c deleted file mode 100644 index ab6f32c5..00000000 --- a/love/src/jni/openal-soft-1.17.0/Alc/mixer_inc.c +++ /dev/null @@ -1,93 +0,0 @@ -#include "config.h" - -#include "alMain.h" -#include "alSource.h" - -#include "hrtf.h" -#include "mixer_defs.h" -#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 ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2], - const ALuint irSize, - ALfloat (*restrict Coeffs)[2], - const ALfloat (*restrict CoeffStep)[2], - ALfloat left, ALfloat right); -static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2], - const ALuint irSize, - ALfloat (*restrict Coeffs)[2], - ALfloat left, ALfloat right); - - -void MixHrtf(ALfloat (*restrict OutBuffer)[BUFFERSIZE], const ALfloat *data, - ALuint Counter, ALuint Offset, ALuint OutPos, const ALuint IrSize, - const HrtfParams *hrtfparams, HrtfState *hrtfstate, ALuint BufferSize) -{ - alignas(16) ALfloat Coeffs[HRIR_LENGTH][2]; - 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); - } - 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++) - { - 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], - (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], - (Delay[1]&HRTFDELAY_MASK)*(1.0f/HRTFDELAY_FRACONE)); - - Delay[0] += hrtfparams->DelayStep[0]; - Delay[1] += hrtfparams->DelayStep[1]; - - hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][0] = 0.0f; - hrtfstate->Values[(Offset+IrSize)&HRIR_MASK][1] = 0.0f; - 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]; - OutPos++; - } - - Delay[0] >>= HRTFDELAY_BITS; - 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->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]; - - OutPos++; - } -} - - -#undef MixHrtf - -#undef MERGE -#undef REAL_MERGE diff --git a/love/src/jni/openal-soft-1.17.0/Alc/mixer_neon.c b/love/src/jni/openal-soft-1.17.0/Alc/mixer_neon.c deleted file mode 100644 index 7b6da2b9..00000000 --- a/love/src/jni/openal-soft-1.17.0/Alc/mixer_neon.c +++ /dev/null @@ -1,118 +0,0 @@ -#include "config.h" - -#include - -#include "AL/al.h" -#include "AL/alc.h" -#include "alMain.h" -#include "alu.h" -#include "hrtf.h" - - -static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2], - const ALuint IrSize, - ALfloat (*restrict Coeffs)[2], - const ALfloat (*restrict CoeffStep)[2], - ALfloat left, ALfloat right) -{ - ALuint c; - float32x4_t leftright4; - { - float32x2_t leftright2 = vdup_n_f32(0.0); - leftright2 = vset_lane_f32(left, leftright2, 0); - leftright2 = vset_lane_f32(right, leftright2, 1); - leftright4 = vcombine_f32(leftright2, leftright2); - } - for(c = 0;c < IrSize;c += 2) - { - const ALuint o0 = (Offset+c)&HRIR_MASK; - const ALuint o1 = (o0+1)&HRIR_MASK; - float32x4_t vals = vcombine_f32(vld1_f32((float32_t*)&Values[o0][0]), - vld1_f32((float32_t*)&Values[o1][0])); - float32x4_t coefs = vld1q_f32((float32_t*)&Coeffs[c][0]); - float32x4_t deltas = vld1q_f32(&CoeffStep[c][0]); - - vals = vmlaq_f32(vals, coefs, leftright4); - coefs = vaddq_f32(coefs, deltas); - - vst1_f32((float32_t*)&Values[o0][0], vget_low_f32(vals)); - vst1_f32((float32_t*)&Values[o1][0], vget_high_f32(vals)); - vst1q_f32(&Coeffs[c][0], coefs); - } -} - -static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2], - const ALuint IrSize, - ALfloat (*restrict Coeffs)[2], - ALfloat left, ALfloat right) -{ - ALuint c; - float32x4_t leftright4; - { - float32x2_t leftright2 = vdup_n_f32(0.0); - leftright2 = vset_lane_f32(left, leftright2, 0); - leftright2 = vset_lane_f32(right, leftright2, 1); - leftright4 = vcombine_f32(leftright2, leftright2); - } - for(c = 0;c < IrSize;c += 2) - { - const ALuint o0 = (Offset+c)&HRIR_MASK; - const ALuint o1 = (o0+1)&HRIR_MASK; - float32x4_t vals = vcombine_f32(vld1_f32((float32_t*)&Values[o0][0]), - vld1_f32((float32_t*)&Values[o1][0])); - float32x4_t coefs = vld1q_f32((float32_t*)&Coeffs[c][0]); - - vals = vmlaq_f32(vals, coefs, leftright4); - - vst1_f32((float32_t*)&Values[o0][0], vget_low_f32(vals)); - vst1_f32((float32_t*)&Values[o1][0], vget_high_f32(vals)); - } -} - - -#define SUFFIX Neon -#include "mixer_inc.c" -#undef SUFFIX - - -void MixDirect_Neon(const ALfloat *data, ALuint OutChans, ALfloat (*restrict OutBuffer)[BUFFERSIZE], - MixGains *Gains, ALuint Counter, ALuint OutPos, ALuint BufferSize) -{ - ALfloat gain, step; - float32x4_t gain4; - ALuint c; - - for(c = 0;c < OutChans;c++) - { - ALuint pos = 0; - gain = Gains[c].Current; - step = Gains[c].Step; - if(step != 1.0f && Counter > 0) - { - for(;pos < BufferSize && pos < Counter;pos++) - { - OutBuffer[c][OutPos+pos] += data[pos]*gain; - 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++) - OutBuffer[c][OutPos+pos] += data[pos]*gain; - } - - if(!(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)); - vst1q_f32(&OutBuffer[c][OutPos+pos], dry4); - } - for(;pos < BufferSize;pos++) - OutBuffer[c][OutPos+pos] += data[pos]*gain; - } -} diff --git a/love/src/jni/openal-soft-1.17.0/Alc/mixer_sse.c b/love/src/jni/openal-soft-1.17.0/Alc/mixer_sse.c deleted file mode 100644 index 970619ec..00000000 --- a/love/src/jni/openal-soft-1.17.0/Alc/mixer_sse.c +++ /dev/null @@ -1,202 +0,0 @@ -#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" -#include "AL/alc.h" -#include "alMain.h" -#include "alu.h" - -#include "alSource.h" -#include "alAuxEffectSlot.h" -#include "mixer_defs.h" - - -static inline void ApplyCoeffsStep(ALuint Offset, ALfloat (*restrict Values)[2], - const ALuint IrSize, - ALfloat (*restrict Coeffs)[2], - const ALfloat (*restrict CoeffStep)[2], - ALfloat left, ALfloat right) -{ - const __m128 lrlr = _mm_setr_ps(left, right, left, right); - __m128 coeffs, deltas, imp0, imp1; - __m128 vals = _mm_setzero_ps(); - ALuint i; - - if((Offset&1)) - { - const ALuint o0 = Offset&HRIR_MASK; - const ALuint o1 = (Offset+IrSize-1)&HRIR_MASK; - - coeffs = _mm_load_ps(&Coeffs[0][0]); - deltas = _mm_load_ps(&CoeffStep[0][0]); - vals = _mm_loadl_pi(vals, (__m64*)&Values[o0][0]); - imp0 = _mm_mul_ps(lrlr, coeffs); - coeffs = _mm_add_ps(coeffs, deltas); - vals = _mm_add_ps(imp0, vals); - _mm_store_ps(&Coeffs[0][0], coeffs); - _mm_storel_pi((__m64*)&Values[o0][0], vals); - for(i = 1;i < IrSize-1;i += 2) - { - const ALuint o2 = (Offset+i)&HRIR_MASK; - - coeffs = _mm_load_ps(&Coeffs[i+1][0]); - deltas = _mm_load_ps(&CoeffStep[i+1][0]); - vals = _mm_load_ps(&Values[o2][0]); - imp1 = _mm_mul_ps(lrlr, coeffs); - coeffs = _mm_add_ps(coeffs, deltas); - imp0 = _mm_shuffle_ps(imp0, imp1, _MM_SHUFFLE(1, 0, 3, 2)); - vals = _mm_add_ps(imp0, vals); - _mm_store_ps(&Coeffs[i+1][0], coeffs); - _mm_store_ps(&Values[o2][0], vals); - imp0 = imp1; - } - vals = _mm_loadl_pi(vals, (__m64*)&Values[o1][0]); - imp0 = _mm_movehl_ps(imp0, imp0); - vals = _mm_add_ps(imp0, vals); - _mm_storel_pi((__m64*)&Values[o1][0], vals); - } - else - { - for(i = 0;i < IrSize;i += 2) - { - const ALuint o = (Offset + i)&HRIR_MASK; - - coeffs = _mm_load_ps(&Coeffs[i][0]); - deltas = _mm_load_ps(&CoeffStep[i][0]); - vals = _mm_load_ps(&Values[o][0]); - imp0 = _mm_mul_ps(lrlr, coeffs); - coeffs = _mm_add_ps(coeffs, deltas); - vals = _mm_add_ps(imp0, vals); - _mm_store_ps(&Coeffs[i][0], coeffs); - _mm_store_ps(&Values[o][0], vals); - } - } -} - -static inline void ApplyCoeffs(ALuint Offset, ALfloat (*restrict Values)[2], - const ALuint IrSize, - ALfloat (*restrict Coeffs)[2], - ALfloat left, ALfloat right) -{ - const __m128 lrlr = _mm_setr_ps(left, right, left, right); - __m128 vals = _mm_setzero_ps(); - __m128 coeffs; - ALuint i; - - if((Offset&1)) - { - const ALuint o0 = Offset&HRIR_MASK; - const ALuint o1 = (Offset+IrSize-1)&HRIR_MASK; - __m128 imp0, imp1; - - coeffs = _mm_load_ps(&Coeffs[0][0]); - vals = _mm_loadl_pi(vals, (__m64*)&Values[o0][0]); - imp0 = _mm_mul_ps(lrlr, coeffs); - vals = _mm_add_ps(imp0, vals); - _mm_storel_pi((__m64*)&Values[o0][0], vals); - for(i = 1;i < IrSize-1;i += 2) - { - const ALuint o2 = (Offset+i)&HRIR_MASK; - - coeffs = _mm_load_ps(&Coeffs[i+1][0]); - vals = _mm_load_ps(&Values[o2][0]); - imp1 = _mm_mul_ps(lrlr, coeffs); - imp0 = _mm_shuffle_ps(imp0, imp1, _MM_SHUFFLE(1, 0, 3, 2)); - vals = _mm_add_ps(imp0, vals); - _mm_store_ps(&Values[o2][0], vals); - imp0 = imp1; - } - vals = _mm_loadl_pi(vals, (__m64*)&Values[o1][0]); - imp0 = _mm_movehl_ps(imp0, imp0); - vals = _mm_add_ps(imp0, vals); - _mm_storel_pi((__m64*)&Values[o1][0], vals); - } - else - { - for(i = 0;i < IrSize;i += 2) - { - const ALuint o = (Offset + i)&HRIR_MASK; - - coeffs = _mm_load_ps(&Coeffs[i][0]); - vals = _mm_load_ps(&Values[o][0]); - vals = _mm_add_ps(vals, _mm_mul_ps(lrlr, coeffs)); - _mm_store_ps(&Values[o][0], vals); - } - } -} - -#define SUFFIX SSE -#include "mixer_inc.c" -#undef SUFFIX - - -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; - ALuint c; - - for(c = 0;c < OutChans;c++) - { - ALuint pos = 0; - gain = Gains[c].Current; - step = Gains[c].Step; - if(step != 1.0f && Counter > 0) - { - /* Mix with applying gain steps in aligned multiples of 4. */ - if(BufferSize-pos > 3 && Counter-pos > 3) - { - gain4 = _mm_setr_ps( - gain, - gain * step, - gain * step * step, - gain * 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); - _mm_store_ps(&OutBuffer[c][OutPos+pos], dry4); - pos += 4; - } while(BufferSize-pos > 3 && Counter-pos > 3); - 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++) - { - OutBuffer[c][OutPos+pos] += data[pos]*gain; - 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++) - OutBuffer[c][OutPos+pos] += data[pos]*gain; - } - - if(!(gain > GAIN_SILENCE_THRESHOLD)) - continue; - gain4 = _mm_set1_ps(gain); - for(;BufferSize-pos > 3;pos += 4) - { - const __m128 val4 = _mm_load_ps(&data[pos]); - __m128 dry4 = _mm_load_ps(&OutBuffer[c][OutPos+pos]); - dry4 = _mm_add_ps(dry4, _mm_mul_ps(val4, gain4)); - _mm_store_ps(&OutBuffer[c][OutPos+pos], dry4); - } - for(;pos < BufferSize;pos++) - OutBuffer[c][OutPos+pos] += data[pos]*gain; - } -} diff --git a/love/src/jni/openal-soft-1.17.0/Alc/mixer_sse41.c b/love/src/jni/openal-soft-1.17.0/Alc/mixer_sse41.c deleted file mode 100644 index 8ce8cd90..00000000 --- a/love/src/jni/openal-soft-1.17.0/Alc/mixer_sse41.c +++ /dev/null @@ -1,82 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 2014 by Timothy Arceri . - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include - -#include "alu.h" -#include "mixer_defs.h" - - -const ALfloat *Resample_lerp32_SSE41(const ALfloat *src, ALuint frac, ALuint increment, - ALfloat *restrict dst, ALuint numsamples) -{ - const __m128i increment4 = _mm_set1_epi32(increment*4); - const __m128 fracOne4 = _mm_set1_ps(1.0f/FRACTIONONE); - const __m128i fracMask4 = _mm_set1_epi32(FRACTIONMASK); - alignas(16) 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)); - - for(i = 0;numsamples-i > 3;i += 4) - { - const __m128 val1 = _mm_setr_ps(src[pos_.i[0]], src[pos_.i[1]], src[pos_.i[2]], src[pos_.i[3]]); - const __m128 val2 = _mm_setr_ps(src[pos_.i[0]+1], src[pos_.i[1]+1], src[pos_.i[2]+1], src[pos_.i[3]+1]); - - /* val1 + (val2-val1)*mu */ - const __m128 r0 = _mm_sub_ps(val2, val1); - const __m128 mu = _mm_mul_ps(_mm_cvtepi32_ps(frac4), fracOne4); - const __m128 out = _mm_add_ps(val1, _mm_mul_ps(mu, r0)); - - _mm_store_ps(&dst[i], out); - - frac4 = _mm_add_epi32(frac4, increment4); - pos4 = _mm_add_epi32(pos4, _mm_srli_epi32(frac4, FRACTIONBITS)); - frac4 = _mm_and_si128(frac4, fracMask4); - - 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); - } - - pos = pos_.i[0]; - frac = _mm_cvtsi128_si32(frac4); - - for(;i < numsamples;i++) - { - dst[i] = lerp(src[pos], src[pos+1], frac * (1.0f/FRACTIONONE)); - - frac += increment; - pos += frac>>FRACTIONBITS; - frac &= FRACTIONMASK; - } - return dst; -} diff --git a/love/src/jni/openal-soft-1.17.0/Alc/panning.c b/love/src/jni/openal-soft-1.17.0/Alc/panning.c deleted file mode 100644 index 30a1e571..00000000 --- a/love/src/jni/openal-soft-1.17.0/Alc/panning.c +++ /dev/null @@ -1,450 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 1999-2010 by authors. - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#include "alMain.h" -#include "AL/al.h" -#include "AL/alc.h" -#include "alu.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) -{ - char *confkey, *next; - char *layout_str; - char *sep, *end; - enum Channel val; - const char *str; - int i; - - if(!ConfigValueStr(NULL, name, &str) && !ConfigValueStr(NULL, "layout", &str)) - return; - - layout_str = strdup(str); - next = confkey = layout_str; - while(next && *next) - { - confkey = next; - next = strchr(confkey, ','); - if(next) - { - *next = 0; - do { - next++; - } while(isspace(*next) || *next == ','); - } - - sep = strchr(confkey, '='); - if(!sep || confkey == sep) - { - ERR("Malformed speaker key: %s\n", confkey); - 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 - { - 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) - { - long angle = strtol(sep, NULL, 10); - if(angle >= -180 && angle <= 180) - SpeakerAngle[i] = DEG2RAD(angle); - else - ERR("Invalid angle for speaker \"%s\": %ld\n", confkey, angle); - break; - } - } - } - 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; - } - } -} - - -void ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat hwidth, ALfloat ingain, ALfloat gains[MaxChannels]) -{ - 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; - - 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) - { - case DevFmtMono: - Device->NumChan = 1; - Speaker2Chan[0] = FrontCenter; - SpeakerAngle[0] = DEG2RAD(0.0f); - layoutname = NULL; - 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"; - 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"; - 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"; - 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"; - 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"; - 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"; - break; - } - if(layoutname && Device->Type != Loopback) - SetSpeakerArrangement(layoutname, SpeakerAngle, Speaker2Chan, Device->NumChan); -} diff --git a/love/src/jni/openal-soft-1.17.0/Alc/vector.h b/love/src/jni/openal-soft-1.17.0/Alc/vector.h deleted file mode 100644 index 9f28d0db..00000000 --- a/love/src/jni/openal-soft-1.17.0/Alc/vector.h +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef AL_VECTOR_H -#define AL_VECTOR_H - -#include - -#include - -/* "Base" vector type, designed to alias with the actual vector types. */ -typedef struct vector__s { - ALsizei Capacity; - ALsizei Size; -} *vector_; - -#define TYPEDEF_VECTOR(T, N) typedef struct { \ - ALsizei Capacity; \ - ALsizei Size; \ - T Data[]; \ -} _##N; \ -typedef _##N* N; \ -typedef const _##N* const_##N; - -#define VECTOR(T) struct { \ - ALsizei Capacity; \ - ALsizei Size; \ - T Data[]; \ -}* - -#define VECTOR_INIT(_x) do { (_x) = NULL; } while(0) -#define VECTOR_INIT_STATIC() NULL -#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); -#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); -#define VECTOR_RESIZE(_x, _c) (vector_resize((char*)&(_x), sizeof(*(_x)), sizeof((_x)->Data[0]), (_c))) - -#define VECTOR_CAPACITY(_x) ((_x) ? (_x)->Capacity : 0) -#define VECTOR_SIZE(_x) ((_x) ? (_x)->Size : 0) - -#define VECTOR_ITER_BEGIN(_x) ((_x) ? (_x)->Data + 0 : NULL) -#define VECTOR_ITER_END(_x) ((_x) ? (_x)->Data + (_x)->Size : NULL) - -ALboolean vector_insert(char *ptr, size_t base_size, size_t obj_size, void *ins_pos, const void *datstart, const void *datend); -#ifdef __GNUC__ -#define TYPE_CHECK(T1, T2) __builtin_types_compatible_p(T1, T2) -#define VECTOR_INSERT(_x, _i, _s, _e) __extension__({ \ - ALboolean _r; \ - static_assert(TYPE_CHECK(__typeof((_x)->Data[0]), __typeof(*(_i))), "Incompatible insertion iterator"); \ - static_assert(TYPE_CHECK(__typeof((_x)->Data[0]), __typeof(*(_s))), "Incompatible insertion source type"); \ - static_assert(TYPE_CHECK(__typeof(*(_s)), __typeof(*(_e))), "Incompatible iterator sources"); \ - _r = vector_insert((char*)&(_x), sizeof(*(_x)), sizeof((_x)->Data[0]), (_i), (_s), (_e)); \ - _r; \ -}) -#else -#define VECTOR_INSERT(_x, _i, _s, _e) (vector_insert((char*)&(_x), sizeof(*(_x)), sizeof((_x)->Data[0]), (_i), (_s), (_e))) -#endif - -#define VECTOR_PUSH_BACK(_x, _obj) (vector_reserve((char*)&(_x), sizeof(*(_x)), sizeof((_x)->Data[0]), VECTOR_SIZE(_x)+1, AL_FALSE) && \ - (((_x)->Data[(_x)->Size++] = (_obj)),AL_TRUE)) -#define VECTOR_POP_BACK(_x) ((void)((_x)->Size--)) - -#define VECTOR_BACK(_x) ((_x)->Data[(_x)->Size-1]) -#define VECTOR_FRONT(_x) ((_x)->Data[0]) - -#define VECTOR_ELEM(_x, _o) ((_x)->Data[(_o)]) - -#define VECTOR_FOR_EACH(_t, _x, _f) do { \ - _t *_iter = VECTOR_ITER_BEGIN((_x)); \ - _t *_end = VECTOR_ITER_END((_x)); \ - for(;_iter != _end;++_iter) \ - _f(_iter); \ -} while(0) - -#define VECTOR_FIND_IF(_i, _t, _x, _f) do { \ - _t *_iter = VECTOR_ITER_BEGIN((_x)); \ - _t *_end = VECTOR_ITER_END((_x)); \ - for(;_iter != _end;++_iter) \ - { \ - if(_f(_iter)) \ - break; \ - } \ - (_i) = _iter; \ -} while(0) - -#endif /* AL_VECTOR_H */ diff --git a/love/src/jni/openal-soft-1.17.0/OpenAL32/Include/alFilter.h b/love/src/jni/openal-soft-1.17.0/OpenAL32/Include/alFilter.h deleted file mode 100644 index 62b5fda8..00000000 --- a/love/src/jni/openal-soft-1.17.0/OpenAL32/Include/alFilter.h +++ /dev/null @@ -1,112 +0,0 @@ -#ifndef _AL_FILTER_H_ -#define _AL_FILTER_H_ - -#include "alMain.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define LOWPASSFREQREF (5000.0f) -#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 */ - -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. */ - ALfilterType_Peaking, - - /** Low-pass cut-off filter, specifying a cut-off frequency and bandwidth. */ - ALfilterType_LowPass, - /** High-pass cut-off filter, specifying a cut-off frequency and bandwidth. */ - ALfilterType_HighPass, - /** Band-pass filter, specifying a center frequency and bandwidth. */ - ALfilterType_BandPass, -} ALfilterType; - -typedef struct ALfilterState { - ALfloat x[2]; /* History of two last input samples */ - ALfloat y[2]; /* History of two last output samples */ - ALfloat a[3]; /* Transfer function coefficients "a" */ - ALfloat b[3]; /* Transfer function coefficients "b" */ - - void (*process)(struct ALfilterState *self, ALfloat *restrict dst, const ALfloat *src, ALuint numsamples); -} ALfilterState; -#define ALfilterState_process(a, ...) ((a)->process((a), __VA_ARGS__)) - -void ALfilterState_clear(ALfilterState *filter); -void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat bandwidth); - -inline ALfloat ALfilterState_processSingle(ALfilterState *filter, ALfloat sample) -{ - ALfloat outsmp; - - outsmp = filter->b[0] * sample + - filter->b[1] * filter->x[0] + - filter->b[2] * filter->x[1] - - filter->a[1] * filter->y[0] - - filter->a[2] * filter->y[1]; - filter->x[1] = filter->x[0]; - filter->x[0] = sample; - filter->y[1] = filter->y[0]; - filter->y[0] = outsmp; - - return outsmp; -} - -void ALfilterState_processC(ALfilterState *filter, ALfloat *restrict dst, const ALfloat *src, ALuint numsamples); - - -typedef struct ALfilter { - // Filter type (AL_FILTER_NULL, ...) - ALenum type; - - ALfloat Gain; - ALfloat GainHF; - ALfloat HFReference; - ALfloat GainLF; - ALfloat LFReference; - - void (*SetParami)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint val); - void (*SetParamiv)(struct ALfilter *filter, ALCcontext *context, ALenum param, const ALint *vals); - void (*SetParamf)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALfloat val); - void (*SetParamfv)(struct ALfilter *filter, ALCcontext *context, ALenum param, const ALfloat *vals); - - void (*GetParami)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint *val); - void (*GetParamiv)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALint *vals); - void (*GetParamf)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *val); - void (*GetParamfv)(struct ALfilter *filter, ALCcontext *context, ALenum param, ALfloat *vals); - - /* Self ID */ - ALuint id; -} ALfilter; - -#define ALfilter_SetParami(x, c, p, v) ((x)->SetParami((x),(c),(p),(v))) -#define ALfilter_SetParamiv(x, c, p, v) ((x)->SetParamiv((x),(c),(p),(v))) -#define ALfilter_SetParamf(x, c, p, v) ((x)->SetParamf((x),(c),(p),(v))) -#define ALfilter_SetParamfv(x, c, p, v) ((x)->SetParamfv((x),(c),(p),(v))) - -#define ALfilter_GetParami(x, c, p, v) ((x)->GetParami((x),(c),(p),(v))) -#define ALfilter_GetParamiv(x, c, p, v) ((x)->GetParamiv((x),(c),(p),(v))) -#define ALfilter_GetParamf(x, c, p, v) ((x)->GetParamf((x),(c),(p),(v))) -#define ALfilter_GetParamfv(x, c, p, v) ((x)->GetParamfv((x),(c),(p),(v))) - -inline struct ALfilter *LookupFilter(ALCdevice *device, ALuint id) -{ return (struct ALfilter*)LookupUIntMapKey(&device->FilterMap, id); } -inline struct ALfilter *RemoveFilter(ALCdevice *device, ALuint id) -{ return (struct ALfilter*)RemoveUIntMapKey(&device->FilterMap, id); } - -ALvoid ReleaseALFilters(ALCdevice *device); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/love/src/jni/openal-soft-1.17.0/OpenAL32/Include/alListener.h b/love/src/jni/openal-soft-1.17.0/OpenAL32/Include/alListener.h deleted file mode 100644 index ee07d87c..00000000 --- a/love/src/jni/openal-soft-1.17.0/OpenAL32/Include/alListener.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef _AL_LISTENER_H_ -#define _AL_LISTENER_H_ - -#include "alMain.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct ALlistener { - volatile ALfloat Position[3]; - volatile ALfloat Velocity[3]; - volatile ALfloat Forward[3]; - volatile ALfloat Up[3]; - volatile ALfloat Gain; - volatile ALfloat MetersPerUnit; - - struct { - ALfloat Matrix[4][4]; - ALfloat Velocity[3]; - } Params; -} ALlistener; - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/love/src/jni/openal-soft-1.17.0/OpenAL32/Include/alMain.h b/love/src/jni/openal-soft-1.17.0/OpenAL32/Include/alMain.h deleted file mode 100644 index 111dde95..00000000 --- a/love/src/jni/openal-soft-1.17.0/OpenAL32/Include/alMain.h +++ /dev/null @@ -1,895 +0,0 @@ -#ifndef AL_MAIN_H -#define AL_MAIN_H - -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_STRINGS_H -#include -#endif - -#ifdef HAVE_FENV_H -#include -#endif - -#include "AL/al.h" -#include "AL/alc.h" -#include "AL/alext.h" - - -#if defined(_WIN64) -#define SZFMT "%I64u" -#elif defined(_WIN32) -#define SZFMT "%u" -#else -#define SZFMT "%zu" -#endif - - -#include "static_assert.h" -#include "align.h" -#include "atomic.h" -#include "uintmap.h" -#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 - -#ifndef ALC_SOFT_device_clock -#define ALC_SOFT_device_clock 1 -typedef int64_t ALCint64SOFT; -typedef uint64_t ALCuint64SOFT; -#define ALC_DEVICE_CLOCK_SOFT 0x1600 -typedef void (ALC_APIENTRY*LPALCGETINTEGER64VSOFT)(ALCdevice *device, ALCenum pname, ALsizei size, ALCint64SOFT *values); -#ifdef AL_ALEXT_PROTOTYPES -ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname, ALsizei size, ALCint64SOFT *values); -#endif -#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)) -#elif SIZEOF_LONG == 8 -#define U64(x) ((ALuint64)(x##ul)) -#elif SIZEOF_LONG_LONG == 8 -#define U64(x) ((ALuint64)(x##ull)) -#endif -#endif - -#ifndef UINT64_MAX -#define UINT64_MAX U64(18446744073709551615) -#endif - -#ifndef UNUSED -#if defined(__cplusplus) -#define UNUSED(x) -#elif defined(__GNUC__) -#define UNUSED(x) UNUSED_##x __attribute__((unused)) -#elif defined(__LCLINT__) -#define UNUSED(x) /*@unused@*/ x -#else -#define UNUSED(x) x -#endif -#endif - -#ifdef __GNUC__ -#define DECL_CONST __attribute__((const)) -#define DECL_FORMAT(x, y, z) __attribute__((format(x, (y), (z)))) -#else -#define DECL_CONST -#define DECL_FORMAT(x, y, z) -#endif - -#if defined(__GNUC__) && defined(__i386__) -/* force_align_arg_pointer is required for proper function arguments aligning - * when SSE code is used. Some systems (Windows, QNX) do not guarantee our - * thread functions will be properly aligned on the stack, even though GCC may - * generate code with the assumption that it is. */ -#define FORCE_ALIGN __attribute__((force_align_arg_pointer)) -#else -#define FORCE_ALIGN -#endif - -#ifdef HAVE_C99_VLA -#define DECL_VLA(T, _name, _size) T _name[(_size)] -#else -#define DECL_VLA(T, _name, _size) T *_name = alloca((_size) * sizeof(T)) -#endif - -#ifndef PATH_MAX -#ifdef MAX_PATH -#define PATH_MAX MAX_PATH -#else -#define PATH_MAX 4096 -#endif -#endif - - -static const union { - ALuint u; - ALubyte b[sizeof(ALuint)]; -} EndianTest = { 1 }; -#define IS_LITTLE_ENDIAN (EndianTest.b[0] == 1) - -#define COUNTOF(x) (sizeof((x))/sizeof((x)[0])) - - -#define DERIVE_FROM_TYPE(t) t t##_parent -#define STATIC_CAST(to, obj) (&(obj)->to##_parent) -#ifdef __GNUC__ -#define STATIC_UPCAST(to, from, obj) __extension__({ \ - static_assert(__builtin_types_compatible_p(from, __typeof(*(obj))), \ - "Invalid upcast object from type"); \ - (to*)((char*)(obj) - offsetof(to, from##_parent)); \ -}) -#else -#define STATIC_UPCAST(to, from, obj) ((to*)((char*)(obj) - offsetof(to, from##_parent))) -#endif - -#define DECLARE_FORWARD(T1, T2, rettype, func) \ -rettype T1##_##func(T1 *obj) \ -{ return T2##_##func(STATIC_CAST(T2, obj)); } - -#define DECLARE_FORWARD1(T1, T2, rettype, func, argtype1) \ -rettype T1##_##func(T1 *obj, argtype1 a) \ -{ return T2##_##func(STATIC_CAST(T2, obj), a); } - -#define DECLARE_FORWARD2(T1, T2, rettype, func, argtype1, argtype2) \ -rettype T1##_##func(T1 *obj, argtype1 a, argtype2 b) \ -{ return T2##_##func(STATIC_CAST(T2, obj), a, b); } - -#define DECLARE_FORWARD3(T1, T2, rettype, func, argtype1, argtype2, argtype3) \ -rettype T1##_##func(T1 *obj, argtype1 a, argtype2 b, argtype3 c) \ -{ return T2##_##func(STATIC_CAST(T2, obj), a, b, c); } - - -#define GET_VTABLE1(T1) (&(T1##_vtable)) -#define GET_VTABLE2(T1, T2) (&(T1##_##T2##_vtable)) - -#define SET_VTABLE1(T1, obj) ((obj)->vtbl = GET_VTABLE1(T1)) -#define SET_VTABLE2(T1, T2, obj) (STATIC_CAST(T2, obj)->vtbl = GET_VTABLE2(T1, T2)) - -#define DECLARE_THUNK(T1, T2, rettype, func) \ -static rettype T1##_##T2##_##func(T2 *obj) \ -{ return T1##_##func(STATIC_UPCAST(T1, T2, obj)); } - -#define DECLARE_THUNK1(T1, T2, rettype, func, argtype1) \ -static rettype T1##_##T2##_##func(T2 *obj, argtype1 a) \ -{ return T1##_##func(STATIC_UPCAST(T1, T2, obj), a); } - -#define DECLARE_THUNK2(T1, T2, rettype, func, argtype1, argtype2) \ -static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b) \ -{ return T1##_##func(STATIC_UPCAST(T1, T2, obj), a, b); } - -#define DECLARE_THUNK3(T1, T2, rettype, func, argtype1, argtype2, argtype3) \ -static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b, argtype3 c) \ -{ return T1##_##func(STATIC_UPCAST(T1, T2, obj), a, b, c); } - -#define DECLARE_DEFAULT_ALLOCATORS(T) \ -static void* T##_New(size_t size) { return malloc(size); } \ -static void T##_Delete(void *ptr) { free(ptr); } - -/* Helper to extract an argument list for VCALL. Not used directly. */ -#define EXTRACT_VCALL_ARGS(...) __VA_ARGS__)) - -/* Call a "virtual" method on an object, with arguments. */ -#define V(obj, func) ((obj)->vtbl->func((obj), EXTRACT_VCALL_ARGS -/* Call a "virtual" method on an object, with no arguments. */ -#define V0(obj, func) ((obj)->vtbl->func((obj) EXTRACT_VCALL_ARGS - -#define DELETE_OBJ(obj) do { \ - if((obj) != NULL) \ - { \ - V0((obj),Destruct)(); \ - V0((obj),Delete)(); \ - } \ -} while(0) - - -#ifdef __cplusplus -extern "C" { -#endif - -struct Hrtf; - - -#define DEFAULT_OUTPUT_RATE (44100) -#define MIN_OUTPUT_RATE (8000) - - -/* Find the next power-of-2 for non-power-of-2 numbers. */ -inline ALuint NextPowerOf2(ALuint value) -{ - if(value > 0) - { - value--; - value |= value>>1; - value |= value>>2; - value |= value>>4; - value |= value>>8; - value |= value>>16; - } - return value+1; -} - -/* Fast float-to-int conversion. Assumes the FPU is already in round-to-zero - * mode. */ -inline ALint fastf2i(ALfloat f) -{ -#ifdef HAVE_LRINTF - return lrintf(f); -#elif defined(_MSC_VER) && defined(_M_IX86) - ALint i; - __asm fld f - __asm fistp i - return i; -#else - return (ALint)f; -#endif -} - -/* Fast float-to-uint conversion. Assumes the FPU is already in round-to-zero - * mode. */ -inline ALuint fastf2u(ALfloat f) -{ return fastf2i(f); } - - -enum DevProbe { - ALL_DEVICE_PROBE, - CAPTURE_DEVICE_PROBE -}; - -typedef struct { - ALCenum (*OpenPlayback)(ALCdevice*, const ALCchar*); - void (*ClosePlayback)(ALCdevice*); - ALCboolean (*ResetPlayback)(ALCdevice*); - ALCboolean (*StartPlayback)(ALCdevice*); - void (*StopPlayback)(ALCdevice*); - - ALCenum (*OpenCapture)(ALCdevice*, const ALCchar*); - void (*CloseCapture)(ALCdevice*); - void (*StartCapture)(ALCdevice*); - 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); -ALCboolean alc_opensl_init(BackendFuncs *func_list); -void alc_opensl_deinit(void); -void alc_opensl_probe(enum DevProbe type); -ALCboolean alc_qsa_init(BackendFuncs *func_list); -void alc_qsa_deinit(void); -void alc_qsa_probe(enum DevProbe type); - -struct ALCbackend; - - -enum DistanceModel { - InverseDistanceClamped = AL_INVERSE_DISTANCE_CLAMPED, - LinearDistanceClamped = AL_LINEAR_DISTANCE_CLAMPED, - ExponentDistanceClamped = AL_EXPONENT_DISTANCE_CLAMPED, - InverseDistance = AL_INVERSE_DISTANCE, - LinearDistance = AL_LINEAR_DISTANCE, - ExponentDistance = AL_EXPONENT_DISTANCE, - DisableDistance = AL_NONE, - - DefaultDistanceModel = InverseDistanceClamped -}; - -enum Resampler { - PointResampler, - LinearResampler, - CubicResampler, - - ResamplerMax, -}; - -enum Channel { - FrontLeft = 0, - FrontRight, - FrontCenter, - LFE, - BackLeft, - BackRight, - BackCenter, - SideLeft, - SideRight, - - MaxChannels, -}; - - -/* Device formats */ -enum DevFmtType { - DevFmtByte = ALC_BYTE_SOFT, - DevFmtUByte = ALC_UNSIGNED_BYTE_SOFT, - DevFmtShort = ALC_SHORT_SOFT, - DevFmtUShort = ALC_UNSIGNED_SHORT_SOFT, - DevFmtInt = ALC_INT_SOFT, - DevFmtUInt = ALC_UNSIGNED_INT_SOFT, - DevFmtFloat = ALC_FLOAT_SOFT, - - DevFmtTypeDefault = DevFmtFloat -}; -enum DevFmtChannels { - DevFmtMono = ALC_MONO_SOFT, - DevFmtStereo = ALC_STEREO_SOFT, - DevFmtQuad = ALC_QUAD_SOFT, - DevFmtX51 = ALC_5POINT1_SOFT, - DevFmtX61 = ALC_6POINT1_SOFT, - DevFmtX71 = ALC_7POINT1_SOFT, - - /* Similar to 5.1, except using the side channels instead of back */ - DevFmtX51Side = 0x80000000, - - DevFmtChannelsDefault = DevFmtStereo -}; - -ALuint BytesFromDevFmt(enum DevFmtType type) DECL_CONST; -ALuint ChannelsFromDevFmt(enum DevFmtChannels chans) DECL_CONST; -inline ALuint FrameSizeFromDevFmt(enum DevFmtChannels chans, enum DevFmtType type) -{ - return ChannelsFromDevFmt(chans) * BytesFromDevFmt(type); -} - - -extern const struct EffectList { - const char *name; - int type; - const char *ename; - ALenum val; -} EffectList[]; - - -enum DeviceType { - Playback, - Capture, - Loopback -}; - - -/* Size for temporary storage of buffer data, in ALfloats. Larger values need - * more memory, while smaller values may need more iterations. The value needs - * to be a sensible size, however, as it constrains the max stepping value used - * for mixing, as well as the maximum number of samples per mixing iteration. - */ -#define BUFFERSIZE (2048u) - - -struct ALCdevice_struct -{ - RefCount ref; - - ALCboolean Connected; - enum DeviceType Type; - - ALuint Frequency; - ALuint UpdateSize; - ALuint NumUpdates; - enum DevFmtChannels FmtChans; - enum DevFmtType FmtType; - - al_string DeviceName; - - ATOMIC(ALCenum) LastError; - - // Maximum number of sources that can be created - ALuint MaxNoOfSources; - // Maximum number of slots that can be created - ALuint AuxiliaryEffectSlotMax; - - ALCuint NumMonoSources; - ALCuint NumStereoSources; - ALuint NumAuxSends; - - // Map of Buffers for this device - UIntMap BufferMap; - - // Map of Effects for this device - UIntMap EffectMap; - - // Map of Filters for this device - UIntMap FilterMap; - - // Map of Soundfonts for this device - UIntMap SfontMap; - - // Map of Presets for this device - UIntMap PresetMap; - - // Map of Fontsounds for this device - UIntMap FontsoundMap; - - /* Default soundfont (accessible as ID 0) */ - struct ALsoundfont *DefaultSfont; - - /* MIDI synth engine */ - struct MidiSynth *Synth; - - /* HRTF filter tables */ - const struct Hrtf *Hrtf; - - // Stereo-to-binaural filter - struct bs2b *Bs2b; - ALCint Bs2bLevel; - - // Device flags - ALuint Flags; - - ALuint ChannelOffsets[MaxChannels]; - - enum Channel Speaker2Chan[MaxChannels]; - ALfloat SpeakerAngle[MaxChannels]; - ALuint NumChan; - - ALuint64 ClockBase; - ALuint SamplesDone; - - /* Temp storage used for each source when mixing. */ - alignas(16) ALfloat SourceData[BUFFERSIZE]; - alignas(16) ALfloat ResampledData[BUFFERSIZE]; - alignas(16) ALfloat FilteredData[BUFFERSIZE]; - - // Dry path buffer mix - alignas(16) ALfloat DryBuffer[MaxChannels][BUFFERSIZE]; - - /* Running count of the mixer invocations, in 31.1 fixed point. This - * actually increments *twice* when mixing, first at the start and then at - * the end, so the bottom bit indicates if the device is currently mixing - * and the upper bits indicates how many mixes have been done. - */ - RefCount MixCount; - - /* Default effect slot */ - struct ALeffectslot *DefaultSlot; - - // Contexts created on this device - ATOMIC(ALCcontext*) ContextList; - - struct ALCbackend *Backend; - - void *ExtraData; // For the backend's use - - ALCdevice *volatile next; - - /* Memory space used by the default slot (Playback devices only) */ - alignas(16) ALCbyte _slot_mem[]; -}; - -// Frequency was requested by the app or config file -#define DEVICE_FREQUENCY_REQUEST (1<<1) -// Channel configuration was requested by the config file -#define DEVICE_CHANNELS_REQUEST (1<<2) -// Sample type was requested by the config file -#define DEVICE_SAMPLE_TYPE_REQUEST (1<<3) -// HRTF was requested by the app -#define DEVICE_HRTF_REQUEST (1<<4) - -// Stereo sources cover 120-degree angles around +/-90 -#define DEVICE_WIDE_STEREO (1<<16) - -// Specifies if the DSP is paused at user request -#define DEVICE_PAUSED (1<<30) - -// Specifies if the device is currently running -#define DEVICE_RUNNING (1<<31) - -/* Invalid channel offset */ -#define INVALID_OFFSET (~0u) - - -/* Nanosecond resolution for the device clock time. */ -#define DEVICE_CLOCK_RES U64(1000000000) - - -/* Must be less than 15 characters (16 including terminating null) for - * compatibility with pthread_setname_np limitations. */ -#define MIXER_THREAD_NAME "alsoft-mixer" - - -struct ALCcontext_struct -{ - RefCount ref; - - struct ALlistener *Listener; - - UIntMap SourceMap; - UIntMap EffectSlotMap; - - ATOMIC(ALenum) LastError; - - ATOMIC(ALenum) UpdateSources; - - volatile enum DistanceModel DistanceModel; - volatile ALboolean SourceDistanceModel; - - volatile ALfloat DopplerFactor; - volatile ALfloat DopplerVelocity; - volatile ALfloat SpeedOfSound; - volatile ALenum DeferUpdates; - - struct ALactivesource **ActiveSources; - ALsizei ActiveSourceCount; - ALsizei MaxActiveSources; - - VECTOR(struct ALeffectslot*) ActiveAuxSlots; - - ALCdevice *Device; - const ALCchar *ExtensionList; - - ALCcontext *volatile next; - - /* Memory space used by the listener */ - alignas(16) ALCbyte _listener_mem[]; -}; - -ALCcontext *GetContextRef(void); - -void ALCcontext_IncRef(ALCcontext *context); -void ALCcontext_DecRef(ALCcontext *context); - -void AppendAllDevicesList(const ALCchar *name); -void AppendCaptureDeviceList(const ALCchar *name); - -ALint64 ALCdevice_GetLatencyDefault(ALCdevice *device); - -void ALCdevice_Lock(ALCdevice *device); -void ALCdevice_Unlock(ALCdevice *device); -ALint64 ALCdevice_GetLatency(ALCdevice *device); - -inline void LockContext(ALCcontext *context) -{ ALCdevice_Lock(context->Device); } - -inline void UnlockContext(ALCcontext *context) -{ ALCdevice_Unlock(context->Device); } - - -void *al_malloc(size_t alignment, size_t size); -void *al_calloc(size_t alignment, size_t size); -void al_free(void *ptr); - - -typedef struct { -#ifdef HAVE_FENV_H - DERIVE_FROM_TYPE(fenv_t); -#else - int state; -#endif -#ifdef HAVE_SSE - int sse_state; -#endif -} FPUCtl; -void SetMixerFPUMode(FPUCtl *ctl); -void RestoreFPUMode(const FPUCtl *ctl); - - -typedef struct RingBuffer RingBuffer; -RingBuffer *CreateRingBuffer(ALsizei frame_size, ALsizei length); -void DestroyRingBuffer(RingBuffer *ring); -ALsizei RingBufferSize(RingBuffer *ring); -void WriteRingBuffer(RingBuffer *ring, const ALubyte *data, ALsizei len); -void ReadRingBuffer(RingBuffer *ring, ALubyte *data, ALsizei len); - -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); - -void SetRTPriority(void); - -void SetDefaultChannelOrder(ALCdevice *device); -void SetDefaultWFXChannelOrder(ALCdevice *device); - -const ALCchar *DevFmtTypeString(enum DevFmtType type) DECL_CONST; -const ALCchar *DevFmtChannelsString(enum DevFmtChannels chans) DECL_CONST; - - -extern FILE *LogFile; - -#if defined(__GNUC__) && !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); -#define AL_PRINT(T, ...) al_print((T), __FUNCTION__, __VA_ARGS__) -#endif - -enum LogLevel { - NoLog, - LogError, - LogWarning, - LogTrace, - LogRef -}; -extern enum LogLevel LogLevel; - -#define TRACEREF(...) do { \ - if(LogLevel >= LogRef) \ - AL_PRINT("(--)", __VA_ARGS__); \ -} while(0) - -#define TRACE(...) do { \ - if(LogLevel >= LogTrace) \ - AL_PRINT("(II)", __VA_ARGS__); \ -} while(0) - -#define WARN(...) do { \ - if(LogLevel >= LogWarning) \ - AL_PRINT("(WW)", __VA_ARGS__); \ -} while(0) - -#define ERR(...) do { \ - if(LogLevel >= LogError) \ - AL_PRINT("(EE)", __VA_ARGS__); \ -} while(0) - - -extern ALint RTPrioLevel; - - -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, -}; - -void FillCPUCaps(ALuint capfilter); - -FILE *OpenDataFile(const char *fname, 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]; - - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/love/src/jni/openal-soft-1.17.0/OpenAL32/Include/alMidi.h b/love/src/jni/openal-soft-1.17.0/OpenAL32/Include/alMidi.h deleted file mode 100644 index 9d9fa6c4..00000000 --- a/love/src/jni/openal-soft-1.17.0/OpenAL32/Include/alMidi.h +++ /dev/null @@ -1,172 +0,0 @@ -#ifndef ALMIDI_H -#define ALMIDI_H - -#include "alMain.h" -#include "atomic.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct ALsfmodulator { - struct { - ALenum Input; - ALenum Type; - ALenum Form; - } Source[2]; - ALint Amount; - ALenum TransformOp; - ALenum Dest; -} ALsfmodulator; - -typedef struct ALenvelope { - ALint DelayTime; - ALint AttackTime; - ALint HoldTime; - ALint DecayTime; - ALint SustainAttn; - ALint ReleaseTime; - ALint KeyToHoldTime; - ALint KeyToDecayTime; -} ALenvelope; - - -typedef struct ALfontsound { - RefCount ref; - - struct ALbuffer *Buffer; - - ALint MinKey, MaxKey; - ALint MinVelocity, MaxVelocity; - - ALint ModLfoToPitch; - ALint VibratoLfoToPitch; - ALint ModEnvToPitch; - - ALint FilterCutoff; - ALint FilterQ; - ALint ModLfoToFilterCutoff; - ALint ModEnvToFilterCutoff; - ALint ModLfoToVolume; - - ALint ChorusSend; - ALint ReverbSend; - - ALint Pan; - - struct { - ALint Delay; - ALint Frequency; - } ModLfo; - struct { - ALint Delay; - ALint Frequency; - } VibratoLfo; - - ALenvelope ModEnv; - ALenvelope VolEnv; - - ALint Attenuation; - - ALint CoarseTuning; - ALint FineTuning; - - ALenum LoopMode; - - ALint TuningScale; - - ALint ExclusiveClass; - - ALuint Start; - ALuint End; - ALuint LoopStart; - ALuint LoopEnd; - ALuint SampleRate; - ALubyte PitchKey; - ALbyte PitchCorrection; - ALenum SampleType; - struct ALfontsound *Link; - - /* NOTE: Each map entry contains *four* (4) ALsfmodulator objects. */ - UIntMap ModulatorMap; - - ALuint id; -} ALfontsound; - -void ALfontsound_setPropi(ALfontsound *self, ALCcontext *context, ALenum param, ALint value); -void ALfontsound_setModStagei(ALfontsound *self, ALCcontext *context, ALsizei stage, ALenum param, ALint value); - -ALfontsound *NewFontsound(ALCcontext *context); -void DeleteFontsound(ALCdevice *device, ALfontsound *sound); - -inline struct ALfontsound *LookupFontsound(ALCdevice *device, ALuint id) -{ return (struct ALfontsound*)LookupUIntMapKey(&device->FontsoundMap, id); } -inline struct ALfontsound *RemoveFontsound(ALCdevice *device, ALuint id) -{ return (struct ALfontsound*)RemoveUIntMapKey(&device->FontsoundMap, id); } - -void ReleaseALFontsounds(ALCdevice *device); - - -typedef struct ALsfpreset { - RefCount ref; - - ALint Preset; /* a.k.a. MIDI program number */ - ALint Bank; /* MIDI bank 0...127, or percussion (bank 128) */ - - ALfontsound **Sounds; - ALsizei NumSounds; - - ALuint id; -} ALsfpreset; - -ALsfpreset *NewPreset(ALCcontext *context); -void DeletePreset(ALCdevice *device, ALsfpreset *preset); - -inline struct ALsfpreset *LookupPreset(ALCdevice *device, ALuint id) -{ return (struct ALsfpreset*)LookupUIntMapKey(&device->PresetMap, id); } -inline struct ALsfpreset *RemovePreset(ALCdevice *device, ALuint id) -{ return (struct ALsfpreset*)RemoveUIntMapKey(&device->PresetMap, id); } - -void ReleaseALPresets(ALCdevice *device); - - -typedef struct ALsoundfont { - RefCount ref; - - ALsfpreset **Presets; - ALsizei NumPresets; - - RWLock Lock; - - ALuint id; -} ALsoundfont; - -ALsoundfont *ALsoundfont_getDefSoundfont(ALCcontext *context); -void ALsoundfont_deleteSoundfont(ALsoundfont *self, ALCdevice *device); - -inline struct ALsoundfont *LookupSfont(ALCdevice *device, ALuint id) -{ return (struct ALsoundfont*)LookupUIntMapKey(&device->SfontMap, id); } -inline struct ALsoundfont *RemoveSfont(ALCdevice *device, ALuint id) -{ return (struct ALsoundfont*)RemoveUIntMapKey(&device->SfontMap, id); } - -void ReleaseALSoundfonts(ALCdevice *device); - - -inline ALboolean IsValidCtrlInput(int cc) -{ - /* These correspond to MIDI functions, not real controller values. */ - if(cc == 0 || cc == 6 || cc == 32 || cc == 38 || (cc >= 98 && cc <= 101) || cc >= 120) - return AL_FALSE; - /* These are the LSB components of CC0...CC31, which are automatically used when - * reading the MSB controller value. */ - if(cc >= 32 && cc <= 63) - return AL_FALSE; - /* All the rest are okay! */ - return AL_TRUE; -} - -#ifdef __cplusplus -} -#endif - -#endif /* ALMIDI_H */ diff --git a/love/src/jni/openal-soft-1.17.0/OpenAL32/Include/alSource.h b/love/src/jni/openal-soft-1.17.0/OpenAL32/Include/alSource.h deleted file mode 100644 index 8d74fc54..00000000 --- a/love/src/jni/openal-soft-1.17.0/OpenAL32/Include/alSource.h +++ /dev/null @@ -1,147 +0,0 @@ -#ifndef _AL_SOURCE_H_ -#define _AL_SOURCE_H_ - -#define MAX_SENDS 4 - -#include "alMain.h" -#include "alu.h" -#include "hrtf.h" - -#ifdef __cplusplus -extern "C" { -#endif - -extern enum Resampler DefaultResampler; - -extern const ALsizei ResamplerPadding[ResamplerMax]; -extern const ALsizei ResamplerPrePadding[ResamplerMax]; - - -typedef struct ALbufferlistitem { - struct ALbuffer *buffer; - struct ALbufferlistitem *volatile next; - struct ALbufferlistitem *volatile prev; -} ALbufferlistitem; - - -typedef struct ALactivesource { - struct ALsource *Source; - - /** Method to update mixing parameters. */ - ALvoid (*Update)(struct ALactivesource *self, const ALCcontext *context); - - /** Current target parameters used for mixing. */ - ALint Step; - - ALboolean IsHrtf; - - ALuint Offset; /* Number of output samples mixed since starting. */ - - DirectParams Direct; - SendParams Send[MAX_SENDS]; -} ALactivesource; - - -typedef struct ALsource { - /** Source properties. */ - volatile ALfloat Pitch; - volatile ALfloat Gain; - volatile ALfloat OuterGain; - volatile ALfloat MinGain; - volatile ALfloat MaxGain; - volatile ALfloat InnerAngle; - volatile ALfloat OuterAngle; - volatile ALfloat RefDistance; - volatile ALfloat MaxDistance; - volatile ALfloat RollOffFactor; - volatile ALfloat Position[3]; - volatile ALfloat Velocity[3]; - volatile ALfloat Orientation[3]; - volatile ALboolean HeadRelative; - volatile ALboolean Looping; - volatile enum DistanceModel DistanceModel; - volatile ALboolean DirectChannels; - - volatile ALboolean DryGainHFAuto; - volatile ALboolean WetGainAuto; - volatile ALboolean WetGainHFAuto; - volatile ALfloat OuterGainHF; - - volatile ALfloat AirAbsorptionFactor; - volatile ALfloat RoomRolloffFactor; - volatile ALfloat DopplerFactor; - - volatile ALfloat Radius; - - enum Resampler Resampler; - - /** - * Last user-specified offset, and the offset type (bytes, samples, or - * seconds). - */ - ALdouble Offset; - ALenum OffsetType; - - /** Source type (static, streaming, or undetermined) */ - volatile ALint SourceType; - - /** Source state (initial, playing, paused, or stopped) */ - volatile ALenum state; - ALenum new_state; - - /** - * Source offset in samples, relative to the currently playing buffer, NOT - * the whole queue, and the fractional (fixed-point) offset to the next - * sample. - */ - ALuint position; - ALuint position_fraction; - - /** Source Buffer Queue info. */ - ATOMIC(ALbufferlistitem*) queue; - ATOMIC(ALbufferlistitem*) current_buffer; - RWLock queue_lock; - - /** Current buffer sample info. */ - ALuint NumChannels; - ALuint SampleSize; - - /** Direct filter and auxiliary send info. */ - struct { - ALfloat Gain; - ALfloat GainHF; - ALfloat HFReference; - ALfloat GainLF; - ALfloat LFReference; - } Direct; - struct { - struct ALeffectslot *Slot; - ALfloat Gain; - ALfloat GainHF; - ALfloat HFReference; - ALfloat GainLF; - ALfloat LFReference; - } Send[MAX_SENDS]; - - /** Source needs to update its mixing parameters. */ - ATOMIC(ALenum) NeedsUpdate; - - /** Self ID */ - ALuint id; -} ALsource; - -inline struct ALsource *LookupSource(ALCcontext *context, ALuint id) -{ return (struct ALsource*)LookupUIntMapKey(&context->SourceMap, id); } -inline struct ALsource *RemoveSource(ALCcontext *context, ALuint id) -{ return (struct ALsource*)RemoveUIntMapKey(&context->SourceMap, id); } - -ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state); -ALboolean ApplyOffset(ALsource *Source); - -ALvoid ReleaseALSources(ALCcontext *Context); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/love/src/jni/openal-soft-1.17.0/OpenAL32/Include/alu.h b/love/src/jni/openal-soft-1.17.0/OpenAL32/Include/alu.h deleted file mode 100644 index 7727c666..00000000 --- a/love/src/jni/openal-soft-1.17.0/OpenAL32/Include/alu.h +++ /dev/null @@ -1,236 +0,0 @@ -#ifndef _ALU_H_ -#define _ALU_H_ - -#include -#include -#ifdef HAVE_FLOAT_H -#include -#endif -#ifdef HAVE_IEEEFP_H -#include -#endif - -#include "alMain.h" -#include "alBuffer.h" -#include "alFilter.h" - -#include "hrtf.h" -#include "align.h" - - -#define F_PI (3.14159265358979323846f) -#define F_PI_2 (1.57079632679489661923f) -#define F_2PI (6.28318530717958647692f) - -#ifndef FLT_EPSILON -#define FLT_EPSILON (1.19209290e-07f) -#endif - -#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< b) ? b : a); } -inline ALfloat maxf(ALfloat a, ALfloat b) -{ return ((a > b) ? a : b); } -inline ALfloat clampf(ALfloat val, ALfloat min, ALfloat max) -{ return minf(max, maxf(min, val)); } - -inline ALdouble mind(ALdouble a, ALdouble b) -{ return ((a > b) ? b : a); } -inline ALdouble maxd(ALdouble a, ALdouble b) -{ return ((a > b) ? a : b); } -inline ALdouble clampd(ALdouble val, ALdouble min, ALdouble max) -{ return mind(max, maxd(min, val)); } - -inline ALuint minu(ALuint a, ALuint b) -{ return ((a > b) ? b : a); } -inline ALuint maxu(ALuint a, ALuint b) -{ return ((a > b) ? a : b); } -inline ALuint clampu(ALuint val, ALuint min, ALuint max) -{ return minu(max, maxu(min, val)); } - -inline ALint mini(ALint a, ALint b) -{ return ((a > b) ? b : a); } -inline ALint maxi(ALint a, ALint b) -{ return ((a > b) ? a : b); } -inline ALint clampi(ALint val, ALint min, ALint max) -{ return mini(max, maxi(min, val)); } - -inline ALint64 mini64(ALint64 a, ALint64 b) -{ return ((a > b) ? b : a); } -inline ALint64 maxi64(ALint64 a, ALint64 b) -{ return ((a > b) ? a : b); } -inline ALint64 clampi64(ALint64 val, ALint64 min, ALint64 max) -{ return mini64(max, maxi64(min, val)); } - -inline ALuint64 minu64(ALuint64 a, ALuint64 b) -{ return ((a > b) ? b : a); } -inline ALuint64 maxu64(ALuint64 a, ALuint64 b) -{ return ((a > b) ? a : b); } -inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max) -{ return minu64(max, maxu64(min, val)); } - - -inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu) -{ - return val1 + (val2-val1)*mu; -} -inline ALfloat cubic(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALfloat mu) -{ - ALfloat mu2 = mu*mu; - ALfloat a0 = -0.5f*val0 + 1.5f*val1 + -1.5f*val2 + 0.5f*val3; - ALfloat a1 = val0 + -2.5f*val1 + 2.0f*val2 + -0.5f*val3; - ALfloat a2 = -0.5f*val0 + 0.5f*val2; - ALfloat a3 = val1; - - return a0*mu*mu2 + a1*mu2 + a2*mu + a3; -} - - -ALvoid aluInitPanning(ALCdevice *Device); - -/** - * ComputeAngleGains - * - * Sets channel gains based on a given source's angle and its half-width. The - * angle and hwidth parameters are in radians. - */ -void ComputeAngleGains(const ALCdevice *device, ALfloat angle, ALfloat hwidth, ALfloat ingain, ALfloat gains[MaxChannels]); - -/** - * SetGains - * - * Helper to set the appropriate channels to the specified gain. - */ -inline void SetGains(const ALCdevice *device, ALfloat ingain, ALfloat gains[MaxChannels]) -{ - ComputeAngleGains(device, 0.0f, F_PI, ingain, gains); -} - - -ALvoid CalcSourceParams(struct ALactivesource *src, const ALCcontext *ALContext); -ALvoid CalcNonAttnSourceParams(struct ALactivesource *src, const ALCcontext *ALContext); - -ALvoid MixSource(struct ALactivesource *src, ALCdevice *Device, ALuint SamplesToDo); - -ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size); -/* Caller must lock the device. */ -ALvoid aluHandleDisconnect(ALCdevice *device); - -extern ALfloat ConeScale; -extern ALfloat ZScale; - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/love/src/jni/openal-soft-1.17.0/OpenAL32/alFontsound.c b/love/src/jni/openal-soft-1.17.0/OpenAL32/alFontsound.c deleted file mode 100644 index 3a8f1460..00000000 --- a/love/src/jni/openal-soft-1.17.0/OpenAL32/alFontsound.c +++ /dev/null @@ -1,1008 +0,0 @@ - -#include "config.h" - -#include -#include - -#include "alMain.h" -#include "alMidi.h" -#include "alError.h" -#include "alThunk.h" -#include "alBuffer.h" - -#include "midi/base.h" - - -extern inline struct ALfontsound *LookupFontsound(ALCdevice *device, ALuint id); -extern inline struct ALfontsound *RemoveFontsound(ALCdevice *device, ALuint id); - - -static void ALfontsound_Construct(ALfontsound *self); -static void ALfontsound_Destruct(ALfontsound *self); -void ALfontsound_setPropi(ALfontsound *self, ALCcontext *context, ALenum param, ALint value); -static ALsfmodulator *ALfontsound_getModStage(ALfontsound *self, ALsizei stage); -void ALfontsound_setModStagei(ALfontsound *self, ALCcontext *context, ALsizei stage, ALenum param, ALint value); -static void ALfontsound_getModStagei(ALfontsound *self, ALCcontext *context, ALsizei stage, ALenum param, ALint *values); - -static inline struct ALsfmodulator *LookupModulator(ALfontsound *sound, ALuint id) -{ - ALsfmodulator *mod = LookupUIntMapKey(&sound->ModulatorMap, id>>2); - if(mod) mod += id&3; - return mod; -} - - -AL_API void AL_APIENTRY alGenFontsoundsSOFT(ALsizei n, ALuint *ids) -{ - ALCcontext *context; - ALsizei cur = 0; - - context = GetContextRef(); - if(!context) return; - - if(!(n >= 0)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - - for(cur = 0;cur < n;cur++) - { - ALfontsound *sound = NewFontsound(context); - if(!sound) - { - alDeleteFontsoundsSOFT(cur, ids); - break; - } - - ids[cur] = sound->id; - } - -done: - ALCcontext_DecRef(context); -} - -AL_API ALvoid AL_APIENTRY alDeleteFontsoundsSOFT(ALsizei n, const ALuint *ids) -{ - ALCdevice *device; - ALCcontext *context; - ALfontsound *inst; - ALsizei i; - - context = GetContextRef(); - if(!context) return; - - if(!(n >= 0)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - - device = context->Device; - for(i = 0;i < n;i++) - { - /* Check for valid ID */ - if((inst=LookupFontsound(device, ids[i])) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); - if(ReadRef(&inst->ref) != 0) - SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done); - } - - for(i = 0;i < n;i++) - { - if((inst=LookupFontsound(device, ids[i])) != NULL) - DeleteFontsound(device, inst); - } - -done: - ALCcontext_DecRef(context); -} - -AL_API ALboolean AL_APIENTRY alIsFontsoundSOFT(ALuint id) -{ - ALCcontext *context; - ALboolean ret; - - context = GetContextRef(); - if(!context) return AL_FALSE; - - ret = LookupFontsound(context->Device, id) ? AL_TRUE : AL_FALSE; - - ALCcontext_DecRef(context); - - return ret; -} - -AL_API void AL_APIENTRY alFontsoundiSOFT(ALuint id, ALenum param, ALint value) -{ - ALCdevice *device; - ALCcontext *context; - ALfontsound *sound; - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - if(!(sound=LookupFontsound(device, id))) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); - if(ReadRef(&sound->ref) != 0) - SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done); - - ALfontsound_setPropi(sound, context, param, value); - -done: - ALCcontext_DecRef(context); -} - -AL_API void AL_APIENTRY alFontsound2iSOFT(ALuint id, ALenum param, ALint value1, ALint value2) -{ - ALCdevice *device; - ALCcontext *context; - ALfontsound *sound; - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - if(!(sound=LookupFontsound(device, id))) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); - if(ReadRef(&sound->ref) != 0) - SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done); - switch(param) - { - case AL_KEY_RANGE_SOFT: - if(!(value1 >= 0 && value1 <= 127 && value2 >= 0 && value2 <= 127 && value2 >= value1)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - sound->MinKey = value1; - sound->MaxKey = value2; - break; - - case AL_VELOCITY_RANGE_SOFT: - if(!(value1 >= 0 && value1 <= 127 && value2 >= 0 && value2 <= 127 && value2 >= value1)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - sound->MinVelocity = value1; - sound->MaxVelocity = value2; - break; - - default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); - } - -done: - ALCcontext_DecRef(context); -} - -AL_API void AL_APIENTRY alFontsoundivSOFT(ALuint id, ALenum param, const ALint *values) -{ - ALCdevice *device; - ALCcontext *context; - ALfontsound *sound; - - switch(param) - { - case AL_KEY_RANGE_SOFT: - case AL_VELOCITY_RANGE_SOFT: - alFontsound2iSOFT(id, param, values[0], values[1]); - return; - - case AL_MOD_LFO_TO_PITCH_SOFT: - case AL_VIBRATO_LFO_TO_PITCH_SOFT: - case AL_MOD_ENV_TO_PITCH_SOFT: - case AL_FILTER_CUTOFF_SOFT: - case AL_FILTER_RESONANCE_SOFT: - case AL_MOD_LFO_TO_FILTER_CUTOFF_SOFT: - case AL_MOD_ENV_TO_FILTER_CUTOFF_SOFT: - case AL_MOD_LFO_TO_VOLUME_SOFT: - case AL_CHORUS_SEND_SOFT: - case AL_REVERB_SEND_SOFT: - case AL_PAN_SOFT: - case AL_MOD_LFO_DELAY_SOFT: - case AL_MOD_LFO_FREQUENCY_SOFT: - case AL_VIBRATO_LFO_DELAY_SOFT: - case AL_VIBRATO_LFO_FREQUENCY_SOFT: - case AL_MOD_ENV_DELAYTIME_SOFT: - case AL_MOD_ENV_ATTACKTIME_SOFT: - case AL_MOD_ENV_HOLDTIME_SOFT: - case AL_MOD_ENV_DECAYTIME_SOFT: - case AL_MOD_ENV_SUSTAINVOLUME_SOFT: - case AL_MOD_ENV_RELEASETIME_SOFT: - case AL_MOD_ENV_KEY_TO_HOLDTIME_SOFT: - case AL_MOD_ENV_KEY_TO_DECAYTIME_SOFT: - case AL_VOLUME_ENV_DELAYTIME_SOFT: - case AL_VOLUME_ENV_ATTACKTIME_SOFT: - case AL_VOLUME_ENV_HOLDTIME_SOFT: - case AL_VOLUME_ENV_DECAYTIME_SOFT: - case AL_VOLUME_ENV_SUSTAINVOLUME_SOFT: - case AL_VOLUME_ENV_RELEASETIME_SOFT: - case AL_VOLUME_ENV_KEY_TO_HOLDTIME_SOFT: - case AL_VOLUME_ENV_KEY_TO_DECAYTIME_SOFT: - case AL_ATTENUATION_SOFT: - case AL_TUNING_COARSE_SOFT: - case AL_TUNING_FINE_SOFT: - case AL_LOOP_MODE_SOFT: - case AL_TUNING_SCALE_SOFT: - case AL_EXCLUSIVE_CLASS_SOFT: - case AL_SAMPLE_START_SOFT: - case AL_SAMPLE_END_SOFT: - case AL_SAMPLE_LOOP_START_SOFT: - case AL_SAMPLE_LOOP_END_SOFT: - case AL_SAMPLE_RATE_SOFT: - case AL_BASE_KEY_SOFT: - case AL_KEY_CORRECTION_SOFT: - case AL_SAMPLE_TYPE_SOFT: - case AL_FONTSOUND_LINK_SOFT: - alFontsoundiSOFT(id, param, values[0]); - return; - } - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - if(!(sound=LookupFontsound(device, id))) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); - if(ReadRef(&sound->ref) != 0) - SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done); - switch(param) - { - default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); - } - -done: - ALCcontext_DecRef(context); -} - -AL_API void AL_APIENTRY alGetFontsoundivSOFT(ALuint id, ALenum param, ALint *values) -{ - ALCdevice *device; - ALCcontext *context; - const ALfontsound *sound; - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - if(!(sound=LookupFontsound(device, id))) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); - switch(param) - { - case AL_BUFFER: - values[0] = (sound->Buffer ? sound->Buffer->id : 0); - break; - - case AL_MOD_LFO_TO_PITCH_SOFT: - values[0] = sound->ModLfoToPitch; - break; - - case AL_VIBRATO_LFO_TO_PITCH_SOFT: - values[0] = sound->VibratoLfoToPitch; - break; - - case AL_MOD_ENV_TO_PITCH_SOFT: - values[0] = sound->ModEnvToPitch; - break; - - case AL_FILTER_CUTOFF_SOFT: - values[0] = sound->FilterCutoff; - break; - - case AL_FILTER_RESONANCE_SOFT: - values[0] = sound->FilterQ; - break; - - case AL_MOD_LFO_TO_FILTER_CUTOFF_SOFT: - values[0] = sound->ModLfoToFilterCutoff; - break; - - case AL_MOD_ENV_TO_FILTER_CUTOFF_SOFT: - values[0] = sound->ModEnvToFilterCutoff; - break; - - case AL_MOD_LFO_TO_VOLUME_SOFT: - values[0] = sound->ModLfoToVolume; - break; - - case AL_CHORUS_SEND_SOFT: - values[0] = sound->ChorusSend; - break; - - case AL_REVERB_SEND_SOFT: - values[0] = sound->ReverbSend; - break; - - case AL_PAN_SOFT: - values[0] = sound->Pan; - break; - - case AL_MOD_LFO_DELAY_SOFT: - values[0] = sound->ModLfo.Delay; - break; - case AL_MOD_LFO_FREQUENCY_SOFT: - values[0] = sound->ModLfo.Frequency; - break; - - case AL_VIBRATO_LFO_DELAY_SOFT: - values[0] = sound->VibratoLfo.Delay; - break; - case AL_VIBRATO_LFO_FREQUENCY_SOFT: - values[0] = sound->VibratoLfo.Frequency; - break; - - case AL_MOD_ENV_DELAYTIME_SOFT: - values[0] = sound->ModEnv.DelayTime; - break; - case AL_MOD_ENV_ATTACKTIME_SOFT: - values[0] = sound->ModEnv.AttackTime; - break; - case AL_MOD_ENV_HOLDTIME_SOFT: - values[0] = sound->ModEnv.HoldTime; - break; - case AL_MOD_ENV_DECAYTIME_SOFT: - values[0] = sound->ModEnv.DecayTime; - break; - case AL_MOD_ENV_SUSTAINVOLUME_SOFT: - values[0] = sound->ModEnv.SustainAttn; - break; - case AL_MOD_ENV_RELEASETIME_SOFT: - values[0] = sound->ModEnv.ReleaseTime; - break; - case AL_MOD_ENV_KEY_TO_HOLDTIME_SOFT: - values[0] = sound->ModEnv.KeyToHoldTime; - break; - case AL_MOD_ENV_KEY_TO_DECAYTIME_SOFT: - values[0] = sound->ModEnv.KeyToDecayTime; - break; - - case AL_VOLUME_ENV_DELAYTIME_SOFT: - values[0] = sound->VolEnv.DelayTime; - break; - case AL_VOLUME_ENV_ATTACKTIME_SOFT: - values[0] = sound->VolEnv.AttackTime; - break; - case AL_VOLUME_ENV_HOLDTIME_SOFT: - values[0] = sound->VolEnv.HoldTime; - break; - case AL_VOLUME_ENV_DECAYTIME_SOFT: - values[0] = sound->VolEnv.DecayTime; - break; - case AL_VOLUME_ENV_SUSTAINVOLUME_SOFT: - values[0] = sound->VolEnv.SustainAttn; - break; - case AL_VOLUME_ENV_RELEASETIME_SOFT: - values[0] = sound->VolEnv.ReleaseTime; - break; - case AL_VOLUME_ENV_KEY_TO_HOLDTIME_SOFT: - values[0] = sound->VolEnv.KeyToHoldTime; - break; - case AL_VOLUME_ENV_KEY_TO_DECAYTIME_SOFT: - values[0] = sound->VolEnv.KeyToDecayTime; - break; - - case AL_KEY_RANGE_SOFT: - values[0] = sound->MinKey; - values[1] = sound->MaxKey; - break; - - case AL_VELOCITY_RANGE_SOFT: - values[0] = sound->MinVelocity; - values[1] = sound->MaxVelocity; - break; - - case AL_ATTENUATION_SOFT: - values[0] = sound->Attenuation; - break; - - case AL_TUNING_COARSE_SOFT: - values[0] = sound->CoarseTuning; - break; - case AL_TUNING_FINE_SOFT: - values[0] = sound->FineTuning; - break; - - case AL_LOOP_MODE_SOFT: - values[0] = sound->LoopMode; - break; - - case AL_TUNING_SCALE_SOFT: - values[0] = sound->TuningScale; - break; - - case AL_EXCLUSIVE_CLASS_SOFT: - values[0] = sound->ExclusiveClass; - break; - - case AL_SAMPLE_START_SOFT: - values[0] = sound->Start; - break; - - case AL_SAMPLE_END_SOFT: - values[0] = sound->End; - break; - - case AL_SAMPLE_LOOP_START_SOFT: - values[0] = sound->LoopStart; - break; - - case AL_SAMPLE_LOOP_END_SOFT: - values[0] = sound->LoopEnd; - break; - - case AL_SAMPLE_RATE_SOFT: - values[0] = sound->SampleRate; - break; - - case AL_BASE_KEY_SOFT: - values[0] = sound->PitchKey; - break; - - case AL_KEY_CORRECTION_SOFT: - values[0] = sound->PitchCorrection; - break; - - case AL_SAMPLE_TYPE_SOFT: - values[0] = sound->SampleType; - break; - - case AL_FONTSOUND_LINK_SOFT: - values[0] = (sound->Link ? sound->Link->id : 0); - break; - - default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); - } - -done: - ALCcontext_DecRef(context); -} - -AL_API void AL_APIENTRY alFontsoundModulatoriSOFT(ALuint id, ALsizei stage, ALenum param, ALint value) -{ - ALCdevice *device; - ALCcontext *context; - ALfontsound *sound; - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - if(!(sound=LookupFontsound(device, id))) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); - ALfontsound_setModStagei(sound, context, stage, param, value); - -done: - ALCcontext_DecRef(context); -} - -AL_API void AL_APIENTRY alGetFontsoundModulatorivSOFT(ALuint id, ALsizei stage, ALenum param, ALint *values) -{ - ALCdevice *device; - ALCcontext *context; - ALfontsound *sound; - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - if(!(sound=LookupFontsound(device, id))) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); - ALfontsound_getModStagei(sound, context, stage, param, values); - -done: - ALCcontext_DecRef(context); -} - - -ALfontsound *NewFontsound(ALCcontext *context) -{ - ALCdevice *device = context->Device; - ALfontsound *sound; - ALenum err; - - sound = calloc(1, sizeof(*sound)); - if(!sound) - SET_ERROR_AND_RETURN_VALUE(context, AL_OUT_OF_MEMORY, NULL); - ALfontsound_Construct(sound); - - err = NewThunkEntry(&sound->id); - if(err == AL_NO_ERROR) - err = InsertUIntMapEntry(&device->FontsoundMap, sound->id, sound); - if(err != AL_NO_ERROR) - { - ALfontsound_Destruct(sound); - memset(sound, 0, sizeof(*sound)); - free(sound); - - SET_ERROR_AND_RETURN_VALUE(context, err, NULL); - } - - return sound; -} - -void DeleteFontsound(ALCdevice *device, ALfontsound *sound) -{ - RemoveFontsound(device, sound->id); - - ALfontsound_Destruct(sound); - - memset(sound, 0, sizeof(*sound)); - free(sound); -} - - -static void ALfontsound_Construct(ALfontsound *self) -{ - InitRef(&self->ref, 0); - - self->Buffer = NULL; - - self->MinKey = 0; - self->MaxKey = 127; - self->MinVelocity = 0; - self->MaxVelocity = 127; - - self->ModLfoToPitch = 0; - self->VibratoLfoToPitch = 0; - self->ModEnvToPitch = 0; - - self->FilterCutoff = 13500; - self->FilterQ = 0; - self->ModLfoToFilterCutoff = 0; - self->ModEnvToFilterCutoff = 0; - self->ModLfoToVolume = 0; - - self->ChorusSend = 0; - self->ReverbSend = 0; - - self->Pan = 0; - - self->ModLfo.Delay = 0; - self->ModLfo.Frequency = 0; - - self->VibratoLfo.Delay = 0; - self->VibratoLfo.Frequency = 0; - - self->ModEnv.DelayTime = -12000; - self->ModEnv.AttackTime = -12000; - self->ModEnv.HoldTime = -12000; - self->ModEnv.DecayTime = -12000; - self->ModEnv.SustainAttn = 0; - self->ModEnv.ReleaseTime = -12000; - self->ModEnv.KeyToHoldTime = 0; - self->ModEnv.KeyToDecayTime = 0; - - self->VolEnv.DelayTime = -12000; - self->VolEnv.AttackTime = -12000; - self->VolEnv.HoldTime = -12000; - self->VolEnv.DecayTime = -12000; - self->VolEnv.SustainAttn = 0; - self->VolEnv.ReleaseTime = -12000; - self->VolEnv.KeyToHoldTime = 0; - self->VolEnv.KeyToDecayTime = 0; - - self->Attenuation = 0; - - self->CoarseTuning = 0; - self->FineTuning = 0; - - self->LoopMode = AL_NONE; - - self->TuningScale = 100; - - self->ExclusiveClass = 0; - - self->Start = 0; - self->End = 0; - self->LoopStart = 0; - self->LoopEnd = 0; - self->SampleRate = 0; - self->PitchKey = 0; - self->PitchCorrection = 0; - self->SampleType = AL_MONO_SOFT; - self->Link = NULL; - - InitUIntMap(&self->ModulatorMap, ~0); - - self->id = 0; -} - -static void ALfontsound_Destruct(ALfontsound *self) -{ - ALsizei i; - - FreeThunkEntry(self->id); - self->id = 0; - - if(self->Buffer) - DecrementRef(&self->Buffer->ref); - self->Buffer = NULL; - if(self->Link) - DecrementRef(&self->Link->ref); - self->Link = NULL; - - for(i = 0;i < self->ModulatorMap.size;i++) - { - free(self->ModulatorMap.array[i].value); - self->ModulatorMap.array[i].value = NULL; - } - ResetUIntMap(&self->ModulatorMap); -} - -void ALfontsound_setPropi(ALfontsound *self, ALCcontext *context, ALenum param, ALint value) -{ - ALfontsound *link; - ALbuffer *buffer; - - switch(param) - { - case AL_BUFFER: - buffer = value ? LookupBuffer(context->Device, value) : NULL; - if(value && !buffer) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - else if(buffer) - { - /* Buffer must have a non-0 length, and must be mono. */ - if(buffer->SampleLen <= 0 || buffer->FmtChannels != FmtMono) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - } - - if(buffer) IncrementRef(&buffer->ref); - if((buffer=ExchangePtr((XchgPtr*)&self->Buffer, buffer)) != NULL) - DecrementRef(&buffer->ref); - break; - - case AL_MOD_LFO_TO_PITCH_SOFT: - self->ModLfoToPitch = value; - break; - - case AL_VIBRATO_LFO_TO_PITCH_SOFT: - self->VibratoLfoToPitch = value; - break; - - case AL_MOD_ENV_TO_PITCH_SOFT: - self->ModEnvToPitch = value; - break; - - case AL_FILTER_CUTOFF_SOFT: - self->FilterCutoff = value; - break; - - case AL_FILTER_RESONANCE_SOFT: - if(!(value >= 0)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - self->FilterQ = value; - break; - - case AL_MOD_LFO_TO_FILTER_CUTOFF_SOFT: - self->ModLfoToFilterCutoff = value; - break; - - case AL_MOD_ENV_TO_FILTER_CUTOFF_SOFT: - self->ModEnvToFilterCutoff = value; - break; - - case AL_MOD_LFO_TO_VOLUME_SOFT: - self->ModLfoToVolume = value; - break; - - case AL_CHORUS_SEND_SOFT: - if(!(value >= 0 && value <= 1000)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - self->ChorusSend = value; - break; - case AL_REVERB_SEND_SOFT: - if(!(value >= 0 && value <= 1000)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - self->ReverbSend = value; - break; - - case AL_PAN_SOFT: - self->Pan = value; - break; - - case AL_MOD_LFO_DELAY_SOFT: - self->ModLfo.Delay = value; - break; - case AL_MOD_LFO_FREQUENCY_SOFT: - self->ModLfo.Frequency = value; - break; - - case AL_VIBRATO_LFO_DELAY_SOFT: - self->VibratoLfo.Delay = value; - break; - case AL_VIBRATO_LFO_FREQUENCY_SOFT: - self->VibratoLfo.Frequency = value; - break; - - case AL_MOD_ENV_DELAYTIME_SOFT: - self->ModEnv.DelayTime = value; - break; - case AL_MOD_ENV_ATTACKTIME_SOFT: - self->ModEnv.AttackTime = value; - break; - case AL_MOD_ENV_HOLDTIME_SOFT: - self->ModEnv.HoldTime = value; - break; - case AL_MOD_ENV_DECAYTIME_SOFT: - self->ModEnv.DecayTime = value; - break; - case AL_MOD_ENV_SUSTAINVOLUME_SOFT: - self->ModEnv.SustainAttn = value; - break; - case AL_MOD_ENV_RELEASETIME_SOFT: - self->ModEnv.ReleaseTime = value; - break; - case AL_MOD_ENV_KEY_TO_HOLDTIME_SOFT: - self->ModEnv.KeyToHoldTime = value; - break; - case AL_MOD_ENV_KEY_TO_DECAYTIME_SOFT: - self->ModEnv.KeyToDecayTime = value; - break; - - case AL_VOLUME_ENV_DELAYTIME_SOFT: - self->VolEnv.DelayTime = value; - break; - case AL_VOLUME_ENV_ATTACKTIME_SOFT: - self->VolEnv.AttackTime = value; - break; - case AL_VOLUME_ENV_HOLDTIME_SOFT: - self->VolEnv.HoldTime = value; - break; - case AL_VOLUME_ENV_DECAYTIME_SOFT: - self->VolEnv.DecayTime = value; - break; - case AL_VOLUME_ENV_SUSTAINVOLUME_SOFT: - self->VolEnv.SustainAttn = value; - break; - case AL_VOLUME_ENV_RELEASETIME_SOFT: - self->VolEnv.ReleaseTime = value; - break; - case AL_VOLUME_ENV_KEY_TO_HOLDTIME_SOFT: - self->VolEnv.KeyToHoldTime = value; - break; - case AL_VOLUME_ENV_KEY_TO_DECAYTIME_SOFT: - self->VolEnv.KeyToDecayTime = value; - break; - - case AL_ATTENUATION_SOFT: - if(!(value >= 0)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - self->Attenuation = value; - break; - - case AL_TUNING_COARSE_SOFT: - self->CoarseTuning = value; - break; - case AL_TUNING_FINE_SOFT: - self->FineTuning = value; - break; - - case AL_LOOP_MODE_SOFT: - if(!(value == AL_NONE || value == AL_LOOP_CONTINUOUS_SOFT || - value == AL_LOOP_UNTIL_RELEASE_SOFT)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - self->LoopMode = value; - break; - - case AL_TUNING_SCALE_SOFT: - self->TuningScale = value; - break; - - case AL_EXCLUSIVE_CLASS_SOFT: - self->ExclusiveClass = value; - break; - - case AL_SAMPLE_START_SOFT: - self->Start = value; - break; - - case AL_SAMPLE_END_SOFT: - self->End = value; - break; - - case AL_SAMPLE_LOOP_START_SOFT: - self->LoopStart = value; - break; - - case AL_SAMPLE_LOOP_END_SOFT: - self->LoopEnd = value; - break; - - case AL_SAMPLE_RATE_SOFT: - if(!(value > 0)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - self->SampleRate = value; - break; - - case AL_BASE_KEY_SOFT: - if(!((value >= 0 && value <= 127) || value == 255)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - self->PitchKey = value; - break; - - case AL_KEY_CORRECTION_SOFT: - if(!(value >= -99 && value <= 99)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - self->PitchCorrection = value; - break; - - case AL_SAMPLE_TYPE_SOFT: - if(!(value == AL_MONO_SOFT || value == AL_RIGHT_SOFT || value == AL_LEFT_SOFT)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - self->SampleType = value; - break; - - case AL_FONTSOUND_LINK_SOFT: - link = value ? LookupFontsound(context->Device, value) : NULL; - if(value && !link) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - - if(link) IncrementRef(&link->ref); - if((link=ExchangePtr((XchgPtr*)&self->Link, link)) != NULL) - DecrementRef(&link->ref); - break; - - default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); - } -} - -static ALsfmodulator *ALfontsound_getModStage(ALfontsound *self, ALsizei stage) -{ - ALsfmodulator *ret = LookupModulator(self, stage); - if(!ret) - { - static const ALsfmodulator moddef = { - { { AL_ONE_SOFT, AL_UNORM_SOFT, AL_LINEAR_SOFT }, - { AL_ONE_SOFT, AL_UNORM_SOFT, AL_LINEAR_SOFT } }, - 0, - AL_LINEAR_SOFT, - AL_NONE - }; - ret = malloc(sizeof(ALsfmodulator[4])); - ret[0] = moddef; - ret[1] = moddef; - ret[2] = moddef; - ret[3] = moddef; - InsertUIntMapEntry(&self->ModulatorMap, stage>>2, ret); - ret += stage&3; - } - return ret; -} - -void ALfontsound_setModStagei(ALfontsound *self, ALCcontext *context, ALsizei stage, ALenum param, ALint value) -{ - ALint srcidx = 0; - - if(ReadRef(&self->ref) != 0) - SET_ERROR_AND_RETURN(context, AL_INVALID_OPERATION); - switch(param) - { - case AL_SOURCE1_INPUT_SOFT: - srcidx++; - /* fall-through */ - case AL_SOURCE0_INPUT_SOFT: - if(!(value == AL_ONE_SOFT || value == AL_NOTEON_VELOCITY_SOFT || - value == AL_NOTEON_KEY_SOFT || value == AL_KEYPRESSURE_SOFT || - value == AL_CHANNELPRESSURE_SOFT || value == AL_PITCHBEND_SOFT || - value == AL_PITCHBEND_SENSITIVITY_SOFT || - IsValidCtrlInput(value))) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - ALfontsound_getModStage(self, stage)->Source[srcidx].Input = value; - break; - - case AL_SOURCE1_TYPE_SOFT: - srcidx++; - /* fall-through */ - case AL_SOURCE0_TYPE_SOFT: - if(!(value == AL_UNORM_SOFT || value == AL_UNORM_REV_SOFT || - value == AL_SNORM_SOFT || value == AL_SNORM_REV_SOFT)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - ALfontsound_getModStage(self, stage)->Source[srcidx].Type = value; - break; - - case AL_SOURCE1_FORM_SOFT: - srcidx++; - /* fall-through */ - case AL_SOURCE0_FORM_SOFT: - if(!(value == AL_LINEAR_SOFT || value == AL_CONCAVE_SOFT || - value == AL_CONVEX_SOFT || value == AL_SWITCH_SOFT)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - ALfontsound_getModStage(self, stage)->Source[srcidx].Form = value; - break; - - case AL_AMOUNT_SOFT: - ALfontsound_getModStage(self, stage)->Amount = value; - break; - - case AL_TRANSFORM_OP_SOFT: - if(!(value == AL_LINEAR_SOFT || value == AL_ABSOLUTE_SOFT)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - ALfontsound_getModStage(self, stage)->TransformOp = value; - break; - - case AL_DESTINATION_SOFT: - if(!(value == AL_MOD_LFO_TO_PITCH_SOFT || value == AL_VIBRATO_LFO_TO_PITCH_SOFT || - value == AL_MOD_ENV_TO_PITCH_SOFT || value == AL_FILTER_CUTOFF_SOFT || - value == AL_FILTER_RESONANCE_SOFT || value == AL_MOD_LFO_TO_FILTER_CUTOFF_SOFT || - value == AL_MOD_ENV_TO_FILTER_CUTOFF_SOFT || value == AL_MOD_LFO_TO_VOLUME_SOFT || - value == AL_CHORUS_SEND_SOFT || value == AL_REVERB_SEND_SOFT || value == AL_PAN_SOFT || - value == AL_MOD_LFO_DELAY_SOFT || value == AL_MOD_LFO_FREQUENCY_SOFT || - value == AL_VIBRATO_LFO_DELAY_SOFT || value == AL_VIBRATO_LFO_FREQUENCY_SOFT || - value == AL_MOD_ENV_DELAYTIME_SOFT || value == AL_MOD_ENV_ATTACKTIME_SOFT || - value == AL_MOD_ENV_HOLDTIME_SOFT || value == AL_MOD_ENV_DECAYTIME_SOFT || - value == AL_MOD_ENV_SUSTAINVOLUME_SOFT || value == AL_MOD_ENV_RELEASETIME_SOFT || - value == AL_MOD_ENV_KEY_TO_HOLDTIME_SOFT || value == AL_MOD_ENV_KEY_TO_DECAYTIME_SOFT || - value == AL_VOLUME_ENV_DELAYTIME_SOFT || value == AL_VOLUME_ENV_ATTACKTIME_SOFT || - value == AL_VOLUME_ENV_HOLDTIME_SOFT || value == AL_VOLUME_ENV_DECAYTIME_SOFT || - value == AL_VOLUME_ENV_SUSTAINVOLUME_SOFT || value == AL_VOLUME_ENV_RELEASETIME_SOFT || - value == AL_VOLUME_ENV_KEY_TO_HOLDTIME_SOFT || value == AL_VOLUME_ENV_KEY_TO_DECAYTIME_SOFT || - value == AL_ATTENUATION_SOFT || value == AL_TUNING_COARSE_SOFT || - value == AL_TUNING_FINE_SOFT || value == AL_TUNING_SCALE_SOFT)) - SET_ERROR_AND_RETURN(context, AL_INVALID_VALUE); - ALfontsound_getModStage(self, stage)->Dest = value; - break; - - default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); - } -} - -static void ALfontsound_getModStagei(ALfontsound *self, ALCcontext *context, ALsizei stage, ALenum param, ALint *values) -{ - ALsfmodulator *mod = LookupModulator(self, stage); - ALint srcidx = 0; - - switch(param) - { - case AL_SOURCE1_INPUT_SOFT: - srcidx++; - /* fall-through */ - case AL_SOURCE0_INPUT_SOFT: - values[0] = mod ? mod->Source[srcidx].Input : AL_ONE_SOFT; - break; - - case AL_SOURCE1_TYPE_SOFT: - srcidx++; - /* fall-through */ - case AL_SOURCE0_TYPE_SOFT: - values[0] = mod ? mod->Source[srcidx].Type : AL_UNORM_SOFT; - break; - - case AL_SOURCE1_FORM_SOFT: - srcidx++; - /* fall-through */ - case AL_SOURCE0_FORM_SOFT: - values[0] = mod ? mod->Source[srcidx].Form : AL_LINEAR_SOFT; - break; - - case AL_AMOUNT_SOFT: - values[0] = mod ? mod->Amount : 0; - break; - - case AL_TRANSFORM_OP_SOFT: - values[0] = mod ? mod->TransformOp : AL_LINEAR_SOFT; - break; - - case AL_DESTINATION_SOFT: - values[0] = mod ? mod->Dest : AL_NONE; - break; - - default: - SET_ERROR_AND_RETURN(context, AL_INVALID_ENUM); - } -} - - -/* ReleaseALFontsounds - * - * Called to destroy any fontsounds that still exist on the device - */ -void ReleaseALFontsounds(ALCdevice *device) -{ - ALsizei i; - for(i = 0;i < device->FontsoundMap.size;i++) - { - ALfontsound *temp = device->FontsoundMap.array[i].value; - device->FontsoundMap.array[i].value = NULL; - - ALfontsound_Destruct(temp); - - memset(temp, 0, sizeof(*temp)); - free(temp); - } -} diff --git a/love/src/jni/openal-soft-1.17.0/OpenAL32/alMidi.c b/love/src/jni/openal-soft-1.17.0/OpenAL32/alMidi.c deleted file mode 100644 index 015b1915..00000000 --- a/love/src/jni/openal-soft-1.17.0/OpenAL32/alMidi.c +++ /dev/null @@ -1,217 +0,0 @@ - -#include "config.h" - -#include -#include -#include -#include - -#include "alMain.h" -#include "alMidi.h" -#include "alError.h" -#include "alThunk.h" -#include "evtqueue.h" -#include "rwlock.h" -#include "alu.h" - -#include "midi/base.h" - - -MidiSynth *SynthCreate(ALCdevice *device) -{ - MidiSynth *synth = NULL; - if(!synth) synth = SSynth_create(device); - if(!synth) synth = FSynth_create(device); - if(!synth) synth = DSynth_create(device); - return synth; -} - - -AL_API void AL_APIENTRY alMidiSoundfontSOFT(ALuint id) -{ - alMidiSoundfontvSOFT(1, &id); -} - -AL_API void AL_APIENTRY alMidiSoundfontvSOFT(ALsizei count, const ALuint *ids) -{ - ALCdevice *device; - ALCcontext *context; - MidiSynth *synth; - ALenum err; - - context = GetContextRef(); - if(!context) return; - - if(count < 0) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - - device = context->Device; - synth = device->Synth; - - WriteLock(&synth->Lock); - if(synth->State == AL_PLAYING || synth->State == AL_PAUSED) - alSetError(context, AL_INVALID_OPERATION); - else - { - err = V(synth,selectSoundfonts)(context, count, ids); - if(err != AL_NO_ERROR) - alSetError(context, err); - } - WriteUnlock(&synth->Lock); - -done: - ALCcontext_DecRef(context); -} - - -AL_API void AL_APIENTRY alMidiEventSOFT(ALuint64SOFT time, ALenum event, ALsizei channel, ALsizei param1, ALsizei param2) -{ - ALCdevice *device; - ALCcontext *context; - ALenum err; - - context = GetContextRef(); - if(!context) return; - - if(!(event == AL_NOTEOFF_SOFT || event == AL_NOTEON_SOFT || - event == AL_KEYPRESSURE_SOFT || event == AL_CONTROLLERCHANGE_SOFT || - event == AL_PROGRAMCHANGE_SOFT || event == AL_CHANNELPRESSURE_SOFT || - event == AL_PITCHBEND_SOFT)) - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); - if(!(channel >= 0 && channel <= 15)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - if(!(param1 >= 0 && param1 <= 127)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - if(!(param2 >= 0 && param2 <= 127)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - - device = context->Device; - ALCdevice_Lock(device); - err = MidiSynth_insertEvent(device->Synth, time, event|channel, param1, param2); - ALCdevice_Unlock(device); - if(err != AL_NO_ERROR) - alSetError(context, err); - -done: - ALCcontext_DecRef(context); -} - -AL_API void AL_APIENTRY alMidiSysExSOFT(ALuint64SOFT time, const ALbyte *data, ALsizei size) -{ - ALCdevice *device; - ALCcontext *context; - ALenum err; - - context = GetContextRef(); - if(!context) return; - - if(!data || size < 0) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - - device = context->Device; - ALCdevice_Lock(device); - err = MidiSynth_insertSysExEvent(device->Synth, time, data, size); - ALCdevice_Unlock(device); - if(err != AL_NO_ERROR) - alSetError(context, err); - -done: - ALCcontext_DecRef(context); -} - -AL_API void AL_APIENTRY alMidiPlaySOFT(void) -{ - ALCcontext *context; - MidiSynth *synth; - - context = GetContextRef(); - if(!context) return; - - synth = context->Device->Synth; - WriteLock(&synth->Lock); - MidiSynth_setState(synth, AL_PLAYING); - WriteUnlock(&synth->Lock); - - ALCcontext_DecRef(context); -} - -AL_API void AL_APIENTRY alMidiPauseSOFT(void) -{ - ALCcontext *context; - MidiSynth *synth; - - context = GetContextRef(); - if(!context) return; - - synth = context->Device->Synth; - WriteLock(&synth->Lock); - MidiSynth_setState(synth, AL_PAUSED); - WriteUnlock(&synth->Lock); - - ALCcontext_DecRef(context); -} - -AL_API void AL_APIENTRY alMidiStopSOFT(void) -{ - ALCdevice *device; - ALCcontext *context; - MidiSynth *synth; - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - synth = device->Synth; - - WriteLock(&synth->Lock); - MidiSynth_setState(synth, AL_STOPPED); - - ALCdevice_Lock(device); - V0(synth,stop)(); - ALCdevice_Unlock(device); - WriteUnlock(&synth->Lock); - - ALCcontext_DecRef(context); -} - -AL_API void AL_APIENTRY alMidiResetSOFT(void) -{ - ALCdevice *device; - ALCcontext *context; - MidiSynth *synth; - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - synth = device->Synth; - - WriteLock(&synth->Lock); - MidiSynth_setState(synth, AL_INITIAL); - - ALCdevice_Lock(device); - V0(synth,reset)(); - ALCdevice_Unlock(device); - WriteUnlock(&synth->Lock); - - ALCcontext_DecRef(context); -} - - -AL_API void AL_APIENTRY alMidiGainSOFT(ALfloat value) -{ - ALCdevice *device; - ALCcontext *context; - - context = GetContextRef(); - if(!context) return; - - if(!(value >= 0.0f && isfinite(value))) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - - device = context->Device; - V(device->Synth,setGain)(value); - -done: - ALCcontext_DecRef(context); -} diff --git a/love/src/jni/openal-soft-1.17.0/OpenAL32/alPreset.c b/love/src/jni/openal-soft-1.17.0/OpenAL32/alPreset.c deleted file mode 100644 index 1934ba05..00000000 --- a/love/src/jni/openal-soft-1.17.0/OpenAL32/alPreset.c +++ /dev/null @@ -1,339 +0,0 @@ - -#include "config.h" - -#include -#include - -#include "alMain.h" -#include "alMidi.h" -#include "alError.h" -#include "alThunk.h" - -#include "midi/base.h" - - -extern inline struct ALsfpreset *LookupPreset(ALCdevice *device, ALuint id); -extern inline struct ALsfpreset *RemovePreset(ALCdevice *device, ALuint id); - -static void ALsfpreset_Construct(ALsfpreset *self); -static void ALsfpreset_Destruct(ALsfpreset *self); - - -AL_API void AL_APIENTRY alGenPresetsSOFT(ALsizei n, ALuint *ids) -{ - ALCcontext *context; - ALsizei cur = 0; - - context = GetContextRef(); - if(!context) return; - - if(!(n >= 0)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - - for(cur = 0;cur < n;cur++) - { - ALsfpreset *preset = NewPreset(context); - if(!preset) - { - alDeletePresetsSOFT(cur, ids); - break; - } - - ids[cur] = preset->id; - } - -done: - ALCcontext_DecRef(context); -} - -AL_API ALvoid AL_APIENTRY alDeletePresetsSOFT(ALsizei n, const ALuint *ids) -{ - ALCdevice *device; - ALCcontext *context; - ALsfpreset *preset; - ALsizei i; - - context = GetContextRef(); - if(!context) return; - - if(!(n >= 0)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - - device = context->Device; - for(i = 0;i < n;i++) - { - /* Check for valid ID */ - if((preset=LookupPreset(device, ids[i])) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); - if(ReadRef(&preset->ref) != 0) - SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done); - } - - for(i = 0;i < n;i++) - { - if((preset=LookupPreset(device, ids[i])) != NULL) - DeletePreset(device, preset); - } - -done: - ALCcontext_DecRef(context); -} - -AL_API ALboolean AL_APIENTRY alIsPresetSOFT(ALuint id) -{ - ALCcontext *context; - ALboolean ret; - - context = GetContextRef(); - if(!context) return AL_FALSE; - - ret = LookupPreset(context->Device, id) ? AL_TRUE : AL_FALSE; - - ALCcontext_DecRef(context); - - return ret; -} - -AL_API void AL_APIENTRY alPresetiSOFT(ALuint id, ALenum param, ALint value) -{ - ALCdevice *device; - ALCcontext *context; - ALsfpreset *preset; - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - if((preset=LookupPreset(device, id)) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); - if(ReadRef(&preset->ref) != 0) - SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done); - switch(param) - { - case AL_MIDI_PRESET_SOFT: - if(!(value >= 0 && value <= 127)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - preset->Preset = value; - break; - - case AL_MIDI_BANK_SOFT: - if(!(value >= 0 && value <= 128)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - preset->Bank = value; - break; - - default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); - } - -done: - ALCcontext_DecRef(context); -} - -AL_API void AL_APIENTRY alPresetivSOFT(ALuint id, ALenum param, const ALint *values) -{ - ALCdevice *device; - ALCcontext *context; - ALsfpreset *preset; - - switch(param) - { - case AL_MIDI_PRESET_SOFT: - case AL_MIDI_BANK_SOFT: - alPresetiSOFT(id, param, values[0]); - return; - } - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - if((preset=LookupPreset(device, id)) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); - if(ReadRef(&preset->ref) != 0) - SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done); - switch(param) - { - default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); - } - -done: - ALCcontext_DecRef(context); -} - -AL_API void AL_APIENTRY alGetPresetivSOFT(ALuint id, ALenum param, ALint *values) -{ - ALCdevice *device; - ALCcontext *context; - ALsfpreset *preset; - ALsizei i; - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - if((preset=LookupPreset(device, id)) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); - switch(param) - { - case AL_MIDI_PRESET_SOFT: - values[0] = preset->Preset; - break; - - case AL_MIDI_BANK_SOFT: - values[0] = preset->Bank; - break; - - case AL_FONTSOUNDS_SIZE_SOFT: - values[0] = preset->NumSounds; - break; - - case AL_FONTSOUNDS_SOFT: - for(i = 0;i < preset->NumSounds;i++) - values[i] = preset->Sounds[i]->id; - break; - - default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); - } - -done: - ALCcontext_DecRef(context); -} - -AL_API void AL_APIENTRY alPresetFontsoundsSOFT(ALuint id, ALsizei count, const ALuint *fsids) -{ - ALCdevice *device; - ALCcontext *context; - ALsfpreset *preset; - ALfontsound **sounds; - ALsizei i; - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - if(!(preset=LookupPreset(device, id))) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); - if(count < 0) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - - if(ReadRef(&preset->ref) != 0) - SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done); - - if(count == 0) - sounds = NULL; - else - { - sounds = calloc(count, sizeof(sounds[0])); - if(!sounds) - SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done); - - for(i = 0;i < count;i++) - { - if(!(sounds[i]=LookupFontsound(device, fsids[i]))) - { - free(sounds); - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - } - } - } - - for(i = 0;i < count;i++) - IncrementRef(&sounds[i]->ref); - - sounds = ExchangePtr((XchgPtr*)&preset->Sounds, sounds); - count = ExchangeInt(&preset->NumSounds, count); - - for(i = 0;i < count;i++) - DecrementRef(&sounds[i]->ref); - free(sounds); - -done: - ALCcontext_DecRef(context); -} - - -ALsfpreset *NewPreset(ALCcontext *context) -{ - ALCdevice *device = context->Device; - ALsfpreset *preset; - ALenum err; - - preset = calloc(1, sizeof(*preset)); - if(!preset) - SET_ERROR_AND_RETURN_VALUE(context, AL_OUT_OF_MEMORY, NULL); - ALsfpreset_Construct(preset); - - err = NewThunkEntry(&preset->id); - if(err == AL_NO_ERROR) - err = InsertUIntMapEntry(&device->PresetMap, preset->id, preset); - if(err != AL_NO_ERROR) - { - ALsfpreset_Destruct(preset); - memset(preset, 0, sizeof(*preset)); - free(preset); - - SET_ERROR_AND_RETURN_VALUE(context, err, NULL); - } - - return preset; -} - -void DeletePreset(ALCdevice *device, ALsfpreset *preset) -{ - RemovePreset(device, preset->id); - - ALsfpreset_Destruct(preset); - memset(preset, 0, sizeof(*preset)); - free(preset); -} - - -static void ALsfpreset_Construct(ALsfpreset *self) -{ - InitRef(&self->ref, 0); - - self->Preset = 0; - self->Bank = 0; - - self->Sounds = NULL; - self->NumSounds = 0; - - self->id = 0; -} - -static void ALsfpreset_Destruct(ALsfpreset *self) -{ - ALsizei i; - - FreeThunkEntry(self->id); - self->id = 0; - - for(i = 0;i < self->NumSounds;i++) - DecrementRef(&self->Sounds[i]->ref); - free(self->Sounds); - self->Sounds = NULL; - self->NumSounds = 0; -} - - -/* ReleaseALPresets - * - * Called to destroy any presets that still exist on the device - */ -void ReleaseALPresets(ALCdevice *device) -{ - ALsizei i; - for(i = 0;i < device->PresetMap.size;i++) - { - ALsfpreset *temp = device->PresetMap.array[i].value; - device->PresetMap.array[i].value = NULL; - - ALsfpreset_Destruct(temp); - - memset(temp, 0, sizeof(*temp)); - free(temp); - } -} diff --git a/love/src/jni/openal-soft-1.17.0/OpenAL32/alSoundfont.c b/love/src/jni/openal-soft-1.17.0/OpenAL32/alSoundfont.c deleted file mode 100644 index 30c97a3a..00000000 --- a/love/src/jni/openal-soft-1.17.0/OpenAL32/alSoundfont.c +++ /dev/null @@ -1,454 +0,0 @@ - -#include "config.h" - -#include -#include -#include -#include - -#include "alMain.h" -#include "alMidi.h" -#include "alThunk.h" -#include "alError.h" -#include - -#include "midi/base.h" - - -extern inline struct ALsoundfont *LookupSfont(ALCdevice *device, ALuint id); -extern inline struct ALsoundfont *RemoveSfont(ALCdevice *device, ALuint id); - -static void ALsoundfont_Construct(ALsoundfont *self); -static void ALsoundfont_Destruct(ALsoundfont *self); -void ALsoundfont_deleteSoundfont(ALsoundfont *self, ALCdevice *device); -ALsoundfont *ALsoundfont_getDefSoundfont(ALCcontext *context); -static size_t ALsoundfont_read(ALvoid *buf, size_t bytes, ALvoid *ptr); - - -AL_API void AL_APIENTRY alGenSoundfontsSOFT(ALsizei n, ALuint *ids) -{ - ALCdevice *device; - ALCcontext *context; - ALsizei cur = 0; - ALenum err; - - context = GetContextRef(); - if(!context) return; - - if(!(n >= 0)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - - device = context->Device; - for(cur = 0;cur < n;cur++) - { - ALsoundfont *sfont = calloc(1, sizeof(ALsoundfont)); - if(!sfont) - { - alDeleteSoundfontsSOFT(cur, ids); - SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done); - } - ALsoundfont_Construct(sfont); - - err = NewThunkEntry(&sfont->id); - if(err == AL_NO_ERROR) - err = InsertUIntMapEntry(&device->SfontMap, sfont->id, sfont); - if(err != AL_NO_ERROR) - { - ALsoundfont_Destruct(sfont); - memset(sfont, 0, sizeof(ALsoundfont)); - free(sfont); - - alDeleteSoundfontsSOFT(cur, ids); - SET_ERROR_AND_GOTO(context, err, done); - } - - ids[cur] = sfont->id; - } - -done: - ALCcontext_DecRef(context); -} - -AL_API ALvoid AL_APIENTRY alDeleteSoundfontsSOFT(ALsizei n, const ALuint *ids) -{ - ALCdevice *device; - ALCcontext *context; - ALsoundfont *sfont; - ALsizei i; - - context = GetContextRef(); - if(!context) return; - - if(!(n >= 0)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - - device = context->Device; - for(i = 0;i < n;i++) - { - /* Check for valid soundfont ID */ - if(ids[i] == 0) - { - if(!(sfont=device->DefaultSfont)) - continue; - } - else if((sfont=LookupSfont(device, ids[i])) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); - if(ReadRef(&sfont->ref) != 0) - SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done); - } - - for(i = 0;i < n;i++) - { - if(ids[i] == 0) - { - MidiSynth *synth = device->Synth; - WriteLock(&synth->Lock); - if(device->DefaultSfont != NULL) - ALsoundfont_deleteSoundfont(device->DefaultSfont, device); - device->DefaultSfont = NULL; - WriteUnlock(&synth->Lock); - continue; - } - else if((sfont=RemoveSfont(device, ids[i])) == NULL) - continue; - - ALsoundfont_Destruct(sfont); - - memset(sfont, 0, sizeof(*sfont)); - free(sfont); - } - -done: - ALCcontext_DecRef(context); -} - -AL_API ALboolean AL_APIENTRY alIsSoundfontSOFT(ALuint id) -{ - ALCcontext *context; - ALboolean ret; - - context = GetContextRef(); - if(!context) return AL_FALSE; - - ret = ((!id || LookupSfont(context->Device, id)) ? - AL_TRUE : AL_FALSE); - - ALCcontext_DecRef(context); - - return ret; -} - -AL_API void AL_APIENTRY alGetSoundfontivSOFT(ALuint id, ALenum param, ALint *values) -{ - ALCdevice *device; - ALCcontext *context; - ALsoundfont *sfont; - ALsizei i; - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - if(id == 0) - sfont = ALsoundfont_getDefSoundfont(context); - else if(!(sfont=LookupSfont(device, id))) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); - switch(param) - { - case AL_PRESETS_SIZE_SOFT: - values[0] = sfont->NumPresets; - break; - - case AL_PRESETS_SOFT: - for(i = 0;i < sfont->NumPresets;i++) - values[i] = sfont->Presets[i]->id; - break; - - default: - SET_ERROR_AND_GOTO(context, AL_INVALID_ENUM, done); - } - -done: - ALCcontext_DecRef(context); -} - -AL_API void AL_APIENTRY alSoundfontPresetsSOFT(ALuint id, ALsizei count, const ALuint *pids) -{ - ALCdevice *device; - ALCcontext *context; - ALsoundfont *sfont; - ALsfpreset **presets; - ALsizei i; - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - if(id == 0) - SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done); - if(!(sfont=LookupSfont(device, id))) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); - if(count < 0) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - - WriteLock(&sfont->Lock); - if(ReadRef(&sfont->ref) != 0) - { - WriteUnlock(&sfont->Lock); - SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done); - } - - if(count == 0) - presets = NULL; - else - { - presets = calloc(count, sizeof(presets[0])); - if(!presets) - { - WriteUnlock(&sfont->Lock); - SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done); - } - - for(i = 0;i < count;i++) - { - if(!(presets[i]=LookupPreset(device, pids[i]))) - { - free(presets); - WriteUnlock(&sfont->Lock); - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - } - } - } - - for(i = 0;i < count;i++) - IncrementRef(&presets[i]->ref); - - presets = ExchangePtr((XchgPtr*)&sfont->Presets, presets); - count = ExchangeInt(&sfont->NumPresets, count); - WriteUnlock(&sfont->Lock); - - for(i = 0;i < count;i++) - DecrementRef(&presets[i]->ref); - free(presets); - -done: - ALCcontext_DecRef(context); -} - - -AL_API void AL_APIENTRY alLoadSoundfontSOFT(ALuint id, size_t(*cb)(ALvoid*,size_t,ALvoid*), ALvoid *user) -{ - ALCdevice *device; - ALCcontext *context; - ALsoundfont *sfont; - Reader reader; - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - if(id == 0) - SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done); - if(!(sfont=LookupSfont(device, id))) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); - - WriteLock(&sfont->Lock); - if(ReadRef(&sfont->ref) != 0) - { - WriteUnlock(&sfont->Lock); - SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done); - } - if(sfont->NumPresets > 0) - { - WriteUnlock(&sfont->Lock); - SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done); - } - - reader.cb = cb; - reader.ptr = user; - reader.error = 0; - loadSf2(&reader, sfont, context); - WriteUnlock(&sfont->Lock); - -done: - ALCcontext_DecRef(context); -} - - -static void ALsoundfont_Construct(ALsoundfont *self) -{ - InitRef(&self->ref, 0); - - self->Presets = NULL; - self->NumPresets = 0; - - RWLockInit(&self->Lock); - - self->id = 0; -} - -static void ALsoundfont_Destruct(ALsoundfont *self) -{ - ALsizei i; - - FreeThunkEntry(self->id); - self->id = 0; - - for(i = 0;i < self->NumPresets;i++) - { - DecrementRef(&self->Presets[i]->ref); - self->Presets[i] = NULL; - } - free(self->Presets); - self->Presets = NULL; - self->NumPresets = 0; -} - -ALsoundfont *ALsoundfont_getDefSoundfont(ALCcontext *context) -{ - ALCdevice *device = context->Device; - al_string fname = AL_STRING_INIT_STATIC(); - const char *namelist; - - if(device->DefaultSfont) - return device->DefaultSfont; - - device->DefaultSfont = calloc(1, sizeof(device->DefaultSfont[0])); - ALsoundfont_Construct(device->DefaultSfont); - - namelist = getenv("ALSOFT_SOUNDFONT"); - if(!namelist || !namelist[0]) - ConfigValueStr("midi", "soundfont", &namelist); - while(namelist && namelist[0]) - { - const char *next, *end; - FILE *f; - - while(*namelist && (isspace(*namelist) || *namelist == ',')) - namelist++; - if(!*namelist) - break; - next = strchr(namelist, ','); - end = next ? next++ : (namelist+strlen(namelist)); - while(--end != namelist && isspace(*end)) { - } - if(end == namelist) - continue; - al_string_append_range(&fname, namelist, end+1); - namelist = next; - - f = OpenDataFile(al_string_get_cstr(fname), "openal/soundfonts"); - if(f == NULL) - ERR("Failed to open %s\n", al_string_get_cstr(fname)); - else - { - Reader reader; - reader.cb = ALsoundfont_read; - reader.ptr = f; - reader.error = 0; - TRACE("Loading %s\n", al_string_get_cstr(fname)); - loadSf2(&reader, device->DefaultSfont, context); - fclose(f); - } - - al_string_clear(&fname); - } - AL_STRING_DEINIT(fname); - - return device->DefaultSfont; -} - -void ALsoundfont_deleteSoundfont(ALsoundfont *self, ALCdevice *device) -{ - ALsfpreset **presets; - ALsizei num_presets; - VECTOR(ALbuffer*) buffers; - ALsizei i; - - VECTOR_INIT(buffers); - presets = ExchangePtr((XchgPtr*)&self->Presets, NULL); - num_presets = ExchangeInt(&self->NumPresets, 0); - - for(i = 0;i < num_presets;i++) - { - ALsfpreset *preset = presets[i]; - ALfontsound **sounds; - ALsizei num_sounds; - ALboolean deleting; - ALsizei j; - - sounds = ExchangePtr((XchgPtr*)&preset->Sounds, NULL); - num_sounds = ExchangeInt(&preset->NumSounds, 0); - - DeletePreset(device, preset); - preset = NULL; - - for(j = 0;j < num_sounds;j++) - DecrementRef(&sounds[j]->ref); - /* Some fontsounds may not be immediately deletable because they're - * linked to another fontsound. When those fontsounds are deleted - * they should become deletable, so use a loop until all fontsounds - * are deleted. */ - do { - deleting = AL_FALSE; - for(j = 0;j < num_sounds;j++) - { - if(sounds[j] && ReadRef(&sounds[j]->ref) == 0) - { - deleting = AL_TRUE; - if(sounds[j]->Buffer) - { - ALbuffer *buffer = sounds[j]->Buffer; - ALbuffer **iter; - -#define MATCH_BUFFER(_i) (buffer == *(_i)) - VECTOR_FIND_IF(iter, ALbuffer*, buffers, MATCH_BUFFER); - if(iter == VECTOR_ITER_END(buffers)) - VECTOR_PUSH_BACK(buffers, buffer); -#undef MATCH_BUFFER - } - DeleteFontsound(device, sounds[j]); - sounds[j] = NULL; - } - } - } while(deleting); - free(sounds); - } - - ALsoundfont_Destruct(self); - free(self); - -#define DELETE_BUFFER(iter) do { \ - assert(ReadRef(&(*(iter))->ref) == 0); \ - DeleteBuffer(device, *(iter)); \ -} while(0) - VECTOR_FOR_EACH(ALbuffer*, buffers, DELETE_BUFFER); - VECTOR_DEINIT(buffers); -#undef DELETE_BUFFER -} - - -static size_t ALsoundfont_read(ALvoid *buf, size_t bytes, ALvoid *ptr) -{ - return fread(buf, 1, bytes, (FILE*)ptr); -} - - -/* ReleaseALSoundfonts - * - * Called to destroy any soundfonts that still exist on the device - */ -void ReleaseALSoundfonts(ALCdevice *device) -{ - ALsizei i; - for(i = 0;i < device->SfontMap.size;i++) - { - ALsoundfont *temp = device->SfontMap.array[i].value; - device->SfontMap.array[i].value = NULL; - - ALsoundfont_Destruct(temp); - - memset(temp, 0, sizeof(*temp)); - free(temp); - } -} diff --git a/love/src/jni/openal-soft-1.17.0/OpenAL32/alSource.c b/love/src/jni/openal-soft-1.17.0/OpenAL32/alSource.c deleted file mode 100644 index 752e2e35..00000000 --- a/love/src/jni/openal-soft-1.17.0/OpenAL32/alSource.c +++ /dev/null @@ -1,2912 +0,0 @@ -/** - * OpenAL cross platform audio library - * Copyright (C) 1999-2007 by authors. - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * Or go to http://www.gnu.org/copyleft/lgpl.html - */ - -#include "config.h" - -#include -#include -#include - -#include "AL/al.h" -#include "AL/alc.h" -#include "alMain.h" -#include "alError.h" -#include "alSource.h" -#include "alBuffer.h" -#include "alThunk.h" -#include "alAuxEffectSlot.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); - -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, - - sfPosition = AL_POSITION, - sfVelocity = AL_VELOCITY, - sfDirection = 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, - - /* 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, - - /* AL_SOFT_direct_channels */ - sfDirectChannelsSOFT = AL_DIRECT_CHANNELS_SOFT, - - /* AL_EXT_source_distance_model */ - sfDistanceModel = AL_DISTANCE_MODEL, - - sfSecLength = 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, - - /* AL_SOFT_source_latency */ - sfSecOffsetLatencySOFT = AL_SEC_OFFSET_LATENCY_SOFT, -} SrcFloatProp; - -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, - - /* 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, - - /* 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 ALint FloatValsByProp(ALenum prop) -{ - if(prop != (ALenum)((SrcFloatProp)prop)) - return 0; - switch((SrcFloatProp)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: - return 1; - - case sfSampleRWOffsetsSOFT: - case sfByteRWOffsetsSOFT: - return 2; - - case sfPosition: - case sfVelocity: - case sfDirection: - return 3; - - case sfSecOffsetLatencySOFT: - break; /* Double only */ - } - return 0; -} -static ALint DoubleValsByProp(ALenum prop) -{ - if(prop != (ALenum)((SrcFloatProp)prop)) - return 0; - switch((SrcFloatProp)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: - return 1; - - case sfSampleRWOffsetsSOFT: - case sfByteRWOffsetsSOFT: - case sfSecOffsetLatencySOFT: - return 2; - - case sfPosition: - case sfVelocity: - case sfDirection: - return 3; - } - return 0; -} - -static ALint IntValsByProp(ALenum prop) -{ - if(prop != (ALenum)((SrcIntProp)prop)) - return 0; - switch((SrcIntProp)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: - return 1; - - case siSampleRWOffsetsSOFT: - case siByteRWOffsetsSOFT: - return 2; - - case siPosition: - case siVelocity: - case siDirection: - case siAuxSendFilter: - return 3; - - case siSampleOffsetLatencySOFT: - break; /* i64 only */ - } - return 0; -} -static ALint Int64ValsByProp(ALenum prop) -{ - if(prop != (ALenum)((SrcIntProp)prop)) - return 0; - switch((SrcIntProp)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: - return 1; - - case siSampleRWOffsetsSOFT: - case siByteRWOffsetsSOFT: - case siSampleOffsetLatencySOFT: - return 2; - - case siPosition: - case siVelocity: - case siDirection: - case siAuxSendFilter: - return 3; - } - return 0; -} - - -#define CHECKVAL(x) do { \ - if(!(x)) \ - 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) -{ - ALint ival; - - switch(prop) - { - case AL_PITCH: - CHECKVAL(*values >= 0.0f); - - Source->Pitch = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); - return AL_TRUE; - - case AL_CONE_INNER_ANGLE: - CHECKVAL(*values >= 0.0f && *values <= 360.0f); - - Source->InnerAngle = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); - return AL_TRUE; - - case AL_CONE_OUTER_ANGLE: - CHECKVAL(*values >= 0.0f && *values <= 360.0f); - - Source->OuterAngle = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); - return AL_TRUE; - - case AL_GAIN: - CHECKVAL(*values >= 0.0f); - - Source->Gain = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); - return AL_TRUE; - - case AL_MAX_DISTANCE: - CHECKVAL(*values >= 0.0f); - - Source->MaxDistance = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); - return AL_TRUE; - - case AL_ROLLOFF_FACTOR: - CHECKVAL(*values >= 0.0f); - - Source->RollOffFactor = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); - return AL_TRUE; - - case AL_REFERENCE_DISTANCE: - CHECKVAL(*values >= 0.0f); - - Source->RefDistance = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); - return AL_TRUE; - - case AL_MIN_GAIN: - CHECKVAL(*values >= 0.0f && *values <= 1.0f); - - Source->MinGain = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); - return AL_TRUE; - - case AL_MAX_GAIN: - CHECKVAL(*values >= 0.0f && *values <= 1.0f); - - Source->MaxGain = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); - return AL_TRUE; - - case AL_CONE_OUTER_GAIN: - CHECKVAL(*values >= 0.0f && *values <= 1.0f); - - Source->OuterGain = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); - return AL_TRUE; - - case AL_CONE_OUTER_GAINHF: - CHECKVAL(*values >= 0.0f && *values <= 1.0f); - - Source->OuterGainHF = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); - return AL_TRUE; - - case AL_AIR_ABSORPTION_FACTOR: - CHECKVAL(*values >= 0.0f && *values <= 10.0f); - - Source->AirAbsorptionFactor = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); - return AL_TRUE; - - case AL_ROOM_ROLLOFF_FACTOR: - CHECKVAL(*values >= 0.0f && *values <= 10.0f); - - Source->RoomRolloffFactor = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); - return AL_TRUE; - - case AL_DOPPLER_FACTOR: - CHECKVAL(*values >= 0.0f && *values <= 1.0f); - - Source->DopplerFactor = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); - return AL_TRUE; - - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - CHECKVAL(*values >= 0.0f); - - LockContext(Context); - Source->OffsetType = prop; - Source->Offset = *values; - - if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) && - !Context->DeferUpdates) - { - if(ApplyOffset(Source) == AL_FALSE) - { - UnlockContext(Context); - SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); - } - } - 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]; - UnlockContext(Context); - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); - return AL_TRUE; - - case AL_VELOCITY: - 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]; - UnlockContext(Context); - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); - return AL_TRUE; - - case AL_DIRECTION: - 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]; - 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: - ival = (ALint)values[0]; - return SetSourceiv(Source, Context, (SrcIntProp)prop, &ival); - - case sfBuffer: - case sfBuffersQueued: - case sfBuffersProcessed: - ival = (ALint)((ALuint)values[0]); - return SetSourceiv(Source, Context, (SrcIntProp)prop, &ival); - } - - 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) -{ - ALCdevice *device = Context->Device; - ALbuffer *buffer = NULL; - ALfilter *filter = NULL; - ALeffectslot *slot = NULL; - ALbufferlistitem *oldlist; - ALbufferlistitem *newlist; - ALfloat fvals[3]; - - switch(prop) - { - case AL_SOURCE_RELATIVE: - CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); - - Source->HeadRelative = (ALboolean)*values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); - return AL_TRUE; - - case AL_LOOPING: - CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); - - Source->Looping = (ALboolean)*values; - return AL_TRUE; - - case AL_BUFFER: - CHECKVAL(*values == 0 || (buffer=LookupBuffer(device, *values)) != NULL); - - WriteLock(&Source->queue_lock); - if(!(Source->state == AL_STOPPED || Source->state == AL_INITIAL)) - { - WriteUnlock(&Source->queue_lock); - SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE); - } - - if(buffer != NULL) - { - /* Add the selected buffer to a one-item queue */ - newlist = malloc(sizeof(ALbufferlistitem)); - newlist->buffer = buffer; - newlist->next = NULL; - newlist->prev = NULL; - IncrementRef(&buffer->ref); - - /* Source is now Static */ - Source->SourceType = AL_STATIC; - - ReadLock(&buffer->lock); - Source->NumChannels = ChannelsFromFmt(buffer->FmtChannels); - Source->SampleSize = BytesFromFmt(buffer->FmtType); - ReadUnlock(&buffer->lock); - } - else - { - /* Source is now Undetermined */ - Source->SourceType = AL_UNDETERMINED; - newlist = NULL; - } - oldlist = ATOMIC_EXCHANGE(ALbufferlistitem*, &Source->queue, newlist); - ATOMIC_STORE(&Source->current_buffer, newlist); - WriteUnlock(&Source->queue_lock); - - /* Delete all elements in the previous queue */ - while(oldlist != NULL) - { - ALbufferlistitem *temp = oldlist; - oldlist = temp->next; - - if(temp->buffer) - DecrementRef(&temp->buffer->ref); - free(temp); - } - 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: - CHECKVAL(*values >= 0); - - LockContext(Context); - Source->OffsetType = prop; - Source->Offset = *values; - - if((Source->state == AL_PLAYING || Source->state == AL_PAUSED) && - !Context->DeferUpdates) - { - if(ApplyOffset(Source) == AL_FALSE) - { - UnlockContext(Context); - SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); - } - } - 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); - - LockContext(Context); - if(!filter) - { - Source->Direct.Gain = 1.0f; - Source->Direct.GainHF = 1.0f; - Source->Direct.HFReference = LOWPASSFREQREF; - Source->Direct.GainLF = 1.0f; - Source->Direct.LFReference = HIGHPASSFREQREF; - } - else - { - Source->Direct.Gain = filter->Gain; - Source->Direct.GainHF = filter->GainHF; - Source->Direct.HFReference = filter->HFReference; - Source->Direct.GainLF = filter->GainLF; - Source->Direct.LFReference = filter->LFReference; - } - UnlockContext(Context); - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); - return AL_TRUE; - - case AL_DIRECT_FILTER_GAINHF_AUTO: - CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); - - Source->DryGainHFAuto = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); - return AL_TRUE; - - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); - - Source->WetGainAuto = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); - return AL_TRUE; - - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); - - Source->WetGainHFAuto = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); - return AL_TRUE; - - case AL_DIRECT_CHANNELS_SOFT: - CHECKVAL(*values == AL_FALSE || *values == AL_TRUE); - - Source->DirectChannels = *values; - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); - return AL_TRUE; - - case AL_DISTANCE_MODEL: - CHECKVAL(*values == AL_NONE || - *values == AL_INVERSE_DISTANCE || - *values == AL_INVERSE_DISTANCE_CLAMPED || - *values == AL_LINEAR_DISTANCE || - *values == AL_LINEAR_DISTANCE_CLAMPED || - *values == AL_EXPONENT_DISTANCE || - *values == AL_EXPONENT_DISTANCE_CLAMPED); - - Source->DistanceModel = *values; - if(Context->SourceDistanceModel) - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); - return AL_TRUE; - - - case AL_AUXILIARY_SEND_FILTER: - LockContext(Context); - if(!((ALuint)values[1] < device->NumAuxSends && - (values[0] == 0 || (slot=LookupEffectSlot(Context, values[0])) != NULL) && - (values[2] == 0 || (filter=LookupFilter(device, values[2])) != NULL))) - { - UnlockContext(Context); - SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_VALUE, AL_FALSE); - } - - /* Add refcount on the new slot, and release the previous slot */ - if(slot) IncrementRef(&slot->ref); - slot = ExchangePtr((XchgPtr*)&Source->Send[values[1]].Slot, slot); - if(slot) DecrementRef(&slot->ref); - - if(!filter) - { - /* Disable filter */ - Source->Send[values[1]].Gain = 1.0f; - Source->Send[values[1]].GainHF = 1.0f; - Source->Send[values[1]].HFReference = LOWPASSFREQREF; - Source->Send[values[1]].GainLF = 1.0f; - Source->Send[values[1]].LFReference = HIGHPASSFREQREF; - } - else - { - Source->Send[values[1]].Gain = filter->Gain; - Source->Send[values[1]].GainHF = filter->GainHF; - Source->Send[values[1]].HFReference = filter->HFReference; - Source->Send[values[1]].GainLF = filter->GainLF; - Source->Send[values[1]].LFReference = filter->LFReference; - } - UnlockContext(Context); - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); - return AL_TRUE; - - - case AL_MAX_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_REFERENCE_DISTANCE: - case siDopplerFactor: - fvals[0] = (ALfloat)*values; - return SetSourcefv(Source, Context, (int)prop, fvals); - - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - fvals[0] = (ALfloat)values[0]; - fvals[1] = (ALfloat)values[1]; - fvals[2] = (ALfloat)values[2]; - return SetSourcefv(Source, Context, (int)prop, fvals); - - case siSampleOffsetLatencySOFT: - /* i64 only */ - break; - } - - ERR("Unexpected property: 0x%04x\n", prop); - SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE); -} - -static ALboolean SetSourcei64v(ALsource *Source, ALCcontext *Context, SrcIntProp prop, const ALint64SOFT *values) -{ - ALfloat fvals[3]; - ALint ivals[3]; - - switch(prop) - { - case siSampleRWOffsetsSOFT: - case siByteRWOffsetsSOFT: - case siSampleOffsetLatencySOFT: - /* Query only */ - SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_OPERATION, AL_FALSE); - - - /* 1x int */ - case AL_SOURCE_RELATIVE: - case AL_LOOPING: - case AL_SOURCE_STATE: - case AL_BYTE_OFFSET: - case AL_SAMPLE_OFFSET: - case siByteLength: - case siSampleLength: - case siSourceType: - case siBuffersQueued: - case siBuffersProcessed: - 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: - CHECKVAL(*values <= INT_MAX && *values >= INT_MIN); - - ivals[0] = (ALint)*values; - return SetSourceiv(Source, Context, (int)prop, ivals); - - /* 1x uint */ - case AL_BUFFER: - case AL_DIRECT_FILTER: - CHECKVAL(*values <= UINT_MAX && *values >= 0); - - ivals[0] = (ALuint)*values; - return SetSourceiv(Source, Context, (int)prop, ivals); - - /* 3x uint */ - case AL_AUXILIARY_SEND_FILTER: - CHECKVAL(values[0] <= UINT_MAX && values[0] >= 0 && - values[1] <= UINT_MAX && values[1] >= 0 && - values[2] <= UINT_MAX && values[2] >= 0); - - ivals[0] = (ALuint)values[0]; - ivals[1] = (ALuint)values[1]; - ivals[2] = (ALuint)values[2]; - return SetSourceiv(Source, Context, (int)prop, ivals); - - /* 1x float */ - case AL_MAX_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - case AL_REFERENCE_DISTANCE: - case AL_SEC_OFFSET: - case siDopplerFactor: - fvals[0] = (ALfloat)*values; - return SetSourcefv(Source, Context, (int)prop, fvals); - - /* 3x float */ - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - fvals[0] = (ALfloat)values[0]; - fvals[1] = (ALfloat)values[1]; - fvals[2] = (ALfloat)values[2]; - return SetSourcefv(Source, Context, (int)prop, fvals); - } - - ERR("Unexpected property: 0x%04x\n", prop); - SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE); -} - -#undef CHECKVAL - - -static ALboolean GetSourcedv(ALsource *Source, ALCcontext *Context, SrcFloatProp prop, ALdouble *values) -{ - ALbufferlistitem *BufferList; - ALdouble offsets[2]; - ALdouble updateLen; - ALint ivals[3]; - ALboolean err; - - switch(prop) - { - case AL_GAIN: - *values = Source->Gain; - return AL_TRUE; - - case AL_PITCH: - *values = Source->Pitch; - return AL_TRUE; - - case AL_MAX_DISTANCE: - *values = Source->MaxDistance; - return AL_TRUE; - - case AL_ROLLOFF_FACTOR: - *values = Source->RollOffFactor; - return AL_TRUE; - - case AL_REFERENCE_DISTANCE: - *values = Source->RefDistance; - return AL_TRUE; - - case AL_CONE_INNER_ANGLE: - *values = Source->InnerAngle; - return AL_TRUE; - - case AL_CONE_OUTER_ANGLE: - *values = Source->OuterAngle; - return AL_TRUE; - - case AL_MIN_GAIN: - *values = Source->MinGain; - return AL_TRUE; - - case AL_MAX_GAIN: - *values = Source->MaxGain; - return AL_TRUE; - - case AL_CONE_OUTER_GAIN: - *values = Source->OuterGain; - return AL_TRUE; - - case AL_SEC_OFFSET: - case AL_SAMPLE_OFFSET: - case AL_BYTE_OFFSET: - LockContext(Context); - ReadLock(&Source->queue_lock); - GetSourceOffsets(Source, prop, offsets, 0.0); - ReadUnlock(&Source->queue_lock); - UnlockContext(Context); - *values = offsets[0]; - return AL_TRUE; - - case AL_CONE_OUTER_GAINHF: - *values = Source->OuterGainHF; - return AL_TRUE; - - case AL_AIR_ABSORPTION_FACTOR: - *values = Source->AirAbsorptionFactor; - return AL_TRUE; - - case AL_ROOM_ROLLOFF_FACTOR: - *values = Source->RoomRolloffFactor; - return AL_TRUE; - - case AL_DOPPLER_FACTOR: - *values = Source->DopplerFactor; - return AL_TRUE; - - case sfSecLength: - ReadLock(&Source->queue_lock); - if(!(BufferList=ATOMIC_LOAD(&Source->queue))) - *values = 0; - else - { - ALint length = 0; - ALsizei freq = 1; - do { - ALbuffer *buffer = BufferList->buffer; - if(buffer && buffer->SampleLen > 0) - { - freq = buffer->Frequency; - length += buffer->SampleLen; - } - } while((BufferList=BufferList->next) != NULL); - *values = (ALdouble)length / (ALdouble)freq; - } - ReadUnlock(&Source->queue_lock); - return AL_TRUE; - - 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; - 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) / - 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]; - 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]; - 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]; - UnlockContext(Context); - return AL_TRUE; - - 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_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) - *values = (ALdouble)ivals[0]; - return err; - } - - 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) -{ - ALbufferlistitem *BufferList; - ALdouble dvals[3]; - ALboolean err; - - switch(prop) - { - case AL_SOURCE_RELATIVE: - *values = Source->HeadRelative; - return AL_TRUE; - - case AL_LOOPING: - *values = Source->Looping; - return AL_TRUE; - - case AL_BUFFER: - ReadLock(&Source->queue_lock); - BufferList = (Source->SourceType == AL_STATIC) ? ATOMIC_LOAD(&Source->queue) : - ATOMIC_LOAD(&Source->current_buffer); - *values = (BufferList && BufferList->buffer) ? BufferList->buffer->id : 0; - ReadUnlock(&Source->queue_lock); - return AL_TRUE; - - case AL_SOURCE_STATE: - *values = Source->state; - return AL_TRUE; - - case siByteLength: - ReadLock(&Source->queue_lock); - if(!(BufferList=ATOMIC_LOAD(&Source->queue))) - *values = 0; - else - { - ALint length = 0; - do { - ALbuffer *buffer = BufferList->buffer; - if(buffer && buffer->SampleLen > 0) - { - ALuint byte_align, sample_align; - if(buffer->OriginalType == UserFmtIMA4) - { - ALsizei align = (buffer->OriginalAlign-1)/2 + 4; - byte_align = align * ChannelsFromFmt(buffer->FmtChannels); - sample_align = buffer->OriginalAlign; - } - else if(buffer->OriginalType == UserFmtMSADPCM) - { - ALsizei align = (buffer->OriginalAlign-2)/2 + 7; - byte_align = align * ChannelsFromFmt(buffer->FmtChannels); - sample_align = buffer->OriginalAlign; - } - else - { - ALsizei align = buffer->OriginalAlign; - byte_align = align * ChannelsFromFmt(buffer->FmtChannels); - sample_align = buffer->OriginalAlign; - } - - length += buffer->SampleLen / sample_align * byte_align; - } - } while((BufferList=BufferList->next) != NULL); - *values = length; - } - ReadUnlock(&Source->queue_lock); - return AL_TRUE; - - case siSampleLength: - ReadLock(&Source->queue_lock); - if(!(BufferList=ATOMIC_LOAD(&Source->queue))) - *values = 0; - else - { - ALint length = 0; - do { - ALbuffer *buffer = BufferList->buffer; - if(buffer) length += buffer->SampleLen; - } while((BufferList=BufferList->next) != NULL); - *values = length; - } - ReadUnlock(&Source->queue_lock); - return AL_TRUE; - - case AL_BUFFERS_QUEUED: - ReadLock(&Source->queue_lock); - if(!(BufferList=ATOMIC_LOAD(&Source->queue))) - *values = 0; - else - { - ALsizei count = 0; - do { - ++count; - } while((BufferList=BufferList->next) != NULL); - *values = count; - } - ReadUnlock(&Source->queue_lock); - return AL_TRUE; - - case AL_BUFFERS_PROCESSED: - ReadLock(&Source->queue_lock); - if(Source->Looping || Source->SourceType != AL_STREAMING) - { - /* Buffers on a looping source are in a perpetual state of - * PENDING, so don't report any as PROCESSED */ - *values = 0; - } - else - { - const ALbufferlistitem *BufferList = ATOMIC_LOAD(&Source->queue); - const ALbufferlistitem *Current = ATOMIC_LOAD(&Source->current_buffer); - ALsizei played = 0; - while(BufferList && BufferList != Current) - { - played++; - BufferList = BufferList->next; - } - *values = played; - } - ReadUnlock(&Source->queue_lock); - return AL_TRUE; - - case AL_SOURCE_TYPE: - *values = Source->SourceType; - return AL_TRUE; - - case AL_DIRECT_FILTER_GAINHF_AUTO: - *values = Source->DryGainHFAuto; - return AL_TRUE; - - case AL_AUXILIARY_SEND_FILTER_GAIN_AUTO: - *values = Source->WetGainAuto; - return AL_TRUE; - - case AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO: - *values = Source->WetGainHFAuto; - return AL_TRUE; - - case AL_DIRECT_CHANNELS_SOFT: - *values = Source->DirectChannels; - return AL_TRUE; - - case AL_DISTANCE_MODEL: - *values = Source->DistanceModel; - return AL_TRUE; - - case AL_MAX_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_REFERENCE_DISTANCE: - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - 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) - *values = (ALint)dvals[0]; - return err; - - case AL_SAMPLE_RW_OFFSETS_SOFT: - case AL_BYTE_RW_OFFSETS_SOFT: - if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE) - { - values[0] = (ALint)dvals[0]; - values[1] = (ALint)dvals[1]; - } - return err; - - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE) - { - values[0] = (ALint)dvals[0]; - values[1] = (ALint)dvals[1]; - values[2] = (ALint)dvals[2]; - } - return err; - - case siSampleOffsetLatencySOFT: - /* i64 only */ - break; - - case siDirectFilter: - case siAuxSendFilter: - /* ??? */ - 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) -{ - ALdouble dvals[3]; - ALint ivals[3]; - ALboolean err; - - switch(prop) - { - 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); - UnlockContext(Context); - return AL_TRUE; - - case AL_MAX_DISTANCE: - case AL_ROLLOFF_FACTOR: - case AL_REFERENCE_DISTANCE: - case AL_CONE_INNER_ANGLE: - case AL_CONE_OUTER_ANGLE: - 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) - *values = (ALint64)dvals[0]; - return err; - - case AL_SAMPLE_RW_OFFSETS_SOFT: - case AL_BYTE_RW_OFFSETS_SOFT: - if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE) - { - values[0] = (ALint64)dvals[0]; - values[1] = (ALint64)dvals[1]; - } - return err; - - case AL_POSITION: - case AL_VELOCITY: - case AL_DIRECTION: - if((err=GetSourcedv(Source, Context, (int)prop, dvals)) != AL_FALSE) - { - values[0] = (ALint64)dvals[0]; - values[1] = (ALint64)dvals[1]; - values[2] = (ALint64)dvals[2]; - } - return err; - - 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_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) - *values = ivals[0]; - return err; - - case siBuffer: - case siDirectFilter: - if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE) - *values = (ALuint)ivals[0]; - return err; - - case siAuxSendFilter: - if((err=GetSourceiv(Source, Context, (int)prop, ivals)) != AL_FALSE) - { - values[0] = (ALuint)ivals[0]; - values[1] = (ALuint)ivals[1]; - values[2] = (ALuint)ivals[2]; - } - return err; - } - - ERR("Unexpected property: 0x%04x\n", prop); - SET_ERROR_AND_RETURN_VALUE(Context, AL_INVALID_ENUM, AL_FALSE); -} - - -AL_API ALvoid AL_APIENTRY alGenSources(ALsizei n, ALuint *sources) -{ - ALCcontext *context; - ALsizei cur = 0; - ALenum err; - - context = GetContextRef(); - if(!context) return; - - if(!(n >= 0)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - for(cur = 0;cur < n;cur++) - { - ALsource *source = al_calloc(16, sizeof(ALsource)); - if(!source) - { - alDeleteSources(cur, sources); - SET_ERROR_AND_GOTO(context, AL_OUT_OF_MEMORY, done); - } - InitSourceParams(source); - - err = NewThunkEntry(&source->id); - if(err == AL_NO_ERROR) - err = InsertUIntMapEntry(&context->SourceMap, source->id, source); - if(err != AL_NO_ERROR) - { - FreeThunkEntry(source->id); - memset(source, 0, sizeof(ALsource)); - al_free(source); - - alDeleteSources(cur, sources); - SET_ERROR_AND_GOTO(context, err, done); - } - - sources[cur] = source->id; - } - -done: - ALCcontext_DecRef(context); -} - - -AL_API ALvoid AL_APIENTRY alDeleteSources(ALsizei n, const ALuint *sources) -{ - ALCcontext *context; - ALbufferlistitem *BufferList; - ALsource *Source; - ALsizei i, j; - - context = GetContextRef(); - if(!context) return; - - if(!(n >= 0)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - - /* Check that all Sources are valid */ - for(i = 0;i < n;i++) - { - if(LookupSource(context, sources[i]) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); - } - for(i = 0;i < n;i++) - { - ALactivesource **srclist, **srclistend; - - if((Source=RemoveSource(context, sources[i])) == NULL) - continue; - FreeThunkEntry(Source->id); - - LockContext(context); - srclist = context->ActiveSources; - srclistend = srclist + context->ActiveSourceCount; - while(srclist != srclistend) - { - if((*srclist)->Source == Source) - { - ALactivesource *temp = *(--srclistend); - *srclistend = *srclist; - *srclist = temp; - --(context->ActiveSourceCount); - break; - } - srclist++; - } - UnlockContext(context); - - BufferList = ATOMIC_EXCHANGE(ALbufferlistitem*, &Source->queue, NULL); - while(BufferList != NULL) - { - ALbufferlistitem *next = BufferList->next; - if(BufferList->buffer != NULL) - DecrementRef(&BufferList->buffer->ref); - free(BufferList); - BufferList = next; - } - - for(j = 0;j < MAX_SENDS;++j) - { - if(Source->Send[j].Slot) - DecrementRef(&Source->Send[j].Slot->ref); - Source->Send[j].Slot = NULL; - } - - memset(Source, 0, sizeof(*Source)); - al_free(Source); - } - -done: - ALCcontext_DecRef(context); -} - - -AL_API ALboolean AL_APIENTRY alIsSource(ALuint source) -{ - ALCcontext *context; - ALboolean ret; - - context = GetContextRef(); - if(!context) return AL_FALSE; - - ret = (LookupSource(context, source) ? AL_TRUE : AL_FALSE); - - ALCcontext_DecRef(context); - - return ret; -} - - -AL_API ALvoid AL_APIENTRY alSourcef(ALuint source, ALenum param, ALfloat value) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); - else if(!(FloatValsByProp(param) == 1)) - alSetError(Context, AL_INVALID_ENUM); - else - SetSourcefv(Source, Context, param, &value); - - ALCcontext_DecRef(Context); -} - -AL_API ALvoid AL_APIENTRY alSource3f(ALuint source, ALenum param, ALfloat value1, ALfloat value2, ALfloat value3) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); - else if(!(FloatValsByProp(param) == 3)) - alSetError(Context, AL_INVALID_ENUM); - else - { - ALfloat fvals[3] = { value1, value2, value3 }; - SetSourcefv(Source, Context, param, fvals); - } - - ALCcontext_DecRef(Context); -} - -AL_API ALvoid AL_APIENTRY alSourcefv(ALuint source, ALenum param, const ALfloat *values) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); - else if(!values) - alSetError(Context, AL_INVALID_VALUE); - else if(!(FloatValsByProp(param) > 0)) - alSetError(Context, AL_INVALID_ENUM); - else - SetSourcefv(Source, Context, param, values); - - ALCcontext_DecRef(Context); -} - - -AL_API ALvoid AL_APIENTRY alSourcedSOFT(ALuint source, ALenum param, ALdouble value) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); - else if(!(DoubleValsByProp(param) == 1)) - alSetError(Context, AL_INVALID_ENUM); - else - { - ALfloat fval = (ALfloat)value; - SetSourcefv(Source, Context, param, &fval); - } - - ALCcontext_DecRef(Context); -} - -AL_API ALvoid AL_APIENTRY alSource3dSOFT(ALuint source, ALenum param, ALdouble value1, ALdouble value2, ALdouble value3) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); - else if(!(DoubleValsByProp(param) == 3)) - alSetError(Context, AL_INVALID_ENUM); - else - { - ALfloat fvals[3] = { (ALfloat)value1, (ALfloat)value2, (ALfloat)value3 }; - SetSourcefv(Source, Context, param, fvals); - } - - ALCcontext_DecRef(Context); -} - -AL_API ALvoid AL_APIENTRY alSourcedvSOFT(ALuint source, ALenum param, const ALdouble *values) -{ - ALCcontext *Context; - ALsource *Source; - ALint count; - - Context = GetContextRef(); - if(!Context) return; - - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); - else if(!values) - alSetError(Context, AL_INVALID_VALUE); - else if(!((count=DoubleValsByProp(param)) > 0 && count <= 3)) - alSetError(Context, AL_INVALID_ENUM); - else - { - ALfloat fvals[3]; - ALint i; - - for(i = 0;i < count;i++) - fvals[i] = (ALfloat)values[i]; - SetSourcefv(Source, Context, param, fvals); - } - - ALCcontext_DecRef(Context); -} - - -AL_API ALvoid AL_APIENTRY alSourcei(ALuint source, ALenum param, ALint value) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); - else if(!(IntValsByProp(param) == 1)) - alSetError(Context, AL_INVALID_ENUM); - else - SetSourceiv(Source, Context, param, &value); - - ALCcontext_DecRef(Context); -} - -AL_API void AL_APIENTRY alSource3i(ALuint source, ALenum param, ALint value1, ALint value2, ALint value3) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); - else if(!(IntValsByProp(param) == 3)) - alSetError(Context, AL_INVALID_ENUM); - else - { - ALint ivals[3] = { value1, value2, value3 }; - SetSourceiv(Source, Context, param, ivals); - } - - ALCcontext_DecRef(Context); -} - -AL_API void AL_APIENTRY alSourceiv(ALuint source, ALenum param, const ALint *values) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); - else if(!values) - alSetError(Context, AL_INVALID_VALUE); - else if(!(IntValsByProp(param) > 0)) - alSetError(Context, AL_INVALID_ENUM); - else - SetSourceiv(Source, Context, param, values); - - ALCcontext_DecRef(Context); -} - - -AL_API ALvoid AL_APIENTRY alSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT value) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); - else if(!(Int64ValsByProp(param) == 1)) - alSetError(Context, AL_INVALID_ENUM); - else - SetSourcei64v(Source, Context, param, &value); - - ALCcontext_DecRef(Context); -} - -AL_API void AL_APIENTRY alSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT value1, ALint64SOFT value2, ALint64SOFT value3) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); - else if(!(Int64ValsByProp(param) == 3)) - alSetError(Context, AL_INVALID_ENUM); - else - { - ALint64SOFT i64vals[3] = { value1, value2, value3 }; - SetSourcei64v(Source, Context, param, i64vals); - } - - ALCcontext_DecRef(Context); -} - -AL_API void AL_APIENTRY alSourcei64vSOFT(ALuint source, ALenum param, const ALint64SOFT *values) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); - else if(!values) - alSetError(Context, AL_INVALID_VALUE); - else if(!(Int64ValsByProp(param) > 0)) - alSetError(Context, AL_INVALID_ENUM); - else - SetSourcei64v(Source, Context, param, values); - - ALCcontext_DecRef(Context); -} - - -AL_API ALvoid AL_APIENTRY alGetSourcef(ALuint source, ALenum param, ALfloat *value) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); - else if(!value) - alSetError(Context, AL_INVALID_VALUE); - else if(!(FloatValsByProp(param) == 1)) - alSetError(Context, AL_INVALID_ENUM); - else - { - ALdouble dval; - if(GetSourcedv(Source, Context, param, &dval)) - *value = (ALfloat)dval; - } - - ALCcontext_DecRef(Context); -} - - -AL_API ALvoid AL_APIENTRY alGetSource3f(ALuint source, ALenum param, ALfloat *value1, ALfloat *value2, ALfloat *value3) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); - else if(!(value1 && value2 && value3)) - alSetError(Context, AL_INVALID_VALUE); - else if(!(FloatValsByProp(param) == 3)) - alSetError(Context, AL_INVALID_ENUM); - else - { - ALdouble dvals[3]; - if(GetSourcedv(Source, Context, param, dvals)) - { - *value1 = (ALfloat)dvals[0]; - *value2 = (ALfloat)dvals[1]; - *value3 = (ALfloat)dvals[2]; - } - } - - ALCcontext_DecRef(Context); -} - - -AL_API ALvoid AL_APIENTRY alGetSourcefv(ALuint source, ALenum param, ALfloat *values) -{ - ALCcontext *Context; - ALsource *Source; - ALint count; - - Context = GetContextRef(); - if(!Context) return; - - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); - else if(!values) - alSetError(Context, AL_INVALID_VALUE); - else if(!((count=FloatValsByProp(param)) > 0 && count <= 3)) - alSetError(Context, AL_INVALID_ENUM); - else - { - ALdouble dvals[3]; - if(GetSourcedv(Source, Context, param, dvals)) - { - ALint i; - for(i = 0;i < count;i++) - values[i] = (ALfloat)dvals[i]; - } - } - - ALCcontext_DecRef(Context); -} - - -AL_API void AL_APIENTRY alGetSourcedSOFT(ALuint source, ALenum param, ALdouble *value) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); - else if(!value) - alSetError(Context, AL_INVALID_VALUE); - else if(!(DoubleValsByProp(param) == 1)) - alSetError(Context, AL_INVALID_ENUM); - else - GetSourcedv(Source, Context, param, value); - - ALCcontext_DecRef(Context); -} - -AL_API void AL_APIENTRY alGetSource3dSOFT(ALuint source, ALenum param, ALdouble *value1, ALdouble *value2, ALdouble *value3) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); - else if(!(value1 && value2 && value3)) - alSetError(Context, AL_INVALID_VALUE); - else if(!(DoubleValsByProp(param) == 3)) - alSetError(Context, AL_INVALID_ENUM); - else - { - ALdouble dvals[3]; - if(GetSourcedv(Source, Context, param, dvals)) - { - *value1 = dvals[0]; - *value2 = dvals[1]; - *value3 = dvals[2]; - } - } - - ALCcontext_DecRef(Context); -} - -AL_API void AL_APIENTRY alGetSourcedvSOFT(ALuint source, ALenum param, ALdouble *values) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); - else if(!values) - alSetError(Context, AL_INVALID_VALUE); - else if(!(DoubleValsByProp(param) > 0)) - alSetError(Context, AL_INVALID_ENUM); - else - GetSourcedv(Source, Context, param, values); - - ALCcontext_DecRef(Context); -} - - -AL_API ALvoid AL_APIENTRY alGetSourcei(ALuint source, ALenum param, ALint *value) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); - else if(!value) - alSetError(Context, AL_INVALID_VALUE); - else if(!(IntValsByProp(param) == 1)) - alSetError(Context, AL_INVALID_ENUM); - else - GetSourceiv(Source, Context, param, value); - - ALCcontext_DecRef(Context); -} - - -AL_API void AL_APIENTRY alGetSource3i(ALuint source, ALenum param, ALint *value1, ALint *value2, ALint *value3) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); - else if(!(value1 && value2 && value3)) - alSetError(Context, AL_INVALID_VALUE); - else if(!(IntValsByProp(param) == 3)) - alSetError(Context, AL_INVALID_ENUM); - else - { - ALint ivals[3]; - if(GetSourceiv(Source, Context, param, ivals)) - { - *value1 = ivals[0]; - *value2 = ivals[1]; - *value3 = ivals[2]; - } - } - - ALCcontext_DecRef(Context); -} - - -AL_API void AL_APIENTRY alGetSourceiv(ALuint source, ALenum param, ALint *values) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); - else if(!values) - alSetError(Context, AL_INVALID_VALUE); - else if(!(IntValsByProp(param) > 0)) - alSetError(Context, AL_INVALID_ENUM); - else - GetSourceiv(Source, Context, param, values); - - ALCcontext_DecRef(Context); -} - - -AL_API void AL_APIENTRY alGetSourcei64SOFT(ALuint source, ALenum param, ALint64SOFT *value) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); - else if(!value) - alSetError(Context, AL_INVALID_VALUE); - else if(!(Int64ValsByProp(param) == 1)) - alSetError(Context, AL_INVALID_ENUM); - else - GetSourcei64v(Source, Context, param, value); - - ALCcontext_DecRef(Context); -} - -AL_API void AL_APIENTRY alGetSource3i64SOFT(ALuint source, ALenum param, ALint64SOFT *value1, ALint64SOFT *value2, ALint64SOFT *value3) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); - else if(!(value1 && value2 && value3)) - alSetError(Context, AL_INVALID_VALUE); - else if(!(Int64ValsByProp(param) == 3)) - alSetError(Context, AL_INVALID_ENUM); - else - { - ALint64 i64vals[3]; - if(GetSourcei64v(Source, Context, param, i64vals)) - { - *value1 = i64vals[0]; - *value2 = i64vals[1]; - *value3 = i64vals[2]; - } - } - - ALCcontext_DecRef(Context); -} - -AL_API void AL_APIENTRY alGetSourcei64vSOFT(ALuint source, ALenum param, ALint64SOFT *values) -{ - ALCcontext *Context; - ALsource *Source; - - Context = GetContextRef(); - if(!Context) return; - - if((Source=LookupSource(Context, source)) == NULL) - alSetError(Context, AL_INVALID_NAME); - else if(!values) - alSetError(Context, AL_INVALID_VALUE); - else if(!(Int64ValsByProp(param) > 0)) - alSetError(Context, AL_INVALID_ENUM); - else - GetSourcei64v(Source, Context, param, values); - - ALCcontext_DecRef(Context); -} - - -AL_API ALvoid AL_APIENTRY alSourcePlay(ALuint source) -{ - alSourcePlayv(1, &source); -} -AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) -{ - ALCcontext *context; - ALsource *source; - ALsizei i; - - context = GetContextRef(); - if(!context) return; - - if(!(n >= 0)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - for(i = 0;i < n;i++) - { - if(!LookupSource(context, sources[i])) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); - } - - LockContext(context); - while(n > context->MaxActiveSources-context->ActiveSourceCount) - { - ALactivesource **temp = NULL; - ALsizei newcount; - - newcount = context->MaxActiveSources << 1; - if(newcount > 0) - temp = realloc(context->ActiveSources, - newcount * sizeof(context->ActiveSources[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; - - context->ActiveSources = temp; - context->MaxActiveSources = newcount; - } - - for(i = 0;i < n;i++) - { - source = LookupSource(context, sources[i]); - if(context->DeferUpdates) source->new_state = AL_PLAYING; - else SetSourceState(source, context, AL_PLAYING); - } - UnlockContext(context); - -done: - ALCcontext_DecRef(context); -} - -AL_API ALvoid AL_APIENTRY alSourcePause(ALuint source) -{ - alSourcePausev(1, &source); -} -AL_API ALvoid AL_APIENTRY alSourcePausev(ALsizei n, const ALuint *sources) -{ - ALCcontext *context; - ALsource *source; - ALsizei i; - - context = GetContextRef(); - if(!context) return; - - if(!(n >= 0)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - for(i = 0;i < n;i++) - { - if(!LookupSource(context, sources[i])) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); - } - - LockContext(context); - for(i = 0;i < n;i++) - { - source = LookupSource(context, sources[i]); - if(context->DeferUpdates) source->new_state = AL_PAUSED; - else SetSourceState(source, context, AL_PAUSED); - } - UnlockContext(context); - -done: - ALCcontext_DecRef(context); -} - -AL_API ALvoid AL_APIENTRY alSourceStop(ALuint source) -{ - alSourceStopv(1, &source); -} -AL_API ALvoid AL_APIENTRY alSourceStopv(ALsizei n, const ALuint *sources) -{ - ALCcontext *context; - ALsource *source; - ALsizei i; - - context = GetContextRef(); - if(!context) return; - - if(!(n >= 0)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - for(i = 0;i < n;i++) - { - if(!LookupSource(context, sources[i])) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); - } - - LockContext(context); - for(i = 0;i < n;i++) - { - source = LookupSource(context, sources[i]); - source->new_state = AL_NONE; - SetSourceState(source, context, AL_STOPPED); - } - UnlockContext(context); - -done: - ALCcontext_DecRef(context); -} - -AL_API ALvoid AL_APIENTRY alSourceRewind(ALuint source) -{ - alSourceRewindv(1, &source); -} -AL_API ALvoid AL_APIENTRY alSourceRewindv(ALsizei n, const ALuint *sources) -{ - ALCcontext *context; - ALsource *source; - ALsizei i; - - context = GetContextRef(); - if(!context) return; - - if(!(n >= 0)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - for(i = 0;i < n;i++) - { - if(!LookupSource(context, sources[i])) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); - } - - LockContext(context); - for(i = 0;i < n;i++) - { - source = LookupSource(context, sources[i]); - source->new_state = AL_NONE; - SetSourceState(source, context, AL_INITIAL); - } - UnlockContext(context); - -done: - ALCcontext_DecRef(context); -} - - -AL_API ALvoid AL_APIENTRY alSourceQueueBuffers(ALuint src, ALsizei nb, const ALuint *buffers) -{ - ALCdevice *device; - ALCcontext *context; - ALsource *source; - ALsizei i; - ALbufferlistitem *BufferListStart; - ALbufferlistitem *BufferList; - ALbuffer *BufferFmt = NULL; - - if(nb == 0) - return; - - context = GetContextRef(); - if(!context) return; - - device = context->Device; - - if(!(nb >= 0)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - if((source=LookupSource(context, src)) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); - - WriteLock(&source->queue_lock); - if(source->SourceType == AL_STATIC) - { - WriteUnlock(&source->queue_lock); - /* Can't queue on a Static Source */ - SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, done); - } - - /* Check for a valid Buffer, for its frequency and format */ - BufferList = ATOMIC_LOAD(&source->queue); - while(BufferList) - { - if(BufferList->buffer) - { - BufferFmt = BufferList->buffer; - break; - } - BufferList = BufferList->next; - } - - BufferListStart = NULL; - BufferList = NULL; - for(i = 0;i < nb;i++) - { - ALbuffer *buffer = NULL; - if(buffers[i] && (buffer=LookupBuffer(device, buffers[i])) == NULL) - { - WriteUnlock(&source->queue_lock); - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, buffer_error); - } - - if(!BufferListStart) - { - BufferListStart = malloc(sizeof(ALbufferlistitem)); - BufferListStart->buffer = buffer; - BufferListStart->next = NULL; - BufferListStart->prev = NULL; - BufferList = BufferListStart; - } - else - { - BufferList->next = malloc(sizeof(ALbufferlistitem)); - BufferList->next->buffer = buffer; - BufferList->next->next = NULL; - BufferList->next->prev = BufferList; - BufferList = BufferList->next; - } - if(!buffer) continue; - - /* Hold a read lock on each buffer being queued while checking all - * provided buffers. This is done so other threads don't see an extra - * reference on some buffers if this operation ends up failing. */ - ReadLock(&buffer->lock); - IncrementRef(&buffer->ref); - - if(BufferFmt == NULL) - { - BufferFmt = buffer; - - source->NumChannels = ChannelsFromFmt(buffer->FmtChannels); - source->SampleSize = BytesFromFmt(buffer->FmtType); - } - else if(BufferFmt->Frequency != buffer->Frequency || - BufferFmt->OriginalChannels != buffer->OriginalChannels || - BufferFmt->OriginalType != buffer->OriginalType) - { - WriteUnlock(&source->queue_lock); - SET_ERROR_AND_GOTO(context, AL_INVALID_OPERATION, buffer_error); - - buffer_error: - /* A buffer failed (invalid ID or format), so unlock and release - * each buffer we had. */ - while(BufferList != NULL) - { - ALbufferlistitem *prev = BufferList->prev; - if((buffer=BufferList->buffer) != NULL) - { - DecrementRef(&buffer->ref); - ReadUnlock(&buffer->lock); - } - free(BufferList); - BufferList = prev; - } - goto done; - } - } - /* All buffers good, unlock them now. */ - while(BufferList != NULL) - { - ALbuffer *buffer = BufferList->buffer; - if(buffer) ReadUnlock(&buffer->lock); - BufferList = BufferList->prev; - } - - /* Source is now streaming */ - source->SourceType = AL_STREAMING; - - BufferList = NULL; - if(!ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->queue, &BufferList, BufferListStart)) - { - /* Queue head is not NULL, append to the end of the queue */ - while(BufferList->next != NULL) - BufferList = BufferList->next; - - BufferListStart->prev = BufferList; - BufferList->next = BufferListStart; - } - BufferList = NULL; - ATOMIC_COMPARE_EXCHANGE_STRONG(ALbufferlistitem*, &source->current_buffer, &BufferList, BufferListStart); - WriteUnlock(&source->queue_lock); - -done: - ALCcontext_DecRef(context); -} - -AL_API ALvoid AL_APIENTRY alSourceUnqueueBuffers(ALuint src, ALsizei nb, ALuint *buffers) -{ - ALCcontext *context; - ALsource *source; - ALbufferlistitem *NewHead; - ALbufferlistitem *OldHead; - ALbufferlistitem *Current; - ALsizei i; - - if(nb == 0) - return; - - context = GetContextRef(); - if(!context) return; - - if(!(nb >= 0)) - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - - if((source=LookupSource(context, src)) == NULL) - SET_ERROR_AND_GOTO(context, AL_INVALID_NAME, done); - - WriteLock(&source->queue_lock); - /* Find the new buffer queue head */ - NewHead = ATOMIC_LOAD(&source->queue); - Current = ATOMIC_LOAD(&source->current_buffer); - for(i = 0;i < nb && NewHead;i++) - { - if(NewHead == Current) - break; - NewHead = NewHead->next; - } - if(source->Looping || source->SourceType != AL_STREAMING || i != nb) - { - WriteUnlock(&source->queue_lock); - /* Trying to unqueue pending buffers, or a buffer that wasn't queued. */ - SET_ERROR_AND_GOTO(context, AL_INVALID_VALUE, done); - } - - /* Swap it, and cut the new head from the old. */ - OldHead = ATOMIC_EXCHANGE(ALbufferlistitem*, &source->queue, NewHead); - if(NewHead) - { - ALCdevice *device = context->Device; - ALbufferlistitem *OldTail = NewHead->prev; - uint count; - - /* Cut the new head's link back to the old body. The mixer is robust - * enough to handle the link back going away. Once the active mix (if - * any) is complete, it's safe to finish cutting the old tail from the - * new head. */ - NewHead->prev = NULL; - if(((count=ReadRef(&device->MixCount))&1) != 0) - { - while(count == ReadRef(&device->MixCount)) - althrd_yield(); - } - OldTail->next = NULL; - } - WriteUnlock(&source->queue_lock); - - while(OldHead != NULL) - { - ALbufferlistitem *next = OldHead->next; - ALbuffer *buffer = OldHead->buffer; - - if(!buffer) - *(buffers++) = 0; - else - { - *(buffers++) = buffer->id; - DecrementRef(&buffer->ref); - } - - free(OldHead); - OldHead = next; - } - -done: - ALCcontext_DecRef(context); -} - - -static ALvoid InitSourceParams(ALsource *Source) -{ - ALuint i; - - RWLockInit(&Source->queue_lock); - - 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; - Source->RefDistance = 1.0f; - Source->MaxDistance = FLT_MAX; - Source->RollOffFactor = 1.0f; - Source->Looping = AL_FALSE; - Source->Gain = 1.0f; - Source->MinGain = 0.0f; - Source->MaxGain = 1.0f; - Source->OuterGain = 0.0f; - Source->OuterGainHF = 1.0f; - - Source->DryGainHFAuto = AL_TRUE; - Source->WetGainAuto = AL_TRUE; - Source->WetGainHFAuto = AL_TRUE; - Source->AirAbsorptionFactor = 0.0f; - Source->RoomRolloffFactor = 0.0f; - Source->DopplerFactor = 1.0f; - Source->DirectChannels = AL_FALSE; - - Source->Radius = 0.0f; - - Source->DistanceModel = DefaultDistanceModel; - - Source->Resampler = DefaultResampler; - - Source->state = AL_INITIAL; - Source->new_state = AL_NONE; - Source->SourceType = AL_UNDETERMINED; - Source->Offset = -1.0; - - ATOMIC_INIT(&Source->queue, NULL); - ATOMIC_INIT(&Source->current_buffer, NULL); - - Source->Direct.Gain = 1.0f; - Source->Direct.GainHF = 1.0f; - Source->Direct.HFReference = LOWPASSFREQREF; - Source->Direct.GainLF = 1.0f; - Source->Direct.LFReference = HIGHPASSFREQREF; - for(i = 0;i < MAX_SENDS;i++) - { - Source->Send[i].Gain = 1.0f; - Source->Send[i].GainHF = 1.0f; - Source->Send[i].HFReference = LOWPASSFREQREF; - Source->Send[i].GainLF = 1.0f; - Source->Send[i].LFReference = HIGHPASSFREQREF; - } - - ATOMIC_INIT(&Source->NeedsUpdate, AL_TRUE); -} - - -/* SetSourceState - * - * Sets the source's new play state given its current state. - */ -ALvoid SetSourceState(ALsource *Source, ALCcontext *Context, ALenum state) -{ - ReadLock(&Source->queue_lock); - if(state == AL_PLAYING) - { - ALCdevice *device = Context->Device; - ALbufferlistitem *BufferList; - ALactivesource *src = NULL; - ALsizei j, k; - - /* Check that there is a queue containing at least one valid, non zero - * length Buffer. */ - BufferList = ATOMIC_LOAD(&Source->queue); - while(BufferList) - { - ALbuffer *buffer; - if((buffer=BufferList->buffer) != NULL && buffer->SampleLen > 0) - break; - BufferList = BufferList->next; - } - - if(Source->state != AL_PAUSED) - { - Source->state = AL_PLAYING; - Source->position = 0; - Source->position_fraction = 0; - ATOMIC_STORE(&Source->current_buffer, BufferList); - } - else - Source->state = AL_PLAYING; - - // Check if an Offset has been set - if(Source->Offset >= 0.0) - ApplyOffset(Source); - - /* 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++) - { - if(Context->ActiveSources[j]->Source == Source) - { - src = Context->ActiveSources[j]; - break; - } - } - if(src == 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; - } - else - { - ALuint i; - - src->Direct.Moving = AL_FALSE; - src->Direct.Counter = 0; - for(j = 0;j < MAX_INPUT_CHANNELS;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; - } - } - - if(BufferList->buffer->FmtChannels == FmtMono) - src->Update = CalcSourceParams; - else - src->Update = CalcNonAttnSourceParams; - - ATOMIC_STORE(&Source->NeedsUpdate, AL_TRUE); - } - else if(state == AL_PAUSED) - { - if(Source->state == AL_PLAYING) - Source->state = AL_PAUSED; - } - else if(state == AL_STOPPED) - { - do_stop: - if(Source->state != AL_INITIAL) - { - Source->state = AL_STOPPED; - ATOMIC_STORE(&Source->current_buffer, NULL); - } - Source->Offset = -1.0; - } - else if(state == AL_INITIAL) - { - if(Source->state != AL_INITIAL) - { - Source->state = AL_INITIAL; - Source->position = 0; - Source->position_fraction = 0; - ATOMIC_STORE(&Source->current_buffer, ATOMIC_LOAD(&Source->queue)); - } - Source->Offset = -1.0; - } - ReadUnlock(&Source->queue_lock); -} - -/* GetSourceOffset - * - * 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) -{ - const ALbufferlistitem *BufferList; - const ALbufferlistitem *Current; - ALuint64 readPos; - - if(Source->state != AL_PLAYING && Source->state != AL_PAUSED) - return 0; - - /* NOTE: This is the offset into the *current* buffer, so add the length of - * any played buffers */ - readPos = (ALuint64)Source->position << 32; - readPos |= (ALuint64)Source->position_fraction << (32-FRACTIONBITS); - BufferList = ATOMIC_LOAD(&Source->queue); - Current = ATOMIC_LOAD(&Source->current_buffer); - while(BufferList && BufferList != Current) - { - if(BufferList->buffer) - readPos += (ALuint64)BufferList->buffer->SampleLen << 32; - BufferList = BufferList->next; - } - - return (ALint64)minu64(readPos, U64(0x7fffffffffffffff)); -} - -/* GetSourceSecOffset - * - * Gets the current read offset for the given Source, in seconds. The offset is - * relative to the start of the queue (not the start of the current buffer). - */ -static ALdouble GetSourceSecOffset(const ALsource *Source) -{ - const ALbufferlistitem *BufferList; - const ALbufferlistitem *Current; - const ALbuffer *Buffer = NULL; - ALuint64 readPos; - - if(Source->state != AL_PLAYING && Source->state != AL_PAUSED) - return 0.0; - - /* NOTE: This is the offset into the *current* buffer, so add the length of - * any played buffers */ - readPos = (ALuint64)Source->position << FRACTIONBITS; - readPos |= (ALuint64)Source->position_fraction; - BufferList = ATOMIC_LOAD(&Source->queue); - Current = ATOMIC_LOAD(&Source->current_buffer); - while(BufferList && BufferList != Current) - { - const ALbuffer *buffer = BufferList->buffer; - if(buffer != NULL) - { - if(!Buffer) Buffer = buffer; - readPos += (ALuint64)buffer->SampleLen << FRACTIONBITS; - } - BufferList = BufferList->next; - } - - while(BufferList && !Buffer) - { - Buffer = BufferList->buffer; - BufferList = BufferList->next; - } - assert(Buffer != NULL); - - return (ALdouble)readPos / (ALdouble)FRACTIONONE / (ALdouble)Buffer->Frequency; -} - -/* GetSourceOffsets - * - * Gets the current read and write offsets for the given Source, in the - * 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) -{ - const ALbufferlistitem *BufferList; - const ALbufferlistitem *Current; - const ALbuffer *Buffer = NULL; - ALboolean readFin = AL_FALSE; - ALuint readPos, writePos; - ALuint totalBufferLen; - - if(Source->state != AL_PLAYING && Source->state != AL_PAUSED) - { - offset[0] = 0.0; - offset[1] = 0.0; - return; - } - - if(updateLen > 0.0 && updateLen < 0.015) - updateLen = 0.015; - - /* NOTE: This is the offset into the *current* buffer, so add the length of - * any played buffers */ - totalBufferLen = 0; - readPos = Source->position; - BufferList = ATOMIC_LOAD(&Source->queue); - Current = ATOMIC_LOAD(&Source->current_buffer); - while(BufferList != NULL) - { - const ALbuffer *buffer; - readFin = readFin || (BufferList == Current); - if((buffer=BufferList->buffer) != NULL) - { - if(!Buffer) Buffer = buffer; - totalBufferLen += buffer->SampleLen; - if(!readFin) readPos += buffer->SampleLen; - } - BufferList = BufferList->next; - } - assert(Buffer != NULL); - - if(Source->state == AL_PLAYING) - writePos = readPos + (ALuint)(updateLen*Buffer->Frequency); - else - writePos = readPos; - - if(Source->Looping) - { - readPos %= totalBufferLen; - writePos %= totalBufferLen; - } - else - { - /* Wrap positions back to 0 */ - if(readPos >= totalBufferLen) - readPos = 0; - if(writePos >= totalBufferLen) - writePos = 0; - } - - switch(name) - { - case AL_SEC_OFFSET: - offset[0] = (ALdouble)readPos / Buffer->Frequency; - offset[1] = (ALdouble)writePos / Buffer->Frequency; - break; - - case AL_SAMPLE_OFFSET: - case AL_SAMPLE_RW_OFFSETS_SOFT: - offset[0] = (ALdouble)readPos; - offset[1] = (ALdouble)writePos; - break; - - case AL_BYTE_OFFSET: - case AL_BYTE_RW_OFFSETS_SOFT: - if(Buffer->OriginalType == UserFmtIMA4) - { - ALsizei align = (Buffer->OriginalAlign-1)/2 + 4; - ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels); - ALuint FrameBlockSize = Buffer->OriginalAlign; - - /* Round down to nearest ADPCM block */ - offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize); - if(Source->state != AL_PLAYING) - offset[1] = offset[0]; - else - { - /* Round up to nearest ADPCM block */ - offset[1] = (ALdouble)((writePos+FrameBlockSize-1) / - FrameBlockSize * BlockSize); - } - } - else if(Buffer->OriginalType == UserFmtMSADPCM) - { - ALsizei align = (Buffer->OriginalAlign-2)/2 + 7; - ALuint BlockSize = align * ChannelsFromFmt(Buffer->FmtChannels); - ALuint FrameBlockSize = Buffer->OriginalAlign; - - /* Round down to nearest ADPCM block */ - offset[0] = (ALdouble)(readPos / FrameBlockSize * BlockSize); - if(Source->state != AL_PLAYING) - offset[1] = offset[0]; - else - { - /* Round up to nearest ADPCM block */ - offset[1] = (ALdouble)((writePos+FrameBlockSize-1) / - FrameBlockSize * BlockSize); - } - } - else - { - ALuint FrameSize = FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType); - offset[0] = (ALdouble)(readPos * FrameSize); - offset[1] = (ALdouble)(writePos * FrameSize); - } - break; - } -} - - -/* ApplyOffset - * - * Apply the stored playback offset to the Source. This function will update - * the number of buffers "played" given the stored offset. - */ -ALboolean ApplyOffset(ALsource *Source) -{ - ALbufferlistitem *BufferList; - const ALbuffer *Buffer; - ALint bufferLen, totalBufferLen; - ALint offset; - - /* Get sample frame offset */ - offset = GetSampleOffset(Source); - if(offset == -1) - return AL_FALSE; - - totalBufferLen = 0; - BufferList = ATOMIC_LOAD(&Source->queue); - while(BufferList && totalBufferLen <= offset) - { - Buffer = BufferList->buffer; - bufferLen = Buffer ? Buffer->SampleLen : 0; - - if(bufferLen > offset-totalBufferLen) - { - /* Offset is in this buffer */ - ATOMIC_STORE(&Source->current_buffer, BufferList); - - Source->position = offset - totalBufferLen; - Source->position_fraction = 0; - return AL_TRUE; - } - - totalBufferLen += bufferLen; - - BufferList = BufferList->next; - } - - /* Offset is out of range of the queue */ - return AL_FALSE; -} - - -/* 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. - */ -static ALint GetSampleOffset(ALsource *Source) -{ - const ALbuffer *Buffer = NULL; - const ALbufferlistitem *BufferList; - ALint Offset = -1; - - /* Find the first valid Buffer in the Queue */ - BufferList = ATOMIC_LOAD(&Source->queue); - while(BufferList) - { - if(BufferList->buffer) - { - Buffer = BufferList->buffer; - break; - } - BufferList = BufferList->next; - } - - if(!Buffer) - { - Source->Offset = -1.0; - return -1; - } - - switch(Source->OffsetType) - { - case AL_BYTE_OFFSET: - /* Determine the ByteOffset (and ensure it is block aligned) */ - Offset = (ALint)Source->Offset; - if(Buffer->OriginalType == UserFmtIMA4) - { - ALsizei align = (Buffer->OriginalAlign-1)/2 + 4; - 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; - } - else - Offset /= FrameSizeFromUserFmt(Buffer->OriginalChannels, Buffer->OriginalType); - break; - - case AL_SAMPLE_OFFSET: - Offset = (ALint)Source->Offset; - break; - - case AL_SEC_OFFSET: - Offset = (ALint)(Source->Offset * Buffer->Frequency); - break; - } - Source->Offset = -1.0; - - return Offset; -} - - -/* ReleaseALSources - * - * Destroys all sources in the source map. - */ -ALvoid ReleaseALSources(ALCcontext *Context) -{ - ALbufferlistitem *item; - ALsizei pos; - ALuint j; - for(pos = 0;pos < Context->SourceMap.size;pos++) - { - ALsource *temp = Context->SourceMap.array[pos].value; - Context->SourceMap.array[pos].value = NULL; - - item = ATOMIC_EXCHANGE(ALbufferlistitem*, &temp->queue, NULL); - while(item != NULL) - { - ALbufferlistitem *next = item->next; - if(item->buffer != NULL) - DecrementRef(&item->buffer->ref); - free(item); - item = next; - } - - for(j = 0;j < MAX_SENDS;++j) - { - if(temp->Send[j].Slot) - DecrementRef(&temp->Send[j].Slot->ref); - temp->Send[j].Slot = NULL; - } - - FreeThunkEntry(temp->id); - memset(temp, 0, sizeof(*temp)); - al_free(temp); - } -} diff --git a/love/src/jni/openal-soft-1.17.0/build/.empty b/love/src/jni/openal-soft-1.17.0/build/.empty deleted file mode 100644 index e69de29b..00000000 diff --git a/love/src/jni/openal-soft-1.17.0/cmake/FindDSound.cmake b/love/src/jni/openal-soft-1.17.0/cmake/FindDSound.cmake deleted file mode 100644 index 36cdf4b5..00000000 --- a/love/src/jni/openal-soft-1.17.0/cmake/FindDSound.cmake +++ /dev/null @@ -1,33 +0,0 @@ -# - Find DirectSound includes and libraries -# -# DSOUND_FOUND - True if DSOUND_INCLUDE_DIR & DSOUND_LIBRARY are found -# DSOUND_LIBRARIES - Set when DSOUND_LIBRARY is found -# DSOUND_INCLUDE_DIRS - Set when DSOUND_INCLUDE_DIR is found -# -# DSOUND_INCLUDE_DIR - where to find dsound.h, etc. -# DSOUND_LIBRARY - the dsound library -# - -find_path(DSOUND_INCLUDE_DIR - PATHS "${DXSDK_DIR}/include" - NAMES dsound.h - DOC "The DirectSound include directory" -) - -find_library(DSOUND_LIBRARY - PATHS "${DXSDK_DIR}/lib" - NAMES dsound - DOC "The DirectSound library" -) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(DSound - REQUIRED_VARS DSOUND_LIBRARY DSOUND_INCLUDE_DIR -) - -if(DSOUND_FOUND) - set(DSOUND_LIBRARIES ${DSOUND_LIBRARY}) - set(DSOUND_INCLUDE_DIRS ${DSOUND_INCLUDE_DIR}) -endif() - -mark_as_advanced(DSOUND_INCLUDE_DIR DSOUND_LIBRARY) diff --git a/love/src/jni/openal-soft-1.17.0/cmake/FindFluidSynth.cmake b/love/src/jni/openal-soft-1.17.0/cmake/FindFluidSynth.cmake deleted file mode 100644 index fe96b225..00000000 --- a/love/src/jni/openal-soft-1.17.0/cmake/FindFluidSynth.cmake +++ /dev/null @@ -1,19 +0,0 @@ -# - Find fluidsynth -# Find the native fluidsynth includes and library -# -# FLUIDSYNTH_INCLUDE_DIR - where to find fluidsynth.h -# FLUIDSYNTH_LIBRARIES - List of libraries when using fluidsynth. -# FLUIDSYNTH_FOUND - True if fluidsynth found. - - -FIND_PATH(FLUIDSYNTH_INCLUDE_DIR fluidsynth.h) - -FIND_LIBRARY(FLUIDSYNTH_LIBRARIES NAMES fluidsynth ) -MARK_AS_ADVANCED( FLUIDSYNTH_LIBRARIES FLUIDSYNTH_INCLUDE_DIR ) - -# handle the QUIETLY and REQUIRED arguments and set FLUIDSYNTH_FOUND to TRUE if -# all listed variables are TRUE -INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(FluidSynth - REQUIRED_VARS FLUIDSYNTH_LIBRARIES FLUIDSYNTH_INCLUDE_DIR) - diff --git a/love/src/jni/openal-soft-1.17.0/cmake/FindSDL_sound.cmake b/love/src/jni/openal-soft-1.17.0/cmake/FindSDL_sound.cmake deleted file mode 100644 index 2dab1a1c..00000000 --- a/love/src/jni/openal-soft-1.17.0/cmake/FindSDL_sound.cmake +++ /dev/null @@ -1,380 +0,0 @@ -# - Locates the SDL_sound library -# -# This module depends on SDL being found and -# must be called AFTER FindSDL.cmake or FindSDL2.cmake is called. -# -# This module defines -# SDL_SOUND_INCLUDE_DIR, where to find SDL_sound.h -# SDL_SOUND_FOUND, if false, do not try to link to SDL_sound -# SDL_SOUND_LIBRARIES, this contains the list of libraries that you need -# to link against. This is a read-only variable and is marked INTERNAL. -# SDL_SOUND_EXTRAS, this is an optional variable for you to add your own -# flags to SDL_SOUND_LIBRARIES. This is prepended to SDL_SOUND_LIBRARIES. -# This is available mostly for cases this module failed to anticipate for -# and you must add additional flags. This is marked as ADVANCED. -# SDL_SOUND_VERSION_STRING, human-readable string containing the version of SDL_sound -# -# This module also defines (but you shouldn't need to use directly) -# SDL_SOUND_LIBRARY, the name of just the SDL_sound library you would link -# against. Use SDL_SOUND_LIBRARIES for you link instructions and not this one. -# And might define the following as needed -# MIKMOD_LIBRARY -# MODPLUG_LIBRARY -# OGG_LIBRARY -# VORBIS_LIBRARY -# SMPEG_LIBRARY -# FLAC_LIBRARY -# SPEEX_LIBRARY -# -# Typically, you should not use these variables directly, and you should use -# SDL_SOUND_LIBRARIES which contains SDL_SOUND_LIBRARY and the other audio libraries -# (if needed) to successfully compile on your system. -# -# Created by Eric Wing. -# This module is a bit more complicated than the other FindSDL* family modules. -# The reason is that SDL_sound can be compiled in a large variety of different ways -# which are independent of platform. SDL_sound may dynamically link against other 3rd -# party libraries to get additional codec support, such as Ogg Vorbis, SMPEG, ModPlug, -# MikMod, FLAC, Speex, and potentially others. -# Under some circumstances which I don't fully understand, -# there seems to be a requirement -# that dependent libraries of libraries you use must also be explicitly -# linked against in order to successfully compile. SDL_sound does not currently -# have any system in place to know how it was compiled. -# So this CMake module does the hard work in trying to discover which 3rd party -# libraries are required for building (if any). -# This module uses a brute force approach to create a test program that uses SDL_sound, -# and then tries to build it. If the build fails, it parses the error output for -# known symbol names to figure out which libraries are needed. -# -# Responds to the $SDLDIR and $SDLSOUNDDIR environmental variable that would -# correspond to the ./configure --prefix=$SDLDIR used in building SDL. -# -# On OSX, this will prefer the Framework version (if found) over others. -# People will have to manually change the cache values of -# SDL_LIBRARY or SDL2_LIBRARY to override this selection or set the CMake -# environment CMAKE_INCLUDE_PATH to modify the search paths. - -#============================================================================= -# Copyright 2005-2009 Kitware, Inc. -# Copyright 2012 Benjamin Eikel -# -# Distributed under the OSI-approved BSD License (the "License"); -# see accompanying file Copyright.txt for details. -# -# This software is distributed WITHOUT ANY WARRANTY; without even the -# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -# See the License for more information. -#============================================================================= -# (To distribute this file outside of CMake, substitute the full -# License text for the above reference.) - -set(SDL_SOUND_EXTRAS "" CACHE STRING "SDL_sound extra flags") -mark_as_advanced(SDL_SOUND_EXTRAS) - -# Find SDL_sound.h -find_path(SDL_SOUND_INCLUDE_DIR SDL_sound.h - HINTS - ENV SDLSOUNDDIR - ENV SDLDIR - PATH_SUFFIXES SDL SDL12 SDL11 -) - -find_library(SDL_SOUND_LIBRARY - NAMES SDL_sound - HINTS - ENV SDLSOUNDDIR - ENV SDLDIR -) - -if(SDL2_FOUND OR SDL_FOUND) - if(SDL_SOUND_INCLUDE_DIR AND SDL_SOUND_LIBRARY) - # CMake is giving me problems using TRY_COMPILE with the CMAKE_FLAGS - # for the :STRING syntax if I have multiple values contained in a - # single variable. This is a problem for the SDL2_LIBRARY variable - # because it does just that. When I feed this variable to the command, - # only the first value gets the appropriate modifier (e.g. -I) and - # the rest get dropped. - # To get multiple single variables to work, I must separate them with a "\;" - # I could go back and modify the FindSDL2.cmake module, but that's kind of painful. - # The solution would be to try something like: - # set(SDL2_TRY_COMPILE_LIBRARY_LIST "${SDL2_TRY_COMPILE_LIBRARY_LIST}\;${CMAKE_THREAD_LIBS_INIT}") - # Instead, it was suggested on the mailing list to write a temporary CMakeLists.txt - # with a temporary test project and invoke that with TRY_COMPILE. - # See message thread "Figuring out dependencies for a library in order to build" - # 2005-07-16 - # try_compile( - # MY_RESULT - # ${CMAKE_BINARY_DIR} - # ${PROJECT_SOURCE_DIR}/DetermineSoundLibs.c - # CMAKE_FLAGS - # -DINCLUDE_DIRECTORIES:STRING=${SDL2_INCLUDE_DIR}\;${SDL_SOUND_INCLUDE_DIR} - # -DLINK_LIBRARIES:STRING=${SDL_SOUND_LIBRARY}\;${SDL2_LIBRARY} - # OUTPUT_VARIABLE MY_OUTPUT - # ) - - # To minimize external dependencies, create a sdlsound test program - # which will be used to figure out if additional link dependencies are - # required for the link phase. - file(WRITE ${PROJECT_BINARY_DIR}/CMakeTmp/DetermineSoundLibs.c - "#include \"SDL_sound.h\" - #include \"SDL.h\" - int main(int argc, char* argv[]) - { - Sound_AudioInfo desired; - Sound_Sample* sample; - - SDL_Init(0); - Sound_Init(); - - /* This doesn't actually have to work, but Init() is a no-op - * for some of the decoders, so this should force more symbols - * to be pulled in. - */ - sample = Sound_NewSampleFromFile(argv[1], &desired, 4096); - - Sound_Quit(); - SDL_Quit(); - return 0; - }" - ) - - # Calling - # target_link_libraries(DetermineSoundLibs "${SDL_SOUND_LIBRARY} ${SDL2_LIBRARY}) - # causes problems when SDL2_LIBRARY looks like - # /Library/Frameworks/SDL2.framework;-framework Cocoa - # 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) - if(SDL2_FOUND) - foreach(lib ${SDL_SOUND_LIBRARY} ${SDL2_LIBRARY}) - set(TMP_TRY_LIBS "${TMP_TRY_LIBS} \"${lib}\"") - endforeach() - set(TMP_INCLUDE_DIRS ${SDL2_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR}) - else() - foreach(lib ${SDL_SOUND_LIBRARY} ${SDL_LIBRARY}) - set(TMP_TRY_LIBS "${TMP_TRY_LIBS} \"${lib}\"") - endforeach() - set(TMP_INCLUDE_DIRS ${SDL_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR}) - endif() - - # 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) - - 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. - - set(SDL_SOUND_LIBRARIES_TMP ${SDL_SOUND_LIBRARY}) - - # 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 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}) - 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}) - endif() - endif() - endif() - - 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() - endif() -endif() - -if(SDL_SOUND_INCLUDE_DIR AND EXISTS "${SDL_SOUND_INCLUDE_DIR}/SDL_sound.h") - file(STRINGS "${SDL_SOUND_INCLUDE_DIR}/SDL_sound.h" SDL_SOUND_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SOUND_VER_MAJOR[ \t]+[0-9]+$") - file(STRINGS "${SDL_SOUND_INCLUDE_DIR}/SDL_sound.h" SDL_SOUND_VERSION_MINOR_LINE REGEX "^#define[ \t]+SOUND_VER_MINOR[ \t]+[0-9]+$") - file(STRINGS "${SDL_SOUND_INCLUDE_DIR}/SDL_sound.h" SDL_SOUND_VERSION_PATCH_LINE REGEX "^#define[ \t]+SOUND_VER_PATCH[ \t]+[0-9]+$") - string(REGEX REPLACE "^#define[ \t]+SOUND_VER_MAJOR[ \t]+([0-9]+)$" "\\1" SDL_SOUND_VERSION_MAJOR "${SDL_SOUND_VERSION_MAJOR_LINE}") - string(REGEX REPLACE "^#define[ \t]+SOUND_VER_MINOR[ \t]+([0-9]+)$" "\\1" SDL_SOUND_VERSION_MINOR "${SDL_SOUND_VERSION_MINOR_LINE}") - string(REGEX REPLACE "^#define[ \t]+SOUND_VER_PATCH[ \t]+([0-9]+)$" "\\1" SDL_SOUND_VERSION_PATCH "${SDL_SOUND_VERSION_PATCH_LINE}") - set(SDL_SOUND_VERSION_STRING ${SDL_SOUND_VERSION_MAJOR}.${SDL_SOUND_VERSION_MINOR}.${SDL_SOUND_VERSION_PATCH}) - unset(SDL_SOUND_VERSION_MAJOR_LINE) - unset(SDL_SOUND_VERSION_MINOR_LINE) - unset(SDL_SOUND_VERSION_PATCH_LINE) - unset(SDL_SOUND_VERSION_MAJOR) - unset(SDL_SOUND_VERSION_MINOR) - unset(SDL_SOUND_VERSION_PATCH) -endif() - -include(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL_sound - REQUIRED_VARS SDL_SOUND_LIBRARIES SDL_SOUND_INCLUDE_DIR - VERSION_VAR SDL_SOUND_VERSION_STRING) diff --git a/love/src/jni/openal-soft-1.17.0/common/uintmap.c b/love/src/jni/openal-soft-1.17.0/common/uintmap.c deleted file mode 100644 index b7a9a29c..00000000 --- a/love/src/jni/openal-soft-1.17.0/common/uintmap.c +++ /dev/null @@ -1,144 +0,0 @@ - -#include "config.h" - -#include "uintmap.h" - -#include -#include - - -extern inline void LockUIntMapRead(UIntMap *map); -extern inline void UnlockUIntMapRead(UIntMap *map); -extern inline void LockUIntMapWrite(UIntMap *map); -extern inline void UnlockUIntMapWrite(UIntMap *map); - - -void InitUIntMap(UIntMap *map, ALsizei limit) -{ - map->array = NULL; - map->size = 0; - map->maxsize = 0; - map->limit = limit; - RWLockInit(&map->lock); -} - -void ResetUIntMap(UIntMap *map) -{ - WriteLock(&map->lock); - free(map->array); - map->array = NULL; - map->size = 0; - map->maxsize = 0; - WriteUnlock(&map->lock); -} - -ALenum InsertUIntMapEntry(UIntMap *map, ALuint key, ALvoid *value) -{ - ALsizei pos = 0; - - WriteLock(&map->lock); - if(map->size > 0) - { - ALsizei low = 0; - ALsizei high = map->size - 1; - while(low < high) - { - ALsizei mid = low + (high-low)/2; - if(map->array[mid].key < key) - low = mid + 1; - else - high = mid; - } - if(map->array[low].key < key) - low++; - pos = low; - } - - if(pos == map->size || map->array[pos].key != key) - { - if(map->size == map->limit) - { - WriteUnlock(&map->lock); - return AL_OUT_OF_MEMORY; - } - - if(map->size == map->maxsize) - { - ALvoid *temp = NULL; - ALsizei newsize; - - newsize = (map->maxsize ? (map->maxsize<<1) : 4); - if(newsize >= map->maxsize) - temp = realloc(map->array, newsize*sizeof(map->array[0])); - if(!temp) - { - WriteUnlock(&map->lock); - return AL_OUT_OF_MEMORY; - } - map->array = temp; - map->maxsize = newsize; - } - - if(pos < map->size) - memmove(&map->array[pos+1], &map->array[pos], - (map->size-pos)*sizeof(map->array[0])); - map->size++; - } - map->array[pos].key = key; - map->array[pos].value = value; - WriteUnlock(&map->lock); - - return AL_NO_ERROR; -} - -ALvoid *RemoveUIntMapKey(UIntMap *map, ALuint key) -{ - ALvoid *ptr = NULL; - WriteLock(&map->lock); - if(map->size > 0) - { - ALsizei low = 0; - ALsizei high = map->size - 1; - while(low < high) - { - ALsizei mid = low + (high-low)/2; - if(map->array[mid].key < key) - low = mid + 1; - else - high = mid; - } - if(map->array[low].key == key) - { - ptr = map->array[low].value; - if(low < map->size-1) - memmove(&map->array[low], &map->array[low+1], - (map->size-1-low)*sizeof(map->array[0])); - map->size--; - } - } - WriteUnlock(&map->lock); - return ptr; -} - -ALvoid *LookupUIntMapKey(UIntMap *map, ALuint key) -{ - ALvoid *ptr = NULL; - ReadLock(&map->lock); - if(map->size > 0) - { - ALsizei low = 0; - ALsizei high = map->size - 1; - while(low < high) - { - ALsizei mid = low + (high-low)/2; - if(map->array[mid].key < key) - low = mid + 1; - else - high = mid; - } - if(map->array[low].key == key) - ptr = map->array[low].value; - } - ReadUnlock(&map->lock); - return ptr; -} diff --git a/love/src/jni/openal-soft-1.17.0/examples/alffplay.c b/love/src/jni/openal-soft-1.17.0/examples/alffplay.c deleted file mode 100644 index d8ef0e57..00000000 --- a/love/src/jni/openal-soft-1.17.0/examples/alffplay.c +++ /dev/null @@ -1,1479 +0,0 @@ -/* - * alffplay.c - * - * A pedagogical video player that really works! Now with seeking features. - * - * Code based on FFplay, Copyright (c) 2003 Fabrice Bellard, and a tutorial by - * Martin Bohme . - * - * Requires C99. - */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "threads.h" -#include "bool.h" - -#include "AL/al.h" -#include "AL/alc.h" -#include "AL/alext.h" - - -static bool has_latency_check = false; -static LPALGETSOURCEDVSOFT alGetSourcedvSOFT; - -#define AUDIO_BUFFER_TIME 100 /* In milliseconds, per-buffer */ -#define AUDIO_BUFFER_QUEUE_SIZE 8 /* Number of buffers to queue */ -#define MAX_AUDIOQ_SIZE (5 * 16 * 1024) /* Bytes of compressed audio data to keep queued */ -#define MAX_VIDEOQ_SIZE (5 * 256 * 1024) /* Bytes of compressed video data to keep queued */ -#define AV_SYNC_THRESHOLD 0.01 -#define AV_NOSYNC_THRESHOLD 10.0 -#define SAMPLE_CORRECTION_MAX_DIFF 0.1 -#define AUDIO_DIFF_AVG_NB 20 -#define VIDEO_PICTURE_QUEUE_SIZE 16 - -enum { - FF_UPDATE_EVENT = SDL_USEREVENT, - FF_REFRESH_EVENT, - FF_QUIT_EVENT -}; - - -typedef struct PacketQueue { - AVPacketList *first_pkt, *last_pkt; - volatile int nb_packets; - volatile int size; - volatile bool flushing; - almtx_t mutex; - alcnd_t cond; -} PacketQueue; - -typedef struct VideoPicture { - SDL_Texture *bmp; - int width, height; /* Logical image size (actual size may be larger) */ - volatile bool updated; - double pts; -} VideoPicture; - -typedef struct AudioState { - AVStream *st; - - PacketQueue q; - AVPacket pkt; - - /* Used for clock difference average computation */ - double diff_accum; - double diff_avg_coef; - double diff_threshold; - - /* Time (in seconds) of the next sample to be buffered */ - double current_pts; - - /* Decompressed sample frame, and swresample context for conversion */ - AVFrame *decoded_aframe; - struct SwrContext *swres_ctx; - - /* Conversion format, for what gets fed to OpenAL */ - int dst_ch_layout; - enum AVSampleFormat dst_sample_fmt; - - /* Storage of converted samples */ - uint8_t *samples; - ssize_t samples_len; /* In samples */ - ssize_t samples_pos; - int samples_max; - - /* OpenAL format */ - ALenum format; - ALint frame_size; - - ALuint source; - ALuint buffer[AUDIO_BUFFER_QUEUE_SIZE]; - ALuint buffer_idx; - almtx_t src_mutex; - - althrd_t thread; -} AudioState; - -typedef struct VideoState { - AVStream *st; - - PacketQueue q; - - double clock; - double frame_timer; - double frame_last_pts; - double frame_last_delay; - double current_pts; - /* time (av_gettime) at which we updated current_pts - used to have running video pts */ - int64_t current_pts_time; - - /* Decompressed video frame, and swscale context for conversion */ - AVFrame *decoded_vframe; - struct SwsContext *swscale_ctx; - - VideoPicture pictq[VIDEO_PICTURE_QUEUE_SIZE]; - int pictq_size, pictq_rindex, pictq_windex; - almtx_t pictq_mutex; - alcnd_t pictq_cond; - - althrd_t thread; -} VideoState; - -typedef struct MovieState { - AVFormatContext *pFormatCtx; - int videoStream, audioStream; - - volatile bool seek_req; - int64_t seek_pos; - - int av_sync_type; - - int64_t external_clock_base; - - AudioState audio; - VideoState video; - - althrd_t parse_thread; - - char filename[1024]; - - volatile bool quit; -} MovieState; - -enum { - AV_SYNC_AUDIO_MASTER, - AV_SYNC_VIDEO_MASTER, - AV_SYNC_EXTERNAL_MASTER, - - DEFAULT_AV_SYNC_TYPE = AV_SYNC_EXTERNAL_MASTER -}; - -static AVPacket flush_pkt = { .data = (uint8_t*)"FLUSH" }; - -static void packet_queue_init(PacketQueue *q) -{ - memset(q, 0, sizeof(PacketQueue)); - almtx_init(&q->mutex, almtx_plain); - alcnd_init(&q->cond); -} -static int packet_queue_put(PacketQueue *q, AVPacket *pkt) -{ - AVPacketList *pkt1; - if(pkt != &flush_pkt && !pkt->buf && av_dup_packet(pkt) < 0) - return -1; - - pkt1 = av_malloc(sizeof(AVPacketList)); - if(!pkt1) return -1; - pkt1->pkt = *pkt; - pkt1->next = NULL; - - almtx_lock(&q->mutex); - if(!q->last_pkt) - q->first_pkt = pkt1; - else - q->last_pkt->next = pkt1; - q->last_pkt = pkt1; - q->nb_packets++; - q->size += pkt1->pkt.size; - almtx_unlock(&q->mutex); - - alcnd_signal(&q->cond); - return 0; -} -static int packet_queue_get(PacketQueue *q, AVPacket *pkt, MovieState *state) -{ - AVPacketList *pkt1; - int ret = -1; - - almtx_lock(&q->mutex); - while(!state->quit) - { - pkt1 = q->first_pkt; - if(pkt1) - { - q->first_pkt = pkt1->next; - if(!q->first_pkt) - q->last_pkt = NULL; - q->nb_packets--; - q->size -= pkt1->pkt.size; - *pkt = pkt1->pkt; - av_free(pkt1); - ret = 1; - break; - } - - if(q->flushing) - { - ret = 0; - break; - } - alcnd_wait(&q->cond, &q->mutex); - } - almtx_unlock(&q->mutex); - return ret; -} -static void packet_queue_clear(PacketQueue *q) -{ - AVPacketList *pkt, *pkt1; - - almtx_lock(&q->mutex); - for(pkt = q->first_pkt;pkt != NULL;pkt = pkt1) - { - pkt1 = pkt->next; - if(pkt->pkt.data != flush_pkt.data) - av_free_packet(&pkt->pkt); - av_freep(&pkt); - } - q->last_pkt = NULL; - q->first_pkt = NULL; - q->nb_packets = 0; - q->size = 0; - almtx_unlock(&q->mutex); -} -static void packet_queue_flush(PacketQueue *q) -{ - almtx_lock(&q->mutex); - q->flushing = true; - almtx_unlock(&q->mutex); - alcnd_signal(&q->cond); -} -static void packet_queue_deinit(PacketQueue *q) -{ - packet_queue_clear(q); - alcnd_destroy(&q->cond); - almtx_destroy(&q->mutex); -} - - -static double get_audio_clock(AudioState *state) -{ - double pts; - - almtx_lock(&state->src_mutex); - /* The audio clock is the timestamp of the sample currently being heard. - * It's based on 4 components: - * 1 - The timestamp of the next sample to buffer (state->current_pts) - * 2 - The length of the source's buffer queue (AL_SEC_LENGTH_SOFT) - * 3 - The offset OpenAL is currently at in the source (the first value - * from AL_SEC_OFFSET_LATENCY_SOFT) - * 4 - The latency between OpenAL and the DAC (the second value from - * AL_SEC_OFFSET_LATENCY_SOFT) - * - * Subtracting the length of the source queue from the next sample's - * timestamp gives the timestamp of the sample at start of the source - * queue. Adding the source offset to that results in the timestamp for - * OpenAL's current position, and subtracting the source latency from that - * gives the timestamp of the sample currently at the DAC. - */ - pts = state->current_pts; - if(state->source) - { - ALdouble offset[2] = { 0.0, 0.0 }; - ALdouble queue_len = 0.0; - ALint status; - - /* NOTE: The source state must be checked last, in case an underrun - * occurs and the source stops between retrieving the offset+latency - * and getting the state. */ - if(has_latency_check) - { - alGetSourcedvSOFT(state->source, AL_SEC_OFFSET_LATENCY_SOFT, offset); - alGetSourcedvSOFT(state->source, AL_SEC_LENGTH_SOFT, &queue_len); - } - else - { - ALint ioffset, ilen; - alGetSourcei(state->source, AL_SAMPLE_OFFSET, &ioffset); - alGetSourcei(state->source, AL_SAMPLE_LENGTH_SOFT, &ilen); - offset[0] = (double)ioffset / state->st->codec->sample_rate; - queue_len = (double)ilen / state->st->codec->sample_rate; - } - alGetSourcei(state->source, AL_SOURCE_STATE, &status); - - /* If the source is AL_STOPPED, then there was an underrun and all - * buffers are processed, so ignore the source queue. The audio thread - * will put the source into an AL_INITIAL state and clear the queue - * when it starts recovery. */ - if(status != AL_STOPPED) - pts = pts - queue_len + offset[0]; - if(status == AL_PLAYING) - pts = pts - offset[1]; - } - almtx_unlock(&state->src_mutex); - - return (pts >= 0.0) ? pts : 0.0; -} -static double get_video_clock(VideoState *state) -{ - double delta = (av_gettime() - state->current_pts_time) / 1000000.0; - return state->current_pts + delta; -} -static double get_external_clock(MovieState *movState) -{ - return (av_gettime()-movState->external_clock_base) / 1000000.0; -} - -double get_master_clock(MovieState *movState) -{ - if(movState->av_sync_type == AV_SYNC_VIDEO_MASTER) - return get_video_clock(&movState->video); - if(movState->av_sync_type == AV_SYNC_AUDIO_MASTER) - return get_audio_clock(&movState->audio); - return get_external_clock(movState); -} - -/* Return how many samples to skip to maintain sync (negative means to - * duplicate samples). */ -static int synchronize_audio(MovieState *movState) -{ - double diff, avg_diff; - double ref_clock; - - if(movState->av_sync_type == AV_SYNC_AUDIO_MASTER) - return 0; - - ref_clock = get_master_clock(movState); - diff = ref_clock - get_audio_clock(&movState->audio); - - if(!(diff < AV_NOSYNC_THRESHOLD)) - { - /* Difference is TOO big; reset diff stuff */ - movState->audio.diff_accum = 0.0; - return 0; - } - - /* Accumulate the diffs */ - movState->audio.diff_accum = movState->audio.diff_accum*movState->audio.diff_avg_coef + diff; - avg_diff = movState->audio.diff_accum*(1.0 - movState->audio.diff_avg_coef); - if(fabs(avg_diff) < movState->audio.diff_threshold) - return 0; - - /* Constrain the per-update difference to avoid exceedingly large skips */ - if(!(diff <= SAMPLE_CORRECTION_MAX_DIFF)) - diff = SAMPLE_CORRECTION_MAX_DIFF; - else if(!(diff >= -SAMPLE_CORRECTION_MAX_DIFF)) - diff = -SAMPLE_CORRECTION_MAX_DIFF; - return (int)(diff*movState->audio.st->codec->sample_rate); -} - -static int audio_decode_frame(MovieState *movState) -{ - AVPacket *pkt = &movState->audio.pkt; - - while(!movState->quit) - { - while(!movState->quit && pkt->size == 0) - { - av_free_packet(pkt); - - /* Get the next packet */ - int err; - if((err=packet_queue_get(&movState->audio.q, pkt, movState)) <= 0) - { - if(err == 0) - break; - return err; - } - if(pkt->data == flush_pkt.data) - { - avcodec_flush_buffers(movState->audio.st->codec); - movState->audio.diff_accum = 0.0; - movState->audio.current_pts = av_q2d(movState->audio.st->time_base)*pkt->pts; - - alSourceRewind(movState->audio.source); - alSourcei(movState->audio.source, AL_BUFFER, 0); - - av_new_packet(pkt, 0); - - return -1; - } - - /* If provided, update w/ pts */ - if(pkt->pts != AV_NOPTS_VALUE) - movState->audio.current_pts = av_q2d(movState->audio.st->time_base)*pkt->pts; - } - - AVFrame *frame = movState->audio.decoded_aframe; - int got_frame = 0; - int len1 = avcodec_decode_audio4(movState->audio.st->codec, frame, - &got_frame, pkt); - if(len1 < 0) break; - - if(len1 <= pkt->size) - { - /* Move the unread data to the front and clear the end bits */ - int remaining = pkt->size - len1; - memmove(pkt->data, &pkt->data[len1], remaining); - av_shrink_packet(pkt, remaining); - } - - if(!got_frame || frame->nb_samples <= 0) - { - av_frame_unref(frame); - continue; - } - - if(frame->nb_samples > movState->audio.samples_max) - { - av_freep(&movState->audio.samples); - av_samples_alloc( - &movState->audio.samples, NULL, movState->audio.st->codec->channels, - frame->nb_samples, movState->audio.dst_sample_fmt, 0 - ); - movState->audio.samples_max = frame->nb_samples; - } - /* Return the amount of sample frames converted */ - int data_size = swr_convert(movState->audio.swres_ctx, - &movState->audio.samples, frame->nb_samples, - (const uint8_t**)frame->data, frame->nb_samples - ); - - av_frame_unref(frame); - return data_size; - } - - return -1; -} - -static int read_audio(MovieState *movState, uint8_t *samples, int length) -{ - int sample_skip = synchronize_audio(movState); - int audio_size = 0; - - /* Read the next chunk of data, refill the buffer, and queue it - * on the source */ - length /= movState->audio.frame_size; - while(audio_size < length) - { - if(movState->audio.samples_len <= 0 || movState->audio.samples_pos >= movState->audio.samples_len) - { - int frame_len = audio_decode_frame(movState); - if(frame_len < 0) return -1; - - movState->audio.samples_len = frame_len; - if(movState->audio.samples_len == 0) - break; - - movState->audio.samples_pos = (movState->audio.samples_len < sample_skip) ? - movState->audio.samples_len : sample_skip; - sample_skip -= movState->audio.samples_pos; - - movState->audio.current_pts += (double)movState->audio.samples_pos / - (double)movState->audio.st->codec->sample_rate; - continue; - } - - int rem = length - audio_size; - if(movState->audio.samples_pos >= 0) - { - int n = movState->audio.frame_size; - int len = movState->audio.samples_len - movState->audio.samples_pos; - if(rem > len) rem = len; - memcpy(samples + audio_size*n, - movState->audio.samples + movState->audio.samples_pos*n, - rem*n); - } - else - { - int n = movState->audio.frame_size; - int len = -movState->audio.samples_pos; - if(rem > len) rem = len; - - /* Add samples by copying the first sample */ - if(n == 1) - { - uint8_t sample = ((uint8_t*)movState->audio.samples)[0]; - uint8_t *q = (uint8_t*)samples + audio_size; - for(int i = 0;i < rem;i++) - *(q++) = sample; - } - else if(n == 2) - { - uint16_t sample = ((uint16_t*)movState->audio.samples)[0]; - uint16_t *q = (uint16_t*)samples + audio_size; - for(int i = 0;i < rem;i++) - *(q++) = sample; - } - else if(n == 4) - { - uint32_t sample = ((uint32_t*)movState->audio.samples)[0]; - uint32_t *q = (uint32_t*)samples + audio_size; - for(int i = 0;i < rem;i++) - *(q++) = sample; - } - else if(n == 8) - { - uint64_t sample = ((uint64_t*)movState->audio.samples)[0]; - uint64_t *q = (uint64_t*)samples + audio_size; - for(int i = 0;i < rem;i++) - *(q++) = sample; - } - else - { - uint8_t *sample = movState->audio.samples; - uint8_t *q = samples + audio_size*n; - for(int i = 0;i < rem;i++) - { - memcpy(q, sample, n); - q += n; - } - } - } - - movState->audio.samples_pos += rem; - movState->audio.current_pts += (double)rem / movState->audio.st->codec->sample_rate; - audio_size += rem; - } - - return audio_size * movState->audio.frame_size; -} - -static int audio_thread(void *userdata) -{ - MovieState *movState = (MovieState*)userdata; - uint8_t *samples = NULL; - ALsizei buffer_len; - - alGenBuffers(AUDIO_BUFFER_QUEUE_SIZE, movState->audio.buffer); - alGenSources(1, &movState->audio.source); - - alSourcei(movState->audio.source, AL_SOURCE_RELATIVE, AL_TRUE); - alSourcei(movState->audio.source, AL_ROLLOFF_FACTOR, 0); - - av_new_packet(&movState->audio.pkt, 0); - - /* Find a suitable format for OpenAL. Currently does not handle surround - * sound (everything non-mono becomes stereo). */ - 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_MONO) - { - movState->audio.dst_ch_layout = AV_CH_LAYOUT_MONO; - movState->audio.frame_size *= 1; - movState->audio.format = AL_FORMAT_MONO8; - } - else - { - 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")) - { - movState->audio.dst_sample_fmt = AV_SAMPLE_FMT_FLT; - movState->audio.frame_size = 4; - 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 - { - movState->audio.dst_ch_layout = AV_CH_LAYOUT_STEREO; - movState->audio.frame_size *= 2; - movState->audio.format = AL_FORMAT_STEREO_FLOAT32; - } - } - else - { - movState->audio.dst_sample_fmt = AV_SAMPLE_FMT_S16; - movState->audio.frame_size = 2; - 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 - { - movState->audio.dst_ch_layout = AV_CH_LAYOUT_STEREO; - movState->audio.frame_size *= 2; - movState->audio.format = AL_FORMAT_STEREO16; - } - } - buffer_len = AUDIO_BUFFER_TIME * movState->audio.st->codec->sample_rate / 1000 * - movState->audio.frame_size; - samples = av_malloc(buffer_len); - - movState->audio.samples = NULL; - movState->audio.samples_max = 0; - movState->audio.samples_pos = 0; - movState->audio.samples_len = 0; - - if(!(movState->audio.decoded_aframe=av_frame_alloc())) - { - fprintf(stderr, "Failed to allocate audio frame\n"); - goto finish; - } - - movState->audio.swres_ctx = swr_alloc_set_opts(NULL, - 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->sample_fmt, - movState->audio.st->codec->sample_rate, - 0, NULL - ); - if(!movState->audio.swres_ctx || swr_init(movState->audio.swres_ctx) != 0) - { - fprintf(stderr, "Failed to initialize audio converter\n"); - goto finish; - } - - almtx_lock(&movState->audio.src_mutex); - while(alGetError() == AL_NO_ERROR && !movState->quit) - { - /* First remove any processed buffers. */ - ALint processed; - alGetSourcei(movState->audio.source, AL_BUFFERS_PROCESSED, &processed); - alSourceUnqueueBuffers(movState->audio.source, processed, (ALuint[AUDIO_BUFFER_QUEUE_SIZE]){}); - - /* Refill the buffer queue. */ - ALint queued; - alGetSourcei(movState->audio.source, AL_BUFFERS_QUEUED, &queued); - while(queued < AUDIO_BUFFER_QUEUE_SIZE) - { - int audio_size; - - /* Read the next chunk of data, fill the buffer, and queue it on - * the source */ - audio_size = read_audio(movState, samples, buffer_len); - if(audio_size < 0) break; - - ALuint bufid = movState->audio.buffer[movState->audio.buffer_idx++]; - movState->audio.buffer_idx %= AUDIO_BUFFER_QUEUE_SIZE; - - alBufferData(bufid, movState->audio.format, samples, audio_size, - movState->audio.st->codec->sample_rate); - alSourceQueueBuffers(movState->audio.source, 1, &bufid); - queued++; - } - - /* Check that the source is playing. */ - ALint state; - alGetSourcei(movState->audio.source, AL_SOURCE_STATE, &state); - if(state == AL_STOPPED) - { - /* AL_STOPPED means there was an underrun. Double-check that all - * processed buffers are removed, then rewind the source to get it - * back into an AL_INITIAL state. */ - alGetSourcei(movState->audio.source, AL_BUFFERS_PROCESSED, &processed); - alSourceUnqueueBuffers(movState->audio.source, processed, (ALuint[AUDIO_BUFFER_QUEUE_SIZE]){}); - alSourceRewind(movState->audio.source); - continue; - } - - almtx_unlock(&movState->audio.src_mutex); - - /* (re)start the source if needed, and wait for a buffer to finish */ - if(state != AL_PLAYING && state != AL_PAUSED) - { - alGetSourcei(movState->audio.source, AL_BUFFERS_QUEUED, &queued); - if(queued > 0) alSourcePlay(movState->audio.source); - } - SDL_Delay(AUDIO_BUFFER_TIME); - - almtx_lock(&movState->audio.src_mutex); - } - almtx_unlock(&movState->audio.src_mutex); - -finish: - av_frame_free(&movState->audio.decoded_aframe); - swr_free(&movState->audio.swres_ctx); - - av_freep(&samples); - av_freep(&movState->audio.samples); - - alDeleteSources(1, &movState->audio.source); - alDeleteBuffers(AUDIO_BUFFER_QUEUE_SIZE, movState->audio.buffer); - - return 0; -} - - -static Uint32 sdl_refresh_timer_cb(Uint32 interval, void *opaque) -{ - (void)interval; - - SDL_PushEvent(&(SDL_Event){ .user={.type=FF_REFRESH_EVENT, .data1=opaque} }); - return 0; /* 0 means stop timer */ -} - -/* Schedule a video refresh in 'delay' ms */ -static void schedule_refresh(MovieState *movState, int delay) -{ - SDL_AddTimer(delay, sdl_refresh_timer_cb, movState); -} - -static void video_display(MovieState *movState, SDL_Window *screen, SDL_Renderer *renderer) -{ - VideoPicture *vp = &movState->video.pictq[movState->video.pictq_rindex]; - - if(!vp->bmp) - return; - - float aspect_ratio; - int win_w, win_h; - int w, h, x, y; - - if(movState->video.st->codec->sample_aspect_ratio.num == 0) - aspect_ratio = 0.0f; - else - { - aspect_ratio = av_q2d(movState->video.st->codec->sample_aspect_ratio) * - movState->video.st->codec->width / - movState->video.st->codec->height; - } - if(aspect_ratio <= 0.0f) - { - aspect_ratio = (float)movState->video.st->codec->width / - (float)movState->video.st->codec->height; - } - - SDL_GetWindowSize(screen, &win_w, &win_h); - h = win_h; - w = ((int)rint(h * aspect_ratio) + 3) & ~3; - if(w > win_w) - { - w = win_w; - h = ((int)rint(w / aspect_ratio) + 3) & ~3; - } - x = (win_w - w) / 2; - y = (win_h - h) / 2; - - SDL_RenderCopy(renderer, vp->bmp, - &(SDL_Rect){ .x=0, .y=0, .w=vp->width, .h=vp->height }, - &(SDL_Rect){ .x=x, .y=y, .w=w, .h=h } - ); - SDL_RenderPresent(renderer); -} - -static void video_refresh_timer(MovieState *movState, SDL_Window *screen, SDL_Renderer *renderer) -{ - if(!movState->video.st) - { - schedule_refresh(movState, 100); - return; - } - - almtx_lock(&movState->video.pictq_mutex); -retry: - if(movState->video.pictq_size == 0) - schedule_refresh(movState, 1); - else - { - VideoPicture *vp = &movState->video.pictq[movState->video.pictq_rindex]; - double actual_delay, delay, sync_threshold, ref_clock, diff; - - movState->video.current_pts = vp->pts; - movState->video.current_pts_time = av_gettime(); - - delay = vp->pts - movState->video.frame_last_pts; /* the pts from last time */ - if(delay <= 0 || delay >= 1.0) - { - /* if incorrect delay, use previous one */ - delay = movState->video.frame_last_delay; - } - /* save for next time */ - movState->video.frame_last_delay = delay; - movState->video.frame_last_pts = vp->pts; - - /* Update delay to sync to clock if not master source. */ - if(movState->av_sync_type != AV_SYNC_VIDEO_MASTER) - { - ref_clock = get_master_clock(movState); - diff = vp->pts - ref_clock; - - /* Skip or repeat the frame. Take delay into account. */ - sync_threshold = (delay > AV_SYNC_THRESHOLD) ? delay : AV_SYNC_THRESHOLD; - if(fabs(diff) < AV_NOSYNC_THRESHOLD) - { - if(diff <= -sync_threshold) - delay = 0; - else if(diff >= sync_threshold) - delay = 2 * delay; - } - } - - movState->video.frame_timer += delay; - /* Compute the REAL delay. */ - actual_delay = movState->video.frame_timer - (av_gettime() / 1000000.0); - if(!(actual_delay >= 0.010)) - { - /* We don't have time to handle this picture, just skip to the next one. */ - movState->video.pictq_rindex = (movState->video.pictq_rindex+1)%VIDEO_PICTURE_QUEUE_SIZE; - movState->video.pictq_size--; - alcnd_signal(&movState->video.pictq_cond); - goto retry; - } - schedule_refresh(movState, (int)(actual_delay*1000.0 + 0.5)); - - /* Show the picture! */ - video_display(movState, screen, renderer); - - /* Update queue for next picture. */ - movState->video.pictq_rindex = (movState->video.pictq_rindex+1)%VIDEO_PICTURE_QUEUE_SIZE; - movState->video.pictq_size--; - alcnd_signal(&movState->video.pictq_cond); - } - almtx_unlock(&movState->video.pictq_mutex); -} - - -static void update_picture(MovieState *movState, bool *first_update, SDL_Window *screen, SDL_Renderer *renderer) -{ - VideoPicture *vp = &movState->video.pictq[movState->video.pictq_windex]; - - /* allocate or resize the buffer! */ - if(!vp->bmp || vp->width != movState->video.st->codec->width || - vp->height != movState->video.st->codec->height) - { - if(vp->bmp) - SDL_DestroyTexture(vp->bmp); - vp->bmp = SDL_CreateTexture( - renderer, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STREAMING, - movState->video.st->codec->coded_width, movState->video.st->codec->coded_height - ); - if(!vp->bmp) - fprintf(stderr, "Failed to create YV12 texture!\n"); - vp->width = movState->video.st->codec->width; - vp->height = movState->video.st->codec->height; - - if(*first_update && vp->width > 0 && vp->height > 0) - { - /* For the first update, set the window size to the video size. */ - *first_update = false; - - int w = vp->width; - int h = vp->height; - if(movState->video.st->codec->sample_aspect_ratio.num != 0 && - movState->video.st->codec->sample_aspect_ratio.den != 0) - { - double aspect_ratio = av_q2d(movState->video.st->codec->sample_aspect_ratio); - if(aspect_ratio >= 1.0) - w = (int)(w*aspect_ratio + 0.5); - else if(aspect_ratio > 0.0) - h = (int)(h/aspect_ratio + 0.5); - } - SDL_SetWindowSize(screen, w, h); - } - } - - if(vp->bmp) - { - AVFrame *frame = movState->video.decoded_vframe; - void *pixels = NULL; - int pitch = 0; - - if(movState->video.st->codec->pix_fmt == PIX_FMT_YUV420P) - SDL_UpdateYUVTexture(vp->bmp, NULL, - frame->data[0], frame->linesize[0], - frame->data[1], frame->linesize[1], - frame->data[2], frame->linesize[2] - ); - else if(SDL_LockTexture(vp->bmp, NULL, &pixels, &pitch) != 0) - fprintf(stderr, "Failed to lock texture\n"); - else - { - // Convert the image into YUV format that SDL uses - int coded_w = movState->video.st->codec->coded_width; - int coded_h = movState->video.st->codec->coded_height; - int w = movState->video.st->codec->width; - int h = movState->video.st->codec->height; - if(!movState->video.swscale_ctx) - movState->video.swscale_ctx = sws_getContext( - w, h, movState->video.st->codec->pix_fmt, - w, h, PIX_FMT_YUV420P, SWS_X, NULL, NULL, NULL - ); - - /* point pict at the queue */ - AVPicture pict; - pict.data[0] = pixels; - pict.data[2] = pict.data[0] + coded_w*coded_h; - pict.data[1] = pict.data[2] + coded_w*coded_h/4; - - pict.linesize[0] = pitch; - pict.linesize[2] = pitch / 2; - pict.linesize[1] = pitch / 2; - - sws_scale(movState->video.swscale_ctx, (const uint8_t**)frame->data, - frame->linesize, 0, h, pict.data, pict.linesize); - SDL_UnlockTexture(vp->bmp); - } - } - - almtx_lock(&movState->video.pictq_mutex); - vp->updated = true; - almtx_unlock(&movState->video.pictq_mutex); - alcnd_signal(&movState->video.pictq_cond); -} - -static int queue_picture(MovieState *movState, double pts) -{ - /* Wait until we have space for a new pic */ - almtx_lock(&movState->video.pictq_mutex); - while(movState->video.pictq_size >= VIDEO_PICTURE_QUEUE_SIZE && !movState->quit) - alcnd_wait(&movState->video.pictq_cond, &movState->video.pictq_mutex); - almtx_unlock(&movState->video.pictq_mutex); - - if(movState->quit) - return -1; - - VideoPicture *vp = &movState->video.pictq[movState->video.pictq_windex]; - - /* We have to create/update the picture in the main thread */ - vp->updated = false; - SDL_PushEvent(&(SDL_Event){ .user={.type=FF_UPDATE_EVENT, .data1=movState} }); - - /* Wait until the picture is updated. */ - almtx_lock(&movState->video.pictq_mutex); - while(!vp->updated && !movState->quit) - alcnd_wait(&movState->video.pictq_cond, &movState->video.pictq_mutex); - almtx_unlock(&movState->video.pictq_mutex); - if(movState->quit) - return -1; - vp->pts = pts; - - movState->video.pictq_windex = (movState->video.pictq_windex+1)%VIDEO_PICTURE_QUEUE_SIZE; - almtx_lock(&movState->video.pictq_mutex); - movState->video.pictq_size++; - almtx_unlock(&movState->video.pictq_mutex); - - return 0; -} - -static double synchronize_video(MovieState *movState, double pts) -{ - double frame_delay; - - if(pts == 0.0) /* if we aren't given a pts, set it to the clock */ - pts = movState->video.clock; - else /* if we have pts, set video clock to it */ - movState->video.clock = pts; - - /* update the video clock */ - frame_delay = av_q2d(movState->video.st->codec->time_base); - /* if we are repeating a frame, adjust clock accordingly */ - frame_delay += movState->video.decoded_vframe->repeat_pict * (frame_delay * 0.5); - movState->video.clock += frame_delay; - return pts; -} - -int video_thread(void *arg) -{ - MovieState *movState = (MovieState*)arg; - AVPacket *packet = (AVPacket[1]){}; - int64_t saved_pts, pkt_pts; - int frameFinished; - - movState->video.decoded_vframe = av_frame_alloc(); - while(packet_queue_get(&movState->video.q, packet, movState) >= 0) - { - if(packet->data == flush_pkt.data) - { - avcodec_flush_buffers(movState->video.st->codec); - - almtx_lock(&movState->video.pictq_mutex); - movState->video.pictq_size = 0; - movState->video.pictq_rindex = 0; - movState->video.pictq_windex = 0; - almtx_unlock(&movState->video.pictq_mutex); - - movState->video.clock = av_q2d(movState->video.st->time_base)*packet->pts; - movState->video.current_pts = movState->video.clock; - movState->video.current_pts_time = av_gettime(); - continue; - } - - pkt_pts = packet->pts; - - /* Decode video frame */ - avcodec_decode_video2(movState->video.st->codec, movState->video.decoded_vframe, - &frameFinished, packet); - if(pkt_pts != AV_NOPTS_VALUE && !movState->video.decoded_vframe->opaque) - { - /* Store the packet's original pts in the frame, in case the frame - * is not finished decoding yet. */ - saved_pts = pkt_pts; - movState->video.decoded_vframe->opaque = &saved_pts; - } - - av_free_packet(packet); - - if(frameFinished) - { - double pts = av_q2d(movState->video.st->time_base); - if(packet->dts != AV_NOPTS_VALUE) - pts *= packet->dts; - else if(movState->video.decoded_vframe->opaque) - pts *= *(int64_t*)movState->video.decoded_vframe->opaque; - else - pts *= 0.0; - movState->video.decoded_vframe->opaque = NULL; - - pts = synchronize_video(movState, pts); - if(queue_picture(movState, pts) < 0) - break; - } - } - - sws_freeContext(movState->video.swscale_ctx); - movState->video.swscale_ctx = NULL; - av_frame_free(&movState->video.decoded_vframe); - return 0; -} - - -static int stream_component_open(MovieState *movState, int stream_index) -{ - AVFormatContext *pFormatCtx = movState->pFormatCtx; - AVCodecContext *codecCtx; - AVCodec *codec; - - if(stream_index < 0 || (unsigned int)stream_index >= pFormatCtx->nb_streams) - return -1; - - /* Get a pointer to the codec context for the video stream, and open the - * associated codec */ - codecCtx = pFormatCtx->streams[stream_index]->codec; - - codec = avcodec_find_decoder(codecCtx->codec_id); - if(!codec || avcodec_open2(codecCtx, codec, NULL) < 0) - { - fprintf(stderr, "Unsupported codec!\n"); - return -1; - } - - /* Initialize and start the media type handler */ - switch(codecCtx->codec_type) - { - case AVMEDIA_TYPE_AUDIO: - movState->audioStream = stream_index; - movState->audio.st = pFormatCtx->streams[stream_index]; - - /* Averaging filter for audio sync */ - movState->audio.diff_avg_coef = exp(log(0.01) / AUDIO_DIFF_AVG_NB); - /* Correct audio only if larger error than this */ - movState->audio.diff_threshold = 2.0 * 0.050/* 50 ms */; - - memset(&movState->audio.pkt, 0, sizeof(movState->audio.pkt)); - if(althrd_create(&movState->audio.thread, audio_thread, movState) != althrd_success) - { - movState->audioStream = -1; - movState->audio.st = NULL; - } - break; - - case AVMEDIA_TYPE_VIDEO: - movState->videoStream = stream_index; - movState->video.st = pFormatCtx->streams[stream_index]; - - movState->video.current_pts_time = av_gettime(); - movState->video.frame_timer = (double)movState->video.current_pts_time / - 1000000.0; - movState->video.frame_last_delay = 40e-3; - - if(althrd_create(&movState->video.thread, video_thread, movState) != althrd_success) - { - movState->videoStream = -1; - movState->video.st = NULL; - } - break; - - default: - break; - } - - return 0; -} - -static int decode_interrupt_cb(void *ctx) -{ - return ((MovieState*)ctx)->quit; -} - -int decode_thread(void *arg) -{ - MovieState *movState = (MovieState *)arg; - AVFormatContext *fmtCtx = movState->pFormatCtx; - AVPacket *packet = (AVPacket[1]){}; - int video_index = -1; - int audio_index = -1; - - movState->videoStream = -1; - movState->audioStream = -1; - - /* Dump information about file onto standard error */ - av_dump_format(fmtCtx, 0, movState->filename, 0); - - /* Find the first video and audio streams */ - for(unsigned int i = 0;i < fmtCtx->nb_streams;i++) - { - if(fmtCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO && video_index < 0) - video_index = i; - else if(fmtCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO && audio_index < 0) - audio_index = i; - } - movState->external_clock_base = av_gettime(); - if(audio_index >= 0) - stream_component_open(movState, audio_index); - if(video_index >= 0) - stream_component_open(movState, video_index); - - if(movState->videoStream < 0 && movState->audioStream < 0) - { - fprintf(stderr, "%s: could not open codecs\n", movState->filename); - goto fail; - } - - /* Main packet handling loop */ - while(!movState->quit) - { - if(movState->seek_req) - { - int64_t seek_target = movState->seek_pos; - int stream_index= -1; - - /* Prefer seeking on the video stream. */ - if(movState->videoStream >= 0) - stream_index = movState->videoStream; - else if(movState->audioStream >= 0) - stream_index = movState->audioStream; - - /* Get a seek timestamp for the appropriate stream. */ - int64_t timestamp = seek_target; - if(stream_index >= 0) - timestamp = av_rescale_q(seek_target, AV_TIME_BASE_Q, fmtCtx->streams[stream_index]->time_base); - - if(av_seek_frame(movState->pFormatCtx, stream_index, timestamp, 0) < 0) - fprintf(stderr, "%s: error while seeking\n", movState->pFormatCtx->filename); - else - { - /* Seek successful, clear the packet queues and send a special - * 'flush' packet with the new stream clock time. */ - if(movState->audioStream >= 0) - { - packet_queue_clear(&movState->audio.q); - flush_pkt.pts = av_rescale_q(seek_target, AV_TIME_BASE_Q, - fmtCtx->streams[movState->audioStream]->time_base - ); - packet_queue_put(&movState->audio.q, &flush_pkt); - } - if(movState->videoStream >= 0) - { - packet_queue_clear(&movState->video.q); - flush_pkt.pts = av_rescale_q(seek_target, AV_TIME_BASE_Q, - fmtCtx->streams[movState->videoStream]->time_base - ); - packet_queue_put(&movState->video.q, &flush_pkt); - } - movState->external_clock_base = av_gettime() - seek_target; - } - movState->seek_req = false; - } - - if(movState->audio.q.size >= MAX_AUDIOQ_SIZE || - movState->video.q.size >= MAX_VIDEOQ_SIZE) - { - SDL_Delay(10); - continue; - } - - if(av_read_frame(movState->pFormatCtx, packet) < 0) - { - packet_queue_flush(&movState->video.q); - packet_queue_flush(&movState->audio.q); - break; - } - - /* Place the packet in the queue it's meant for, or discard it. */ - if(packet->stream_index == movState->videoStream) - packet_queue_put(&movState->video.q, packet); - else if(packet->stream_index == movState->audioStream) - packet_queue_put(&movState->audio.q, packet); - else - av_free_packet(packet); - } - - /* all done - wait for it */ - while(!movState->quit) - { - if(movState->audio.q.nb_packets == 0 && movState->video.q.nb_packets == 0) - break; - SDL_Delay(100); - } - -fail: - movState->quit = true; - packet_queue_flush(&movState->video.q); - packet_queue_flush(&movState->audio.q); - - if(movState->videoStream >= 0) - althrd_join(movState->video.thread, NULL); - if(movState->audioStream >= 0) - althrd_join(movState->audio.thread, NULL); - - SDL_PushEvent(&(SDL_Event){ .user={.type=FF_QUIT_EVENT, .data1=movState} }); - - return 0; -} - - -static void stream_seek(MovieState *movState, double incr) -{ - if(!movState->seek_req) - { - double newtime = get_master_clock(movState)+incr; - if(newtime <= 0.0) movState->seek_pos = 0; - else movState->seek_pos = (int64_t)(newtime * AV_TIME_BASE); - movState->seek_req = true; - } -} - -int main(int argc, char *argv[]) -{ - SDL_Event event; - MovieState *movState; - bool first_update = true; - SDL_Window *screen; - SDL_Renderer *renderer; - ALCdevice *device; - ALCcontext *context; - - if(argc < 2) - { - fprintf(stderr, "Usage: %s \n", argv[0]); - return 1; - } - /* Register all formats and codecs */ - av_register_all(); - /* Initialize networking protocols */ - avformat_network_init(); - - if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER)) - { - fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError()); - return 1; - } - - /* Make a window to put our video */ - screen = SDL_CreateWindow("alffplay", 0, 0, 640, 480, SDL_WINDOW_RESIZABLE); - if(!screen) - { - fprintf(stderr, "SDL: could not set video mode - exiting\n"); - return 1; - } - /* Make a renderer to handle the texture image surface and rendering. */ - renderer = SDL_CreateRenderer(screen, -1, SDL_RENDERER_ACCELERATED); - if(renderer) - { - SDL_RendererInfo rinf; - bool ok = false; - - /* Make sure the renderer supports YV12 textures. If not, fallback to a - * software renderer. */ - if(SDL_GetRendererInfo(renderer, &rinf) == 0) - { - for(Uint32 i = 0;!ok && i < rinf.num_texture_formats;i++) - ok = (rinf.texture_formats[i] == SDL_PIXELFORMAT_YV12); - } - if(!ok) - { - fprintf(stderr, "YV12 pixelformat textures not supported on renderer %s\n", rinf.name); - SDL_DestroyRenderer(renderer); - renderer = NULL; - } - } - if(!renderer) - renderer = SDL_CreateRenderer(screen, -1, SDL_RENDERER_SOFTWARE); - if(!renderer) - { - fprintf(stderr, "SDL: could not create renderer - exiting\n"); - return 1; - } - SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); - SDL_RenderFillRect(renderer, NULL); - SDL_RenderPresent(renderer); - - /* Open an audio device */ - device = alcOpenDevice(NULL); - if(!device) - { - fprintf(stderr, "OpenAL: could not open device - exiting\n"); - return 1; - } - context = alcCreateContext(device, NULL); - if(!context) - { - fprintf(stderr, "OpenAL: could not create context - exiting\n"); - return 1; - } - if(alcMakeContextCurrent(context) == ALC_FALSE) - { - fprintf(stderr, "OpenAL: could not make context current - exiting\n"); - return 1; - } - - if(!alIsExtensionPresent("AL_SOFT_source_length")) - { - fprintf(stderr, "Required AL_SOFT_source_length not supported - exiting\n"); - return 1; - } - - if(!alIsExtensionPresent("AL_SOFT_source_latency")) - fprintf(stderr, "AL_SOFT_source_latency not supported, audio may be a bit laggy.\n"); - else - { - alGetSourcedvSOFT = alGetProcAddress("alGetSourcedvSOFT"); - has_latency_check = true; - } - - - movState = av_mallocz(sizeof(MovieState)); - - av_strlcpy(movState->filename, argv[1], sizeof(movState->filename)); - - packet_queue_init(&movState->audio.q); - packet_queue_init(&movState->video.q); - - almtx_init(&movState->video.pictq_mutex, almtx_plain); - alcnd_init(&movState->video.pictq_cond); - almtx_init(&movState->audio.src_mutex, almtx_recursive); - - movState->av_sync_type = DEFAULT_AV_SYNC_TYPE; - - movState->pFormatCtx = avformat_alloc_context(); - movState->pFormatCtx->interrupt_callback = (AVIOInterruptCB){.callback=decode_interrupt_cb, .opaque=movState}; - - if(avio_open2(&movState->pFormatCtx->pb, movState->filename, AVIO_FLAG_READ, - &movState->pFormatCtx->interrupt_callback, NULL)) - { - fprintf(stderr, "Failed to open %s\n", movState->filename); - return 1; - } - - /* Open movie file */ - if(avformat_open_input(&movState->pFormatCtx, movState->filename, NULL, NULL) != 0) - { - fprintf(stderr, "Failed to open %s\n", movState->filename); - return 1; - } - - /* Retrieve stream information */ - if(avformat_find_stream_info(movState->pFormatCtx, NULL) < 0) - { - fprintf(stderr, "%s: failed to find stream info\n", movState->filename); - return 1; - } - - schedule_refresh(movState, 40); - - - if(althrd_create(&movState->parse_thread, decode_thread, movState) != althrd_success) - { - fprintf(stderr, "Failed to create parse thread!\n"); - return 1; - } - while(SDL_WaitEvent(&event) == 1) - { - switch(event.type) - { - case SDL_KEYDOWN: - switch(event.key.keysym.sym) - { - case SDLK_ESCAPE: - movState->quit = true; - break; - - case SDLK_LEFT: - stream_seek(movState, -10.0); - break; - case SDLK_RIGHT: - stream_seek(movState, 10.0); - break; - case SDLK_UP: - stream_seek(movState, 30.0); - break; - case SDLK_DOWN: - stream_seek(movState, -30.0); - break; - - default: - break; - } - break; - - case SDL_WINDOWEVENT: - switch(event.window.event) - { - case SDL_WINDOWEVENT_RESIZED: - SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); - SDL_RenderFillRect(renderer, NULL); - break; - - default: - break; - } - break; - - case SDL_QUIT: - movState->quit = true; - break; - - case FF_UPDATE_EVENT: - update_picture(event.user.data1, &first_update, screen, renderer); - break; - - case FF_REFRESH_EVENT: - video_refresh_timer(event.user.data1, screen, renderer); - break; - - case FF_QUIT_EVENT: - althrd_join(movState->parse_thread, NULL); - - avformat_close_input(&movState->pFormatCtx); - - almtx_destroy(&movState->audio.src_mutex); - almtx_destroy(&movState->video.pictq_mutex); - alcnd_destroy(&movState->video.pictq_cond); - packet_queue_deinit(&movState->video.q); - packet_queue_deinit(&movState->audio.q); - - alcMakeContextCurrent(NULL); - alcDestroyContext(context); - alcCloseDevice(device); - - SDL_Quit(); - exit(0); - - default: - break; - } - } - - fprintf(stderr, "SDL_WaitEvent error - %s\n", SDL_GetError()); - return 1; -} diff --git a/love/src/jni/openal-soft-1.17.0/examples/common/alhelpers.c b/love/src/jni/openal-soft-1.17.0/examples/common/alhelpers.c deleted file mode 100644 index 4582321c..00000000 --- a/love/src/jni/openal-soft-1.17.0/examples/common/alhelpers.c +++ /dev/null @@ -1,327 +0,0 @@ -/* - * OpenAL Helpers - * - * Copyright (c) 2011 by Chris Robinson - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -/* This file contains routines to help with some menial OpenAL-related tasks, - * such as opening a device and setting up a context, closing the device and - * destroying its context, converting between frame counts and byte lengths, - * finding an appropriate buffer format, and getting readable strings for - * channel configs and sample types. */ - -#include - -#include "AL/al.h" -#include "AL/alc.h" -#include "AL/alext.h" - -#include "alhelpers.h" - - -/* InitAL opens the default device and sets up a context using default - * attributes, making the program ready to call OpenAL functions. */ -int InitAL(void) -{ - ALCdevice *device; - ALCcontext *ctx; - - /* Open and initialize a device with default settings */ - device = alcOpenDevice(NULL); - if(!device) - { - fprintf(stderr, "Could not open a device!\n"); - return 1; - } - - ctx = alcCreateContext(device, NULL); - if(ctx == NULL || alcMakeContextCurrent(ctx) == ALC_FALSE) - { - if(ctx != NULL) - alcDestroyContext(ctx); - alcCloseDevice(device); - fprintf(stderr, "Could not set a context!\n"); - return 1; - } - - printf("Opened \"%s\"\n", alcGetString(device, ALC_DEVICE_SPECIFIER)); - return 0; -} - -/* CloseAL closes the device belonging to the current context, and destroys the - * context. */ -void CloseAL(void) -{ - ALCdevice *device; - ALCcontext *ctx; - - ctx = alcGetCurrentContext(); - if(ctx == NULL) - return; - - device = alcGetContextsDevice(ctx); - - alcMakeContextCurrent(NULL); - alcDestroyContext(ctx); - alcCloseDevice(device); -} - - -/* GetFormat retrieves a compatible buffer format given the channel config and - * sample type. If an alIsBufferFormatSupportedSOFT-compatible function is - * provided, it will be called to find the closest-matching format from - * AL_SOFT_buffer_samples. Returns AL_NONE (0) if no supported format can be - * found. */ -ALenum GetFormat(ALenum channels, ALenum type, LPALISBUFFERFORMATSUPPORTEDSOFT palIsBufferFormatSupportedSOFT) -{ - ALenum format = AL_NONE; - - /* If using AL_SOFT_buffer_samples, try looking through its formats */ - if(palIsBufferFormatSupportedSOFT) - { - /* AL_SOFT_buffer_samples is more lenient with matching formats. The - * specified sample type does not need to match the returned format, - * but it is nice to try to get something close. */ - if(type == AL_UNSIGNED_BYTE_SOFT || type == AL_BYTE_SOFT) - { - if(channels == AL_MONO_SOFT) format = AL_MONO8_SOFT; - else if(channels == AL_STEREO_SOFT) format = AL_STEREO8_SOFT; - else if(channels == AL_QUAD_SOFT) format = AL_QUAD8_SOFT; - else if(channels == AL_5POINT1_SOFT) format = AL_5POINT1_8_SOFT; - else if(channels == AL_6POINT1_SOFT) format = AL_6POINT1_8_SOFT; - else if(channels == AL_7POINT1_SOFT) format = AL_7POINT1_8_SOFT; - } - else if(type == AL_UNSIGNED_SHORT_SOFT || type == AL_SHORT_SOFT) - { - if(channels == AL_MONO_SOFT) format = AL_MONO16_SOFT; - else if(channels == AL_STEREO_SOFT) format = AL_STEREO16_SOFT; - else if(channels == AL_QUAD_SOFT) format = AL_QUAD16_SOFT; - else if(channels == AL_5POINT1_SOFT) format = AL_5POINT1_16_SOFT; - else if(channels == AL_6POINT1_SOFT) format = AL_6POINT1_16_SOFT; - else if(channels == AL_7POINT1_SOFT) format = AL_7POINT1_16_SOFT; - } - else if(type == AL_UNSIGNED_BYTE3_SOFT || type == AL_BYTE3_SOFT || - type == AL_UNSIGNED_INT_SOFT || type == AL_INT_SOFT || - type == AL_FLOAT_SOFT || type == AL_DOUBLE_SOFT) - { - if(channels == AL_MONO_SOFT) format = AL_MONO32F_SOFT; - else if(channels == AL_STEREO_SOFT) format = AL_STEREO32F_SOFT; - else if(channels == AL_QUAD_SOFT) format = AL_QUAD32F_SOFT; - else if(channels == AL_5POINT1_SOFT) format = AL_5POINT1_32F_SOFT; - else if(channels == AL_6POINT1_SOFT) format = AL_6POINT1_32F_SOFT; - else if(channels == AL_7POINT1_SOFT) format = AL_7POINT1_32F_SOFT; - } - - if(format != AL_NONE && !palIsBufferFormatSupportedSOFT(format)) - format = AL_NONE; - - /* A matching format was not found or supported. Try 32-bit float. */ - if(format == AL_NONE) - { - if(channels == AL_MONO_SOFT) format = AL_MONO32F_SOFT; - else if(channels == AL_STEREO_SOFT) format = AL_STEREO32F_SOFT; - else if(channels == AL_QUAD_SOFT) format = AL_QUAD32F_SOFT; - else if(channels == AL_5POINT1_SOFT) format = AL_5POINT1_32F_SOFT; - else if(channels == AL_6POINT1_SOFT) format = AL_6POINT1_32F_SOFT; - else if(channels == AL_7POINT1_SOFT) format = AL_7POINT1_32F_SOFT; - - if(format != AL_NONE && !palIsBufferFormatSupportedSOFT(format)) - format = AL_NONE; - } - /* 32-bit float not supported. Try 16-bit int. */ - if(format == AL_NONE) - { - if(channels == AL_MONO_SOFT) format = AL_MONO16_SOFT; - else if(channels == AL_STEREO_SOFT) format = AL_STEREO16_SOFT; - else if(channels == AL_QUAD_SOFT) format = AL_QUAD16_SOFT; - else if(channels == AL_5POINT1_SOFT) format = AL_5POINT1_16_SOFT; - else if(channels == AL_6POINT1_SOFT) format = AL_6POINT1_16_SOFT; - else if(channels == AL_7POINT1_SOFT) format = AL_7POINT1_16_SOFT; - - if(format != AL_NONE && !palIsBufferFormatSupportedSOFT(format)) - format = AL_NONE; - } - /* 16-bit int not supported. Try 8-bit int. */ - if(format == AL_NONE) - { - if(channels == AL_MONO_SOFT) format = AL_MONO8_SOFT; - else if(channels == AL_STEREO_SOFT) format = AL_STEREO8_SOFT; - else if(channels == AL_QUAD_SOFT) format = AL_QUAD8_SOFT; - else if(channels == AL_5POINT1_SOFT) format = AL_5POINT1_8_SOFT; - else if(channels == AL_6POINT1_SOFT) format = AL_6POINT1_8_SOFT; - else if(channels == AL_7POINT1_SOFT) format = AL_7POINT1_8_SOFT; - - if(format != AL_NONE && !palIsBufferFormatSupportedSOFT(format)) - format = AL_NONE; - } - - return format; - } - - /* We use the AL_EXT_MCFORMATS extension to provide output of Quad, 5.1, - * and 7.1 channel configs, AL_EXT_FLOAT32 for 32-bit float samples, and - * AL_EXT_DOUBLE for 64-bit float samples. */ - if(type == AL_UNSIGNED_BYTE_SOFT) - { - if(channels == AL_MONO_SOFT) - format = AL_FORMAT_MONO8; - else if(channels == AL_STEREO_SOFT) - format = AL_FORMAT_STEREO8; - else if(alIsExtensionPresent("AL_EXT_MCFORMATS")) - { - if(channels == AL_QUAD_SOFT) - format = alGetEnumValue("AL_FORMAT_QUAD8"); - else if(channels == AL_5POINT1_SOFT) - format = alGetEnumValue("AL_FORMAT_51CHN8"); - else if(channels == AL_6POINT1_SOFT) - format = alGetEnumValue("AL_FORMAT_61CHN8"); - else if(channels == AL_7POINT1_SOFT) - format = alGetEnumValue("AL_FORMAT_71CHN8"); - } - } - else if(type == AL_SHORT_SOFT) - { - if(channels == AL_MONO_SOFT) - format = AL_FORMAT_MONO16; - else if(channels == AL_STEREO_SOFT) - format = AL_FORMAT_STEREO16; - else if(alIsExtensionPresent("AL_EXT_MCFORMATS")) - { - if(channels == AL_QUAD_SOFT) - format = alGetEnumValue("AL_FORMAT_QUAD16"); - else if(channels == AL_5POINT1_SOFT) - format = alGetEnumValue("AL_FORMAT_51CHN16"); - else if(channels == AL_6POINT1_SOFT) - format = alGetEnumValue("AL_FORMAT_61CHN16"); - else if(channels == AL_7POINT1_SOFT) - format = alGetEnumValue("AL_FORMAT_71CHN16"); - } - } - else if(type == AL_FLOAT_SOFT && alIsExtensionPresent("AL_EXT_FLOAT32")) - { - if(channels == AL_MONO_SOFT) - format = alGetEnumValue("AL_FORMAT_MONO_FLOAT32"); - else if(channels == AL_STEREO_SOFT) - format = alGetEnumValue("AL_FORMAT_STEREO_FLOAT32"); - else if(alIsExtensionPresent("AL_EXT_MCFORMATS")) - { - if(channels == AL_QUAD_SOFT) - format = alGetEnumValue("AL_FORMAT_QUAD32"); - else if(channels == AL_5POINT1_SOFT) - format = alGetEnumValue("AL_FORMAT_51CHN32"); - else if(channels == AL_6POINT1_SOFT) - format = alGetEnumValue("AL_FORMAT_61CHN32"); - else if(channels == AL_7POINT1_SOFT) - format = alGetEnumValue("AL_FORMAT_71CHN32"); - } - } - else if(type == AL_DOUBLE_SOFT && alIsExtensionPresent("AL_EXT_DOUBLE")) - { - if(channels == AL_MONO_SOFT) - format = alGetEnumValue("AL_FORMAT_MONO_DOUBLE"); - else if(channels == AL_STEREO_SOFT) - format = alGetEnumValue("AL_FORMAT_STEREO_DOUBLE"); - } - - /* NOTE: It seems OSX returns -1 from alGetEnumValue for unknown enums, as - * opposed to 0. Correct it. */ - if(format == -1) - format = 0; - - return format; -} - - -void AL_APIENTRY wrap_BufferSamples(ALuint buffer, ALuint samplerate, - ALenum internalformat, ALsizei samples, - ALenum channels, ALenum type, - const ALvoid *data) -{ - alBufferData(buffer, internalformat, data, - FramesToBytes(samples, channels, type), - samplerate); -} - - -const char *ChannelsName(ALenum chans) -{ - switch(chans) - { - case AL_MONO_SOFT: return "Mono"; - case AL_STEREO_SOFT: return "Stereo"; - case AL_REAR_SOFT: return "Rear"; - case AL_QUAD_SOFT: return "Quadraphonic"; - case AL_5POINT1_SOFT: return "5.1 Surround"; - case AL_6POINT1_SOFT: return "6.1 Surround"; - case AL_7POINT1_SOFT: return "7.1 Surround"; - } - return "Unknown Channels"; -} - -const char *TypeName(ALenum type) -{ - switch(type) - { - case AL_BYTE_SOFT: return "S8"; - case AL_UNSIGNED_BYTE_SOFT: return "U8"; - case AL_SHORT_SOFT: return "S16"; - case AL_UNSIGNED_SHORT_SOFT: return "U16"; - case AL_INT_SOFT: return "S32"; - case AL_UNSIGNED_INT_SOFT: return "U32"; - case AL_FLOAT_SOFT: return "Float32"; - case AL_DOUBLE_SOFT: return "Float64"; - } - return "Unknown Type"; -} - - -ALsizei FramesToBytes(ALsizei size, ALenum channels, ALenum type) -{ - switch(channels) - { - case AL_MONO_SOFT: size *= 1; break; - case AL_STEREO_SOFT: size *= 2; break; - case AL_REAR_SOFT: size *= 2; break; - case AL_QUAD_SOFT: size *= 4; break; - case AL_5POINT1_SOFT: size *= 6; break; - case AL_6POINT1_SOFT: size *= 7; break; - case AL_7POINT1_SOFT: size *= 8; break; - } - - switch(type) - { - case AL_BYTE_SOFT: size *= sizeof(ALbyte); break; - case AL_UNSIGNED_BYTE_SOFT: size *= sizeof(ALubyte); break; - case AL_SHORT_SOFT: size *= sizeof(ALshort); break; - case AL_UNSIGNED_SHORT_SOFT: size *= sizeof(ALushort); break; - case AL_INT_SOFT: size *= sizeof(ALint); break; - case AL_UNSIGNED_INT_SOFT: size *= sizeof(ALuint); break; - case AL_FLOAT_SOFT: size *= sizeof(ALfloat); break; - case AL_DOUBLE_SOFT: size *= sizeof(ALdouble); break; - } - - return size; -} - -ALsizei BytesToFrames(ALsizei size, ALenum channels, ALenum type) -{ - return size / FramesToBytes(1, channels, type); -} diff --git a/love/src/jni/openal-soft-1.17.0/examples/common/alhelpers.h b/love/src/jni/openal-soft-1.17.0/examples/common/alhelpers.h deleted file mode 100644 index 62ed5be2..00000000 --- a/love/src/jni/openal-soft-1.17.0/examples/common/alhelpers.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef ALHELPERS_H -#define ALHELPERS_H - -#ifndef _WIN32 -#include -#define Sleep(x) usleep((x)*1000) -#else -#define WIN32_LEAN_AND_MEAN -#include -#endif - -#include "AL/alc.h" -#include "AL/al.h" -#include "AL/alext.h" - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* Some helper functions to get the name from the channel and type enums. */ -const char *ChannelsName(ALenum chans); -const char *TypeName(ALenum type); - -/* Helpers to convert frame counts and byte lengths. */ -ALsizei FramesToBytes(ALsizei size, ALenum channels, ALenum type); -ALsizei BytesToFrames(ALsizei size, ALenum channels, ALenum type); - -/* Retrieves a compatible buffer format given the channel configuration and - * sample type. If an alIsBufferFormatSupportedSOFT-compatible function is - * provided, it will be called to find the closest-matching format from - * AL_SOFT_buffer_samples. Returns AL_NONE (0) if no supported format can be - * found. */ -ALenum GetFormat(ALenum channels, ALenum type, LPALISBUFFERFORMATSUPPORTEDSOFT palIsBufferFormatSupportedSOFT); - -/* Loads samples into a buffer using the standard alBufferData call, but with a - * LPALBUFFERSAMPLESSOFT-compatible prototype. Assumes internalformat is valid - * for alBufferData, and that channels and type match it. */ -void AL_APIENTRY wrap_BufferSamples(ALuint buffer, ALuint samplerate, - ALenum internalformat, ALsizei samples, - ALenum channels, ALenum type, - const ALvoid *data); - -/* Easy device init/deinit functions. InitAL returns 0 on success. */ -int InitAL(void); -void CloseAL(void); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* ALHELPERS_H */ diff --git a/love/src/jni/openal-soft-1.17.0/examples/common/sdl_sound.c b/love/src/jni/openal-soft-1.17.0/examples/common/sdl_sound.c deleted file mode 100644 index 79a5bf32..00000000 --- a/love/src/jni/openal-soft-1.17.0/examples/common/sdl_sound.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * SDL_sound Decoder Helpers - * - * Copyright (c) 2013 by Chris Robinson - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -/* This file contains routines for helping to decode audio using SDL_sound. - * There's very little OpenAL-specific code here. - */ -#include "sdl_sound.h" - -#include -#include -#include -#include -#include - -#include - -#include "AL/al.h" -#include "AL/alc.h" -#include "AL/alext.h" - -#include "alhelpers.h" - - -static int done_init = 0; - -FilePtr openAudioFile(const char *fname, size_t buftime_ms) -{ - FilePtr file; - ALuint rate; - Uint32 bufsize; - ALenum chans, type; - - /* We need to make sure SDL_sound is initialized. */ - if(!done_init) - { - Sound_Init(); - done_init = 1; - } - - file = Sound_NewSampleFromFile(fname, NULL, 0); - if(!file) - { - fprintf(stderr, "Failed to open %s: %s\n", fname, Sound_GetError()); - return NULL; - } - - if(getAudioInfo(file, &rate, &chans, &type) != 0) - { - Sound_FreeSample(file); - return NULL; - } - - bufsize = FramesToBytes((ALsizei)(buftime_ms/1000.0*rate), chans, type); - if(Sound_SetBufferSize(file, bufsize) == 0) - { - fprintf(stderr, "Failed to set buffer size to %u bytes: %s\n", bufsize, Sound_GetError()); - Sound_FreeSample(file); - return NULL; - } - - return file; -} - -void closeAudioFile(FilePtr file) -{ - if(file) - Sound_FreeSample(file); -} - - -int getAudioInfo(FilePtr file, ALuint *rate, ALenum *channels, ALenum *type) -{ - if(file->actual.channels == 1) - *channels = AL_MONO_SOFT; - else if(file->actual.channels == 2) - *channels = AL_STEREO_SOFT; - else - { - fprintf(stderr, "Unsupported channel count: %d\n", file->actual.channels); - return 1; - } - - if(file->actual.format == AUDIO_U8) - *type = AL_UNSIGNED_BYTE_SOFT; - else if(file->actual.format == AUDIO_S8) - *type = AL_BYTE_SOFT; - else if(file->actual.format == AUDIO_U16LSB || file->actual.format == AUDIO_U16MSB) - *type = AL_UNSIGNED_SHORT_SOFT; - else if(file->actual.format == AUDIO_S16LSB || file->actual.format == AUDIO_S16MSB) - *type = AL_SHORT_SOFT; - else - { - fprintf(stderr, "Unsupported sample format: 0x%04x\n", file->actual.format); - return 1; - } - - *rate = file->actual.rate; - - return 0; -} - - -uint8_t *getAudioData(FilePtr file, size_t *length) -{ - *length = Sound_Decode(file); - if(*length == 0) - return NULL; - if((file->actual.format == AUDIO_U16LSB && AUDIO_U16LSB != AUDIO_U16SYS) || - (file->actual.format == AUDIO_U16MSB && AUDIO_U16MSB != AUDIO_U16SYS) || - (file->actual.format == AUDIO_S16LSB && AUDIO_S16LSB != AUDIO_S16SYS) || - (file->actual.format == AUDIO_S16MSB && AUDIO_S16MSB != AUDIO_S16SYS)) - { - /* Swap bytes if the decoded endianness doesn't match the system. */ - char *buffer = file->buffer; - size_t i; - for(i = 0;i < *length;i+=2) - { - char b = buffer[i]; - buffer[i] = buffer[i+1]; - buffer[i+1] = b; - } - } - return file->buffer; -} - -void *decodeAudioStream(FilePtr file, size_t *length) -{ - Uint32 got; - char *mem; - - got = Sound_DecodeAll(file); - if(got == 0) - { - *length = 0; - return NULL; - } - - mem = malloc(got); - memcpy(mem, file->buffer, got); - - *length = got; - return mem; -} diff --git a/love/src/jni/openal-soft-1.17.0/examples/common/sdl_sound.h b/love/src/jni/openal-soft-1.17.0/examples/common/sdl_sound.h deleted file mode 100644 index e93ab92b..00000000 --- a/love/src/jni/openal-soft-1.17.0/examples/common/sdl_sound.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef EXAMPLES_SDL_SOUND_H -#define EXAMPLES_SDL_SOUND_H - -#include "AL/al.h" - -#include - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* Opaque handles to files and streams. Apps don't need to concern themselves - * with the internals */ -typedef Sound_Sample *FilePtr; - -/* Opens a file with SDL_sound, and specifies the size of the sample buffer in - * milliseconds. */ -FilePtr openAudioFile(const char *fname, size_t buftime_ms); - -/* Closes/frees an opened file */ -void closeAudioFile(FilePtr file); - -/* Returns information about the given audio stream. Returns 0 on success. */ -int getAudioInfo(FilePtr file, ALuint *rate, ALenum *channels, ALenum *type); - -/* Returns a pointer to the next available chunk of decoded audio. The size (in - * bytes) of the returned data buffer is stored in 'length', and the returned - * pointer is only valid until the next call to getAudioData. */ -uint8_t *getAudioData(FilePtr file, size_t *length); - -/* Decodes all remaining data from the stream and returns a buffer containing - * the audio data, with the size stored in 'length'. The returned pointer must - * be freed with a call to free(). Note that since this decodes the whole - * stream, using it on lengthy streams (eg, music) will use a lot of memory. - * Such streams are better handled using getAudioData to keep smaller chunks in - * memory at any given time. */ -void *decodeAudioStream(FilePtr, size_t *length); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* EXAMPLES_SDL_SOUND_H */ diff --git a/love/src/jni/openal-soft-1.17.0/hrtf/default-44100.mhr b/love/src/jni/openal-soft-1.17.0/hrtf/default-44100.mhr deleted file mode 100644 index e0d0bf4b6c42e1211af3ead111275fbdb118afa9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53853 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

dCu@tZqPa^Ns4*bMj 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 J&t|jX{{hDUFed;2 diff --git a/love/src/jni/openal-soft-1.17.0/include/atomic.h b/love/src/jni/openal-soft-1.17.0/include/atomic.h deleted file mode 100644 index d761890e..00000000 --- a/love/src/jni/openal-soft-1.17.0/include/atomic.h +++ /dev/null @@ -1,313 +0,0 @@ -#ifndef AL_ATOMIC_H -#define AL_ATOMIC_H - -#include "static_assert.h" -#include "bool.h" - -#ifdef __cplusplus -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 ATOMIC(T) struct { T _Atomic value; } - -#define ATOMIC_INIT(_val, _newval) atomic_init(&(_val)->value, (_newval)) -#define ATOMIC_INIT_STATIC(_newval) {ATOMIC_VAR_INIT(_newval)} - -#define ATOMIC_LOAD(_val) atomic_load(&(_val)->value) -#define ATOMIC_STORE(_val, _newval) atomic_store(&(_val)->value, (_newval)) - -#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_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)) - -/* 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); } - - -#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__({ \ - __typeof((_val)->value) _r = (_val)->value; \ - __asm__ __volatile__("" ::: "memory"); \ - _r; \ -}) -#define ATOMIC_STORE(_val, _newval) do { \ - __asm__ __volatile__("" ::: "memory"); \ - (_val)->value = (_newval); \ -} while(0) - -#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__({ \ - 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__({ \ - 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__({ \ - 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)); \ - *(_oldval) == _o; \ -}) - -/* Atomics using x86/x86-64 GCC inline assembly */ -#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) - -#define WRAP_ADD(ret, dest, incr) __asm__ __volatile__( \ - "lock; xaddl %0,(%1)" \ - : "=r" (ret) \ - : "r" (dest), "0" (incr) \ - : "memory" \ -) -#define WRAP_SUB(ret, dest, decr) __asm__ __volatile__( \ - "lock; xaddl %0,(%1)" \ - : "=r" (ret) \ - : "r" (dest), "0" (-(decr)) \ - : "memory" \ -) - -#define WRAP_XCHG(S, ret, dest, newval) __asm__ __volatile__( \ - "lock; xchg"S" %0,(%1)" \ - : "=r" (ret) \ - : "r" (dest), "0" (newval) \ - : "memory" \ -) -#define WRAP_CMPXCHG(S, ret, dest, oldval, newval) __asm__ __volatile__( \ - "lock; cmpxchg"S" %2,(%1)" \ - : "=a" (ret) \ - : "r" (dest), "r" (newval), "0" (oldval) \ - : "memory" \ -) - - -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 - - -#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__({ \ - __typeof((_val)->value) _r = (_val)->value; \ - __asm__ __volatile__("" ::: "memory"); \ - _r; \ -}) -#define ATOMIC_STORE(_val, _newval) do { \ - __asm__ __volatile__("" ::: "memory"); \ - (_val)->value = (_newval); \ -} while(0) - -#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__({ \ - 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_SUB(_r, &(_val)->value, (T)(_decr)); \ - _r; \ -}) - -#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; \ - if(sizeof(T) == 4) WRAP_XCHG("l", _r, &(_val)->value, (T)(_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__({ \ - 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); \ - if(sizeof(T) == 4) WRAP_CMPXCHG("l", *(_oldval), &(_val)->value, _old, (T)(_newval)); \ - else if(sizeof(T) == 8) WRAP_CMPXCHG("q", *(_oldval), &(_val)->value, _old, (T)(_newval)); \ - *(_oldval) == _old; \ -}) - -/* Atomics using Windows methods */ -#elif defined(_WIN32) - -#define WIN32_LEAN_AND_MEAN -#include - -/* NOTE: This mess is *extremely* noisy, at least on GCC. It works by wrapping - * Windows' 32-bit and 64-bit atomic methods, which are then casted to use the - * given type based on its size (e.g. int and float use 32-bit atomics). This - * is fine for the swap and compare-and-swap methods, although the add and - * subtract methods only work properly for integer types. - * - * Despite how noisy it is, it's unfortunately the only way that doesn't rely - * on C99 (damn MSVC). - */ - -inline LONG AtomicAdd32(volatile LONG *dest, LONG incr) -{ - return InterlockedExchangeAdd(dest, incr); -} -inline LONG AtomicSub32(volatile LONG *dest, LONG decr) -{ - return InterlockedExchangeAdd(dest, -decr); -} - -inline LONG AtomicSwap32(volatile LONG *dest, LONG newval) -{ - return InterlockedExchange(dest, newval); -} -inline LONGLONG AtomicSwap64(volatile LONGLONG *dest, LONGLONG newval) -{ - return InterlockedExchange64(dest, newval); -} - -inline bool CompareAndSwap32(volatile LONG *dest, LONG newval, LONG *oldval) -{ - LONG old = *oldval; - *oldval = InterlockedCompareExchange(dest, newval, *oldval); - return old == *oldval; -} -inline bool CompareAndSwap64(volatile LONGLONG *dest, LONGLONG newval, LONGLONG *oldval) -{ - LONGLONG old = *oldval; - *oldval = InterlockedCompareExchange64(dest, newval, *oldval); - return old == *oldval; -} - -#define WRAP_ADDSUB(T, _func, _ptr, _amnt) ((T(*)(T volatile*,T))_func)((_ptr), (_amnt)) -#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 - - -#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); \ -} while(0) - -int _al_invalid_atomic_size(); /* not defined */ - -#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) \ - ((sizeof(T)==4) ? WRAP_ADDSUB(T, AtomicSub32, &(_val)->value, (_decr)) : \ - (T)_al_invalid_atomic_size()) - -#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) \ - ((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()) - -#else - -#error "No atomic functions available on this platform!" - -#define ATOMIC(T) T - -#define ATOMIC_INIT_STATIC(_newval) (0) - -#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_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) -#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) -#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; - -inline void InitRef(RefCount *ptr, uint value) -{ ATOMIC_INIT(ptr, value); } -inline uint ReadRef(RefCount *ptr) -{ return ATOMIC_LOAD(ptr); } -inline uint IncrementRef(RefCount *ptr) -{ return ATOMIC_ADD(uint, ptr, 1)+1; } -inline uint DecrementRef(RefCount *ptr) -{ return ATOMIC_SUB(uint, ptr, 1)-1; } - -#ifdef __cplusplus -} -#endif - -#endif /* AL_ATOMIC_H */ diff --git a/love/src/jni/openal-soft-1.17.0/utils/alsoft-config/CMakeLists.txt b/love/src/jni/openal-soft-1.17.0/utils/alsoft-config/CMakeLists.txt deleted file mode 100644 index a6707a3d..00000000 --- a/love/src/jni/openal-soft-1.17.0/utils/alsoft-config/CMakeLists.txt +++ /dev/null @@ -1,29 +0,0 @@ -project(alsoft-config) - -include_directories("${alsoft-config_BINARY_DIR}") - -# Need Qt 4.8.0 or newer for the iconset theme attribute to work -find_package(Qt4 4.8.0 COMPONENTS QtCore QtGui) -if(QT4_FOUND) - include(${QT_USE_FILE}) - - set(alsoft-config_SRCS main.cpp - mainwindow.cpp - ) - - set(alsoft-config_UIS mainwindow.ui) - QT4_WRAP_UI(UIS ${alsoft-config_UIS}) - - set(alsoft-config_MOCS mainwindow.h) - QT4_WRAP_CPP(MOCS ${alsoft-config_MOCS}) - - add_executable(alsoft-config ${alsoft-config_SRCS} ${UIS} ${RSCS} ${TRS} ${MOCS}) - target_link_libraries(alsoft-config ${QT_LIBRARIES}) - set_target_properties(alsoft-config PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${OpenAL_BINARY_DIR}) - - install(TARGETS alsoft-config - RUNTIME DESTINATION bin - LIBRARY DESTINATION "lib${LIB_SUFFIX}" - ARCHIVE DESTINATION "lib${LIB_SUFFIX}" - ) -endif() diff --git a/love/src/jni/openal-soft-1.17.0/utils/alsoft-config/mainwindow.cpp b/love/src/jni/openal-soft-1.17.0/utils/alsoft-config/mainwindow.cpp deleted file mode 100644 index 1d5a3dcd..00000000 --- a/love/src/jni/openal-soft-1.17.0/utils/alsoft-config/mainwindow.cpp +++ /dev/null @@ -1,660 +0,0 @@ -#include -#include -#include -#include -#include "mainwindow.h" -#include "ui_mainwindow.h" - -namespace { -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" }, -#endif -#ifdef Q_OS_MAC - { "core", "Add CoreAudio" }, -#endif - { "pulse", "Add PulseAudio" }, -#ifdef Q_OS_UNIX - { "alsa", "Add ALSA" }, - { "oss", "Add OSS" }, - { "solaris", "Add Solaris" }, - { "sndio", "Add SndIO" }, - { "qsa", "Add QSA" }, -#endif - { "port", "Add PortAudio" }, - { "opensl", "Add OpenSL" }, - { "null", "Add Null Output" }, - { "wave", "Add Wave Writer" }, - { "", "" } -}; - -static QString getDefaultConfigName() -{ -#ifdef Q_OS_WIN32 - static const char fname[] = "alsoft.ini"; - QByteArray base = qgetenv("AppData"); -#else - static const char fname[] = "alsoft.conf"; - QByteArray base = qgetenv("XDG_CONFIG_HOME"); - if(base.isEmpty()) - { - base = qgetenv("HOME"); - if(base.isEmpty() == false) - base += "/.config"; - } -#endif - if(base.isEmpty() == false) - return base +'/'+ fname; - return fname; -} - -static QString getBaseDataPath() -{ -#ifdef Q_OS_WIN32 - QByteArray base = qgetenv("AppData"); -#else - QByteArray base = qgetenv("XDG_DATA_HOME"); - if(base.isEmpty()) - { - base = qgetenv("HOME"); - if(!base.isEmpty()) - base += "/.local/share"; - } -#endif - return base; -} - -static QStringList getAllDataPaths(QString append=QString()) -{ - QStringList list; - list.append(getBaseDataPath()); -#ifdef Q_OS_WIN32 - // TODO: Common AppData path -#else - QString paths = qgetenv("XDG_DATA_DIRS"); - if(paths.isEmpty()) - paths = "/usr/local/share/:/usr/share/"; - list += paths.split(QChar(':'), QString::SkipEmptyParts); -#endif - QStringList::iterator iter = list.begin(); - while(iter != list.end()) - { - if(iter->isEmpty()) - iter = list.erase(iter); - else - { - iter->append(append); - iter++; - } - } - return list; -} -} - -MainWindow::MainWindow(QWidget *parent) : - QMainWindow(parent), - ui(new Ui::MainWindow), - mPeriodSizeValidator(NULL), - mPeriodCountValidator(NULL), - mSourceCountValidator(NULL), - mEffectSlotValidator(NULL), - mSourceSendValidator(NULL), - mSampleRateValidator(NULL), - mReverbBoostValidator(NULL) -{ - ui->setupUi(this); - - mPeriodSizeValidator = new QIntValidator(64, 8192, this); - ui->periodSizeEdit->setValidator(mPeriodSizeValidator); - mPeriodCountValidator = new QIntValidator(2, 16, this); - ui->periodCountEdit->setValidator(mPeriodCountValidator); - - mSourceCountValidator = new QIntValidator(0, 256, this); - ui->srcCountLineEdit->setValidator(mSourceCountValidator); - mEffectSlotValidator = new QIntValidator(0, 16, this); - ui->effectSlotLineEdit->setValidator(mEffectSlotValidator); - mSourceSendValidator = new QIntValidator(0, 4, this); - ui->srcSendLineEdit->setValidator(mSourceSendValidator); - 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())); - - connect(ui->applyButton, SIGNAL(clicked()), this, SLOT(saveCurrentConfig())); - - connect(ui->periodSizeSlider, SIGNAL(valueChanged(int)), this, SLOT(updatePeriodSizeEdit(int))); - connect(ui->periodSizeEdit, SIGNAL(editingFinished()), this, SLOT(updatePeriodSizeSlider())); - connect(ui->periodCountSlider, SIGNAL(valueChanged(int)), this, SLOT(updatePeriodCountEdit(int))); - connect(ui->periodCountEdit, SIGNAL(editingFinished()), this, SLOT(updatePeriodCountSlider())); - - connect(ui->hrtfAddButton, SIGNAL(clicked()), this, SLOT(addHrtfFile())); - connect(ui->hrtfRemoveButton, SIGNAL(clicked()), this, SLOT(removeHrtfFile())); - connect(ui->hrtfFileList, SIGNAL(itemSelectionChanged()), this, SLOT(updateHrtfRemoveButton())); - - ui->enabledBackendList->setContextMenuPolicy(Qt::CustomContextMenu); - connect(ui->enabledBackendList, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showEnabledBackendMenu(QPoint))); - - 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()); -} - -MainWindow::~MainWindow() -{ - delete ui; - delete mPeriodSizeValidator; - delete mPeriodCountValidator; - delete mSourceCountValidator; - delete mEffectSlotValidator; - delete mSourceSendValidator; - delete mSampleRateValidator; - delete mReverbBoostValidator; -} - -void MainWindow::loadConfigFromFile() -{ - QString fname = QFileDialog::getOpenFileName(this, tr("Select Files")); - if(fname.isEmpty() == false) - loadConfig(fname); -} - -void MainWindow::loadConfig(const QString &fname) -{ - QSettings settings(fname, QSettings::IniFormat); - - QString sampletype = settings.value("sample-type").toString(); - ui->sampleFormatCombo->setCurrentIndex(0); - if(sampletype.isEmpty() == false) - { - for(int i = 1;i < ui->sampleFormatCombo->count();i++) - { - QString item = ui->sampleFormatCombo->itemText(i); - if(item.startsWith(sampletype)) - { - ui->sampleFormatCombo->setCurrentIndex(i); - break; - } - } - } - - QString channelconfig = settings.value("channels").toString(); - ui->channelConfigCombo->setCurrentIndex(0); - if(channelconfig.isEmpty() == false) - { - for(int i = 1;i < ui->channelConfigCombo->count();i++) - { - QString item = ui->channelConfigCombo->itemText(i); - if(item.startsWith(channelconfig)) - { - ui->channelConfigCombo->setCurrentIndex(i); - break; - } - } - } - - QString srate = settings.value("frequency").toString(); - if(srate.isEmpty()) - ui->sampleRateCombo->setCurrentIndex(0); - else - { - ui->sampleRateCombo->lineEdit()->clear(); - ui->sampleRateCombo->lineEdit()->insert(srate); - } - - ui->srcCountLineEdit->clear(); - ui->srcCountLineEdit->insert(settings.value("sources").toString()); - ui->effectSlotLineEdit->clear(); - ui->effectSlotLineEdit->insert(settings.value("slots").toString()); - ui->srcSendLineEdit->clear(); - ui->srcSendLineEdit->insert(settings.value("sends").toString()); - - QString resampler = settings.value("resampler").toString().trimmed(); - if(resampler.isEmpty()) - ui->resamplerComboBox->setCurrentIndex(0); - else - { - for(int i = 1;i < ui->resamplerComboBox->count();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) - { - ui->resamplerComboBox->setCurrentIndex(i); - break; - } - } - } - - int periodsize = settings.value("period_size").toInt(); - ui->periodSizeEdit->clear(); - if(periodsize >= 64) - { - ui->periodSizeEdit->insert(QString::number(periodsize)); - updatePeriodSizeSlider(); - } - - int periodcount = settings.value("periods").toInt(); - ui->periodCountEdit->clear(); - if(periodcount >= 2) - { - ui->periodCountEdit->insert(QString::number(periodcount)); - updatePeriodCountSlider(); - } - - QStringList disabledCpuExts = settings.value("disable-cpu-exts").toStringList(); - if(disabledCpuExts.size() == 1) - disabledCpuExts = disabledCpuExts[0].split(QChar(',')); - std::transform(disabledCpuExts.begin(), disabledCpuExts.end(), - 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->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); - else - { - if(settings.value("hrtf", true).toBool()) - ui->hrtfForceButton->setChecked(true); - else - ui->hrtfDisableButton->setChecked(true); - } - - QStringList hrtf_tables = settings.value("hrtf_tables").toStringList(); - if(hrtf_tables.size() == 1) - hrtf_tables = hrtf_tables[0].split(QChar(',')); - std::transform(hrtf_tables.begin(), hrtf_tables.end(), - hrtf_tables.begin(), std::mem_fun_ref(&QString::trimmed)); - ui->hrtfFileList->clear(); - ui->hrtfFileList->addItems(hrtf_tables); - updateHrtfRemoveButton(); - - ui->enabledBackendList->clear(); - ui->disabledBackendList->clear(); - QStringList drivers = settings.value("drivers").toStringList(); - if(drivers.size() == 0) - ui->backendCheckBox->setChecked(true); - else - { - if(drivers.size() == 1) - drivers = drivers[0].split(QChar(',')); - std::transform(drivers.begin(), drivers.end(), - drivers.begin(), std::mem_fun_ref(&QString::trimmed)); - - bool lastWasEmpty = false; - foreach(const QString &backend, drivers) - { - lastWasEmpty = backend.isEmpty(); - if(!backend.startsWith(QChar('-')) && !lastWasEmpty) - ui->enabledBackendList->addItem(backend); - else if(backend.size() > 1) - ui->disabledBackendList->addItem(backend.right(backend.size()-1)); - } - ui->backendCheckBox->setChecked(lastWasEmpty); - } - - QString defaultreverb = settings.value("default-reverb").toString().toLower(); - ui->defaultReverbComboBox->setCurrentIndex(0); - if(defaultreverb.isEmpty() == false) - { - for(int i = 0;i < ui->defaultReverbComboBox->count();i++) - { - if(defaultreverb.compare(ui->defaultReverbComboBox->itemText(i).toLower()) == 0) - { - ui->defaultReverbComboBox->setCurrentIndex(i); - break; - } - } - } - - 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) - excludefx = excludefx[0].split(QChar(',')); - std::transform(excludefx.begin(), excludefx.end(), - excludefx.begin(), std::mem_fun_ref(&QString::trimmed)); - ui->enableEaxReverbCheck->setChecked(!excludefx.contains("eaxreverb", Qt::CaseInsensitive)); - ui->enableStdReverbCheck->setChecked(!excludefx.contains("reverb", Qt::CaseInsensitive)); - ui->enableChorusCheck->setChecked(!excludefx.contains("chorus", Qt::CaseInsensitive)); - ui->enableCompressorCheck->setChecked(!excludefx.contains("compressor", Qt::CaseInsensitive)); - ui->enableDistortionCheck->setChecked(!excludefx.contains("distortion", Qt::CaseInsensitive)); - ui->enableEchoCheck->setChecked(!excludefx.contains("echo", Qt::CaseInsensitive)); - ui->enableEqualizerCheck->setChecked(!excludefx.contains("equalizer", Qt::CaseInsensitive)); - ui->enableFlangerCheck->setChecked(!excludefx.contains("flanger", Qt::CaseInsensitive)); - ui->enableModulatorCheck->setChecked(!excludefx.contains("modulator", Qt::CaseInsensitive)); - ui->enableDedicatedCheck->setChecked(!excludefx.contains("dedicated", Qt::CaseInsensitive)); -} - -void MainWindow::saveCurrentConfig() -{ - saveConfig(getDefaultConfigName()); - QMessageBox::information(this, tr("Information"), - tr("Applications using OpenAL need to be restarted for changes to take effect.")); -} - -void MainWindow::saveConfigAsFile() -{ - QString fname = QFileDialog::getOpenFileName(this, tr("Select Files")); - if(fname.isEmpty() == false) - saveConfig(fname); -} - -void MainWindow::saveConfig(const QString &fname) const -{ - QSettings settings(fname, QSettings::IniFormat); - - /* HACK: Compound any stringlist values into a comma-separated string. */ - QStringList allkeys = settings.allKeys(); - foreach(const QString &key, allkeys) - { - QStringList vals = settings.value(key).toStringList(); - if(vals.size() > 1) - settings.setValue(key, vals.join(QChar(','))); - } - - QString str = ui->sampleFormatCombo->currentText(); - str.truncate(str.indexOf('-')); - settings.setValue("sample-type", str.trimmed()); - - str = ui->channelConfigCombo->currentText(); - str.truncate(str.indexOf('-')); - settings.setValue("channels", str.trimmed()); - - uint rate = ui->sampleRateCombo->currentText().toUInt(); - if(rate == 0) - settings.setValue("frequency", QString()); - else - settings.setValue("frequency", rate); - - settings.setValue("period_size", ui->periodSizeEdit->text()); - settings.setValue("periods", ui->periodCountEdit->text()); - - 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(); - settings.setValue("resampler", str.split(' ').first().toLower()); - } - - QStringList strlist; - if(!ui->enableSSECheckBox->isChecked()) - strlist.append("sse"); - if(!ui->enableSSE2CheckBox->isChecked()) - strlist.append("sse2"); - 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()) - settings.setValue("hrtf", "true"); - else if(ui->hrtfDisableButton->isChecked()) - settings.setValue("hrtf", "false"); - else - settings.setValue("hrtf", QString()); - - strlist.clear(); - QList items = ui->hrtfFileList->findItems("*", Qt::MatchWildcard); - foreach(const QListWidgetItem *item, items) - strlist.append(item->text()); - settings.setValue("hrtf_tables", strlist.join(QChar(','))); - - strlist.clear(); - items = ui->enabledBackendList->findItems("*", Qt::MatchWildcard); - foreach(const QListWidgetItem *item, items) - strlist.append(item->text()); - items = ui->disabledBackendList->findItems("*", Qt::MatchWildcard); - foreach(const QListWidgetItem *item, items) - strlist.append(QChar('-')+item->text()); - if(strlist.size() == 0 && !ui->backendCheckBox->isChecked()) - strlist.append("-all"); - else if(ui->backendCheckBox->isChecked()) - strlist.append(QString()); - settings.setValue("drivers", strlist.join(QChar(','))); - - // TODO: Remove check when we can properly match global values. - if(ui->defaultReverbComboBox->currentIndex() == 0) - settings.setValue("default-reverb", QString()); - else - { - str = ui->defaultReverbComboBox->currentText().toLower(); - settings.setValue("default-reverb", str); - } - - if(ui->emulateEaxCheckBox->isChecked()) - settings.setValue("reverb/emulate-eax", "true"); - 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"); - if(!ui->enableStdReverbCheck->isChecked()) - strlist.append("reverb"); - if(!ui->enableChorusCheck->isChecked()) - strlist.append("chorus"); - if(!ui->enableDistortionCheck->isChecked()) - strlist.append("distortion"); - if(!ui->enableCompressorCheck->isChecked()) - strlist.append("compressor"); - if(!ui->enableEchoCheck->isChecked()) - strlist.append("echo"); - if(!ui->enableEqualizerCheck->isChecked()) - strlist.append("equalizer"); - if(!ui->enableFlangerCheck->isChecked()) - strlist.append("flanger"); - if(!ui->enableModulatorCheck->isChecked()) - strlist.append("modulator"); - if(!ui->enableDedicatedCheck->isChecked()) - strlist.append("dedicated"); - settings.setValue("excludefx", strlist.join(QChar(','))); - - /* Remove empty keys - * FIXME: Should only remove keys whose value matches the globally-specified value. - */ - allkeys = settings.allKeys(); - foreach(const QString &key, allkeys) - { - str = settings.value(key).toString(); - if(str == QString()) - settings.remove(key); - } -} - - -void MainWindow::updatePeriodSizeEdit(int size) -{ - ui->periodSizeEdit->clear(); - if(size >= 64) - { - size = (size+32)&~0x3f; - ui->periodSizeEdit->insert(QString::number(size)); - } -} - -void MainWindow::updatePeriodSizeSlider() -{ - int pos = ui->periodSizeEdit->text().toInt(); - if(pos >= 64) - { - if(pos > 8192) - pos = 8192; - ui->periodSizeSlider->setSliderPosition(pos); - } -} - -void MainWindow::updatePeriodCountEdit(int count) -{ - ui->periodCountEdit->clear(); - if(count >= 2) - ui->periodCountEdit->insert(QString::number(count)); -} - -void MainWindow::updatePeriodCountSlider() -{ - int pos = ui->periodCountEdit->text().toInt(); - if(pos < 2) - pos = 0; - else if(pos > 16) - pos = 16; - ui->periodCountSlider->setSliderPosition(pos); -} - - -void MainWindow::addHrtfFile() -{ - const QStringList datapaths = getAllDataPaths("/openal/hrtf"); - QStringList fnames = QFileDialog::getOpenFileNames(this, tr("Select Files"), - datapaths.empty() ? QString() : datapaths[0], - "HRTF Datasets(*.mhr);;All Files(*.*)"); - if(fnames.isEmpty() == false) - { - for(QStringList::iterator iter = fnames.begin();iter != fnames.end();iter++) - { - QStringList::const_iterator path = datapaths.constBegin(); - for(;path != datapaths.constEnd();path++) - { - QDir hrtfdir(*path); - if(!hrtfdir.isAbsolute()) - continue; - - const QString relname = hrtfdir.relativeFilePath(*iter); - if(!relname.startsWith("..")) - { - // If filename is within this path, use the relative pathname - ui->hrtfFileList->addItem(relname); - break; - } - } - if(path == datapaths.constEnd()) - { - // Filename is not within any data path, use the absolute pathname - ui->hrtfFileList->addItem(*iter); - } - } - } -} - -void MainWindow::removeHrtfFile() -{ - QList selected = ui->hrtfFileList->selectedItems(); - foreach(QListWidgetItem *item, selected) - delete item; -} - -void MainWindow::updateHrtfRemoveButton() -{ - ui->hrtfRemoveButton->setEnabled(ui->hrtfFileList->selectedItems().size() != 0); -} - -void MainWindow::showEnabledBackendMenu(QPoint pt) -{ - QMap actionMap; - - pt = ui->enabledBackendList->mapToGlobal(pt); - - QMenu ctxmenu; - QAction *removeAction = ctxmenu.addAction(QIcon::fromTheme("list-remove"), "Remove"); - if(ui->enabledBackendList->selectedItems().size() == 0) - removeAction->setEnabled(false); - ctxmenu.addSeparator(); - for(size_t i = 0;backendMenuList[i].backend_name[0];i++) - { - QAction *action = ctxmenu.addAction(backendMenuList[i].menu_string); - actionMap[action] = backendMenuList[i].backend_name; - if(ui->enabledBackendList->findItems(backendMenuList[i].backend_name, Qt::MatchFixedString).size() != 0 || - ui->disabledBackendList->findItems(backendMenuList[i].backend_name, Qt::MatchFixedString).size() != 0) - action->setEnabled(false); - } - - QAction *gotAction = ctxmenu.exec(pt); - if(gotAction == removeAction) - { - QList selected = ui->enabledBackendList->selectedItems(); - foreach(QListWidgetItem *item, selected) - delete item; - } - else if(gotAction != NULL) - { - QMap::const_iterator iter = actionMap.find(gotAction); - if(iter != actionMap.end()) - ui->enabledBackendList->addItem(iter.value()); - } -} - -void MainWindow::showDisabledBackendMenu(QPoint pt) -{ - QMap actionMap; - - pt = ui->disabledBackendList->mapToGlobal(pt); - - QMenu ctxmenu; - QAction *removeAction = ctxmenu.addAction(QIcon::fromTheme("list-remove"), "Remove"); - if(ui->disabledBackendList->selectedItems().size() == 0) - removeAction->setEnabled(false); - ctxmenu.addSeparator(); - for(size_t i = 0;backendMenuList[i].backend_name[0];i++) - { - QAction *action = ctxmenu.addAction(backendMenuList[i].menu_string); - actionMap[action] = backendMenuList[i].backend_name; - if(ui->disabledBackendList->findItems(backendMenuList[i].backend_name, Qt::MatchFixedString).size() != 0 || - ui->enabledBackendList->findItems(backendMenuList[i].backend_name, Qt::MatchFixedString).size() != 0) - action->setEnabled(false); - } - - QAction *gotAction = ctxmenu.exec(pt); - if(gotAction == removeAction) - { - QList selected = ui->disabledBackendList->selectedItems(); - foreach(QListWidgetItem *item, selected) - delete item; - } - else if(gotAction != NULL) - { - QMap::const_iterator iter = actionMap.find(gotAction); - if(iter != actionMap.end()) - 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/love/src/jni/openal-soft-1.17.0/utils/alsoft-config/mainwindow.ui b/love/src/jni/openal-soft-1.17.0/utils/alsoft-config/mainwindow.ui deleted file mode 100644 index 3c92abf6..00000000 --- a/love/src/jni/openal-soft-1.17.0/utils/alsoft-config/mainwindow.ui +++ /dev/null @@ -1,1464 +0,0 @@ - - - MainWindow - - - - 0 - 0 - 564 - 454 - - - - OpenAL Soft Configuration - - - - - - - - - - - 470 - 405 - 81 - 25 - - - - Apply - - - - - - - - - - - 10 - 0 - 541 - 401 - - - - 0 - - - - Playback - - - - - 120 - 20 - 188 - 22 - - - - The output sample type. Currently, all mixing is done with 32-bit -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 - 101 - 21 - - - - Sample Format: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 10 - 50 - 101 - 21 - - - - Channels: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 120 - 50 - 227 - 22 - - - - The output channel configuration. Note that not all backends -can properly detect the channel configuration and may default -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 - 22 - - - - The playback/mixing sample rate. - - - true - - - QComboBox::NoInsert - - - QComboBox::AdjustToContents - - - - - Autodetect - - - - - - 96000 - - - - - 48000 - - - - - 44100 - - - - - 32000 - - - - - 22050 - - - - - 16000 - - - - - 11025 - - - - - 8000 - - - - - - - 10 - 80 - 101 - 21 - - - - Sample Rate: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 10 - 200 - 511 - 161 - - - - 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 - 30 - 301 - 121 - - - - A list of files containing HRTF data sets. The listed data sets -are used in place of the default sets. The filenames may -contain these markers, which will be replaced as needed: -%r - Device sampling rate -%% - Percent sign (%) - - - false - - - QAbstractItemView::InternalMove - - - true - - - QAbstractItemView::ExtendedSelection - - - Qt::ElideNone - - - - - - 419 - 30 - 81 - 25 - - - - Add... - - - - - - - - false - - - - - - 419 - 60 - 81 - 25 - - - - Remove - - - - - - - - - - - - 10 - 110 - 511 - 91 - - - - Buffer Metrics - - - - - 260 - 20 - 241 - 51 - - - - 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. - - - - - 20 - 0 - 201 - 21 - - - - Period Count - - - Qt::AlignCenter - - - - - - 70 - 20 - 160 - 23 - - - - 1 - - - 16 - - - 1 - - - 2 - - - 1 - - - true - - - Qt::Horizontal - - - QSlider::TicksBelow - - - 1 - - - - - - 20 - 20 - 51 - 22 - - - - 4 - - - - - - - 10 - 20 - 241 - 51 - - - - The update period size, in sample frames. This is the number of -frames needed for each mixing update. - - - - - 60 - 20 - 160 - 23 - - - - 0 - - - 8192 - - - 64 - - - 1024 - - - 0 - - - true - - - Qt::Horizontal - - - QSlider::TicksBelow - - - 512 - - - - - - 10 - 0 - 201 - 21 - - - - Period Samples - - - Qt::AlignCenter - - - - - - 10 - 20 - 51 - 22 - - - - 1024 - - - - - - - - Resources - - - - - 190 - 20 - 51 - 22 - - - - 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. - - - - - - 3 - - - true - - - 256 - - - - - - 10 - 20 - 171 - 21 - - - - Number of Sound Sources: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 10 - 50 - 171 - 21 - - - - Number of Effect Slots: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 190 - 50 - 51 - 22 - - - - 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 if no sources are feeding it, so this -may help when apps use more than the system can handle. - - - - - - 1 - - - true - - - 4 - - - - - - 10 - 80 - 171 - 21 - - - - Number of Source Sends: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 190 - 80 - 51 - 22 - - - - The number of auxiliary sends per source. When not specified, -it allows the app to request how many it wants. The maximum -value currently possible is 4. - - - 1 - - - Auto - - - - - - 30 - 120 - 71 - 21 - - - - Resampler: - - - - - - 110 - 120 - 185 - 22 - - - - The resampling method used when mixing sources. - - - QComboBox::AdjustToContents - - - - - Default - - - - - - Point (low quality, fast) - - - - - Linear (basic quality, fast) - - - - - Cubic Spline (good quality) - - - - - - - 10 - 150 - 511 - 91 - - - - Enables use of specific CPU extensions. Certain methods may -utilize CPU extensions when detected, and disabling these can -be useful for preventing those extensions from being used. - - - CPU Extensions - - - - - 180 - 20 - 71 - 31 - - - - SSE - - - true - - - - - - 180 - 50 - 71 - 31 - - - - SSE2 - - - true - - - - - - 260 - 50 - 71 - 31 - - - - Neon - - - true - - - - - - 260 - 20 - 71 - 31 - - - - SSE4.1 - - - true - - - - - - - Backends - - - - - 170 - 200 - 161 - 21 - - - - When checked, allows all other available backends not listed in the priority or disabled lists. - - - Allow Other Backends - - - true - - - - - - 40 - 40 - 191 - 151 - - - - The backend driver list order. Unknown backends and -duplicated names are ignored. - - - QAbstractItemView::InternalMove - - - - - - 40 - 20 - 191 - 20 - - - - Priority Backends: - - - - - - 270 - 40 - 191 - 151 - - - - Disabled backend driver list. - - - - - - 270 - 20 - 191 - 20 - - - - Disabled Backends: - - - - - - Effects - - - - - 10 - 60 - 161 - 21 - - - - Uses a simpler reverb method to emulate the EAX reverb -effect. This may slightly improve performance at the cost of -some quality. - - - Qt::RightToLeft - - - 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 - 511 - 191 - - - - Specifies which effects apps can recognize. Disabling effects -can help for apps that try to use ones that are too intensive -for the system to handle. - - - Enabled Effects - - - - - 70 - 30 - 131 - 21 - - - - EAX Reverb - - - true - - - - - - 70 - 60 - 131 - 21 - - - - Standard Reverb - - - true - - - - - - 70 - 90 - 131 - 21 - - - - Chorus - - - true - - - - - - 70 - 150 - 131 - 21 - - - - Distortion - - - true - - - - - - 320 - 30 - 131 - 21 - - - - Echo - - - true - - - - - - 320 - 60 - 131 - 21 - - - - Equalizer - - - true - - - - - - 320 - 90 - 131 - 21 - - - - Flanger - - - true - - - - - - 320 - 120 - 131 - 21 - - - - Ring Modulator - - - true - - - - - - 320 - 150 - 131 - 21 - - - - Enables both the Dedicated Dialog and Dedicated LFE effects -added by the ALC_EXT_DEDICATED extension. - - - Dedicated ... - - - true - - - - - - 70 - 120 - 111 - 21 - - - - Compressor - - - true - - - - - - - 10 - 20 - 141 - 21 - - - - Default Reverb Effect: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - 160 - 20 - 131 - 22 - - - - QComboBox::AdjustToContents - - - - None - - - - - Generic - - - - - PaddedCell - - - - - Room - - - - - Bathroom - - - - - Livingroom - - - - - Stoneroom - - - - - Auditorium - - - - - ConcertHall - - - - - Cave - - - - - Arena - - - - - Hangar - - - - - CarpetedHallway - - - - - Hallway - - - - - StoneCorridor - - - - - Alley - - - - - Forest - - - - - City - - - - - Mountains - - - - - Quarry - - - - - Plain - - - - - ParkingLot - - - - - SewerPipe - - - - - Underwater - - - - - Drugged - - - - - Dizzy - - - - - Psychotic - - - - - - - - - - 0 - 0 - 564 - 19 - - - - - &File - - - - - - - - - - - - - - - - &Quit - - - - - - - - - - Save &As... - - - Save Configuration As - - - - - - - - - - &Load... - - - Load Configuration File - - - - - - - - actionQuit - activated() - MainWindow - close() - - - -1 - -1 - - - 267 - 181 - - - - - - ShowHRTFContextMenu(QPoint) - - diff --git a/love/src/jni/openal-soft-1.17.0/utils/makehrtf.c b/love/src/jni/openal-soft-1.17.0/utils/makehrtf.c deleted file mode 100644 index 0a1bd043..00000000 --- a/love/src/jni/openal-soft-1.17.0/utils/makehrtf.c +++ /dev/null @@ -1,2749 +0,0 @@ -/* - * HRTF utility for producing and demonstrating the process of creating an - * OpenAL Soft compatible HRIR data set. - * - * Copyright (C) 2011-2014 Christopher Fitzgerald - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Or visit: http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * - * -------------------------------------------------------------------------- - * - * A big thanks goes out to all those whose work done in the field of - * binaural sound synthesis using measured HRTFs makes this utility and the - * OpenAL Soft implementation possible. - * - * The algorithm for diffuse-field equalization was adapted from the work - * done by Rio Emmanuel and Larcher Veronique of IRCAM and Bill Gardner of - * MIT Media Laboratory. It operates as follows: - * - * 1. Take the FFT of each HRIR and only keep the magnitude responses. - * 2. Calculate the diffuse-field power-average of all HRIRs weighted by - * their contribution to the total surface area covered by their - * measurement. - * 3. Take the diffuse-field average and limit its magnitude range. - * 4. Equalize the responses by using the inverse of the diffuse-field - * average. - * 5. Reconstruct the minimum-phase responses. - * 5. Zero the DC component. - * 6. IFFT the result and truncate to the desired-length minimum-phase FIR. - * - * The spherical head algorithm for calculating propagation delay was adapted - * from the paper: - * - * Modeling Interaural Time Difference Assuming a Spherical Head - * Joel David Miller - * Music 150, Musical Acoustics, Stanford University - * December 2, 2001 - * - * The formulae for calculating the Kaiser window metrics are from the - * the textbook: - * - * Discrete-Time Signal Processing - * Alan V. Oppenheim and Ronald W. Schafer - * Prentice-Hall Signal Processing Series - * 1999 - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#ifdef HAVE_STRINGS_H -#include -#endif - -// Rely (if naively) on OpenAL's header for the types used for serialization. -#include "AL/al.h" -#include "AL/alext.h" - -#ifndef M_PI -#define M_PI (3.14159265358979323846) -#endif - -#ifndef HUGE_VAL -#define HUGE_VAL (1.0 / 0.0) -#endif - -// The epsilon used to maintain signal stability. -#define EPSILON (1e-15) - -// Constants for accessing the token reader's ring buffer. -#define TR_RING_BITS (16) -#define TR_RING_SIZE (1 << TR_RING_BITS) -#define TR_RING_MASK (TR_RING_SIZE - 1) - -// The token reader's load interval in bytes. -#define TR_LOAD_SIZE (TR_RING_SIZE >> 2) - -// The maximum identifier length used when processing the data set -// definition. -#define MAX_IDENT_LEN (16) - -// The maximum path length used when processing filenames. -#define MAX_PATH_LEN (256) - -// The limits for the sample 'rate' metric in the data set definition and for -// resampling. -#define MIN_RATE (32000) -#define MAX_RATE (96000) - -// The limits for the HRIR 'points' metric in the data set definition. -#define MIN_POINTS (16) -#define MAX_POINTS (8192) - -// The limits to the number of 'azimuths' listed in the data set definition. -#define MIN_EV_COUNT (5) -#define MAX_EV_COUNT (128) - -// The limits for each of the 'azimuths' listed in the data set definition. -#define MIN_AZ_COUNT (1) -#define MAX_AZ_COUNT (128) - -// The limits for the listener's head 'radius' in the data set definition. -#define MIN_RADIUS (0.05) -#define MAX_RADIUS (0.15) - -// The limits for the 'distance' from source to listener in the definition -// file. -#define MIN_DISTANCE (0.5) -#define MAX_DISTANCE (2.5) - -// The maximum number of channels that can be addressed for a WAVE file -// source listed in the data set definition. -#define MAX_WAVE_CHANNELS (65535) - -// The limits to the byte size for a binary source listed in the definition -// file. -#define MIN_BIN_SIZE (2) -#define MAX_BIN_SIZE (4) - -// The minimum number of significant bits for binary sources listed in the -// data set definition. The maximum is calculated from the byte size. -#define MIN_BIN_BITS (16) - -// The limits to the number of significant bits for an ASCII source listed in -// the data set definition. -#define MIN_ASCII_BITS (16) -#define MAX_ASCII_BITS (32) - -// The limits to the FFT window size override on the command line. -#define MIN_FFTSIZE (512) -#define MAX_FFTSIZE (16384) - -// The limits to the equalization range limit on the command line. -#define MIN_LIMIT (2.0) -#define MAX_LIMIT (120.0) - -// The limits to the truncation window size on the command line. -#define MIN_TRUNCSIZE (8) -#define MAX_TRUNCSIZE (128) - -// The limits to the custom head radius on the command line. -#define MIN_CUSTOM_RADIUS (0.05) -#define MAX_CUSTOM_RADIUS (0.15) - -// The truncation window size must be a multiple of the below value to allow -// for vectorized convolution. -#define MOD_TRUNCSIZE (8) - -// The defaults for the command line options. -#define DEFAULT_EQUALIZE (1) -#define DEFAULT_SURFACE (1) -#define DEFAULT_LIMIT (24.0) -#define DEFAULT_TRUNCSIZE (32) -#define DEFAULT_HEAD_MODEL (HM_DATASET) -#define DEFAULT_CUSTOM_RADIUS (0.0) - -// The four-character-codes for RIFF/RIFX WAVE file chunks. -#define FOURCC_RIFF (0x46464952) // 'RIFF' -#define FOURCC_RIFX (0x58464952) // 'RIFX' -#define FOURCC_WAVE (0x45564157) // 'WAVE' -#define FOURCC_FMT (0x20746D66) // 'fmt ' -#define FOURCC_DATA (0x61746164) // 'data' -#define FOURCC_LIST (0x5453494C) // 'LIST' -#define FOURCC_WAVL (0x6C766177) // 'wavl' -#define FOURCC_SLNT (0x746E6C73) // 'slnt' - -// The supported wave formats. -#define WAVE_FORMAT_PCM (0x0001) -#define WAVE_FORMAT_IEEE_FLOAT (0x0003) -#define WAVE_FORMAT_EXTENSIBLE (0xFFFE) - -// The maximum propagation delay value supported by OpenAL Soft. -#define MAX_HRTD (63.0) - -// The OpenAL Soft HRTF format marker. It stands for minimum-phase head -// response protocol 01. -#define MHR_FORMAT ("MinPHR01") - -// Byte order for the serialization routines. -enum ByteOrderT { - BO_NONE = 0, - BO_LITTLE , - BO_BIG -}; - -// Source format for the references listed in the data set definition. -enum SourceFormatT { - SF_NONE = 0, - SF_WAVE , // RIFF/RIFX WAVE file. - SF_BIN_LE , // Little-endian binary file. - SF_BIN_BE , // Big-endian binary file. - SF_ASCII // ASCII text file. -}; - -// Element types for the references listed in the data set definition. -enum ElementTypeT { - ET_NONE = 0, - ET_INT , // Integer elements. - ET_FP // Floating-point elements. -}; - -// Head model used for calculating the impulse delays. -enum HeadModelT { - HM_NONE = 0, - HM_DATASET , // Measure the onset from the dataset. - HM_SPHERE // Calculate the onset using a spherical head model. -}; - -// 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). -}; - -// Unsigned integer type. -typedef unsigned int uint; - -// Serialization types. The trailing digit indicates the number of bits. -typedef ALubyte uint8; - -typedef ALint int32; -typedef ALuint uint32; -typedef ALuint64SOFT uint64; - -typedef enum ByteOrderT ByteOrderT; -typedef enum SourceFormatT SourceFormatT; -typedef enum ElementTypeT ElementTypeT; -typedef enum HeadModelT HeadModelT; -typedef enum OutputFormatT OutputFormatT; - -typedef struct TokenReaderT TokenReaderT; -typedef struct SourceRefT SourceRefT; -typedef struct HrirDataT HrirDataT; -typedef struct ResamplerT ResamplerT; - -// Token reader state for parsing the data set definition. -struct TokenReaderT { - FILE * mFile; - const char * mName; - uint mLine, - mColumn; - char mRing [TR_RING_SIZE]; - size_t mIn, - mOut; -}; - -// Source reference state used when loading sources. -struct SourceRefT { - SourceFormatT mFormat; - ElementTypeT mType; - uint mSize; - int mBits; - uint mChannel, - mSkip, - mOffset; - char mPath [MAX_PATH_LEN + 1]; -}; - -// The HRIR metrics and data set used when loading, processing, and storing -// the resulting HRTF. -struct HrirDataT { - uint mIrRate, - mIrCount, - mIrSize, - mIrPoints, - mFftSize, - mEvCount, - mEvStart, - mAzCount [MAX_EV_COUNT], - mEvOffset [MAX_EV_COUNT]; - double mRadius, - mDistance, - * mHrirs, - * mHrtds, - mMaxHrtd; -}; - -// The resampler metrics and FIR filter. -struct ResamplerT { - uint mP, - mQ, - mM, - mL; - double * mF; -}; - -/* Token reader routines for parsing text files. Whitespace is not - * significant. It can process tokens as identifiers, numbers (integer and - * floating-point), strings, and operators. Strings must be encapsulated by - * double-quotes and cannot span multiple lines. - */ - -// Setup the reader on the given file. The filename can be NULL if no error -// output is desired. -static void TrSetup (FILE * fp, const char * filename, TokenReaderT * tr) { - const char * name = NULL; - char ch; - - tr -> mFile = fp; - name = filename; - // If a filename was given, store a pointer to the base name. - if (filename != NULL) { - while ((ch = (* filename)) != '\0') { - if ((ch == '/') || (ch == '\\')) - name = filename + 1; - filename ++; - } - } - tr -> mName = name; - tr -> mLine = 1; - tr -> mColumn = 1; - tr -> mIn = 0; - tr -> mOut = 0; -} - -// Prime the reader's ring buffer, and return a result indicating that there -// is text to process. -static int TrLoad (TokenReaderT * tr) { - size_t toLoad, in, count; - - toLoad = TR_RING_SIZE - (tr -> mIn - tr -> mOut); - if ((toLoad >= TR_LOAD_SIZE) && (! feof (tr -> mFile))) { - // Load TR_LOAD_SIZE (or less if at the end of the file) per read. - toLoad = TR_LOAD_SIZE; - in = tr -> mIn & TR_RING_MASK; - count = TR_RING_SIZE - in; - if (count < toLoad) { - tr -> mIn += fread (& tr -> mRing [in], 1, count, tr -> mFile); - tr -> mIn += fread (& tr -> mRing [0], 1, toLoad - count, tr -> mFile); - } else { - tr -> mIn += fread (& tr -> mRing [in], 1, toLoad, tr -> mFile); - } - if (tr -> mOut >= TR_RING_SIZE) { - tr -> mOut -= TR_RING_SIZE; - tr -> mIn -= TR_RING_SIZE; - } - } - if (tr -> mIn > tr -> mOut) - return (1); - return (0); -} - -// Error display routine. Only displays when the base name is not NULL. -static void TrErrorVA (const TokenReaderT * tr, uint line, uint column, const char * format, va_list argPtr) { - if (tr -> mName != NULL) { - fprintf (stderr, "Error (%s:%u:%u): ", tr -> mName, line, column); - vfprintf (stderr, format, argPtr); - } -} - -// Used to display an error at a saved line/column. -static void TrErrorAt (const TokenReaderT * tr, uint line, uint column, const char * format, ...) { - va_list argPtr; - - va_start (argPtr, format); - TrErrorVA (tr, line, column, format, argPtr); - va_end (argPtr); -} - -// Used to display an error at the current line/column. -static void TrError (const TokenReaderT * tr, const char * format, ...) { - va_list argPtr; - - va_start (argPtr, format); - TrErrorVA (tr, tr -> mLine, tr -> mColumn, format, argPtr); - va_end (argPtr); -} - -// Skips to the next line. -static void TrSkipLine (TokenReaderT * tr) { - char ch; - - while (TrLoad (tr)) { - ch = tr -> mRing [tr -> mOut & TR_RING_MASK]; - tr -> mOut ++; - if (ch == '\n') { - tr -> mLine ++; - tr -> mColumn = 1; - break; - } - tr -> mColumn ++; - } -} - -// Skips to the next token. -static int TrSkipWhitespace (TokenReaderT * tr) { - char ch; - - while (TrLoad (tr)) { - ch = tr -> mRing [tr -> mOut & TR_RING_MASK]; - if (isspace (ch)) { - tr -> mOut ++; - if (ch == '\n') { - tr -> mLine ++; - tr -> mColumn = 1; - } else { - tr -> mColumn ++; - } - } else if (ch == '#') { - TrSkipLine (tr); - } else { - return (1); - } - } - return (0); -} - -// Get the line and/or column of the next token (or the end of input). -static void TrIndication (TokenReaderT * tr, uint * line, uint * column) { - TrSkipWhitespace (tr); - if (line != NULL) - (* line) = tr -> mLine; - if (column != NULL) - (* column) = tr -> mColumn; -} - -// Checks to see if a token is the given operator. It does not display any -// errors and will not proceed to the next token. -static int TrIsOperator (TokenReaderT * tr, const char * op) { - size_t out, len; - char ch; - - if (! TrSkipWhitespace (tr)) - return (0); - out = tr -> mOut; - len = 0; - while ((op [len] != '\0') && (out < tr -> mIn)) { - ch = tr -> mRing [out & TR_RING_MASK]; - if (ch != op [len]) - break; - len ++; - out ++; - } - if (op [len] == '\0') - return (1); - return (0); -} - -/* The TrRead*() routines obtain the value of a matching token type. They - * display type, form, and boundary errors and will proceed to the next - * token. - */ - -// Reads and validates an identifier token. -static int TrReadIdent (TokenReaderT * tr, const uint maxLen, char * ident) { - uint col, len; - char ch; - - col = tr -> mColumn; - if (TrSkipWhitespace (tr)) { - col = tr -> mColumn; - ch = tr -> mRing [tr -> mOut & TR_RING_MASK]; - if ((ch == '_') || isalpha (ch)) { - len = 0; - do { - if (len < maxLen) - ident [len] = ch; - len ++; - tr -> mOut ++; - if (! TrLoad (tr)) - break; - ch = tr -> mRing [tr -> mOut & TR_RING_MASK]; - } while ((ch == '_') || isdigit (ch) || isalpha (ch)); - tr -> mColumn += len; - if (len > maxLen) { - TrErrorAt (tr, tr -> mLine, col, "Identifier is too long.\n"); - return (0); - } - ident [len] = '\0'; - return (1); - } - } - TrErrorAt (tr, tr -> mLine, col, "Expected an identifier.\n"); - return (0); -} - -// Reads and validates (including bounds) an integer token. -static int TrReadInt (TokenReaderT * tr, const int loBound, const int hiBound, int * value) { - uint col, digis, len; - char ch, temp [64 + 1]; - - col = tr -> mColumn; - if (TrSkipWhitespace (tr)) { - col = tr -> mColumn; - len = 0; - ch = tr -> mRing [tr -> mOut & TR_RING_MASK]; - if ((ch == '+') || (ch == '-')) { - temp [len] = ch; - len ++; - tr -> mOut ++; - } - digis = 0; - while (TrLoad (tr)) { - ch = tr -> mRing [tr -> mOut & TR_RING_MASK]; - if (! isdigit (ch)) - break; - if (len < 64) - temp [len] = ch; - len ++; - digis ++; - tr -> mOut ++; - } - tr -> mColumn += len; - if ((digis > 0) && (ch != '.') && (! isalpha (ch))) { - if (len > 64) { - TrErrorAt (tr, tr -> mLine, col, "Integer is too long."); - return (0); - } - temp [len] = '\0'; - (* value) = strtol (temp, NULL, 10); - if (((* value) < loBound) || ((* value) > hiBound)) { - TrErrorAt (tr, tr -> mLine, col, "Expected a value from %d to %d.\n", loBound, hiBound); - return (0); - } - return (1); - } - } - TrErrorAt (tr, tr -> mLine, col, "Expected an integer.\n"); - return (0); -} - -// Reads and validates (including bounds) a float token. -static int TrReadFloat (TokenReaderT * tr, const double loBound, const double hiBound, double * value) { - uint col, digis, len; - char ch, temp [64 + 1]; - - col = tr -> mColumn; - if (TrSkipWhitespace (tr)) { - col = tr -> mColumn; - len = 0; - ch = tr -> mRing [tr -> mOut & TR_RING_MASK]; - if ((ch == '+') || (ch == '-')) { - temp [len] = ch; - len ++; - tr -> mOut ++; - } - digis = 0; - while (TrLoad (tr)) { - ch = tr -> mRing [tr -> mOut & TR_RING_MASK]; - if (! isdigit (ch)) - break; - if (len < 64) - temp [len] = ch; - len ++; - digis ++; - tr -> mOut ++; - } - if (ch == '.') { - if (len < 64) - temp [len] = ch; - len ++; - tr -> mOut ++; - } - while (TrLoad (tr)) { - ch = tr -> mRing [tr -> mOut & TR_RING_MASK]; - if (! isdigit (ch)) - break; - if (len < 64) - temp [len] = ch; - len ++; - digis ++; - tr -> mOut ++; - } - if (digis > 0) { - if ((ch == 'E') || (ch == 'e')) { - if (len < 64) - temp [len] = ch; - len ++; - digis = 0; - tr -> mOut ++; - if ((ch == '+') || (ch == '-')) { - if (len < 64) - temp [len] = ch; - len ++; - tr -> mOut ++; - } - while (TrLoad (tr)) { - ch = tr -> mRing [tr -> mOut & TR_RING_MASK]; - if (! isdigit (ch)) - break; - if (len < 64) - temp [len] = ch; - len ++; - digis ++; - tr -> mOut ++; - } - } - tr -> mColumn += len; - if ((digis > 0) && (ch != '.') && (! isalpha (ch))) { - if (len > 64) { - TrErrorAt (tr, tr -> mLine, col, "Float is too long."); - return (0); - } - temp [len] = '\0'; - (* value) = strtod (temp, NULL); - if (((* value) < loBound) || ((* value) > hiBound)) { - TrErrorAt (tr, tr -> mLine, col, "Expected a value from %f to %f.\n", loBound, hiBound); - return (0); - } - return (1); - } - } else { - tr -> mColumn += len; - } - } - TrErrorAt (tr, tr -> mLine, col, "Expected a float.\n"); - return (0); -} - -// Reads and validates a string token. -static int TrReadString (TokenReaderT * tr, const uint maxLen, char * text) { - uint col, len; - char ch; - - col = tr -> mColumn; - if (TrSkipWhitespace (tr)) { - col = tr -> mColumn; - ch = tr -> mRing [tr -> mOut & TR_RING_MASK]; - if (ch == '\"') { - tr -> mOut ++; - len = 0; - while (TrLoad (tr)) { - ch = tr -> mRing [tr -> mOut & TR_RING_MASK]; - tr -> mOut ++; - if (ch == '\"') - break; - if (ch == '\n') { - TrErrorAt (tr, tr -> mLine, col, "Unterminated string at end of line.\n"); - return (0); - } - if (len < maxLen) - text [len] = ch; - len ++; - } - if (ch != '\"') { - tr -> mColumn += 1 + len; - TrErrorAt (tr, tr -> mLine, col, "Unterminated string at end of input.\n"); - return (0); - } - tr -> mColumn += 2 + len; - if (len > maxLen) { - TrErrorAt (tr, tr -> mLine, col, "String is too long.\n"); - return (0); - } - text [len] = '\0'; - return (1); - } - } - TrErrorAt (tr, tr -> mLine, col, "Expected a string.\n"); - return (0); -} - -// Reads and validates the given operator. -static int TrReadOperator (TokenReaderT * tr, const char * op) { - uint col, len; - char ch; - - col = tr -> mColumn; - if (TrSkipWhitespace (tr)) { - col = tr -> mColumn; - len = 0; - while ((op [len] != '\0') && TrLoad (tr)) { - ch = tr -> mRing [tr -> mOut & TR_RING_MASK]; - if (ch != op [len]) - break; - len ++; - tr -> mOut ++; - } - tr -> mColumn += len; - if (op [len] == '\0') - return (1); - } - TrErrorAt (tr, tr -> mLine, col, "Expected '%s' operator.\n", op); - return (0); -} - -/* Performs a string substitution. Any case-insensitive occurrences of the - * pattern string are replaced with the replacement string. The result is - * truncated if necessary. - */ -static int StrSubst (const char * in, const char * pat, const char * rep, const size_t maxLen, char * out) { - size_t inLen, patLen, repLen; - size_t si, di; - int truncated; - - inLen = strlen (in); - patLen = strlen (pat); - repLen = strlen (rep); - si = 0; - di = 0; - truncated = 0; - while ((si < inLen) && (di < maxLen)) { - if (patLen <= (inLen - si)) { - if (strncasecmp (& in [si], pat, patLen) == 0) { - if (repLen > (maxLen - di)) { - repLen = maxLen - di; - truncated = 1; - } - strncpy (& out [di], rep, repLen); - si += patLen; - di += repLen; - } - } - out [di] = in [si]; - si ++; - di ++; - } - if (si < inLen) - truncated = 1; - out [di] = '\0'; - return (! truncated); -} - -// Provide missing math routines for MSVC versions < 1800 (Visual Studio 2013). -#if defined(_MSC_VER) && _MSC_VER < 1800 -static double round (double val) { - if (val < 0.0) - return (ceil (val - 0.5)); - return (floor (val + 0.5)); -} - -static double fmin (double a, double b) { - return ((a < b) ? a : b); -} - -static double fmax (double a, double b) { - return ((a > b) ? a : b); -} -#endif - -// Simple clamp routine. -static double Clamp (const double val, const double lower, const double upper) { - return (fmin (fmax (val, lower), upper)); -} - -// Performs linear interpolation. -static double Lerp (const double a, const double b, const double f) { - return (a + (f * (b - a))); -} - -// Performs a high-passed triangular probability density function dither from -// a double to an integer. It assumes the input sample is already scaled. -static int HpTpdfDither (const double in, int * hpHist) { - const double PRNG_SCALE = 1.0 / (RAND_MAX + 1.0); - int prn; - double out; - - prn = rand (); - out = round (in + (PRNG_SCALE * (prn - (* hpHist)))); - (* hpHist) = prn; - return ((int) out); -} - -// Allocates an array of doubles. -static double *CreateArray(size_t n) -{ - double *a; - - if(n == 0) n = 1; - a = calloc(n, sizeof(double)); - if(a == NULL) - { - fprintf(stderr, "Error: Out of memory.\n"); - exit(-1); - } - return a; -} - -// Frees an array of doubles. -static void DestroyArray(double *a) -{ free(a); } - -// Complex number routines. All outputs must be non-NULL. - -// Magnitude/absolute value. -static double ComplexAbs (const double r, const double i) { - return (sqrt ((r * r) + (i * i))); -} - -// Multiply. -static void ComplexMul (const double aR, const double aI, const double bR, const double bI, double * outR, double * outI) { - (* outR) = (aR * bR) - (aI * bI); - (* outI) = (aI * bR) + (aR * bI); -} - -// Base-e exponent. -static void ComplexExp (const double inR, const double inI, double * outR, double * outI) { - double e; - - e = exp (inR); - (* outR) = e * cos (inI); - (* outI) = e * sin (inI); -} - -/* Fast Fourier transform routines. The number of points must be a power of - * two. In-place operation is possible only if both the real and imaginary - * parts are in-place together. - */ - -// Performs bit-reversal ordering. -static void FftArrange (const uint n, const double * inR, const double * inI, double * outR, double * outI) { - uint rk, k, m; - double tempR, tempI; - - if ((inR == outR) && (inI == outI)) { - // Handle in-place arrangement. - rk = 0; - for (k = 0; k < n; k ++) { - if (rk > k) { - tempR = inR [rk]; - tempI = inI [rk]; - outR [rk] = inR [k]; - outI [rk] = inI [k]; - outR [k] = tempR; - outI [k] = tempI; - } - m = n; - while (rk & (m >>= 1)) - rk &= ~m; - rk |= m; - } - } else { - // Handle copy arrangement. - rk = 0; - for (k = 0; k < n; k ++) { - outR [rk] = inR [k]; - outI [rk] = inI [k]; - m = n; - while (rk & (m >>= 1)) - rk &= ~m; - rk |= m; - } - } -} - -// Performs the summation. -static void FftSummation (const uint n, const double s, double * re, double * im) { - double pi; - uint m, m2; - double vR, vI, wR, wI; - uint i, k, mk; - double tR, tI; - - pi = s * M_PI; - for (m = 1, m2 = 2; m < n; m <<= 1, m2 <<= 1) { - // v = Complex (-2.0 * sin (0.5 * pi / m) * sin (0.5 * pi / m), -sin (pi / m)) - vR = sin (0.5 * pi / m); - vR = -2.0 * vR * vR; - vI = -sin (pi / m); - // w = Complex (1.0, 0.0) - wR = 1.0; - wI = 0.0; - for (i = 0; i < m; i ++) { - for (k = i; k < n; k += m2) { - mk = k + m; - // t = ComplexMul (w, out [km2]) - tR = (wR * re [mk]) - (wI * im [mk]); - tI = (wR * im [mk]) + (wI * re [mk]); - // out [mk] = ComplexSub (out [k], t) - re [mk] = re [k] - tR; - im [mk] = im [k] - tI; - // out [k] = ComplexAdd (out [k], t) - re [k] += tR; - im [k] += tI; - } - // t = ComplexMul (v, w) - tR = (vR * wR) - (vI * wI); - tI = (vR * wI) + (vI * wR); - // w = ComplexAdd (w, t) - wR += tR; - wI += tI; - } - } -} - -// Performs a forward FFT. -static void FftForward (const uint n, const double * inR, const double * inI, double * outR, double * outI) { - FftArrange (n, inR, inI, outR, outI); - FftSummation (n, 1.0, outR, outI); -} - -// Performs an inverse FFT. -static void FftInverse (const uint n, const double * inR, const double * inI, double * outR, double * outI) { - double f; - uint i; - - FftArrange (n, inR, inI, outR, outI); - FftSummation (n, -1.0, outR, outI); - f = 1.0 / n; - for (i = 0; i < n; i ++) { - outR [i] *= f; - outI [i] *= f; - } -} - -/* Calculate the complex helical sequence (or discrete-time analytical - * signal) of the given input using the Hilbert transform. Given the - * negative natural logarithm of a signal's magnitude response, the imaginary - * components can be used as the angles for minimum-phase reconstruction. - */ -static void Hilbert (const uint n, const double * in, double * outR, double * outI) { - uint i; - - if (in == outR) { - // Handle in-place operation. - for (i = 0; i < n; i ++) - outI [i] = 0.0; - } else { - // Handle copy operation. - for (i = 0; i < n; i ++) { - outR [i] = in [i]; - outI [i] = 0.0; - } - } - FftForward (n, outR, outI, outR, outI); - /* Currently the Fourier routines operate only on point counts that are - * powers of two. If that changes and n is odd, the following conditional - * should be: i < (n + 1) / 2. - */ - for (i = 1; i < (n / 2); i ++) { - outR [i] *= 2.0; - outI [i] *= 2.0; - } - // If n is odd, the following increment should be skipped. - i ++; - for (; i < n; i ++) { - outR [i] = 0.0; - outI [i] = 0.0; - } - FftInverse (n, outR, outI, outR, outI); -} - -/* Calculate the magnitude response of the given input. This is used in - * place of phase decomposition, since the phase residuals are discarded for - * minimum phase reconstruction. The mirrored half of the response is also - * discarded. - */ -static void MagnitudeResponse (const uint n, const double * inR, const double * inI, double * out) { - const uint m = 1 + (n / 2); - uint i; - - for (i = 0; i < m; i ++) - out [i] = fmax (ComplexAbs (inR [i], inI [i]), EPSILON); -} - -/* Apply a range limit (in dB) to the given magnitude response. This is used - * to adjust the effects of the diffuse-field average on the equalization - * process. - */ -static void LimitMagnitudeResponse (const uint n, const double limit, const double * in, double * out) { - const uint m = 1 + (n / 2); - double halfLim; - uint i, lower, upper; - double ave; - - halfLim = limit / 2.0; - // Convert the response to dB. - for (i = 0; i < m; i ++) - out [i] = 20.0 * log10 (in [i]); - // Use six octaves to calculate the average magnitude of the signal. - lower = ((uint) ceil (n / pow (2.0, 8.0))) - 1; - upper = ((uint) floor (n / pow (2.0, 2.0))) - 1; - ave = 0.0; - for (i = lower; i <= upper; i ++) - ave += out [i]; - ave /= upper - lower + 1; - // Keep the response within range of the average magnitude. - for (i = 0; i < m; i ++) - out [i] = Clamp (out [i], ave - halfLim, ave + halfLim); - // Convert the response back to linear magnitude. - for (i = 0; i < m; i ++) - out [i] = pow (10.0, out [i] / 20.0); -} - -/* Reconstructs the minimum-phase component for the given magnitude response - * of a signal. This is equivalent to phase recomposition, sans the missing - * residuals (which were discarded). The mirrored half of the response is - * reconstructed. - */ -static void MinimumPhase (const uint n, const double * in, double * outR, double * outI) { - const uint m = 1 + (n / 2); - double * mags = NULL; - uint i; - double aR, aI; - - mags = CreateArray (n); - for (i = 0; i < m; i ++) { - mags [i] = fmax (in [i], EPSILON); - outR [i] = -log (mags [i]); - } - for (; i < n; i ++) { - mags [i] = mags [n - i]; - outR [i] = outR [n - i]; - } - Hilbert (n, outR, outR, outI); - // Remove any DC offset the filter has. - outR [0] = 0.0; - outI [0] = 0.0; - for (i = 1; i < n; i ++) { - ComplexExp (0.0, outI [i], & aR, & aI); - ComplexMul (mags [i], 0.0, aR, aI, & outR [i], & outI [i]); - } - DestroyArray (mags); -} - -/* This is the normalized cardinal sine (sinc) function. - * - * sinc(x) = { 1, x = 0 - * { sin(pi x) / (pi x), otherwise. - */ -static double Sinc (const double x) { - if (fabs (x) < EPSILON) - return (1.0); - return (sin (M_PI * x) / (M_PI * x)); -} - -/* The zero-order modified Bessel function of the first kind, used for the - * Kaiser window. - * - * I_0(x) = sum_{k=0}^inf (1 / k!)^2 (x / 2)^(2 k) - * = sum_{k=0}^inf ((x / 2)^k / k!)^2 - */ -static double BesselI_0 (const double x) { - double term, sum, x2, y, last_sum; - int k; - - // Start at k=1 since k=0 is trivial. - term = 1.0; - sum = 1.0; - x2 = x / 2.0; - k = 1; - // Let the integration converge until the term of the sum is no longer - // significant. - do { - y = x2 / k; - k ++; - last_sum = sum; - term *= y * y; - sum += term; - } while (sum != last_sum); - return (sum); -} - -/* Calculate a Kaiser window from the given beta value and a normalized k - * [-1, 1]. - * - * w(k) = { I_0(B sqrt(1 - k^2)) / I_0(B), -1 <= k <= 1 - * { 0, elsewhere. - * - * Where k can be calculated as: - * - * k = i / l, where -l <= i <= l. - * - * or: - * - * k = 2 i / M - 1, where 0 <= i <= M. - */ -static double Kaiser (const double b, const double k) { - double k2; - - k2 = Clamp (k, -1.0, 1.0); - if ((k < -1.0) || (k > 1.0)) - return (0.0); - k2 *= k2; - return (BesselI_0 (b * sqrt (1.0 - k2)) / BesselI_0 (b)); -} - -// Calculates the greatest common divisor of a and b. -static uint Gcd (const uint a, const uint b) { - uint x, y, z; - - x = a; - y = b; - while (y > 0) { - z = y; - y = x % y; - x = z; - } - return (x); -} - -/* Calculates the size (order) of the Kaiser window. Rejection is in dB and - * the transition width is normalized frequency (0.5 is nyquist). - * - * M = { ceil((r - 7.95) / (2.285 2 pi f_t)), r > 21 - * { ceil(5.79 / 2 pi f_t), r <= 21. - * - */ -static uint CalcKaiserOrder (const double rejection, const double transition) { - double w_t; - - w_t = 2.0 * M_PI * transition; - if (rejection > 21.0) - return ((uint) ceil ((rejection - 7.95) / (2.285 * w_t))); - return ((uint) ceil (5.79 / w_t)); -} - -// Calculates the beta value of the Kaiser window. Rejection is in dB. -static double CalcKaiserBeta (const double rejection) { - if (rejection > 50.0) - return (0.1102 * (rejection - 8.7)); - else if (rejection >= 21.0) - return ((0.5842 * pow (rejection - 21.0, 0.4)) + - (0.07886 * (rejection - 21.0))); - else - return (0.0); -} - -/* Calculates a point on the Kaiser-windowed sinc filter for the given half- - * width, beta, gain, and cutoff. The point is specified in non-normalized - * samples, from 0 to M, where M = (2 l + 1). - * - * w(k) 2 p f_t sinc(2 f_t x) - * - * x -- centered sample index (i - l) - * k -- normalized and centered window index (x / l) - * w(k) -- window function (Kaiser) - * p -- gain compensation factor when sampling - * f_t -- normalized center frequency (or cutoff; 0.5 is nyquist) - */ -static double SincFilter (const int l, const double b, const double gain, const double cutoff, const int i) { - return (Kaiser (b, ((double) (i - l)) / l) * 2.0 * gain * cutoff * Sinc (2.0 * cutoff * (i - l))); -} - -/* This is a polyphase sinc-filtered resampler. - * - * Upsample Downsample - * - * p/q = 3/2 p/q = 3/5 - * - * M-+-+-+-> M-+-+-+-> - * -------------------+ ---------------------+ - * p s * f f f f|f| | p s * f f f f f | - * | 0 * 0 0 0|0|0 | | 0 * 0 0 0 0|0| | - * v 0 * 0 0|0|0 0 | v 0 * 0 0 0|0|0 | - * s * f|f|f f f | s * f f|f|f f | - * 0 * |0|0 0 0 0 | 0 * 0|0|0 0 0 | - * --------+=+--------+ 0 * |0|0 0 0 0 | - * d . d .|d|. d . d ----------+=+--------+ - * d . . . .|d|. . . . - * q-> - * q-+-+-+-> - * - * P_f(i,j) = q i mod p + pj - * P_s(i,j) = floor(q i / p) - j - * d[i=0..N-1] = sum_{j=0}^{floor((M - 1) / p)} { - * { f[P_f(i,j)] s[P_s(i,j)], P_f(i,j) < M - * { 0, P_f(i,j) >= M. } - */ - -// Calculate the resampling metrics and build the Kaiser-windowed sinc filter -// that's used to cut frequencies above the destination nyquist. -static void ResamplerSetup (ResamplerT * rs, const uint srcRate, const uint dstRate) { - uint gcd, l; - double cutoff, width, beta; - int i; - - gcd = Gcd (srcRate, dstRate); - rs -> mP = dstRate / gcd; - rs -> mQ = srcRate / gcd; - /* The cutoff is adjusted by half the transition width, so the transition - * ends before the nyquist (0.5). Both are scaled by the downsampling - * factor. - */ - if (rs -> mP > rs -> mQ) { - cutoff = 0.45 / rs -> mP; - width = 0.1 / rs -> mP; - } else { - cutoff = 0.45 / rs -> mQ; - width = 0.1 / rs -> mQ; - } - // A rejection of -180 dB is used for the stop band. - l = CalcKaiserOrder (180.0, width) / 2; - beta = CalcKaiserBeta (180.0); - rs -> mM = (2 * l) + 1; - rs -> mL = l; - rs -> mF = CreateArray (rs -> mM); - for (i = 0; i < ((int) rs -> mM); i ++) - rs -> mF [i] = SincFilter ((int) l, beta, rs -> mP, cutoff, i); -} - -// Clean up after the resampler. -static void ResamplerClear (ResamplerT * rs) { - DestroyArray (rs -> mF); - rs -> mF = NULL; -} - -// Perform the upsample-filter-downsample resampling operation using a -// polyphase filter implementation. -static void ResamplerRun (ResamplerT * rs, const uint inN, const double * in, const uint outN, double * out) { - const uint p = rs -> mP, q = rs -> mQ, m = rs -> mM, l = rs -> mL; - const double * f = rs -> mF; - double * work = NULL; - uint i; - double r; - uint j_f, j_s; - - if (outN == 0) - return; - - // Handle in-place operation. - if (in == out) - work = CreateArray (outN); - else - work = out; - // Resample the input. - for (i = 0; i < outN; i ++) { - r = 0.0; - // Input starts at l to compensate for the filter delay. This will - // drop any build-up from the first half of the filter. - j_f = (l + (q * i)) % p; - j_s = (l + (q * i)) / p; - while (j_f < m) { - // Only take input when 0 <= j_s < inN. This single unsigned - // comparison catches both cases. - if (j_s < inN) - r += f [j_f] * in [j_s]; - j_f += p; - j_s --; - } - work [i] = r; - } - // Clean up after in-place operation. - if (in == out) { - for (i = 0; i < outN; i ++) - out [i] = work [i]; - DestroyArray (work); - } -} - -// Read a binary value of the specified byte order and byte size from a file, -// storing it as a 32-bit unsigned integer. -static int ReadBin4 (FILE * fp, const char * filename, const ByteOrderT order, const uint bytes, uint32 * out) { - uint8 in [4]; - uint32 accum; - uint i; - - if (fread (in, 1, bytes, fp) != bytes) { - fprintf (stderr, "Error: Bad read from file '%s'.\n", filename); - return (0); - } - accum = 0; - switch (order) { - case BO_LITTLE : - for (i = 0; i < bytes; i ++) - accum = (accum << 8) | in [bytes - i - 1]; - break; - case BO_BIG : - for (i = 0; i < bytes; i ++) - accum = (accum << 8) | in [i]; - break; - default : - break; - } - (* out) = accum; - return (1); -} - -// Read a binary value of the specified byte order from a file, storing it as -// a 64-bit unsigned integer. -static int ReadBin8 (FILE * fp, const char * filename, const ByteOrderT order, uint64 * out) { - uint8 in [8]; - uint64 accum; - uint i; - - if (fread (in, 1, 8, fp) != 8) { - fprintf (stderr, "Error: Bad read from file '%s'.\n", filename); - return (0); - } - accum = 0ULL; - switch (order) { - case BO_LITTLE : - for (i = 0; i < 8; i ++) - accum = (accum << 8) | in [8 - i - 1]; - break; - case BO_BIG : - for (i = 0; i < 8; i ++) - accum = (accum << 8) | in [i]; - break; - default : - break; - } - (* out) = accum; - return (1); -} - -// Write an ASCII string to a file. -static int WriteAscii (const char * out, FILE * fp, const char * filename) { - size_t len; - - len = strlen (out); - if (fwrite (out, 1, len, fp) != len) { - fclose (fp); - fprintf (stderr, "Error: Bad write to file '%s'.\n", filename); - return (0); - } - return (1); -} - -// Write a binary value of the given byte order and byte size to a file, -// loading it from a 32-bit unsigned integer. -static int WriteBin4 (const ByteOrderT order, const uint bytes, const uint32 in, FILE * fp, const char * filename) { - uint8 out [4]; - uint i; - - switch (order) { - case BO_LITTLE : - for (i = 0; i < bytes; i ++) - out [i] = (in >> (i * 8)) & 0x000000FF; - break; - case BO_BIG : - for (i = 0; i < bytes; i ++) - out [bytes - i - 1] = (in >> (i * 8)) & 0x000000FF; - break; - default : - break; - } - if (fwrite (out, 1, bytes, fp) != bytes) { - fprintf (stderr, "Error: Bad write to file '%s'.\n", filename); - return (0); - } - return (1); -} - -/* Read a binary value of the specified type, byte order, and byte size from - * a file, converting it to a double. For integer types, the significant - * bits are used to normalize the result. The sign of bits determines - * whether they are padded toward the MSB (negative) or LSB (positive). - * Floating-point types are not normalized. - */ -static int ReadBinAsDouble (FILE * fp, const char * filename, const ByteOrderT order, const ElementTypeT type, const uint bytes, const int bits, double * out) { - union { - uint32 ui; - int32 i; - float f; - } v4; - union { - uint64 ui; - double f; - } v8; - - (* out) = 0.0; - if (bytes > 4) { - if (! ReadBin8 (fp, filename, order, & v8 . ui)) - return (0); - if (type == ET_FP) - (* out) = v8 . f; - } else { - if (! ReadBin4 (fp, filename, order, bytes, & v4 . ui)) - return (0); - if (type == ET_FP) { - (* out) = (double) v4 . f; - } else { - if (bits > 0) - v4 . ui >>= (8 * bytes) - ((uint) bits); - else - v4 . ui &= (0xFFFFFFFF >> (32 + bits)); - if (v4 . ui & ((uint) (1 << (abs (bits) - 1)))) - v4 . ui |= (0xFFFFFFFF << abs (bits)); - (* out) = v4 . i / ((double) (1 << (abs (bits) - 1))); - } - } - return (1); -} - -/* Read an ascii value of the specified type from a file, converting it to a - * double. For integer types, the significant bits are used to normalize the - * result. The sign of the bits should always be positive. This also skips - * up to one separator character before the element itself. - */ -static int ReadAsciiAsDouble (TokenReaderT * tr, const char * filename, const ElementTypeT type, const uint bits, double * out) { - int v; - - if (TrIsOperator (tr, ",")) - TrReadOperator (tr, ","); - else if (TrIsOperator (tr, ":")) - TrReadOperator (tr, ":"); - else if (TrIsOperator (tr, ";")) - TrReadOperator (tr, ";"); - else if (TrIsOperator (tr, "|")) - TrReadOperator (tr, "|"); - if (type == ET_FP) { - if (! TrReadFloat (tr, -HUGE_VAL, HUGE_VAL, out)) { - fprintf (stderr, "Error: Bad read from file '%s'.\n", filename); - return (0); - } - } else { - if (! TrReadInt (tr, -(1 << (bits - 1)), (1 << (bits - 1)) - 1, & v)) { - fprintf (stderr, "Error: Bad read from file '%s'.\n", filename); - return (0); - } - (* out) = v / ((double) ((1 << (bits - 1)) - 1)); - } - return (1); -} - -// Read the RIFF/RIFX WAVE format chunk from a file, validating it against -// the source parameters and data set metrics. -static int ReadWaveFormat (FILE * fp, const ByteOrderT order, const uint hrirRate, SourceRefT * src) { - uint32 fourCC, chunkSize; - uint32 format, channels, rate, dummy, block, size, bits; - - chunkSize = 0; - do { - if (chunkSize > 0) - fseek (fp, (long) chunkSize, SEEK_CUR); - if ((! ReadBin4 (fp, src -> mPath, BO_LITTLE, 4, & fourCC)) || - (! ReadBin4 (fp, src -> mPath, order, 4, & chunkSize))) - return (0); - } while (fourCC != FOURCC_FMT); - if ((! ReadBin4 (fp, src -> mPath, order, 2, & format)) || - (! ReadBin4 (fp, src -> mPath, order, 2, & channels)) || - (! ReadBin4 (fp, src -> mPath, order, 4, & rate)) || - (! ReadBin4 (fp, src -> mPath, order, 4, & dummy)) || - (! ReadBin4 (fp, src -> mPath, order, 2, & block))) - return (0); - block /= channels; - if (chunkSize > 14) { - if (! ReadBin4 (fp, src -> mPath, order, 2, & size)) - return (0); - size /= 8; - if (block > size) - size = block; - } else { - size = block; - } - if (format == WAVE_FORMAT_EXTENSIBLE) { - fseek (fp, 2, SEEK_CUR); - if (! ReadBin4 (fp, src -> mPath, order, 2, & bits)) - return (0); - if (bits == 0) - bits = 8 * size; - fseek (fp, 4, SEEK_CUR); - if (! ReadBin4 (fp, src -> mPath, order, 2, & format)) - return (0); - fseek (fp, (long) (chunkSize - 26), SEEK_CUR); - } else { - bits = 8 * size; - if (chunkSize > 14) - fseek (fp, (long) (chunkSize - 16), SEEK_CUR); - else - fseek (fp, (long) (chunkSize - 14), SEEK_CUR); - } - if ((format != WAVE_FORMAT_PCM) && (format != WAVE_FORMAT_IEEE_FLOAT)) { - fprintf (stderr, "Error: Unsupported WAVE format in file '%s'.\n", src -> mPath); - return (0); - } - if (src -> mChannel >= channels) { - fprintf (stderr, "Error: Missing source channel in WAVE file '%s'.\n", src -> mPath); - return (0); - } - if (rate != hrirRate) { - fprintf (stderr, "Error: Mismatched source sample rate in WAVE file '%s'.\n", src -> mPath); - return (0); - } - if (format == WAVE_FORMAT_PCM) { - if ((size < 2) || (size > 4)) { - fprintf (stderr, "Error: Unsupported sample size in WAVE file '%s'.\n", src -> mPath); - return (0); - } - if ((bits < 16) || (bits > (8 * size))) { - fprintf (stderr, "Error: Bad significant bits in WAVE file '%s'.\n", src -> mPath); - return (0); - } - src -> mType = ET_INT; - } else { - if ((size != 4) && (size != 8)) { - fprintf (stderr, "Error: Unsupported sample size in WAVE file '%s'.\n", src -> mPath); - return (0); - } - src -> mType = ET_FP; - } - src -> mSize = size; - src -> mBits = (int) bits; - src -> mSkip = channels; - return (1); -} - -// Read a RIFF/RIFX WAVE data chunk, converting all elements to doubles. -static int ReadWaveData (FILE * fp, const SourceRefT * src, const ByteOrderT order, const uint n, double * hrir) { - int pre, post, skip; - uint i; - - pre = (int) (src -> mSize * src -> mChannel); - post = (int) (src -> mSize * (src -> mSkip - src -> mChannel - 1)); - skip = 0; - for (i = 0; i < n; i ++) { - skip += pre; - if (skip > 0) - fseek (fp, skip, SEEK_CUR); - if (! ReadBinAsDouble (fp, src -> mPath, order, src -> mType, src -> mSize, src -> mBits, & hrir [i])) - return (0); - skip = post; - } - if (skip > 0) - fseek (fp, skip, SEEK_CUR); - return (1); -} - -// Read the RIFF/RIFX WAVE list or data chunk, converting all elements to -// doubles. -static int ReadWaveList (FILE * fp, const SourceRefT * src, const ByteOrderT order, const uint n, double * hrir) { - uint32 fourCC, chunkSize, listSize, count; - uint block, skip, offset, i; - double lastSample; - - for (;;) { - if ((! ReadBin4 (fp, src -> mPath, BO_LITTLE, 4, & fourCC)) || - (! ReadBin4 (fp, src -> mPath, order, 4, & chunkSize))) - return (0); - if (fourCC == FOURCC_DATA) { - block = src -> mSize * src -> mSkip; - count = chunkSize / block; - if (count < (src -> mOffset + n)) { - fprintf (stderr, "Error: Bad read from file '%s'.\n", src -> mPath); - return (0); - } - fseek (fp, (long) (src -> mOffset * block), SEEK_CUR); - if (! ReadWaveData (fp, src, order, n, & hrir [0])) - return (0); - return (1); - } else if (fourCC == FOURCC_LIST) { - if (! ReadBin4 (fp, src -> mPath, BO_LITTLE, 4, & fourCC)) - return (0); - chunkSize -= 4; - if (fourCC == FOURCC_WAVL) - break; - } - if (chunkSize > 0) - fseek (fp, (long) chunkSize, SEEK_CUR); - } - listSize = chunkSize; - block = src -> mSize * src -> mSkip; - skip = src -> mOffset; - offset = 0; - lastSample = 0.0; - while ((offset < n) && (listSize > 8)) { - if ((! ReadBin4 (fp, src -> mPath, BO_LITTLE, 4, & fourCC)) || - (! ReadBin4 (fp, src -> mPath, order, 4, & chunkSize))) - return (0); - listSize -= 8 + chunkSize; - if (fourCC == FOURCC_DATA) { - count = chunkSize / block; - if (count > skip) { - fseek (fp, (long) (skip * block), SEEK_CUR); - chunkSize -= skip * block; - count -= skip; - skip = 0; - if (count > (n - offset)) - count = n - offset; - if (! ReadWaveData (fp, src, order, count, & hrir [offset])) - return (0); - chunkSize -= count * block; - offset += count; - lastSample = hrir [offset - 1]; - } else { - skip -= count; - count = 0; - } - } else if (fourCC == FOURCC_SLNT) { - if (! ReadBin4 (fp, src -> mPath, order, 4, & count)) - return (0); - chunkSize -= 4; - if (count > skip) { - count -= skip; - skip = 0; - if (count > (n - offset)) - count = n - offset; - for (i = 0; i < count; i ++) - hrir [offset + i] = lastSample; - offset += count; - } else { - skip -= count; - count = 0; - } - } - if (chunkSize > 0) - fseek (fp, (long) chunkSize, SEEK_CUR); - } - if (offset < n) { - fprintf (stderr, "Error: Bad read from file '%s'.\n", src -> mPath); - return (0); - } - return (1); -} - -// Load a source HRIR from a RIFF/RIFX WAVE file. -static int LoadWaveSource (FILE * fp, SourceRefT * src, const uint hrirRate, const uint n, double * hrir) { - uint32 fourCC, dummy; - ByteOrderT order; - - if ((! ReadBin4 (fp, src -> mPath, BO_LITTLE, 4, & fourCC)) || - (! ReadBin4 (fp, src -> mPath, BO_LITTLE, 4, & dummy))) - return (0); - if (fourCC == FOURCC_RIFF) { - order = BO_LITTLE; - } else if (fourCC == FOURCC_RIFX) { - order = BO_BIG; - } else { - fprintf (stderr, "Error: No RIFF/RIFX chunk in file '%s'.\n", src -> mPath); - return (0); - } - if (! ReadBin4 (fp, src -> mPath, BO_LITTLE, 4, & fourCC)) - return (0); - if (fourCC != FOURCC_WAVE) { - fprintf (stderr, "Error: Not a RIFF/RIFX WAVE file '%s'.\n", src -> mPath); - return (0); - } - if (! ReadWaveFormat (fp, order, hrirRate, src)) - return (0); - if (! ReadWaveList (fp, src, order, n, hrir)) - return (0); - return (1); -} - -// Load a source HRIR from a binary file. -static int LoadBinarySource (FILE * fp, const SourceRefT * src, const ByteOrderT order, const uint n, double * hrir) { - uint i; - - fseek (fp, (long) src -> mOffset, SEEK_SET); - for (i = 0; i < n; i ++) { - if (! ReadBinAsDouble (fp, src -> mPath, order, src -> mType, src -> mSize, src -> mBits, & hrir [i])) - return (0); - if (src -> mSkip > 0) - fseek (fp, (long) src -> mSkip, SEEK_CUR); - } - return (1); -} - -// Load a source HRIR from an ASCII text file containing a list of elements -// separated by whitespace or common list operators (',', ';', ':', '|'). -static int LoadAsciiSource (FILE * fp, const SourceRefT * src, const uint n, double * hrir) { - TokenReaderT tr; - uint i, j; - double dummy; - - TrSetup (fp, NULL, & tr); - for (i = 0; i < src -> mOffset; i ++) { - if (! ReadAsciiAsDouble (& tr, src -> mPath, src -> mType, (uint) src -> mBits, & dummy)) - return (0); - } - for (i = 0; i < n; i ++) { - if (! ReadAsciiAsDouble (& tr, src -> mPath, src -> mType, (uint) src -> mBits, & hrir [i])) - return (0); - for (j = 0; j < src -> mSkip; j ++) { - if (! ReadAsciiAsDouble (& tr, src -> mPath, src -> mType, (uint) src -> mBits, & dummy)) - return (0); - } - } - return (1); -} - -// Load a source HRIR from a supported file type. -static int LoadSource (SourceRefT * src, const uint hrirRate, const uint n, double * hrir) { - FILE * fp = NULL; - int result; - - if (src -> mFormat == SF_ASCII) - fp = fopen (src -> mPath, "r"); - else - fp = fopen (src -> mPath, "rb"); - if (fp == NULL) { - fprintf (stderr, "Error: Could not open source file '%s'.\n", src -> mPath); - return (0); - } - if (src -> mFormat == SF_WAVE) - result = LoadWaveSource (fp, src, hrirRate, n, hrir); - else if (src -> mFormat == SF_BIN_LE) - result = LoadBinarySource (fp, src, BO_LITTLE, n, hrir); - else if (src -> mFormat == SF_BIN_BE) - result = LoadBinarySource (fp, src, BO_BIG, n, hrir); - else - result = LoadAsciiSource (fp, src, n, hrir); - fclose (fp); - return (result); -} - -// Calculate the onset time of an HRIR and average it with any existing -// timing for its elevation and azimuth. -static void AverageHrirOnset (const double * hrir, const double f, const uint ei, const uint ai, const HrirDataT * hData) { - double mag; - uint n, i, j; - - mag = 0.0; - n = hData -> mIrPoints; - for (i = 0; i < n; i ++) - mag = fmax (fabs (hrir [i]), mag); - mag *= 0.15; - for (i = 0; i < n; i ++) { - if (fabs (hrir [i]) >= mag) - break; - } - j = hData -> mEvOffset [ei] + ai; - hData -> mHrtds [j] = Lerp (hData -> mHrtds [j], ((double) i) / hData -> mIrRate, f); -} - -// Calculate the magnitude response of an HRIR and average it with any -// existing responses for its elevation and azimuth. -static void AverageHrirMagnitude (const double * hrir, const double f, const uint ei, const uint ai, const HrirDataT * hData) { - double * re = NULL, * im = NULL; - uint n, m, i, j; - - n = hData -> mFftSize; - re = CreateArray (n); - im = CreateArray (n); - for (i = 0; i < hData -> mIrPoints; i ++) { - re [i] = hrir [i]; - im [i] = 0.0; - } - for (; i < n; i ++) { - re [i] = 0.0; - im [i] = 0.0; - } - FftForward (n, re, im, re, im); - MagnitudeResponse (n, re, im, re); - m = 1 + (n / 2); - j = (hData -> mEvOffset [ei] + ai) * hData -> mIrSize; - for (i = 0; i < m; i ++) - hData -> mHrirs [j + i] = Lerp (hData -> mHrirs [j + i], re [i], f); - DestroyArray (im); - DestroyArray (re); -} - -/* Calculate the contribution of each HRIR to the diffuse-field average based - * on the area of its surface patch. All patches are centered at the HRIR - * coordinates on the unit sphere and are measured by solid angle. - */ -static void CalculateDfWeights (const HrirDataT * hData, double * weights) { - uint ei; - double evs, sum, ev, up_ev, down_ev, solidAngle; - - evs = 90.0 / (hData -> mEvCount - 1); - sum = 0.0; - for (ei = hData -> mEvStart; ei < hData -> mEvCount; ei ++) { - // For each elevation, calculate the upper and lower limits of the - // patch band. - ev = -90.0 + (ei * 2.0 * evs); - if (ei < (hData -> mEvCount - 1)) - up_ev = (ev + evs) * M_PI / 180.0; - else - up_ev = M_PI / 2.0; - if (ei > 0) - down_ev = (ev - evs) * M_PI / 180.0; - else - down_ev = -M_PI / 2.0; - // Calculate the area of the patch band. - solidAngle = 2.0 * M_PI * (sin (up_ev) - sin (down_ev)); - // Each weight is the area of one patch. - weights [ei] = solidAngle / hData -> mAzCount [ei]; - // Sum the total surface area covered by the HRIRs. - sum += solidAngle; - } - // Normalize the weights given the total surface coverage. - for (ei = hData -> mEvStart; ei < hData -> mEvCount; ei ++) - weights [ei] /= sum; -} - -/* Calculate the diffuse-field average from the given magnitude responses of - * the HRIR set. Weighting can be applied to compensate for the varying - * surface area covered by each HRIR. The final average can then be limited - * by the specified magnitude range (in positive dB; 0.0 to skip). - */ -static void CalculateDiffuseFieldAverage (const HrirDataT * hData, const int weighted, const double limit, double * dfa) { - double * weights = NULL; - uint ei, ai, count, step, start, end, m, j, i; - double weight; - - weights = CreateArray (hData -> mEvCount); - if (weighted) { - // Use coverage weighting to calculate the average. - CalculateDfWeights (hData, weights); - } else { - // If coverage weighting is not used, the weights still need to be - // averaged by the number of HRIRs. - count = 0; - for (ei = hData -> mEvStart; ei < hData -> mEvCount; ei ++) - count += hData -> mAzCount [ei]; - for (ei = hData -> mEvStart; ei < hData -> mEvCount; ei ++) - weights [ei] = 1.0 / count; - } - ei = hData -> mEvStart; - ai = 0; - step = hData -> mIrSize; - start = hData -> mEvOffset [ei] * step; - end = hData -> mIrCount * step; - m = 1 + (hData -> mFftSize / 2); - for (i = 0; i < m; i ++) - dfa [i] = 0.0; - for (j = start; j < end; j += step) { - // Get the weight for this HRIR's contribution. - weight = weights [ei]; - // Add this HRIR's weighted power average to the total. - for (i = 0; i < m; i ++) - dfa [i] += weight * hData -> mHrirs [j + i] * hData -> mHrirs [j + i]; - // Determine the next weight to use. - ai ++; - if (ai >= hData -> mAzCount [ei]) { - ei ++; - ai = 0; - } - } - // Finish the average calculation and keep it from being too small. - for (i = 0; i < m; i ++) - dfa [i] = fmax (sqrt (dfa [i]), EPSILON); - // Apply a limit to the magnitude range of the diffuse-field average if - // desired. - if (limit > 0.0) - LimitMagnitudeResponse (hData -> mFftSize, limit, dfa, dfa); - DestroyArray (weights); -} - -// Perform diffuse-field equalization on the magnitude responses of the HRIR -// set using the given average response. -static void DiffuseFieldEqualize (const double * dfa, const HrirDataT * hData) { - uint step, start, end, m, j, i; - - step = hData -> mIrSize; - start = hData -> mEvOffset [hData -> mEvStart] * step; - end = hData -> mIrCount * step; - m = 1 + (hData -> mFftSize / 2); - for (j = start; j < end; j += step) { - for (i = 0; i < m; i ++) - hData -> mHrirs [j + i] /= dfa [i]; - } -} - -// Perform minimum-phase reconstruction using the magnitude responses of the -// HRIR set. -static void ReconstructHrirs (const HrirDataT * hData) { - double * re = NULL, * im = NULL; - uint step, start, end, n, j, i; - - step = hData -> mIrSize; - start = hData -> mEvOffset [hData -> mEvStart] * step; - end = hData -> mIrCount * step; - n = hData -> mFftSize; - re = CreateArray (n); - im = CreateArray (n); - for (j = start; j < end; j += step) { - MinimumPhase (n, & hData -> mHrirs [j], re, im); - FftInverse (n, re, im, re, im); - for (i = 0; i < hData -> mIrPoints; i ++) - hData -> mHrirs [j + i] = re [i]; - } - DestroyArray (im); - DestroyArray (re); -} - -// Resamples the HRIRs for use at the given sampling rate. -static void ResampleHrirs (const uint rate, HrirDataT * hData) { - ResamplerT rs; - uint n, step, start, end, j; - - ResamplerSetup (& rs, hData -> mIrRate, rate); - n = hData -> mIrPoints; - step = hData -> mIrSize; - start = hData -> mEvOffset [hData -> mEvStart] * step; - end = hData -> mIrCount * step; - for (j = start; j < end; j += step) - ResamplerRun (& rs, n, & hData -> mHrirs [j], n, & hData -> mHrirs [j]); - ResamplerClear (& rs); - hData -> mIrRate = rate; -} - -/* Given an elevation index and an azimuth, calculate the indices of the two - * HRIRs that bound the coordinate along with a factor for calculating the - * continous HRIR using interpolation. - */ -static void CalcAzIndices (const HrirDataT * hData, const uint ei, const double az, uint * j0, uint * j1, double * jf) { - double af; - uint ai; - - af = ((2.0 * M_PI) + az) * hData -> mAzCount [ei] / (2.0 * M_PI); - ai = ((uint) af) % hData -> mAzCount [ei]; - af -= floor (af); - (* j0) = hData -> mEvOffset [ei] + ai; - (* j1) = hData -> mEvOffset [ei] + ((ai + 1) % hData -> mAzCount [ei]); - (* jf) = af; -} - -// Synthesize any missing onset timings at the bottom elevations. This just -// blends between slightly exaggerated known onsets. Not an accurate model. -static void SynthesizeOnsets (HrirDataT * hData) { - uint oi, e, a, j0, j1; - double t, of, jf; - - oi = hData -> mEvStart; - t = 0.0; - for (a = 0; a < hData -> mAzCount [oi]; a ++) - t += hData -> mHrtds [hData -> mEvOffset [oi] + a]; - hData -> mHrtds [0] = 1.32e-4 + (t / hData -> mAzCount [oi]); - for (e = 1; e < hData -> mEvStart; e ++) { - of = ((double) e) / hData -> mEvStart; - for (a = 0; a < hData -> mAzCount [e]; a ++) { - CalcAzIndices (hData, oi, a * 2.0 * M_PI / hData -> mAzCount [e], & j0, & j1, & jf); - hData -> mHrtds [hData -> mEvOffset [e] + a] = Lerp (hData -> mHrtds [0], Lerp (hData -> mHrtds [j0], hData -> mHrtds [j1], jf), of); - } - } -} - -/* Attempt to synthesize any missing HRIRs at the bottom elevations. Right - * now this just blends the lowest elevation HRIRs together and applies some - * attenuation and high frequency damping. It is a simple, if inaccurate - * model. - */ -static void SynthesizeHrirs (HrirDataT * hData) { - uint oi, a, e, step, n, i, j; - double of, b; - uint j0, j1; - double jf; - double lp [4], s0, s1; - - if (hData -> mEvStart <= 0) - return; - step = hData -> mIrSize; - oi = hData -> mEvStart; - n = hData -> mIrPoints; - for (i = 0; i < n; i ++) - hData -> mHrirs [i] = 0.0; - for (a = 0; a < hData -> mAzCount [oi]; a ++) { - j = (hData -> mEvOffset [oi] + a) * step; - for (i = 0; i < n; i ++) - hData -> mHrirs [i] += hData -> mHrirs [j + i] / hData -> mAzCount [oi]; - } - for (e = 1; e < hData -> mEvStart; e ++) { - of = ((double) e) / hData -> mEvStart; - b = (1.0 - of) * (3.5e-6 * hData -> mIrRate); - for (a = 0; a < hData -> mAzCount [e]; a ++) { - j = (hData -> mEvOffset [e] + a) * step; - CalcAzIndices (hData, oi, a * 2.0 * M_PI / hData -> mAzCount [e], & j0, & j1, & jf); - j0 *= step; - j1 *= step; - lp [0] = 0.0; - lp [1] = 0.0; - lp [2] = 0.0; - lp [3] = 0.0; - for (i = 0; i < n; i ++) { - s0 = hData -> mHrirs [i]; - s1 = Lerp (hData -> mHrirs [j0 + i], hData -> mHrirs [j1 + i], jf); - s0 = Lerp (s0, s1, of); - lp [0] = Lerp (s0, lp [0], b); - lp [1] = Lerp (lp [0], lp [1], b); - lp [2] = Lerp (lp [1], lp [2], b); - lp [3] = Lerp (lp [2], lp [3], b); - hData -> mHrirs [j + i] = lp [3]; - } - } - } - b = 3.5e-6 * hData -> mIrRate; - lp [0] = 0.0; - lp [1] = 0.0; - lp [2] = 0.0; - lp [3] = 0.0; - for (i = 0; i < n; i ++) { - s0 = hData -> mHrirs [i]; - lp [0] = Lerp (s0, lp [0], b); - lp [1] = Lerp (lp [0], lp [1], b); - lp [2] = Lerp (lp [1], lp [2], b); - lp [3] = Lerp (lp [2], lp [3], b); - hData -> mHrirs [i] = lp [3]; - } - hData -> mEvStart = 0; -} - -// The following routines assume a full set of HRIRs for all elevations. - -// Normalize the HRIR set and slightly attenuate the result. -static void NormalizeHrirs (const HrirDataT * hData) { - uint step, end, n, j, i; - double maxLevel; - - step = hData -> mIrSize; - end = hData -> mIrCount * step; - n = hData -> mIrPoints; - maxLevel = 0.0; - for (j = 0; j < end; j += step) { - for (i = 0; i < n; i ++) - maxLevel = fmax (fabs (hData -> mHrirs [j + i]), maxLevel); - } - maxLevel = 1.01 * maxLevel; - for (j = 0; j < end; j += step) { - for (i = 0; i < n; i ++) - hData -> mHrirs [j + i] /= maxLevel; - } -} - -// Calculate the left-ear time delay using a spherical head model. -static double CalcLTD (const double ev, const double az, const double rad, const double dist) { - double azp, dlp, l, al; - - azp = asin (cos (ev) * sin (az)); - dlp = sqrt ((dist * dist) + (rad * rad) + (2.0 * dist * rad * sin (azp))); - l = sqrt ((dist * dist) - (rad * rad)); - al = (0.5 * M_PI) + azp; - if (dlp > l) - dlp = l + (rad * (al - acos (rad / dist))); - return (dlp / 343.3); -} - -// Calculate the effective head-related time delays for each minimum-phase -// HRIR. -static void CalculateHrtds (const HeadModelT model, const double radius, HrirDataT * hData) { - double minHrtd, maxHrtd; - uint e, a, j; - double t; - - minHrtd = 1000.0; - maxHrtd = -1000.0; - for (e = 0; e < hData -> mEvCount; e ++) { - for (a = 0; a < hData -> mAzCount [e]; a ++) { - j = hData -> mEvOffset [e] + a; - if (model == HM_DATASET) { - t = hData -> mHrtds [j] * radius / hData -> mRadius; - } else { - t = CalcLTD ((-90.0 + (e * 180.0 / (hData -> mEvCount - 1))) * M_PI / 180.0, - (a * 360.0 / hData -> mAzCount [e]) * M_PI / 180.0, - radius, hData -> mDistance); - } - hData -> mHrtds [j] = t; - maxHrtd = fmax (t, maxHrtd); - minHrtd = fmin (t, minHrtd); - } - } - maxHrtd -= minHrtd; - for (j = 0; j < hData -> mIrCount; j ++) - hData -> mHrtds [j] -= minHrtd; - hData -> mMaxHrtd = maxHrtd; -} - -// Store the OpenAL Soft HRTF data set. -static int StoreMhr (const HrirDataT * hData, const char * filename) { - FILE * fp = NULL; - uint e, step, end, n, j, i; - int hpHist, v; - - if ((fp = fopen (filename, "wb")) == NULL) { - fprintf (stderr, "Error: Could not open MHR file '%s'.\n", filename); - return (0); - } - if (! WriteAscii (MHR_FORMAT, fp, filename)) - return (0); - if (! WriteBin4 (BO_LITTLE, 4, (uint32) hData -> mIrRate, fp, filename)) - return (0); - if (! WriteBin4 (BO_LITTLE, 1, (uint32) hData -> mIrPoints, fp, filename)) - return (0); - if (! WriteBin4 (BO_LITTLE, 1, (uint32) hData -> mEvCount, fp, filename)) - return (0); - for (e = 0; e < hData -> mEvCount; e ++) { - if (! WriteBin4 (BO_LITTLE, 1, (uint32) hData -> mAzCount [e], fp, filename)) - return (0); - } - step = hData -> mIrSize; - end = hData -> mIrCount * step; - n = hData -> mIrPoints; - srand (0x31DF840C); - for (j = 0; j < end; j += step) { - hpHist = 0; - for (i = 0; i < n; i ++) { - v = HpTpdfDither (32767.0 * hData -> mHrirs [j + i], & hpHist); - if (! WriteBin4 (BO_LITTLE, 2, (uint32) v, fp, filename)) - return (0); - } - } - for (j = 0; j < hData -> mIrCount; j ++) { - v = (int) fmin (round (hData -> mIrRate * hData -> mHrtds [j]), MAX_HRTD); - if (! WriteBin4 (BO_LITTLE, 1, (uint32) v, fp, filename)) - return (0); - } - fclose (fp); - 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]; - uint line, col; - int intVal; - uint points; - double fpVal; - int hasRate = 0, hasPoints = 0, hasAzimuths = 0; - int hasRadius = 0, hasDistance = 0; - - while (! (hasRate && hasPoints && hasAzimuths && hasRadius && hasDistance)) { - TrIndication (tr, & line, & col); - if (! TrReadIdent (tr, MAX_IDENT_LEN, ident)) - return (0); - if (strcasecmp (ident, "rate") == 0) { - if (hasRate) { - TrErrorAt (tr, line, col, "Redefinition of 'rate'.\n"); - return (0); - } - if (! TrReadOperator (tr, "=")) - return (0); - if (! TrReadInt (tr, MIN_RATE, MAX_RATE, & intVal)) - return (0); - hData -> mIrRate = (uint) intVal; - hasRate = 1; - } else if (strcasecmp (ident, "points") == 0) { - if (hasPoints) { - TrErrorAt (tr, line, col, "Redefinition of 'points'.\n"); - return (0); - } - if (! TrReadOperator (tr, "=")) - return (0); - TrIndication (tr, & line, & col); - if (! TrReadInt (tr, MIN_POINTS, MAX_POINTS, & intVal)) - return (0); - points = (uint) intVal; - if ((fftSize > 0) && (points > fftSize)) { - TrErrorAt (tr, line, col, "Value exceeds the overridden FFT size.\n"); - return (0); - } - if (points < truncSize) { - TrErrorAt (tr, line, col, "Value is below the truncation size.\n"); - return (0); - } - hData -> mIrPoints = points; - hData -> mFftSize = fftSize; - if (fftSize <= 0) { - points = 1; - while (points < (4 * hData -> mIrPoints)) - points <<= 1; - hData -> mFftSize = points; - hData -> mIrSize = 1 + (points / 2); - } else { - hData -> mFftSize = fftSize; - hData -> mIrSize = 1 + (fftSize / 2); - if (points > hData -> mIrSize) - hData -> mIrSize = points; - } - hasPoints = 1; - } else if (strcasecmp (ident, "azimuths") == 0) { - if (hasAzimuths) { - TrErrorAt (tr, line, col, "Redefinition of 'azimuths'.\n"); - return (0); - } - if (! TrReadOperator (tr, "=")) - return (0); - hData -> mIrCount = 0; - hData -> mEvCount = 0; - hData -> mEvOffset [0] = 0; - for (;;) { - if (! TrReadInt (tr, MIN_AZ_COUNT, MAX_AZ_COUNT, & intVal)) - return (0); - hData -> mAzCount [hData -> mEvCount] = (uint) intVal; - hData -> mIrCount += (uint) intVal; - hData -> mEvCount ++; - if (! TrIsOperator (tr, ",")) - break; - if (hData -> mEvCount >= MAX_EV_COUNT) { - TrError (tr, "Exceeded the maximum of %d elevations.\n", MAX_EV_COUNT); - return (0); - } - hData -> mEvOffset [hData -> mEvCount] = hData -> mEvOffset [hData -> mEvCount - 1] + ((uint) intVal); - TrReadOperator (tr, ","); - } - if (hData -> mEvCount < MIN_EV_COUNT) { - TrErrorAt (tr, line, col, "Did not reach the minimum of %d azimuth counts.\n", MIN_EV_COUNT); - return (0); - } - hasAzimuths = 1; - } else if (strcasecmp (ident, "radius") == 0) { - if (hasRadius) { - TrErrorAt (tr, line, col, "Redefinition of 'radius'.\n"); - return (0); - } - if (! TrReadOperator (tr, "=")) - return (0); - if (! TrReadFloat (tr, MIN_RADIUS, MAX_RADIUS, & fpVal)) - return (0); - hData -> mRadius = fpVal; - hasRadius = 1; - } else if (strcasecmp (ident, "distance") == 0) { - if (hasDistance) { - TrErrorAt (tr, line, col, "Redefinition of 'distance'.\n"); - return (0); - } - if (! TrReadOperator (tr, "=")) - return (0); - if (! TrReadFloat (tr, MIN_DISTANCE, MAX_DISTANCE, & fpVal)) - return (0); - hData -> mDistance = fpVal; - hasDistance = 1; - } else { - TrErrorAt (tr, line, col, "Expected a metric name.\n"); - return (0); - } - TrSkipWhitespace (tr); - } - return (1); -} - -// Parse an index pair from the data set definition. -static int ReadIndexPair (TokenReaderT * tr, const HrirDataT * hData, uint * ei, uint * ai) { - int intVal; - - if (! TrReadInt (tr, 0, (int) hData -> mEvCount, & intVal)) - return (0); - (* ei) = (uint) intVal; - if (! TrReadOperator (tr, ",")) - return (0); - if (! TrReadInt (tr, 0, (int) hData -> mAzCount [(* ei)], & intVal)) - return (0); - (* ai) = (uint) intVal; - return (1); -} - -// Match the source format from a given identifier. -static SourceFormatT MatchSourceFormat (const char * ident) { - if (strcasecmp (ident, "wave") == 0) - return (SF_WAVE); - else if (strcasecmp (ident, "bin_le") == 0) - return (SF_BIN_LE); - else if (strcasecmp (ident, "bin_be") == 0) - return (SF_BIN_BE); - else if (strcasecmp (ident, "ascii") == 0) - return (SF_ASCII); - return (SF_NONE); -} - -// Match the source element type from a given identifier. -static ElementTypeT MatchElementType (const char * ident) { - if (strcasecmp (ident, "int") == 0) - return (ET_INT); - else if (strcasecmp (ident, "fp") == 0) - return (ET_FP); - return (ET_NONE); -} - -// Parse and validate a source reference from the data set definition. -static int ReadSourceRef (TokenReaderT * tr, SourceRefT * src) { - uint line, col; - char ident [MAX_IDENT_LEN + 1]; - int intVal; - - TrIndication (tr, & line, & col); - if (! TrReadIdent (tr, MAX_IDENT_LEN, ident)) - return (0); - src -> mFormat = MatchSourceFormat (ident); - if (src -> mFormat == SF_NONE) { - TrErrorAt (tr, line, col, "Expected a source format.\n"); - return (0); - } - if (! TrReadOperator (tr, "(")) - return (0); - if (src -> mFormat == SF_WAVE) { - if (! TrReadInt (tr, 0, MAX_WAVE_CHANNELS, & intVal)) - return (0); - src -> mType = ET_NONE; - src -> mSize = 0; - src -> mBits = 0; - src -> mChannel = (uint) intVal; - src -> mSkip = 0; - } else { - TrIndication (tr, & line, & col); - if (! TrReadIdent (tr, MAX_IDENT_LEN, ident)) - return (0); - src -> mType = MatchElementType (ident); - if (src -> mType == ET_NONE) { - TrErrorAt (tr, line, col, "Expected a source element type.\n"); - return (0); - } - if ((src -> mFormat == SF_BIN_LE) || (src -> mFormat == SF_BIN_BE)) { - if (! TrReadOperator (tr, ",")) - return (0); - if (src -> mType == ET_INT) { - if (! TrReadInt (tr, MIN_BIN_SIZE, MAX_BIN_SIZE, & intVal)) - return (0); - src -> mSize = (uint) intVal; - if (TrIsOperator (tr, ",")) { - TrReadOperator (tr, ","); - TrIndication (tr, & line, & col); - if (! TrReadInt (tr, -2147483647 - 1, 2147483647, & intVal)) - return (0); - if ((abs (intVal) < MIN_BIN_BITS) || (((uint) abs (intVal)) > (8 * src -> mSize))) { - TrErrorAt (tr, line, col, "Expected a value of (+/-) %d to %d.\n", MIN_BIN_BITS, 8 * src -> mSize); - return (0); - } - src -> mBits = intVal; - } else { - src -> mBits = (int) (8 * src -> mSize); - } - } else { - TrIndication (tr, & line, & col); - if (! TrReadInt (tr, -2147483647 - 1, 2147483647, & intVal)) - return (0); - if ((intVal != 4) && (intVal != 8)) { - TrErrorAt (tr, line, col, "Expected a value of 4 or 8.\n"); - return (0); - } - src -> mSize = (uint) intVal; - src -> mBits = 0; - } - } else if ((src -> mFormat == SF_ASCII) && (src -> mType == ET_INT)) { - if (! TrReadOperator (tr, ",")) - return (0); - if (! TrReadInt (tr, MIN_ASCII_BITS, MAX_ASCII_BITS, & intVal)) - return (0); - src -> mSize = 0; - src -> mBits = intVal; - } else { - src -> mSize = 0; - src -> mBits = 0; - } - if (TrIsOperator (tr, ";")) { - TrReadOperator (tr, ";"); - if (! TrReadInt (tr, 0, 0x7FFFFFFF, & intVal)) - return (0); - src -> mSkip = (uint) intVal; - } else { - src -> mSkip = 0; - } - } - if (! TrReadOperator (tr, ")")) - return (0); - if (TrIsOperator (tr, "@")) { - TrReadOperator (tr, "@"); - if (! TrReadInt (tr, 0, 0x7FFFFFFF, & intVal)) - return (0); - src -> mOffset = (uint) intVal; - } else { - src -> mOffset = 0; - } - if (! TrReadOperator (tr, ":")) - return (0); - if (! TrReadString (tr, MAX_PATH_LEN, src -> mPath)) - return (0); - return (1); -} - -// Process the list of sources in the data set definition. -static int ProcessSources (const HeadModelT model, TokenReaderT * tr, HrirDataT * hData) { - uint * setCount = NULL, * setFlag = NULL; - double * hrir = NULL; - uint line, col, ei, ai; - SourceRefT src; - double factor; - - setCount = (uint *) calloc (hData -> mEvCount, sizeof (uint)); - setFlag = (uint *) calloc (hData -> mIrCount, sizeof (uint)); - hrir = CreateArray (hData -> mIrPoints); - while (TrIsOperator (tr, "[")) { - TrIndication (tr, & line, & col); - TrReadOperator (tr, "["); - if (ReadIndexPair (tr, hData, & ei, & ai)) { - if (TrReadOperator (tr, "]")) { - if (! setFlag [hData -> mEvOffset [ei] + ai]) { - if (TrReadOperator (tr, "=")) { - factor = 1.0; - for (;;) { - if (ReadSourceRef (tr, & src)) { - if (LoadSource (& src, hData -> mIrRate, hData -> mIrPoints, hrir)) { - if (model == HM_DATASET) - AverageHrirOnset (hrir, 1.0 / factor, ei, ai, hData); - AverageHrirMagnitude (hrir, 1.0 / factor, ei, ai, hData); - factor += 1.0; - if (! TrIsOperator (tr, "+")) - break; - TrReadOperator (tr, "+"); - continue; - } - } - DestroyArray (hrir); - free (setFlag); - free (setCount); - return (0); - } - setFlag [hData -> mEvOffset [ei] + ai] = 1; - setCount [ei] ++; - continue; - } - } else { - TrErrorAt (tr, line, col, "Redefinition of source.\n"); - } - } - } - DestroyArray (hrir); - free (setFlag); - free (setCount); - return (0); - } - ei = 0; - while ((ei < hData -> mEvCount) && (setCount [ei] < 1)) - ei ++; - if (ei < hData -> mEvCount) { - hData -> mEvStart = ei; - while ((ei < hData -> mEvCount) && (setCount [ei] == hData -> mAzCount [ei])) - ei ++; - if (ei >= hData -> mEvCount) { - if (! TrLoad (tr)) { - DestroyArray (hrir); - free (setFlag); - free (setCount); - return (1); - } else { - TrError (tr, "Errant data at end of source list.\n"); - } - } else { - TrError (tr, "Missing sources for elevation index %d.\n", ei); - } - } else { - TrError (tr, "Missing source references.\n"); - } - DestroyArray (hrir); - free (setFlag); - free (setCount); - return (0); -} - -/* Parse the data set definition and process the source data, storing the - * resulting data set as desired. If the input name is NULL it will read - * from standard input. - */ -static int ProcessDefinition (const char * inName, const uint outRate, const uint fftSize, const int equalize, const int surface, const double limit, const uint truncSize, const HeadModelT model, const double radius, const OutputFormatT outFormat, const char * outName) { - FILE * fp = NULL; - TokenReaderT tr; - HrirDataT hData; - double * dfa = NULL; - char rateStr [8 + 1], expName [MAX_PATH_LEN]; - - hData . mIrRate = 0; - hData . mIrPoints = 0; - hData . mFftSize = 0; - hData . mIrSize = 0; - hData . mIrCount = 0; - hData . mEvCount = 0; - hData . mRadius = 0; - hData . mDistance = 0; - fprintf (stdout, "Reading HRIR definition...\n"); - if (inName != NULL) { - fp = fopen (inName, "r"); - if (fp == NULL) { - fprintf (stderr, "Error: Could not open definition file '%s'\n", inName); - return (0); - } - TrSetup (fp, inName, & tr); - } else { - fp = stdin; - TrSetup (fp, "", & tr); - } - if (! ProcessMetrics (& tr, fftSize, truncSize, & hData)) { - if (inName != NULL) - fclose (fp); - return (0); - } - hData . mHrirs = CreateArray (hData . mIrCount * hData . mIrSize); - hData . mHrtds = CreateArray (hData . mIrCount); - if (! ProcessSources (model, & tr, & hData)) { - DestroyArray (hData . mHrtds); - DestroyArray (hData . mHrirs); - if (inName != NULL) - fclose (fp); - return (0); - } - if (inName != NULL) - fclose (fp); - if (equalize) { - dfa = CreateArray (1 + (hData . mFftSize / 2)); - fprintf (stdout, "Calculating diffuse-field average...\n"); - CalculateDiffuseFieldAverage (& hData, surface, limit, dfa); - fprintf (stdout, "Performing diffuse-field equalization...\n"); - DiffuseFieldEqualize (dfa, & hData); - DestroyArray (dfa); - } - fprintf (stdout, "Performing minimum phase reconstruction...\n"); - ReconstructHrirs (& hData); - if ((outRate != 0) && (outRate != hData . mIrRate)) { - fprintf (stdout, "Resampling HRIRs...\n"); - ResampleHrirs (outRate, & hData); - } - fprintf (stdout, "Truncating minimum-phase HRIRs...\n"); - hData . mIrPoints = truncSize; - fprintf (stdout, "Synthesizing missing elevations...\n"); - if (model == HM_DATASET) - SynthesizeOnsets (& hData); - SynthesizeHrirs (& hData); - fprintf (stdout, "Normalizing final HRIRs...\n"); - NormalizeHrirs (& hData); - fprintf (stdout, "Calculating impulse delays...\n"); - CalculateHrtds (model, (radius > DEFAULT_CUSTOM_RADIUS) ? radius : hData . mRadius, & hData); - snprintf (rateStr, 8, "%u", hData . mIrRate); - StrSubst (outName, "%r", rateStr, MAX_PATH_LEN, expName); - switch (outFormat) { - case OF_MHR : - fprintf (stdout, "Creating MHR data set file...\n"); - 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; - } - DestroyArray (hData . mHrtds); - DestroyArray (hData . mHrirs); - return (1); -} - -// Standard command line dispatch. -int main (const int argc, const char * argv []) { - const char * inName = NULL, * outName = NULL; - OutputFormatT outFormat; - int argi; - uint outRate, fftSize; - int equalize, surface; - double limit; - uint truncSize; - HeadModelT model; - double radius; - char * end = NULL; - - if (argc < 2) { - fprintf (stderr, "Error: No command specified. See '%s -h' for help.\n", argv [0]); - return (-1); - } - if ((strcmp (argv [1], "--help") == 0) || (strcmp (argv [1], "-h") == 0)) { - fprintf (stdout, "HRTF Processing and Composition Utility\n\n"); - fprintf (stdout, "Usage: %s [

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 Gn*JXIKpHjx literal 0 HcmV?d00001 diff --git a/love/src/jni/openal-soft-1.17.0/include/AL/al.h b/love/src/jni/openal-soft-1.18.2/include/AL/al.h similarity index 100% rename from love/src/jni/openal-soft-1.17.0/include/AL/al.h rename to love/src/jni/openal-soft-1.18.2/include/AL/al.h diff --git a/love/src/jni/openal-soft-1.17.0/include/AL/alc.h b/love/src/jni/openal-soft-1.18.2/include/AL/alc.h similarity index 100% rename from love/src/jni/openal-soft-1.17.0/include/AL/alc.h rename to love/src/jni/openal-soft-1.18.2/include/AL/alc.h diff --git a/love/src/jni/openal-soft-1.17.0/include/AL/alext.h b/love/src/jni/openal-soft-1.18.2/include/AL/alext.h similarity index 85% rename from love/src/jni/openal-soft-1.17.0/include/AL/alext.h rename to love/src/jni/openal-soft-1.18.2/include/AL/alext.h index 7d2a9527..4b9a1553 100644 --- a/love/src/jni/openal-soft-1.17.0/include/AL/alext.h +++ b/love/src/jni/openal-soft-1.18.2/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,72 @@ 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 + +#ifndef AL_SOFT_gain_clamp_ex +#define AL_SOFT_gain_clamp_ex 1 +#define AL_GAIN_LIMIT_SOFT 0x200E +#endif + +#ifndef AL_SOFT_source_resampler +#define AL_SOFT_source_resampler +#define AL_NUM_RESAMPLERS_SOFT 0x1210 +#define AL_DEFAULT_RESAMPLER_SOFT 0x1211 +#define AL_SOURCE_RESAMPLER_SOFT 0x1212 +#define AL_RESAMPLER_NAME_SOFT 0x1213 +typedef const ALchar* (AL_APIENTRY*LPALGETSTRINGISOFT)(ALenum pname, ALsizei index); +#ifdef AL_ALEXT_PROTOTYPES +AL_API const ALchar* AL_APIENTRY alGetStringiSOFT(ALenum pname, ALsizei index); +#endif +#endif + +#ifndef AL_SOFT_source_spatialize +#define AL_SOFT_source_spatialize +#define AL_SOURCE_SPATIALIZE_SOFT 0x1214 +#define AL_AUTO_SOFT 0x0002 +#endif + +#ifndef ALC_SOFT_output_limiter +#define ALC_SOFT_output_limiter +#define ALC_OUTPUT_LIMITER_SOFT 0x199A +#endif + #ifdef __cplusplus } #endif diff --git a/love/src/jni/openal-soft-1.17.0/include/AL/efx-creative.h b/love/src/jni/openal-soft-1.18.2/include/AL/efx-creative.h similarity index 100% rename from love/src/jni/openal-soft-1.17.0/include/AL/efx-creative.h rename to love/src/jni/openal-soft-1.18.2/include/AL/efx-creative.h diff --git a/love/src/jni/openal-soft-1.17.0/include/AL/efx-presets.h b/love/src/jni/openal-soft-1.18.2/include/AL/efx-presets.h similarity index 99% rename from love/src/jni/openal-soft-1.17.0/include/AL/efx-presets.h rename to love/src/jni/openal-soft-1.18.2/include/AL/efx-presets.h index 86dcbda2..8539fd51 100644 --- a/love/src/jni/openal-soft-1.17.0/include/AL/efx-presets.h +++ b/love/src/jni/openal-soft-1.18.2/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/love/src/jni/openal-soft-1.17.0/include/AL/efx.h b/love/src/jni/openal-soft-1.18.2/include/AL/efx.h similarity index 100% rename from love/src/jni/openal-soft-1.17.0/include/AL/efx.h rename to love/src/jni/openal-soft-1.18.2/include/AL/efx.h diff --git a/love/src/jni/openal-soft-1.18.2/native-tools/CMakeLists.txt b/love/src/jni/openal-soft-1.18.2/native-tools/CMakeLists.txt new file mode 100644 index 00000000..4713dc56 --- /dev/null +++ b/love/src/jni/openal-soft-1.18.2/native-tools/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.0.2) +project(native-tools) +add_executable(bin2h bin2h.c) +# Enforce no dressing for executable names, so the main script can find it +set_target_properties(bin2h PROPERTIES OUTPUT_NAME bin2h) +# Avoid configuration-dependent subdirectories while building with Visual Studio +set_target_properties(bin2h PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}") +set_target_properties(bin2h PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}") diff --git a/love/src/jni/openal-soft-1.18.2/native-tools/bin2h.c b/love/src/jni/openal-soft-1.18.2/native-tools/bin2h.c new file mode 100644 index 00000000..92f2b8a5 --- /dev/null +++ b/love/src/jni/openal-soft-1.18.2/native-tools/bin2h.c @@ -0,0 +1,100 @@ + +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#endif + +#include +#include +#include +#include + +int main (int argc, char *argv[]) +{ + char* input_name; + FILE* input_file; + + char* output_name; + FILE* output_file; + + char* variable_name; + + if (4 != argc) + { + puts("Usage: bin2h [input] [output] [variable]"); + return EXIT_FAILURE; + } + + input_name = argv[1]; + output_name = argv[2]; + variable_name = argv[3]; + + input_file = fopen(input_name, "rb"); + + if (NULL == input_file) + { + printf("Could not open input file '%s': %s\n", input_name, strerror(errno)); + return EXIT_FAILURE; + } + + output_file = fopen(output_name, "w"); + + if (NULL == output_file) + { + printf("Could not open output file '%s': %s\n", output_name, strerror(errno)); + return EXIT_FAILURE; + } + + if (fprintf(output_file, "static const unsigned char %s[] = {", variable_name) < 0) + { + printf("Could not write to output file '%s': %s\n", output_name, strerror(ferror(output_file))); + return EXIT_FAILURE; + } + + while (0 == feof(input_file)) + { + unsigned char buffer[4096]; + size_t i, count = fread(buffer, 1, sizeof(buffer), input_file); + + if (sizeof(buffer) != count) + { + if (0 == feof(input_file) || 0 != ferror(input_file)) + { + printf("Could not read from input file '%s': %s\n", input_name, strerror(ferror(input_file))); + return EXIT_FAILURE; + } + } + + for (i = 0; i < count; ++i) + { + if ((i & 15) == 0) + { + if (fprintf(output_file, "\n ") < 0) + { + printf("Could not write to output file '%s': %s\n", output_name, strerror(ferror(output_file))); + return EXIT_FAILURE; + } + } + + if (fprintf(output_file, "0x%2.2x, ", buffer[i]) < 0) + { + printf("Could not write to output file '%s': %s\n", output_name, strerror(ferror(output_file))); + return EXIT_FAILURE; + } + + } + } + + if (fprintf(output_file, "\n};\n") < 0) + { + printf("Could not write to output file '%s': %s\n", output_name, strerror(ferror(output_file))); + return EXIT_FAILURE; + } + + if (fclose(output_file) < 0) + { + printf("Could not close output file '%s': %s\n", output_name, strerror(ferror(output_file))); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/love/src/jni/openal-soft-1.17.0/openal.pc.in b/love/src/jni/openal-soft-1.18.2/openal.pc.in similarity index 100% rename from love/src/jni/openal-soft-1.17.0/openal.pc.in rename to love/src/jni/openal-soft-1.18.2/openal.pc.in diff --git a/love/src/jni/openal-soft-1.18.2/presets/3D7.1.ambdec b/love/src/jni/openal-soft-1.18.2/presets/3D7.1.ambdec new file mode 100644 index 00000000..42b6a0bb --- /dev/null +++ b/love/src/jni/openal-soft-1.18.2/presets/3D7.1.ambdec @@ -0,0 +1,43 @@ +# AmbDec configuration +# Written by Ambisonic Decoder Toolbox, version 8.0 + +/description 3D7_2h1v_allrad_5200_rE_max_1_band + +/version 3 + +/dec/chan_mask 1bf +/dec/freq_bands 1 +/dec/speakers 7 +/dec/coeff_scale fuma + +/opt/input_scale fuma +/opt/nfeff_comp output +/opt/delay_comp on +/opt/level_comp on +/opt/xover_freq 400.000000 +/opt/xover_ratio 0.000000 + +/speakers/{ +# id dist azim elev conn +#----------------------------------------------------------------------- +add_spkr LF 1.500000 51.000000 24.000000 +add_spkr RF 1.500000 -51.000000 24.000000 +add_spkr CE 1.500000 0.000000 0.000000 +add_spkr LB 1.500000 180.000000 55.000000 +add_spkr RB 1.500000 0.000000 -55.000000 +add_spkr LS 1.500000 129.000000 -24.000000 +add_spkr RS 1.500000 -129.000000 -24.000000 +/} + +/matrix/{ +order_gain 1.000000 0.774597 0.400000 0.000000 +add_row 0.325031 0.357638 0.206500 0.234037 0.202440 0.135692 0.116927 -0.098768 +add_row 0.325036 -0.357619 0.206537 0.234033 -0.202427 -0.135680 0.116934 -0.098768 +add_row 0.080073 -0.000010 -0.000296 0.155843 -0.000016 -0.000011 -0.000623 0.163306 +add_row 0.353556 0.000002 0.408453 -0.288377 -0.000004 -0.000003 -0.221039 0.077297 +add_row 0.325297 0.000008 -0.414018 0.232789 0.000004 0.000003 -0.232940 0.018311 +add_row 0.353558 0.352704 -0.203542 -0.290124 -0.191868 -0.134582 0.110616 -0.038294 +add_row 0.353556 -0.352691 -0.203576 -0.290115 0.191871 0.134585 0.110612 -0.038293 +/} + +/end diff --git a/love/src/jni/openal-soft-1.18.2/presets/hexagon.ambdec b/love/src/jni/openal-soft-1.18.2/presets/hexagon.ambdec new file mode 100644 index 00000000..d45f2732 --- /dev/null +++ b/love/src/jni/openal-soft-1.18.2/presets/hexagon.ambdec @@ -0,0 +1,51 @@ +# AmbDec configuration +# Written by Ambisonic Decoder Toolbox, version 8.0 + +/description Hexagon_2h0p_pinv_match_rV_max_rE_2_band + +/version 3 + +/dec/chan_mask 11b +/dec/freq_bands 2 +/dec/speakers 6 +/dec/coeff_scale fuma + +/opt/input_scale fuma +/opt/nfeff_comp input +/opt/delay_comp on +/opt/level_comp on +/opt/xover_freq 400.000000 +/opt/xover_ratio 0.000000 + +/speakers/{ +# id dist azim elev conn +#----------------------------------------------------------------------- +add_spkr LF 1.000000 30.000000 0.000000 +add_spkr RF 1.000000 -30.000000 0.000000 +add_spkr RS 1.000000 -90.000000 0.000000 +add_spkr RB 1.000000 -150.000000 0.000000 +add_spkr LB 1.000000 150.000000 0.000000 +add_spkr LS 1.000000 90.000000 0.000000 +/} + +/lfmatrix/{ +order_gain 1.000000 1.000000 1.000000 0.000000 +add_row 0.235702 0.166667 0.288675 0.288675 0.166667 +add_row 0.235702 -0.166667 0.288675 -0.288675 0.166667 +add_row 0.235702 -0.333333 0.000000 -0.000000 -0.333333 +add_row 0.235702 -0.166667 -0.288675 0.288675 0.166667 +add_row 0.235702 0.166667 -0.288675 -0.288675 0.166667 +add_row 0.235702 0.333333 0.000000 -0.000000 -0.333333 +/} + +/hfmatrix/{ +order_gain 1.414214 1.224745 0.707107 0.000000 +add_row 0.235702 0.166667 0.288675 0.288675 0.166667 +add_row 0.235702 -0.166667 0.288675 -0.288675 0.166667 +add_row 0.235702 -0.333333 0.000000 -0.000000 -0.333333 +add_row 0.235702 -0.166667 -0.288675 0.288675 0.166667 +add_row 0.235702 0.166667 -0.288675 -0.288675 0.166667 +add_row 0.235702 0.333333 0.000000 -0.000000 -0.333333 +/} + +/end diff --git a/love/src/jni/openal-soft-1.18.2/presets/itu5.1-nocenter.ambdec b/love/src/jni/openal-soft-1.18.2/presets/itu5.1-nocenter.ambdec new file mode 100644 index 00000000..23839d0e --- /dev/null +++ b/love/src/jni/openal-soft-1.18.2/presets/itu5.1-nocenter.ambdec @@ -0,0 +1,46 @@ +# AmbDec configuration +# Written by Ambisonic Decoder Toolbox, version 8.0 + +# input channel order: WYXVU + +/description itu50-noCenter_2h0p_allrad_5200_rE_max_1_band + +# Although unused in this configuration, the front-center is declared here so +# that an appropriate distance may be set (for proper delaying or attenuating +# of dialog and such which feed it directly). It otherwise does not contribute +# to positional sound output. + +/version 3 + +/dec/chan_mask 11b +/dec/freq_bands 1 +/dec/speakers 5 +/dec/coeff_scale fuma + +/opt/input_scale fuma +/opt/nfeff_comp input +/opt/delay_comp on +/opt/level_comp on +/opt/xover_freq 400.000000 +/opt/xover_ratio 0.000000 + +/speakers/{ +# id dist azim elev conn +#----------------------------------------------------------------------- +add_spkr LS 1.000000 110.000000 0.000000 system:playback_3 +add_spkr LF 1.000000 30.000000 0.000000 system:playback_1 +add_spkr CE 1.000000 0.000000 0.000000 system:playback_5 +add_spkr RF 1.000000 -30.000000 0.000000 system:playback_2 +add_spkr RS 1.000000 -110.000000 0.000000 system:playback_4 +/} + +/matrix/{ +order_gain 1.00000000e+00 8.66025404e-01 5.00000000e-01 0.000000 +add_row 4.70934222e-01 3.78169605e-01 -4.00084750e-01 -8.22264454e-02 -4.43765986e-02 +add_row 2.66639870e-01 2.55418584e-01 3.32591390e-01 2.82949132e-01 8.16816772e-02 +add_row 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00 +add_row 2.66634915e-01 -2.55421639e-01 3.32586482e-01 -2.82947688e-01 8.16782588e-02 +add_row 4.70935891e-01 -3.78173080e-01 -4.00080588e-01 8.22279700e-02 -4.43716394e-02 +/} + +/end diff --git a/love/src/jni/openal-soft-1.18.2/presets/itu5.1.ambdec b/love/src/jni/openal-soft-1.18.2/presets/itu5.1.ambdec new file mode 100644 index 00000000..74386034 --- /dev/null +++ b/love/src/jni/openal-soft-1.18.2/presets/itu5.1.ambdec @@ -0,0 +1,48 @@ +# AmbDec configuration +# Written by Ambisonic Decoder Toolbox, version 8.0 + +/description itu50_2h0p_allrad_5200_rE_max_1_band + +/version 3 + +/dec/chan_mask 11b +/dec/freq_bands 2 +/dec/speakers 5 +/dec/coeff_scale fuma + +/opt/input_scale fuma +/opt/nfeff_comp output +/opt/delay_comp on +/opt/level_comp on +/opt/xover_freq 400.000000 +/opt/xover_ratio 3.000000 + +/speakers/{ +# id dist azim elev conn +#----------------------------------------------------------------------- +add_spkr LS 1.000000 110.000000 0.000000 +add_spkr LF 1.000000 30.000000 0.000000 +add_spkr CE 1.000000 0.000000 0.000000 +add_spkr RF 1.000000 -30.000000 0.000000 +add_spkr RS 1.000000 -110.000000 0.000000 +/} + +/lfmatrix/{ +order_gain 1.000000 1.000000 1.000000 0.000000 +add_row 0.420330 0.330200 -0.312250 0.019350 -0.027010 +add_row 0.197700 0.288820 0.287820 0.049110 0.007420 +add_row 0.058030 0.000000 0.205970 0.000000 0.050790 +add_row 0.197700 -0.288820 0.287820 -0.049110 0.007420 +add_row 0.420330 -0.330200 -0.312250 -0.019350 -0.027010 +/} + +/hfmatrix/{ +order_gain 1.000000 0.866025 0.500000 0.000000 +add_row 0.470934 0.378170 -0.400085 -0.082226 -0.044377 +add_row 0.208954 0.257988 0.230383 0.288520 -0.025085 +add_row 0.109403 -0.000002 0.194278 -0.000003 0.200863 +add_row 0.208950 -0.257989 0.230379 -0.288516 -0.025088 +add_row 0.470936 -0.378173 -0.400081 0.082228 -0.044372 +/} + +/end diff --git a/love/src/jni/openal-soft-1.18.2/presets/presets.txt b/love/src/jni/openal-soft-1.18.2/presets/presets.txt new file mode 100644 index 00000000..94968720 --- /dev/null +++ b/love/src/jni/openal-soft-1.18.2/presets/presets.txt @@ -0,0 +1,42 @@ +Ambisonic decoder configuration presets are provided here for common surround +sound speaker layouts. The presets are prepared to work with OpenAL Soft's high +quality decoder. By default all of the speaker distances within a preset are +set to the same value, which results in no effect from distance compensation. +If this doesn't match your physical speaker setup, it may be worth copying the +preset and modifying the distance values to match (note that modifying the +azimuth and elevation values in the presets will not have any effect; the +specified angles do not change the decoder behavior). + +Details of the individual presets are as follows. + +square.ambdec +Specifies a basic square speaker setup for Quadrophonic output, with identical +width and depth. Front speakers are placed at +45 and -45 degrees, and back +speakers are placed at +135 and -135 degrees. + +rectangle.ambdec +Specifies a narrower speaker setup for Quadrophonic output, with a little less +width but a little more depth over a basic square setup. Front speakers are +placed at +30 and -30 degrees, providing a bit more compatibility for existing +stereo content, with back speakers at +150 and -150 degrees. + +itu5.1.ambdec +Specifies a standard ITU 5.0/5.1 setup for 5.1 Surround output. The front- +center speaker is placed directly in front at 0 degrees, with the front-left +and front-right at +30 and -30 degrees, and the surround speakers (side or +back) at +110 and -110 degrees. + +hexagon.ambdec +Specifies a flat-front hexagonal speaker setup for 7.1 Surround output. The +front left and right speakers are placed at +30 and -30 degrees, the side +speakers are placed at +90 and -90 degrees, and the back speakers are placed at ++150 and -150 degrees. Although this is for 7.1 output, no front-center speaker +is defined for the decoder, meaning that speaker will be silent for 3D sound +(however it may still be used with AL_SOFT_direct_channels or ALC_EXT_DEDICATED +output). A "proper" 7.1 decoder may be provided in the future, but due to the +nature of the speaker configuration will have trade-offs. + +3D7.1.ambdec +Specifies a 3D7.1 speaker setup for 7.1 Surround output. Although it's for 7.1 +output, the speakers for such a configuration need to be placed in different +positions for proper results. Please see docs/3D7.1.txt for more information. diff --git a/love/src/jni/openal-soft-1.18.2/presets/rectangle.ambdec b/love/src/jni/openal-soft-1.18.2/presets/rectangle.ambdec new file mode 100644 index 00000000..caf72318 --- /dev/null +++ b/love/src/jni/openal-soft-1.18.2/presets/rectangle.ambdec @@ -0,0 +1,45 @@ +# AmbDec configuration +# Written by Ambisonic Decoder Toolbox, version 8.0 + +/description Rectangle_1h0p_pinv_match_rV_max_rE_2_band + +/version 3 + +/dec/chan_mask b +/dec/freq_bands 2 +/dec/speakers 4 +/dec/coeff_scale fuma + +/opt/input_scale fuma +/opt/nfeff_comp input +/opt/delay_comp on +/opt/level_comp on +/opt/xover_freq 400.000000 +/opt/xover_ratio 0.000000 + +/speakers/{ +# id dist azim elev conn +#----------------------------------------------------------------------- +add_spkr LF 1.000000 30.000000 0.000000 +add_spkr RF 1.000000 -30.000000 0.000000 +add_spkr RB 1.000000 -150.000000 0.000000 +add_spkr LB 1.000000 150.000000 0.000000 +/} + +/lfmatrix/{ +order_gain 1.000000 1.000000 0.000000 0.000000 +add_row 0.353553 0.500000 0.288675 +add_row 0.353553 -0.500000 0.288675 +add_row 0.353553 -0.500000 -0.288675 +add_row 0.353553 0.500000 -0.288675 +/} + +/hfmatrix/{ +order_gain 1.414214 1.000000 0.000000 0.000000 +add_row 0.353553 0.500000 0.288675 +add_row 0.353553 -0.500000 0.288675 +add_row 0.353553 -0.500000 -0.288675 +add_row 0.353553 0.500000 -0.288675 +/} + +/end diff --git a/love/src/jni/openal-soft-1.18.2/presets/square.ambdec b/love/src/jni/openal-soft-1.18.2/presets/square.ambdec new file mode 100644 index 00000000..547ed367 --- /dev/null +++ b/love/src/jni/openal-soft-1.18.2/presets/square.ambdec @@ -0,0 +1,45 @@ +# AmbDec configuration +# Written by Ambisonic Decoder Toolbox, version 8.0 + +/description Square_1h0p_pinv_match_rV_max_rE_2_band + +/version 3 + +/dec/chan_mask b +/dec/freq_bands 2 +/dec/speakers 4 +/dec/coeff_scale fuma + +/opt/input_scale fuma +/opt/nfeff_comp input +/opt/delay_comp on +/opt/level_comp on +/opt/xover_freq 400.000000 +/opt/xover_ratio 0.000000 + +/speakers/{ +# id dist azim elev conn +#----------------------------------------------------------------------- +add_spkr LF 1.000000 45.000000 0.000000 +add_spkr RF 1.000000 -45.000000 0.000000 +add_spkr RB 1.000000 -135.000000 0.000000 +add_spkr LB 1.000000 135.000000 0.000000 +/} + +/lfmatrix/{ +order_gain 1.000000 1.000000 0.000000 0.000000 +add_row 0.353553 0.353553 0.353553 +add_row 0.353553 -0.353553 0.353553 +add_row 0.353553 -0.353553 -0.353553 +add_row 0.353553 0.353553 -0.353553 +/} + +/hfmatrix/{ +order_gain 1.414214 1.000000 0.000000 0.000000 +add_row 0.353553 0.353553 0.353553 +add_row 0.353553 -0.353553 0.353553 +add_row 0.353553 -0.353553 -0.353553 +add_row 0.353553 0.353553 -0.353553 +/} + +/end diff --git a/love/src/jni/openal-soft-1.18.2/router/al.c b/love/src/jni/openal-soft-1.18.2/router/al.c new file mode 100644 index 00000000..3349ad13 --- /dev/null +++ b/love/src/jni/openal-soft-1.18.2/router/al.c @@ -0,0 +1,132 @@ + +#include "config.h" + +#include + +#include "AL/al.h" +#include "router.h" + + +ATOMIC(DriverIface*) CurrentCtxDriver = ATOMIC_INIT_STATIC(NULL); + +#define DECL_THUNK1(R,n,T1) AL_API R AL_APIENTRY n(T1 a) \ +{ \ + DriverIface *iface = altss_get(ThreadCtxDriver); \ + if(!iface) iface = ATOMIC_LOAD(&CurrentCtxDriver, almemory_order_acquire);\ + return iface->n(a); \ +} +#define DECL_THUNK2(R,n,T1,T2) AL_API R AL_APIENTRY n(T1 a, T2 b) \ +{ \ + DriverIface *iface = altss_get(ThreadCtxDriver); \ + if(!iface) iface = ATOMIC_LOAD(&CurrentCtxDriver, almemory_order_acquire);\ + return iface->n(a, b); \ +} +#define DECL_THUNK3(R,n,T1,T2,T3) AL_API R AL_APIENTRY n(T1 a, T2 b, T3 c) \ +{ \ + DriverIface *iface = altss_get(ThreadCtxDriver); \ + if(!iface) iface = ATOMIC_LOAD(&CurrentCtxDriver, almemory_order_acquire);\ + return iface->n(a, b, c); \ +} +#define DECL_THUNK4(R,n,T1,T2,T3,T4) AL_API R AL_APIENTRY n(T1 a, T2 b, T3 c, T4 d) \ +{ \ + DriverIface *iface = altss_get(ThreadCtxDriver); \ + if(!iface) iface = ATOMIC_LOAD(&CurrentCtxDriver, almemory_order_acquire);\ + return iface->n(a, b, c, d); \ +} +#define DECL_THUNK5(R,n,T1,T2,T3,T4,T5) AL_API R AL_APIENTRY n(T1 a, T2 b, T3 c, T4 d, T5 e) \ +{ \ + DriverIface *iface = altss_get(ThreadCtxDriver); \ + if(!iface) iface = ATOMIC_LOAD(&CurrentCtxDriver, almemory_order_acquire);\ + return iface->n(a, b, c, d, e); \ +} + + +/* Ugly hack for some apps calling alGetError without a current context, and + * expecting it to be AL_NO_ERROR. + */ +AL_API ALenum AL_APIENTRY alGetError(void) +{ + DriverIface *iface = altss_get(ThreadCtxDriver); + if(!iface) iface = ATOMIC_LOAD(&CurrentCtxDriver, almemory_order_acquire); + return iface ? iface->alGetError() : AL_NO_ERROR; +} + + +DECL_THUNK1(void, alDopplerFactor, ALfloat) +DECL_THUNK1(void, alDopplerVelocity, ALfloat) +DECL_THUNK1(void, alSpeedOfSound, ALfloat) +DECL_THUNK1(void, alDistanceModel, ALenum) + +DECL_THUNK1(void, alEnable, ALenum) +DECL_THUNK1(void, alDisable, ALenum) +DECL_THUNK1(ALboolean, alIsEnabled, ALenum) + +DECL_THUNK1(const ALchar*, alGetString, ALenum) +DECL_THUNK2(void, alGetBooleanv, ALenum, ALboolean*) +DECL_THUNK2(void, alGetIntegerv, ALenum, ALint*) +DECL_THUNK2(void, alGetFloatv, ALenum, ALfloat*) +DECL_THUNK2(void, alGetDoublev, ALenum, ALdouble*) +DECL_THUNK1(ALboolean, alGetBoolean, ALenum) +DECL_THUNK1(ALint, alGetInteger, ALenum) +DECL_THUNK1(ALfloat, alGetFloat, ALenum) +DECL_THUNK1(ALdouble, alGetDouble, ALenum) + +DECL_THUNK1(ALboolean, alIsExtensionPresent, const ALchar*) +DECL_THUNK1(void*, alGetProcAddress, const ALchar*) +DECL_THUNK1(ALenum, alGetEnumValue, const ALchar*) + +DECL_THUNK2(void, alListenerf, ALenum, ALfloat) +DECL_THUNK4(void, alListener3f, ALenum, ALfloat, ALfloat, ALfloat) +DECL_THUNK2(void, alListenerfv, ALenum, const ALfloat*) +DECL_THUNK2(void, alListeneri, ALenum, ALint) +DECL_THUNK4(void, alListener3i, ALenum, ALint, ALint, ALint) +DECL_THUNK2(void, alListeneriv, ALenum, const ALint*) +DECL_THUNK2(void, alGetListenerf, ALenum, ALfloat*) +DECL_THUNK4(void, alGetListener3f, ALenum, ALfloat*, ALfloat*, ALfloat*) +DECL_THUNK2(void, alGetListenerfv, ALenum, ALfloat*) +DECL_THUNK2(void, alGetListeneri, ALenum, ALint*) +DECL_THUNK4(void, alGetListener3i, ALenum, ALint*, ALint*, ALint*) +DECL_THUNK2(void, alGetListeneriv, ALenum, ALint*) + +DECL_THUNK2(void, alGenSources, ALsizei, ALuint*) +DECL_THUNK2(void, alDeleteSources, ALsizei, const ALuint*) +DECL_THUNK1(ALboolean, alIsSource, ALuint) +DECL_THUNK3(void, alSourcef, ALuint, ALenum, ALfloat) +DECL_THUNK5(void, alSource3f, ALuint, ALenum, ALfloat, ALfloat, ALfloat) +DECL_THUNK3(void, alSourcefv, ALuint, ALenum, const ALfloat*) +DECL_THUNK3(void, alSourcei, ALuint, ALenum, ALint) +DECL_THUNK5(void, alSource3i, ALuint, ALenum, ALint, ALint, ALint) +DECL_THUNK3(void, alSourceiv, ALuint, ALenum, const ALint*) +DECL_THUNK3(void, alGetSourcef, ALuint, ALenum, ALfloat*) +DECL_THUNK5(void, alGetSource3f, ALuint, ALenum, ALfloat*, ALfloat*, ALfloat*) +DECL_THUNK3(void, alGetSourcefv, ALuint, ALenum, ALfloat*) +DECL_THUNK3(void, alGetSourcei, ALuint, ALenum, ALint*) +DECL_THUNK5(void, alGetSource3i, ALuint, ALenum, ALint*, ALint*, ALint*) +DECL_THUNK3(void, alGetSourceiv, ALuint, ALenum, ALint*) +DECL_THUNK2(void, alSourcePlayv, ALsizei, const ALuint*) +DECL_THUNK2(void, alSourceStopv, ALsizei, const ALuint*) +DECL_THUNK2(void, alSourceRewindv, ALsizei, const ALuint*) +DECL_THUNK2(void, alSourcePausev, ALsizei, const ALuint*) +DECL_THUNK1(void, alSourcePlay, ALuint) +DECL_THUNK1(void, alSourceStop, ALuint) +DECL_THUNK1(void, alSourceRewind, ALuint) +DECL_THUNK1(void, alSourcePause, ALuint) +DECL_THUNK3(void, alSourceQueueBuffers, ALuint, ALsizei, const ALuint*) +DECL_THUNK3(void, alSourceUnqueueBuffers, ALuint, ALsizei, ALuint*) + +DECL_THUNK2(void, alGenBuffers, ALsizei, ALuint*) +DECL_THUNK2(void, alDeleteBuffers, ALsizei, const ALuint*) +DECL_THUNK1(ALboolean, alIsBuffer, ALuint) +DECL_THUNK3(void, alBufferf, ALuint, ALenum, ALfloat) +DECL_THUNK5(void, alBuffer3f, ALuint, ALenum, ALfloat, ALfloat, ALfloat) +DECL_THUNK3(void, alBufferfv, ALuint, ALenum, const ALfloat*) +DECL_THUNK3(void, alBufferi, ALuint, ALenum, ALint) +DECL_THUNK5(void, alBuffer3i, ALuint, ALenum, ALint, ALint, ALint) +DECL_THUNK3(void, alBufferiv, ALuint, ALenum, const ALint*) +DECL_THUNK3(void, alGetBufferf, ALuint, ALenum, ALfloat*) +DECL_THUNK5(void, alGetBuffer3f, ALuint, ALenum, ALfloat*, ALfloat*, ALfloat*) +DECL_THUNK3(void, alGetBufferfv, ALuint, ALenum, ALfloat*) +DECL_THUNK3(void, alGetBufferi, ALuint, ALenum, ALint*) +DECL_THUNK5(void, alGetBuffer3i, ALuint, ALenum, ALint*, ALint*, ALint*) +DECL_THUNK3(void, alGetBufferiv, ALuint, ALenum, ALint*) +DECL_THUNK5(void, alBufferData, ALuint, ALenum, const ALvoid*, ALsizei, ALsizei) diff --git a/love/src/jni/openal-soft-1.18.2/router/alc.c b/love/src/jni/openal-soft-1.18.2/router/alc.c new file mode 100644 index 00000000..946c7d4c --- /dev/null +++ b/love/src/jni/openal-soft-1.18.2/router/alc.c @@ -0,0 +1,956 @@ + +#include "config.h" + +#include +#include +#include +#include + +#include "AL/alc.h" +#include "router.h" +#include "almalloc.h" + + +#define COUNTOF(x) (sizeof(x)/sizeof(x[0])) + +#define DECL(x) { #x, (ALCvoid*)(x) } +static const struct { + const ALCchar *funcName; + ALCvoid *address; +} alcFunctions[] = { + DECL(alcCreateContext), + DECL(alcMakeContextCurrent), + DECL(alcProcessContext), + DECL(alcSuspendContext), + DECL(alcDestroyContext), + DECL(alcGetCurrentContext), + DECL(alcGetContextsDevice), + DECL(alcOpenDevice), + DECL(alcCloseDevice), + DECL(alcGetError), + DECL(alcIsExtensionPresent), + DECL(alcGetProcAddress), + DECL(alcGetEnumValue), + DECL(alcGetString), + DECL(alcGetIntegerv), + DECL(alcCaptureOpenDevice), + DECL(alcCaptureCloseDevice), + DECL(alcCaptureStart), + DECL(alcCaptureStop), + DECL(alcCaptureSamples), + + DECL(alcSetThreadContext), + DECL(alcGetThreadContext), + + DECL(alEnable), + DECL(alDisable), + DECL(alIsEnabled), + DECL(alGetString), + DECL(alGetBooleanv), + DECL(alGetIntegerv), + DECL(alGetFloatv), + DECL(alGetDoublev), + DECL(alGetBoolean), + DECL(alGetInteger), + DECL(alGetFloat), + DECL(alGetDouble), + DECL(alGetError), + DECL(alIsExtensionPresent), + DECL(alGetProcAddress), + DECL(alGetEnumValue), + DECL(alListenerf), + DECL(alListener3f), + DECL(alListenerfv), + DECL(alListeneri), + DECL(alListener3i), + DECL(alListeneriv), + DECL(alGetListenerf), + DECL(alGetListener3f), + DECL(alGetListenerfv), + DECL(alGetListeneri), + DECL(alGetListener3i), + DECL(alGetListeneriv), + DECL(alGenSources), + DECL(alDeleteSources), + DECL(alIsSource), + DECL(alSourcef), + DECL(alSource3f), + DECL(alSourcefv), + DECL(alSourcei), + DECL(alSource3i), + DECL(alSourceiv), + DECL(alGetSourcef), + DECL(alGetSource3f), + DECL(alGetSourcefv), + DECL(alGetSourcei), + DECL(alGetSource3i), + DECL(alGetSourceiv), + DECL(alSourcePlayv), + DECL(alSourceStopv), + DECL(alSourceRewindv), + DECL(alSourcePausev), + DECL(alSourcePlay), + DECL(alSourceStop), + DECL(alSourceRewind), + DECL(alSourcePause), + DECL(alSourceQueueBuffers), + DECL(alSourceUnqueueBuffers), + DECL(alGenBuffers), + DECL(alDeleteBuffers), + DECL(alIsBuffer), + DECL(alBufferData), + DECL(alBufferf), + DECL(alBuffer3f), + DECL(alBufferfv), + DECL(alBufferi), + DECL(alBuffer3i), + DECL(alBufferiv), + DECL(alGetBufferf), + DECL(alGetBuffer3f), + DECL(alGetBufferfv), + DECL(alGetBufferi), + DECL(alGetBuffer3i), + DECL(alGetBufferiv), + DECL(alDopplerFactor), + DECL(alDopplerVelocity), + DECL(alSpeedOfSound), + DECL(alDistanceModel), +}; +#undef DECL + +#define DECL(x) { #x, (x) } +static const struct { + const ALCchar *enumName; + ALCenum value; +} alcEnumerations[] = { + DECL(ALC_INVALID), + DECL(ALC_FALSE), + DECL(ALC_TRUE), + + DECL(ALC_MAJOR_VERSION), + DECL(ALC_MINOR_VERSION), + DECL(ALC_ATTRIBUTES_SIZE), + DECL(ALC_ALL_ATTRIBUTES), + DECL(ALC_DEFAULT_DEVICE_SPECIFIER), + DECL(ALC_DEVICE_SPECIFIER), + DECL(ALC_ALL_DEVICES_SPECIFIER), + DECL(ALC_DEFAULT_ALL_DEVICES_SPECIFIER), + DECL(ALC_EXTENSIONS), + DECL(ALC_FREQUENCY), + DECL(ALC_REFRESH), + DECL(ALC_SYNC), + DECL(ALC_MONO_SOURCES), + DECL(ALC_STEREO_SOURCES), + DECL(ALC_CAPTURE_DEVICE_SPECIFIER), + DECL(ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER), + DECL(ALC_CAPTURE_SAMPLES), + + DECL(ALC_NO_ERROR), + DECL(ALC_INVALID_DEVICE), + DECL(ALC_INVALID_CONTEXT), + DECL(ALC_INVALID_ENUM), + DECL(ALC_INVALID_VALUE), + DECL(ALC_OUT_OF_MEMORY), + + DECL(AL_INVALID), + DECL(AL_NONE), + DECL(AL_FALSE), + DECL(AL_TRUE), + + DECL(AL_SOURCE_RELATIVE), + DECL(AL_CONE_INNER_ANGLE), + DECL(AL_CONE_OUTER_ANGLE), + DECL(AL_PITCH), + DECL(AL_POSITION), + DECL(AL_DIRECTION), + DECL(AL_VELOCITY), + DECL(AL_LOOPING), + DECL(AL_BUFFER), + DECL(AL_GAIN), + DECL(AL_MIN_GAIN), + DECL(AL_MAX_GAIN), + DECL(AL_ORIENTATION), + DECL(AL_REFERENCE_DISTANCE), + DECL(AL_ROLLOFF_FACTOR), + DECL(AL_CONE_OUTER_GAIN), + DECL(AL_MAX_DISTANCE), + DECL(AL_SEC_OFFSET), + DECL(AL_SAMPLE_OFFSET), + DECL(AL_BYTE_OFFSET), + DECL(AL_SOURCE_TYPE), + DECL(AL_STATIC), + DECL(AL_STREAMING), + DECL(AL_UNDETERMINED), + + DECL(AL_SOURCE_STATE), + DECL(AL_INITIAL), + DECL(AL_PLAYING), + DECL(AL_PAUSED), + DECL(AL_STOPPED), + + DECL(AL_BUFFERS_QUEUED), + DECL(AL_BUFFERS_PROCESSED), + + DECL(AL_FORMAT_MONO8), + DECL(AL_FORMAT_MONO16), + DECL(AL_FORMAT_STEREO8), + DECL(AL_FORMAT_STEREO16), + + DECL(AL_FREQUENCY), + DECL(AL_BITS), + DECL(AL_CHANNELS), + DECL(AL_SIZE), + + DECL(AL_UNUSED), + DECL(AL_PENDING), + DECL(AL_PROCESSED), + + DECL(AL_NO_ERROR), + DECL(AL_INVALID_NAME), + DECL(AL_INVALID_ENUM), + DECL(AL_INVALID_VALUE), + DECL(AL_INVALID_OPERATION), + DECL(AL_OUT_OF_MEMORY), + + DECL(AL_VENDOR), + DECL(AL_VERSION), + DECL(AL_RENDERER), + DECL(AL_EXTENSIONS), + + DECL(AL_DOPPLER_FACTOR), + DECL(AL_DOPPLER_VELOCITY), + DECL(AL_DISTANCE_MODEL), + DECL(AL_SPEED_OF_SOUND), + + DECL(AL_INVERSE_DISTANCE), + DECL(AL_INVERSE_DISTANCE_CLAMPED), + DECL(AL_LINEAR_DISTANCE), + DECL(AL_LINEAR_DISTANCE_CLAMPED), + DECL(AL_EXPONENT_DISTANCE), + DECL(AL_EXPONENT_DISTANCE_CLAMPED), +}; +#undef DECL + +static const ALCchar alcNoError[] = "No Error"; +static const ALCchar alcErrInvalidDevice[] = "Invalid Device"; +static const ALCchar alcErrInvalidContext[] = "Invalid Context"; +static const ALCchar alcErrInvalidEnum[] = "Invalid Enum"; +static const ALCchar alcErrInvalidValue[] = "Invalid Value"; +static const ALCchar alcErrOutOfMemory[] = "Out of Memory"; +static const ALCchar alcExtensionList[] = + "ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE " + "ALC_EXT_thread_local_context"; + +static const ALCint alcMajorVersion = 1; +static const ALCint alcMinorVersion = 1; + + +static almtx_t EnumerationLock; +static almtx_t ContextSwitchLock; + +static ATOMIC(ALCenum) LastError = ATOMIC_INIT_STATIC(ALC_NO_ERROR); +static PtrIntMap DeviceIfaceMap = PTRINTMAP_STATIC_INITIALIZE; +static PtrIntMap ContextIfaceMap = PTRINTMAP_STATIC_INITIALIZE; + + +typedef struct EnumeratedList { + ALCchar *Names; + ALCchar *NamesEnd; + ALCint *Indicies; + ALCsizei IndexSize; +} EnumeratedList; +static EnumeratedList DevicesList = { NULL, NULL, NULL, 0 }; +static EnumeratedList AllDevicesList = { NULL, NULL, NULL, 0 }; +static EnumeratedList CaptureDevicesList = { NULL, NULL, NULL, 0 }; + +static void ClearDeviceList(EnumeratedList *list) +{ + al_free(list->Names); + list->Names = NULL; + list->NamesEnd = NULL; + + al_free(list->Indicies); + list->Indicies = NULL; + list->IndexSize = 0; +} + +static void AppendDeviceList(EnumeratedList *list, const ALCchar *names, ALint idx) +{ + const ALCchar *name_end = names; + ALCsizei count = 0; + ALCchar *new_list; + ALCint *new_indicies; + size_t len; + ALCsizei i; + + if(!name_end) + return; + while(*name_end) + { + TRACE("Enumerated \"%s\", driver %d\n", name_end, idx); + count++; + name_end += strlen(name_end)+1; + } + if(names == name_end) + return; + + len = (list->NamesEnd - list->Names) + (name_end - names); + new_list = al_calloc(DEF_ALIGN, len + 1); + memcpy(new_list, list->Names, list->NamesEnd - list->Names); + memcpy(new_list + (list->NamesEnd - list->Names), names, name_end - names); + al_free(list->Names); + list->Names = new_list; + list->NamesEnd = list->Names + len; + + new_indicies = al_calloc(16, sizeof(ALCint)*(list->IndexSize + count)); + for(i = 0;i < list->IndexSize;i++) + new_indicies[i] = list->Indicies[i]; + for(i = 0;i < count;i++) + new_indicies[list->IndexSize+i] = idx; + al_free(list->Indicies); + list->Indicies = new_indicies; + list->IndexSize += count; +} + +static ALint GetDriverIndexForName(const EnumeratedList *list, const ALCchar *name) +{ + const ALCchar *devnames = list->Names; + const ALCint *index = list->Indicies; + + while(devnames && *devnames) + { + if(strcmp(name, devnames) == 0) + return *index; + devnames += strlen(devnames)+1; + index++; + } + return -1; +} + +void InitALC(void) +{ + almtx_init(&EnumerationLock, almtx_recursive); + almtx_init(&ContextSwitchLock, almtx_plain); +} + +void ReleaseALC(void) +{ + ClearDeviceList(&DevicesList); + ClearDeviceList(&AllDevicesList); + ClearDeviceList(&CaptureDevicesList); + + ResetPtrIntMap(&ContextIfaceMap); + ResetPtrIntMap(&DeviceIfaceMap); + + almtx_destroy(&ContextSwitchLock); + almtx_destroy(&EnumerationLock); +} + + +ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename) +{ + ALCdevice *device = NULL; + ALint idx; + + /* Prior to the enumeration extension, apps would hardcode these names as a + * quality hint for the wrapper driver. Ignore them since there's no sane + * way to map them. + */ + if(devicename && (devicename[0] == '\0' || + strcmp(devicename, "DirectSound3D") == 0 || + strcmp(devicename, "DirectSound") == 0 || + strcmp(devicename, "MMSYSTEM") == 0)) + devicename = NULL; + if(devicename) + { + almtx_lock(&EnumerationLock); + if(!DevicesList.Names) + (void)alcGetString(NULL, ALC_DEVICE_SPECIFIER); + idx = GetDriverIndexForName(&DevicesList, devicename); + if(idx < 0) + { + if(!AllDevicesList.Names) + (void)alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER); + idx = GetDriverIndexForName(&AllDevicesList, devicename); + } + almtx_unlock(&EnumerationLock); + if(idx < 0) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_VALUE); + TRACE("Failed to find driver for name \"%s\"\n", devicename); + return NULL; + } + TRACE("Found driver %d for name \"%s\"\n", idx, devicename); + device = DriverList[idx].alcOpenDevice(devicename); + } + else + { + int i; + for(i = 0;i < DriverListSize;i++) + { + if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || + DriverList[i].alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT")) + { + idx = i; + TRACE("Using default device from driver %d\n", idx); + device = DriverList[idx].alcOpenDevice(NULL); + break; + } + } + } + + if(device) + { + if(InsertPtrIntMapEntry(&DeviceIfaceMap, device, idx) != ALC_NO_ERROR) + { + DriverList[idx].alcCloseDevice(device); + device = NULL; + } + } + + return device; +} + +ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) +{ + ALint idx; + + if(!device || (idx=LookupPtrIntMapKey(&DeviceIfaceMap, device)) < 0) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + return ALC_FALSE; + } + if(!DriverList[idx].alcCloseDevice(device)) + return ALC_FALSE; + RemovePtrIntMapKey(&DeviceIfaceMap, device); + return ALC_TRUE; +} + + +ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint *attrlist) +{ + ALCcontext *context; + ALint idx; + + if(!device || (idx=LookupPtrIntMapKey(&DeviceIfaceMap, device)) < 0) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + return ALC_FALSE; + } + context = DriverList[idx].alcCreateContext(device, attrlist); + if(context) + { + if(InsertPtrIntMapEntry(&ContextIfaceMap, context, idx) != ALC_NO_ERROR) + { + DriverList[idx].alcDestroyContext(context); + context = NULL; + } + } + + return context; +} + +ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context) +{ + ALint idx = -1; + + almtx_lock(&ContextSwitchLock); + if(context) + { + idx = LookupPtrIntMapKey(&ContextIfaceMap, context); + if(idx < 0) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT); + almtx_unlock(&ContextSwitchLock); + return ALC_FALSE; + } + if(!DriverList[idx].alcMakeContextCurrent(context)) + { + almtx_unlock(&ContextSwitchLock); + return ALC_FALSE; + } + } + + /* Unset the context from the old driver if it's different from the new + * current one. + */ + if(idx < 0) + { + DriverIface *oldiface = altss_get(ThreadCtxDriver); + if(oldiface) oldiface->alcSetThreadContext(NULL); + oldiface = ATOMIC_EXCHANGE_PTR_SEQ(&CurrentCtxDriver, NULL); + if(oldiface) oldiface->alcMakeContextCurrent(NULL); + } + else + { + DriverIface *oldiface = altss_get(ThreadCtxDriver); + if(oldiface && oldiface != &DriverList[idx]) + oldiface->alcSetThreadContext(NULL); + oldiface = ATOMIC_EXCHANGE_PTR_SEQ(&CurrentCtxDriver, &DriverList[idx]); + if(oldiface && oldiface != &DriverList[idx]) + oldiface->alcMakeContextCurrent(NULL); + } + almtx_unlock(&ContextSwitchLock); + altss_set(ThreadCtxDriver, NULL); + + return ALC_TRUE; +} + +ALC_API void ALC_APIENTRY alcProcessContext(ALCcontext *context) +{ + if(context) + { + ALint idx = LookupPtrIntMapKey(&ContextIfaceMap, context); + if(idx >= 0) + return DriverList[idx].alcProcessContext(context); + } + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT); +} + +ALC_API void ALC_APIENTRY alcSuspendContext(ALCcontext *context) +{ + if(context) + { + ALint idx = LookupPtrIntMapKey(&ContextIfaceMap, context); + if(idx >= 0) + return DriverList[idx].alcSuspendContext(context); + } + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT); +} + +ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context) +{ + ALint idx; + + if(!context || (idx=LookupPtrIntMapKey(&ContextIfaceMap, context)) < 0) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT); + return; + } + + DriverList[idx].alcDestroyContext(context); + RemovePtrIntMapKey(&ContextIfaceMap, context); +} + +ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void) +{ + DriverIface *iface = altss_get(ThreadCtxDriver); + if(!iface) iface = ATOMIC_LOAD_SEQ(&CurrentCtxDriver); + return iface ? iface->alcGetCurrentContext() : NULL; +} + +ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *context) +{ + if(context) + { + ALint idx = LookupPtrIntMapKey(&ContextIfaceMap, context); + if(idx >= 0) + return DriverList[idx].alcGetContextsDevice(context); + } + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT); + return NULL; +} + + +ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device) +{ + if(device) + { + ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + if(idx < 0) return ALC_INVALID_DEVICE; + return DriverList[idx].alcGetError(device); + } + return ATOMIC_EXCHANGE_SEQ(&LastError, ALC_NO_ERROR); +} + +ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extname) +{ + const char *ptr; + size_t len; + + if(device) + { + ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + if(idx < 0) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + return ALC_FALSE; + } + return DriverList[idx].alcIsExtensionPresent(device, extname); + } + + len = strlen(extname); + ptr = alcExtensionList; + while(ptr && *ptr) + { + if(strncasecmp(ptr, extname, len) == 0 && (ptr[len] == '\0' || isspace(ptr[len]))) + return ALC_TRUE; + if((ptr=strchr(ptr, ' ')) != NULL) + { + do { + ++ptr; + } while(isspace(*ptr)); + } + } + return ALC_FALSE; +} + +ALC_API void* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcname) +{ + size_t i; + + if(device) + { + ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + if(idx < 0) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + return NULL; + } + return DriverList[idx].alcGetProcAddress(device, funcname); + } + + for(i = 0;i < COUNTOF(alcFunctions);i++) + { + if(strcmp(funcname, alcFunctions[i].funcName) == 0) + return alcFunctions[i].address; + } + return NULL; +} + +ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumname) +{ + size_t i; + + if(device) + { + ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + if(idx < 0) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + return 0; + } + return DriverList[idx].alcGetEnumValue(device, enumname); + } + + for(i = 0;i < COUNTOF(alcEnumerations);i++) + { + if(strcmp(enumname, alcEnumerations[i].enumName) == 0) + return alcEnumerations[i].value; + } + return 0; +} + +ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum param) +{ + ALsizei i = 0; + + if(device) + { + ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + if(idx < 0) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + return NULL; + } + return DriverList[idx].alcGetString(device, param); + } + + switch(param) + { + case ALC_NO_ERROR: + return alcNoError; + case ALC_INVALID_ENUM: + return alcErrInvalidEnum; + case ALC_INVALID_VALUE: + return alcErrInvalidValue; + case ALC_INVALID_DEVICE: + return alcErrInvalidDevice; + case ALC_INVALID_CONTEXT: + return alcErrInvalidContext; + case ALC_OUT_OF_MEMORY: + return alcErrOutOfMemory; + case ALC_EXTENSIONS: + return alcExtensionList; + + case ALC_DEVICE_SPECIFIER: + almtx_lock(&EnumerationLock); + ClearDeviceList(&DevicesList); + for(i = 0;i < DriverListSize;i++) + { + /* Only enumerate names from drivers that support it. */ + if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || + DriverList[i].alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT")) + AppendDeviceList(&DevicesList, + DriverList[i].alcGetString(NULL, ALC_DEVICE_SPECIFIER), i + ); + } + almtx_unlock(&EnumerationLock); + return DevicesList.Names; + + case ALC_ALL_DEVICES_SPECIFIER: + almtx_lock(&EnumerationLock); + ClearDeviceList(&AllDevicesList); + for(i = 0;i < DriverListSize;i++) + { + /* If the driver doesn't support ALC_ENUMERATE_ALL_EXT, substitute + * standard enumeration. + */ + if(DriverList[i].alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT")) + AppendDeviceList(&AllDevicesList, + DriverList[i].alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER), i + ); + else if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || + DriverList[i].alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT")) + AppendDeviceList(&AllDevicesList, + DriverList[i].alcGetString(NULL, ALC_DEVICE_SPECIFIER), i + ); + } + almtx_unlock(&EnumerationLock); + return AllDevicesList.Names; + + case ALC_CAPTURE_DEVICE_SPECIFIER: + almtx_lock(&EnumerationLock); + ClearDeviceList(&CaptureDevicesList); + for(i = 0;i < DriverListSize;i++) + { + if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || + DriverList[i].alcIsExtensionPresent(NULL, "ALC_EXT_CAPTURE")) + AppendDeviceList(&CaptureDevicesList, + DriverList[i].alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER), i + ); + } + almtx_unlock(&EnumerationLock); + return CaptureDevicesList.Names; + + case ALC_DEFAULT_DEVICE_SPECIFIER: + for(i = 0;i < DriverListSize;i++) + { + if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || + DriverList[i].alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT")) + return DriverList[i].alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER); + } + return ""; + + case ALC_DEFAULT_ALL_DEVICES_SPECIFIER: + for(i = 0;i < DriverListSize;i++) + { + if(DriverList[i].alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT")) + return DriverList[i].alcGetString(NULL, ALC_DEFAULT_ALL_DEVICES_SPECIFIER); + } + return ""; + + case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER: + for(i = 0;i < DriverListSize;i++) + { + if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || + DriverList[i].alcIsExtensionPresent(NULL, "ALC_EXT_CAPTURE")) + return DriverList[i].alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER); + } + return ""; + + default: + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_ENUM); + break; + } + return NULL; +} + +ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values) +{ + if(device) + { + ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + if(idx < 0) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + return; + } + return DriverList[idx].alcGetIntegerv(device, param, size, values); + } + + if(size <= 0 || values == NULL) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_VALUE); + return; + } + + switch(param) + { + case ALC_MAJOR_VERSION: + if(size >= 1) + { + values[0] = alcMajorVersion; + return; + } + /*fall-through*/ + case ALC_MINOR_VERSION: + if(size >= 1) + { + values[0] = alcMinorVersion; + return; + } + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_VALUE); + return; + + case ALC_ATTRIBUTES_SIZE: + case ALC_ALL_ATTRIBUTES: + case ALC_FREQUENCY: + case ALC_REFRESH: + case ALC_SYNC: + case ALC_MONO_SOURCES: + case ALC_STEREO_SOURCES: + case ALC_CAPTURE_SAMPLES: + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + return; + + default: + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_ENUM); + return; + } +} + + +ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize) +{ + ALCdevice *device = NULL; + ALint idx; + + if(devicename && devicename[0] == '\0') + devicename = NULL; + if(devicename) + { + almtx_lock(&EnumerationLock); + if(!CaptureDevicesList.Names) + (void)alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); + idx = GetDriverIndexForName(&CaptureDevicesList, devicename); + almtx_unlock(&EnumerationLock); + if(idx < 0) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_VALUE); + TRACE("Failed to find driver for name \"%s\"\n", devicename); + return NULL; + } + TRACE("Found driver %d for name \"%s\"\n", idx, devicename); + device = DriverList[idx].alcCaptureOpenDevice( + devicename, frequency, format, buffersize + ); + } + else + { + int i; + for(i = 0;i < DriverListSize;i++) + { + if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || + DriverList[i].alcIsExtensionPresent(NULL, "ALC_EXT_CAPTURE")) + { + idx = i; + TRACE("Using default capture device from driver %d\n", idx); + device = DriverList[idx].alcCaptureOpenDevice( + NULL, frequency, format, buffersize + ); + break; + } + } + } + + if(device) + { + if(InsertPtrIntMapEntry(&DeviceIfaceMap, device, idx) != ALC_NO_ERROR) + { + DriverList[idx].alcCaptureCloseDevice(device); + device = NULL; + } + } + + return device; +} + +ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) +{ + ALint idx; + + if(!device || (idx=LookupPtrIntMapKey(&DeviceIfaceMap, device)) < 0) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + return ALC_FALSE; + } + if(!DriverList[idx].alcCaptureCloseDevice(device)) + return ALC_FALSE; + RemovePtrIntMapKey(&DeviceIfaceMap, device); + return ALC_TRUE; +} + +ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device) +{ + if(device) + { + ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + if(idx >= 0) + return DriverList[idx].alcCaptureStart(device); + } + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); +} + +ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device) +{ + if(device) + { + ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + if(idx >= 0) + return DriverList[idx].alcCaptureStop(device); + } + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); +} + +ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples) +{ + if(device) + { + ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + if(idx >= 0) + return DriverList[idx].alcCaptureSamples(device, buffer, samples); + } + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); +} + + +ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context) +{ + ALCenum err = ALC_INVALID_CONTEXT; + ALint idx; + + if(!context) + { + DriverIface *oldiface = altss_get(ThreadCtxDriver); + if(oldiface && !oldiface->alcSetThreadContext(NULL)) + return ALC_FALSE; + altss_set(ThreadCtxDriver, NULL); + return ALC_TRUE; + } + + idx = LookupPtrIntMapKey(&ContextIfaceMap, context); + if(idx >= 0) + { + if(DriverList[idx].alcSetThreadContext(context)) + { + DriverIface *oldiface = altss_get(ThreadCtxDriver); + if(oldiface != &DriverList[idx]) + { + altss_set(ThreadCtxDriver, &DriverList[idx]); + if(oldiface) oldiface->alcSetThreadContext(NULL); + } + return ALC_TRUE; + } + err = DriverList[idx].alcGetError(NULL); + } + ATOMIC_STORE_SEQ(&LastError, err); + return ALC_FALSE; +} + +ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void) +{ + DriverIface *iface = altss_get(ThreadCtxDriver); + if(iface) return iface->alcGetThreadContext(); + return NULL; +} diff --git a/love/src/jni/openal-soft-1.18.2/router/router.c b/love/src/jni/openal-soft-1.18.2/router/router.c new file mode 100644 index 00000000..0497a1d2 --- /dev/null +++ b/love/src/jni/openal-soft-1.18.2/router/router.c @@ -0,0 +1,512 @@ + +#include "config.h" + +#include "router.h" + +#include +#include +#include + +#include "AL/alc.h" +#include "AL/al.h" +#include "almalloc.h" + +#include "version.h" + + +DriverIface *DriverList = NULL; +int DriverListSize = 0; +static int DriverListSizeMax = 0; + +altss_t ThreadCtxDriver; + +enum LogLevel LogLevel = LogLevel_Error; +FILE *LogFile; + +static void LoadDriverList(void); + + +BOOL APIENTRY DllMain(HINSTANCE UNUSED(module), DWORD reason, void* UNUSED(reserved)) +{ + const char *str; + int i; + + switch(reason) + { + case DLL_PROCESS_ATTACH: + LogFile = stderr; + str = getenv("ALROUTER_LOGFILE"); + if(str && *str != '\0') + { + FILE *f = fopen(str, "w"); + if(f == NULL) + ERR("Could not open log file: %s\n", str); + else + LogFile = f; + } + str = getenv("ALROUTER_LOGLEVEL"); + if(str && *str != '\0') + { + char *end = NULL; + long l = strtol(str, &end, 0); + if(!end || *end != '\0') + ERR("Invalid log level value: %s\n", str); + else if(l < LogLevel_None || l > LogLevel_Trace) + ERR("Log level out of range: %s\n", str); + else + LogLevel = l; + } + TRACE("Initializing router v0.1-%s %s\n", ALSOFT_GIT_COMMIT_HASH, ALSOFT_GIT_BRANCH); + LoadDriverList(); + + altss_create(&ThreadCtxDriver, NULL); + InitALC(); + break; + + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + break; + + case DLL_PROCESS_DETACH: + ReleaseALC(); + altss_delete(ThreadCtxDriver); + + for(i = 0;i < DriverListSize;i++) + { + if(DriverList[i].Module) + FreeLibrary(DriverList[i].Module); + } + al_free(DriverList); + DriverList = NULL; + DriverListSize = 0; + DriverListSizeMax = 0; + + if(LogFile && LogFile != stderr) + fclose(LogFile); + LogFile = NULL; + break; + } + return TRUE; +} + + +#ifdef __GNUC__ +#define CAST_FUNC(x) (__typeof(x)) +#else +#define CAST_FUNC(x) (void*) +#endif + +static void AddModule(HMODULE module, const WCHAR *name) +{ + DriverIface newdrv; + int err = 0; + int i; + + for(i = 0;i < DriverListSize;i++) + { + if(DriverList[i].Module == module) + { + TRACE("Skipping already-loaded module %p\n", module); + FreeLibrary(module); + return; + } + if(wcscmp(DriverList[i].Name, name) == 0) + { + TRACE("Skipping similarly-named module %ls\n", name); + FreeLibrary(module); + return; + } + } + + if(DriverListSize == DriverListSizeMax) + { + int newmax = DriverListSizeMax ? DriverListSizeMax<<1 : 4; + void *newlist = al_calloc(DEF_ALIGN, sizeof(DriverList[0])*newmax); + if(!newlist) return; + + memcpy(newlist, DriverList, DriverListSize*sizeof(DriverList[0])); + al_free(DriverList); + DriverList = newlist; + DriverListSizeMax = newmax; + } + + memset(&newdrv, 0, sizeof(newdrv)); + /* Load required functions. */ +#define LOAD_PROC(x) do { \ + newdrv.x = CAST_FUNC(newdrv.x) GetProcAddress(module, #x); \ + if(!newdrv.x) \ + { \ + ERR("Failed to find entry point for %s in %ls\n", #x, name); \ + err = 1; \ + } \ +} while(0) + LOAD_PROC(alcCreateContext); + LOAD_PROC(alcMakeContextCurrent); + LOAD_PROC(alcProcessContext); + LOAD_PROC(alcSuspendContext); + LOAD_PROC(alcDestroyContext); + LOAD_PROC(alcGetCurrentContext); + LOAD_PROC(alcGetContextsDevice); + LOAD_PROC(alcOpenDevice); + LOAD_PROC(alcCloseDevice); + LOAD_PROC(alcGetError); + LOAD_PROC(alcIsExtensionPresent); + LOAD_PROC(alcGetProcAddress); + LOAD_PROC(alcGetEnumValue); + LOAD_PROC(alcGetString); + LOAD_PROC(alcGetIntegerv); + LOAD_PROC(alcCaptureOpenDevice); + LOAD_PROC(alcCaptureCloseDevice); + LOAD_PROC(alcCaptureStart); + LOAD_PROC(alcCaptureStop); + LOAD_PROC(alcCaptureSamples); + + LOAD_PROC(alEnable); + LOAD_PROC(alDisable); + LOAD_PROC(alIsEnabled); + LOAD_PROC(alGetString); + LOAD_PROC(alGetBooleanv); + LOAD_PROC(alGetIntegerv); + LOAD_PROC(alGetFloatv); + LOAD_PROC(alGetDoublev); + LOAD_PROC(alGetBoolean); + LOAD_PROC(alGetInteger); + LOAD_PROC(alGetFloat); + LOAD_PROC(alGetDouble); + LOAD_PROC(alGetError); + LOAD_PROC(alIsExtensionPresent); + LOAD_PROC(alGetProcAddress); + LOAD_PROC(alGetEnumValue); + LOAD_PROC(alListenerf); + LOAD_PROC(alListener3f); + LOAD_PROC(alListenerfv); + LOAD_PROC(alListeneri); + LOAD_PROC(alListener3i); + LOAD_PROC(alListeneriv); + LOAD_PROC(alGetListenerf); + LOAD_PROC(alGetListener3f); + LOAD_PROC(alGetListenerfv); + LOAD_PROC(alGetListeneri); + LOAD_PROC(alGetListener3i); + LOAD_PROC(alGetListeneriv); + LOAD_PROC(alGenSources); + LOAD_PROC(alDeleteSources); + LOAD_PROC(alIsSource); + LOAD_PROC(alSourcef); + LOAD_PROC(alSource3f); + LOAD_PROC(alSourcefv); + LOAD_PROC(alSourcei); + LOAD_PROC(alSource3i); + LOAD_PROC(alSourceiv); + LOAD_PROC(alGetSourcef); + LOAD_PROC(alGetSource3f); + LOAD_PROC(alGetSourcefv); + LOAD_PROC(alGetSourcei); + LOAD_PROC(alGetSource3i); + LOAD_PROC(alGetSourceiv); + LOAD_PROC(alSourcePlayv); + LOAD_PROC(alSourceStopv); + LOAD_PROC(alSourceRewindv); + LOAD_PROC(alSourcePausev); + LOAD_PROC(alSourcePlay); + LOAD_PROC(alSourceStop); + LOAD_PROC(alSourceRewind); + LOAD_PROC(alSourcePause); + LOAD_PROC(alSourceQueueBuffers); + LOAD_PROC(alSourceUnqueueBuffers); + LOAD_PROC(alGenBuffers); + LOAD_PROC(alDeleteBuffers); + LOAD_PROC(alIsBuffer); + LOAD_PROC(alBufferf); + LOAD_PROC(alBuffer3f); + LOAD_PROC(alBufferfv); + LOAD_PROC(alBufferi); + LOAD_PROC(alBuffer3i); + LOAD_PROC(alBufferiv); + LOAD_PROC(alGetBufferf); + LOAD_PROC(alGetBuffer3f); + LOAD_PROC(alGetBufferfv); + LOAD_PROC(alGetBufferi); + LOAD_PROC(alGetBuffer3i); + LOAD_PROC(alGetBufferiv); + LOAD_PROC(alBufferData); + LOAD_PROC(alDopplerFactor); + LOAD_PROC(alDopplerVelocity); + LOAD_PROC(alSpeedOfSound); + LOAD_PROC(alDistanceModel); + if(!err) + { + ALCint alc_ver[2] = { 0, 0 }; + wcsncpy(newdrv.Name, name, 32); + newdrv.Module = module; + newdrv.alcGetIntegerv(NULL, ALC_MAJOR_VERSION, 1, &alc_ver[0]); + newdrv.alcGetIntegerv(NULL, ALC_MINOR_VERSION, 1, &alc_ver[1]); + if(newdrv.alcGetError(NULL) == ALC_NO_ERROR) + newdrv.ALCVer = MAKE_ALC_VER(alc_ver[0], alc_ver[1]); + else + newdrv.ALCVer = MAKE_ALC_VER(1, 0); + +#undef LOAD_PROC +#define LOAD_PROC(x) do { \ + newdrv.x = CAST_FUNC(newdrv.x) newdrv.alcGetProcAddress(NULL, #x); \ + if(!newdrv.x) \ + { \ + ERR("Failed to find entry point for %s in %ls\n", #x, name); \ + err = 1; \ + } \ +} while(0) + if(newdrv.alcIsExtensionPresent(NULL, "ALC_EXT_thread_local_context")) + { + LOAD_PROC(alcSetThreadContext); + LOAD_PROC(alcGetThreadContext); + } + } + + if(!err) + { + TRACE("Loaded module %p, %ls, ALC %d.%d\n", module, name, + newdrv.ALCVer>>8, newdrv.ALCVer&255); + DriverList[DriverListSize++] = newdrv; + } +#undef LOAD_PROC +} + +static void SearchDrivers(WCHAR *path) +{ + WCHAR srchPath[MAX_PATH+1] = L""; + WIN32_FIND_DATAW fdata; + HANDLE srchHdl; + + TRACE("Searching for drivers in %ls...\n", path); + wcsncpy(srchPath, path, MAX_PATH); + wcsncat(srchPath, L"\\*oal.dll", MAX_PATH - lstrlenW(srchPath)); + srchHdl = FindFirstFileW(srchPath, &fdata); + if(srchHdl != INVALID_HANDLE_VALUE) + { + do { + HMODULE mod; + + wcsncpy(srchPath, path, MAX_PATH); + wcsncat(srchPath, L"\\", MAX_PATH - lstrlenW(srchPath)); + wcsncat(srchPath, fdata.cFileName, MAX_PATH - lstrlenW(srchPath)); + TRACE("Found %ls\n", srchPath); + + mod = LoadLibraryW(srchPath); + if(!mod) + WARN("Could not load %ls\n", srchPath); + else + AddModule(mod, fdata.cFileName); + } while(FindNextFileW(srchHdl, &fdata)); + FindClose(srchHdl); + } +} + +static WCHAR *strrchrW(WCHAR *str, WCHAR ch) +{ + WCHAR *res = NULL; + while(str && *str != '\0') + { + if(*str == ch) + res = str; + ++str; + } + return res; +} + +static int GetLoadedModuleDirectory(const WCHAR *name, WCHAR *moddir, DWORD length) +{ + HMODULE module = NULL; + WCHAR *sep0, *sep1; + + if(name) + { + module = GetModuleHandleW(name); + if(!module) return 0; + } + + if(GetModuleFileNameW(module, moddir, length) == 0) + return 0; + + sep0 = strrchrW(moddir, '/'); + if(sep0) sep1 = strrchrW(sep0+1, '\\'); + else sep1 = strrchrW(moddir, '\\'); + + if(sep1) *sep1 = '\0'; + else if(sep0) *sep0 = '\0'; + else *moddir = '\0'; + + return 1; +} + +void LoadDriverList(void) +{ + WCHAR path[MAX_PATH+1] = L""; + int len; + + if(GetLoadedModuleDirectory(L"OpenAL32.dll", path, MAX_PATH)) + SearchDrivers(path); + + GetCurrentDirectoryW(MAX_PATH, path); + len = lstrlenW(path); + if(len > 0 && (path[len-1] == '\\' || path[len-1] == '/')) + path[len-1] = '\0'; + SearchDrivers(path); + + if(GetLoadedModuleDirectory(NULL, path, MAX_PATH)) + SearchDrivers(path); + + GetSystemDirectoryW(path, MAX_PATH); + len = lstrlenW(path); + if(len > 0 && (path[len-1] == '\\' || path[len-1] == '/')) + path[len-1] = '\0'; + SearchDrivers(path); +} + + +void InitPtrIntMap(PtrIntMap *map) +{ + map->keys = NULL; + map->values = NULL; + map->size = 0; + map->capacity = 0; + RWLockInit(&map->lock); +} + +void ResetPtrIntMap(PtrIntMap *map) +{ + WriteLock(&map->lock); + al_free(map->keys); + map->keys = NULL; + map->values = NULL; + map->size = 0; + map->capacity = 0; + WriteUnlock(&map->lock); +} + +ALenum InsertPtrIntMapEntry(PtrIntMap *map, ALvoid *key, ALint value) +{ + ALsizei pos = 0; + + WriteLock(&map->lock); + if(map->size > 0) + { + ALsizei count = map->size; + do { + ALsizei step = count>>1; + ALsizei i = pos+step; + if(!(map->keys[i] < key)) + count = step; + else + { + pos = i+1; + count -= step+1; + } + } while(count > 0); + } + + if(pos == map->size || map->keys[pos] != key) + { + if(map->size == map->capacity) + { + ALvoid **keys = NULL; + ALint *values; + ALsizei newcap; + + newcap = (map->capacity ? (map->capacity<<1) : 4); + if(newcap > map->capacity) + keys = al_calloc(16, (sizeof(map->keys[0])+sizeof(map->values[0]))*newcap); + if(!keys) + { + WriteUnlock(&map->lock); + return AL_OUT_OF_MEMORY; + } + values = (ALint*)&keys[newcap]; + + if(map->keys) + { + memcpy(keys, map->keys, map->size*sizeof(map->keys[0])); + memcpy(values, map->values, map->size*sizeof(map->values[0])); + } + al_free(map->keys); + map->keys = keys; + map->values = values; + map->capacity = newcap; + } + + if(pos < map->size) + { + memmove(&map->keys[pos+1], &map->keys[pos], + (map->size-pos)*sizeof(map->keys[0])); + memmove(&map->values[pos+1], &map->values[pos], + (map->size-pos)*sizeof(map->values[0])); + } + map->size++; + } + map->keys[pos] = key; + map->values[pos] = value; + WriteUnlock(&map->lock); + + return AL_NO_ERROR; +} + +ALint RemovePtrIntMapKey(PtrIntMap *map, ALvoid *key) +{ + ALint ret = -1; + WriteLock(&map->lock); + if(map->size > 0) + { + ALsizei pos = 0; + ALsizei count = map->size; + do { + ALsizei step = count>>1; + ALsizei i = pos+step; + if(!(map->keys[i] < key)) + count = step; + else + { + pos = i+1; + count -= step+1; + } + } while(count > 0); + if(pos < map->size && map->keys[pos] == key) + { + ret = map->values[pos]; + if(pos < map->size-1) + { + memmove(&map->keys[pos], &map->keys[pos+1], + (map->size-1-pos)*sizeof(map->keys[0])); + memmove(&map->values[pos], &map->values[pos+1], + (map->size-1-pos)*sizeof(map->values[0])); + } + map->size--; + } + } + WriteUnlock(&map->lock); + return ret; +} + +ALint LookupPtrIntMapKey(PtrIntMap *map, ALvoid *key) +{ + ALint ret = -1; + ReadLock(&map->lock); + if(map->size > 0) + { + ALsizei pos = 0; + ALsizei count = map->size; + do { + ALsizei step = count>>1; + ALsizei i = pos+step; + if(!(map->keys[i] < key)) + count = step; + else + { + pos = i+1; + count -= step+1; + } + } while(count > 0); + if(pos < map->size && map->keys[pos] == key) + ret = map->values[pos]; + } + ReadUnlock(&map->lock); + return ret; +} diff --git a/love/src/jni/openal-soft-1.18.2/router/router.h b/love/src/jni/openal-soft-1.18.2/router/router.h new file mode 100644 index 00000000..ee885d85 --- /dev/null +++ b/love/src/jni/openal-soft-1.18.2/router/router.h @@ -0,0 +1,196 @@ +#ifndef ROUTER_ROUTER_H +#define ROUTER_ROUTER_H + +#define WIN32_LEAN_AND_MEAN +#include +#include + +#include + +#include "AL/alc.h" +#include "AL/al.h" +#include "AL/alext.h" +#include "atomic.h" +#include "rwlock.h" +#include "threads.h" + + +#ifndef UNUSED +#if defined(__cplusplus) +#define UNUSED(x) +#elif defined(__GNUC__) +#define UNUSED(x) UNUSED_##x __attribute__((unused)) +#elif defined(__LCLINT__) +#define UNUSED(x) /*@unused@*/ x +#else +#define UNUSED(x) x +#endif +#endif + +#define MAKE_ALC_VER(major, minor) (((major)<<8) | (minor)) + +typedef struct DriverIface { + WCHAR Name[32]; + HMODULE Module; + int ALCVer; + + LPALCCREATECONTEXT alcCreateContext; + LPALCMAKECONTEXTCURRENT alcMakeContextCurrent; + LPALCPROCESSCONTEXT alcProcessContext; + LPALCSUSPENDCONTEXT alcSuspendContext; + LPALCDESTROYCONTEXT alcDestroyContext; + LPALCGETCURRENTCONTEXT alcGetCurrentContext; + LPALCGETCONTEXTSDEVICE alcGetContextsDevice; + LPALCOPENDEVICE alcOpenDevice; + LPALCCLOSEDEVICE alcCloseDevice; + LPALCGETERROR alcGetError; + LPALCISEXTENSIONPRESENT alcIsExtensionPresent; + LPALCGETPROCADDRESS alcGetProcAddress; + LPALCGETENUMVALUE alcGetEnumValue; + LPALCGETSTRING alcGetString; + LPALCGETINTEGERV alcGetIntegerv; + LPALCCAPTUREOPENDEVICE alcCaptureOpenDevice; + LPALCCAPTURECLOSEDEVICE alcCaptureCloseDevice; + LPALCCAPTURESTART alcCaptureStart; + LPALCCAPTURESTOP alcCaptureStop; + LPALCCAPTURESAMPLES alcCaptureSamples; + + PFNALCSETTHREADCONTEXTPROC alcSetThreadContext; + PFNALCGETTHREADCONTEXTPROC alcGetThreadContext; + + LPALENABLE alEnable; + LPALDISABLE alDisable; + LPALISENABLED alIsEnabled; + LPALGETSTRING alGetString; + LPALGETBOOLEANV alGetBooleanv; + LPALGETINTEGERV alGetIntegerv; + LPALGETFLOATV alGetFloatv; + LPALGETDOUBLEV alGetDoublev; + LPALGETBOOLEAN alGetBoolean; + LPALGETINTEGER alGetInteger; + LPALGETFLOAT alGetFloat; + LPALGETDOUBLE alGetDouble; + LPALGETERROR alGetError; + LPALISEXTENSIONPRESENT alIsExtensionPresent; + LPALGETPROCADDRESS alGetProcAddress; + LPALGETENUMVALUE alGetEnumValue; + LPALLISTENERF alListenerf; + LPALLISTENER3F alListener3f; + LPALLISTENERFV alListenerfv; + LPALLISTENERI alListeneri; + LPALLISTENER3I alListener3i; + LPALLISTENERIV alListeneriv; + LPALGETLISTENERF alGetListenerf; + LPALGETLISTENER3F alGetListener3f; + LPALGETLISTENERFV alGetListenerfv; + LPALGETLISTENERI alGetListeneri; + LPALGETLISTENER3I alGetListener3i; + LPALGETLISTENERIV alGetListeneriv; + LPALGENSOURCES alGenSources; + LPALDELETESOURCES alDeleteSources; + LPALISSOURCE alIsSource; + LPALSOURCEF alSourcef; + LPALSOURCE3F alSource3f; + LPALSOURCEFV alSourcefv; + LPALSOURCEI alSourcei; + LPALSOURCE3I alSource3i; + LPALSOURCEIV alSourceiv; + LPALGETSOURCEF alGetSourcef; + LPALGETSOURCE3F alGetSource3f; + LPALGETSOURCEFV alGetSourcefv; + LPALGETSOURCEI alGetSourcei; + LPALGETSOURCE3I alGetSource3i; + LPALGETSOURCEIV alGetSourceiv; + LPALSOURCEPLAYV alSourcePlayv; + LPALSOURCESTOPV alSourceStopv; + LPALSOURCEREWINDV alSourceRewindv; + LPALSOURCEPAUSEV alSourcePausev; + LPALSOURCEPLAY alSourcePlay; + LPALSOURCESTOP alSourceStop; + LPALSOURCEREWIND alSourceRewind; + LPALSOURCEPAUSE alSourcePause; + LPALSOURCEQUEUEBUFFERS alSourceQueueBuffers; + LPALSOURCEUNQUEUEBUFFERS alSourceUnqueueBuffers; + LPALGENBUFFERS alGenBuffers; + LPALDELETEBUFFERS alDeleteBuffers; + LPALISBUFFER alIsBuffer; + LPALBUFFERF alBufferf; + LPALBUFFER3F alBuffer3f; + LPALBUFFERFV alBufferfv; + LPALBUFFERI alBufferi; + LPALBUFFER3I alBuffer3i; + LPALBUFFERIV alBufferiv; + LPALGETBUFFERF alGetBufferf; + LPALGETBUFFER3F alGetBuffer3f; + LPALGETBUFFERFV alGetBufferfv; + LPALGETBUFFERI alGetBufferi; + LPALGETBUFFER3I alGetBuffer3i; + LPALGETBUFFERIV alGetBufferiv; + LPALBUFFERDATA alBufferData; + LPALDOPPLERFACTOR alDopplerFactor; + LPALDOPPLERVELOCITY alDopplerVelocity; + LPALSPEEDOFSOUND alSpeedOfSound; + LPALDISTANCEMODEL alDistanceModel; +} DriverIface; + +extern DriverIface *DriverList; +extern int DriverListSize; + +extern altss_t ThreadCtxDriver; +extern ATOMIC(DriverIface*) CurrentCtxDriver; + + +typedef struct PtrIntMap { + ALvoid **keys; + /* Shares memory with keys. */ + ALint *values; + + ALsizei size; + ALsizei capacity; + RWLock lock; +} PtrIntMap; +#define PTRINTMAP_STATIC_INITIALIZE { NULL, NULL, 0, 0, RWLOCK_STATIC_INITIALIZE } + +void InitPtrIntMap(PtrIntMap *map); +void ResetPtrIntMap(PtrIntMap *map); +ALenum InsertPtrIntMapEntry(PtrIntMap *map, ALvoid *key, ALint value); +ALint RemovePtrIntMapKey(PtrIntMap *map, ALvoid *key); +ALint LookupPtrIntMapKey(PtrIntMap *map, ALvoid *key); + + +void InitALC(void); +void ReleaseALC(void); + + +enum LogLevel { + LogLevel_None = 0, + LogLevel_Error = 1, + LogLevel_Warn = 2, + LogLevel_Trace = 3, +}; +extern enum LogLevel LogLevel; +extern FILE *LogFile; + +#define TRACE(...) do { \ + if(LogLevel >= LogLevel_Trace) \ + { \ + fprintf(LogFile, "AL Router (II): " __VA_ARGS__); \ + fflush(LogFile); \ + } \ +} while(0) +#define WARN(...) do { \ + if(LogLevel >= LogLevel_Warn) \ + { \ + fprintf(LogFile, "AL Router (WW): " __VA_ARGS__); \ + fflush(LogFile); \ + } \ +} while(0) +#define ERR(...) do { \ + if(LogLevel >= LogLevel_Error) \ + { \ + fprintf(LogFile, "AL Router (EE): " __VA_ARGS__); \ + fflush(LogFile); \ + } \ +} while(0) + +#endif /* ROUTER_ROUTER_H */ diff --git a/love/src/jni/openal-soft-1.17.0/utils/CIAIR.def b/love/src/jni/openal-soft-1.18.2/utils/CIAIR.def similarity index 100% rename from love/src/jni/openal-soft-1.17.0/utils/CIAIR.def rename to love/src/jni/openal-soft-1.18.2/utils/CIAIR.def diff --git a/love/src/jni/openal-soft-1.17.0/utils/IRC_1005.def b/love/src/jni/openal-soft-1.18.2/utils/IRC_1005.def similarity index 100% rename from love/src/jni/openal-soft-1.17.0/utils/IRC_1005.def rename to love/src/jni/openal-soft-1.18.2/utils/IRC_1005.def diff --git a/love/src/jni/openal-soft-1.17.0/utils/MIT_KEMAR.def b/love/src/jni/openal-soft-1.18.2/utils/MIT_KEMAR.def similarity index 100% rename from love/src/jni/openal-soft-1.17.0/utils/MIT_KEMAR.def rename to love/src/jni/openal-soft-1.18.2/utils/MIT_KEMAR.def diff --git a/love/src/jni/openal-soft-1.18.2/utils/alsoft-config/CMakeLists.txt b/love/src/jni/openal-soft-1.18.2/utils/alsoft-config/CMakeLists.txt new file mode 100644 index 00000000..4911b9d8 --- /dev/null +++ b/love/src/jni/openal-soft-1.18.2/utils/alsoft-config/CMakeLists.txt @@ -0,0 +1,56 @@ +project(alsoft-config) + +option(ALSOFT_NO_QT5 "Use Qt4 instead of Qt5 for alsoft-config" FALSE) + +include_directories("${alsoft-config_BINARY_DIR}") + +set(alsoft-config_SRCS main.cpp + mainwindow.cpp +) +set(alsoft-config_UIS mainwindow.ui) +set(alsoft-config_MOCS mainwindow.h) + +find_package(Qt5Widgets) +if(Qt5Widgets_FOUND AND NOT ALSOFT_NO_QT5) + qt5_wrap_ui(UIS ${alsoft-config_UIS}) + + qt5_wrap_cpp(MOCS ${alsoft-config_MOCS}) + + add_executable(alsoft-config ${alsoft-config_SRCS} ${UIS} ${RSCS} ${TRS} ${MOCS}) + target_link_libraries(alsoft-config Qt5::Widgets) + set_property(TARGET alsoft-config APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) + set_target_properties(alsoft-config PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${OpenAL_BINARY_DIR}) + if(TARGET build_version) + add_dependencies(alsoft-config build_version) + endif() + + install(TARGETS alsoft-config + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + ) +else() + # Need Qt 4.8.0 or newer for the iconset theme attribute to work + find_package(Qt4 4.8.0 COMPONENTS QtCore QtGui) + if(QT4_FOUND) + include(${QT_USE_FILE}) + + qt4_wrap_ui(UIS ${alsoft-config_UIS}) + + qt4_wrap_cpp(MOCS ${alsoft-config_MOCS}) + + add_executable(alsoft-config ${alsoft-config_SRCS} ${UIS} ${RSCS} ${TRS} ${MOCS}) + target_link_libraries(alsoft-config ${QT_LIBRARIES}) + set_property(TARGET alsoft-config APPEND PROPERTY COMPILE_FLAGS ${EXTRA_CFLAGS}) + set_target_properties(alsoft-config PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${OpenAL_BINARY_DIR}) + if(TARGET build_version) + add_dependencies(alsoft-config build_version) + endif() + + install(TARGETS alsoft-config + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + ) + endif() +endif() diff --git a/love/src/jni/openal-soft-1.17.0/utils/alsoft-config/main.cpp b/love/src/jni/openal-soft-1.18.2/utils/alsoft-config/main.cpp similarity index 100% rename from love/src/jni/openal-soft-1.17.0/utils/alsoft-config/main.cpp rename to love/src/jni/openal-soft-1.18.2/utils/alsoft-config/main.cpp diff --git a/love/src/jni/openal-soft-1.18.2/utils/alsoft-config/mainwindow.cpp b/love/src/jni/openal-soft-1.18.2/utils/alsoft-config/mainwindow.cpp new file mode 100644 index 00000000..a743ca6a --- /dev/null +++ b/love/src/jni/openal-soft-1.18.2/utils/alsoft-config/mainwindow.cpp @@ -0,0 +1,1364 @@ + +#include "config.h" + +#include "version.h" + +#include +#include + +#include +#include +#include +#include +#include +#include "mainwindow.h" +#include "ui_mainwindow.h" + +namespace { + +static const struct { + char backend_name[16]; + char full_string[32]; +} backendList[] = { +#ifdef HAVE_JACK + { "jack", "JACK" }, +#endif +#ifdef HAVE_PULSEAUDIO + { "pulse", "PulseAudio" }, +#endif +#ifdef HAVE_ALSA + { "alsa", "ALSA" }, +#endif +#ifdef HAVE_COREAUDIO + { "core", "CoreAudio" }, +#endif +#ifdef HAVE_OSS + { "oss", "OSS" }, +#endif +#ifdef HAVE_SOLARIS + { "solaris", "Solaris" }, +#endif +#ifdef HAVE_SNDIO + { "sndio", "SoundIO" }, +#endif +#ifdef HAVE_QSA + { "qsa", "QSA" }, +#endif +#ifdef HAVE_MMDEVAPI + { "mmdevapi", "MMDevAPI" }, +#endif +#ifdef HAVE_DSOUND + { "dsound", "DirectSound" }, +#endif +#ifdef HAVE_WINMM + { "winmm", "Windows Multimedia" }, +#endif +#ifdef HAVE_PORTAUDIO + { "port", "PortAudio" }, +#endif +#ifdef HAVE_OPENSL + { "opensl", "OpenSL" }, +#endif + + { "null", "Null Output" }, +#ifdef HAVE_WAVE + { "wave", "Wave Writer" }, +#endif + { "", "" } +}; + +static const struct NameValuePair { + 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" }, + + { "Ambisonic, 1st Order", "ambi1" }, + { "Ambisonic, 2nd Order", "ambi2" }, + { "Ambisonic, 3rd Order", "ambi3" }, + + { "", "" } +}, 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[] = { + { "Point", "point" }, + { "Linear", "linear" }, + { "Default (Linear)", "" }, + { "4-Point Sinc", "sinc4" }, + { "Band-limited Sinc", "bsinc" }, + + { "", "" } +}, stereoModeList[] = { + { "Autodetect", "" }, + { "Speakers", "speakers" }, + { "Headphones", "headphones" }, + + { "", "" } +}, stereoEncList[] = { + { "Default", "" }, + { "Pan Pot", "panpot" }, + { "UHJ", "uhj" }, + + { "", "" } +}, ambiFormatList[] = { + { "Default", "" }, + { "ACN + SN3D", "acn+sn3d" }, + { "ACN + N3D", "acn+n3d" }, + { "Furse-Malham", "fuma" }, + + { "", "" } +}; + +static QString getDefaultConfigName() +{ +#ifdef Q_OS_WIN32 + static const char fname[] = "alsoft.ini"; + QByteArray base = qgetenv("AppData"); +#else + static const char fname[] = "alsoft.conf"; + QByteArray base = qgetenv("XDG_CONFIG_HOME"); + if(base.isEmpty()) + { + base = qgetenv("HOME"); + if(base.isEmpty() == false) + base += "/.config"; + } +#endif + if(base.isEmpty() == false) + return base +'/'+ fname; + return fname; +} + +static QString getBaseDataPath() +{ +#ifdef Q_OS_WIN32 + QByteArray base = qgetenv("AppData"); +#else + QByteArray base = qgetenv("XDG_DATA_HOME"); + if(base.isEmpty()) + { + base = qgetenv("HOME"); + if(!base.isEmpty()) + base += "/.local/share"; + } +#endif + return base; +} + +static QStringList getAllDataPaths(QString append=QString()) +{ + QStringList list; + list.append(getBaseDataPath()); +#ifdef Q_OS_WIN32 + // TODO: Common AppData path +#else + QString paths = qgetenv("XDG_DATA_DIRS"); + if(paths.isEmpty()) + paths = "/usr/local/share/:/usr/share/"; + list += paths.split(QChar(':'), QString::SkipEmptyParts); +#endif + QStringList::iterator iter = list.begin(); + while(iter != list.end()) + { + if(iter->isEmpty()) + iter = list.erase(iter); + else + { + iter->append(append); + iter++; + } + } + return list; +} + +template +static QString getValueFromName(const NameValuePair (&list)[N], const QString &str) +{ + for(size_t i = 0;i < N-1;i++) + { + if(str == list[i].name) + return list[i].value; + } + return QString(); +} + +template +static QString getNameFromValue(const NameValuePair (&list)[N], const QString &str) +{ + for(size_t i = 0;i < N-1;i++) + { + if(str == list[i].value) + return list[i].name; + } + return QString(); +} + +} + +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow), + mPeriodSizeValidator(NULL), + mPeriodCountValidator(NULL), + mSourceCountValidator(NULL), + mEffectSlotValidator(NULL), + mSourceSendValidator(NULL), + mSampleRateValidator(NULL), + mJackBufferValidator(NULL), + mNeedsSave(false) +{ + 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;stereoModeList[i].name[0];i++) + ui->stereoModeCombo->addItem(stereoModeList[i].name); + ui->stereoModeCombo->adjustSize(); + for(int i = 0;stereoEncList[i].name[0];i++) + ui->stereoEncodingComboBox->addItem(stereoEncList[i].name); + ui->stereoEncodingComboBox->adjustSize(); + for(int i = 0;ambiFormatList[i].name[0];i++) + ui->ambiFormatComboBox->addItem(ambiFormatList[i].name); + ui->ambiFormatComboBox->adjustSize(); + + int count; + for(count = 0;resamplerList[count].name[0];count++) { + } + ui->resamplerSlider->setRange(0, count-1); + + 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); + ui->periodCountEdit->setValidator(mPeriodCountValidator); + + mSourceCountValidator = new QIntValidator(0, 4096, this); + ui->srcCountLineEdit->setValidator(mSourceCountValidator); + mEffectSlotValidator = new QIntValidator(0, 64, this); + ui->effectSlotLineEdit->setValidator(mEffectSlotValidator); + mSourceSendValidator = new QIntValidator(0, 16, this); + ui->srcSendLineEdit->setValidator(mSourceSendValidator); + mSampleRateValidator = new QIntValidator(8000, 192000, this); + ui->sampleRateCombo->lineEdit()->setValidator(mSampleRateValidator); + + mJackBufferValidator = new QIntValidator(0, 8192, this); + ui->jackBufferSizeLine->setValidator(mJackBufferValidator); + + connect(ui->actionLoad, SIGNAL(triggered()), this, SLOT(loadConfigFromFile())); + connect(ui->actionSave_As, SIGNAL(triggered()), this, SLOT(saveConfigAsFile())); + + connect(ui->actionAbout, SIGNAL(triggered()), this, SLOT(showAboutPage())); + + connect(ui->closeCancelButton, SIGNAL(clicked()), this, SLOT(cancelCloseAction())); + connect(ui->applyButton, SIGNAL(clicked()), this, SLOT(saveCurrentConfig())); + + connect(ui->channelConfigCombo, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton())); + connect(ui->sampleFormatCombo, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton())); + connect(ui->stereoModeCombo, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton())); + connect(ui->sampleRateCombo, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton())); + connect(ui->sampleRateCombo, SIGNAL(editTextChanged(const QString&)), this, SLOT(enableApplyButton())); + + connect(ui->resamplerSlider, SIGNAL(valueChanged(int)), this, SLOT(updateResamplerLabel(int))); + + connect(ui->periodSizeSlider, SIGNAL(valueChanged(int)), this, SLOT(updatePeriodSizeEdit(int))); + connect(ui->periodSizeEdit, SIGNAL(editingFinished()), this, SLOT(updatePeriodSizeSlider())); + connect(ui->periodCountSlider, SIGNAL(valueChanged(int)), this, SLOT(updatePeriodCountEdit(int))); + connect(ui->periodCountEdit, SIGNAL(editingFinished()), this, SLOT(updatePeriodCountSlider())); + + connect(ui->stereoEncodingComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(enableApplyButton())); + connect(ui->ambiFormatComboBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(enableApplyButton())); + connect(ui->outputLimiterCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->outputDitherCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + + connect(ui->decoderHQModeCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->decoderDistCompCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->decoderNFEffectsCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->decoderNFRefDelaySpinBox, SIGNAL(valueChanged(double)), this, SLOT(enableApplyButton())); + connect(ui->decoderQuadLineEdit, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); + connect(ui->decoderQuadButton, SIGNAL(clicked()), this, SLOT(selectQuadDecoderFile())); + connect(ui->decoder51LineEdit, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); + connect(ui->decoder51Button, SIGNAL(clicked()), this, SLOT(select51DecoderFile())); + connect(ui->decoder61LineEdit, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); + connect(ui->decoder61Button, SIGNAL(clicked()), this, SLOT(select61DecoderFile())); + connect(ui->decoder71LineEdit, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); + connect(ui->decoder71Button, SIGNAL(clicked()), this, SLOT(select71DecoderFile())); + + connect(ui->preferredHrtfComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton())); + connect(ui->hrtfStateComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton())); + connect(ui->hrtfAddButton, SIGNAL(clicked()), this, SLOT(addHrtfFile())); + connect(ui->hrtfRemoveButton, SIGNAL(clicked()), this, SLOT(removeHrtfFile())); + connect(ui->hrtfFileList, SIGNAL(itemSelectionChanged()), this, SLOT(updateHrtfRemoveButton())); + connect(ui->defaultHrtfPathsCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + + connect(ui->srcCountLineEdit, SIGNAL(editingFinished()), this, SLOT(enableApplyButton())); + connect(ui->srcSendLineEdit, SIGNAL(editingFinished()), this, SLOT(enableApplyButton())); + connect(ui->effectSlotLineEdit, SIGNAL(editingFinished()), this, SLOT(enableApplyButton())); + + connect(ui->enableSSECheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->enableSSE2CheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->enableSSE3CheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->enableSSE41CheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->enableNeonCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + + ui->enabledBackendList->setContextMenuPolicy(Qt::CustomContextMenu); + connect(ui->enabledBackendList, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showEnabledBackendMenu(QPoint))); + + ui->disabledBackendList->setContextMenuPolicy(Qt::CustomContextMenu); + connect(ui->disabledBackendList, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showDisabledBackendMenu(QPoint))); + connect(ui->backendCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + + connect(ui->defaultReverbComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton())); + connect(ui->emulateEaxCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->enableEaxReverbCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->enableStdReverbCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->enableChorusCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->enableCompressorCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->enableDistortionCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->enableEchoCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->enableEqualizerCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->enableFlangerCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->enableModulatorCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->enableDedicatedCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + + connect(ui->pulseAutospawnCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->pulseAllowMovesCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->pulseFixRateCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + + connect(ui->jackAutospawnCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->jackBufferSizeSlider, SIGNAL(valueChanged(int)), this, SLOT(updateJackBufferSizeEdit(int))); + connect(ui->jackBufferSizeLine, SIGNAL(editingFinished()), this, SLOT(updateJackBufferSizeSlider())); + + connect(ui->alsaDefaultDeviceLine, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); + connect(ui->alsaDefaultCaptureLine, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); + connect(ui->alsaResamplerCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + connect(ui->alsaMmapCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + + connect(ui->ossDefaultDeviceLine, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); + connect(ui->ossPlaybackPushButton, SIGNAL(clicked(bool)), this, SLOT(selectOSSPlayback())); + connect(ui->ossDefaultCaptureLine, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); + connect(ui->ossCapturePushButton, SIGNAL(clicked(bool)), this, SLOT(selectOSSCapture())); + + connect(ui->solarisDefaultDeviceLine, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); + connect(ui->solarisPlaybackPushButton, SIGNAL(clicked(bool)), this, SLOT(selectSolarisPlayback())); + + connect(ui->waveOutputLine, SIGNAL(textChanged(QString)), this, SLOT(enableApplyButton())); + connect(ui->waveOutputButton, SIGNAL(clicked(bool)), this, SLOT(selectWaveOutput())); + connect(ui->waveBFormatCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton())); + + ui->backendListWidget->setCurrentRow(0); + ui->tabWidget->setCurrentIndex(0); + + for(int i = 1;i < ui->backendListWidget->count();i++) + ui->backendListWidget->setRowHidden(i, true); + for(int i = 0;backendList[i].backend_name[0];i++) + { + QList items = ui->backendListWidget->findItems( + backendList[i].full_string, Qt::MatchFixedString + ); + foreach(const QListWidgetItem *item, items) + ui->backendListWidget->setItemHidden(item, false); + } + + loadConfig(getDefaultConfigName()); +} + +MainWindow::~MainWindow() +{ + delete ui; + delete mPeriodSizeValidator; + delete mPeriodCountValidator; + delete mSourceCountValidator; + delete mEffectSlotValidator; + delete mSourceSendValidator; + delete mSampleRateValidator; + delete mJackBufferValidator; +} + +void MainWindow::closeEvent(QCloseEvent *event) +{ + if(!mNeedsSave) + event->accept(); + else + { + QMessageBox::StandardButton btn = QMessageBox::warning(this, + tr("Apply changes?"), tr("Save changes before quitting?"), + QMessageBox::Save | QMessageBox::No | QMessageBox::Cancel + ); + if(btn == QMessageBox::Save) + saveCurrentConfig(); + if(btn == QMessageBox::Cancel) + event->ignore(); + else + event->accept(); + } +} + +void MainWindow::cancelCloseAction() +{ + mNeedsSave = false; + close(); +} + + +void MainWindow::showAboutPage() +{ + QMessageBox::information(this, tr("About"), + tr("OpenAL Soft Configuration Utility.\nBuilt for OpenAL Soft library version ")+ + (ALSOFT_VERSION "-" ALSOFT_GIT_COMMIT_HASH " (" ALSOFT_GIT_BRANCH " branch).") + ); +} + + +QStringList MainWindow::collectHrtfs() +{ + QStringList ret; + QStringList processed; + + for(int i = 0;i < ui->hrtfFileList->count();i++) + { + QDir dir(ui->hrtfFileList->item(i)->text()); + QStringList fnames = dir.entryList(QDir::Files | QDir::Readable, QDir::Name); + foreach(const QString &fname, fnames) + { + if(!fname.endsWith(".mhr", Qt::CaseInsensitive)) + continue; + QString fullname = dir.absoluteFilePath(fname); + if(processed.contains(fullname)) + continue; + processed.push_back(fullname); + + QString name = fname.left(fname.length()-4); + if(!ret.contains(name)) + ret.push_back(name); + else + { + size_t i = 2; + do { + QString s = name+" #"+QString::number(i); + if(!ret.contains(s)) + { + ret.push_back(s); + break; + } + ++i; + } while(1); + } + } + } + + if(ui->defaultHrtfPathsCheckBox->isChecked()) + { + QStringList paths = getAllDataPaths("/openal/hrtf"); + foreach(const QString &name, paths) + { + QDir dir(name); + QStringList fnames = dir.entryList(QDir::Files | QDir::Readable, QDir::Name); + foreach(const QString &fname, fnames) + { + if(!fname.endsWith(".mhr", Qt::CaseInsensitive)) + continue; + QString fullname = dir.absoluteFilePath(fname); + if(processed.contains(fullname)) + continue; + processed.push_back(fullname); + + QString name = fname.left(fname.length()-4); + if(!ret.contains(name)) + ret.push_back(name); + else + { + size_t i = 2; + do { + QString s = name+" #"+QString::number(i); + if(!ret.contains(s)) + { + ret.push_back(s); + break; + } + ++i; + } while(1); + } + } + } + +#ifdef ALSOFT_EMBED_HRTF_DATA + ret.push_back("Built-In 44100hz"); + ret.push_back("Built-In 48000hz"); +#endif + } + return ret; +} + + +void MainWindow::loadConfigFromFile() +{ + QString fname = QFileDialog::getOpenFileName(this, tr("Select Files")); + if(fname.isEmpty() == false) + loadConfig(fname); +} + +void MainWindow::loadConfig(const QString &fname) +{ + QSettings settings(fname, QSettings::IniFormat); + + QString sampletype = settings.value("sample-type").toString(); + ui->sampleFormatCombo->setCurrentIndex(0); + if(sampletype.isEmpty() == false) + { + QString str = getNameFromValue(sampleTypeList, sampletype); + if(!str.isEmpty()) + { + int j = ui->sampleFormatCombo->findText(str); + if(j > 0) ui->sampleFormatCombo->setCurrentIndex(j); + } + } + + QString channelconfig = settings.value("channels").toString(); + ui->channelConfigCombo->setCurrentIndex(0); + if(channelconfig.isEmpty() == false) + { + QString str = getNameFromValue(speakerModeList, channelconfig); + if(!str.isEmpty()) + { + int j = ui->channelConfigCombo->findText(str); + if(j > 0) ui->channelConfigCombo->setCurrentIndex(j); + } + } + + QString srate = settings.value("frequency").toString(); + if(srate.isEmpty()) + ui->sampleRateCombo->setCurrentIndex(0); + else + { + ui->sampleRateCombo->lineEdit()->clear(); + ui->sampleRateCombo->lineEdit()->insert(srate); + } + + ui->srcCountLineEdit->clear(); + ui->srcCountLineEdit->insert(settings.value("sources").toString()); + ui->effectSlotLineEdit->clear(); + ui->effectSlotLineEdit->insert(settings.value("slots").toString()); + ui->srcSendLineEdit->clear(); + ui->srcSendLineEdit->insert(settings.value("sends").toString()); + + QString resampler = settings.value("resampler").toString().trimmed(); + ui->resamplerSlider->setValue(2); + ui->resamplerLabel->setText(resamplerList[2].name); + /* The "cubic" and "sinc8" resamplers are no longer supported. Use "sinc4" + * as a fallback. + */ + if(resampler == "cubic" || resampler == "sinc8") + resampler = "sinc4"; + for(int i = 0;resamplerList[i].name[0];i++) + { + if(resampler == resamplerList[i].value) + { + ui->resamplerSlider->setValue(i); + ui->resamplerLabel->setText(resamplerList[i].name); + break; + } + } + + QString stereomode = settings.value("stereo-mode").toString().trimmed(); + ui->stereoModeCombo->setCurrentIndex(0); + if(stereomode.isEmpty() == false) + { + QString str = getNameFromValue(stereoModeList, stereomode); + if(!str.isEmpty()) + { + int j = ui->stereoModeCombo->findText(str); + if(j > 0) ui->stereoModeCombo->setCurrentIndex(j); + } + } + + int periodsize = settings.value("period_size").toInt(); + ui->periodSizeEdit->clear(); + if(periodsize >= 64) + { + ui->periodSizeEdit->insert(QString::number(periodsize)); + updatePeriodSizeSlider(); + } + + int periodcount = settings.value("periods").toInt(); + ui->periodCountEdit->clear(); + if(periodcount >= 2) + { + ui->periodCountEdit->insert(QString::number(periodcount)); + updatePeriodCountSlider(); + } + + if(settings.value("output-limiter").isNull()) + ui->outputLimiterCheckBox->setCheckState(Qt::PartiallyChecked); + else + ui->outputLimiterCheckBox->setCheckState( + settings.value("output-limiter").toBool() ? Qt::Checked : Qt::Unchecked + ); + + if(settings.value("dither").isNull()) + ui->outputDitherCheckBox->setCheckState(Qt::PartiallyChecked); + else + ui->outputDitherCheckBox->setCheckState( + settings.value("dither").toBool() ? Qt::Checked : Qt::Unchecked + ); + + QString stereopan = settings.value("stereo-encoding").toString(); + ui->stereoEncodingComboBox->setCurrentIndex(0); + if(stereopan.isEmpty() == false) + { + QString str = getNameFromValue(stereoEncList, stereopan); + if(!str.isEmpty()) + { + int j = ui->stereoEncodingComboBox->findText(str); + if(j > 0) ui->stereoEncodingComboBox->setCurrentIndex(j); + } + } + + QString ambiformat = settings.value("ambi-format").toString(); + ui->ambiFormatComboBox->setCurrentIndex(0); + if(ambiformat.isEmpty() == false) + { + QString str = getNameFromValue(ambiFormatList, ambiformat); + if(!str.isEmpty()) + { + int j = ui->ambiFormatComboBox->findText(str); + if(j > 0) ui->ambiFormatComboBox->setCurrentIndex(j); + } + } + + bool hqmode = settings.value("decoder/hq-mode", false).toBool(); + ui->decoderHQModeCheckBox->setChecked(hqmode); + bool distcomp = settings.value("decoder/distance-comp", true).toBool(); + ui->decoderDistCompCheckBox->setChecked(distcomp); + bool nfeffects = settings.value("decoder/nfc", true).toBool(); + ui->decoderNFEffectsCheckBox->setChecked(nfeffects); + double refdelay = settings.value("decoder/nfc-ref-delay", 0.0).toDouble(); + ui->decoderNFRefDelaySpinBox->setValue(refdelay); + + ui->decoderQuadLineEdit->setText(settings.value("decoder/quad").toString()); + ui->decoder51LineEdit->setText(settings.value("decoder/surround51").toString()); + ui->decoder61LineEdit->setText(settings.value("decoder/surround61").toString()); + ui->decoder71LineEdit->setText(settings.value("decoder/surround71").toString()); + + QStringList disabledCpuExts = settings.value("disable-cpu-exts").toStringList(); + if(disabledCpuExts.size() == 1) + disabledCpuExts = disabledCpuExts[0].split(QChar(',')); + for(QStringList::iterator iter = disabledCpuExts.begin();iter != disabledCpuExts.end();iter++) + *iter = iter->trimmed(); + 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)); + + QStringList hrtf_paths = settings.value("hrtf-paths").toStringList(); + if(hrtf_paths.size() == 1) + hrtf_paths = hrtf_paths[0].split(QChar(',')); + for(QStringList::iterator iter = hrtf_paths.begin();iter != hrtf_paths.end();iter++) + *iter = iter->trimmed(); + if(!hrtf_paths.empty() && !hrtf_paths.back().isEmpty()) + ui->defaultHrtfPathsCheckBox->setCheckState(Qt::Unchecked); + else + { + hrtf_paths.removeAll(QString()); + ui->defaultHrtfPathsCheckBox->setCheckState(Qt::Checked); + } + hrtf_paths.removeDuplicates(); + ui->hrtfFileList->clear(); + ui->hrtfFileList->addItems(hrtf_paths); + updateHrtfRemoveButton(); + + QString hrtfstate = settings.value("hrtf").toString().toLower(); + if(hrtfstate == "true") + ui->hrtfStateComboBox->setCurrentIndex(1); + else if(hrtfstate == "false") + ui->hrtfStateComboBox->setCurrentIndex(2); + else + ui->hrtfStateComboBox->setCurrentIndex(0); + + ui->preferredHrtfComboBox->clear(); + ui->preferredHrtfComboBox->addItem("- Any -"); + if(ui->defaultHrtfPathsCheckBox->isChecked()) + { + QStringList hrtfs = collectHrtfs(); + foreach(const QString &name, hrtfs) + ui->preferredHrtfComboBox->addItem(name); + } + + QString defaulthrtf = settings.value("default-hrtf").toString(); + ui->preferredHrtfComboBox->setCurrentIndex(0); + if(defaulthrtf.isEmpty() == false) + { + int i = ui->preferredHrtfComboBox->findText(defaulthrtf); + if(i > 0) + ui->preferredHrtfComboBox->setCurrentIndex(i); + else + { + i = ui->preferredHrtfComboBox->count(); + ui->preferredHrtfComboBox->addItem(defaulthrtf); + ui->preferredHrtfComboBox->setCurrentIndex(i); + } + } + ui->preferredHrtfComboBox->adjustSize(); + + ui->enabledBackendList->clear(); + ui->disabledBackendList->clear(); + QStringList drivers = settings.value("drivers").toStringList(); + if(drivers.size() == 0) + ui->backendCheckBox->setChecked(true); + else + { + if(drivers.size() == 1) + drivers = drivers[0].split(QChar(',')); + for(QStringList::iterator iter = drivers.begin();iter != drivers.end();iter++) + *iter = iter->trimmed(); + + bool lastWasEmpty = false; + foreach(const QString &backend, drivers) + { + lastWasEmpty = backend.isEmpty(); + if(lastWasEmpty) continue; + + if(!backend.startsWith(QChar('-'))) + for(int j = 0;backendList[j].backend_name[0];j++) + { + if(backend == backendList[j].backend_name) + { + ui->enabledBackendList->addItem(backendList[j].full_string); + break; + } + } + else if(backend.size() > 1) + { + QStringRef backendref = backend.rightRef(backend.size()-1); + for(int j = 0;backendList[j].backend_name[0];j++) + { + if(backendref == backendList[j].backend_name) + { + ui->disabledBackendList->addItem(backendList[j].full_string); + break; + } + } + } + } + ui->backendCheckBox->setChecked(lastWasEmpty); + } + + QString defaultreverb = settings.value("default-reverb").toString().toLower(); + ui->defaultReverbComboBox->setCurrentIndex(0); + if(defaultreverb.isEmpty() == false) + { + for(int i = 0;i < ui->defaultReverbComboBox->count();i++) + { + if(defaultreverb.compare(ui->defaultReverbComboBox->itemText(i).toLower()) == 0) + { + ui->defaultReverbComboBox->setCurrentIndex(i); + break; + } + } + } + + ui->emulateEaxCheckBox->setChecked(settings.value("reverb/emulate-eax", false).toBool()); + + QStringList excludefx = settings.value("excludefx").toStringList(); + if(excludefx.size() == 1) + excludefx = excludefx[0].split(QChar(',')); + for(QStringList::iterator iter = excludefx.begin();iter != excludefx.end();iter++) + *iter = iter->trimmed(); + ui->enableEaxReverbCheck->setChecked(!excludefx.contains("eaxreverb", Qt::CaseInsensitive)); + ui->enableStdReverbCheck->setChecked(!excludefx.contains("reverb", Qt::CaseInsensitive)); + ui->enableChorusCheck->setChecked(!excludefx.contains("chorus", Qt::CaseInsensitive)); + ui->enableCompressorCheck->setChecked(!excludefx.contains("compressor", Qt::CaseInsensitive)); + ui->enableDistortionCheck->setChecked(!excludefx.contains("distortion", Qt::CaseInsensitive)); + ui->enableEchoCheck->setChecked(!excludefx.contains("echo", Qt::CaseInsensitive)); + ui->enableEqualizerCheck->setChecked(!excludefx.contains("equalizer", Qt::CaseInsensitive)); + ui->enableFlangerCheck->setChecked(!excludefx.contains("flanger", Qt::CaseInsensitive)); + ui->enableModulatorCheck->setChecked(!excludefx.contains("modulator", Qt::CaseInsensitive)); + ui->enableDedicatedCheck->setChecked(!excludefx.contains("dedicated", Qt::CaseInsensitive)); + + ui->pulseAutospawnCheckBox->setChecked(settings.value("pulse/spawn-server", true).toBool()); + ui->pulseAllowMovesCheckBox->setChecked(settings.value("pulse/allow-moves", false).toBool()); + ui->pulseFixRateCheckBox->setChecked(settings.value("pulse/fix-rate", false).toBool()); + + ui->jackAutospawnCheckBox->setChecked(settings.value("jack/spawn-server", false).toBool()); + ui->jackBufferSizeLine->setText(settings.value("jack/buffer-size", QString()).toString()); + updateJackBufferSizeSlider(); + + ui->alsaDefaultDeviceLine->setText(settings.value("alsa/device", QString()).toString()); + ui->alsaDefaultCaptureLine->setText(settings.value("alsa/capture", QString()).toString()); + ui->alsaResamplerCheckBox->setChecked(settings.value("alsa/allow-resampler", false).toBool()); + ui->alsaMmapCheckBox->setChecked(settings.value("alsa/mmap", true).toBool()); + + ui->ossDefaultDeviceLine->setText(settings.value("oss/device", QString()).toString()); + ui->ossDefaultCaptureLine->setText(settings.value("oss/capture", QString()).toString()); + + ui->solarisDefaultDeviceLine->setText(settings.value("solaris/device", QString()).toString()); + + ui->waveOutputLine->setText(settings.value("wave/file", QString()).toString()); + ui->waveBFormatCheckBox->setChecked(settings.value("wave/bformat", false).toBool()); + + ui->applyButton->setEnabled(false); + ui->closeCancelButton->setText(tr("Close")); + mNeedsSave = false; +} + +void MainWindow::saveCurrentConfig() +{ + saveConfig(getDefaultConfigName()); + ui->applyButton->setEnabled(false); + ui->closeCancelButton->setText(tr("Close")); + mNeedsSave = false; + QMessageBox::information(this, tr("Information"), + tr("Applications using OpenAL need to be restarted for changes to take effect.")); +} + +void MainWindow::saveConfigAsFile() +{ + QString fname = QFileDialog::getOpenFileName(this, tr("Select Files")); + if(fname.isEmpty() == false) + { + saveConfig(fname); + ui->applyButton->setEnabled(false); + mNeedsSave = false; + } +} + +void MainWindow::saveConfig(const QString &fname) const +{ + QSettings settings(fname, QSettings::IniFormat); + + /* HACK: Compound any stringlist values into a comma-separated string. */ + QStringList allkeys = settings.allKeys(); + foreach(const QString &key, allkeys) + { + QStringList vals = settings.value(key).toStringList(); + if(vals.size() > 1) + settings.setValue(key, vals.join(QChar(','))); + } + + settings.setValue("sample-type", getValueFromName(sampleTypeList, ui->sampleFormatCombo->currentText())); + settings.setValue("channels", getValueFromName(speakerModeList, ui->channelConfigCombo->currentText())); + + uint rate = ui->sampleRateCombo->currentText().toUInt(); + if(!(rate > 0)) + settings.setValue("frequency", QString()); + else + settings.setValue("frequency", rate); + + settings.setValue("period_size", ui->periodSizeEdit->text()); + settings.setValue("periods", ui->periodCountEdit->text()); + + settings.setValue("sources", ui->srcCountLineEdit->text()); + settings.setValue("slots", ui->effectSlotLineEdit->text()); + + settings.setValue("resampler", resamplerList[ui->resamplerSlider->value()].value); + + settings.setValue("stereo-mode", getValueFromName(stereoModeList, ui->stereoModeCombo->currentText())); + settings.setValue("stereo-encoding", getValueFromName(stereoEncList, ui->stereoEncodingComboBox->currentText())); + settings.setValue("ambi-format", getValueFromName(ambiFormatList, ui->ambiFormatComboBox->currentText())); + + Qt::CheckState limiter = ui->outputLimiterCheckBox->checkState(); + if(limiter == Qt::PartiallyChecked) + settings.setValue("output-limiter", QString()); + else if(limiter == Qt::Checked) + settings.setValue("output-limiter", QString("true")); + else if(limiter == Qt::Unchecked) + settings.setValue("output-limiter", QString("false")); + + Qt::CheckState dither = ui->outputDitherCheckBox->checkState(); + if(dither == Qt::PartiallyChecked) + settings.setValue("dither", QString()); + else if(dither == Qt::Checked) + settings.setValue("dither", QString("true")); + else if(dither == Qt::Unchecked) + settings.setValue("dither", QString("false")); + + settings.setValue("decoder/hq-mode", + ui->decoderHQModeCheckBox->isChecked() ? QString("true") : QString(/*"false"*/) + ); + settings.setValue("decoder/distance-comp", + ui->decoderDistCompCheckBox->isChecked() ? QString(/*"true"*/) : QString("false") + ); + settings.setValue("decoder/nfc", + ui->decoderNFEffectsCheckBox->isChecked() ? QString(/*"true"*/) : QString("false") + ); + double refdelay = ui->decoderNFRefDelaySpinBox->value(); + settings.setValue("decoder/nfc-ref-delay", + (refdelay > 0.0) ? QString::number(refdelay) : QString() + ); + + settings.setValue("decoder/quad", ui->decoderQuadLineEdit->text()); + settings.setValue("decoder/surround51", ui->decoder51LineEdit->text()); + settings.setValue("decoder/surround61", ui->decoder61LineEdit->text()); + settings.setValue("decoder/surround71", ui->decoder71LineEdit->text()); + + QStringList strlist; + if(!ui->enableSSECheckBox->isChecked()) + 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->hrtfStateComboBox->currentIndex() == 1) + settings.setValue("hrtf", "true"); + else if(ui->hrtfStateComboBox->currentIndex() == 2) + settings.setValue("hrtf", "false"); + else + settings.setValue("hrtf", QString()); + + if(ui->preferredHrtfComboBox->currentIndex() == 0) + settings.setValue("default-hrtf", QString()); + else + { + QString str = ui->preferredHrtfComboBox->currentText(); + settings.setValue("default-hrtf", str); + } + + strlist.clear(); + for(int i = 0;i < ui->hrtfFileList->count();i++) + strlist.append(ui->hrtfFileList->item(i)->text()); + if(!strlist.empty() && ui->defaultHrtfPathsCheckBox->isChecked()) + strlist.append(QString()); + settings.setValue("hrtf-paths", strlist.join(QChar(','))); + + strlist.clear(); + for(int i = 0;i < ui->enabledBackendList->count();i++) + { + QString label = ui->enabledBackendList->item(i)->text(); + for(int j = 0;backendList[j].backend_name[0];j++) + { + if(label == backendList[j].full_string) + { + strlist.append(backendList[j].backend_name); + break; + } + } + } + for(int i = 0;i < ui->disabledBackendList->count();i++) + { + QString label = ui->disabledBackendList->item(i)->text(); + for(int j = 0;backendList[j].backend_name[0];j++) + { + if(label == backendList[j].full_string) + { + strlist.append(QChar('-')+QString(backendList[j].backend_name)); + break; + } + } + } + if(strlist.size() == 0 && !ui->backendCheckBox->isChecked()) + strlist.append("-all"); + else if(ui->backendCheckBox->isChecked()) + strlist.append(QString()); + settings.setValue("drivers", strlist.join(QChar(','))); + + // TODO: Remove check when we can properly match global values. + if(ui->defaultReverbComboBox->currentIndex() == 0) + settings.setValue("default-reverb", QString()); + else + { + QString str = ui->defaultReverbComboBox->currentText().toLower(); + settings.setValue("default-reverb", str); + } + + if(ui->emulateEaxCheckBox->isChecked()) + settings.setValue("reverb/emulate-eax", "true"); + else + settings.remove("reverb/emulate-eax"/*, "false"*/); + + strlist.clear(); + if(!ui->enableEaxReverbCheck->isChecked()) + strlist.append("eaxreverb"); + if(!ui->enableStdReverbCheck->isChecked()) + strlist.append("reverb"); + if(!ui->enableChorusCheck->isChecked()) + strlist.append("chorus"); + if(!ui->enableDistortionCheck->isChecked()) + strlist.append("distortion"); + if(!ui->enableCompressorCheck->isChecked()) + strlist.append("compressor"); + if(!ui->enableEchoCheck->isChecked()) + strlist.append("echo"); + if(!ui->enableEqualizerCheck->isChecked()) + strlist.append("equalizer"); + if(!ui->enableFlangerCheck->isChecked()) + strlist.append("flanger"); + if(!ui->enableModulatorCheck->isChecked()) + strlist.append("modulator"); + if(!ui->enableDedicatedCheck->isChecked()) + strlist.append("dedicated"); + settings.setValue("excludefx", strlist.join(QChar(','))); + + settings.setValue("pulse/spawn-server", + ui->pulseAutospawnCheckBox->isChecked() ? QString(/*"true"*/) : QString("false") + ); + settings.setValue("pulse/allow-moves", + ui->pulseAllowMovesCheckBox->isChecked() ? QString("true") : QString(/*"false"*/) + ); + settings.setValue("pulse/fix-rate", + ui->pulseFixRateCheckBox->isChecked() ? QString("true") : QString(/*"false"*/) + ); + + settings.setValue("jack/spawn-server", + ui->jackAutospawnCheckBox->isChecked() ? QString("true") : QString(/*"false"*/) + ); + settings.setValue("jack/buffer-size", ui->jackBufferSizeLine->text()); + + settings.setValue("alsa/device", ui->alsaDefaultDeviceLine->text()); + settings.setValue("alsa/capture", ui->alsaDefaultCaptureLine->text()); + settings.setValue("alsa/allow-resampler", + ui->alsaResamplerCheckBox->isChecked() ? QString("true") : QString(/*"false"*/) + ); + settings.setValue("alsa/mmap", + ui->alsaMmapCheckBox->isChecked() ? QString(/*"true"*/) : QString("false") + ); + + settings.setValue("oss/device", ui->ossDefaultDeviceLine->text()); + settings.setValue("oss/capture", ui->ossDefaultCaptureLine->text()); + + settings.setValue("solaris/device", ui->solarisDefaultDeviceLine->text()); + + settings.setValue("wave/file", ui->waveOutputLine->text()); + settings.setValue("wave/bformat", + ui->waveBFormatCheckBox->isChecked() ? QString("true") : QString(/*"false"*/) + ); + + /* Remove empty keys + * FIXME: Should only remove keys whose value matches the globally-specified value. + */ + allkeys = settings.allKeys(); + foreach(const QString &key, allkeys) + { + QString str = settings.value(key).toString(); + if(str == QString()) + settings.remove(key); + } +} + + +void MainWindow::enableApplyButton() +{ + if(!mNeedsSave) + ui->applyButton->setEnabled(true); + mNeedsSave = true; + ui->closeCancelButton->setText(tr("Cancel")); +} + + +void MainWindow::updateResamplerLabel(int num) +{ + ui->resamplerLabel->setText(resamplerList[num].name); + enableApplyButton(); +} + + +void MainWindow::updatePeriodSizeEdit(int size) +{ + ui->periodSizeEdit->clear(); + if(size >= 64) + { + size = (size+32)&~0x3f; + ui->periodSizeEdit->insert(QString::number(size)); + } + enableApplyButton(); +} + +void MainWindow::updatePeriodSizeSlider() +{ + int pos = ui->periodSizeEdit->text().toInt(); + if(pos >= 64) + { + if(pos > 8192) + pos = 8192; + ui->periodSizeSlider->setSliderPosition(pos); + } + enableApplyButton(); +} + +void MainWindow::updatePeriodCountEdit(int count) +{ + ui->periodCountEdit->clear(); + if(count >= 2) + ui->periodCountEdit->insert(QString::number(count)); + enableApplyButton(); +} + +void MainWindow::updatePeriodCountSlider() +{ + int pos = ui->periodCountEdit->text().toInt(); + if(pos < 2) + pos = 0; + else if(pos > 16) + pos = 16; + ui->periodCountSlider->setSliderPosition(pos); + enableApplyButton(); +} + + +void MainWindow::selectQuadDecoderFile() +{ selectDecoderFile(ui->decoderQuadLineEdit, "Select Quadrophonic Decoder");} +void MainWindow::select51DecoderFile() +{ selectDecoderFile(ui->decoder51LineEdit, "Select 5.1 Surround Decoder");} +void MainWindow::select61DecoderFile() +{ selectDecoderFile(ui->decoder61LineEdit, "Select 6.1 Surround Decoder");} +void MainWindow::select71DecoderFile() +{ selectDecoderFile(ui->decoder71LineEdit, "Select 7.1 Surround Decoder");} +void MainWindow::selectDecoderFile(QLineEdit *line, const char *caption) +{ + QString dir = line->text(); + if(dir.isEmpty() || QDir::isRelativePath(dir)) + { + QStringList paths = getAllDataPaths("/openal/presets"); + while(!paths.isEmpty()) + { + if(QDir(paths.last()).exists()) + { + dir = paths.last(); + break; + } + paths.removeLast(); + } + } + QString fname = QFileDialog::getOpenFileName(this, tr(caption), + dir, tr("AmbDec Files (*.ambdec);;All Files (*.*)") + ); + if(!fname.isEmpty()) + { + line->setText(fname); + enableApplyButton(); + } +} + + +void MainWindow::updateJackBufferSizeEdit(int size) +{ + ui->jackBufferSizeLine->clear(); + if(size > 0) + ui->jackBufferSizeLine->insert(QString::number(1<jackBufferSizeLine->text().toInt(); + int pos = (int)floor(log2(value) + 0.5); + ui->jackBufferSizeSlider->setSliderPosition(pos); + enableApplyButton(); +} + + +void MainWindow::addHrtfFile() +{ + QString path = QFileDialog::getExistingDirectory(this, tr("Select HRTF Path")); + if(path.isEmpty() == false && !getAllDataPaths("/openal/hrtf").contains(path)) + { + ui->hrtfFileList->addItem(path); + enableApplyButton(); + } +} + +void MainWindow::removeHrtfFile() +{ + QList selected = ui->hrtfFileList->selectedItems(); + if(!selected.isEmpty()) + { + foreach(QListWidgetItem *item, selected) + delete item; + enableApplyButton(); + } +} + +void MainWindow::updateHrtfRemoveButton() +{ + ui->hrtfRemoveButton->setEnabled(ui->hrtfFileList->selectedItems().size() != 0); +} + +void MainWindow::showEnabledBackendMenu(QPoint pt) +{ + QMap actionMap; + + pt = ui->enabledBackendList->mapToGlobal(pt); + + QMenu ctxmenu; + QAction *removeAction = ctxmenu.addAction(QIcon::fromTheme("list-remove"), "Remove"); + if(ui->enabledBackendList->selectedItems().size() == 0) + removeAction->setEnabled(false); + ctxmenu.addSeparator(); + for(size_t i = 0;backendList[i].backend_name[0];i++) + { + QString backend = backendList[i].full_string; + QAction *action = ctxmenu.addAction(QString("Add ")+backend); + actionMap[action] = backend; + if(ui->enabledBackendList->findItems(backend, Qt::MatchFixedString).size() != 0 || + ui->disabledBackendList->findItems(backend, Qt::MatchFixedString).size() != 0) + action->setEnabled(false); + } + + QAction *gotAction = ctxmenu.exec(pt); + if(gotAction == removeAction) + { + QList selected = ui->enabledBackendList->selectedItems(); + foreach(QListWidgetItem *item, selected) + delete item; + enableApplyButton(); + } + else if(gotAction != NULL) + { + QMap::const_iterator iter = actionMap.find(gotAction); + if(iter != actionMap.end()) + ui->enabledBackendList->addItem(iter.value()); + enableApplyButton(); + } +} + +void MainWindow::showDisabledBackendMenu(QPoint pt) +{ + QMap actionMap; + + pt = ui->disabledBackendList->mapToGlobal(pt); + + QMenu ctxmenu; + QAction *removeAction = ctxmenu.addAction(QIcon::fromTheme("list-remove"), "Remove"); + if(ui->disabledBackendList->selectedItems().size() == 0) + removeAction->setEnabled(false); + ctxmenu.addSeparator(); + for(size_t i = 0;backendList[i].backend_name[0];i++) + { + QString backend = backendList[i].full_string; + QAction *action = ctxmenu.addAction(QString("Add ")+backend); + actionMap[action] = backend; + if(ui->disabledBackendList->findItems(backend, Qt::MatchFixedString).size() != 0 || + ui->enabledBackendList->findItems(backend, Qt::MatchFixedString).size() != 0) + action->setEnabled(false); + } + + QAction *gotAction = ctxmenu.exec(pt); + if(gotAction == removeAction) + { + QList selected = ui->disabledBackendList->selectedItems(); + foreach(QListWidgetItem *item, selected) + delete item; + enableApplyButton(); + } + else if(gotAction != NULL) + { + QMap::const_iterator iter = actionMap.find(gotAction); + if(iter != actionMap.end()) + ui->disabledBackendList->addItem(iter.value()); + enableApplyButton(); + } +} + +void MainWindow::selectOSSPlayback() +{ + QString current = ui->ossDefaultDeviceLine->text(); + if(current.isEmpty()) current = ui->ossDefaultDeviceLine->placeholderText(); + QString fname = QFileDialog::getOpenFileName(this, tr("Select Playback Device"), current); + if(!fname.isEmpty()) + { + ui->ossDefaultDeviceLine->setText(fname); + enableApplyButton(); + } +} + +void MainWindow::selectOSSCapture() +{ + QString current = ui->ossDefaultCaptureLine->text(); + if(current.isEmpty()) current = ui->ossDefaultCaptureLine->placeholderText(); + QString fname = QFileDialog::getOpenFileName(this, tr("Select Capture Device"), current); + if(!fname.isEmpty()) + { + ui->ossDefaultCaptureLine->setText(fname); + enableApplyButton(); + } +} + +void MainWindow::selectSolarisPlayback() +{ + QString current = ui->solarisDefaultDeviceLine->text(); + if(current.isEmpty()) current = ui->solarisDefaultDeviceLine->placeholderText(); + QString fname = QFileDialog::getOpenFileName(this, tr("Select Playback Device"), current); + if(!fname.isEmpty()) + { + ui->solarisDefaultDeviceLine->setText(fname); + enableApplyButton(); + } +} + +void MainWindow::selectWaveOutput() +{ + QString fname = QFileDialog::getSaveFileName(this, tr("Select Wave File Output"), + ui->waveOutputLine->text(), tr("Wave Files (*.wav *.amb);;All Files (*.*)") + ); + if(!fname.isEmpty()) + { + ui->waveOutputLine->setText(fname); + enableApplyButton(); + } +} diff --git a/love/src/jni/openal-soft-1.17.0/utils/alsoft-config/mainwindow.h b/love/src/jni/openal-soft-1.18.2/utils/alsoft-config/mainwindow.h similarity index 61% rename from love/src/jni/openal-soft-1.17.0/utils/alsoft-config/mainwindow.h rename to love/src/jni/openal-soft-1.18.2/utils/alsoft-config/mainwindow.h index 0421aabb..8b763845 100644 --- a/love/src/jni/openal-soft-1.17.0/utils/alsoft-config/mainwindow.h +++ b/love/src/jni/openal-soft-1.18.2/utils/alsoft-config/mainwindow.h @@ -17,16 +17,32 @@ public: ~MainWindow(); private slots: + void cancelCloseAction(); + void saveCurrentConfig(); void saveConfigAsFile(); void loadConfigFromFile(); + void showAboutPage(); + + void enableApplyButton(); + + void updateResamplerLabel(int num); + void updatePeriodSizeEdit(int size); void updatePeriodSizeSlider(); void updatePeriodCountEdit(int size); void updatePeriodCountSlider(); + void selectQuadDecoderFile(); + void select51DecoderFile(); + void select61DecoderFile(); + void select71DecoderFile(); + + void updateJackBufferSizeEdit(int size); + void updateJackBufferSizeSlider(); + void addHrtfFile(); void removeHrtfFile(); @@ -35,8 +51,12 @@ private slots: void showEnabledBackendMenu(QPoint pt); void showDisabledBackendMenu(QPoint pt); - void updateReverbBoostEdit(int size); - void updateReverbBoostSlider(QString value); + void selectOSSPlayback(); + void selectOSSCapture(); + + void selectSolarisPlayback(); + + void selectWaveOutput(); private: Ui::MainWindow *ui; @@ -47,7 +67,15 @@ private: QValidator *mEffectSlotValidator; QValidator *mSourceSendValidator; QValidator *mSampleRateValidator; - QValidator *mReverbBoostValidator; + QValidator *mJackBufferValidator; + + bool mNeedsSave; + + void closeEvent(QCloseEvent *event); + + void selectDecoderFile(QLineEdit *line, const char *name); + + QStringList collectHrtfs(); void loadConfig(const QString &fname); void saveConfig(const QString &fname) const; diff --git a/love/src/jni/openal-soft-1.18.2/utils/alsoft-config/mainwindow.ui b/love/src/jni/openal-soft-1.18.2/utils/alsoft-config/mainwindow.ui new file mode 100644 index 00000000..23d7573a --- /dev/null +++ b/love/src/jni/openal-soft-1.18.2/utils/alsoft-config/mainwindow.ui @@ -0,0 +1,2423 @@ + + + MainWindow + + + + 0 + 0 + 564 + 460 + + + + + 564 + 460 + + + + OpenAL Soft Configuration + + + + + + + + + + + 470 + 405 + 81 + 21 + + + + Apply + + + + + + + + + + + 10 + 0 + 541 + 401 + + + + + Playback + + + + + 110 + 50 + 78 + 21 + + + + The output sample type. Currently, all mixing is done with 32-bit +float and converted to the output sample type as needed. + + + QComboBox::AdjustToContents + + + + + + 0 + 50 + 101 + 21 + + + + Sample Format: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 0 + 20 + 101 + 21 + + + + Channels: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 110 + 20 + 78 + 21 + + + + The output channel configuration. Note that not all backends +can properly detect the channel configuration and may default +to stereo output. + + + QComboBox::AdjustToContents + + + + + + 380 + 20 + 91 + 29 + + + + The playback/mixing sample rate. + + + true + + + QComboBox::NoInsert + + + QComboBox::AdjustToContents + + + + Autodetect + + + + + 8000 + + + + + 11025 + + + + + 16000 + + + + + 22050 + + + + + 32000 + + + + + 44100 + + + + + 48000 + + + + + + + 290 + 20 + 81 + 21 + + + + Sample Rate: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 290 + 50 + 81 + 21 + + + + Stereo Mode: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 380 + 50 + 78 + 21 + + + + 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. + + + + + + -11 + 180 + 551 + 201 + + + + Advanced Settings + + + Qt::AlignCenter + + + + + 20 + 30 + 511 + 91 + + + + Buffer Metrics + + + Qt::AlignCenter + + + + + 260 + 20 + 241 + 51 + + + + 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. + + + + + 20 + 0 + 201 + 21 + + + + Period Count + + + Qt::AlignCenter + + + + + + 80 + 20 + 160 + 21 + + + + 1 + + + 16 + + + 1 + + + 2 + + + 1 + + + true + + + Qt::Horizontal + + + QSlider::TicksBelow + + + 1 + + + + + + 20 + 20 + 51 + 21 + + + + 3 + + + + + + + 10 + 20 + 241 + 51 + + + + The update period size, in sample frames. This is the number of +frames needed for each mixing update. + + + + + 60 + 20 + 160 + 21 + + + + 0 + + + 8192 + + + 64 + + + 1024 + + + 0 + + + true + + + Qt::Horizontal + + + QSlider::TicksBelow + + + 512 + + + + + + 10 + 0 + 201 + 21 + + + + Period Samples + + + Qt::AlignCenter + + + + + + 0 + 20 + 51 + 21 + + + + 1024 + + + + + + + + 130 + 130 + 131 + 21 + + + + Pan Pot uses standard amplitude panning (aka +pair-wise, stereo pair, etc) between -30 and +30 +degrees, while UHJ creates a stereo-compatible +two-channel UHJ mix, which encodes some +surround sound information into stereo output +that can be decoded with a surround sound +receiver. + + + + + + 20 + 130 + 101 + 21 + + + + Stereo Encoding: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 270 + 130 + 111 + 21 + + + + Ambisonic Format: + + + + + + 390 + 130 + 131 + 21 + + + + + + + 30 + 160 + 231 + 20 + + + + Applies a gain limiter on the final mixed output. This reduces the +volume when the output samples would otherwise be clamped, +avoiding excessive clipping noise. + + + Enable Gain Limiter + + + true + + + + + + 270 + 160 + 261 + 21 + + + + Applies dithering on the final mix for 8- and 16-bit output. +This replaces the distortion created by nearest-value +quantization with low-level whitenoise. + + + Enable Dithering + + + true + + + + + + + 60 + 80 + 421 + 81 + + + + Resampler Quality + + + Qt::AlignCenter + + + + + 50 + 50 + 321 + 21 + + + + Default + + + Qt::AlignCenter + + + + + + 80 + 30 + 251 + 23 + + + + Qt::Horizontal + + + + + + 20 + 30 + 51 + 21 + + + + Speed + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 340 + 30 + 51 + 21 + + + + Quality + + + + + + + Renderer + + + + + 10 + 20 + 181 + 21 + + + + Enables high-quality ambisonic rendering. This mode is +capable of frequency-dependent processing, creating a +better reproduction of 3D sound rendering over +surround sound speakers. Enabling this also requires +specifying decoder configuration files for the +appropriate speaker configuration you intend to use. + + + Qt::RightToLeft + + + High Quality Mode: + + + + + + 10 + 50 + 181 + 21 + + + + This applies the necessary delays and attenuation +to make the speakers behave as though they are +all equidistant, which is important for proper +playback of 3D sound rendering. Requires the +proper distances to be specified in the decoder +configuration file. + + + Qt::RightToLeft + + + Distance Compensation: + + + true + + + + + + -10 + 160 + 551 + 161 + + + + Decoder Configurations + + + Qt::AlignCenter + + + + + 120 + 30 + 311 + 21 + + + + + + + 20 + 30 + 91 + 21 + + + + Quadrophonic: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 440 + 30 + 91 + 21 + + + + Browse... + + + + + + 120 + 60 + 311 + 21 + + + + + + + 440 + 60 + 91 + 21 + + + + Browse... + + + + + + 20 + 60 + 91 + 21 + + + + 5.1 Surround: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 20 + 90 + 91 + 21 + + + + 6.1 Surround: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 120 + 90 + 311 + 21 + + + + + + + 440 + 90 + 91 + 21 + + + + Browse... + + + + + + 440 + 120 + 91 + 21 + + + + Browse... + + + + + + 120 + 120 + 311 + 21 + + + + + + + 20 + 120 + 91 + 21 + + + + 7.1 Surround: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + 10 + 80 + 181 + 21 + + + + Simulates and compensates for low-frequency effects +caused by the curvature of nearby sound-waves, which +creates a more realistic perception of sound distance. +Note that the effect may be stronger or weaker than +intended if the application doesn't use or specify an +appropriate unit scale, or if incorrect speaker distances +are set in the decoder configuration file. Requires High +Quality Mode to be enabled. + + + Qt::RightToLeft + + + Near-Field Effects: + + + true + + + + + + -10 + 110 + 281 + 21 + + + + The reference delay value for ambisonic output. When +Channels is set to one of the Ambisonic formats, this +option enables NFC-HOA output with the specified +Reference Delay parameter. The specified value can then +be shared with an appropriate NFC-HOA decoder to +reproduce correct near-field effects. Keep in mind that +despite being designed for higher-order ambisonics, this +applies to first-order output all the same. When left unset, +normal output is created with no near-field simulation. + + + + + 20 + 0 + 151 + 21 + + + + Near-Field Reference Delay: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 180 + 0 + 91 + 21 + + + + sec + + + 4 + + + 1000.000000000000000 + + + 0.010000000000000 + + + + + + + HRTF + + + + + -10 + 200 + 551 + 181 + + + + Advanced Settings + + + Qt::AlignCenter + + + false + + + false + + + + + 20 + 30 + 511 + 141 + + + + HRTF Profile Paths + + + Qt::AlignCenter + + + + + 20 + 20 + 391 + 81 + + + + A list of additional paths containing HRTF data sets. + + + QAbstractItemView::InternalMove + + + true + + + QAbstractItemView::ExtendedSelection + + + Qt::ElideNone + + + + + + 420 + 20 + 81 + 21 + + + + Add... + + + + + + + + false + + + + + + 180 + 110 + 151 + 21 + + + + Include the default system paths in addition to any +listed above. + + + Include Default Paths + + + true + + + + + + 420 + 50 + 81 + 21 + + + + Remove + + + + + + + + + + + + + 40 + 50 + 71 + 21 + + + + HRTF Mode: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 130 + 50 + 161 + 21 + + + + Forces HRTF processing on or off, or leaves it to the +application or system to determine if it should be used. + + + QComboBox::AdjustToContentsOnFirstShow + + + + Application preference + + + + + Force on + + + + + Force off + + + + + + + 20 + 20 + 91 + 21 + + + + Preferred HRTF: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 130 + 20 + 161 + 21 + + + + The default HRTF to use if the application doesn't request one. + + + + + + Backends + + + + + 0 + 11 + 111 + 361 + + + + true + + + + General + + + + + PulseAudio + + + + + JACK + + + + + ALSA + + + + + OSS + + + + + Solaris + + + + + Wave Writer + + + + + + + 110 + 10 + 421 + 361 + + + + + + + 20 + 190 + 391 + 21 + + + + When checked, allows all other available backends not listed in the priority or disabled lists. + + + Allow Other Backends + + + true + + + + + + 220 + 30 + 191 + 151 + + + + Disabled backend driver list. + + + + + + 20 + 30 + 191 + 151 + + + + The backend driver list order. Unknown backends and +duplicated names are ignored. + + + QAbstractItemView::InternalMove + + + + + + 230 + 10 + 171 + 20 + + + + Disabled Backends: + + + + + + 30 + 10 + 171 + 20 + + + + Priority Backends: + + + + + + + + 20 + 10 + 141 + 21 + + + + Automatically spawn a PulseAudio server if one +is not already running. + + + AutoSpawn Server + + + true + + + + + + 20 + 40 + 161 + 21 + + + + Allows moving PulseAudio streams to different +devices during playback or capture. Note that the +device specifier and device format will not change +to match the new device. + + + Allow Moving Streams + + + + + + 20 + 70 + 121 + 21 + + + + When checked, fix the OpenAL device's sample +rate to match the PulseAudio device. + + + Fix Sample Rate + + + + + + + + 20 + 10 + 141 + 21 + + + + AutoSpawn Server + + + + + + 10 + 40 + 401 + 80 + + + + The update buffer size, in samples, that the backend +will keep buffered to handle the server's real-time +processing requests. Must be a power of 2. + + + Buffer Size + + + Qt::AlignCenter + + + + + 320 + 30 + 71 + 21 + + + + 0 + + + + + + 10 + 30 + 301 + 21 + + + + 13 + + + 1 + + + 4 + + + Qt::Horizontal + + + QSlider::TicksBelow + + + 1 + + + + + + + + + 10 + 30 + 141 + 21 + + + + Default Playback Device: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 160 + 30 + 231 + 21 + + + + default + + + + + + 10 + 60 + 141 + 21 + + + + Default Capture Device: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 160 + 60 + 231 + 21 + + + + default + + + + + + 20 + 100 + 191 + 21 + + + + Allow use of ALSA's software resampler. This lets +the OpenAL device to be set to a different sample +rate than the backend device, but incurs another +resample pass on top of OpenAL's resampler. + + + Allow Resampler + + + + + + 210 + 100 + 191 + 21 + + + + Accesses the audio device buffer through an mmap, +potentially avoiding an extra sample buffer copy +during updates. + + + MMap Buffer + + + true + + + + + + + + 10 + 30 + 141 + 21 + + + + Default Playback Device: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 160 + 30 + 151 + 21 + + + + /dev/dsp + + + + + + 10 + 60 + 141 + 21 + + + + Default Capture Device: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 160 + 60 + 151 + 21 + + + + /dev/dsp + + + + + + 320 + 30 + 91 + 21 + + + + Browse... + + + + + + 320 + 60 + 91 + 21 + + + + Browse... + + + + + + + + 160 + 30 + 151 + 21 + + + + /dev/audio + + + + + + 10 + 30 + 141 + 21 + + + + Default Playback Device: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 320 + 30 + 91 + 21 + + + + Browse... + + + + + + + + 10 + 30 + 71 + 21 + + + + Output File: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 90 + 30 + 221 + 21 + + + + + + + 0 + 90 + 421 + 71 + + + + <html><head/><body><p align="center"><span style=" font-style:italic;">Warning: The specified output file will be OVERWRITTEN WITHOUT</span></p><p align="center"><span style=" font-style:italic;">QUESTION when the Wave Writer device is opened.</span></p></body></html> + + + + + + 320 + 30 + 91 + 21 + + + + Browse... + + + + + + 120 + 60 + 191 + 21 + + + + Create .amb (B-Format) files + + + + + + + + Resources + + + + + 190 + 20 + 51 + 21 + + + + 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. + + + 4 + + + 256 + + + + + + 10 + 20 + 171 + 21 + + + + Number of Sound Sources: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 10 + 50 + 171 + 21 + + + + Number of Effect Slots: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 190 + 50 + 51 + 21 + + + + 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 if no sources are feeding it, so this +may help when apps use more than the system can handle. + + + 3 + + + 64 + + + + + + 10 + 80 + 171 + 21 + + + + Number of Source Sends: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 190 + 80 + 51 + 21 + + + + Limits the number of auxiliary sends allowed per source. +Setting this higher than the default has no effect. + + + 2 + + + 16 + + + + + + 10 + 120 + 511 + 121 + + + + Enables use of specific CPU extensions. Certain methods may +utilize CPU extensions when detected, and disabling these can +be useful for preventing those extensions from being used. + + + CPU Extensions + + + + + 100 + 20 + 71 + 31 + + + + SSE + + + true + + + + + + 180 + 20 + 71 + 31 + + + + SSE2 + + + true + + + + + + 100 + 50 + 71 + 31 + + + + Neon + + + true + + + + + + 340 + 20 + 71 + 31 + + + + SSE4.1 + + + 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> + + + + + + + Effects + + + + + 10 + 60 + 161 + 21 + + + + Uses a simpler reverb method to emulate the EAX reverb +effect. This may slightly improve performance at the cost of +some quality. + + + Qt::RightToLeft + + + Emulate EAX Reverb: + + + + + + 10 + 100 + 511 + 191 + + + + Specifies which effects apps can recognize. Disabling effects +can help for apps that try to use ones that are too intensive +for the system to handle. + + + Enabled Effects + + + + + 70 + 30 + 131 + 21 + + + + EAX Reverb + + + true + + + + + + 70 + 60 + 131 + 21 + + + + Standard Reverb + + + true + + + + + + 70 + 90 + 131 + 21 + + + + Chorus + + + true + + + + + + 70 + 150 + 131 + 21 + + + + Distortion + + + true + + + + + + 320 + 30 + 131 + 21 + + + + Echo + + + true + + + + + + 320 + 60 + 131 + 21 + + + + Equalizer + + + true + + + + + + 320 + 90 + 131 + 21 + + + + Flanger + + + true + + + + + + 320 + 120 + 131 + 21 + + + + Ring Modulator + + + true + + + + + + 320 + 150 + 131 + 21 + + + + Enables both the Dedicated Dialog and Dedicated LFE effects +added by the ALC_EXT_DEDICATED extension. + + + Dedicated ... + + + true + + + + + + 70 + 120 + 111 + 21 + + + + Compressor + + + true + + + + + + + 10 + 20 + 141 + 21 + + + + Default Reverb Effect: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 160 + 20 + 123 + 29 + + + + QComboBox::AdjustToContents + + + + None + + + + + Generic + + + + + PaddedCell + + + + + Room + + + + + Bathroom + + + + + Livingroom + + + + + Stoneroom + + + + + Auditorium + + + + + ConcertHall + + + + + Cave + + + + + Arena + + + + + Hangar + + + + + CarpetedHallway + + + + + Hallway + + + + + StoneCorridor + + + + + Alley + + + + + Forest + + + + + City + + + + + Mountains + + + + + Quarry + + + + + Plain + + + + + ParkingLot + + + + + SewerPipe + + + + + Underwater + + + + + Drugged + + + + + Dizzy + + + + + Psychotic + + + + + + + + + 370 + 405 + 91 + 21 + + + + Cancel + + + + + + + + + + + + 0 + 0 + 564 + 27 + + + + + &File + + + + + + + + + &Help + + + + + + + + + + + + + + &Quit + + + + + + + + + + Save &As... + + + Save Configuration As + + + + + + + + + + &Load... + + + Load Configuration File + + + + + &About... + + + + + + + + actionQuit + activated() + MainWindow + close() + + + -1 + -1 + + + 267 + 181 + + + + + backendListWidget + currentRowChanged(int) + backendStackedWidget + setCurrentIndex(int) + + + 69 + 233 + + + 329 + 232 + + + + + + ShowHRTFContextMenu(QPoint) + + diff --git a/love/src/jni/openal-soft-1.18.2/utils/bsincgen.c b/love/src/jni/openal-soft-1.18.2/utils/bsincgen.c new file mode 100644 index 00000000..33783a27 --- /dev/null +++ b/love/src/jni/openal-soft-1.18.2/utils/bsincgen.c @@ -0,0 +1,412 @@ +/* + * Sinc interpolator coefficient and delta generator for the OpenAL Soft + * cross platform audio library. + * + * Copyright (C) 2015 by Christopher Fitzgerald. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * Or visit: http://www.gnu.org/licenses/old-licenses/lgpl-2.0.html + * + * -------------------------------------------------------------------------- + * + * This is a modified version of the bandlimited windowed sinc interpolator + * algorithm presented here: + * + * Smith, J.O. "Windowed Sinc Interpolation", in + * Physical Audio Signal Processing, + * https://ccrma.stanford.edu/~jos/pasp/Windowed_Sinc_Interpolation.html, + * online book, + * accessed October 2012. + */ + +#include +#include +#include + +#ifndef M_PI +#define M_PI (3.14159265358979323846) +#endif + +// The number of distinct scale and phase intervals within the filter table. +#define BSINC_SCALE_COUNT (16) +#define BSINC_PHASE_COUNT (16) + +#define BSINC_REJECTION (60.0) +#define BSINC_POINTS_MIN (12) + +static double MinDouble(double a, double b) +{ return (a <= b) ? a : b; } + +static double MaxDouble(double a, double b) +{ return (a >= b) ? a : b; } + +/* NOTE: This is the normalized (instead of just sin(x)/x) cardinal sine + * function. + * 2 f_t sinc(2 f_t x) + * f_t -- normalized transition frequency (0.5 is nyquist) + * x -- sample index (-N to N) + */ +static double Sinc(const double x) +{ + if(fabs(x) < 1e-15) + return 1.0; + return sin(M_PI * x) / (M_PI * x); +} + +static double BesselI_0(const double x) +{ + double term, sum, last_sum, x2, y; + int i; + + term = 1.0; + sum = 1.0; + x2 = x / 2.0; + i = 1; + + do { + y = x2 / i; + i++; + last_sum = sum; + term *= y * y; + sum += term; + } while(sum != last_sum); + + return sum; +} + +/* NOTE: k is assumed normalized (-1 to 1) + * beta is equivalent to 2 alpha + */ +static double Kaiser(const double b, const double k) +{ + double k2; + + if((k < -1.0) || (k > 1.0)) + return 0.0; + + k2 = MaxDouble(1.0 - (k * k), 0.0); + + return BesselI_0(b * sqrt(k2)) / BesselI_0(b); +} + +/* NOTE: Calculates the transition width of the Kaiser window. Rejection is + * in dB. + */ +static double CalcKaiserWidth(const double rejection, const int order) +{ + double w_t = 2.0 * M_PI; + + if(rejection > 21.0) + return (rejection - 7.95) / (order * 2.285 * w_t); + + return 5.79 / (order * w_t); +} + +static double CalcKaiserBeta(const double rejection) +{ + if(rejection > 50.0) + return 0.1102 * (rejection - 8.7); + else if(rejection >= 21.0) + return (0.5842 * pow(rejection - 21.0, 0.4)) + + (0.07886 * (rejection - 21.0)); + return 0.0; +} + +/* Generates the coefficient, delta, and index tables required by the bsinc resampler */ +static void BsiGenerateTables() +{ + static double filter[BSINC_SCALE_COUNT][BSINC_PHASE_COUNT + 1][2 * BSINC_POINTS_MIN]; + static double scDeltas[BSINC_SCALE_COUNT - 1][BSINC_PHASE_COUNT][2 * BSINC_POINTS_MIN]; + static double phDeltas[BSINC_SCALE_COUNT][BSINC_PHASE_COUNT + 1][2 * BSINC_POINTS_MIN]; + static double spDeltas[BSINC_SCALE_COUNT - 1][BSINC_PHASE_COUNT][2 * BSINC_POINTS_MIN]; + static int mt[BSINC_SCALE_COUNT]; + static double at[BSINC_SCALE_COUNT]; + double width, beta, scaleBase, scaleRange; + int si, pi, i; + + memset(filter, 0, sizeof(filter)); + memset(scDeltas, 0, sizeof(scDeltas)); + memset(phDeltas, 0, sizeof(phDeltas)); + memset(spDeltas, 0, sizeof(spDeltas)); + + /* Calculate windowing parameters. The width describes the transition + band, but it may vary due to the linear interpolation between scales + of the filter. + */ + width = CalcKaiserWidth(BSINC_REJECTION, BSINC_POINTS_MIN); + beta = CalcKaiserBeta(BSINC_REJECTION); + scaleBase = width / 2.0; + scaleRange = 1.0 - scaleBase; + + // Determine filter scaling. + for(si = 0; si < BSINC_SCALE_COUNT; si++) + { + const double scale = scaleBase + (scaleRange * si / (BSINC_SCALE_COUNT - 1)); + const double a = MinDouble(BSINC_POINTS_MIN, BSINC_POINTS_MIN / (2.0 * scale)); + int m = 2 * (int)floor(a); + + // Make sure the number of points is a multiple of 4 (for SSE). + m += ~(m - 1) & 3; + + mt[si] = m; + at[si] = a; + } + + /* Calculate the Kaiser-windowed Sinc filter coefficients for each scale + and phase. + */ + for(si = 0; si < BSINC_SCALE_COUNT; si++) + { + const int m = mt[si]; + const int o = BSINC_POINTS_MIN - (m / 2); + const int l = (m / 2) - 1; + const double a = at[si]; + const double scale = scaleBase + (scaleRange * si / (BSINC_SCALE_COUNT - 1)); + const double cutoff = (0.5 * scale) - (scaleBase * MaxDouble(0.5, scale)); + + for(pi = 0; pi <= BSINC_PHASE_COUNT; pi++) + { + const double phase = l + ((double)pi / BSINC_PHASE_COUNT); + + for(i = 0; i < m; i++) + { + const double x = i - phase; + filter[si][pi][o + i] = Kaiser(beta, x / a) * 2.0 * cutoff * Sinc(2.0 * cutoff * x); + } + } + } + + /* Linear interpolation between scales is simplified by pre-calculating + the delta (b - a) in: x = a + f (b - a) + + Given a difference in points between scales, the destination points + will be 0, thus: x = a + f (-a) + */ + for(si = 0; si < (BSINC_SCALE_COUNT - 1); si++) + { + const int m = mt[si]; + const int o = BSINC_POINTS_MIN - (m / 2); + + for(pi = 0; pi < BSINC_PHASE_COUNT; pi++) + { + for(i = 0; i < m; i++) + scDeltas[si][pi][o + i] = filter[si + 1][pi][o + i] - filter[si][pi][o + i]; + } + } + + // Linear interpolation between phases is also simplified. + for(si = 0; si < BSINC_SCALE_COUNT; si++) + { + const int m = mt[si]; + const int o = BSINC_POINTS_MIN - (m / 2); + + for(pi = 0; pi < BSINC_PHASE_COUNT; pi++) + { + for(i = 0; i < m; i++) + phDeltas[si][pi][o + i] = filter[si][pi + 1][o + i] - filter[si][pi][o + i]; + } + } + + /* This last simplification is done to complete the bilinear equation for + the combination of scale and phase. + */ + for(si = 0; si < (BSINC_SCALE_COUNT - 1); si++) + { + const int m = mt[si]; + const int o = BSINC_POINTS_MIN - (m / 2); + + for(pi = 0; pi < BSINC_PHASE_COUNT; pi++) + { + for(i = 0; i < m; i++) + spDeltas[si][pi][o + i] = phDeltas[si + 1][pi][o + i] - phDeltas[si][pi][o + i]; + } + } + + // Calculate the table size. + i = mt[0]; + for(si = 1; si < BSINC_SCALE_COUNT; si++) + i += BSINC_PHASE_COUNT * mt[si]; + for(si = 0; si < (BSINC_SCALE_COUNT - 1); si++) + i += 2 * BSINC_PHASE_COUNT * mt[si]; + for(si = 1; si < BSINC_SCALE_COUNT; si++) + i += BSINC_PHASE_COUNT * mt[si]; + + fprintf(stdout, "static const float bsincTab[%d] =\n{\n", i); + + /* Only output enough coefficients for the first (cut) scale as needed to + perform interpolation without extra branching. + */ + fprintf(stdout, " /* %2d,%2d */", mt[0], 0); + for(i = 0; i < mt[0]; i++) + fprintf(stdout, " %+14.9ef,", filter[0][0][i]); + fprintf(stdout, "\n\n"); + + for(si = 1; si < BSINC_SCALE_COUNT; si++) + { + const int m = mt[si]; + const int o = BSINC_POINTS_MIN - (m / 2); + + for(pi = 0; pi < BSINC_PHASE_COUNT; pi++) + { + fprintf(stdout, " /* %2d,%2d */", m, pi); + for(i = 0; i < m; i++) + fprintf(stdout, " %+14.9ef,", filter[si][pi][o + i]); + fprintf(stdout, "\n"); + } + } + fprintf(stdout, "\n"); + + // There are N-1 scale deltas for N scales. + for(si = 0; si < (BSINC_SCALE_COUNT - 1); si++) + { + const int m = mt[si]; + const int o = BSINC_POINTS_MIN - (m / 2); + + for(pi = 0; pi < BSINC_PHASE_COUNT; pi++) + { + fprintf(stdout, " /* %2d,%2d */", m, pi); + for(i = 0; i < m; i++) + fprintf(stdout, " %+14.9ef,", scDeltas[si][pi][o + i]); + fprintf(stdout, "\n"); + } + } + fprintf(stdout, "\n"); + + // Exclude phases for the first (cut) scale. + for(si = 1; si < BSINC_SCALE_COUNT; si++) + { + const int m = mt[si]; + const int o = BSINC_POINTS_MIN - (m / 2); + + for(pi = 0; pi < BSINC_PHASE_COUNT; pi++) + { + fprintf(stdout, " /* %2d,%2d */", m, pi); + for(i = 0; i < m; i++) + fprintf(stdout, " %+14.9ef,", phDeltas[si][pi][o + i]); + fprintf(stdout, "\n"); + } + } + fprintf(stdout, "\n"); + + for(si = 0; si < (BSINC_SCALE_COUNT - 1); si++) + { + const int m = mt[si]; + const int o = BSINC_POINTS_MIN - (m / 2); + + for(pi = 0; pi < BSINC_PHASE_COUNT; pi++) + { + fprintf(stdout, " /* %2d,%2d */", m, pi); + for(i = 0; i < m; i++) + fprintf(stdout, " %+14.9ef,", spDeltas[si][pi][o + i]); + fprintf(stdout, "\n"); + } + } + fprintf(stdout, "};\n\n"); + + /* The scaleBase is calculated from the Kaiser window transition width. + It represents the absolute limit to the filter before it fully cuts + the signal. The limit in octaves can be calculated by taking the + base-2 logarithm of its inverse: log_2(1 / scaleBase) + */ + fprintf(stdout, " static const ALfloat scaleBase = %.9ef, scaleRange = %.9ef;\n", scaleBase, 1.0 / scaleRange); + fprintf(stdout, " static const ALuint m[BSINC_SCALE_COUNT] = {"); + + fprintf(stdout, " %d", mt[0]); + for(si = 1; si < BSINC_SCALE_COUNT; si++) + fprintf(stdout, ", %d", mt[si]); + + fprintf(stdout, " };\n"); + fprintf(stdout, " static const ALuint to[4][BSINC_SCALE_COUNT] =\n {\n { 0"); + + i = mt[0]; + for(si = 1; si < BSINC_SCALE_COUNT; si++) + { + fprintf(stdout, ", %d", i); + i += BSINC_PHASE_COUNT * mt[si]; + } + fprintf(stdout, " },\n {"); + for(si = 0; si < (BSINC_SCALE_COUNT - 1); si++) + { + fprintf(stdout, " %d,", i); + i += BSINC_PHASE_COUNT * mt[si]; + } + fprintf(stdout, " 0 },\n { 0"); + for(si = 1; si < BSINC_SCALE_COUNT; si++) + { + fprintf(stdout, ", %d", i); + i += BSINC_PHASE_COUNT * mt[si]; + } + fprintf (stdout, " },\n {"); + for(si = 0; si < (BSINC_SCALE_COUNT - 1); si++) + { + fprintf(stdout, " %d,", i); + i += BSINC_PHASE_COUNT * mt[si]; + } + fprintf(stdout, " 0 }\n };\n"); + + fprintf(stdout, " static const ALuint tm[2][BSINC_SCALE_COUNT] = \n {\n { 0"); + for(si = 1; si < BSINC_SCALE_COUNT; si++) + fprintf(stdout, ", %d", mt[si]); + fprintf(stdout, " },\n {"); + for(si = 0; si < (BSINC_SCALE_COUNT - 1); si++) + fprintf(stdout, " %d,", mt[si]); + fprintf(stdout, " 0 }\n };\n\n"); +} + + +/* These methods generate a much simplified 4-point sinc interpolator using a + * Kaiser windows. This is much simpler to process at run-time, but has notably + * more aliasing noise. + */ + +/* Same as in alu.h! */ +#define FRACTIONBITS (12) +#define FRACTIONONE (1< +#include +#include +#include +#include +#include +#ifdef HAVE_STRINGS_H +#include +#endif + +// Rely (if naively) on OpenAL's header for the types used for serialization. +#include "AL/al.h" +#include "AL/alext.h" + +#ifndef M_PI +#define M_PI (3.14159265358979323846) +#endif + +#ifndef HUGE_VAL +#define HUGE_VAL (1.0 / 0.0) +#endif + +// The epsilon used to maintain signal stability. +#define EPSILON (1e-9) + +// Constants for accessing the token reader's ring buffer. +#define TR_RING_BITS (16) +#define TR_RING_SIZE (1 << TR_RING_BITS) +#define TR_RING_MASK (TR_RING_SIZE - 1) + +// The token reader's load interval in bytes. +#define TR_LOAD_SIZE (TR_RING_SIZE >> 2) + +// The maximum identifier length used when processing the data set +// definition. +#define MAX_IDENT_LEN (16) + +// The maximum path length used when processing filenames. +#define MAX_PATH_LEN (256) + +// The limits for the sample 'rate' metric in the data set definition and for +// resampling. +#define MIN_RATE (32000) +#define MAX_RATE (96000) + +// The limits for the HRIR 'points' metric in the data set definition. +#define MIN_POINTS (16) +#define MAX_POINTS (8192) + +// The limits to the number of 'azimuths' listed in the data set definition. +#define MIN_EV_COUNT (5) +#define MAX_EV_COUNT (128) + +// The limits for each of the 'azimuths' listed in the data set definition. +#define MIN_AZ_COUNT (1) +#define MAX_AZ_COUNT (128) + +// The limits for the listener's head 'radius' in the data set definition. +#define MIN_RADIUS (0.05) +#define MAX_RADIUS (0.15) + +// The limits for the 'distance' from source to listener in the definition +// file. +#define MIN_DISTANCE (0.5) +#define MAX_DISTANCE (2.5) + +// The maximum number of channels that can be addressed for a WAVE file +// source listed in the data set definition. +#define MAX_WAVE_CHANNELS (65535) + +// The limits to the byte size for a binary source listed in the definition +// file. +#define MIN_BIN_SIZE (2) +#define MAX_BIN_SIZE (4) + +// The minimum number of significant bits for binary sources listed in the +// data set definition. The maximum is calculated from the byte size. +#define MIN_BIN_BITS (16) + +// The limits to the number of significant bits for an ASCII source listed in +// the data set definition. +#define MIN_ASCII_BITS (16) +#define MAX_ASCII_BITS (32) + +// The limits to the FFT window size override on the command line. +#define MIN_FFTSIZE (65536) +#define MAX_FFTSIZE (131072) + +// The limits to the equalization range limit on the command line. +#define MIN_LIMIT (2.0) +#define MAX_LIMIT (120.0) + +// The limits to the truncation window size on the command line. +#define MIN_TRUNCSIZE (16) +#define MAX_TRUNCSIZE (512) + +// The limits to the custom head radius on the command line. +#define MIN_CUSTOM_RADIUS (0.05) +#define MAX_CUSTOM_RADIUS (0.15) + +// The truncation window size must be a multiple of the below value to allow +// for vectorized convolution. +#define MOD_TRUNCSIZE (8) + +// The defaults for the command line options. +#define DEFAULT_FFTSIZE (65536) +#define DEFAULT_EQUALIZE (1) +#define DEFAULT_SURFACE (1) +#define DEFAULT_LIMIT (24.0) +#define DEFAULT_TRUNCSIZE (32) +#define DEFAULT_HEAD_MODEL (HM_DATASET) +#define DEFAULT_CUSTOM_RADIUS (0.0) + +// The four-character-codes for RIFF/RIFX WAVE file chunks. +#define FOURCC_RIFF (0x46464952) // 'RIFF' +#define FOURCC_RIFX (0x58464952) // 'RIFX' +#define FOURCC_WAVE (0x45564157) // 'WAVE' +#define FOURCC_FMT (0x20746D66) // 'fmt ' +#define FOURCC_DATA (0x61746164) // 'data' +#define FOURCC_LIST (0x5453494C) // 'LIST' +#define FOURCC_WAVL (0x6C766177) // 'wavl' +#define FOURCC_SLNT (0x746E6C73) // 'slnt' + +// The supported wave formats. +#define WAVE_FORMAT_PCM (0x0001) +#define WAVE_FORMAT_IEEE_FLOAT (0x0003) +#define WAVE_FORMAT_EXTENSIBLE (0xFFFE) + +// The maximum propagation delay value supported by OpenAL Soft. +#define MAX_HRTD (63.0) + +// The OpenAL Soft HRTF format marker. It stands for minimum-phase head +// response protocol 01. +#define MHR_FORMAT ("MinPHR01") + +// Byte order for the serialization routines. +typedef enum ByteOrderT { + BO_NONE, + BO_LITTLE, + BO_BIG +} ByteOrderT; + +// Source format for the references listed in the data set definition. +typedef enum SourceFormatT { + SF_NONE, + SF_WAVE, // RIFF/RIFX WAVE file. + SF_BIN_LE, // Little-endian binary file. + SF_BIN_BE, // Big-endian binary file. + SF_ASCII // ASCII text file. +} SourceFormatT; + +// Element types for the references listed in the data set definition. +typedef enum ElementTypeT { + ET_NONE, + ET_INT, // Integer elements. + ET_FP // Floating-point elements. +} ElementTypeT; + +// Head model used for calculating the impulse delays. +typedef enum HeadModelT { + HM_NONE, + HM_DATASET, // Measure the onset from the dataset. + HM_SPHERE // Calculate the onset using a spherical head model. +} HeadModelT; + +// Desired output format from the command line. +typedef enum OutputFormatT { + OF_NONE, + OF_MHR // OpenAL Soft MHR data set file. +} OutputFormatT; + +// Unsigned integer type. +typedef unsigned int uint; + +// Serialization types. The trailing digit indicates the number of bits. +typedef ALubyte uint8; +typedef ALint int32; +typedef ALuint uint32; +typedef ALuint64SOFT uint64; + +// Token reader state for parsing the data set definition. +typedef struct TokenReaderT { + FILE *mFile; + const char *mName; + uint mLine; + uint mColumn; + char mRing[TR_RING_SIZE]; + size_t mIn; + size_t mOut; +} TokenReaderT; + +// Source reference state used when loading sources. +typedef struct SourceRefT { + SourceFormatT mFormat; + ElementTypeT mType; + uint mSize; + int mBits; + uint mChannel; + uint mSkip; + uint mOffset; + char mPath[MAX_PATH_LEN+1]; +} SourceRefT; + +// The HRIR metrics and data set used when loading, processing, and storing +// the resulting HRTF. +typedef struct HrirDataT { + uint mIrRate; + uint mIrCount; + uint mIrSize; + uint mIrPoints; + uint mFftSize; + uint mEvCount; + uint mEvStart; + uint mAzCount[MAX_EV_COUNT]; + uint mEvOffset[MAX_EV_COUNT]; + double mRadius; + double mDistance; + double *mHrirs; + double *mHrtds; + double mMaxHrtd; +} HrirDataT; + +// The resampler metrics and FIR filter. +typedef struct ResamplerT { + uint mP, mQ, mM, mL; + double *mF; +} ResamplerT; + + +/***************************** + *** Token reader routines *** + *****************************/ + +/* Whitespace is not significant. It can process tokens as identifiers, numbers + * (integer and floating-point), strings, and operators. Strings must be + * encapsulated by double-quotes and cannot span multiple lines. + */ + +// Setup the reader on the given file. The filename can be NULL if no error +// output is desired. +static void TrSetup(FILE *fp, const char *filename, TokenReaderT *tr) +{ + const char *name = NULL; + + if(filename) + { + const char *slash = strrchr(filename, '/'); + if(slash) + { + const char *bslash = strrchr(slash+1, '\\'); + if(bslash) name = bslash+1; + else name = slash+1; + } + else + { + const char *bslash = strrchr(filename, '\\'); + if(bslash) name = bslash+1; + else name = filename; + } + } + + tr->mFile = fp; + tr->mName = name; + tr->mLine = 1; + tr->mColumn = 1; + tr->mIn = 0; + tr->mOut = 0; +} + +// Prime the reader's ring buffer, and return a result indicating that there +// is text to process. +static int TrLoad(TokenReaderT *tr) +{ + size_t toLoad, in, count; + + toLoad = TR_RING_SIZE - (tr->mIn - tr->mOut); + if(toLoad >= TR_LOAD_SIZE && !feof(tr->mFile)) + { + // Load TR_LOAD_SIZE (or less if at the end of the file) per read. + toLoad = TR_LOAD_SIZE; + in = tr->mIn&TR_RING_MASK; + count = TR_RING_SIZE - in; + if(count < toLoad) + { + tr->mIn += fread(&tr->mRing[in], 1, count, tr->mFile); + tr->mIn += fread(&tr->mRing[0], 1, toLoad-count, tr->mFile); + } + else + tr->mIn += fread(&tr->mRing[in], 1, toLoad, tr->mFile); + + if(tr->mOut >= TR_RING_SIZE) + { + tr->mOut -= TR_RING_SIZE; + tr->mIn -= TR_RING_SIZE; + } + } + if(tr->mIn > tr->mOut) + return 1; + return 0; +} + +// Error display routine. Only displays when the base name is not NULL. +static void TrErrorVA(const TokenReaderT *tr, uint line, uint column, const char *format, va_list argPtr) +{ + if(!tr->mName) + return; + fprintf(stderr, "Error (%s:%u:%u): ", tr->mName, line, column); + vfprintf(stderr, format, argPtr); +} + +// Used to display an error at a saved line/column. +static void TrErrorAt(const TokenReaderT *tr, uint line, uint column, const char *format, ...) +{ + va_list argPtr; + + va_start(argPtr, format); + TrErrorVA(tr, line, column, format, argPtr); + va_end(argPtr); +} + +// Used to display an error at the current line/column. +static void TrError(const TokenReaderT *tr, const char *format, ...) +{ + va_list argPtr; + + va_start(argPtr, format); + TrErrorVA(tr, tr->mLine, tr->mColumn, format, argPtr); + va_end(argPtr); +} + +// Skips to the next line. +static void TrSkipLine(TokenReaderT *tr) +{ + char ch; + + while(TrLoad(tr)) + { + ch = tr->mRing[tr->mOut&TR_RING_MASK]; + tr->mOut++; + if(ch == '\n') + { + tr->mLine++; + tr->mColumn = 1; + break; + } + tr->mColumn ++; + } +} + +// Skips to the next token. +static int TrSkipWhitespace(TokenReaderT *tr) +{ + char ch; + + while(TrLoad(tr)) + { + ch = tr->mRing[tr->mOut&TR_RING_MASK]; + if(isspace(ch)) + { + tr->mOut++; + if(ch == '\n') + { + tr->mLine++; + tr->mColumn = 1; + } + else + tr->mColumn++; + } + else if(ch == '#') + TrSkipLine(tr); + else + return 1; + } + return 0; +} + +// Get the line and/or column of the next token (or the end of input). +static void TrIndication(TokenReaderT *tr, uint *line, uint *column) +{ + TrSkipWhitespace(tr); + if(line) *line = tr->mLine; + if(column) *column = tr->mColumn; +} + +// Checks to see if a token is the given operator. It does not display any +// errors and will not proceed to the next token. +static int TrIsOperator(TokenReaderT *tr, const char *op) +{ + size_t out, len; + char ch; + + if(!TrSkipWhitespace(tr)) + return 0; + out = tr->mOut; + len = 0; + while(op[len] != '\0' && out < tr->mIn) + { + ch = tr->mRing[out&TR_RING_MASK]; + if(ch != op[len]) break; + len++; + out++; + } + if(op[len] == '\0') + return 1; + return 0; +} + +/* The TrRead*() routines obtain the value of a matching token type. They + * display type, form, and boundary errors and will proceed to the next + * token. + */ + +// Reads and validates an identifier token. +static int TrReadIdent(TokenReaderT *tr, const uint maxLen, char *ident) +{ + uint col, len; + char ch; + + col = tr->mColumn; + if(TrSkipWhitespace(tr)) + { + col = tr->mColumn; + ch = tr->mRing[tr->mOut&TR_RING_MASK]; + if(ch == '_' || isalpha(ch)) + { + len = 0; + do { + if(len < maxLen) + ident[len] = ch; + len++; + tr->mOut++; + if(!TrLoad(tr)) + break; + ch = tr->mRing[tr->mOut&TR_RING_MASK]; + } while(ch == '_' || isdigit(ch) || isalpha(ch)); + + tr->mColumn += len; + if(len < maxLen) + { + ident[len] = '\0'; + return 1; + } + TrErrorAt(tr, tr->mLine, col, "Identifier is too long.\n"); + return 0; + } + } + TrErrorAt(tr, tr->mLine, col, "Expected an identifier.\n"); + return 0; +} + +// Reads and validates (including bounds) an integer token. +static int TrReadInt(TokenReaderT *tr, const int loBound, const int hiBound, int *value) +{ + uint col, digis, len; + char ch, temp[64+1]; + + col = tr->mColumn; + if(TrSkipWhitespace(tr)) + { + col = tr->mColumn; + len = 0; + ch = tr->mRing[tr->mOut&TR_RING_MASK]; + if(ch == '+' || ch == '-') + { + temp[len] = ch; + len++; + tr->mOut++; + } + digis = 0; + while(TrLoad(tr)) + { + ch = tr->mRing[tr->mOut&TR_RING_MASK]; + if(!isdigit(ch)) break; + if(len < 64) + temp[len] = ch; + len++; + digis++; + tr->mOut++; + } + tr->mColumn += len; + if(digis > 0 && ch != '.' && !isalpha(ch)) + { + if(len > 64) + { + TrErrorAt(tr, tr->mLine, col, "Integer is too long."); + return 0; + } + temp[len] = '\0'; + *value = strtol(temp, NULL, 10); + if(*value < loBound || *value > hiBound) + { + TrErrorAt(tr, tr->mLine, col, "Expected a value from %d to %d.\n", loBound, hiBound); + return (0); + } + return (1); + } + } + TrErrorAt(tr, tr->mLine, col, "Expected an integer.\n"); + return 0; +} + +// Reads and validates (including bounds) a float token. +static int TrReadFloat(TokenReaderT *tr, const double loBound, const double hiBound, double *value) +{ + uint col, digis, len; + char ch, temp[64+1]; + + col = tr->mColumn; + if(TrSkipWhitespace(tr)) + { + col = tr->mColumn; + len = 0; + ch = tr->mRing[tr->mOut&TR_RING_MASK]; + if(ch == '+' || ch == '-') + { + temp[len] = ch; + len++; + tr->mOut++; + } + + digis = 0; + while(TrLoad(tr)) + { + ch = tr->mRing[tr->mOut&TR_RING_MASK]; + if(!isdigit(ch)) break; + if(len < 64) + temp[len] = ch; + len++; + digis++; + tr->mOut++; + } + if(ch == '.') + { + if(len < 64) + temp[len] = ch; + len++; + tr->mOut++; + } + while(TrLoad(tr)) + { + ch = tr->mRing[tr->mOut&TR_RING_MASK]; + if(!isdigit(ch)) break; + if(len < 64) + temp[len] = ch; + len++; + digis++; + tr->mOut++; + } + if(digis > 0) + { + if(ch == 'E' || ch == 'e') + { + if(len < 64) + temp[len] = ch; + len++; + digis = 0; + tr->mOut++; + if(ch == '+' || ch == '-') + { + if(len < 64) + temp[len] = ch; + len++; + tr->mOut++; + } + while(TrLoad(tr)) + { + ch = tr->mRing[tr->mOut&TR_RING_MASK]; + if(!isdigit(ch)) break; + if(len < 64) + temp[len] = ch; + len++; + digis++; + tr->mOut++; + } + } + tr->mColumn += len; + if(digis > 0 && ch != '.' && !isalpha(ch)) + { + if(len > 64) + { + TrErrorAt(tr, tr->mLine, col, "Float is too long."); + return 0; + } + temp[len] = '\0'; + *value = strtod(temp, NULL); + if(*value < loBound || *value > hiBound) + { + TrErrorAt (tr, tr->mLine, col, "Expected a value from %f to %f.\n", loBound, hiBound); + return 0; + } + return 1; + } + } + else + tr->mColumn += len; + } + TrErrorAt(tr, tr->mLine, col, "Expected a float.\n"); + return 0; +} + +// Reads and validates a string token. +static int TrReadString(TokenReaderT *tr, const uint maxLen, char *text) +{ + uint col, len; + char ch; + + col = tr->mColumn; + if(TrSkipWhitespace(tr)) + { + col = tr->mColumn; + ch = tr->mRing[tr->mOut&TR_RING_MASK]; + if(ch == '\"') + { + tr->mOut++; + len = 0; + while(TrLoad(tr)) + { + ch = tr->mRing[tr->mOut&TR_RING_MASK]; + tr->mOut++; + if(ch == '\"') + break; + if(ch == '\n') + { + TrErrorAt (tr, tr->mLine, col, "Unterminated string at end of line.\n"); + return 0; + } + if(len < maxLen) + text[len] = ch; + len++; + } + if(ch != '\"') + { + tr->mColumn += 1 + len; + TrErrorAt(tr, tr->mLine, col, "Unterminated string at end of input.\n"); + return 0; + } + tr->mColumn += 2 + len; + if(len > maxLen) + { + TrErrorAt (tr, tr->mLine, col, "String is too long.\n"); + return 0; + } + text[len] = '\0'; + return 1; + } + } + TrErrorAt(tr, tr->mLine, col, "Expected a string.\n"); + return 0; +} + +// Reads and validates the given operator. +static int TrReadOperator(TokenReaderT *tr, const char *op) +{ + uint col, len; + char ch; + + col = tr->mColumn; + if(TrSkipWhitespace(tr)) + { + col = tr->mColumn; + len = 0; + while(op[len] != '\0' && TrLoad(tr)) + { + ch = tr->mRing[tr->mOut&TR_RING_MASK]; + if(ch != op[len]) break; + len++; + tr->mOut++; + } + tr->mColumn += len; + if(op[len] == '\0') + return 1; + } + TrErrorAt(tr, tr->mLine, col, "Expected '%s' operator.\n", op); + return 0; +} + +/* Performs a string substitution. Any case-insensitive occurrences of the + * pattern string are replaced with the replacement string. The result is + * truncated if necessary. + */ +static int StrSubst(const char *in, const char *pat, const char *rep, const size_t maxLen, char *out) +{ + size_t inLen, patLen, repLen; + size_t si, di; + int truncated; + + inLen = strlen(in); + patLen = strlen(pat); + repLen = strlen(rep); + si = 0; + di = 0; + truncated = 0; + while(si < inLen && di < maxLen) + { + if(patLen <= inLen-si) + { + if(strncasecmp(&in[si], pat, patLen) == 0) + { + if(repLen > maxLen-di) + { + repLen = maxLen - di; + truncated = 1; + } + strncpy(&out[di], rep, repLen); + si += patLen; + di += repLen; + } + } + out[di] = in[si]; + si++; + di++; + } + if(si < inLen) + truncated = 1; + out[di] = '\0'; + return !truncated; +} + + +/********************* + *** Math routines *** + *********************/ + +// Provide missing math routines for MSVC versions < 1800 (Visual Studio 2013). +#if defined(_MSC_VER) && _MSC_VER < 1800 +static double round(double val) +{ + if(val < 0.0) + return ceil(val-0.5); + return floor(val+0.5); +} + +static double fmin(double a, double b) +{ + return (ab) ? a : b; +} +#endif + +// Simple clamp routine. +static double Clamp(const double val, const double lower, const double upper) +{ + return fmin(fmax(val, lower), upper); +} + +// Performs linear interpolation. +static double Lerp(const double a, const double b, const double f) +{ + return a + (f * (b - a)); +} + +// Performs a high-passed triangular probability density function dither from +// a double to an integer. It assumes the input sample is already scaled. +static int HpTpdfDither(const double in, int *hpHist) +{ + static const double PRNG_SCALE = 1.0 / (RAND_MAX+1.0); + int prn; + double out; + + prn = rand(); + out = round(in + (PRNG_SCALE * (prn - *hpHist))); + *hpHist = prn; + return (int)out; +} + +// Allocates an array of doubles. +static double *CreateArray(size_t n) +{ + double *a; + + if(n == 0) n = 1; + a = calloc(n, sizeof(double)); + if(a == NULL) + { + fprintf(stderr, "Error: Out of memory.\n"); + exit(-1); + } + return a; +} + +// Frees an array of doubles. +static void DestroyArray(double *a) +{ free(a); } + +// Complex number routines. All outputs must be non-NULL. + +// Magnitude/absolute value. +static double ComplexAbs(const double r, const double i) +{ + return sqrt(r*r + i*i); +} + +// Multiply. +static void ComplexMul(const double aR, const double aI, const double bR, const double bI, double *outR, double *outI) +{ + *outR = (aR * bR) - (aI * bI); + *outI = (aI * bR) + (aR * bI); +} + +// Base-e exponent. +static void ComplexExp(const double inR, const double inI, double *outR, double *outI) +{ + double e = exp(inR); + *outR = e * cos(inI); + *outI = e * sin(inI); +} + +/* Fast Fourier transform routines. The number of points must be a power of + * two. In-place operation is possible only if both the real and imaginary + * parts are in-place together. + */ + +// Performs bit-reversal ordering. +static void FftArrange(const uint n, const double *inR, const double *inI, double *outR, double *outI) +{ + uint rk, k, m; + double tempR, tempI; + + if(inR == outR && inI == outI) + { + // Handle in-place arrangement. + rk = 0; + for(k = 0;k < n;k++) + { + if(rk > k) + { + tempR = inR[rk]; + tempI = inI[rk]; + outR[rk] = inR[k]; + outI[rk] = inI[k]; + outR[k] = tempR; + outI[k] = tempI; + } + m = n; + while(rk&(m >>= 1)) + rk &= ~m; + rk |= m; + } + } + else + { + // Handle copy arrangement. + rk = 0; + for(k = 0;k < n;k++) + { + outR[rk] = inR[k]; + outI[rk] = inI[k]; + m = n; + while(rk&(m >>= 1)) + rk &= ~m; + rk |= m; + } + } +} + +// Performs the summation. +static void FftSummation(const uint n, const double s, double *re, double *im) +{ + double pi; + uint m, m2; + double vR, vI, wR, wI; + uint i, k, mk; + double tR, tI; + + pi = s * M_PI; + for(m = 1, m2 = 2;m < n; m <<= 1, m2 <<= 1) + { + // v = Complex (-2.0 * sin (0.5 * pi / m) * sin (0.5 * pi / m), -sin (pi / m)) + vR = sin(0.5 * pi / m); + vR = -2.0 * vR * vR; + vI = -sin(pi / m); + // w = Complex (1.0, 0.0) + wR = 1.0; + wI = 0.0; + for(i = 0;i < m;i++) + { + for(k = i;k < n;k += m2) + { + mk = k + m; + // t = ComplexMul(w, out[km2]) + tR = (wR * re[mk]) - (wI * im[mk]); + tI = (wR * im[mk]) + (wI * re[mk]); + // out[mk] = ComplexSub (out [k], t) + re[mk] = re[k] - tR; + im[mk] = im[k] - tI; + // out[k] = ComplexAdd (out [k], t) + re[k] += tR; + im[k] += tI; + } + // t = ComplexMul (v, w) + tR = (vR * wR) - (vI * wI); + tI = (vR * wI) + (vI * wR); + // w = ComplexAdd (w, t) + wR += tR; + wI += tI; + } + } +} + +// Performs a forward FFT. +static void FftForward(const uint n, const double *inR, const double *inI, double *outR, double *outI) +{ + FftArrange(n, inR, inI, outR, outI); + FftSummation(n, 1.0, outR, outI); +} + +// Performs an inverse FFT. +static void FftInverse(const uint n, const double *inR, const double *inI, double *outR, double *outI) +{ + double f; + uint i; + + FftArrange(n, inR, inI, outR, outI); + FftSummation(n, -1.0, outR, outI); + f = 1.0 / n; + for(i = 0;i < n;i++) + { + outR[i] *= f; + outI[i] *= f; + } +} + +/* Calculate the complex helical sequence (or discrete-time analytical signal) + * of the given input using the Hilbert transform. Given the natural logarithm + * of a signal's magnitude response, the imaginary components can be used as + * the angles for minimum-phase reconstruction. + */ +static void Hilbert(const uint n, const double *in, double *outR, double *outI) +{ + uint i; + + if(in == outR) + { + // Handle in-place operation. + for(i = 0;i < n;i++) + outI[i] = 0.0; + } + else + { + // Handle copy operation. + for(i = 0;i < n;i++) + { + outR[i] = in[i]; + outI[i] = 0.0; + } + } + FftInverse(n, outR, outI, outR, outI); + for(i = 1;i < (n+1)/2;i++) + { + outR[i] *= 2.0; + outI[i] *= 2.0; + } + /* Increment i if n is even. */ + i += (n&1)^1; + for(;i < n;i++) + { + outR[i] = 0.0; + outI[i] = 0.0; + } + FftForward(n, outR, outI, outR, outI); +} + +/* Calculate the magnitude response of the given input. This is used in + * place of phase decomposition, since the phase residuals are discarded for + * minimum phase reconstruction. The mirrored half of the response is also + * discarded. + */ +static void MagnitudeResponse(const uint n, const double *inR, const double *inI, double *out) +{ + const uint m = 1 + (n / 2); + uint i; + for(i = 0;i < m;i++) + out[i] = fmax(ComplexAbs(inR[i], inI[i]), EPSILON); +} + +/* Apply a range limit (in dB) to the given magnitude response. This is used + * to adjust the effects of the diffuse-field average on the equalization + * process. + */ +static void LimitMagnitudeResponse(const uint n, const double limit, const double *in, double *out) +{ + const uint m = 1 + (n / 2); + double halfLim; + uint i, lower, upper; + double ave; + + halfLim = limit / 2.0; + // Convert the response to dB. + for(i = 0;i < m;i++) + out[i] = 20.0 * log10(in[i]); + // Use six octaves to calculate the average magnitude of the signal. + lower = ((uint)ceil(n / pow(2.0, 8.0))) - 1; + upper = ((uint)floor(n / pow(2.0, 2.0))) - 1; + ave = 0.0; + for(i = lower;i <= upper;i++) + ave += out[i]; + ave /= upper - lower + 1; + // Keep the response within range of the average magnitude. + for(i = 0;i < m;i++) + out[i] = Clamp(out[i], ave - halfLim, ave + halfLim); + // Convert the response back to linear magnitude. + for(i = 0;i < m;i++) + out[i] = pow(10.0, out[i] / 20.0); +} + +/* Reconstructs the minimum-phase component for the given magnitude response + * of a signal. This is equivalent to phase recomposition, sans the missing + * residuals (which were discarded). The mirrored half of the response is + * reconstructed. + */ +static void MinimumPhase(const uint n, const double *in, double *outR, double *outI) +{ + const uint m = 1 + (n / 2); + double *mags; + double aR, aI; + uint i; + + mags = CreateArray(n); + for(i = 0;i < m;i++) + { + mags[i] = fmax(EPSILON, in[i]); + outR[i] = log(mags[i]); + } + for(;i < n;i++) + { + mags[i] = mags[n - i]; + outR[i] = outR[n - i]; + } + Hilbert(n, outR, outR, outI); + // Remove any DC offset the filter has. + mags[0] = EPSILON; + for(i = 0;i < n;i++) + { + ComplexExp(0.0, outI[i], &aR, &aI); + ComplexMul(mags[i], 0.0, aR, aI, &outR[i], &outI[i]); + } + DestroyArray(mags); +} + + +/*************************** + *** Resampler functions *** + ***************************/ + +/* This is the normalized cardinal sine (sinc) function. + * + * sinc(x) = { 1, x = 0 + * { sin(pi x) / (pi x), otherwise. + */ +static double Sinc(const double x) +{ + if(fabs(x) < EPSILON) + return 1.0; + return sin(M_PI * x) / (M_PI * x); +} + +/* The zero-order modified Bessel function of the first kind, used for the + * Kaiser window. + * + * I_0(x) = sum_{k=0}^inf (1 / k!)^2 (x / 2)^(2 k) + * = sum_{k=0}^inf ((x / 2)^k / k!)^2 + */ +static double BesselI_0(const double x) +{ + double term, sum, x2, y, last_sum; + int k; + + // Start at k=1 since k=0 is trivial. + term = 1.0; + sum = 1.0; + x2 = x/2.0; + k = 1; + + // Let the integration converge until the term of the sum is no longer + // significant. + do { + y = x2 / k; + k++; + last_sum = sum; + term *= y * y; + sum += term; + } while(sum != last_sum); + return sum; +} + +/* Calculate a Kaiser window from the given beta value and a normalized k + * [-1, 1]. + * + * w(k) = { I_0(B sqrt(1 - k^2)) / I_0(B), -1 <= k <= 1 + * { 0, elsewhere. + * + * Where k can be calculated as: + * + * k = i / l, where -l <= i <= l. + * + * or: + * + * k = 2 i / M - 1, where 0 <= i <= M. + */ +static double Kaiser(const double b, const double k) +{ + if(!(k >= -1.0 && k <= 1.0)) + return 0.0; + return BesselI_0(b * sqrt(1.0 - k*k)) / BesselI_0(b); +} + +// Calculates the greatest common divisor of a and b. +static uint Gcd(uint x, uint y) +{ + while(y > 0) + { + uint z = y; + y = x % y; + x = z; + } + return x; +} + +/* Calculates the size (order) of the Kaiser window. Rejection is in dB and + * the transition width is normalized frequency (0.5 is nyquist). + * + * M = { ceil((r - 7.95) / (2.285 2 pi f_t)), r > 21 + * { ceil(5.79 / 2 pi f_t), r <= 21. + * + */ +static uint CalcKaiserOrder(const double rejection, const double transition) +{ + double w_t = 2.0 * M_PI * transition; + if(rejection > 21.0) + return (uint)ceil((rejection - 7.95) / (2.285 * w_t)); + return (uint)ceil(5.79 / w_t); +} + +// Calculates the beta value of the Kaiser window. Rejection is in dB. +static double CalcKaiserBeta(const double rejection) +{ + if(rejection > 50.0) + return 0.1102 * (rejection - 8.7); + if(rejection >= 21.0) + return (0.5842 * pow(rejection - 21.0, 0.4)) + + (0.07886 * (rejection - 21.0)); + return 0.0; +} + +/* Calculates a point on the Kaiser-windowed sinc filter for the given half- + * width, beta, gain, and cutoff. The point is specified in non-normalized + * samples, from 0 to M, where M = (2 l + 1). + * + * w(k) 2 p f_t sinc(2 f_t x) + * + * x -- centered sample index (i - l) + * k -- normalized and centered window index (x / l) + * w(k) -- window function (Kaiser) + * p -- gain compensation factor when sampling + * f_t -- normalized center frequency (or cutoff; 0.5 is nyquist) + */ +static double SincFilter(const int l, const double b, const double gain, const double cutoff, const int i) +{ + return Kaiser(b, (double)(i - l) / l) * 2.0 * gain * cutoff * Sinc(2.0 * cutoff * (i - l)); +} + +/* This is a polyphase sinc-filtered resampler. + * + * Upsample Downsample + * + * p/q = 3/2 p/q = 3/5 + * + * M-+-+-+-> M-+-+-+-> + * -------------------+ ---------------------+ + * p s * f f f f|f| | p s * f f f f f | + * | 0 * 0 0 0|0|0 | | 0 * 0 0 0 0|0| | + * v 0 * 0 0|0|0 0 | v 0 * 0 0 0|0|0 | + * s * f|f|f f f | s * f f|f|f f | + * 0 * |0|0 0 0 0 | 0 * 0|0|0 0 0 | + * --------+=+--------+ 0 * |0|0 0 0 0 | + * d . d .|d|. d . d ----------+=+--------+ + * d . . . .|d|. . . . + * q-> + * q-+-+-+-> + * + * P_f(i,j) = q i mod p + pj + * P_s(i,j) = floor(q i / p) - j + * d[i=0..N-1] = sum_{j=0}^{floor((M - 1) / p)} { + * { f[P_f(i,j)] s[P_s(i,j)], P_f(i,j) < M + * { 0, P_f(i,j) >= M. } + */ + +// Calculate the resampling metrics and build the Kaiser-windowed sinc filter +// that's used to cut frequencies above the destination nyquist. +static void ResamplerSetup(ResamplerT *rs, const uint srcRate, const uint dstRate) +{ + double cutoff, width, beta; + uint gcd, l; + int i; + + gcd = Gcd(srcRate, dstRate); + rs->mP = dstRate / gcd; + rs->mQ = srcRate / gcd; + /* The cutoff is adjusted by half the transition width, so the transition + * ends before the nyquist (0.5). Both are scaled by the downsampling + * factor. + */ + if(rs->mP > rs->mQ) + { + cutoff = 0.475 / rs->mP; + width = 0.05 / rs->mP; + } + else + { + cutoff = 0.475 / rs->mQ; + width = 0.05 / rs->mQ; + } + // A rejection of -180 dB is used for the stop band. + l = CalcKaiserOrder(180.0, width) / 2; + beta = CalcKaiserBeta(180.0); + rs->mM = (2 * l) + 1; + rs->mL = l; + rs->mF = CreateArray(rs->mM); + for(i = 0;i < ((int)rs->mM);i++) + rs->mF[i] = SincFilter((int)l, beta, rs->mP, cutoff, i); +} + +// Clean up after the resampler. +static void ResamplerClear(ResamplerT *rs) +{ + DestroyArray(rs->mF); + rs->mF = NULL; +} + +// Perform the upsample-filter-downsample resampling operation using a +// polyphase filter implementation. +static void ResamplerRun(ResamplerT *rs, const uint inN, const double *in, const uint outN, double *out) +{ + const uint p = rs->mP, q = rs->mQ, m = rs->mM, l = rs->mL; + const double *f = rs->mF; + uint j_f, j_s; + double *work; + uint i; + + if(outN == 0) + return; + + // Handle in-place operation. + if(in == out) + work = CreateArray(outN); + else + work = out; + // Resample the input. + for(i = 0;i < outN;i++) + { + double r = 0.0; + // Input starts at l to compensate for the filter delay. This will + // drop any build-up from the first half of the filter. + j_f = (l + (q * i)) % p; + j_s = (l + (q * i)) / p; + while(j_f < m) + { + // Only take input when 0 <= j_s < inN. This single unsigned + // comparison catches both cases. + if(j_s < inN) + r += f[j_f] * in[j_s]; + j_f += p; + j_s--; + } + work[i] = r; + } + // Clean up after in-place operation. + if(in == out) + { + for(i = 0;i < outN;i++) + out[i] = work[i]; + DestroyArray(work); + } +} + +/************************* + *** File source input *** + *************************/ + +// Read a binary value of the specified byte order and byte size from a file, +// storing it as a 32-bit unsigned integer. +static int ReadBin4(FILE *fp, const char *filename, const ByteOrderT order, const uint bytes, uint32 *out) +{ + uint8 in[4]; + uint32 accum; + uint i; + + if(fread(in, 1, bytes, fp) != bytes) + { + fprintf(stderr, "Error: Bad read from file '%s'.\n", filename); + return 0; + } + accum = 0; + switch(order) + { + case BO_LITTLE: + for(i = 0;i < bytes;i++) + accum = (accum<<8) | in[bytes - i - 1]; + break; + case BO_BIG: + for(i = 0;i < bytes;i++) + accum = (accum<<8) | in[i]; + break; + default: + break; + } + *out = accum; + return 1; +} + +// Read a binary value of the specified byte order from a file, storing it as +// a 64-bit unsigned integer. +static int ReadBin8(FILE *fp, const char *filename, const ByteOrderT order, uint64 *out) +{ + uint8 in [8]; + uint64 accum; + uint i; + + if(fread(in, 1, 8, fp) != 8) + { + fprintf(stderr, "Error: Bad read from file '%s'.\n", filename); + return 0; + } + accum = 0ULL; + switch(order) + { + case BO_LITTLE: + for(i = 0;i < 8;i++) + accum = (accum<<8) | in[8 - i - 1]; + break; + case BO_BIG: + for(i = 0;i < 8;i++) + accum = (accum<<8) | in[i]; + break; + default: + break; + } + *out = accum; + return 1; +} + +/* Read a binary value of the specified type, byte order, and byte size from + * a file, converting it to a double. For integer types, the significant + * bits are used to normalize the result. The sign of bits determines + * whether they are padded toward the MSB (negative) or LSB (positive). + * Floating-point types are not normalized. + */ +static int ReadBinAsDouble(FILE *fp, const char *filename, const ByteOrderT order, const ElementTypeT type, const uint bytes, const int bits, double *out) +{ + union { + uint32 ui; + int32 i; + float f; + } v4; + union { + uint64 ui; + double f; + } v8; + + *out = 0.0; + if(bytes > 4) + { + if(!ReadBin8(fp, filename, order, &v8.ui)) + return 0; + if(type == ET_FP) + *out = v8.f; + } + else + { + if(!ReadBin4(fp, filename, order, bytes, &v4.ui)) + return 0; + if(type == ET_FP) + *out = v4.f; + else + { + if(bits > 0) + v4.ui >>= (8*bytes) - ((uint)bits); + else + v4.ui &= (0xFFFFFFFF >> (32+bits)); + + if(v4.ui&(uint)(1<<(abs(bits)-1))) + v4.ui |= (0xFFFFFFFF << abs (bits)); + *out = v4.i / (double)(1<<(abs(bits)-1)); + } + } + return 1; +} + +/* Read an ascii value of the specified type from a file, converting it to a + * double. For integer types, the significant bits are used to normalize the + * result. The sign of the bits should always be positive. This also skips + * up to one separator character before the element itself. + */ +static int ReadAsciiAsDouble(TokenReaderT *tr, const char *filename, const ElementTypeT type, const uint bits, double *out) +{ + if(TrIsOperator(tr, ",")) + TrReadOperator(tr, ","); + else if(TrIsOperator(tr, ":")) + TrReadOperator(tr, ":"); + else if(TrIsOperator(tr, ";")) + TrReadOperator(tr, ";"); + else if(TrIsOperator(tr, "|")) + TrReadOperator(tr, "|"); + + if(type == ET_FP) + { + if(!TrReadFloat(tr, -HUGE_VAL, HUGE_VAL, out)) + { + fprintf(stderr, "Error: Bad read from file '%s'.\n", filename); + return 0; + } + } + else + { + int v; + if(!TrReadInt(tr, -(1<<(bits-1)), (1<<(bits-1))-1, &v)) + { + fprintf(stderr, "Error: Bad read from file '%s'.\n", filename); + return 0; + } + *out = v / (double)((1<<(bits-1))-1); + } + return 1; +} + +// Read the RIFF/RIFX WAVE format chunk from a file, validating it against +// the source parameters and data set metrics. +static int ReadWaveFormat(FILE *fp, const ByteOrderT order, const uint hrirRate, SourceRefT *src) +{ + uint32 fourCC, chunkSize; + uint32 format, channels, rate, dummy, block, size, bits; + + chunkSize = 0; + do { + if (chunkSize > 0) + fseek (fp, (long) chunkSize, SEEK_CUR); + if(!ReadBin4(fp, src->mPath, BO_LITTLE, 4, &fourCC) || + !ReadBin4(fp, src->mPath, order, 4, &chunkSize)) + return 0; + } while(fourCC != FOURCC_FMT); + if(!ReadBin4(fp, src->mPath, order, 2, & format) || + !ReadBin4(fp, src->mPath, order, 2, & channels) || + !ReadBin4(fp, src->mPath, order, 4, & rate) || + !ReadBin4(fp, src->mPath, order, 4, & dummy) || + !ReadBin4(fp, src->mPath, order, 2, & block)) + return (0); + block /= channels; + if(chunkSize > 14) + { + if(!ReadBin4(fp, src->mPath, order, 2, &size)) + return 0; + size /= 8; + if(block > size) + size = block; + } + else + size = block; + if(format == WAVE_FORMAT_EXTENSIBLE) + { + fseek(fp, 2, SEEK_CUR); + if(!ReadBin4(fp, src->mPath, order, 2, &bits)) + return 0; + if(bits == 0) + bits = 8 * size; + fseek(fp, 4, SEEK_CUR); + if(!ReadBin4(fp, src->mPath, order, 2, &format)) + return 0; + fseek(fp, (long)(chunkSize - 26), SEEK_CUR); + } + else + { + bits = 8 * size; + if(chunkSize > 14) + fseek(fp, (long)(chunkSize - 16), SEEK_CUR); + else + fseek(fp, (long)(chunkSize - 14), SEEK_CUR); + } + if(format != WAVE_FORMAT_PCM && format != WAVE_FORMAT_IEEE_FLOAT) + { + fprintf(stderr, "Error: Unsupported WAVE format in file '%s'.\n", src->mPath); + return 0; + } + if(src->mChannel >= channels) + { + fprintf(stderr, "Error: Missing source channel in WAVE file '%s'.\n", src->mPath); + return 0; + } + if(rate != hrirRate) + { + fprintf(stderr, "Error: Mismatched source sample rate in WAVE file '%s'.\n", src->mPath); + return 0; + } + if(format == WAVE_FORMAT_PCM) + { + if(size < 2 || size > 4) + { + fprintf(stderr, "Error: Unsupported sample size in WAVE file '%s'.\n", src->mPath); + return 0; + } + if(bits < 16 || bits > (8*size)) + { + fprintf (stderr, "Error: Bad significant bits in WAVE file '%s'.\n", src->mPath); + return 0; + } + src->mType = ET_INT; + } + else + { + if(size != 4 && size != 8) + { + fprintf(stderr, "Error: Unsupported sample size in WAVE file '%s'.\n", src->mPath); + return 0; + } + src->mType = ET_FP; + } + src->mSize = size; + src->mBits = (int)bits; + src->mSkip = channels; + return 1; +} + +// Read a RIFF/RIFX WAVE data chunk, converting all elements to doubles. +static int ReadWaveData(FILE *fp, const SourceRefT *src, const ByteOrderT order, const uint n, double *hrir) +{ + int pre, post, skip; + uint i; + + pre = (int)(src->mSize * src->mChannel); + post = (int)(src->mSize * (src->mSkip - src->mChannel - 1)); + skip = 0; + for(i = 0;i < n;i++) + { + skip += pre; + if(skip > 0) + fseek(fp, skip, SEEK_CUR); + if(!ReadBinAsDouble(fp, src->mPath, order, src->mType, src->mSize, src->mBits, &hrir[i])) + return 0; + skip = post; + } + if(skip > 0) + fseek(fp, skip, SEEK_CUR); + return 1; +} + +// Read the RIFF/RIFX WAVE list or data chunk, converting all elements to +// doubles. +static int ReadWaveList(FILE *fp, const SourceRefT *src, const ByteOrderT order, const uint n, double *hrir) +{ + uint32 fourCC, chunkSize, listSize, count; + uint block, skip, offset, i; + double lastSample; + + for (;;) { + if(!ReadBin4(fp, src->mPath, BO_LITTLE, 4, & fourCC) || + !ReadBin4(fp, src->mPath, order, 4, & chunkSize)) + return (0); + + if(fourCC == FOURCC_DATA) + { + block = src->mSize * src->mSkip; + count = chunkSize / block; + if(count < (src->mOffset + n)) + { + fprintf(stderr, "Error: Bad read from file '%s'.\n", src->mPath); + return 0; + } + fseek(fp, (long)(src->mOffset * block), SEEK_CUR); + if(!ReadWaveData(fp, src, order, n, &hrir[0])) + return 0; + return 1; + } + else if(fourCC == FOURCC_LIST) + { + if(!ReadBin4(fp, src->mPath, BO_LITTLE, 4, &fourCC)) + return 0; + chunkSize -= 4; + if(fourCC == FOURCC_WAVL) + break; + } + if(chunkSize > 0) + fseek(fp, (long)chunkSize, SEEK_CUR); + } + listSize = chunkSize; + block = src->mSize * src->mSkip; + skip = src->mOffset; + offset = 0; + lastSample = 0.0; + while(offset < n && listSize > 8) + { + if(!ReadBin4(fp, src->mPath, BO_LITTLE, 4, &fourCC) || + !ReadBin4(fp, src->mPath, order, 4, &chunkSize)) + return 0; + listSize -= 8 + chunkSize; + if(fourCC == FOURCC_DATA) + { + count = chunkSize / block; + if(count > skip) + { + fseek(fp, (long)(skip * block), SEEK_CUR); + chunkSize -= skip * block; + count -= skip; + skip = 0; + if(count > (n - offset)) + count = n - offset; + if(!ReadWaveData(fp, src, order, count, &hrir[offset])) + return 0; + chunkSize -= count * block; + offset += count; + lastSample = hrir [offset - 1]; + } + else + { + skip -= count; + count = 0; + } + } + else if(fourCC == FOURCC_SLNT) + { + if(!ReadBin4(fp, src->mPath, order, 4, &count)) + return 0; + chunkSize -= 4; + if(count > skip) + { + count -= skip; + skip = 0; + if(count > (n - offset)) + count = n - offset; + for(i = 0; i < count; i ++) + hrir[offset + i] = lastSample; + offset += count; + } + else + { + skip -= count; + count = 0; + } + } + if(chunkSize > 0) + fseek(fp, (long)chunkSize, SEEK_CUR); + } + if(offset < n) + { + fprintf(stderr, "Error: Bad read from file '%s'.\n", src->mPath); + return 0; + } + return 1; +} + +// Load a source HRIR from a RIFF/RIFX WAVE file. +static int LoadWaveSource(FILE *fp, SourceRefT *src, const uint hrirRate, const uint n, double *hrir) +{ + uint32 fourCC, dummy; + ByteOrderT order; + + if(!ReadBin4(fp, src->mPath, BO_LITTLE, 4, &fourCC) || + !ReadBin4(fp, src->mPath, BO_LITTLE, 4, &dummy)) + return 0; + if(fourCC == FOURCC_RIFF) + order = BO_LITTLE; + else if(fourCC == FOURCC_RIFX) + order = BO_BIG; + else + { + fprintf(stderr, "Error: No RIFF/RIFX chunk in file '%s'.\n", src->mPath); + return 0; + } + + if(!ReadBin4(fp, src->mPath, BO_LITTLE, 4, &fourCC)) + return 0; + if(fourCC != FOURCC_WAVE) + { + fprintf(stderr, "Error: Not a RIFF/RIFX WAVE file '%s'.\n", src->mPath); + return 0; + } + if(!ReadWaveFormat(fp, order, hrirRate, src)) + return 0; + if(!ReadWaveList(fp, src, order, n, hrir)) + return 0; + return 1; +} + +// Load a source HRIR from a binary file. +static int LoadBinarySource(FILE *fp, const SourceRefT *src, const ByteOrderT order, const uint n, double *hrir) +{ + uint i; + + fseek(fp, (long)src->mOffset, SEEK_SET); + for(i = 0;i < n;i++) + { + if(!ReadBinAsDouble(fp, src->mPath, order, src->mType, src->mSize, src->mBits, &hrir[i])) + return 0; + if(src->mSkip > 0) + fseek(fp, (long)src->mSkip, SEEK_CUR); + } + return 1; +} + +// Load a source HRIR from an ASCII text file containing a list of elements +// separated by whitespace or common list operators (',', ';', ':', '|'). +static int LoadAsciiSource(FILE *fp, const SourceRefT *src, const uint n, double *hrir) +{ + TokenReaderT tr; + uint i, j; + double dummy; + + TrSetup(fp, NULL, &tr); + for(i = 0;i < src->mOffset;i++) + { + if(!ReadAsciiAsDouble(&tr, src->mPath, src->mType, (uint)src->mBits, &dummy)) + return (0); + } + for(i = 0;i < n;i++) + { + if(!ReadAsciiAsDouble(&tr, src->mPath, src->mType, (uint)src->mBits, &hrir[i])) + return 0; + for(j = 0;j < src->mSkip;j++) + { + if(!ReadAsciiAsDouble(&tr, src->mPath, src->mType, (uint)src->mBits, &dummy)) + return 0; + } + } + return 1; +} + +// Load a source HRIR from a supported file type. +static int LoadSource(SourceRefT *src, const uint hrirRate, const uint n, double *hrir) +{ + int result; + FILE *fp; + + if (src->mFormat == SF_ASCII) + fp = fopen(src->mPath, "r"); + else + fp = fopen(src->mPath, "rb"); + if(fp == NULL) + { + fprintf(stderr, "Error: Could not open source file '%s'.\n", src->mPath); + return 0; + } + if(src->mFormat == SF_WAVE) + result = LoadWaveSource(fp, src, hrirRate, n, hrir); + else if(src->mFormat == SF_BIN_LE) + result = LoadBinarySource(fp, src, BO_LITTLE, n, hrir); + else if(src->mFormat == SF_BIN_BE) + result = LoadBinarySource(fp, src, BO_BIG, n, hrir); + else + result = LoadAsciiSource(fp, src, n, hrir); + fclose(fp); + return result; +} + + +/*************************** + *** File storage output *** + ***************************/ + +// Write an ASCII string to a file. +static int WriteAscii(const char *out, FILE *fp, const char *filename) +{ + size_t len; + + len = strlen(out); + if(fwrite(out, 1, len, fp) != len) + { + fclose(fp); + fprintf(stderr, "Error: Bad write to file '%s'.\n", filename); + return 0; + } + return 1; +} + +// Write a binary value of the given byte order and byte size to a file, +// loading it from a 32-bit unsigned integer. +static int WriteBin4(const ByteOrderT order, const uint bytes, const uint32 in, FILE *fp, const char *filename) +{ + uint8 out[4]; + uint i; + + switch(order) + { + case BO_LITTLE: + for(i = 0;i < bytes;i++) + out[i] = (in>>(i*8)) & 0x000000FF; + break; + case BO_BIG: + for(i = 0;i < bytes;i++) + out[bytes - i - 1] = (in>>(i*8)) & 0x000000FF; + break; + default: + break; + } + if(fwrite(out, 1, bytes, fp) != bytes) + { + fprintf(stderr, "Error: Bad write to file '%s'.\n", filename); + return 0; + } + return 1; +} + +// Store the OpenAL Soft HRTF data set. +static int StoreMhr(const HrirDataT *hData, const char *filename) +{ + uint e, step, end, n, j, i; + int hpHist, v; + FILE *fp; + + if((fp=fopen(filename, "wb")) == NULL) + { + fprintf(stderr, "Error: Could not open MHR file '%s'.\n", filename); + return 0; + } + if(!WriteAscii(MHR_FORMAT, fp, filename)) + return 0; + if(!WriteBin4(BO_LITTLE, 4, (uint32)hData->mIrRate, fp, filename)) + return 0; + if(!WriteBin4(BO_LITTLE, 1, (uint32)hData->mIrPoints, fp, filename)) + return 0; + if(!WriteBin4(BO_LITTLE, 1, (uint32)hData->mEvCount, fp, filename)) + return 0; + for(e = 0;e < hData->mEvCount;e++) + { + if(!WriteBin4(BO_LITTLE, 1, (uint32)hData->mAzCount[e], fp, filename)) + return 0; + } + step = hData->mIrSize; + end = hData->mIrCount * step; + n = hData->mIrPoints; + srand(0x31DF840C); + for(j = 0;j < end;j += step) + { + hpHist = 0; + for(i = 0;i < n;i++) + { + v = HpTpdfDither(32767.0 * hData->mHrirs[j+i], &hpHist); + if(!WriteBin4(BO_LITTLE, 2, (uint32)v, fp, filename)) + return 0; + } + } + for(j = 0;j < hData->mIrCount;j++) + { + v = (int)fmin(round(hData->mIrRate * hData->mHrtds[j]), MAX_HRTD); + if(!WriteBin4(BO_LITTLE, 1, (uint32)v, fp, filename)) + return 0; + } + fclose(fp); + return 1; +} + + +/*********************** + *** HRTF processing *** + ***********************/ + +// Calculate the onset time of an HRIR and average it with any existing +// timing for its elevation and azimuth. +static void AverageHrirOnset(const double *hrir, const double f, const uint ei, const uint ai, const HrirDataT *hData) +{ + double mag; + uint n, i, j; + + mag = 0.0; + n = hData->mIrPoints; + for(i = 0;i < n;i++) + mag = fmax(fabs(hrir[i]), mag); + mag *= 0.15; + for(i = 0;i < n;i++) + { + if(fabs(hrir[i]) >= mag) + break; + } + j = hData->mEvOffset[ei] + ai; + hData->mHrtds[j] = Lerp(hData->mHrtds[j], ((double)i) / hData->mIrRate, f); +} + +// Calculate the magnitude response of an HRIR and average it with any +// existing responses for its elevation and azimuth. +static void AverageHrirMagnitude(const double *hrir, const double f, const uint ei, const uint ai, const HrirDataT *hData) +{ + double *re, *im; + uint n, m, i, j; + + n = hData->mFftSize; + re = CreateArray(n); + im = CreateArray(n); + for(i = 0;i < hData->mIrPoints;i++) + { + re[i] = hrir[i]; + im[i] = 0.0; + } + for(;i < n;i++) + { + re[i] = 0.0; + im[i] = 0.0; + } + FftForward(n, re, im, re, im); + MagnitudeResponse(n, re, im, re); + m = 1 + (n / 2); + j = (hData->mEvOffset[ei] + ai) * hData->mIrSize; + for(i = 0;i < m;i++) + hData->mHrirs[j+i] = Lerp(hData->mHrirs[j+i], re[i], f); + DestroyArray(im); + DestroyArray(re); +} + +/* Calculate the contribution of each HRIR to the diffuse-field average based + * on the area of its surface patch. All patches are centered at the HRIR + * coordinates on the unit sphere and are measured by solid angle. + */ +static void CalculateDfWeights(const HrirDataT *hData, double *weights) +{ + double evs, sum, ev, up_ev, down_ev, solidAngle; + uint ei; + + evs = 90.0 / (hData->mEvCount - 1); + sum = 0.0; + for(ei = hData->mEvStart;ei < hData->mEvCount;ei++) + { + // For each elevation, calculate the upper and lower limits of the + // patch band. + ev = -90.0 + (ei * 2.0 * evs); + if(ei < (hData->mEvCount - 1)) + up_ev = (ev + evs) * M_PI / 180.0; + else + up_ev = M_PI / 2.0; + if(ei > 0) + down_ev = (ev - evs) * M_PI / 180.0; + else + down_ev = -M_PI / 2.0; + // Calculate the area of the patch band. + solidAngle = 2.0 * M_PI * (sin(up_ev) - sin(down_ev)); + // Each weight is the area of one patch. + weights[ei] = solidAngle / hData->mAzCount [ei]; + // Sum the total surface area covered by the HRIRs. + sum += solidAngle; + } + // Normalize the weights given the total surface coverage. + for(ei = hData->mEvStart;ei < hData->mEvCount;ei++) + weights[ei] /= sum; +} + +/* Calculate the diffuse-field average from the given magnitude responses of + * the HRIR set. Weighting can be applied to compensate for the varying + * surface area covered by each HRIR. The final average can then be limited + * by the specified magnitude range (in positive dB; 0.0 to skip). + */ +static void CalculateDiffuseFieldAverage(const HrirDataT *hData, const int weighted, const double limit, double *dfa) +{ + uint ei, ai, count, step, start, end, m, j, i; + double *weights; + + weights = CreateArray(hData->mEvCount); + if(weighted) + { + // Use coverage weighting to calculate the average. + CalculateDfWeights(hData, weights); + } + else + { + // If coverage weighting is not used, the weights still need to be + // averaged by the number of HRIRs. + count = 0; + for(ei = hData->mEvStart;ei < hData->mEvCount;ei++) + count += hData->mAzCount [ei]; + for(ei = hData->mEvStart;ei < hData->mEvCount;ei++) + weights[ei] = 1.0 / count; + } + ei = hData->mEvStart; + ai = 0; + step = hData->mIrSize; + start = hData->mEvOffset[ei] * step; + end = hData->mIrCount * step; + m = 1 + (hData->mFftSize / 2); + for(i = 0;i < m;i++) + dfa[i] = 0.0; + for(j = start;j < end;j += step) + { + // Get the weight for this HRIR's contribution. + double weight = weights[ei]; + // Add this HRIR's weighted power average to the total. + for(i = 0;i < m;i++) + dfa[i] += weight * hData->mHrirs[j+i] * hData->mHrirs[j+i]; + // Determine the next weight to use. + ai++; + if(ai >= hData->mAzCount[ei]) + { + ei++; + ai = 0; + } + } + // Finish the average calculation and keep it from being too small. + for(i = 0;i < m;i++) + dfa[i] = fmax(sqrt(dfa[i]), EPSILON); + // Apply a limit to the magnitude range of the diffuse-field average if + // desired. + if(limit > 0.0) + LimitMagnitudeResponse(hData->mFftSize, limit, dfa, dfa); + DestroyArray(weights); +} + +// Perform diffuse-field equalization on the magnitude responses of the HRIR +// set using the given average response. +static void DiffuseFieldEqualize(const double *dfa, const HrirDataT *hData) +{ + uint step, start, end, m, j, i; + + step = hData->mIrSize; + start = hData->mEvOffset[hData->mEvStart] * step; + end = hData->mIrCount * step; + m = 1 + (hData->mFftSize / 2); + for(j = start;j < end;j += step) + { + for(i = 0;i < m;i++) + hData->mHrirs[j+i] /= dfa[i]; + } +} + +// Perform minimum-phase reconstruction using the magnitude responses of the +// HRIR set. +static void ReconstructHrirs(const HrirDataT *hData) +{ + uint step, start, end, n, j, i; + double *re, *im; + + step = hData->mIrSize; + start = hData->mEvOffset[hData->mEvStart] * step; + end = hData->mIrCount * step; + n = hData->mFftSize; + re = CreateArray(n); + im = CreateArray(n); + for(j = start;j < end;j += step) + { + MinimumPhase(n, &hData->mHrirs[j], re, im); + FftInverse(n, re, im, re, im); + for(i = 0;i < hData->mIrPoints;i++) + hData->mHrirs[j+i] = re[i]; + } + DestroyArray (im); + DestroyArray (re); +} + +// Resamples the HRIRs for use at the given sampling rate. +static void ResampleHrirs(const uint rate, HrirDataT *hData) +{ + uint n, step, start, end, j; + ResamplerT rs; + + ResamplerSetup(&rs, hData->mIrRate, rate); + n = hData->mIrPoints; + step = hData->mIrSize; + start = hData->mEvOffset[hData->mEvStart] * step; + end = hData->mIrCount * step; + for(j = start;j < end;j += step) + ResamplerRun(&rs, n, &hData->mHrirs[j], n, &hData->mHrirs[j]); + ResamplerClear(&rs); + hData->mIrRate = rate; +} + +/* Given an elevation index and an azimuth, calculate the indices of the two + * HRIRs that bound the coordinate along with a factor for calculating the + * continous HRIR using interpolation. + */ +static void CalcAzIndices(const HrirDataT *hData, const uint ei, const double az, uint *j0, uint *j1, double *jf) +{ + double af; + uint ai; + + af = ((2.0*M_PI) + az) * hData->mAzCount[ei] / (2.0*M_PI); + ai = ((uint)af) % hData->mAzCount[ei]; + af -= floor(af); + + *j0 = hData->mEvOffset[ei] + ai; + *j1 = hData->mEvOffset[ei] + ((ai+1) % hData->mAzCount [ei]); + *jf = af; +} + +// Synthesize any missing onset timings at the bottom elevations. This just +// blends between slightly exaggerated known onsets. Not an accurate model. +static void SynthesizeOnsets(HrirDataT *hData) +{ + uint oi, e, a, j0, j1; + double t, of, jf; + + oi = hData->mEvStart; + t = 0.0; + for(a = 0;a < hData->mAzCount[oi];a++) + t += hData->mHrtds[hData->mEvOffset[oi] + a]; + hData->mHrtds[0] = 1.32e-4 + (t / hData->mAzCount[oi]); + for(e = 1;e < hData->mEvStart;e++) + { + of = ((double)e) / hData->mEvStart; + for(a = 0;a < hData->mAzCount[e];a++) + { + CalcAzIndices(hData, oi, a * 2.0 * M_PI / hData->mAzCount[e], &j0, &j1, &jf); + hData->mHrtds[hData->mEvOffset[e] + a] = Lerp(hData->mHrtds[0], Lerp(hData->mHrtds[j0], hData->mHrtds[j1], jf), of); + } + } +} + +/* Attempt to synthesize any missing HRIRs at the bottom elevations. Right + * now this just blends the lowest elevation HRIRs together and applies some + * attenuation and high frequency damping. It is a simple, if inaccurate + * model. + */ +static void SynthesizeHrirs (HrirDataT *hData) +{ + uint oi, a, e, step, n, i, j; + double lp[4], s0, s1; + double of, b; + uint j0, j1; + double jf; + + if(hData->mEvStart <= 0) + return; + step = hData->mIrSize; + oi = hData->mEvStart; + n = hData->mIrPoints; + for(i = 0;i < n;i++) + hData->mHrirs[i] = 0.0; + for(a = 0;a < hData->mAzCount[oi];a++) + { + j = (hData->mEvOffset[oi] + a) * step; + for(i = 0;i < n;i++) + hData->mHrirs[i] += hData->mHrirs[j+i] / hData->mAzCount[oi]; + } + for(e = 1;e < hData->mEvStart;e++) + { + of = ((double)e) / hData->mEvStart; + b = (1.0 - of) * (3.5e-6 * hData->mIrRate); + for(a = 0;a < hData->mAzCount[e];a++) + { + j = (hData->mEvOffset[e] + a) * step; + CalcAzIndices(hData, oi, a * 2.0 * M_PI / hData->mAzCount[e], &j0, &j1, &jf); + j0 *= step; + j1 *= step; + lp[0] = 0.0; + lp[1] = 0.0; + lp[2] = 0.0; + lp[3] = 0.0; + for(i = 0;i < n;i++) + { + s0 = hData->mHrirs[i]; + s1 = Lerp(hData->mHrirs[j0+i], hData->mHrirs[j1+i], jf); + s0 = Lerp(s0, s1, of); + lp[0] = Lerp(s0, lp[0], b); + lp[1] = Lerp(lp[0], lp[1], b); + lp[2] = Lerp(lp[1], lp[2], b); + lp[3] = Lerp(lp[2], lp[3], b); + hData->mHrirs[j+i] = lp[3]; + } + } + } + b = 3.5e-6 * hData->mIrRate; + lp[0] = 0.0; + lp[1] = 0.0; + lp[2] = 0.0; + lp[3] = 0.0; + for(i = 0;i < n;i++) + { + s0 = hData->mHrirs[i]; + lp[0] = Lerp(s0, lp[0], b); + lp[1] = Lerp(lp[0], lp[1], b); + lp[2] = Lerp(lp[1], lp[2], b); + lp[3] = Lerp(lp[2], lp[3], b); + hData->mHrirs[i] = lp[3]; + } + hData->mEvStart = 0; +} + +// The following routines assume a full set of HRIRs for all elevations. + +// Normalize the HRIR set and slightly attenuate the result. +static void NormalizeHrirs (const HrirDataT *hData) +{ + uint step, end, n, j, i; + double maxLevel; + + step = hData->mIrSize; + end = hData->mIrCount * step; + n = hData->mIrPoints; + maxLevel = 0.0; + for(j = 0;j < end;j += step) + { + for(i = 0;i < n;i++) + maxLevel = fmax(fabs(hData->mHrirs[j+i]), maxLevel); + } + maxLevel = 1.01 * maxLevel; + for(j = 0;j < end;j += step) + { + for(i = 0;i < n;i++) + hData->mHrirs[j+i] /= maxLevel; + } +} + +// Calculate the left-ear time delay using a spherical head model. +static double CalcLTD(const double ev, const double az, const double rad, const double dist) +{ + double azp, dlp, l, al; + + azp = asin(cos(ev) * sin(az)); + dlp = sqrt((dist*dist) + (rad*rad) + (2.0*dist*rad*sin(azp))); + l = sqrt((dist*dist) - (rad*rad)); + al = (0.5 * M_PI) + azp; + if(dlp > l) + dlp = l + (rad * (al - acos(rad / dist))); + return (dlp / 343.3); +} + +// Calculate the effective head-related time delays for each minimum-phase +// HRIR. +static void CalculateHrtds (const HeadModelT model, const double radius, HrirDataT *hData) +{ + double minHrtd, maxHrtd; + uint e, a, j; + double t; + + minHrtd = 1000.0; + maxHrtd = -1000.0; + for(e = 0;e < hData->mEvCount;e++) + { + for(a = 0;a < hData->mAzCount[e];a++) + { + j = hData->mEvOffset[e] + a; + if(model == HM_DATASET) + t = hData->mHrtds[j] * radius / hData->mRadius; + else + t = CalcLTD((-90.0 + (e * 180.0 / (hData->mEvCount - 1))) * M_PI / 180.0, + (a * 360.0 / hData->mAzCount [e]) * M_PI / 180.0, + radius, hData->mDistance); + hData->mHrtds[j] = t; + maxHrtd = fmax(t, maxHrtd); + minHrtd = fmin(t, minHrtd); + } + } + maxHrtd -= minHrtd; + for(j = 0;j < hData->mIrCount;j++) + hData->mHrtds[j] -= minHrtd; + hData->mMaxHrtd = maxHrtd; +} + + +// Process the data set definition to read and validate the data set metrics. +static int ProcessMetrics(TokenReaderT *tr, const uint fftSize, const uint truncSize, HrirDataT *hData) +{ + int hasRate = 0, hasPoints = 0, hasAzimuths = 0; + int hasRadius = 0, hasDistance = 0; + char ident[MAX_IDENT_LEN+1]; + uint line, col; + double fpVal; + uint points; + int intVal; + + while(!(hasRate && hasPoints && hasAzimuths && hasRadius && hasDistance)) + { + TrIndication(tr, & line, & col); + if(!TrReadIdent(tr, MAX_IDENT_LEN, ident)) + return 0; + if(strcasecmp(ident, "rate") == 0) + { + if(hasRate) + { + TrErrorAt(tr, line, col, "Redefinition of 'rate'.\n"); + return 0; + } + if(!TrReadOperator(tr, "=")) + return 0; + if(!TrReadInt(tr, MIN_RATE, MAX_RATE, &intVal)) + return 0; + hData->mIrRate = (uint)intVal; + hasRate = 1; + } + else if(strcasecmp(ident, "points") == 0) + { + if (hasPoints) { + TrErrorAt(tr, line, col, "Redefinition of 'points'.\n"); + return 0; + } + if(!TrReadOperator(tr, "=")) + return 0; + TrIndication(tr, &line, &col); + if(!TrReadInt(tr, MIN_POINTS, MAX_POINTS, &intVal)) + return 0; + points = (uint)intVal; + if(fftSize > 0 && points > fftSize) + { + TrErrorAt(tr, line, col, "Value exceeds the overridden FFT size.\n"); + return 0; + } + if(points < truncSize) + { + TrErrorAt(tr, line, col, "Value is below the truncation size.\n"); + return 0; + } + hData->mIrPoints = points; + if(fftSize <= 0) + { + hData->mFftSize = DEFAULT_FFTSIZE; + hData->mIrSize = 1 + (DEFAULT_FFTSIZE / 2); + } + else + { + hData->mFftSize = fftSize; + hData->mIrSize = 1 + (fftSize / 2); + if(points > hData->mIrSize) + hData->mIrSize = points; + } + hasPoints = 1; + } + else if(strcasecmp(ident, "azimuths") == 0) + { + if(hasAzimuths) + { + TrErrorAt(tr, line, col, "Redefinition of 'azimuths'.\n"); + return 0; + } + if(!TrReadOperator(tr, "=")) + return 0; + hData->mIrCount = 0; + hData->mEvCount = 0; + hData->mEvOffset[0] = 0; + for(;;) + { + if(!TrReadInt(tr, MIN_AZ_COUNT, MAX_AZ_COUNT, &intVal)) + return 0; + hData->mAzCount[hData->mEvCount] = (uint)intVal; + hData->mIrCount += (uint)intVal; + hData->mEvCount ++; + if(!TrIsOperator(tr, ",")) + break; + if(hData->mEvCount >= MAX_EV_COUNT) + { + TrError(tr, "Exceeded the maximum of %d elevations.\n", MAX_EV_COUNT); + return 0; + } + hData->mEvOffset[hData->mEvCount] = hData->mEvOffset[hData->mEvCount - 1] + ((uint)intVal); + TrReadOperator(tr, ","); + } + if(hData->mEvCount < MIN_EV_COUNT) + { + TrErrorAt(tr, line, col, "Did not reach the minimum of %d azimuth counts.\n", MIN_EV_COUNT); + return 0; + } + hasAzimuths = 1; + } + else if(strcasecmp(ident, "radius") == 0) + { + if(hasRadius) + { + TrErrorAt(tr, line, col, "Redefinition of 'radius'.\n"); + return 0; + } + if(!TrReadOperator(tr, "=")) + return 0; + if(!TrReadFloat(tr, MIN_RADIUS, MAX_RADIUS, &fpVal)) + return 0; + hData->mRadius = fpVal; + hasRadius = 1; + } + else if(strcasecmp(ident, "distance") == 0) + { + if(hasDistance) + { + TrErrorAt(tr, line, col, "Redefinition of 'distance'.\n"); + return 0; + } + if(!TrReadOperator(tr, "=")) + return 0; + if(!TrReadFloat(tr, MIN_DISTANCE, MAX_DISTANCE, & fpVal)) + return 0; + hData->mDistance = fpVal; + hasDistance = 1; + } + else + { + TrErrorAt(tr, line, col, "Expected a metric name.\n"); + return 0; + } + TrSkipWhitespace (tr); + } + return 1; +} + +// Parse an index pair from the data set definition. +static int ReadIndexPair(TokenReaderT *tr, const HrirDataT *hData, uint *ei, uint *ai) +{ + int intVal; + if(!TrReadInt(tr, 0, (int)hData->mEvCount, &intVal)) + return 0; + *ei = (uint)intVal; + if(!TrReadOperator(tr, ",")) + return 0; + if(!TrReadInt(tr, 0, (int)hData->mAzCount[*ei], &intVal)) + return 0; + *ai = (uint)intVal; + return 1; +} + +// Match the source format from a given identifier. +static SourceFormatT MatchSourceFormat(const char *ident) +{ + if(strcasecmp(ident, "wave") == 0) + return SF_WAVE; + if(strcasecmp(ident, "bin_le") == 0) + return SF_BIN_LE; + if(strcasecmp(ident, "bin_be") == 0) + return SF_BIN_BE; + if(strcasecmp(ident, "ascii") == 0) + return SF_ASCII; + return SF_NONE; +} + +// Match the source element type from a given identifier. +static ElementTypeT MatchElementType(const char *ident) +{ + if(strcasecmp(ident, "int") == 0) + return ET_INT; + if(strcasecmp(ident, "fp") == 0) + return ET_FP; + return ET_NONE; +} + +// Parse and validate a source reference from the data set definition. +static int ReadSourceRef(TokenReaderT *tr, SourceRefT *src) +{ + char ident[MAX_IDENT_LEN+1]; + uint line, col; + int intVal; + + TrIndication(tr, &line, &col); + if(!TrReadIdent(tr, MAX_IDENT_LEN, ident)) + return 0; + src->mFormat = MatchSourceFormat(ident); + if(src->mFormat == SF_NONE) + { + TrErrorAt(tr, line, col, "Expected a source format.\n"); + return 0; + } + if(!TrReadOperator(tr, "(")) + return 0; + if(src->mFormat == SF_WAVE) + { + if(!TrReadInt(tr, 0, MAX_WAVE_CHANNELS, &intVal)) + return 0; + src->mType = ET_NONE; + src->mSize = 0; + src->mBits = 0; + src->mChannel = (uint)intVal; + src->mSkip = 0; + } + else + { + TrIndication(tr, &line, &col); + if(!TrReadIdent(tr, MAX_IDENT_LEN, ident)) + return 0; + src->mType = MatchElementType(ident); + if(src->mType == ET_NONE) + { + TrErrorAt(tr, line, col, "Expected a source element type.\n"); + return 0; + } + if(src->mFormat == SF_BIN_LE || src->mFormat == SF_BIN_BE) + { + if(!TrReadOperator(tr, ",")) + return 0; + if(src->mType == ET_INT) + { + if(!TrReadInt(tr, MIN_BIN_SIZE, MAX_BIN_SIZE, &intVal)) + return 0; + src->mSize = (uint)intVal; + if(!TrIsOperator(tr, ",")) + src->mBits = (int)(8*src->mSize); + else + { + TrReadOperator(tr, ","); + TrIndication(tr, &line, &col); + if(!TrReadInt(tr, -2147483647-1, 2147483647, &intVal)) + return 0; + if(abs(intVal) < MIN_BIN_BITS || ((uint)abs(intVal)) > (8*src->mSize)) + { + TrErrorAt(tr, line, col, "Expected a value of (+/-) %d to %d.\n", MIN_BIN_BITS, 8*src->mSize); + return 0; + } + src->mBits = intVal; + } + } + else + { + TrIndication(tr, &line, &col); + if(!TrReadInt(tr, -2147483647-1, 2147483647, &intVal)) + return 0; + if(intVal != 4 && intVal != 8) + { + TrErrorAt(tr, line, col, "Expected a value of 4 or 8.\n"); + return 0; + } + src->mSize = (uint)intVal; + src->mBits = 0; + } + } + else if(src->mFormat == SF_ASCII && src->mType == ET_INT) + { + if(!TrReadOperator(tr, ",")) + return 0; + if(!TrReadInt(tr, MIN_ASCII_BITS, MAX_ASCII_BITS, &intVal)) + return 0; + src->mSize = 0; + src->mBits = intVal; + } + else + { + src->mSize = 0; + src->mBits = 0; + } + + if(!TrIsOperator(tr, ";")) + src->mSkip = 0; + else + { + TrReadOperator(tr, ";"); + if(!TrReadInt (tr, 0, 0x7FFFFFFF, &intVal)) + return 0; + src->mSkip = (uint)intVal; + } + } + if(!TrReadOperator(tr, ")")) + return 0; + if(TrIsOperator(tr, "@")) + { + TrReadOperator(tr, "@"); + if(!TrReadInt(tr, 0, 0x7FFFFFFF, &intVal)) + return 0; + src->mOffset = (uint)intVal; + } + else + src->mOffset = 0; + if(!TrReadOperator(tr, ":")) + return 0; + if(!TrReadString(tr, MAX_PATH_LEN, src->mPath)) + return 0; + return 1; +} + +// Process the list of sources in the data set definition. +static int ProcessSources(const HeadModelT model, TokenReaderT *tr, HrirDataT *hData) +{ + uint *setCount, *setFlag; + uint line, col, ei, ai; + SourceRefT src; + double factor; + double *hrir; + + setCount = (uint*)calloc(hData->mEvCount, sizeof(uint)); + setFlag = (uint*)calloc(hData->mIrCount, sizeof(uint)); + hrir = CreateArray(hData->mIrPoints); + while(TrIsOperator(tr, "[")) + { + TrIndication(tr, & line, & col); + TrReadOperator(tr, "["); + if(!ReadIndexPair(tr, hData, &ei, &ai)) + goto error; + if(!TrReadOperator(tr, "]")) + goto error; + if(setFlag[hData->mEvOffset[ei] + ai]) + { + TrErrorAt(tr, line, col, "Redefinition of source.\n"); + goto error; + } + if(!TrReadOperator(tr, "=")) + goto error; + + factor = 1.0; + for(;;) + { + if(!ReadSourceRef(tr, &src)) + goto error; + if(!LoadSource(&src, hData->mIrRate, hData->mIrPoints, hrir)) + goto error; + + if(model == HM_DATASET) + AverageHrirOnset(hrir, 1.0 / factor, ei, ai, hData); + AverageHrirMagnitude(hrir, 1.0 / factor, ei, ai, hData); + factor += 1.0; + if(!TrIsOperator(tr, "+")) + break; + TrReadOperator(tr, "+"); + } + setFlag[hData->mEvOffset[ei] + ai] = 1; + setCount[ei]++; + } + + ei = 0; + while(ei < hData->mEvCount && setCount[ei] < 1) + ei++; + if(ei < hData->mEvCount) + { + hData->mEvStart = ei; + while(ei < hData->mEvCount && setCount[ei] == hData->mAzCount[ei]) + ei++; + if(ei >= hData->mEvCount) + { + if(!TrLoad(tr)) + { + DestroyArray(hrir); + free(setFlag); + free(setCount); + return 1; + } + TrError(tr, "Errant data at end of source list.\n"); + } + else + TrError(tr, "Missing sources for elevation index %d.\n", ei); + } + else + TrError(tr, "Missing source references.\n"); + +error: + DestroyArray(hrir); + free(setFlag); + free(setCount); + return 0; +} + +/* Parse the data set definition and process the source data, storing the + * resulting data set as desired. If the input name is NULL it will read + * from standard input. + */ +static int ProcessDefinition(const char *inName, const uint outRate, const uint fftSize, const int equalize, const int surface, const double limit, const uint truncSize, const HeadModelT model, const double radius, const OutputFormatT outFormat, const char *outName) +{ + char rateStr[8+1], expName[MAX_PATH_LEN]; + TokenReaderT tr; + HrirDataT hData; + double *dfa; + FILE *fp; + + hData.mIrRate = 0; + hData.mIrPoints = 0; + hData.mFftSize = 0; + hData.mIrSize = 0; + hData.mIrCount = 0; + hData.mEvCount = 0; + hData.mRadius = 0; + hData.mDistance = 0; + fprintf(stdout, "Reading HRIR definition...\n"); + if(inName != NULL) + { + fp = fopen(inName, "r"); + if(fp == NULL) + { + fprintf(stderr, "Error: Could not open definition file '%s'\n", inName); + return 0; + } + TrSetup(fp, inName, &tr); + } + else + { + fp = stdin; + TrSetup(fp, "", &tr); + } + if(!ProcessMetrics(&tr, fftSize, truncSize, &hData)) + { + if(inName != NULL) + fclose(fp); + return 0; + } + hData.mHrirs = CreateArray(hData.mIrCount * hData.mIrSize); + hData.mHrtds = CreateArray(hData.mIrCount); + if(!ProcessSources(model, &tr, &hData)) + { + DestroyArray(hData.mHrtds); + DestroyArray(hData.mHrirs); + if(inName != NULL) + fclose(fp); + return 0; + } + if(inName != NULL) + fclose(fp); + if(equalize) + { + dfa = CreateArray(1 + (hData.mFftSize/2)); + fprintf(stdout, "Calculating diffuse-field average...\n"); + CalculateDiffuseFieldAverage(&hData, surface, limit, dfa); + fprintf(stdout, "Performing diffuse-field equalization...\n"); + DiffuseFieldEqualize(dfa, &hData); + DestroyArray(dfa); + } + fprintf(stdout, "Performing minimum phase reconstruction...\n"); + ReconstructHrirs(&hData); + if(outRate != 0 && outRate != hData.mIrRate) + { + fprintf(stdout, "Resampling HRIRs...\n"); + ResampleHrirs(outRate, &hData); + } + fprintf(stdout, "Truncating minimum-phase HRIRs...\n"); + hData.mIrPoints = truncSize; + fprintf(stdout, "Synthesizing missing elevations...\n"); + if(model == HM_DATASET) + SynthesizeOnsets(&hData); + SynthesizeHrirs(&hData); + fprintf(stdout, "Normalizing final HRIRs...\n"); + NormalizeHrirs(&hData); + fprintf(stdout, "Calculating impulse delays...\n"); + CalculateHrtds(model, (radius > DEFAULT_CUSTOM_RADIUS) ? radius : hData.mRadius, &hData); + snprintf(rateStr, 8, "%u", hData.mIrRate); + StrSubst(outName, "%r", rateStr, MAX_PATH_LEN, expName); + switch(outFormat) + { + case OF_MHR: + fprintf(stdout, "Creating MHR data set file...\n"); + if(!StoreMhr(&hData, expName)) + { + DestroyArray(hData.mHrtds); + DestroyArray(hData.mHrirs); + return 0; + } + break; + default: + break; + } + DestroyArray(hData.mHrtds); + DestroyArray(hData.mHrirs); + return 1; +} + +static void PrintHelp(const char *argv0, FILE *ofile) +{ + fprintf(ofile, "Usage: %s [