From 5603c7057423d197b7f3033d428f4a1b0120f0ca Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 13 Aug 2010 07:07:26 +0000 Subject: [PATCH 01/88] [OpenAL branch] - apply Chris's latest patch. SVN r2534 (openal) --- CMakeLists.txt | 3 + output_sdl/CMakeLists.txt | 14 +- src/CMakeLists.txt | 210 ++- src/m_options.cpp | 121 +- src/sdl/crashcatcher.c | 91 +- src/sound/efx.h | 758 +++++++++ src/sound/fmod_wrap.h | 3 + src/sound/fmodsound.cpp | 60 +- src/sound/fmodsound.h | 3 + src/sound/i_sound.cpp | 23 +- src/sound/i_soundinternal.h | 2 + src/sound/music_midi_base.cpp | 8 +- src/sound/oalsound.cpp | 2823 +++++++++++++++++++++++++++++++++ src/sound/oalsound.h | 211 +++ zdoom.vcproj | 12 + 15 files changed, 4170 insertions(+), 172 deletions(-) create mode 100644 src/sound/efx.h create mode 100644 src/sound/oalsound.cpp create mode 100644 src/sound/oalsound.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b541a9c20d..dfedd7f195 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,9 @@ if( CMAKE_COMPILER_IS_GNUCXX ) set( PROFILE 0 CACHE BOOL "Enable profiling with gprof for Debug and RelWithDebInfo build types." ) endif( CMAKE_COMPILER_IS_GNUCXX ) +option( NO_FMOD "Disable FMODEx sound support" ) +option( NO_OPENAL "Disable OpenAL sound support" ) + find_package( BZip2 ) find_package( JPEG ) find_package( ZLIB ) diff --git a/output_sdl/CMakeLists.txt b/output_sdl/CMakeLists.txt index b959a68730..1e7a9eb000 100644 --- a/output_sdl/CMakeLists.txt +++ b/output_sdl/CMakeLists.txt @@ -1,8 +1,10 @@ cmake_minimum_required( VERSION 2.4 ) -add_library( output_sdl MODULE output_sdl.c ) -include_directories( ${FMOD_INCLUDE_DIR} ${SDL_INCLUDE_DIR} ) +if( NOT NO_FMOD AND FMOD_INCLUDE_DIR ) + add_library( output_sdl MODULE output_sdl.c ) + include_directories( ${FMOD_INCLUDE_DIR} ${SDL_INCLUDE_DIR} ) -FILE( WRITE ${CMAKE_CURRENT_BINARY_DIR}/link-make "if [ ! -e ${ZDOOM_OUTPUT_DIR}/liboutput_sdl.so ]; then ln -sf output_sdl/liboutput_sdl.so ${ZDOOM_OUTPUT_DIR}/liboutput_sdl.so; fi" ) -add_custom_command( TARGET output_sdl POST_BUILD - COMMAND chmod +x ${CMAKE_CURRENT_BINARY_DIR}/link-make - COMMAND /bin/sh -c ${CMAKE_CURRENT_BINARY_DIR}/link-make ) + FILE( WRITE ${CMAKE_CURRENT_BINARY_DIR}/link-make "if [ ! -e ${ZDOOM_OUTPUT_DIR}/liboutput_sdl.so ]; then ln -sf output_sdl/liboutput_sdl.so ${ZDOOM_OUTPUT_DIR}/liboutput_sdl.so; fi" ) + add_custom_command( TARGET output_sdl POST_BUILD + COMMAND chmod +x ${CMAKE_CURRENT_BINARY_DIR}/link-make + COMMAND /bin/sh -c ${CMAKE_CURRENT_BINARY_DIR}/link-make ) +endif( NOT NO_FMOD AND FMOD_INCLUDE_DIR ) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9b763dee33..d7b4dfcbfb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -115,6 +115,60 @@ if( WIN32 ) message( FATAL_ERROR "Could not find DirectX 9 libraries" ) endif( NOT DX_LIBS_FOUND ) + + if( NOT NO_OPENAL ) + SET( GST_SEARCH_PATHS + ENV GSTSDK_DIR + ENV MINGDIR + "C:/Program Files/gstreamer" + "C:/gstreamer" ) + + message( STATUS "Looking for glib.h" ) + find_path( GLIB_INCLUDE_DIR glib.h + PATHS ${GST_SEARCH_PATHS} + PATH_SUFFIXES include include/glib-2.0 ) + if( GLIB_INCLUDE_DIR ) + message(STATUS "Looking for glib.h - found: ${GLIB_INCLUDE_DIR}") + else( GLIB_INCLUDE_DIR ) + message(STATUS "Looking for glib.h - not found") + endif( GLIB_INCLUDE_DIR ) + + message( STATUS "Looking for gst/gst.h" ) + find_path( GST_INCLUDE_DIR gst/gst.h + PATHS ${GST_SEARCH_PATHS} + PATH_SUFFIXES include include/gstreamer-0.10 ) + if( GST_INCLUDE_DIR ) + message( STATUS "Looking for gst/gst.h - found: ${GST_INCLUDE_DIR}" ) + else( GST_INCLUDE_DIR ) + message( STATUS "Looking for gst/gst.h - not found" ) + endif( GST_INCLUDE_DIR ) + + message( STATUS "Looking for al.h" ) + set( OPENAL_SEARCH_PATHS + ENV ALSDK_DIR + ENV MINGDIR + "C:/Program Files/OpenAL 1.1 SDK" + "C:/Program Files (x86)/OpenAL 1.1 SDK" + "E:/Programs/Dev/OpenAL" + "E:/Program Files (x86)/OpenAL 1.1 SDK" ) + + find_path( OPENAL_INCLUDE_DIR al.h + PATHS ${OPENAL_SEARCH_PATHS} + PATH_SUFFIXES include include/AL ) + if( OPENAL_INCLUDE_DIR ) + message( STATUS "Looking for al.h - found: ${OPENAL_INCLUDE_DIR}" ) + else( OPENAL_INCLUDE_DIR ) + message( STATUS "Looking for al.h - not found" ) + endif( OPENAL_INCLUDE_DIR ) + + if( NOT OPENAL_INCLUDE_DIR OR NOT GLIB_INCLUDE_DIR OR NOT GST_INCLUDE_DIR ) + set( NO_OPENAL ON ) + else( NOT OPENAL_INCLUDE_DIR OR NOT GLIB_INCLUDE_DIR OR NOT GST_INCLUDE_DIR ) + include_directories( ${OPENAL_INCLUDE_DIR} ${GLIB_INCLUDE_DIR} ${GST_INCLUDE_DIR} ) + endif( NOT OPENAL_INCLUDE_DIR OR NOT GLIB_INCLUDE_DIR OR NOT GST_INCLUDE_DIR ) + endif( NOT NO_OPENAL ) + + set( ZDOOM_LIBS wsock32 winmm @@ -129,12 +183,57 @@ if( WIN32 ) ws2_32 setupapi oleaut32 ) + + if( NOT NO_OPENAL ) + message( STATUS "Looking for GST libraries" ) + find_library( OPENAL_LIBRARY NAMES OpenAL32 + PATHS ${OPENAL_SEARCH_PATHS} + PATH_SUFFIXES lib ) + find_library( GST_LIBRARY1 NAMES gstapp-0.10 + PATHS ${GST_SEARCH_PATHS} + PATH_SUFFIXES lib ) + find_library( GST_LIBRARY2 NAMES gstaudio-0.10 + PATHS ${GST_SEARCH_PATHS} + PATH_SUFFIXES lib ) + find_library( GST_LIBRARY3 NAMES gstreamer-0.10 + PATHS ${GST_SEARCH_PATHS} + PATH_SUFFIXES lib ) + find_library( GST_LIBRARY4 NAMES gthread-2.0 + PATHS ${GST_SEARCH_PATHS} + PATH_SUFFIXES lib ) + find_library( GST_LIBRARY5 NAMES gmodule-2.0 + PATHS ${GST_SEARCH_PATHS} + PATH_SUFFIXES lib ) + find_library( GST_LIBRARY6 NAMES gobject-2.0 + PATHS ${GST_SEARCH_PATHS} + PATH_SUFFIXES lib ) + find_library( GST_LIBRARY7 NAMES glib-2.0 + PATHS ${GST_SEARCH_PATHS} + PATH_SUFFIXES lib ) + if( OPENAL_LIBRARY AND GST_LIBRARY1 AND GST_LIBRARY2 AND GST_LIBRARY3 AND GST_LIBRARY4 AND GST_LIBRARY5 AND GST_LIBRARY6 AND GST_LIBRARY7 ) + set( ZDOOM_LIBS ${ZDOOM_LIBS} "${OPENAL_LIBRARY}" "${GST_LIBRARY1}" "${GST_LIBRARY2}" "${GST_LIBRARY3}" "${GST_LIBRARY4}" "${GST_LIBRARY5}" "${GST_LIBRARY6}" "${GST_LIBRARY7}" ) + message( STATUS "Looking for GST libraries - found" ) + else( OPENAL_LIBRARY AND GST_LIBRARY1 AND GST_LIBRARY2 AND GST_LIBRARY3 AND GST_LIBRARY4 AND GST_LIBRARY5 AND GST_LIBRARY6 AND GST_LIBRARY7 ) + set( NO_OPENAL ON ) + message( STATUS "Looking for GST libraries - not found" ) + endif( OPENAL_LIBRARY AND GST_LIBRARY1 AND GST_LIBRARY2 AND GST_LIBRARY3 AND GST_LIBRARY4 AND GST_LIBRARY5 AND GST_LIBRARY6 AND GST_LIBRARY7 ) + endif( NOT NO_OPENAL ) else( WIN32 ) if( APPLE ) set( FMOD_SEARCH_PATHS "/Developer/FMOD Programmers API Mac/api" ) set( FMOD_INC_PATH_SUFFIXES PATH_SUFFIXES inc ) set( FMOD_LIB_PATH_SUFFIXES PATH_SUFFIXES lib ) set( NO_GTK ON ) + + if( NOT NO_OPENAL ) + check_library_exists( gstapp-0.10 gst_app_src_set_callbacks "" HAS_GSTAPP ) + check_library_exists( gstaudio-0.10 gst_audio_set_channel_positions "" HAS_GSTAUDIO ) + if( HAS_GSTAPP AND HAS_GSTAUDIO ) + set( ZDOOM_LIBS ${ZDOOM_LIBS} gstapp-0.10 gst-audio-0.10 "-framework OpenAL") + else( HAS_GSTAPP AND HAS_GSTAUDIO ) + set( NO_OPENAL ON ) + endif( HAS_GSTAPP AND HAS_GSTAUDIO ) + endif( NOT NO_OPENAL ) else( APPLE ) option( NO_GTK "Disable GTK+ dialogs (Not applicable to Windows)" ) option( VALGRIND "Add special Valgrind sequences to self-modifying code" ) @@ -160,6 +259,14 @@ else( WIN32 ) set( NO_GTK ON ) endif( GTK2_FOUND ) endif( NOT NO_GTK ) + + pkg_check_modules( OPENAL openal gstreamer-app-0.10>=0.10.23 gstreamer-audio-0.10 ) + if( OPENAL_FOUND ) + set( ZDOOM_LIBS ${ZDOOM_LIBS} ${OPENAL_LIBRARIES} ) + include_directories( ${OPENAL_INCLUDE_DIRS} ) + else( OPENAL_FOUND ) + set( NO_OPENAL ON ) + endif( OPENAL_FOUND ) endif( APPLE ) set( NASM_NAMES nasm ) @@ -182,59 +289,69 @@ else( WIN32 ) endif( FPU_CONTROL_DIR ) endif( WIN32 ) -# Decide on the name of the FMOD library we want to use. -if( NOT FMOD_LIB_NAME AND MSVC ) - set( FMOD_LIB_NAME fmodex${X64}_vc ) -endif( NOT FMOD_LIB_NAME AND MSVC ) +if( NOT NO_FMOD ) + # Search for FMOD include files + if( NOT WIN32 ) + find_path( FMOD_INCLUDE_DIR fmod.hpp + PATHS ${FMOD_LOCAL_INC_DIRS} ) + endif( NOT WIN32 ) -if( NOT FMOD_LIB_NAME AND BORLAND ) - set( FMOD_LIB_NAME fmodex${X64}_bc ) -endif( NOT FMOD_LIB_NAME AND BORLAND ) + if( NOT FMOD_INCLUDE_DIR ) + find_path( FMOD_INCLUDE_DIR fmod.hpp + PATHS ${FMOD_SEARCH_PATHS} + ${FMOD_INC_PATH_SUFFIXES} ) + endif( NOT FMOD_INCLUDE_DIR ) -if( NOT FMOD_LIB_NAME ) - set( FMOD_LIB_NAME fmodex${X64} ) -endif( NOT FMOD_LIB_NAME ) + if( FMOD_INCLUDE_DIR ) + message( STATUS "FMOD include files found at ${FMOD_INCLUDE_DIR}" ) + include_directories( "${FMOD_INCLUDE_DIR}" ) + else( FMOD_INCLUDE_DIR ) + message( STATUS "Could not find FMOD include files" ) + set( NO_FMOD ON ) + endif( FMOD_INCLUDE_DIR ) +endif( NOT NO_FMOD ) +if( NOT NO_FMOD ) + # Decide on the name of the FMOD library we want to use. + if( NOT FMOD_LIB_NAME AND MSVC ) + set( FMOD_LIB_NAME fmodex${X64}_vc ) + endif( NOT FMOD_LIB_NAME AND MSVC ) -# Search for FMOD include files + if( NOT FMOD_LIB_NAME AND BORLAND ) + set( FMOD_LIB_NAME fmodex${X64}_bc ) + endif( NOT FMOD_LIB_NAME AND BORLAND ) -if( NOT WIN32 ) - find_path( FMOD_INCLUDE_DIR fmod.hpp - PATHS ${FMOD_LOCAL_INC_DIRS} ) -endif( NOT WIN32 ) + if( NOT FMOD_LIB_NAME ) + set( FMOD_LIB_NAME fmodex${X64} ) + endif( NOT FMOD_LIB_NAME ) -if( NOT FMOD_INCLUDE_DIR ) - find_path( FMOD_INCLUDE_DIR fmod.hpp - PATHS ${FMOD_SEARCH_PATHS} - ${FMOD_INC_PATH_SUFFIXES} ) -endif( NOT FMOD_INCLUDE_DIR ) + # Search for FMOD library + if( WIN32 OR APPLE ) + find_library( FMOD_LIBRARY ${FMOD_LIB_NAME} + PATHS ${FMOD_SEARCH_PATHS} + ${FMOD_LIB_PATH_SUFFIXES} ) + else( WIN32 OR APPLE ) + find_library( FMOD_LIBRARY + NAMES ${FMOD_VERSIONS} + PATHS ${FMOD_LOCAL_LIB_DIRS} ) + endif( WIN32 OR APPLE ) -if( FMOD_INCLUDE_DIR ) - message( STATUS "FMOD include files found at ${FMOD_INCLUDE_DIR}" ) -else( FMOD_INCLUDE_DIR ) - message( SEND_ERROR "Could not find FMOD include files" ) -endif( FMOD_INCLUDE_DIR ) - - -# Search for FMOD library - -if( WIN32 OR APPLE ) - find_library( FMOD_LIBRARY ${FMOD_LIB_NAME} - PATHS ${FMOD_SEARCH_PATHS} - ${FMOD_LIB_PATH_SUFFIXES} ) -else( WIN32 OR APPLE ) - find_library( FMOD_LIBRARY - NAMES ${FMOD_VERSIONS} - PATHS ${FMOD_LOCAL_LIB_DIRS} ) -endif( WIN32 OR APPLE ) - -if( FMOD_LIBRARY ) - message( STATUS "FMOD library found at ${FMOD_LIBRARY}" ) -else( FMOD_LIBRARY ) - message( SEND_ERROR "Could not find FMOD library" ) -endif( FMOD_LIBRARY ) + if( FMOD_LIBRARY ) + message( STATUS "FMOD library found at ${FMOD_LIBRARY}" ) + set( ZDOOM_LIBS ${ZDOOM_LIBS} "${FMOD_LIBRARY}" ) + else( FMOD_LIBRARY ) + message( STATUS "Could not find FMOD library" ) + set( NO_FMOD ON ) + endif( FMOD_LIBRARY ) +endif( NOT NO_FMOD ) +if( NO_FMOD ) + add_definitions( -DNO_FMOD=1 ) +endif( NO_FMOD ) +if( NO_OPENAL ) + add_definitions( -DNO_OPENAL=1 ) +endif( NO_OPENAL ) # Search for NASM @@ -476,8 +593,8 @@ add_custom_target( revision_check ALL # Libraries ZDoom needs -set( ZDOOM_LIBS ${ZDOOM_LIBS} "${ZLIB_LIBRARIES}" "${JPEG_LIBRARIES}" "${BZIP2_LIBRARIES}" "${FMOD_LIBRARY}" ) -include_directories( "${ZLIB_INCLUDE_DIR}" "${FMOD_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" ) +set( ZDOOM_LIBS ${ZDOOM_LIBS} "${ZLIB_LIBRARIES}" "${JPEG_LIBRARIES}" "${BZIP2_LIBRARIES}" ) +include_directories( "${ZLIB_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" ) # Start defining source files for ZDoom @@ -795,6 +912,7 @@ add_executable( zdoom WIN32 sound/music_stream.cpp sound/music_timidity_mididevice.cpp sound/music_win_mididevice.cpp + sound/oalsound.cpp textures/automaptexture.cpp textures/bitmap.cpp textures/buildtexture.cpp diff --git a/src/m_options.cpp b/src/m_options.cpp index 7e17ef7986..eed3e9d852 100644 --- a/src/m_options.cpp +++ b/src/m_options.cpp @@ -122,6 +122,8 @@ void M_SizeDisplay (int diff); int M_StringHeight (char *string); +int BuildALDeviceList(valueenum_t **menulist); + EColorRange LabelColor; EColorRange ValueColor; EColorRange MoreColor; @@ -1167,9 +1169,15 @@ EXTERN_CVAR (Int, snd_samplerate) EXTERN_CVAR (Bool, snd_hrtf) EXTERN_CVAR (Bool, snd_waterreverb) EXTERN_CVAR (Float, snd_waterlp) +EXTERN_CVAR (Float, snd_waterabsorption) EXTERN_CVAR (Int, snd_mididevice) +EXTERN_CVAR (String, snd_backend) +EXTERN_CVAR (String, snd_aldevice) +EXTERN_CVAR (Bool, snd_efx) static void MakeSoundChanges (); +static void FMODSoundOptions (); +static void OpenALSoundOptions (); static void AdvSoundOptions (); static void ModReplayerOptions (); @@ -1213,7 +1221,7 @@ static value_t BufferCounts[] = { 12.f, "12" } }; -static valueenum_t Outputs[] = +static valueenum_t FMODOutputs[] = { { "Default", "Default" }, #if defined(_WIN32) @@ -1234,6 +1242,17 @@ static valueenum_t Outputs[] = { "No sound", "No sound" } }; +static valueenum_t Backends[] = +{ +#ifndef NO_FMOD + { "fmod", "FMOD" }, +#endif +#ifndef NO_OPENAL + { "openal", "OpenAL" }, +#endif + { "null", "No sound" } +}; + static valueenum_t OutputFormats[] = { { "PCM-8", "8-bit" }, @@ -1263,6 +1282,49 @@ static valueenum_t Resamplers[] = { "Spline", "Spline" } }; +static menuitem_t FMODSoundItems[] = +{ + { slider, "Underwater cutoff", {&snd_waterlp}, {0.0}, {2000.0},{50.0}, {NULL} }, + { ediscrete,"Output system", {&snd_output}, {countof(FMODOutputs)}, {0.0}, {0.0}, {(value_t *)FMODOutputs} }, + { ediscrete,"Output format", {&snd_output_format}, {5.0}, {0.0}, {0.0}, {(value_t *)OutputFormats} }, + { ediscrete,"Speaker mode", {&snd_speakermode}, {8.0}, {0.0}, {0.0}, {(value_t *)SpeakerModes} }, + { ediscrete,"Resampler", {&snd_resampler}, {4.0}, {0.0}, {0.0}, {(value_t *)Resamplers} }, + { discrete, "HRTF filter", {&snd_hrtf}, {2.0}, {0.0}, {0.0}, {(value_t *)OnOff} }, + { redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} }, + { discrete, "Buffer size", {&snd_buffersize}, {8.0}, {0.0}, {0.0}, {BufferSizes} }, + { discrete, "Buffer count", {&snd_buffercount}, {12.0},{0.0}, {0.0}, {BufferCounts} }, +}; + +static menu_t FMODSoundMenu = +{ + "FMOD SOUND OPTIONS", + 0, + countof(FMODSoundItems), + 0, + FMODSoundItems, +}; + + +static valueenum_t *ALOutputs = NULL; + +static menuitem_t OpenALSoundItems[] = +{ + { ediscrete, "Playback device", {&snd_aldevice}, {0.0}, {0.0},{0.0}, {(value_t *)ALOutputs} }, + { discrete, "Enable EFX", {&snd_efx}, {2.0}, {0.0},{0.0}, {(value_t *)YesNo} }, + { redtext, " ", {NULL}, {0.0}, {0.0},{0.0}, {NULL} }, + { whitetext, "Requires EFX", {NULL}, {0.0}, {0.0},{0.0}, {NULL} }, + { slider, "Underwater absorption",{&snd_waterabsorption}, {0.0}, {10.0},{0.5},{NULL} }, +}; + +static menu_t OpenALSoundMenu = +{ + "OPENAL SOUND OPTIONS", + 0, + countof(OpenALSoundItems), + 0, + OpenALSoundItems, +}; + static menuitem_t SoundItems[] = { { slider, "Sounds volume", {&snd_sfxvolume}, {0.0}, {1.0}, {0.05f}, {NULL} }, @@ -1270,17 +1332,18 @@ static menuitem_t SoundItems[] = { discrete, "MIDI device", {&snd_mididevice}, {0.0}, {0.0}, {0.0}, {NULL} }, { redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} }, { discrete, "Underwater reverb", {&snd_waterreverb}, {2.0}, {0.0}, {0.0}, {OnOff} }, - { slider, "Underwater cutoff", {&snd_waterlp}, {0.0}, {2000.0},{50.0}, {NULL} }, { discrete, "Randomize pitches", {&snd_pitched}, {2.0}, {0.0}, {0.0}, {OnOff} }, { slider, "Sound channels", {&snd_channels}, {8.0}, {256.0}, {8.0}, {NULL} }, + { ediscrete,"Sound backend", {&snd_backend}, {countof(Backends)}, {0.0}, {0.0}, {(value_t *)Backends} }, + { redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} }, +#ifndef NO_FMOD + { more, "FMOD sound options", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)FMODSoundOptions} }, +#endif +#ifndef NO_OPENAL + { more, "OpenAL sound options", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)OpenALSoundOptions} }, +#endif { redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} }, { more, "Restart sound", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)MakeSoundChanges} }, - { redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} }, - { ediscrete,"Output system", {&snd_output}, {countof(Outputs)}, {0.0}, {0.0}, {(value_t *)Outputs} }, - { ediscrete,"Output format", {&snd_output_format}, {5.0}, {0.0}, {0.0}, {(value_t *)OutputFormats} }, - { ediscrete,"Speaker mode", {&snd_speakermode}, {8.0}, {0.0}, {0.0}, {(value_t *)SpeakerModes} }, - { ediscrete,"Resampler", {&snd_resampler}, {4.0}, {0.0}, {0.0}, {(value_t *)Resamplers} }, - { discrete, "HRTF filter", {&snd_hrtf}, {2.0}, {0.0}, {0.0}, {(value_t *)OnOff} }, { redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} }, { more, "Advanced options", {NULL}, {0.0}, {0.0}, {0.0}, {(value_t *)AdvSoundOptions} }, @@ -1309,8 +1372,6 @@ EXTERN_CVAR (Bool, opl_onechip) static menuitem_t AdvSoundItems[] = { { discrete, "Sample rate", {&snd_samplerate}, {8.0}, {0.0}, {0.0}, {SampleRates} }, - { discrete, "Buffer size", {&snd_buffersize}, {8.0}, {0.0}, {0.0}, {BufferSizes} }, - { discrete, "Buffer count", {&snd_buffercount}, {12.0}, {0.0}, {0.0}, {BufferCounts} }, { redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} }, { whitetext,"OPL Synthesis", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} }, { discrete, "Only emulate one OPL chip", {&opl_onechip}, {2.0}, {0.0}, {0.0}, {OnOff} }, @@ -1342,7 +1403,7 @@ EXTERN_CVAR(Int, mod_autochip_scan_threshold) static value_t ModReplayers[] = { - { 0.0, "FMOD" }, + { 0.0, "Sound System" }, { 1.0, "foo_dumb" } }; @@ -3380,6 +3441,36 @@ CCMD (menu_sound) SoundOptions (); } +static void FMODSoundOptions () +{ + M_SwitchMenu (&FMODSoundMenu); +} + +CCMD (menu_fmodsound) +{ +#ifndef NO_FMOD + M_StartControlPanel (true); + OptionsActive = true; + FMODSoundOptions (); +#endif +} + +static void OpenALSoundOptions () +{ + OpenALSoundItems[0].b.numvalues = BuildALDeviceList (&ALOutputs); + OpenALSoundItems[0].e.enumvalues = ALOutputs; + M_SwitchMenu (&OpenALSoundMenu); +} + +CCMD (menu_openalsound) +{ +#ifndef NO_OPENAL + M_StartControlPanel (true); + OptionsActive = true; + OpenALSoundOptions (); +#endif +} + static void AdvSoundOptions () { M_SwitchMenu (&AdvSoundMenu); @@ -3825,6 +3916,14 @@ CCMD (addmenukey) void M_Deinit () { + if (ALOutputs) + { + for (size_t i = 0;ALOutputs[i].value;i++) + delete[] const_cast(ALOutputs[i].value); + delete[] ALOutputs; + ALOutputs = NULL; + } + // Free bitdepth names for the modes menu. for (size_t i = 0; i < countof(Depths); ++i) { diff --git a/src/sdl/crashcatcher.c b/src/sdl/crashcatcher.c index 7dc928407e..53f3c6a677 100644 --- a/src/sdl/crashcatcher.c +++ b/src/sdl/crashcatcher.c @@ -97,8 +97,7 @@ static void gdb_info(pid_t pid) strcpy(respfile, "gdb-respfile-XXXXXX"); if((fd = mkstemp(respfile)) >= 0 && (f = fdopen(fd, "w"))) { - fprintf(f, "signal SIGCHLD\n" - "shell echo \"\"\n" + fprintf(f, "shell echo \"\"\n" "shell echo \"* Loaded Libraries\"\n" "info sharedlibrary\n" "shell echo \"\"\n" @@ -115,36 +114,8 @@ static void gdb_info(pid_t pid) "x/x $eip-3\nx/x $eip\n" "shell echo \"\"\n" "shell echo \"* Backtrace\"\n" - "backtrace full\n" -#if 0 /* This sorta works to print out the core, but is too slow and skips 0's.. */ - "shell echo \"\"\n" - "shell echo \"* Stack\"\n" - "set var $_sp = $esp\n" - "while $_sp <= $ebp - 12\n" - " printf \"%%08x: \", $_sp\n" - " set var $_i = $_sp\n" - " while $_i < $_sp + 16\n" - " printf \"%%08x \", {int} $_i\n" - " set $_i += 4\n" - " end\n" - " set var $_i = $_sp\n" - " while $_i < $_sp + 16\n" - " printf \"%%c\", {int} $_i\n" - " set ++$_i\n" - " end\n" - " set var $_sp += 16\n" - " printf \"\\n\"\n" - "end\n" - "if $_sp <= $ebp\n" - " printf \"%%08x: \", $esp\n" - " while $_sp <= $ebp\n" - " printf \"%%08x \", {int} $_i\n" - " set $_sp += 4\n" - " end\n" - " printf \"\\n\"\n" - "end\n" -#endif - "kill\n" + "thread apply all backtrace full\n" + "detach\n" "quit\n"); fclose(f); @@ -152,8 +123,8 @@ static void gdb_info(pid_t pid) snprintf(buf, sizeof(buf), "gdb --quiet --batch --command=%s --pid=%i", respfile, pid); printf("Executing: %s\n", buf); fflush(stdout); - system(buf); + system(buf); /* Clean up */ remove(respfile); } @@ -168,6 +139,7 @@ static void gdb_info(pid_t pid) printf("Could not create gdb command file\n"); } fflush(stdout); + kill(pid, SIGKILL); } @@ -267,8 +239,8 @@ static void crash_catcher(int signum, siginfo_t *siginfo, void *context) /* Make sure the effective uid is the real uid */ if (getuid() != geteuid()) { - fprintf(stderr, "%s (signal %i)\ngetuid() does not match geteuid().\n", sigdesc, signum); - _exit(-1); + raise(signum); + return; } #endif @@ -325,48 +297,18 @@ static void crash_catcher(int signum, siginfo_t *siginfo, void *context) } gdb_info(pid); -#if 0 /* Why won't this work? */ - if(ucontext) - { - unsigned char *ptr = ucontext->uc_stack.ss_sp; - size_t len; - - fprintf(f, "\n* Stack\n"); - for(len = ucontext->uc_stack.ss_size/4;len > 0; len -= 4) - { - fprintf(f, "0x%08x:", (int)ptr); - for(i = 0;i < ((len < 4) ? len : 4);++i) - { - fprintf(f, " %02x%02x%02x%02x", ptr[i*4 + 0], ptr[i*4 + 1], - ptr[i*4 + 2], ptr[i*4 + 3]); - } - fputc(' ', f); - fflush(f); - for(i = 0;i < ((len < 4) ? len : 4);++i) - { - fprintf(f, "%c", *(ptr++)); - fprintf(f, "%c", *(ptr++)); - fprintf(f, "%c", *(ptr++)); - fprintf(f, "%c", *(ptr++)); - } - fputc('\n', f); - fflush(f); - } - } -#endif - if(f != stderr) { fclose(f); #if (defined __unix__) if(cc_logfile) { - char buf[256]; + char buf[512]; snprintf(buf, sizeof(buf), - "if (which gxmessage > /dev/null 2>&1);" - "then gxmessage -buttons \"Damn it:0\" -center -title \"Very Fatal Error\" -file %s;" - "elif (which xmessage > /dev/null 2>&1);" - "then xmessage -buttons \"Damn it:0\" -center -file %s -geometry 600x400;" + "if (which gxmessage > /dev/null 2>&1) ; then\n" + " gxmessage -buttons \"Damn it:0\" -center -title \"Very Fatal Error\" -file %s\n" + "elif (which xmessage > /dev/null 2>&1) ; then\n" + " xmessage -buttons \"Damn it:0\" -center -file %s -geometry 600x400\n" "fi", cc_logfile, cc_logfile); system(buf); } @@ -376,8 +318,8 @@ static void crash_catcher(int signum, siginfo_t *siginfo, void *context) _exit(0); default: - /* Wait and let the child attach gdb */ - waitpid(dbg_pid, NULL, 0); + /* Wait indefinitely; we'll be killed when gdb is done */ + while(1) usleep(1000000); } } @@ -388,12 +330,13 @@ int cc_install_handlers(int num_signals, int *signals, const char *logfile, int memset(&sa, 0, sizeof(sa)); sa.sa_sigaction = crash_catcher; - -#if !defined(__FreeBSD__) && !defined(__APPLE__) + +#ifdef SA_ONESHOT sa.sa_flags = SA_ONESHOT | SA_NODEFER | SA_SIGINFO; #else sa.sa_flags = SA_NODEFER | SA_SIGINFO; #endif + sigemptyset(&sa.sa_mask); cc_logfile = logfile; cc_user_info = user_info; diff --git a/src/sound/efx.h b/src/sound/efx.h new file mode 100644 index 0000000000..1f89ae9b9d --- /dev/null +++ b/src/sound/efx.h @@ -0,0 +1,758 @@ +#ifndef AL_EFX_H +#define AL_EFX_H + + +#ifdef __cplusplus +extern "C" { +#endif + +#define ALC_EXT_EFX_NAME "ALC_EXT_EFX" + +#define ALC_EFX_MAJOR_VERSION 0x20001 +#define ALC_EFX_MINOR_VERSION 0x20002 +#define ALC_MAX_AUXILIARY_SENDS 0x20003 + + +/* Listener properties. */ +#define AL_METERS_PER_UNIT 0x20004 + +/* Source properties. */ +#define AL_DIRECT_FILTER 0x20005 +#define AL_AUXILIARY_SEND_FILTER 0x20006 +#define AL_AIR_ABSORPTION_FACTOR 0x20007 +#define AL_ROOM_ROLLOFF_FACTOR 0x20008 +#define AL_CONE_OUTER_GAINHF 0x20009 +#define AL_DIRECT_FILTER_GAINHF_AUTO 0x2000A +#define AL_AUXILIARY_SEND_FILTER_GAIN_AUTO 0x2000B +#define AL_AUXILIARY_SEND_FILTER_GAINHF_AUTO 0x2000C + + +/* Effect properties. */ + +/* Reverb effect parameters */ +#define AL_REVERB_DENSITY 0x0001 +#define AL_REVERB_DIFFUSION 0x0002 +#define AL_REVERB_GAIN 0x0003 +#define AL_REVERB_GAINHF 0x0004 +#define AL_REVERB_DECAY_TIME 0x0005 +#define AL_REVERB_DECAY_HFRATIO 0x0006 +#define AL_REVERB_REFLECTIONS_GAIN 0x0007 +#define AL_REVERB_REFLECTIONS_DELAY 0x0008 +#define AL_REVERB_LATE_REVERB_GAIN 0x0009 +#define AL_REVERB_LATE_REVERB_DELAY 0x000A +#define AL_REVERB_AIR_ABSORPTION_GAINHF 0x000B +#define AL_REVERB_ROOM_ROLLOFF_FACTOR 0x000C +#define AL_REVERB_DECAY_HFLIMIT 0x000D + +/* EAX Reverb effect parameters */ +#define AL_EAXREVERB_DENSITY 0x0001 +#define AL_EAXREVERB_DIFFUSION 0x0002 +#define AL_EAXREVERB_GAIN 0x0003 +#define AL_EAXREVERB_GAINHF 0x0004 +#define AL_EAXREVERB_GAINLF 0x0005 +#define AL_EAXREVERB_DECAY_TIME 0x0006 +#define AL_EAXREVERB_DECAY_HFRATIO 0x0007 +#define AL_EAXREVERB_DECAY_LFRATIO 0x0008 +#define AL_EAXREVERB_REFLECTIONS_GAIN 0x0009 +#define AL_EAXREVERB_REFLECTIONS_DELAY 0x000A +#define AL_EAXREVERB_REFLECTIONS_PAN 0x000B +#define AL_EAXREVERB_LATE_REVERB_GAIN 0x000C +#define AL_EAXREVERB_LATE_REVERB_DELAY 0x000D +#define AL_EAXREVERB_LATE_REVERB_PAN 0x000E +#define AL_EAXREVERB_ECHO_TIME 0x000F +#define AL_EAXREVERB_ECHO_DEPTH 0x0010 +#define AL_EAXREVERB_MODULATION_TIME 0x0011 +#define AL_EAXREVERB_MODULATION_DEPTH 0x0012 +#define AL_EAXREVERB_AIR_ABSORPTION_GAINHF 0x0013 +#define AL_EAXREVERB_HFREFERENCE 0x0014 +#define AL_EAXREVERB_LFREFERENCE 0x0015 +#define AL_EAXREVERB_ROOM_ROLLOFF_FACTOR 0x0016 +#define AL_EAXREVERB_DECAY_HFLIMIT 0x0017 + +/* Chorus effect parameters */ +#define AL_CHORUS_WAVEFORM 0x0001 +#define AL_CHORUS_PHASE 0x0002 +#define AL_CHORUS_RATE 0x0003 +#define AL_CHORUS_DEPTH 0x0004 +#define AL_CHORUS_FEEDBACK 0x0005 +#define AL_CHORUS_DELAY 0x0006 + +/* Distortion effect parameters */ +#define AL_DISTORTION_EDGE 0x0001 +#define AL_DISTORTION_GAIN 0x0002 +#define AL_DISTORTION_LOWPASS_CUTOFF 0x0003 +#define AL_DISTORTION_EQCENTER 0x0004 +#define AL_DISTORTION_EQBANDWIDTH 0x0005 + +/* Echo effect parameters */ +#define AL_ECHO_DELAY 0x0001 +#define AL_ECHO_LRDELAY 0x0002 +#define AL_ECHO_DAMPING 0x0003 +#define AL_ECHO_FEEDBACK 0x0004 +#define AL_ECHO_SPREAD 0x0005 + +/* Flanger effect parameters */ +#define AL_FLANGER_WAVEFORM 0x0001 +#define AL_FLANGER_PHASE 0x0002 +#define AL_FLANGER_RATE 0x0003 +#define AL_FLANGER_DEPTH 0x0004 +#define AL_FLANGER_FEEDBACK 0x0005 +#define AL_FLANGER_DELAY 0x0006 + +/* Frequency shifter effect parameters */ +#define AL_FREQUENCY_SHIFTER_FREQUENCY 0x0001 +#define AL_FREQUENCY_SHIFTER_LEFT_DIRECTION 0x0002 +#define AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION 0x0003 + +/* Vocal morpher effect parameters */ +#define AL_VOCAL_MORPHER_PHONEMEA 0x0001 +#define AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING 0x0002 +#define AL_VOCAL_MORPHER_PHONEMEB 0x0003 +#define AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING 0x0004 +#define AL_VOCAL_MORPHER_WAVEFORM 0x0005 +#define AL_VOCAL_MORPHER_RATE 0x0006 + +/* Pitchshifter effect parameters */ +#define AL_PITCH_SHIFTER_COARSE_TUNE 0x0001 +#define AL_PITCH_SHIFTER_FINE_TUNE 0x0002 + +/* Ringmodulator effect parameters */ +#define AL_RING_MODULATOR_FREQUENCY 0x0001 +#define AL_RING_MODULATOR_HIGHPASS_CUTOFF 0x0002 +#define AL_RING_MODULATOR_WAVEFORM 0x0003 + +/* Autowah effect parameters */ +#define AL_AUTOWAH_ATTACK_TIME 0x0001 +#define AL_AUTOWAH_RELEASE_TIME 0x0002 +#define AL_AUTOWAH_RESONANCE 0x0003 +#define AL_AUTOWAH_PEAK_GAIN 0x0004 + +/* Compressor effect parameters */ +#define AL_COMPRESSOR_ONOFF 0x0001 + +/* Equalizer effect parameters */ +#define AL_EQUALIZER_LOW_GAIN 0x0001 +#define AL_EQUALIZER_LOW_CUTOFF 0x0002 +#define AL_EQUALIZER_MID1_GAIN 0x0003 +#define AL_EQUALIZER_MID1_CENTER 0x0004 +#define AL_EQUALIZER_MID1_WIDTH 0x0005 +#define AL_EQUALIZER_MID2_GAIN 0x0006 +#define AL_EQUALIZER_MID2_CENTER 0x0007 +#define AL_EQUALIZER_MID2_WIDTH 0x0008 +#define AL_EQUALIZER_HIGH_GAIN 0x0009 +#define AL_EQUALIZER_HIGH_CUTOFF 0x000A + +/* Effect type */ +#define AL_EFFECT_FIRST_PARAMETER 0x0000 +#define AL_EFFECT_LAST_PARAMETER 0x8000 +#define AL_EFFECT_TYPE 0x8001 + +/* Effect types, used with the AL_EFFECT_TYPE property */ +#define AL_EFFECT_NULL 0x0000 +#define AL_EFFECT_REVERB 0x0001 +#define AL_EFFECT_CHORUS 0x0002 +#define AL_EFFECT_DISTORTION 0x0003 +#define AL_EFFECT_ECHO 0x0004 +#define AL_EFFECT_FLANGER 0x0005 +#define AL_EFFECT_FREQUENCY_SHIFTER 0x0006 +#define AL_EFFECT_VOCAL_MORPHER 0x0007 +#define AL_EFFECT_PITCH_SHIFTER 0x0008 +#define AL_EFFECT_RING_MODULATOR 0x0009 +#define AL_EFFECT_AUTOWAH 0x000A +#define AL_EFFECT_COMPRESSOR 0x000B +#define AL_EFFECT_EQUALIZER 0x000C +#define AL_EFFECT_EAXREVERB 0x8000 + +/* Auxiliary Effect Slot properties. */ +#define AL_EFFECTSLOT_EFFECT 0x0001 +#define AL_EFFECTSLOT_GAIN 0x0002 +#define AL_EFFECTSLOT_AUXILIARY_SEND_AUTO 0x0003 + +/* NULL Auxiliary Slot ID to disable a source send. */ +#define AL_EFFECTSLOT_NULL 0x0000 + + +/* Filter properties. */ + +/* Lowpass filter parameters */ +#define AL_LOWPASS_GAIN 0x0001 +#define AL_LOWPASS_GAINHF 0x0002 + +/* Highpass filter parameters */ +#define AL_HIGHPASS_GAIN 0x0001 +#define AL_HIGHPASS_GAINLF 0x0002 + +/* Bandpass filter parameters */ +#define AL_BANDPASS_GAIN 0x0001 +#define AL_BANDPASS_GAINLF 0x0002 +#define AL_BANDPASS_GAINHF 0x0003 + +/* Filter type */ +#define AL_FILTER_FIRST_PARAMETER 0x0000 +#define AL_FILTER_LAST_PARAMETER 0x8000 +#define AL_FILTER_TYPE 0x8001 + +/* Filter types, used with the AL_FILTER_TYPE property */ +#define AL_FILTER_NULL 0x0000 +#define AL_FILTER_LOWPASS 0x0001 +#define AL_FILTER_HIGHPASS 0x0002 +#define AL_FILTER_BANDPASS 0x0003 + + +/* Effect object function types. */ +typedef void (AL_APIENTRY *LPALGENEFFECTS)(ALsizei, ALuint*); +typedef void (AL_APIENTRY *LPALDELETEEFFECTS)(ALsizei, ALuint*); +typedef ALboolean (AL_APIENTRY *LPALISEFFECT)(ALuint); +typedef void (AL_APIENTRY *LPALEFFECTI)(ALuint, ALenum, ALint); +typedef void (AL_APIENTRY *LPALEFFECTIV)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALEFFECTF)(ALuint, ALenum, ALfloat); +typedef void (AL_APIENTRY *LPALEFFECTFV)(ALuint, ALenum, ALfloat*); +typedef void (AL_APIENTRY *LPALGETEFFECTI)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALGETEFFECTIV)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALGETEFFECTF)(ALuint, ALenum, ALfloat*); +typedef void (AL_APIENTRY *LPALGETEFFECTFV)(ALuint, ALenum, ALfloat*); + +/* Filter object function types. */ +typedef void (AL_APIENTRY *LPALGENFILTERS)(ALsizei, ALuint*); +typedef void (AL_APIENTRY *LPALDELETEFILTERS)(ALsizei, ALuint*); +typedef ALboolean (AL_APIENTRY *LPALISFILTER)(ALuint); +typedef void (AL_APIENTRY *LPALFILTERI)(ALuint, ALenum, ALint); +typedef void (AL_APIENTRY *LPALFILTERIV)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALFILTERF)(ALuint, ALenum, ALfloat); +typedef void (AL_APIENTRY *LPALFILTERFV)(ALuint, ALenum, ALfloat*); +typedef void (AL_APIENTRY *LPALGETFILTERI)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALGETFILTERIV)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALGETFILTERF)(ALuint, ALenum, ALfloat*); +typedef void (AL_APIENTRY *LPALGETFILTERFV)(ALuint, ALenum, ALfloat*); + +/* Auxiliary Effect Slot object function types. */ +typedef void (AL_APIENTRY *LPALGENAUXILIARYEFFECTSLOTS)(ALsizei, ALuint*); +typedef void (AL_APIENTRY *LPALDELETEAUXILIARYEFFECTSLOTS)(ALsizei, ALuint*); +typedef ALboolean (AL_APIENTRY *LPALISAUXILIARYEFFECTSLOT)(ALuint); +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint); +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat); +typedef void (AL_APIENTRY *LPALAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, ALfloat*); +typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTI)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTIV)(ALuint, ALenum, ALint*); +typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTF)(ALuint, ALenum, ALfloat*); +typedef void (AL_APIENTRY *LPALGETAUXILIARYEFFECTSLOTFV)(ALuint, ALenum, ALfloat*); + +#ifdef AL_ALEXT_PROTOTYPES +AL_API ALvoid AL_APIENTRY alGenEffects(ALsizei n, ALuint *effects); +AL_API ALvoid AL_APIENTRY alDeleteEffects(ALsizei n, ALuint *effects); +AL_API ALboolean AL_APIENTRY alIsEffect(ALuint effect); +AL_API ALvoid AL_APIENTRY alEffecti(ALuint effect, ALenum param, ALint iValue); +AL_API ALvoid AL_APIENTRY alEffectiv(ALuint effect, ALenum param, ALint *piValues); +AL_API ALvoid AL_APIENTRY alEffectf(ALuint effect, ALenum param, ALfloat flValue); +AL_API ALvoid AL_APIENTRY alEffectfv(ALuint effect, ALenum param, ALfloat *pflValues); +AL_API ALvoid AL_APIENTRY alGetEffecti(ALuint effect, ALenum param, ALint *piValue); +AL_API ALvoid AL_APIENTRY alGetEffectiv(ALuint effect, ALenum param, ALint *piValues); +AL_API ALvoid AL_APIENTRY alGetEffectf(ALuint effect, ALenum param, ALfloat *pflValue); +AL_API ALvoid AL_APIENTRY alGetEffectfv(ALuint effect, ALenum param, ALfloat *pflValues); + +AL_API ALvoid AL_APIENTRY alGenFilters(ALsizei n, ALuint *filters); +AL_API ALvoid AL_APIENTRY alDeleteFilters(ALsizei n, ALuint *filters); +AL_API ALboolean AL_APIENTRY alIsFilter(ALuint filter); +AL_API ALvoid AL_APIENTRY alFilteri(ALuint filter, ALenum param, ALint iValue); +AL_API ALvoid AL_APIENTRY alFilteriv(ALuint filter, ALenum param, ALint *piValues); +AL_API ALvoid AL_APIENTRY alFilterf(ALuint filter, ALenum param, ALfloat flValue); +AL_API ALvoid AL_APIENTRY alFilterfv(ALuint filter, ALenum param, ALfloat *pflValues); +AL_API ALvoid AL_APIENTRY alGetFilteri(ALuint filter, ALenum param, ALint *piValue); +AL_API ALvoid AL_APIENTRY alGetFilteriv(ALuint filter, ALenum param, ALint *piValues); +AL_API ALvoid AL_APIENTRY alGetFilterf(ALuint filter, ALenum param, ALfloat *pflValue); +AL_API ALvoid AL_APIENTRY alGetFilterfv(ALuint filter, ALenum param, ALfloat *pflValues); + +AL_API ALvoid AL_APIENTRY alGenAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots); +AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, ALuint *effectslots); +AL_API ALboolean AL_APIENTRY alIsAuxiliaryEffectSlot(ALuint effectslot); +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint iValue); +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues); +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat flValue); +AL_API ALvoid AL_APIENTRY alAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues); +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSloti(ALuint effectslot, ALenum param, ALint *piValue); +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotiv(ALuint effectslot, ALenum param, ALint *piValues); +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotf(ALuint effectslot, ALenum param, ALfloat *pflValue); +AL_API ALvoid AL_APIENTRY alGetAuxiliaryEffectSlotfv(ALuint effectslot, ALenum param, ALfloat *pflValues); +#endif + +/* Filter ranges and defaults. */ + +/* Lowpass filter */ +#define LOWPASS_MIN_GAIN (0.0f) +#define LOWPASS_MAX_GAIN (1.0f) +#define LOWPASS_DEFAULT_GAIN (1.0f) + +#define LOWPASS_MIN_GAINHF (0.0f) +#define LOWPASS_MAX_GAINHF (1.0f) +#define LOWPASS_DEFAULT_GAINHF (1.0f) + +/* Highpass filter */ +#define HIGHPASS_MIN_GAIN (0.0f) +#define HIGHPASS_MAX_GAIN (1.0f) +#define HIGHPASS_DEFAULT_GAIN (1.0f) + +#define HIGHPASS_MIN_GAINLF (0.0f) +#define HIGHPASS_MAX_GAINLF (1.0f) +#define HIGHPASS_DEFAULT_GAINLF (1.0f) + +/* Bandpass filter */ +#define BANDPASS_MIN_GAIN (0.0f) +#define BANDPASS_MAX_GAIN (1.0f) +#define BANDPASS_DEFAULT_GAIN (1.0f) + +#define BANDPASS_MIN_GAINHF (0.0f) +#define BANDPASS_MAX_GAINHF (1.0f) +#define BANDPASS_DEFAULT_GAINHF (1.0f) + +#define BANDPASS_MIN_GAINLF (0.0f) +#define BANDPASS_MAX_GAINLF (1.0f) +#define BANDPASS_DEFAULT_GAINLF (1.0f) + + +/* Effect parameter ranges and defaults. */ + +/* Standard reverb effect */ +#define AL_REVERB_MIN_DENSITY (0.0f) +#define AL_REVERB_MAX_DENSITY (1.0f) +#define AL_REVERB_DEFAULT_DENSITY (1.0f) + +#define AL_REVERB_MIN_DIFFUSION (0.0f) +#define AL_REVERB_MAX_DIFFUSION (1.0f) +#define AL_REVERB_DEFAULT_DIFFUSION (1.0f) + +#define AL_REVERB_MIN_GAIN (0.0f) +#define AL_REVERB_MAX_GAIN (1.0f) +#define AL_REVERB_DEFAULT_GAIN (0.32f) + +#define AL_REVERB_MIN_GAINHF (0.0f) +#define AL_REVERB_MAX_GAINHF (1.0f) +#define AL_REVERB_DEFAULT_GAINHF (0.89f) + +#define AL_REVERB_MIN_DECAY_TIME (0.1f) +#define AL_REVERB_MAX_DECAY_TIME (20.0f) +#define AL_REVERB_DEFAULT_DECAY_TIME (1.49f) + +#define AL_REVERB_MIN_DECAY_HFRATIO (0.1f) +#define AL_REVERB_MAX_DECAY_HFRATIO (2.0f) +#define AL_REVERB_DEFAULT_DECAY_HFRATIO (0.83f) + +#define AL_REVERB_MIN_REFLECTIONS_GAIN (0.0f) +#define AL_REVERB_MAX_REFLECTIONS_GAIN (3.16f) +#define AL_REVERB_DEFAULT_REFLECTIONS_GAIN (0.05f) + +#define AL_REVERB_MIN_REFLECTIONS_DELAY (0.0f) +#define AL_REVERB_MAX_REFLECTIONS_DELAY (0.3f) +#define AL_REVERB_DEFAULT_REFLECTIONS_DELAY (0.007f) + +#define AL_REVERB_MIN_LATE_REVERB_GAIN (0.0f) +#define AL_REVERB_MAX_LATE_REVERB_GAIN (10.0f) +#define AL_REVERB_DEFAULT_LATE_REVERB_GAIN (1.26f) + +#define AL_REVERB_MIN_LATE_REVERB_DELAY (0.0f) +#define AL_REVERB_MAX_LATE_REVERB_DELAY (0.1f) +#define AL_REVERB_DEFAULT_LATE_REVERB_DELAY (0.011f) + +#define AL_REVERB_MIN_AIR_ABSORPTION_GAINHF (0.892f) +#define AL_REVERB_MAX_AIR_ABSORPTION_GAINHF (1.0f) +#define AL_REVERB_DEFAULT_AIR_ABSORPTION_GAINHF (0.994f) + +#define AL_REVERB_MIN_ROOM_ROLLOFF_FACTOR (0.0f) +#define AL_REVERB_MAX_ROOM_ROLLOFF_FACTOR (10.0f) +#define AL_REVERB_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f) + +#define AL_REVERB_MIN_DECAY_HFLIMIT AL_FALSE +#define AL_REVERB_MAX_DECAY_HFLIMIT AL_TRUE +#define AL_REVERB_DEFAULT_DECAY_HFLIMIT AL_TRUE + +/* EAX reverb effect */ +#define AL_EAXREVERB_MIN_DENSITY (0.0f) +#define AL_EAXREVERB_MAX_DENSITY (1.0f) +#define AL_EAXREVERB_DEFAULT_DENSITY (1.0f) + +#define AL_EAXREVERB_MIN_DIFFUSION (0.0f) +#define AL_EAXREVERB_MAX_DIFFUSION (1.0f) +#define AL_EAXREVERB_DEFAULT_DIFFUSION (1.0f) + +#define AL_EAXREVERB_MIN_GAIN (0.0f) +#define AL_EAXREVERB_MAX_GAIN (1.0f) +#define AL_EAXREVERB_DEFAULT_GAIN (0.32f) + +#define AL_EAXREVERB_MIN_GAINHF (0.0f) +#define AL_EAXREVERB_MAX_GAINHF (1.0f) +#define AL_EAXREVERB_DEFAULT_GAINHF (0.89f) + +#define AL_EAXREVERB_MIN_GAINLF (0.0f) +#define AL_EAXREVERB_MAX_GAINLF (1.0f) +#define AL_EAXREVERB_DEFAULT_GAINLF (1.0f) + +#define AL_EAXREVERB_MIN_DECAY_TIME (0.1f) +#define AL_EAXREVERB_MAX_DECAY_TIME (20.0f) +#define AL_EAXREVERB_DEFAULT_DECAY_TIME (1.49f) + +#define AL_EAXREVERB_MIN_DECAY_HFRATIO (0.1f) +#define AL_EAXREVERB_MAX_DECAY_HFRATIO (2.0f) +#define AL_EAXREVERB_DEFAULT_DECAY_HFRATIO (0.83f) + +#define AL_EAXREVERB_MIN_DECAY_LFRATIO (0.1f) +#define AL_EAXREVERB_MAX_DECAY_LFRATIO (2.0f) +#define AL_EAXREVERB_DEFAULT_DECAY_LFRATIO (1.0f) + +#define AL_EAXREVERB_MIN_REFLECTIONS_GAIN (0.0f) +#define AL_EAXREVERB_MAX_REFLECTIONS_GAIN (3.16f) +#define AL_EAXREVERB_DEFAULT_REFLECTIONS_GAIN (0.05f) + +#define AL_EAXREVERB_MIN_REFLECTIONS_DELAY (0.0f) +#define AL_EAXREVERB_MAX_REFLECTIONS_DELAY (0.3f) +#define AL_EAXREVERB_DEFAULT_REFLECTIONS_DELAY (0.007f) + +#define AL_EAXREVERB_DEFAULT_REFLECTIONS_PAN_XYZ (0.0f) + +#define AL_EAXREVERB_MIN_LATE_REVERB_GAIN (0.0f) +#define AL_EAXREVERB_MAX_LATE_REVERB_GAIN (10.0f) +#define AL_EAXREVERB_DEFAULT_LATE_REVERB_GAIN (1.26f) + +#define AL_EAXREVERB_MIN_LATE_REVERB_DELAY (0.0f) +#define AL_EAXREVERB_MAX_LATE_REVERB_DELAY (0.1f) +#define AL_EAXREVERB_DEFAULT_LATE_REVERB_DELAY (0.011f) + +#define AL_EAXREVERB_DEFAULT_LATE_REVERB_PAN_XYZ (0.0f) + +#define AL_EAXREVERB_MIN_ECHO_TIME (0.075f) +#define AL_EAXREVERB_MAX_ECHO_TIME (0.25f) +#define AL_EAXREVERB_DEFAULT_ECHO_TIME (0.25f) + +#define AL_EAXREVERB_MIN_ECHO_DEPTH (0.0f) +#define AL_EAXREVERB_MAX_ECHO_DEPTH (1.0f) +#define AL_EAXREVERB_DEFAULT_ECHO_DEPTH (0.0f) + +#define AL_EAXREVERB_MIN_MODULATION_TIME (0.04f) +#define AL_EAXREVERB_MAX_MODULATION_TIME (4.0f) +#define AL_EAXREVERB_DEFAULT_MODULATION_TIME (0.25f) + +#define AL_EAXREVERB_MIN_MODULATION_DEPTH (0.0f) +#define AL_EAXREVERB_MAX_MODULATION_DEPTH (1.0f) +#define AL_EAXREVERB_DEFAULT_MODULATION_DEPTH (0.0f) + +#define AL_EAXREVERB_MIN_AIR_ABSORPTION_GAINHF (0.892f) +#define AL_EAXREVERB_MAX_AIR_ABSORPTION_GAINHF (1.0f) +#define AL_EAXREVERB_DEFAULT_AIR_ABSORPTION_GAINHF (0.994f) + +#define AL_EAXREVERB_MIN_HFREFERENCE (1000.0f) +#define AL_EAXREVERB_MAX_HFREFERENCE (20000.0f) +#define AL_EAXREVERB_DEFAULT_HFREFERENCE (5000.0f) + +#define AL_EAXREVERB_MIN_LFREFERENCE (20.0f) +#define AL_EAXREVERB_MAX_LFREFERENCE (1000.0f) +#define AL_EAXREVERB_DEFAULT_LFREFERENCE (250.0f) + +#define AL_EAXREVERB_MIN_ROOM_ROLLOFF_FACTOR (0.0f) +#define AL_EAXREVERB_MAX_ROOM_ROLLOFF_FACTOR (10.0f) +#define AL_EAXREVERB_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f) + +#define AL_EAXREVERB_MIN_DECAY_HFLIMIT AL_FALSE +#define AL_EAXREVERB_MAX_DECAY_HFLIMIT AL_TRUE +#define AL_EAXREVERB_DEFAULT_DECAY_HFLIMIT AL_TRUE + +/* Chorus effect */ +#define AL_CHORUS_WAVEFORM_SINUSOID (0) +#define AL_CHORUS_WAVEFORM_TRIANGLE (1) + +#define AL_CHORUS_MIN_WAVEFORM (0) +#define AL_CHORUS_MAX_WAVEFORM (1) +#define AL_CHORUS_DEFAULT_WAVEFORM (1) + +#define AL_CHORUS_MIN_PHASE (-180) +#define AL_CHORUS_MAX_PHASE (180) +#define AL_CHORUS_DEFAULT_PHASE (90) + +#define AL_CHORUS_MIN_RATE (0.0f) +#define AL_CHORUS_MAX_RATE (10.0f) +#define AL_CHORUS_DEFAULT_RATE (1.1f) + +#define AL_CHORUS_MIN_DEPTH (0.0f) +#define AL_CHORUS_MAX_DEPTH (1.0f) +#define AL_CHORUS_DEFAULT_DEPTH (0.1f) + +#define AL_CHORUS_MIN_FEEDBACK (-1.0f) +#define AL_CHORUS_MAX_FEEDBACK (1.0f) +#define AL_CHORUS_DEFAULT_FEEDBACK (0.25f) + +#define AL_CHORUS_MIN_DELAY (0.0f) +#define AL_CHORUS_MAX_DELAY (0.016f) +#define AL_CHORUS_DEFAULT_DELAY (0.016f) + +/* Distortion effect */ +#define AL_DISTORTION_MIN_EDGE (0.0f) +#define AL_DISTORTION_MAX_EDGE (1.0f) +#define AL_DISTORTION_DEFAULT_EDGE (0.2f) + +#define AL_DISTORTION_MIN_GAIN (0.01f) +#define AL_DISTORTION_MAX_GAIN (1.0f) +#define AL_DISTORTION_DEFAULT_GAIN (0.05f) + +#define AL_DISTORTION_MIN_LOWPASS_CUTOFF (80.0f) +#define AL_DISTORTION_MAX_LOWPASS_CUTOFF (24000.0f) +#define AL_DISTORTION_DEFAULT_LOWPASS_CUTOFF (8000.0f) + +#define AL_DISTORTION_MIN_EQCENTER (80.0f) +#define AL_DISTORTION_MAX_EQCENTER (24000.0f) +#define AL_DISTORTION_DEFAULT_EQCENTER (3600.0f) + +#define AL_DISTORTION_MIN_EQBANDWIDTH (80.0f) +#define AL_DISTORTION_MAX_EQBANDWIDTH (24000.0f) +#define AL_DISTORTION_DEFAULT_EQBANDWIDTH (3600.0f) + +/* Echo effect */ +#define AL_ECHO_MIN_DELAY (0.0f) +#define AL_ECHO_MAX_DELAY (0.207f) +#define AL_ECHO_DEFAULT_DELAY (0.1f) + +#define AL_ECHO_MIN_LRDELAY (0.0f) +#define AL_ECHO_MAX_LRDELAY (0.404f) +#define AL_ECHO_DEFAULT_LRDELAY (0.1f) + +#define AL_ECHO_MIN_DAMPING (0.0f) +#define AL_ECHO_MAX_DAMPING (0.99f) +#define AL_ECHO_DEFAULT_DAMPING (0.5f) + +#define AL_ECHO_MIN_FEEDBACK (0.0f) +#define AL_ECHO_MAX_FEEDBACK (1.0f) +#define AL_ECHO_DEFAULT_FEEDBACK (0.5f) + +#define AL_ECHO_MIN_SPREAD (-1.0f) +#define AL_ECHO_MAX_SPREAD (1.0f) +#define AL_ECHO_DEFAULT_SPREAD (-1.0f) + +/* Flanger effect */ +#define AL_FLANGER_WAVEFORM_SINUSOID (0) +#define AL_FLANGER_WAVEFORM_TRIANGLE (1) + +#define AL_FLANGER_MIN_WAVEFORM (0) +#define AL_FLANGER_MAX_WAVEFORM (1) +#define AL_FLANGER_DEFAULT_WAVEFORM (1) + +#define AL_FLANGER_MIN_PHASE (-180) +#define AL_FLANGER_MAX_PHASE (180) +#define AL_FLANGER_DEFAULT_PHASE (0) + +#define AL_FLANGER_MIN_RATE (0.0f) +#define AL_FLANGER_MAX_RATE (10.0f) +#define AL_FLANGER_DEFAULT_RATE (0.27f) + +#define AL_FLANGER_MIN_DEPTH (0.0f) +#define AL_FLANGER_MAX_DEPTH (1.0f) +#define AL_FLANGER_DEFAULT_DEPTH (1.0f) + +#define AL_FLANGER_MIN_FEEDBACK (-1.0f) +#define AL_FLANGER_MAX_FEEDBACK (1.0f) +#define AL_FLANGER_DEFAULT_FEEDBACK (-0.5f) + +#define AL_FLANGER_MIN_DELAY (0.0f) +#define AL_FLANGER_MAX_DELAY (0.004f) +#define AL_FLANGER_DEFAULT_DELAY (0.002f) + +/* Frequency shifter effect */ +#define AL_FREQUENCY_SHIFTER_MIN_FREQUENCY (0.0f) +#define AL_FREQUENCY_SHIFTER_MAX_FREQUENCY (24000.0f) +#define AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY (0.0f) + +#define AL_FREQUENCY_SHIFTER_MIN_LEFT_DIRECTION (0) +#define AL_FREQUENCY_SHIFTER_MAX_LEFT_DIRECTION (2) +#define AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION (0) + +#define AL_FREQUENCY_SHIFTER_DIRECTION_DOWN (0) +#define AL_FREQUENCY_SHIFTER_DIRECTION_UP (1) +#define AL_FREQUENCY_SHIFTER_DIRECTION_OFF (2) + +#define AL_FREQUENCY_SHIFTER_MIN_RIGHT_DIRECTION (0) +#define AL_FREQUENCY_SHIFTER_MAX_RIGHT_DIRECTION (2) +#define AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION (0) + +/* Vocal morpher effect */ +#define AL_VOCAL_MORPHER_MIN_PHONEMEA (0) +#define AL_VOCAL_MORPHER_MAX_PHONEMEA (29) +#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEA (0) + +#define AL_VOCAL_MORPHER_MIN_PHONEMEA_COARSE_TUNING (-24) +#define AL_VOCAL_MORPHER_MAX_PHONEMEA_COARSE_TUNING (24) +#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEA_COARSE_TUNING (0) + +#define AL_VOCAL_MORPHER_MIN_PHONEMEB (0) +#define AL_VOCAL_MORPHER_MAX_PHONEMEB (29) +#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEB (10) + +#define AL_VOCAL_MORPHER_MIN_PHONEMEB_COARSE_TUNING (-24) +#define AL_VOCAL_MORPHER_MAX_PHONEMEB_COARSE_TUNING (24) +#define AL_VOCAL_MORPHER_DEFAULT_PHONEMEB_COARSE_TUNING (0) + +#define AL_VOCAL_MORPHER_PHONEME_A (0) +#define AL_VOCAL_MORPHER_PHONEME_E (1) +#define AL_VOCAL_MORPHER_PHONEME_I (2) +#define AL_VOCAL_MORPHER_PHONEME_O (3) +#define AL_VOCAL_MORPHER_PHONEME_U (4) +#define AL_VOCAL_MORPHER_PHONEME_AA (5) +#define AL_VOCAL_MORPHER_PHONEME_AE (6) +#define AL_VOCAL_MORPHER_PHONEME_AH (7) +#define AL_VOCAL_MORPHER_PHONEME_AO (8) +#define AL_VOCAL_MORPHER_PHONEME_EH (9) +#define AL_VOCAL_MORPHER_PHONEME_ER (10) +#define AL_VOCAL_MORPHER_PHONEME_IH (11) +#define AL_VOCAL_MORPHER_PHONEME_IY (12) +#define AL_VOCAL_MORPHER_PHONEME_UH (13) +#define AL_VOCAL_MORPHER_PHONEME_UW (14) +#define AL_VOCAL_MORPHER_PHONEME_B (15) +#define AL_VOCAL_MORPHER_PHONEME_D (16) +#define AL_VOCAL_MORPHER_PHONEME_F (17) +#define AL_VOCAL_MORPHER_PHONEME_G (18) +#define AL_VOCAL_MORPHER_PHONEME_J (19) +#define AL_VOCAL_MORPHER_PHONEME_K (20) +#define AL_VOCAL_MORPHER_PHONEME_L (21) +#define AL_VOCAL_MORPHER_PHONEME_M (22) +#define AL_VOCAL_MORPHER_PHONEME_N (23) +#define AL_VOCAL_MORPHER_PHONEME_P (24) +#define AL_VOCAL_MORPHER_PHONEME_R (25) +#define AL_VOCAL_MORPHER_PHONEME_S (26) +#define AL_VOCAL_MORPHER_PHONEME_T (27) +#define AL_VOCAL_MORPHER_PHONEME_V (28) +#define AL_VOCAL_MORPHER_PHONEME_Z (29) + +#define AL_VOCAL_MORPHER_WAVEFORM_SINUSOID (0) +#define AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE (1) +#define AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH (2) + +#define AL_VOCAL_MORPHER_MIN_WAVEFORM (0) +#define AL_VOCAL_MORPHER_MAX_WAVEFORM (2) +#define AL_VOCAL_MORPHER_DEFAULT_WAVEFORM (0) + +#define AL_VOCAL_MORPHER_MIN_RATE (0.0f) +#define AL_VOCAL_MORPHER_MAX_RATE (10.0f) +#define AL_VOCAL_MORPHER_DEFAULT_RATE (1.41f) + +/* Pitch shifter effect */ +#define AL_PITCH_SHIFTER_MIN_COARSE_TUNE (-12) +#define AL_PITCH_SHIFTER_MAX_COARSE_TUNE (12) +#define AL_PITCH_SHIFTER_DEFAULT_COARSE_TUNE (12) + +#define AL_PITCH_SHIFTER_MIN_FINE_TUNE (-50) +#define AL_PITCH_SHIFTER_MAX_FINE_TUNE (50) +#define AL_PITCH_SHIFTER_DEFAULT_FINE_TUNE (0) + +/* Ring modulator effect */ +#define AL_RING_MODULATOR_MIN_FREQUENCY (0.0f) +#define AL_RING_MODULATOR_MAX_FREQUENCY (8000.0f) +#define AL_RING_MODULATOR_DEFAULT_FREQUENCY (440.0f) + +#define AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF (0.0f) +#define AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF (24000.0f) +#define AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF (800.0f) + +#define AL_RING_MODULATOR_SINUSOID (0) +#define AL_RING_MODULATOR_SAWTOOTH (1) +#define AL_RING_MODULATOR_SQUARE (2) + +#define AL_RING_MODULATOR_MIN_WAVEFORM (0) +#define AL_RING_MODULATOR_MAX_WAVEFORM (2) +#define AL_RING_MODULATOR_DEFAULT_WAVEFORM (0) + +/* Autowah effect */ +#define AL_AUTOWAH_MIN_ATTACK_TIME (0.0001f) +#define AL_AUTOWAH_MAX_ATTACK_TIME (1.0f) +#define AL_AUTOWAH_DEFAULT_ATTACK_TIME (0.06f) + +#define AL_AUTOWAH_MIN_RELEASE_TIME (0.0001f) +#define AL_AUTOWAH_MAX_RELEASE_TIME (1.0f) +#define AL_AUTOWAH_DEFAULT_RELEASE_TIME (0.06f) + +#define AL_AUTOWAH_MIN_RESONANCE (2.0f) +#define AL_AUTOWAH_MAX_RESONANCE (1000.0f) +#define AL_AUTOWAH_DEFAULT_RESONANCE (1000.0f) + +#define AL_AUTOWAH_MIN_PEAK_GAIN (0.00003f) +#define AL_AUTOWAH_MAX_PEAK_GAIN (31621.0f) +#define AL_AUTOWAH_DEFAULT_PEAK_GAIN (11.22f) + +/* Compressor effect */ +#define AL_COMPRESSOR_MIN_ONOFF (0) +#define AL_COMPRESSOR_MAX_ONOFF (1) +#define AL_COMPRESSOR_DEFAULT_ONOFF (1) + +/* Equalizer effect */ +#define AL_EQUALIZER_MIN_LOW_GAIN (0.126f) +#define AL_EQUALIZER_MAX_LOW_GAIN (7.943f) +#define AL_EQUALIZER_DEFAULT_LOW_GAIN (1.0f) + +#define AL_EQUALIZER_MIN_LOW_CUTOFF (50.0f) +#define AL_EQUALIZER_MAX_LOW_CUTOFF (800.0f) +#define AL_EQUALIZER_DEFAULT_LOW_CUTOFF (200.0f) + +#define AL_EQUALIZER_MIN_MID1_GAIN (0.126f) +#define AL_EQUALIZER_MAX_MID1_GAIN (7.943f) +#define AL_EQUALIZER_DEFAULT_MID1_GAIN (1.0f) + +#define AL_EQUALIZER_MIN_MID1_CENTER (200.0f) +#define AL_EQUALIZER_MAX_MID1_CENTER (3000.0f) +#define AL_EQUALIZER_DEFAULT_MID1_CENTER (500.0f) + +#define AL_EQUALIZER_MIN_MID1_WIDTH (0.01f) +#define AL_EQUALIZER_MAX_MID1_WIDTH (1.0f) +#define AL_EQUALIZER_DEFAULT_MID1_WIDTH (1.0f) + +#define AL_EQUALIZER_MIN_MID2_GAIN (0.126f) +#define AL_EQUALIZER_MAX_MID2_GAIN (7.943f) +#define AL_EQUALIZER_DEFAULT_MID2_GAIN (1.0f) + +#define AL_EQUALIZER_MIN_MID2_CENTER (1000.0f) +#define AL_EQUALIZER_MAX_MID2_CENTER (8000.0f) +#define AL_EQUALIZER_DEFAULT_MID2_CENTER (3000.0f) + +#define AL_EQUALIZER_MIN_MID2_WIDTH (0.01f) +#define AL_EQUALIZER_MAX_MID2_WIDTH (1.0f) +#define AL_EQUALIZER_DEFAULT_MID2_WIDTH (1.0f) + +#define AL_EQUALIZER_MIN_HIGH_GAIN (0.126f) +#define AL_EQUALIZER_MAX_HIGH_GAIN (7.943f) +#define AL_EQUALIZER_DEFAULT_HIGH_GAIN (1.0f) + +#define AL_EQUALIZER_MIN_HIGH_CUTOFF (4000.0f) +#define AL_EQUALIZER_MAX_HIGH_CUTOFF (16000.0f) +#define AL_EQUALIZER_DEFAULT_HIGH_CUTOFF (6000.0f) + + +/* Source parameter value ranges and defaults. */ +#define AL_MIN_AIR_ABSORPTION_FACTOR (0.0f) +#define AL_MAX_AIR_ABSORPTION_FACTOR (10.0f) +#define AL_DEFAULT_AIR_ABSORPTION_FACTOR (0.0f) + +#define AL_MIN_ROOM_ROLLOFF_FACTOR (0.0f) +#define AL_MAX_ROOM_ROLLOFF_FACTOR (10.0f) +#define AL_DEFAULT_ROOM_ROLLOFF_FACTOR (0.0f) + +#define AL_MIN_CONE_OUTER_GAINHF (0.0f) +#define AL_MAX_CONE_OUTER_GAINHF (1.0f) +#define AL_DEFAULT_CONE_OUTER_GAINHF (1.0f) + +#define AL_MIN_DIRECT_FILTER_GAINHF_AUTO AL_FALSE +#define AL_MAX_DIRECT_FILTER_GAINHF_AUTO AL_TRUE +#define AL_DEFAULT_DIRECT_FILTER_GAINHF_AUTO AL_TRUE + +#define AL_MIN_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_FALSE +#define AL_MAX_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_TRUE +#define AL_DEFAULT_AUXILIARY_SEND_FILTER_GAIN_AUTO AL_TRUE + +#define AL_MIN_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_FALSE +#define AL_MAX_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_TRUE +#define AL_DEFAULT_AUXILIARY_SEND_FILTER_GAINHF_AUTO AL_TRUE + + +/* Listener parameter value ranges and defaults. */ +#define AL_MIN_METERS_PER_UNIT FLT_MIN +#define AL_MAX_METERS_PER_UNIT FLT_MAX +#define AL_DEFAULT_METERS_PER_UNIT (1.0f) + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* AL_EFX_H */ diff --git a/src/sound/fmod_wrap.h b/src/sound/fmod_wrap.h index f77eed36c6..be676d9ddc 100644 --- a/src/sound/fmod_wrap.h +++ b/src/sound/fmod_wrap.h @@ -2,6 +2,8 @@ #ifndef FMOD_WRAP_H #define FMOD_WRAP_H +#ifndef NO_FMOD + #if !defined(_WIN32) || defined(_MSC_VER) // Use the real C++ interface if it's supported on this platform. #include "fmod.hpp" @@ -610,3 +612,4 @@ namespace FMOD #endif #endif +#endif diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index 30efe22d9c..cdbb70645a 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -75,6 +75,36 @@ extern HWND Window; #define SPECTRUM_SIZE 256 +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +ReverbContainer *ForcedEnvironment; + +CVAR (Int, snd_driver, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CVAR (Int, snd_buffercount, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CVAR (Bool, snd_hrtf, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CVAR (Bool, snd_waterreverb, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CVAR (String, snd_resampler, "Linear", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CVAR (String, snd_speakermode, "Auto", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CVAR (String, snd_output_format, "PCM-16", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CVAR (String, snd_midipatchset, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CVAR (Bool, snd_profile, false, 0) + +// Underwater low-pass filter cutoff frequency. Set to 0 to disable the filter. +CUSTOM_CVAR (Float, snd_waterlp, 250, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +{ + // Clamp to the DSP unit's limits. + if (*self < 10 && *self != 0) + { + self = 10; + } + else if (*self > 22000) + { + self = 22000; + } +} + +#ifndef NO_FMOD + // TYPES ------------------------------------------------------------------- struct FEnumList @@ -104,34 +134,6 @@ EXTERN_CVAR (Int, snd_channels) extern int sfx_empty; -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -ReverbContainer *ForcedEnvironment; - -CVAR (Int, snd_driver, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (Int, snd_buffercount, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (Bool, snd_hrtf, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (Bool, snd_waterreverb, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (String, snd_resampler, "Linear", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (String, snd_speakermode, "Auto", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (String, snd_output_format, "PCM-16", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (String, snd_midipatchset, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (Bool, snd_profile, false, 0) - -// Underwater low-pass filter cutoff frequency. Set to 0 to disable the filter. -CUSTOM_CVAR (Float, snd_waterlp, 250, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - // Clamp to the DSP unit's limits. - if (*self < 10 && *self != 0) - { - self = 10; - } - else if (*self > 22000) - { - self = 22000; - } -} - // PRIVATE DATA DEFINITIONS ------------------------------------------------ static const ReverbContainer *PrevEnvironment; @@ -2900,3 +2902,5 @@ void FMODSoundRenderer::InitCreateSoundExInfo(FMOD_CREATESOUNDEXINFO *exinfo) co } memset((BYTE *)exinfo + sizeof(exinfo->cbsize), 0, exinfo->cbsize - sizeof(exinfo->cbsize)); } + +#endif // NO_FMOD diff --git a/src/sound/fmodsound.h b/src/sound/fmodsound.h index 1460b697b8..fcaffda8d2 100644 --- a/src/sound/fmodsound.h +++ b/src/sound/fmodsound.h @@ -2,6 +2,8 @@ #define FMODSOUND_H #include "i_sound.h" + +#ifndef NO_FMOD #include "fmod_wrap.h" class FMODSoundRenderer : public SoundRenderer @@ -117,3 +119,4 @@ private: }; #endif +#endif diff --git a/src/sound/i_sound.cpp b/src/sound/i_sound.cpp index b25bbd6fbf..8261d4611a 100644 --- a/src/sound/i_sound.cpp +++ b/src/sound/i_sound.cpp @@ -53,6 +53,7 @@ extern HINSTANCE g_hInst; #include #include "fmodsound.h" +#include "oalsound.h" #include "m_swap.h" #include "stats.h" @@ -77,6 +78,14 @@ CVAR (Int, snd_samplerate, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (Int, snd_buffersize, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (String, snd_output, "default", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +#ifndef NO_FMOD +CVAR (String, snd_backend, "fmod", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +#elif !defined(NO_OPENAL) +CVAR (String, snd_backend, "openal", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +#else +CVAR (String, snd_backend, "null", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +#endif + // killough 2/21/98: optionally use varying pitched sounds CVAR (Bool, snd_pitched, false, CVAR_ARCHIVE) @@ -243,9 +252,17 @@ void I_InitSound () return; } - GSnd = new FMODSoundRenderer; - - if (!GSnd->IsValid ()) + if(stricmp(snd_backend, "null") == 0) + GSnd = new NullSoundRenderer; +#ifndef NO_FMOD + else if(stricmp(snd_backend, "fmod") == 0) + GSnd = new FMODSoundRenderer; +#endif +#ifndef NO_OPENAL + else if(stricmp(snd_backend, "openal") == 0) + GSnd = new OpenALSoundRenderer; +#endif + if (!GSnd || !GSnd->IsValid ()) { I_CloseSound(); GSnd = new NullSoundRenderer; diff --git a/src/sound/i_soundinternal.h b/src/sound/i_soundinternal.h index 157c9c87bc..b0f42913a3 100644 --- a/src/sound/i_soundinternal.h +++ b/src/sound/i_soundinternal.h @@ -96,6 +96,8 @@ struct FISoundChannel // callback that can't be passed a sound channel pointer FRolloffInfo Rolloff; float DistanceScale; + float DistanceSqr; + bool ManualGain; }; diff --git a/src/sound/music_midi_base.cpp b/src/sound/music_midi_base.cpp index d7983a70f3..77c8dde9c7 100644 --- a/src/sound/music_midi_base.cpp +++ b/src/sound/music_midi_base.cpp @@ -85,7 +85,7 @@ void I_BuildMIDIMenuList (struct value_t **outValues, float *numValues) values[0].value = -3.0; values[1].name = "TiMidity++"; values[1].value = -2.0; - values[2].name = "FMOD"; + values[2].name = "Sound System"; values[2].value = -1.0; for (id = 0, p = 3; id < nummididevices; ++id) { @@ -153,7 +153,7 @@ CCMD (snd_listmididevices) PrintMidiDevice (-3, "Emulated OPL FM Synth", MOD_FMSYNTH, 0); PrintMidiDevice (-2, "TiMidity++", 0, MOD_SWSYNTH); - PrintMidiDevice (-1, "FMOD", 0, MOD_SWSYNTH); + PrintMidiDevice (-1, "Sound System", 0, MOD_SWSYNTH); if (nummididevices != 0) { for (id = 0; id < nummididevices; ++id) @@ -195,7 +195,7 @@ void I_BuildMIDIMenuList (struct value_t **outValues, float *numValues) values[0].value = -3.0; values[1].name = "TiMidity++"; values[1].value = -2.0; - values[2].name = "FMOD"; + values[2].name = "Sound System"; values[2].value = -1.0; *numValues = 3.f; } @@ -205,6 +205,6 @@ CCMD (snd_listmididevices) { Printf("%s-3. Emulated OPL FM Synth\n", -3 == snd_mididevice ? TEXTCOLOR_BOLD : ""); Printf("%s-2. TiMidity++\n", -2 == snd_mididevice ? TEXTCOLOR_BOLD : ""); - Printf("%s-1. FMOD\n", -1 == snd_mididevice ? TEXTCOLOR_BOLD : ""); + Printf("%s-1. Sound System\n", -1 == snd_mididevice ? TEXTCOLOR_BOLD : ""); } #endif diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp new file mode 100644 index 0000000000..06107751ed --- /dev/null +++ b/src/sound/oalsound.cpp @@ -0,0 +1,2823 @@ +/* +** oalsound.cpp +** System interface for sound; uses OpenAL +** +**--------------------------------------------------------------------------- +** Copyright 2008-2010 Chris Robinson +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#define USE_WINDOWS_DWORD +#endif + +#include "doomstat.h" +#include "templates.h" +#include "oalsound.h" +#include "c_cvars.h" +#include "c_dispatch.h" +#include "i_system.h" +#include "v_text.h" +#include "gi.h" +#include "actor.h" +#include "r_state.h" +#include "w_wad.h" +#include "i_music.h" +#include "i_musicinterns.h" +#include "tempfiles.h" + + +CVAR (String, snd_aldevice, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CVAR (Bool, snd_efx, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CUSTOM_CVAR (Float, snd_waterabsorption, 10.0f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +{ + if(*self < 0.0f) + self = 0.0f; + else if(*self > 10.0f) + self = 10.0f; +} + +int BuildALDeviceList(valueenum_t **menulist) +{ + std::vector list; + static const char def[] = ""; + + valueenum_t val; + size_t len = strlen(def)+1; + + char *n = new char[len]; + memcpy(n, def, len); + + val.value = n; + val.name = "Default"; + list.push_back(val); + +#ifndef NO_OPENAL + const ALCchar *names = (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") ? + alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER) : + alcGetString(NULL, ALC_DEVICE_SPECIFIER)); + if(!names) + Printf("Failed to get device list: %s\n", alcGetString(NULL, alcGetError(NULL))); + else while(*names) + { + len = strlen(names)+1; + + n = new char[len]; + memcpy(n, names, len); + + val.value = n; + val.name = val.value; + list.push_back(val); + + names += len; + } +#endif + + static const valueenum_t listend = {NULL,NULL}; + list.push_back(listend); + + valueenum_t *newlist = new valueenum_t[list.size()]; + memcpy(&newlist[0], &list[0], list.size()*sizeof(newlist[0])); + + if(*menulist) + { + for(size_t i = 0;(*menulist)[i].value;i++) + delete[] const_cast((*menulist)[i].value); + delete[] *menulist; + } + *menulist = newlist; + return list.size()-1; +} + +#ifndef NO_OPENAL + +#include +#include +#include +#include + + +EXTERN_CVAR (Int, snd_channels) +EXTERN_CVAR (Int, snd_samplerate) +EXTERN_CVAR (Bool, snd_waterreverb) +EXTERN_CVAR (Bool, snd_pitched) + + +#define foreach(type, name, vec) \ + for(std::vector::iterator (name) = (vec).begin(), \ + (_end_##name) = (vec).end(); \ + (name) != (_end_##name);(name)++) + + +static ALenum checkALError(const char *fn, unsigned int ln) +{ + ALenum err = alGetError(); + if(err != AL_NO_ERROR) + { + if(strchr(fn, '/')) + fn = strrchr(fn, '/')+1; + else if(strchr(fn, '\\')) + fn = strrchr(fn, '\\')+1; + Printf(">>>>>>>>>>>> Received AL error %s (%#x), %s:%u\n", alGetString(err), err, fn, ln); + } + return err; +} +#define getALError() checkALError(__FILE__, __LINE__) + +static ALCenum checkALCError(ALCdevice *device, const char *fn, unsigned int ln) +{ + ALCenum err = alcGetError(device); + if(err != ALC_NO_ERROR) + { + if(strchr(fn, '/')) + fn = strrchr(fn, '/')+1; + else if(strchr(fn, '\\')) + fn = strrchr(fn, '\\')+1; + Printf(">>>>>>>>>>>> Received ALC error %s (%#x), %s:%u\n", alcGetString(device, err), err, fn, ln); + } + return err; +} +#define getALCError(d) checkALCError((d), __FILE__, __LINE__) + +static ALsizei GetBufferLength(ALuint buffer, const char *fn, unsigned int ln) +{ + ALint bits, channels, size; + alGetBufferi(buffer, AL_BITS, &bits); + alGetBufferi(buffer, AL_CHANNELS, &channels); + alGetBufferi(buffer, AL_SIZE, &size); + if(checkALError(fn, ln) == AL_NO_ERROR) + return (ALsizei)(size / (channels * bits / 8)); + return 0; +} +#define getBufferLength(b) GetBufferLength((b), __FILE__, __LINE__) + +extern ReverbContainer *ForcedEnvironment; + +#define PITCH_MULT (0.7937005f) /* Approx. 4 semitones lower; what Nash suggested */ + +#define PITCH(pitch) (snd_pitched ? (pitch)/128.f : 1.f) + + +static float GetRolloff(const FRolloffInfo *rolloff, float distance) +{ + if(distance <= rolloff->MinDistance) + return 1.f; + // Logarithmic rolloff has no max distance where it goes silent. + if(rolloff->RolloffType == ROLLOFF_Log) + return rolloff->MinDistance / + (rolloff->MinDistance + rolloff->RolloffFactor*(distance-rolloff->MinDistance)); + if(distance >= rolloff->MaxDistance) + return 0.f; + + float volume = (rolloff->MaxDistance - distance) / (rolloff->MaxDistance - rolloff->MinDistance); + if(rolloff->RolloffType == ROLLOFF_Linear) + return volume; + + if(rolloff->RolloffType == ROLLOFF_Custom && S_SoundCurve != NULL) + return S_SoundCurve[int(S_SoundCurveSize * (1.f - volume))] / 127.f; + return (powf(10.f, volume) - 1.f) / 9.f; +} + + +/*** GStreamer start ***/ +#include +#include +#include +#include +#include + +/* Bad GStreamer, using enums for bit fields... (GStreamerMM probably fixes this) */ +static GstMessageType operator|(const GstMessageType &a, const GstMessageType &b) +{ return GstMessageType((unsigned)a|(unsigned)b); } +static GstSeekFlags operator|(const GstSeekFlags &a, const GstSeekFlags &b) +{ return GstSeekFlags((unsigned)a|(unsigned)b); } + +static void PrintErrMsg(const char *str, GstMessage *msg) +{ + GError *error; + gchar *debug; + + gst_message_parse_error(msg, &error, &debug); + Printf("%s: %s\n", str, error->message); + DPrintf("%s\n", debug); + + g_error_free(error); + g_free(debug); +} + +static GstCaps *SupportedBufferFormatCaps(int forcebits=0) +{ + GstStructure *structure; + GstCaps *caps; + + caps = gst_caps_new_empty(); + if(alIsExtensionPresent("AL_EXT_MCFORMATS")) + { + static const struct { + gint count; + GstAudioChannelPosition pos[8]; + } chans[] = { + { 1, + { GST_AUDIO_CHANNEL_POSITION_FRONT_MONO } }, + { 2, + { GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, + GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT } }, + { 4, + { GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, + GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, + GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, + GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT } }, + { 6, + { GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, + GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, + GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, + GST_AUDIO_CHANNEL_POSITION_LFE, + GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, + GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT } }, + { 7, + { GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, + GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, + GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, + GST_AUDIO_CHANNEL_POSITION_LFE, + GST_AUDIO_CHANNEL_POSITION_REAR_CENTER, + GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT, + GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT } }, + { 8, + { GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, + GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, + GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, + GST_AUDIO_CHANNEL_POSITION_LFE, + GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, + GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, + GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT, + GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT } }, + }; + static const char *fmt32[] = { + "AL_FORMAT_MONO_FLOAT32", "AL_FORMAT_STEREO_FLOAT32", "AL_FORMAT_QUAD32", + "AL_FORMAT_51CHN32", "AL_FORMAT_61CHN32", "AL_FORMAT_71CHN32", NULL + }; + static const char *fmt16[] = { + "AL_FORMAT_MONO16", "AL_FORMAT_STEREO16", "AL_FORMAT_QUAD16", + "AL_FORMAT_51CHN16", "AL_FORMAT_61CHN16", "AL_FORMAT_71CHN16", NULL + }; + static const char *fmt8[] = { + "AL_FORMAT_MONO8", "AL_FORMAT_STEREO8", "AL_FORMAT_QUAD8", + "AL_FORMAT_51CHN8", "AL_FORMAT_61CHN8", "AL_FORMAT_71CHN8", NULL + }; + + if(alIsExtensionPresent("AL_EXT_FLOAT32")) + { + for(size_t i = 0;fmt32[i];i++) + { + if(forcebits && forcebits != 32) + break; + + ALenum val = alGetEnumValue(fmt32[i]); + if(getALError() != AL_NO_ERROR || val == 0 || val == -1) + continue; + + structure = gst_structure_new("audio/x-raw-float", + "endianness", G_TYPE_INT, G_BYTE_ORDER, + "width", G_TYPE_INT, 32, NULL); + gst_structure_set(structure, "channels", G_TYPE_INT, + chans[i].count, NULL); + if(chans[i].count > 2) + gst_audio_set_channel_positions(structure, chans[i].pos); + gst_caps_append_structure(caps, structure); + } + } + for(size_t i = 0;fmt16[i];i++) + { + if(forcebits && forcebits != 16) + break; + + ALenum val = alGetEnumValue(fmt16[i]); + if(getALError() != AL_NO_ERROR || val == 0 || val == -1) + continue; + + structure = gst_structure_new("audio/x-raw-int", + "endianness", G_TYPE_INT, G_BYTE_ORDER, + "width", G_TYPE_INT, 16, + "depth", G_TYPE_INT, 16, + "signed", G_TYPE_BOOLEAN, TRUE, NULL); + gst_structure_set(structure, "channels", G_TYPE_INT, + chans[i].count, NULL); + if(chans[i].count > 2) + gst_audio_set_channel_positions(structure, chans[i].pos); + gst_caps_append_structure(caps, structure); + } + for(size_t i = 0;fmt8[i];i++) + { + if(forcebits && forcebits != 8) + break; + + ALenum val = alGetEnumValue(fmt8[i]); + if(getALError() != AL_NO_ERROR || val == 0 || val == -1) + continue; + + structure = gst_structure_new("audio/x-raw-int", + "width", G_TYPE_INT, 8, + "depth", G_TYPE_INT, 8, + "signed", G_TYPE_BOOLEAN, FALSE, NULL); + gst_structure_set(structure, "channels", G_TYPE_INT, + chans[i].count, NULL); + if(chans[i].count > 2) + gst_audio_set_channel_positions(structure, chans[i].pos); + gst_caps_append_structure(caps, structure); + } + } + else + { + if(alIsExtensionPresent("AL_EXT_FLOAT32") && + (!forcebits || forcebits == 32)) + { + structure = gst_structure_new("audio/x-raw-float", + "endianness", G_TYPE_INT, G_BYTE_ORDER, + "width", G_TYPE_INT, 32, + "channels", GST_TYPE_INT_RANGE, 1, 2, NULL); + gst_caps_append_structure(caps, structure); + } + if(!forcebits || forcebits == 16) + { + structure = gst_structure_new("audio/x-raw-int", + "endianness", G_TYPE_INT, G_BYTE_ORDER, + "width", G_TYPE_INT, 16, + "depth", G_TYPE_INT, 16, + "signed", G_TYPE_BOOLEAN, TRUE, + "channels", GST_TYPE_INT_RANGE, 1, 2, NULL); + gst_caps_append_structure(caps, structure); + } + if(!forcebits || forcebits == 8) + { + structure = gst_structure_new("audio/x-raw-int", + "width", G_TYPE_INT, 8, + "depth", G_TYPE_INT, 8, + "signed", G_TYPE_BOOLEAN, FALSE, + "channels", GST_TYPE_INT_RANGE, 1, 2, NULL); + gst_caps_append_structure(caps, structure); + } + } + return caps; +} + +static ALenum FormatFromDesc(int bits, int channels) +{ + if(bits == 8) + { + if(channels == 1) return AL_FORMAT_MONO8; + if(channels == 2) return AL_FORMAT_STEREO8; + if(channels == 4) return AL_FORMAT_QUAD8; + if(channels == 6) return AL_FORMAT_51CHN8; + if(channels == 7) return AL_FORMAT_61CHN8; + if(channels == 8) return AL_FORMAT_71CHN8; + } + if(bits == 16) + { + if(channels == 1) return AL_FORMAT_MONO16; + if(channels == 2) return AL_FORMAT_STEREO16; + if(channels == 4) return AL_FORMAT_QUAD16; + if(channels == 6) return AL_FORMAT_51CHN16; + if(channels == 7) return AL_FORMAT_61CHN16; + if(channels == 8) return AL_FORMAT_71CHN16; + } + if(bits == 32) + { + if(channels == 1) return AL_FORMAT_MONO_FLOAT32; + if(channels == 2) return AL_FORMAT_STEREO_FLOAT32; + if(channels == 4) return AL_FORMAT_QUAD32; + if(channels == 6) return AL_FORMAT_51CHN32; + if(channels == 7) return AL_FORMAT_61CHN32; + if(channels == 8) return AL_FORMAT_71CHN32; + } + return AL_NONE; +} + +class OpenALSoundStream : public SoundStream +{ + OpenALSoundRenderer *Renderer; + GstElement *gstPipeline; + GstTagList *TagList; + gint64 LoopPts[2]; + ALuint Source; + + bool Playing; + bool Looping; + + // Custom OpenAL sink; this is pretty crappy compared to the real + // openalsink element, but it gets the job done + static const ALsizei MaxSamplesQueued = 32768; + std::vector Buffers; + ALsizei SamplesQueued; + ALsizei SampleRate; + ALenum Format; + + static void sink_eos(GstAppSink *sink, gpointer user_data) + { + OpenALSoundStream *self = static_cast(user_data); + + if(!self->Playing) + return; + + ALint state; + do { + g_usleep(10000); + alGetSourcei(self->Source, AL_SOURCE_STATE, &state); + } while(getALError() == AL_NO_ERROR && state == AL_PLAYING); + + alSourceRewind(self->Source); + getALError(); + } + + static GstFlowReturn sink_preroll(GstAppSink *sink, gpointer user_data) + { + OpenALSoundStream *self = static_cast(user_data); + + // get the buffer from appsink + GstBuffer *buffer = gst_app_sink_pull_preroll(sink); + if(!buffer) return GST_FLOW_ERROR; + + GstCaps *caps = GST_BUFFER_CAPS(buffer); + gint bits = 0, channels = 0, rate = 0, i; + for(i = gst_caps_get_size(caps)-1;i >= 0;i--) + { + GstStructure *struc = gst_caps_get_structure(caps, i); + if(gst_structure_has_field(struc, "width")) + gst_structure_get_int(struc, "width", &bits); + if(gst_structure_has_field(struc, "channels")) + gst_structure_get_int(struc, "channels", &channels); + if(gst_structure_has_field(struc, "rate")) + gst_structure_get_int(struc, "rate", &rate); + } + + self->SampleRate = rate; + self->Format = FormatFromDesc(bits, channels); + + gst_buffer_unref(buffer); + if(self->Format == AL_NONE || self->SampleRate <= 0) + return GST_FLOW_ERROR; + return GST_FLOW_OK; + } + + static GstFlowReturn sink_buffer(GstAppSink *sink, gpointer user_data) + { + OpenALSoundStream *self = static_cast(user_data); + + GstBuffer *buffer = gst_app_sink_pull_buffer(sink); + if(!buffer) return GST_FLOW_ERROR; + + if(GST_BUFFER_SIZE(buffer) == 0) + { + gst_buffer_unref(buffer); + return GST_FLOW_OK; + } + + ALint processed, state; + next_buffer: + do { + alGetSourcei(self->Source, AL_SOURCE_STATE, &state); + alGetSourcei(self->Source, AL_BUFFERS_PROCESSED, &processed); + if(getALError() != AL_NO_ERROR) + { + gst_buffer_unref(buffer); + return GST_FLOW_ERROR; + } + if(processed > 0 || self->SamplesQueued < MaxSamplesQueued || + state != AL_PLAYING) + break; + + g_usleep(10000); + } while(1); + + if(!self->Playing) + { + gst_buffer_unref(buffer); + return GST_FLOW_OK; + } + + ALuint bufID; + if(processed == 0) + { + alGenBuffers(1, &bufID); + if(getALError() != AL_NO_ERROR) + { + gst_buffer_unref(buffer); + return GST_FLOW_ERROR; + } + self->Buffers.push_back(bufID); + } + else while(1) + { + alSourceUnqueueBuffers(self->Source, 1, &bufID); + if(getALError() != AL_NO_ERROR) + { + gst_buffer_unref(buffer); + return GST_FLOW_ERROR; + } + + self->SamplesQueued -= getBufferLength(bufID); + processed--; + if(self->SamplesQueued < MaxSamplesQueued) + break; + if(processed == 0) + goto next_buffer; + self->Buffers.erase(find(self->Buffers.begin(), self->Buffers.end(), bufID)); + alDeleteBuffers(1, &bufID); + } + + alBufferData(bufID, self->Format, GST_BUFFER_DATA(buffer), + GST_BUFFER_SIZE(buffer), self->SampleRate); + alSourceQueueBuffers(self->Source, 1, &bufID); + gst_buffer_unref(buffer); + + if(getALError() != AL_NO_ERROR) + return GST_FLOW_ERROR; + + self->SamplesQueued += getBufferLength(bufID); + if(state != AL_PLAYING && processed == 0) + { + alSourcePlay(self->Source); + if(getALError() != AL_NO_ERROR) + return GST_FLOW_ERROR; + } + return GST_FLOW_OK; + } + + // Memory-based data source + std::vector MemData; + size_t MemDataPos; + + static void need_memdata(GstAppSrc *appsrc, guint size, gpointer user_data) + { + OpenALSoundStream *self = static_cast(user_data); + + if(self->MemDataPos >= self->MemData.size()) + { + gst_app_src_end_of_stream(appsrc); + return; + } + + // "read" the data it wants, up to the remaining amount + guint8 *data = &self->MemData[self->MemDataPos]; + size = (std::min)(size, (guint)(self->MemData.size() - self->MemDataPos)); + self->MemDataPos += size; + + GstBuffer *buffer = gst_buffer_new(); + GST_BUFFER_DATA(buffer) = data; + GST_BUFFER_SIZE(buffer) = size; + + // this takes ownership of the buffer; don't unref + gst_app_src_push_buffer(appsrc, buffer); + } + + static gboolean seek_memdata(GstAppSrc *appsrc, guint64 position, gpointer user_data) + { + OpenALSoundStream *self = static_cast(user_data); + + if(position > self->MemData.size()) + return FALSE; + self->MemDataPos = position; + return TRUE; + } + + static void memdata_source(GObject *object, GObject *orig, GParamSpec *pspec, OpenALSoundStream *self) + { + GstElement *elem; + g_object_get(self->gstPipeline, "source", &elem, NULL); + + GstAppSrc *appsrc = GST_APP_SRC(elem); + GstAppSrcCallbacks callbacks = { + need_memdata, NULL, seek_memdata + }; + gst_app_src_set_callbacks(appsrc, &callbacks, self, NULL); + gst_app_src_set_size(appsrc, self->MemData.size()); + gst_app_src_set_stream_type(appsrc, GST_APP_STREAM_TYPE_RANDOM_ACCESS); + + gst_object_unref(appsrc); + } + + // Callback-based data source + SoundStreamCallback Callback; + void *UserData; + int BufferBytes; + GstCaps *SrcCaps; + + static void need_callback(GstAppSrc *appsrc, guint size, gpointer user_data) + { + OpenALSoundStream *self = static_cast(user_data); + + GstBuffer *buffer; + if(!self->Playing) + buffer = gst_buffer_new_and_alloc(0); + else + { + buffer = gst_buffer_new_and_alloc(size); + if(!self->Callback(self, GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer), self->UserData)) + { + gst_buffer_unref(buffer); + + gst_app_src_end_of_stream(appsrc); + return; + } + } + + gst_app_src_push_buffer(appsrc, buffer); + } + + static void callback_source(GObject *object, GObject *orig, GParamSpec *pspec, OpenALSoundStream *self) + { + GstElement *elem; + g_object_get(self->gstPipeline, "source", &elem, NULL); + + GstAppSrc *appsrc = GST_APP_SRC(elem); + GstAppSrcCallbacks callbacks = { + need_callback, NULL, NULL + }; + gst_app_src_set_callbacks(appsrc, &callbacks, self, NULL); + gst_app_src_set_size(appsrc, -1); + gst_app_src_set_max_bytes(appsrc, self->BufferBytes); + gst_app_src_set_stream_type(appsrc, GST_APP_STREAM_TYPE_STREAM); + gst_app_src_set_caps(appsrc, self->SrcCaps); + + gst_object_unref(appsrc); + } + + // General methods + virtual bool SetupSource() + { + // We don't actually use this source if we have an openalsink. However, + // holding on to it helps ensure we don't overrun our allotted voice + // count. + if(Renderer->FreeSfx.size() == 0) + { + FSoundChan *lowest = Renderer->FindLowestChannel(); + if(lowest) Renderer->StopChannel(lowest); + + if(Renderer->FreeSfx.size() == 0) + return false; + } + Source = Renderer->FreeSfx.back(); + Renderer->FreeSfx.pop_back(); + + alSource3f(Source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); + alSource3f(Source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); + alSource3f(Source, AL_POSITION, 0.0f, 0.0f, 0.0f); + alSourcef(Source, AL_MAX_GAIN, 1.0f); + alSourcef(Source, AL_GAIN, 1.0f); + alSourcef(Source, AL_PITCH, 1.0f); + alSourcef(Source, AL_ROLLOFF_FACTOR, 0.0f); + alSourcef(Source, AL_SEC_OFFSET, 0.0f); + alSourcei(Source, AL_SOURCE_RELATIVE, AL_TRUE); + alSourcei(Source, AL_LOOPING, AL_FALSE); + if(Renderer->EnvSlot) + { + alSourcef(Source, AL_ROOM_ROLLOFF_FACTOR, 0.0f); + alSourcef(Source, AL_AIR_ABSORPTION_FACTOR, 0.0f); + alSourcei(Source, AL_DIRECT_FILTER, AL_FILTER_NULL); + alSource3i(Source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL); + } + + return (getALError() == AL_NO_ERROR); + } + + bool PipelineSetup() + { + TagList = gst_tag_list_new(); + g_return_val_if_fail(TagList != NULL, false); + + // Flags (can be combined): + // 0x01: video - Render the video stream + // 0x02: audio - Render the audio stream + // 0x04: text - Render subtitles + // 0x08: vis - Render visualisation when no video is present + // 0x10: soft-volume - Use software volume + // 0x20: native-audio - Only use native audio formats + // 0x40: native-video - Only use native video formats + // 0x80: download - Attempt progressive download buffering + int flags = 0x02 | 0x10; + + gstPipeline = gst_element_factory_make("playbin2", NULL); + g_return_val_if_fail(gstPipeline != NULL, false); + + GstElement *sink = gst_element_factory_make("openalsink", NULL); + if(sink != NULL) + { + // Give the sink our device, so it can create its own context and + // source to play with (and not risk cross-contaminating errors) + g_object_set(sink, "device-handle", Renderer->Device, NULL); + } + else + { + static bool warned = false; + if(!warned) + g_warning("Could not create an openalsink\n"); + warned = true; + + sink = gst_element_factory_make("appsink", NULL); + g_return_val_if_fail(sink != NULL, false); + + GstAppSink *appsink = GST_APP_SINK(sink); + GstAppSinkCallbacks callbacks = { + sink_eos, sink_preroll, sink_buffer, NULL + }; + GstCaps *caps = SupportedBufferFormatCaps(); + + gst_app_sink_set_callbacks(appsink, &callbacks, this, NULL); + gst_app_sink_set_drop(appsink, FALSE); + gst_app_sink_set_caps(appsink, caps); + gst_caps_unref(caps); + } + + // This takes ownership of the element; don't unref it + g_object_set(gstPipeline, "audio-sink", sink, NULL); + g_object_set(gstPipeline, "flags", flags, NULL); + return true; + } + + void HandleLoopTags() + { + // FIXME: Sample offsets assume a 44.1khz rate. Need to find some way + // to get the actual rate of the file from GStreamer + bool looppt_is_samples; + unsigned int looppt; + gchar *valstr; + + LoopPts[0] = 0; + if(gst_tag_list_get_string(TagList, "LOOP_START", &valstr)) + { + g_print("Got LOOP_START string: %s\n", valstr); + if(!S_ParseTimeTag(valstr, &looppt_is_samples, &looppt)) + Printf("Invalid LOOP_START tag: '%s'\n", valstr); + else + LoopPts[0] = (looppt_is_samples ? ((gint64)looppt*1000000000/44100) : + ((gint64)looppt*1000000)); + g_free(valstr); + } + LoopPts[1] = -1; + if(gst_tag_list_get_string(TagList, "LOOP_END", &valstr)) + { + g_print("Got LOOP_END string: %s\n", valstr); + if(!S_ParseTimeTag(valstr, &looppt_is_samples, &looppt)) + Printf("Invalid LOOP_END tag: '%s'\n", valstr); + else + { + LoopPts[1] = (looppt_is_samples ? ((gint64)looppt*1000000000/44100) : + ((gint64)looppt*1000000)); + if(LoopPts[1] <= LoopPts[0]) + LoopPts[1] = -1; + } + g_free(valstr); + } + } + + bool PreparePipeline() + { + GstBus *bus = gst_element_get_bus(gstPipeline); + if(!bus) return false; + + GstStateChangeReturn ret = gst_element_set_state(gstPipeline, GST_STATE_PAUSED); + if(ret == GST_STATE_CHANGE_ASYNC) + { + const GstMessageType types = GST_MESSAGE_ERROR | GST_MESSAGE_TAG | GST_MESSAGE_ASYNC_DONE; + GstMessage *msg; + while((msg=gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, types)) != NULL) + { + if(GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) + { + PrintErrMsg("Play Error", msg); + ret = GST_STATE_CHANGE_FAILURE; + break; + } + else if(GST_MESSAGE_TYPE(msg) == GST_MESSAGE_TAG) + { + GstTagList *tags = NULL; + gst_message_parse_tag(msg, &tags); + + gst_tag_list_insert(TagList, tags, GST_TAG_MERGE_KEEP); + + gst_tag_list_free(tags); + } + else break; + gst_message_unref(msg); + } + } + else if(ret == GST_STATE_CHANGE_SUCCESS) + { + GstMessage *msg; + while((msg=gst_bus_pop(bus)) != NULL) + { + if(GST_MESSAGE_TYPE(msg) == GST_MESSAGE_TAG) + { + GstTagList *tags = NULL; + gst_message_parse_tag(msg, &tags); + + gst_tag_list_insert(TagList, tags, GST_TAG_MERGE_KEEP); + + gst_tag_list_free(tags); + } + gst_message_unref(msg); + } + } + HandleLoopTags(); + + gst_object_unref(bus); + bus = NULL; + + return (ret != GST_STATE_CHANGE_FAILURE); + } + +public: + FTempFileName tmpfile; + ALfloat Volume; + + OpenALSoundStream(OpenALSoundRenderer *renderer) + : Renderer(renderer), gstPipeline(NULL), TagList(NULL), Source(0), + Playing(false), Looping(false), SamplesQueued(0), Callback(NULL), + UserData(NULL), BufferBytes(0), SrcCaps(NULL), Volume(1.0f) + { + LoopPts[0] = LoopPts[1] = 0; + Renderer->Streams.push_back(this); + } + + virtual ~OpenALSoundStream() + { + Playing = false; + + if(SrcCaps) + gst_caps_unref(SrcCaps); + SrcCaps = NULL; + + if(gstPipeline) + { + gst_element_set_state(gstPipeline, GST_STATE_NULL); + gst_object_unref(gstPipeline); + gstPipeline = NULL; + } + + if(TagList) + gst_tag_list_free(TagList); + TagList = NULL; + + if(Source) + { + alSourceRewind(Source); + alSourcei(Source, AL_BUFFER, 0); + + Renderer->FreeSfx.push_back(Source); + Source = 0; + } + + if(Buffers.size() > 0) + { + alDeleteBuffers(Buffers.size(), &Buffers[0]); + Buffers.clear(); + } + getALError(); + + Renderer->Streams.erase(find(Renderer->Streams.begin(), + Renderer->Streams.end(), this)); + Renderer = NULL; + } + + virtual bool Play(bool looping, float vol) + { + if(Playing) + return true; + + GstBus *bus = gst_element_get_bus(gstPipeline); + if(!bus) return false; + + Looping = looping; + SetVolume(vol); + + if(Looping) + { + const GstSeekFlags flags = GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SEGMENT; + gst_element_seek(gstPipeline, 1.0, GST_FORMAT_TIME, flags, + GST_SEEK_TYPE_NONE, 0, GST_SEEK_TYPE_SET, LoopPts[1]); + } + + // Start playing the stream + Playing = true; + GstStateChangeReturn ret = gst_element_set_state(gstPipeline, GST_STATE_PLAYING); + if(ret == GST_STATE_CHANGE_FAILURE) + Playing = false; + if(ret == GST_STATE_CHANGE_ASYNC) + { + const GstMessageType types = GST_MESSAGE_ERROR | GST_MESSAGE_ASYNC_DONE; + GstMessage *msg; + if((msg=gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, types)) != NULL) + { + if(GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) + { + PrintErrMsg("Play Error", msg); + Playing = false; + } + gst_message_unref(msg); + } + } + + gst_object_unref(bus); + bus = NULL; + + return Playing; + } + + virtual void Stop() + { + GstBus *bus = gst_element_get_bus(gstPipeline); + if(!bus) return; + + // Stop the stream + GstStateChangeReturn ret = gst_element_set_state(gstPipeline, GST_STATE_PAUSED); + if(ret == GST_STATE_CHANGE_ASYNC) + { + Playing = false; + // Wait for the state change before requesting a seek + const GstMessageType types = GST_MESSAGE_ERROR | GST_MESSAGE_ASYNC_DONE; + GstMessage *msg; + if((msg=gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, types)) != NULL) + { + if(GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) + PrintErrMsg("Stop Error", msg); + else if(GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ASYNC_DONE) + ret = GST_STATE_CHANGE_SUCCESS; + gst_message_unref(msg); + } + } + if(ret == GST_STATE_CHANGE_SUCCESS) + { + Playing = false; + + alSourceRewind(Source); + getALError(); + + const GstSeekFlags flags = GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT; + gst_element_seek_simple(gstPipeline, GST_FORMAT_TIME, flags, 0); + } + + gst_object_unref(bus); + bus = NULL; + } + + virtual bool SetPaused(bool paused) + { + GstBus *bus = gst_element_get_bus(gstPipeline); + if(!bus) return false; + + GstStateChangeReturn ret; + ret = gst_element_set_state(gstPipeline, (paused ? GST_STATE_PAUSED : GST_STATE_PLAYING)); + if(ret == GST_STATE_CHANGE_ASYNC) + { + const GstMessageType types = GST_MESSAGE_ERROR | GST_MESSAGE_ASYNC_DONE; + GstMessage *msg; + if((msg=gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, types)) != NULL) + { + if(GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) + { + PrintErrMsg("Pause Error", msg); + ret = GST_STATE_CHANGE_FAILURE; + } + gst_message_unref(msg); + } + } + + if(ret != GST_STATE_CHANGE_FAILURE && paused) + { + alSourcePause(Source); + getALError(); + } + + gst_object_unref(bus); + bus = NULL; + + return (ret != GST_STATE_CHANGE_FAILURE); + } + + virtual void SetVolume(float vol) + { + Volume = vol; + g_object_set(gstPipeline, "volume", (double)(Volume*Renderer->MusicVolume), NULL); + } + + virtual unsigned int GetPosition() + { + GstFormat format = GST_FORMAT_TIME; + gint64 pos; + + // Position will be handled in milliseconds; GStreamer's time format is in nanoseconds + if(gst_element_query_position(gstPipeline, &format, &pos) && format == GST_FORMAT_TIME) + return (unsigned int)(pos / 1000000); + return 0; + } + + virtual bool SetPosition(unsigned int val) + { + gint64 pos = (gint64)val * 1000000; + return gst_element_seek_simple(gstPipeline, GST_FORMAT_TIME, GST_SEEK_FLAG_ACCURATE, pos); + } + + virtual bool IsEnded() + { + GstBus *bus = gst_element_get_bus(gstPipeline); + if(!bus) return true; + + GstMessage *msg; + while((msg=gst_bus_pop(bus)) != NULL) + { + switch(GST_MESSAGE_TYPE(msg)) + { + case GST_MESSAGE_SEGMENT_DONE: + case GST_MESSAGE_EOS: + Playing = false; + if(Looping) + Playing = gst_element_seek(gstPipeline, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | + GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_SEGMENT, + GST_SEEK_TYPE_SET, LoopPts[0], + GST_SEEK_TYPE_SET, LoopPts[1]); + break; + + case GST_MESSAGE_ERROR: + PrintErrMsg("Pipeline Error", msg); + Playing = false; + break; + + case GST_MESSAGE_WARNING: + PrintErrMsg("Pipeline Warning", msg); + break; + + default: + break; + } + + gst_message_unref(msg); + } + + gst_object_unref(bus); + bus = NULL; + + return !Playing; + } + + bool Init(const char *filename) + { + if(!SetupSource() || !PipelineSetup()) + return false; + + GError *err = NULL; + gchar *uri; + if(g_path_is_absolute(filename)) + uri = g_filename_to_uri(filename, NULL, &err); + else if(g_strrstr(filename, "://") != NULL) + uri = g_strdup(filename); + else + { + gchar *curdir = g_get_current_dir(); + gchar *absolute_path = g_strconcat(curdir, G_DIR_SEPARATOR_S, filename, NULL); + uri = g_filename_to_uri(absolute_path, NULL, &err); + g_free(absolute_path); + g_free(curdir); + } + + if(!uri) + { + if(err) + { + Printf("Failed to convert "TEXTCOLOR_BOLD"%s"TEXTCOLOR_NORMAL" to URI: %s\n", filename, err->message); + g_error_free(err); + } + return false; + } + + g_object_set(gstPipeline, "uri", uri, NULL); + g_free(uri); + + return PreparePipeline(); + } + + bool Init(const BYTE *data, unsigned int datalen) + { + // Can't keep the original pointer since the memory can apparently be + // overwritten at some point (happens with MIDI data, at least) + MemData.resize(datalen); + memcpy(&MemData[0], data, datalen); + MemDataPos = 0; + + if(!SetupSource() || !PipelineSetup()) + return false; + + g_object_set(gstPipeline, "uri", "appsrc://", NULL); + g_signal_connect(gstPipeline, "deep-notify::source", G_CALLBACK(memdata_source), this); + + return PreparePipeline(); + } + + bool Init(SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata) + { + Callback = callback; + UserData = userdata; + BufferBytes = buffbytes; + + GstStructure *structure; + if((flags&Float)) + structure = gst_structure_new("audio/x-raw-float", + "endianness", G_TYPE_INT, G_BYTE_ORDER, + "width", G_TYPE_INT, 32, NULL); + else if((flags&Bits32)) + structure = gst_structure_new("audio/x-raw-int", + "endianness", G_TYPE_INT, G_BYTE_ORDER, + "width", G_TYPE_INT, 32, + "depth", G_TYPE_INT, 32, + "signed", G_TYPE_BOOLEAN, TRUE, NULL); + else if((flags&Bits8)) + structure = gst_structure_new("audio/x-raw-int", + "width", G_TYPE_INT, 8, + "depth", G_TYPE_INT, 8, + "signed", G_TYPE_BOOLEAN, TRUE, NULL); + else + structure = gst_structure_new("audio/x-raw-int", + "endianness", G_TYPE_INT, G_BYTE_ORDER, + "width", G_TYPE_INT, 16, + "depth", G_TYPE_INT, 16, + "signed", G_TYPE_BOOLEAN, TRUE, NULL); + gst_structure_set(structure, "channels", G_TYPE_INT, (flags&Mono)?1:2, NULL); + gst_structure_set(structure, "rate", G_TYPE_INT, samplerate, NULL); + + SrcCaps = gst_caps_new_full(structure, NULL); + + if(!SrcCaps || !SetupSource() || !PipelineSetup()) + return false; + + g_object_set(gstPipeline, "uri", "appsrc://", NULL); + g_signal_connect(gstPipeline, "deep-notify::source", G_CALLBACK(callback_source), this); + + return PreparePipeline(); + } +}; + + +class Decoder +{ + GstElement *gstPipeline, *gstSink; + GstTagList *TagList; + + const guint8 *MemData; + size_t MemDataSize; + size_t MemDataPos; + GstCaps *SrcCaps; + + static void need_memdata(GstAppSrc *appsrc, guint size, gpointer user_data) + { + Decoder *self = static_cast(user_data); + GstFlowReturn ret; + + if(self->MemDataPos >= self->MemDataSize) + { + gst_app_src_end_of_stream(appsrc); + return; + } + + const guint8 *data = &self->MemData[self->MemDataPos]; + size = (std::min)(size, (guint)(self->MemDataSize - self->MemDataPos)); + self->MemDataPos += size; + + GstBuffer *buffer = gst_buffer_new(); + GST_BUFFER_DATA(buffer) = const_cast(data); + GST_BUFFER_SIZE(buffer) = size; + + gst_app_src_push_buffer(appsrc, buffer); + } + + static gboolean seek_memdata(GstAppSrc *appsrc, guint64 position, gpointer user_data) + { + Decoder *self = static_cast(user_data); + + if(position > self->MemDataSize) + return FALSE; + self->MemDataPos = position; + return TRUE; + } + + static void memdata_source(GObject *object, GObject *orig, GParamSpec *pspec, Decoder *self) + { + GstElement *elem; + g_object_get(self->gstPipeline, "source", &elem, NULL); + + GstAppSrc *appsrc = GST_APP_SRC(elem); + GstAppSrcCallbacks callbacks = { + need_memdata, NULL, seek_memdata + }; + gst_app_src_set_callbacks(appsrc, &callbacks, self, NULL); + gst_app_src_set_size(appsrc, self->MemDataSize); + gst_app_src_set_caps(appsrc, self->SrcCaps); + gst_app_src_set_stream_type(appsrc, GST_APP_STREAM_TYPE_RANDOM_ACCESS); + + gst_object_unref(appsrc); + } + + static GstFlowReturn sink_preroll(GstAppSink *sink, gpointer user_data) + { + Decoder *self = static_cast(user_data); + + GstBuffer *buffer = gst_app_sink_pull_preroll(sink); + if(!buffer) return GST_FLOW_ERROR; + + if(self->OutRate == 0) + { + GstCaps *caps = GST_BUFFER_CAPS(buffer); + + gint channels = 0, rate = 0, bits = 0, i; + for(i = gst_caps_get_size(caps)-1;i >= 0;i--) + { + GstStructure *struc = gst_caps_get_structure(caps, i); + if(gst_structure_has_field(struc, "channels")) + gst_structure_get_int(struc, "channels", &channels); + if(gst_structure_has_field(struc, "rate")) + gst_structure_get_int(struc, "rate", &rate); + if(gst_structure_has_field(struc, "width")) + gst_structure_get_int(struc, "width", &bits); + } + + self->OutChannels = channels; + self->OutBits = bits; + self->OutRate = rate; + } + + gst_buffer_unref(buffer); + if(self->OutRate <= 0) + return GST_FLOW_ERROR; + return GST_FLOW_OK; + } + + static GstFlowReturn sink_buffer(GstAppSink *sink, gpointer user_data) + { + Decoder *self = static_cast(user_data); + + GstBuffer *buffer = gst_app_sink_pull_buffer(sink); + if(!buffer) return GST_FLOW_ERROR; + + guint newsize = GST_BUFFER_SIZE(buffer); + size_t pos = self->OutData.size(); + self->OutData.resize(pos+newsize); + + memcpy(&self->OutData[pos], GST_BUFFER_DATA(buffer), newsize); + + gst_buffer_unref(buffer); + return GST_FLOW_OK; + } + + bool PipelineSetup(int forcebits) + { + if(forcebits && forcebits != 8 && forcebits != 16) + return false; + + TagList = gst_tag_list_new(); + g_return_val_if_fail(TagList != NULL, false); + + gstPipeline = gst_element_factory_make("playbin2", NULL); + g_return_val_if_fail(gstPipeline != NULL, false); + + gstSink = gst_element_factory_make("appsink", NULL); + g_return_val_if_fail(gstSink != NULL, false); + + GstAppSink *appsink = GST_APP_SINK(gstSink); + GstAppSinkCallbacks callbacks = { + NULL, sink_preroll, sink_buffer, NULL + }; + + GstCaps *caps = SupportedBufferFormatCaps(forcebits); + g_object_set(appsink, "sync", FALSE, NULL); + gst_app_sink_set_callbacks(appsink, &callbacks, this, NULL); + gst_app_sink_set_drop(appsink, FALSE); + gst_app_sink_set_caps(appsink, caps); + + g_object_set(gstPipeline, "audio-sink", gst_object_ref(gstSink), NULL); + g_object_set(gstPipeline, "flags", 0x02, NULL); + + gst_caps_unref(caps); + return true; + } + + void HandleLoopTags(unsigned int looppt[2], bool looppt_is_samples[2], bool has_looppt[2]) + { + gchar *valstr; + + if(gst_tag_list_get_string(TagList, "LOOP_START", &valstr)) + { + g_print("Got LOOP_START string: %s\n", valstr); + has_looppt[0] = S_ParseTimeTag(valstr, &looppt_is_samples[0], &looppt[0]); + if(!has_looppt[0]) + Printf("Invalid LOOP_START tag: '%s'\n", valstr); + g_free(valstr); + } + if(gst_tag_list_get_string(TagList, "LOOP_END", &valstr)) + { + g_print("Got LOOP_END string: %s\n", valstr); + has_looppt[1] = S_ParseTimeTag(valstr, &looppt_is_samples[1], &looppt[1]); + if(!has_looppt[1]) + Printf("Invalid LOOP_END tag: '%s'\n", valstr); + g_free(valstr); + } + } + +public: + std::vector OutData; + ALint LoopPts[2]; + ALsizei OutRate; + ALuint OutChannels; + ALuint OutBits; + + Decoder() + : gstPipeline(NULL), gstSink(NULL), TagList(NULL), SrcCaps(NULL), + OutRate(0), OutChannels(0), OutBits(0) + { LoopPts[0] = LoopPts[1] = 0; } + + virtual ~Decoder() + { + if(SrcCaps) + gst_caps_unref(SrcCaps); + SrcCaps = NULL; + + if(gstSink) + gst_object_unref(gstSink); + gstSink = NULL; + + if(gstPipeline) + { + gst_element_set_state(gstPipeline, GST_STATE_NULL); + gst_object_unref(gstPipeline); + gstPipeline = NULL; + } + + if(TagList) + gst_tag_list_free(TagList); + TagList = NULL; + } + + bool DecodeRaw(const void *data, unsigned int datalen, int rawbits, int rawchannels, int rawrate) + { + GstStructure *structure = gst_structure_new("audio/x-raw-int", + "endianness", G_TYPE_INT, G_BYTE_ORDER, + "width", G_TYPE_INT, rawbits, + "depth", G_TYPE_INT, rawbits, + "signed", G_TYPE_BOOLEAN, ((rawbits==8)?FALSE:TRUE), NULL); + gst_structure_set(structure, "channels", G_TYPE_INT, rawchannels, NULL); + gst_structure_set(structure, "rate", G_TYPE_INT, rawrate, NULL); + + SrcCaps = gst_caps_new_full(structure, NULL); + if(!SrcCaps) + return false; + return Decode(data, datalen); + } + + bool Decode(const void *data, unsigned int datalen, int forcebits=0) + { + MemData = static_cast(data); + MemDataSize = datalen; + MemDataPos = 0; + OutData.clear(); + + if(!PipelineSetup(forcebits)) + return false; + + g_object_set(gstPipeline, "uri", "appsrc://", NULL); + g_signal_connect(gstPipeline, "deep-notify::source", G_CALLBACK(memdata_source), this); + + + GstBus *bus = gst_element_get_bus(gstPipeline); + if(!bus) return false; + GstMessage *msg; + + GstStateChangeReturn ret = gst_element_set_state(gstPipeline, GST_STATE_PLAYING); + if(ret == GST_STATE_CHANGE_ASYNC) + { + const GstMessageType types = GST_MESSAGE_ERROR | GST_MESSAGE_TAG | GST_MESSAGE_ASYNC_DONE; + while((msg=gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, types)) != NULL) + { + if(GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ASYNC_DONE) + { + ret = GST_STATE_CHANGE_SUCCESS; + break; + } + else if(GST_MESSAGE_TYPE(msg) == GST_MESSAGE_TAG) + { + GstTagList *tags = NULL; + gst_message_parse_tag(msg, &tags); + + gst_tag_list_insert(TagList, tags, GST_TAG_MERGE_KEEP); + + gst_tag_list_free(tags); + } + else if(GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) + { + ret = GST_STATE_CHANGE_FAILURE; + PrintErrMsg("Decoder Error", msg); + break; + } + gst_message_unref(msg); + } + } + + bool err = true; + if(ret == GST_STATE_CHANGE_SUCCESS) + { + const GstMessageType types = GST_MESSAGE_ERROR | GST_MESSAGE_TAG | GST_MESSAGE_EOS; + while((msg=gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, types)) != NULL) + { + if(GST_MESSAGE_TYPE(msg) == GST_MESSAGE_EOS) + { + err = false; + break; + } + else if(GST_MESSAGE_TYPE(msg) == GST_MESSAGE_TAG) + { + GstTagList *tags = NULL; + gst_message_parse_tag(msg, &tags); + + gst_tag_list_insert(TagList, tags, GST_TAG_MERGE_KEEP); + + gst_tag_list_free(tags); + } + else if(GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) + { + PrintErrMsg("Decoder Error", msg); + break; + } + gst_message_unref(msg); + } + } + + if(!err) + { + ALuint FrameSize = OutChannels*OutBits/8; + if(OutData.size() >= FrameSize) + { + // HACK: Evilness abound. Seems GStreamer doesn't like (certain?) + // wave files and produces an extra sample, which can cause an + // audible click at the end. Cut it. + OutData.resize(OutData.size() - FrameSize); + } + + unsigned int looppt[2] = { 0, 0 }; + bool looppt_is_samples[2] = { true, true }; + bool has_looppt[2] = { false, false }; + HandleLoopTags(looppt, looppt_is_samples, has_looppt); + + if(has_looppt[0] || has_looppt[1]) + { + if(!has_looppt[0]) + LoopPts[0] = 0; + else if(looppt_is_samples[0]) + LoopPts[0] = (std::min)((ALint)looppt[0], + (ALint)(OutData.size() / FrameSize)); + else + LoopPts[0] = (std::min)((ALint)((gint64)looppt[0] * OutRate / 1000), + (ALint)(OutData.size() / FrameSize)); + + if(!has_looppt[1]) + LoopPts[1] = OutData.size() / FrameSize; + else if(looppt_is_samples[1]) + LoopPts[1] = (std::min)((ALint)looppt[1], + (ALint)(OutData.size() / FrameSize)); + else + LoopPts[1] = (std::min)((ALint)((gint64)looppt[1] * OutRate / 1000), + (ALint)(OutData.size() / FrameSize)); + } + } + + gst_object_unref(bus); + bus = NULL; + + return !err; + } +}; +/*** GStreamer end ***/ + +template +static void LoadALFunc(const char *name, T *x) +{ *x = reinterpret_cast(alGetProcAddress(name)); } + +OpenALSoundRenderer::OpenALSoundRenderer() + : Device(NULL), Context(NULL), SrcDistanceModel(false), SFXPaused(0), + PrevEnvironment(NULL), EnvSlot(0) +{ + EnvFilters[0] = EnvFilters[1] = 0; + + Printf("I_InitSound: Initializing OpenAL\n"); + + static bool GSTInited = false; + if(!GSTInited) + { + GError *error; + if(!gst_init_check(NULL, NULL, &error)) + { + Printf("Failed to initialize GStreamer: %s\n", error->message); + g_error_free(error); + return; + } + GSTInited = true; + } + + if((*snd_aldevice)[0] != 0) + { + Device = alcOpenDevice(*snd_aldevice); + if(!Device) + Printf(TEXTCOLOR_BLUE" Failed to open device "TEXTCOLOR_BOLD"%s"TEXTCOLOR_BLUE". Trying default.\n", *snd_aldevice); + } + + if(!Device) + { + Device = alcOpenDevice(NULL); + if(!Device) + { + Printf(TEXTCOLOR_RED" Could not open audio device\n"); + return; + } + } + + Printf(" Opened device "TEXTCOLOR_ORANGE"%s\n", alcGetString(Device, ALC_DEVICE_SPECIFIER)); + ALCint major=0, minor=0; + alcGetIntegerv(Device, ALC_MAJOR_VERSION, 1, &major); + alcGetIntegerv(Device, ALC_MINOR_VERSION, 1, &minor); + DPrintf(" ALC Version: "TEXTCOLOR_BLUE"%d.%d\n", major, minor); + DPrintf(" ALC Extensions: "TEXTCOLOR_ORANGE"%s\n", alcGetString(Device, ALC_EXTENSIONS)); + + DisconnectNotify = alcIsExtensionPresent(Device, "ALC_EXT_disconnect"); + + std::vector attribs; + if(*snd_samplerate > 0) + { + attribs.push_back(ALC_FREQUENCY); + attribs.push_back(*snd_samplerate); + } + // Make sure one source is capable of stereo output with the rest doing + // mono, without running out of voices + attribs.push_back(ALC_MONO_SOURCES); + attribs.push_back((std::max)(*snd_channels, 2) - 1); + attribs.push_back(ALC_STEREO_SOURCES); + attribs.push_back(1); + // Other attribs..? + attribs.push_back(0); + + Context = alcCreateContext(Device, &attribs[0]); + if(!Context || alcMakeContextCurrent(Context) == ALC_FALSE) + { + Printf(TEXTCOLOR_RED" Failed to setup context: %s\n", alcGetString(Device, alcGetError(Device))); + if(Context) + alcDestroyContext(Context); + Context = NULL; + alcCloseDevice(Device); + Device = NULL; + return; + } + attribs.clear(); + + DPrintf(" Vendor: "TEXTCOLOR_ORANGE"%s\n", alGetString(AL_VENDOR)); + DPrintf(" Renderer: "TEXTCOLOR_ORANGE"%s\n", alGetString(AL_RENDERER)); + DPrintf(" Version: "TEXTCOLOR_ORANGE"%s\n", alGetString(AL_VERSION)); + DPrintf(" Extensions: "TEXTCOLOR_ORANGE"%s\n", alGetString(AL_EXTENSIONS)); + + SrcDistanceModel = alIsExtensionPresent("AL_EXT_source_distance_model"); + LoopPoints = alIsExtensionPresent("AL_EXT_loop_points"); + + alDopplerFactor(0.5f); + alSpeedOfSound(343.3f * 96.0f); + alDistanceModel(AL_INVERSE_DISTANCE); + if(SrcDistanceModel) + alEnable(AL_SOURCE_DISTANCE_MODEL); + + ALenum err = getALError(); + if(err != AL_NO_ERROR) + { + alcMakeContextCurrent(NULL); + alcDestroyContext(Context); + Context = NULL; + alcCloseDevice(Device); + Device = NULL; + return; + } + + ALCint numMono=0, numStereo=0; + alcGetIntegerv(Device, ALC_MONO_SOURCES, 1, &numMono); + alcGetIntegerv(Device, ALC_STEREO_SOURCES, 1, &numStereo); + + Sources.resize((std::min)((std::max)(*snd_channels, 2), numMono+numStereo)); + for(size_t i = 0;i < Sources.size();i++) + { + alGenSources(1, &Sources[i]); + if(getALError() != AL_NO_ERROR) + { + Sources.resize(i); + break; + } + FreeSfx.push_back(Sources[i]); + } + if(Sources.size() == 0) + { + Printf(TEXTCOLOR_RED" Error: could not generate any sound sources!\n"); + alcMakeContextCurrent(NULL); + alcDestroyContext(Context); + Context = NULL; + alcCloseDevice(Device); + Device = NULL; + return; + } + DPrintf(" Allocated "TEXTCOLOR_BLUE"%u"TEXTCOLOR_NORMAL" sources\n", Sources.size()); + + LastWaterAbsorb = 0.0f; + if(*snd_efx && alcIsExtensionPresent(Device, "ALC_EXT_EFX")) + { + // EFX function pointers +#define LOAD_FUNC(x) (LoadALFunc(#x, &x)) + LOAD_FUNC(alGenEffects); + LOAD_FUNC(alDeleteEffects); + LOAD_FUNC(alIsEffect); + LOAD_FUNC(alEffecti); + LOAD_FUNC(alEffectiv); + LOAD_FUNC(alEffectf); + LOAD_FUNC(alEffectfv); + LOAD_FUNC(alGetEffecti); + LOAD_FUNC(alGetEffectiv); + LOAD_FUNC(alGetEffectf); + LOAD_FUNC(alGetEffectfv); + + LOAD_FUNC(alGenFilters); + LOAD_FUNC(alDeleteFilters); + LOAD_FUNC(alIsFilter); + LOAD_FUNC(alFilteri); + LOAD_FUNC(alFilteriv); + LOAD_FUNC(alFilterf); + LOAD_FUNC(alFilterfv); + LOAD_FUNC(alGetFilteri); + LOAD_FUNC(alGetFilteriv); + LOAD_FUNC(alGetFilterf); + LOAD_FUNC(alGetFilterfv); + + LOAD_FUNC(alGenAuxiliaryEffectSlots); + LOAD_FUNC(alDeleteAuxiliaryEffectSlots); + LOAD_FUNC(alIsAuxiliaryEffectSlot); + LOAD_FUNC(alAuxiliaryEffectSloti); + LOAD_FUNC(alAuxiliaryEffectSlotiv); + LOAD_FUNC(alAuxiliaryEffectSlotf); + LOAD_FUNC(alAuxiliaryEffectSlotfv); + LOAD_FUNC(alGetAuxiliaryEffectSloti); + LOAD_FUNC(alGetAuxiliaryEffectSlotiv); + LOAD_FUNC(alGetAuxiliaryEffectSlotf); + LOAD_FUNC(alGetAuxiliaryEffectSlotfv); +#undef LOAD_FUNC + if(getALError() == AL_NO_ERROR) + { + ALuint envReverb; + alGenEffects(1, &envReverb); + if(getALError() == AL_NO_ERROR) + { + alEffecti(envReverb, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB); + if(alGetError() == AL_NO_ERROR) + DPrintf(" EAX Reverb found\n"); + alEffecti(envReverb, AL_EFFECT_TYPE, AL_EFFECT_REVERB); + if(alGetError() == AL_NO_ERROR) + DPrintf(" Standard Reverb found\n"); + + alDeleteEffects(1, &envReverb); + getALError(); + } + + alGenAuxiliaryEffectSlots(1, &EnvSlot); + alGenFilters(2, EnvFilters); + if(getALError() == AL_NO_ERROR) + { + alFilteri(EnvFilters[0], AL_FILTER_TYPE, AL_FILTER_LOWPASS); + alFilteri(EnvFilters[1], AL_FILTER_TYPE, AL_FILTER_LOWPASS); + if(getALError() == AL_NO_ERROR) + DPrintf(" Lowpass found\n"); + else + { + alDeleteFilters(2, EnvFilters); + EnvFilters[0] = EnvFilters[1] = 0; + alDeleteAuxiliaryEffectSlots(1, &EnvSlot); + EnvSlot = 0; + getALError(); + } + } + else + { + alDeleteFilters(2, EnvFilters); + alDeleteAuxiliaryEffectSlots(1, &EnvSlot); + EnvFilters[0] = EnvFilters[1] = 0; + EnvSlot = 0; + getALError(); + } + } + } + + if(EnvSlot) + Printf(" EFX enabled\n"); + + snd_sfxvolume.Callback(); +} + +OpenALSoundRenderer::~OpenALSoundRenderer() +{ + if(!Device) + return; + + while(Streams.size() > 0) + delete Streams[0]; + + alDeleteSources(Sources.size(), &Sources[0]); + Sources.clear(); + FreeSfx.clear(); + SfxGroup.clear(); + PausableSfx.clear(); + ReverbSfx.clear(); + + for(EffectMap::iterator i = EnvEffects.begin();i != EnvEffects.end();i++) + { + if(i->second) + alDeleteEffects(1, &(i->second)); + } + EnvEffects.clear(); + + if(EnvSlot) + { + alDeleteAuxiliaryEffectSlots(1, &EnvSlot); + alDeleteFilters(2, EnvFilters); + } + EnvSlot = 0; + EnvFilters[0] = EnvFilters[1] = 0; + + alcMakeContextCurrent(NULL); + alcDestroyContext(Context); + Context = NULL; + alcCloseDevice(Device); + Device = NULL; +} + +void OpenALSoundRenderer::SetSfxVolume(float volume) +{ + SfxVolume = volume; + + FSoundChan *schan = Channels; + while(schan) + { + if(schan->SysChannel != NULL) + { + ALuint source = *((ALuint*)schan->SysChannel); + volume = SfxVolume; + + alcSuspendContext(Context); + alSourcef(source, AL_MAX_GAIN, volume); + if(schan->ManualGain) + volume *= GetRolloff(&schan->Rolloff, sqrt(schan->DistanceSqr)); + alSourcef(source, AL_GAIN, volume); + } + schan = schan->NextChan; + } + + getALError(); +} + +void OpenALSoundRenderer::SetMusicVolume(float volume) +{ + MusicVolume = volume; + foreach(OpenALSoundStream*, i, Streams) + (*i)->SetVolume((*i)->Volume); +} + +unsigned int OpenALSoundRenderer::GetMSLength(SoundHandle sfx) +{ + if(sfx.data) + { + ALuint buffer = *((ALuint*)sfx.data); + if(alIsBuffer(buffer)) + { + ALint bits, channels, freq, size; + alGetBufferi(buffer, AL_BITS, &bits); + alGetBufferi(buffer, AL_CHANNELS, &channels); + alGetBufferi(buffer, AL_FREQUENCY, &freq); + alGetBufferi(buffer, AL_SIZE, &size); + if(getALError() == AL_NO_ERROR) + return (unsigned int)(size / (channels*bits/8) * 1000.0 / freq); + } + } + return 0; +} + +unsigned int OpenALSoundRenderer::GetSampleLength(SoundHandle sfx) +{ + if(sfx.data) + return getBufferLength(*((ALuint*)sfx.data)); + return 0; +} + +float OpenALSoundRenderer::GetOutputRate() +{ + ALCint rate = *snd_samplerate; // Default, just in case + alcGetIntegerv(Device, ALC_FREQUENCY, 1, &rate); + return (float)rate; +} + + +SoundHandle OpenALSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int length, int frequency, int channels, int bits, int loopstart) +{ + SoundHandle retval = { NULL }; + + if(length == 0) return retval; + + if(bits == -8) + { + // Simple signed->unsigned conversion + for(int i = 0;i < length;i++) + sfxdata[i] ^= 0x80; + bits = -bits; + } + + ALenum format = AL_NONE; + if(bits == 16) + { + if(channels == 1) format = AL_FORMAT_MONO16; + if(channels == 2) format = AL_FORMAT_STEREO16; + } + else if(bits == 8) + { + if(channels == 1) format = AL_FORMAT_MONO8; + if(channels == 2) format = AL_FORMAT_STEREO8; + } + + Decoder decoder; + if(format == AL_NONE && decoder.DecodeRaw(sfxdata, length, bits, channels, frequency)) + { + sfxdata = &decoder.OutData[0]; + length = decoder.OutData.size(); + frequency = decoder.OutRate; + bits = decoder.OutBits; + channels = decoder.OutChannels; + format = FormatFromDesc(bits, channels); + } + if(format == AL_NONE || frequency <= 0) + { + Printf("Unhandled format: %d bit, %d channel, %d hz\n", bits, channels, frequency); + return retval; + } + length -= length%(channels*bits/8); + + ALenum err; + ALuint buffer = 0; + alGenBuffers(1, &buffer); + alBufferData(buffer, format, sfxdata, length, frequency); + if((err=getALError()) != AL_NO_ERROR) + { + Printf("Failed to buffer data: %s\n", alGetString(err)); + alDeleteBuffers(1, &buffer); + getALError(); + return retval; + } + + if(loopstart > 0 && LoopPoints) + { + ALint loops[2] = { + loopstart, + length / (channels*bits/8) + }; + Printf("Setting loop points %d -> %d\n", loops[0], loops[1]); + alBufferiv(buffer, AL_LOOP_POINTS, loops); + getALError(); + } + else if(loopstart > 0) + { + static bool warned = false; + if(!warned) + Printf("Loop points not supported!\n"); + warned = true; + } + + retval.data = new ALuint(buffer); + return retval; +} + +SoundHandle OpenALSoundRenderer::LoadSound(BYTE *sfxdata, int length) +{ + SoundHandle retval = { NULL }; + + Decoder decoder; + if(!decoder.Decode(sfxdata, length)) + { + DPrintf("Failed to decode sound\n"); + return retval; + } + + ALenum format = FormatFromDesc(decoder.OutBits, decoder.OutChannels); + if(format == AL_NONE) + { + Printf("Unhandled format: %d bit, %d channel\n", decoder.OutBits, decoder.OutChannels); + return retval; + } + + ALenum err; + ALuint buffer = 0; + alGenBuffers(1, &buffer); + alBufferData(buffer, format, &decoder.OutData[0], + decoder.OutData.size(), decoder.OutRate); + if((err=getALError()) != AL_NO_ERROR) + { + Printf("Failed to buffer data: %s\n", alGetString(err)); + alDeleteBuffers(1, &buffer); + getALError(); + return retval; + } + + if(LoopPoints && decoder.LoopPts[0] > decoder.LoopPts[1]) + { + alBufferiv(buffer, AL_LOOP_POINTS, decoder.LoopPts); + getALError(); + } + else if(decoder.LoopPts[0] > decoder.LoopPts[1]) + { + static bool warned = false; + if(!warned) + Printf("Loop points not supported!\n"); + warned = true; + } + + retval.data = new ALuint(buffer); + return retval; +} + +void OpenALSoundRenderer::UnloadSound(SoundHandle sfx) +{ + if(!sfx.data) + return; + + FSoundChan *schan = Channels; + while(schan) + { + if(schan->SysChannel) + { + ALint bufID = 0; + alGetSourcei(*((ALuint*)schan->SysChannel), AL_BUFFER, &bufID); + if(bufID == *((ALint*)sfx.data)) + { + FSoundChan *next = schan->NextChan; + StopChannel(schan); + schan = next; + continue; + } + } + schan = schan->NextChan; + } + + alDeleteBuffers(1, ((ALuint*)sfx.data)); + getALError(); + delete ((ALuint*)sfx.data); +} + +short *OpenALSoundRenderer::DecodeSample(int outlen, const void *coded, int sizebytes, ECodecType type) +{ + Decoder decoder; + // Force 16-bit + if(!decoder.Decode(coded, sizebytes, 16)) + { + DPrintf("Failed to decode sample\n"); + return NULL; + } + if(decoder.OutBits != 16 || decoder.OutChannels != 1) + { + DPrintf("Sample is not mono\n"); + return NULL; + } + + short *samples = (short*)malloc(outlen); + if((size_t)outlen > decoder.OutData.size()) + { + memcpy(samples, &decoder.OutData[0], decoder.OutData.size()); + memset(&samples[decoder.OutData.size()/sizeof(short)], 0, outlen-decoder.OutData.size()); + } + else + memcpy(samples, &decoder.OutData[0], outlen); + + return samples; +} + +SoundStream *OpenALSoundRenderer::CreateStream(SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata) +{ + OpenALSoundStream *stream = new OpenALSoundStream(this); + if(!stream->Init(callback, buffbytes, flags, samplerate, userdata)) + { + delete stream; + stream = NULL; + } + return stream; +} + +SoundStream *OpenALSoundRenderer::OpenStream(const char *filename, int flags, int offset, int length) +{ + std::auto_ptr stream(new OpenALSoundStream(this)); + + if(offset > 0) + { + // If there's an offset to the start of the data, separate it into its + // own temp file + FILE *infile = fopen(filename, "rb"); + FILE *f = fopen(stream->tmpfile, "wb"); + if(!infile || !f || fseek(infile, offset, SEEK_SET) != 0) + { + if(infile) fclose(infile); + if(f) fclose(f); + return NULL; + } + BYTE buf[1024]; + size_t got; + do { + got = (std::min)(sizeof(buf), (size_t)length); + got = fread(buf, 1, got, infile); + if(got == 0) + break; + } while(fwrite(buf, 1, got, f) == got && (length-=got) > 0); + fclose(f); + fclose(infile); + + filename = stream->tmpfile; + } + + bool ok = ((offset == -1) ? stream->Init((const BYTE*)filename, length) : + stream->Init(filename)); + if(ok == false) + return NULL; + + return stream.release(); +} + +FISoundChannel *OpenALSoundRenderer::StartSound(SoundHandle sfx, float vol, int pitch, int chanflags, FISoundChannel *reuse_chan) +{ + if(FreeSfx.size() == 0) + { + FSoundChan *lowest = FindLowestChannel(); + if(lowest) StopChannel(lowest); + + if(FreeSfx.size() == 0) + return NULL; + } + + ALuint buffer = *((ALuint*)sfx.data); + ALuint &source = *find(Sources.begin(), Sources.end(), FreeSfx.back()); + alSource3f(source, AL_POSITION, 0.0f, 0.0f, 0.0f); + alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); + alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); + alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); + alSourcei(source, AL_LOOPING, (chanflags&SNDF_LOOP)?AL_TRUE:AL_FALSE); + alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f); + alSourcef(source, AL_MAX_DISTANCE, 1000.0f); + alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f); + alSourcef(source, AL_MAX_GAIN, SfxVolume); + alSourcef(source, AL_GAIN, SfxVolume*vol); + if(EnvSlot) + { + if(!(chanflags&SNDF_NOREVERB)) + { + alSourcei(source, AL_DIRECT_FILTER, EnvFilters[0]); + alSource3i(source, AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); + alSourcef(source, AL_AIR_ABSORPTION_FACTOR, LastWaterAbsorb); + } + else + { + alSourcei(source, AL_DIRECT_FILTER, AL_FILTER_NULL); + alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL); + alSourcef(source, AL_AIR_ABSORPTION_FACTOR, 0.0f); + } + alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, 0.0f); + alSourcef(source, AL_PITCH, PITCH(pitch)); + } + else if(LastWaterAbsorb > 0.0f && !(chanflags&SNDF_NOREVERB)) + alSourcef(source, AL_PITCH, PITCH(pitch)*PITCH_MULT); + else + alSourcef(source, AL_PITCH, PITCH(pitch)); + if(!reuse_chan) + alSourcef(source, AL_SEC_OFFSET, 0.0f); + else + { + if((chanflags&SNDF_ABSTIME)) + alSourcef(source, AL_SEC_OFFSET, reuse_chan->StartTime.Lo/1000.0f); + else + { + // FIXME: set offset based on the current time and the StartTime + alSourcef(source, AL_SEC_OFFSET, 0.0f); + } + } + if(getALError() != AL_NO_ERROR) + return NULL; + + alSourcei(source, AL_BUFFER, buffer); + if((chanflags&SNDF_NOPAUSE) || !SFXPaused) + alSourcePlay(source); + if(getALError() != AL_NO_ERROR) + { + alSourcei(source, AL_BUFFER, 0); + getALError(); + return NULL; + } + + if(!(chanflags&SNDF_NOREVERB)) + ReverbSfx.push_back(source); + if(!(chanflags&SNDF_NOPAUSE)) + PausableSfx.push_back(source); + SfxGroup.push_back(source); + FreeSfx.pop_back(); + + FISoundChannel *chan = reuse_chan; + if(!chan) chan = S_GetChannel(&source); + else chan->SysChannel = &source; + + chan->Rolloff.RolloffType = ROLLOFF_Linear; + chan->Rolloff.MaxDistance = 2.0f; + chan->Rolloff.MinDistance = 1.0f; + chan->DistanceScale = 1.0f; + chan->DistanceSqr = (2.0f-vol)*(2.0f-vol); + chan->ManualGain = true; + + return chan; +} + +FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener *listener, float vol, + FRolloffInfo *rolloff, float distscale, int pitch, int priority, const FVector3 &pos, const FVector3 &vel, + int channum, int chanflags, FISoundChannel *reuse_chan) +{ + float dist_sqr = (pos - listener->position).LengthSquared() * + distscale*distscale; + + if(FreeSfx.size() == 0) + { + FSoundChan *lowest = FindLowestChannel(); + if(lowest) + { + if(lowest->Priority < priority || (lowest->Priority == priority && + lowest->DistanceSqr > dist_sqr)) + StopChannel(lowest); + } + if(FreeSfx.size() == 0) + return NULL; + } + + float rolloffFactor, gain; + bool manualGain = true; + + ALuint buffer = *((ALuint*)sfx.data); + ALint channels = 1; + alGetBufferi(buffer, AL_CHANNELS, &channels); + + ALuint &source = *find(Sources.begin(), Sources.end(), FreeSfx.back()); + alSource3f(source, AL_POSITION, pos[0], pos[1], -pos[2]); + alSource3f(source, AL_VELOCITY, vel[0], vel[1], -vel[2]); + alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); + alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); + + alSourcei(source, AL_LOOPING, (chanflags&SNDF_LOOP)?AL_TRUE:AL_FALSE); + + // Multi-channel sources won't attenuate in OpenAL, and "area sounds" have + // special rolloff properties (they have a panning radius of 32 units, but + // starts attenuating at MinDistance). + if(channels == 1 && !(chanflags&SNDF_AREA)) + { + if(rolloff->RolloffType == ROLLOFF_Log) + { + if(SrcDistanceModel) + alSourcei(source, AL_DISTANCE_MODEL, AL_INVERSE_DISTANCE); + alSourcef(source, AL_REFERENCE_DISTANCE, rolloff->MinDistance/distscale); + alSourcef(source, AL_MAX_DISTANCE, (1000.0f+rolloff->MinDistance)/distscale); + rolloffFactor = rolloff->RolloffFactor; + manualGain = false; + gain = 1.0f; + } + else if(rolloff->RolloffType == ROLLOFF_Linear && SrcDistanceModel) + { + alSourcei(source, AL_DISTANCE_MODEL, AL_LINEAR_DISTANCE); + alSourcef(source, AL_REFERENCE_DISTANCE, rolloff->MinDistance/distscale); + alSourcef(source, AL_MAX_DISTANCE, rolloff->MaxDistance/distscale); + rolloffFactor = 1.0f; + manualGain = false; + gain = 1.0f; + } + } + if(manualGain) + { + if(SrcDistanceModel) + alSourcei(source, AL_DISTANCE_MODEL, AL_NONE); + if((chanflags&SNDF_AREA) && rolloff->MinDistance < 32.0f) + alSourcef(source, AL_REFERENCE_DISTANCE, 32.0f/distscale); + else + alSourcef(source, AL_REFERENCE_DISTANCE, rolloff->MinDistance/distscale); + alSourcef(source, AL_MAX_DISTANCE, (1000.0f+rolloff->MinDistance)/distscale); + rolloffFactor = 0.0f; + gain = GetRolloff(rolloff, sqrt(dist_sqr)); + } + alSourcef(source, AL_ROLLOFF_FACTOR, rolloffFactor); + alSourcef(source, AL_MAX_GAIN, SfxVolume); + alSourcef(source, AL_GAIN, SfxVolume * gain); + + if(EnvSlot) + { + if(!(chanflags&SNDF_NOREVERB)) + { + alSourcei(source, AL_DIRECT_FILTER, EnvFilters[0]); + alSource3i(source, AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); + alSourcef(source, AL_AIR_ABSORPTION_FACTOR, LastWaterAbsorb); + } + else + { + alSourcei(source, AL_DIRECT_FILTER, AL_FILTER_NULL); + alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL); + alSourcef(source, AL_AIR_ABSORPTION_FACTOR, 0.0f); + } + alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, rolloffFactor); + alSourcef(source, AL_PITCH, PITCH(pitch)); + } + else if(LastWaterAbsorb > 0.0f && !(chanflags&SNDF_NOREVERB)) + alSourcef(source, AL_PITCH, PITCH(pitch)*PITCH_MULT); + else + alSourcef(source, AL_PITCH, PITCH(pitch)); + if(!reuse_chan) + alSourcef(source, AL_SEC_OFFSET, 0.0f); + else + { + if((chanflags&SNDF_ABSTIME)) + alSourcef(source, AL_SEC_OFFSET, reuse_chan->StartTime.Lo/1000.0f); + else + { + // FIXME: set offset based on the current time and the StartTime + alSourcef(source, AL_SAMPLE_OFFSET, 0.0f); + } + } + if(getALError() != AL_NO_ERROR) + return NULL; + + alSourcei(source, AL_BUFFER, buffer); + if((chanflags&SNDF_NOPAUSE) || !SFXPaused) + alSourcePlay(source); + if(getALError() != AL_NO_ERROR) + { + alSourcei(source, AL_BUFFER, 0); + getALError(); + return NULL; + } + + if(!(chanflags&SNDF_NOREVERB)) + ReverbSfx.push_back(source); + if(!(chanflags&SNDF_NOPAUSE)) + PausableSfx.push_back(source); + SfxGroup.push_back(source); + FreeSfx.pop_back(); + + FISoundChannel *chan = reuse_chan; + if(!chan) chan = S_GetChannel(&source); + else chan->SysChannel = &source; + + chan->Rolloff = *rolloff; + chan->DistanceScale = distscale; + chan->DistanceSqr = dist_sqr; + chan->ManualGain = manualGain; + + return chan; +} + +void OpenALSoundRenderer::StopChannel(FISoundChannel *chan) +{ + if(chan == NULL || chan->SysChannel == NULL) + return; + + ALuint source = *((ALuint*)chan->SysChannel); + // Release first, so it can be properly marked as evicted if it's being + // forcefully killed + S_ChannelEnded(chan); + + alSourceRewind(source); + alSourcei(source, AL_BUFFER, 0); + getALError(); + + std::vector::iterator i; + + i = find(PausableSfx.begin(), PausableSfx.end(), source); + if(i != PausableSfx.end()) PausableSfx.erase(i); + i = find(ReverbSfx.begin(), ReverbSfx.end(), source); + if(i != ReverbSfx.end()) ReverbSfx.erase(i); + + SfxGroup.erase(find(SfxGroup.begin(), SfxGroup.end(), source)); + FreeSfx.push_back(source); +} + +unsigned int OpenALSoundRenderer::GetPosition(FISoundChannel *chan) +{ + if(chan == NULL || chan->SysChannel == NULL) + return 0; + + ALint pos; + alGetSourcei(*((ALuint*)chan->SysChannel), AL_SAMPLE_OFFSET, &pos); + if(getALError() == AL_NO_ERROR) + return pos; + return 0; +} + + +void OpenALSoundRenderer::SetSfxPaused(bool paused, int slot) +{ + int oldslots = SFXPaused; + + if(paused) + { + SFXPaused |= 1 << slot; + if(oldslots == 0 && PausableSfx.size() > 0) + { + alSourcePausev(PausableSfx.size(), &PausableSfx[0]); + getALError(); + PurgeStoppedSources(); + } + } + else + { + SFXPaused &= ~(1 << slot); + if(SFXPaused == 0 && oldslots != 0 && PausableSfx.size() > 0) + { + alSourcePlayv(PausableSfx.size(), &PausableSfx[0]); + getALError(); + } + } +} + +void OpenALSoundRenderer::SetInactive(bool inactive) +{ +} + +void OpenALSoundRenderer::Sync(bool sync) +{ + if(sync) + { + if(SfxGroup.size() > 0) + { + alSourcePausev(SfxGroup.size(), &SfxGroup[0]); + getALError(); + PurgeStoppedSources(); + } + } + else + { + // Might already be something to handle this; basically, get a vector + // of all values in SfxGroup that are not also in PausableSfx (when + // SFXPaused is non-0). + std::vector toplay = SfxGroup; + if(SFXPaused) + { + std::vector::iterator i = toplay.begin(); + while(i != toplay.end()) + { + if(find(PausableSfx.begin(), PausableSfx.end(), *i) != PausableSfx.end()) + i = toplay.erase(i); + else + i++; + } + } + if(toplay.size() > 0) + { + alSourcePlayv(toplay.size(), &toplay[0]); + getALError(); + } + } +} + +void OpenALSoundRenderer::UpdateSoundParams3D(SoundListener *listener, FISoundChannel *chan, bool areasound, const FVector3 &pos, const FVector3 &vel) +{ + if(chan == NULL || chan->SysChannel == NULL) + return; + + alcSuspendContext(Context); + + ALuint source = *((ALuint*)chan->SysChannel); + alSource3f(source, AL_POSITION, pos[0], pos[1], -pos[2]); + alSource3f(source, AL_VELOCITY, vel[0], vel[1], -vel[2]); + + chan->DistanceSqr = (pos - listener->position).LengthSquared() * + chan->DistanceScale*chan->DistanceScale; + // Not all sources can use the distance models provided by OpenAL. + // For the ones that can't, apply the calculated attenuation as the + // source gain. Positions still handle the panning, + if(chan->ManualGain) + { + float gain = GetRolloff(&chan->Rolloff, sqrt(chan->DistanceSqr)); + alSourcef(source, AL_GAIN, SfxVolume*gain); + } + + getALError(); +} + +void OpenALSoundRenderer::UpdateListener(SoundListener *listener) +{ + if(!listener->valid) + return; + + alcSuspendContext(Context); + + float angle = listener->angle; + ALfloat orient[6]; + // forward + orient[0] = cos(angle); + orient[1] = 0.0f; + orient[2] = -sin(angle); + // up + orient[3] = 0.0f; + orient[4] = 1.0f; + orient[5] = 0.0f; + + alListenerfv(AL_ORIENTATION, orient); + alListener3f(AL_POSITION, listener->position.X, + listener->position.Y, + -listener->position.Z); + alListener3f(AL_VELOCITY, listener->velocity.X, + listener->velocity.Y, + -listener->velocity.Z); + getALError(); + + const ReverbContainer *env = ForcedEnvironment; + if(!env) + { + env = listener->Environment; + if(!env) + env = DefaultEnvironments[0]; + } + if(env != PrevEnvironment || env->Modified) + { + PrevEnvironment = env; + DPrintf("Reverb Environment %s\n", env->Name); + + if(EnvSlot != 0) + LoadReverb(env); + + const_cast(env)->Modified = false; + } + + // NOTE: Moving into and out of water (and changing water absorption) will + // undo pitch variations on sounds if either snd_waterreverb or EFX are + // disabled. + if(listener->underwater || env->SoftwareWater) + { + if(LastWaterAbsorb != *snd_waterabsorption) + { + LastWaterAbsorb = *snd_waterabsorption; + + if(EnvSlot != 0 && *snd_waterreverb) + { + // Find the "Underwater" reverb environment + env = Environments; + while(env && env->ID != 0x1600) + env = env->Next; + LoadReverb(env ? env : DefaultEnvironments[0]); + + alFilterf(EnvFilters[0], AL_LOWPASS_GAIN, 0.25f); + alFilterf(EnvFilters[0], AL_LOWPASS_GAINHF, 0.75f); + alFilterf(EnvFilters[1], AL_LOWPASS_GAIN, 1.0f); + alFilterf(EnvFilters[1], AL_LOWPASS_GAINHF, 1.0f); + + // Apply the updated filters on the sources + foreach(ALuint, i, ReverbSfx) + { + alSourcef(*i, AL_AIR_ABSORPTION_FACTOR, LastWaterAbsorb); + alSourcei(*i, AL_DIRECT_FILTER, EnvFilters[0]); + alSource3i(*i, AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); + } + } + else + { + foreach(ALuint, i, ReverbSfx) + alSourcef(*i, AL_PITCH, PITCH_MULT); + } + getALError(); + } + } + else + { + if(LastWaterAbsorb > 0.0f) + { + LastWaterAbsorb = 0.0f; + + if(EnvSlot != 0) + { + LoadReverb(env); + + alFilterf(EnvFilters[0], AL_LOWPASS_GAIN, 1.0f); + alFilterf(EnvFilters[0], AL_LOWPASS_GAINHF, 1.0f); + alFilterf(EnvFilters[1], AL_LOWPASS_GAIN, 1.0f); + alFilterf(EnvFilters[1], AL_LOWPASS_GAINHF, 1.0f); + foreach(ALuint, i, ReverbSfx) + { + alSourcef(*i, AL_AIR_ABSORPTION_FACTOR, 0.0f); + alSourcei(*i, AL_DIRECT_FILTER, EnvFilters[0]); + alSource3i(*i, AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); + } + } + else + { + foreach(ALuint, i, ReverbSfx) + alSourcef(*i, AL_PITCH, 1.0f); + } + getALError(); + } + } +} + +void OpenALSoundRenderer::UpdateSounds() +{ + alcProcessContext(Context); + + if(DisconnectNotify) + { + ALCint connected = ALC_TRUE; + alcGetIntegerv(Device, ALC_CONNECTED, 1, &connected); + if(connected == ALC_FALSE) + { + Printf("Sound device disconnected; restarting...\n"); + static char snd_reset[] = "snd_reset"; + AddCommandString(snd_reset); + return; + } + } + + PurgeStoppedSources(); +} + +bool OpenALSoundRenderer::IsValid() +{ + return Device != NULL; +} + +void OpenALSoundRenderer::MarkStartTime(FISoundChannel *chan) +{ + // FIXME: Get current time (preferably from the audio clock, but the system + // time will have to do) + chan->StartTime.AsOne = 0; +} + +float OpenALSoundRenderer::GetAudibility(FISoundChannel *chan) +{ + if(chan == NULL || chan->SysChannel == NULL) + return 0.0f; + + ALuint source = *((ALuint*)chan->SysChannel); + ALfloat volume = 0.0f; + + if(!chan->ManualGain) + volume = SfxVolume * GetRolloff(&chan->Rolloff, sqrt(chan->DistanceSqr)); + else + { + alGetSourcef(source, AL_GAIN, &volume); + getALError(); + } + return volume; +} + + +void OpenALSoundRenderer::PrintStatus() +{ + Printf("Output device: "TEXTCOLOR_ORANGE"%s\n", alcGetString(Device, ALC_DEVICE_SPECIFIER)); + getALCError(Device); + + ALCint frequency=0, major=0, minor=0, mono=0, stereo=0; + alcGetIntegerv(Device, ALC_FREQUENCY, 1, &frequency); + alcGetIntegerv(Device, ALC_MAJOR_VERSION, 1, &major); + alcGetIntegerv(Device, ALC_MINOR_VERSION, 1, &minor); + alcGetIntegerv(Device, ALC_MONO_SOURCES, 1, &mono); + alcGetIntegerv(Device, ALC_STEREO_SOURCES, 1, &stereo); + if(getALCError(Device) == AL_NO_ERROR) + { + Printf("Device sample rate: "TEXTCOLOR_BLUE"%d"TEXTCOLOR_NORMAL"hz\n", frequency); + Printf("ALC Version: "TEXTCOLOR_BLUE"%d.%d\n", major, minor); + Printf("ALC Extensions: "TEXTCOLOR_ORANGE"%s\n", alcGetString(Device, ALC_EXTENSIONS)); + Printf("Available sources: "TEXTCOLOR_BLUE"%d"TEXTCOLOR_NORMAL" ("TEXTCOLOR_BLUE"%d"TEXTCOLOR_NORMAL" mono, "TEXTCOLOR_BLUE"%d"TEXTCOLOR_NORMAL" stereo)\n", mono+stereo, mono, stereo); + } + if(!alcIsExtensionPresent(Device, "ALC_EXT_EFX")) + Printf("EFX not found\n"); + else + { + ALCint sends; + alcGetIntegerv(Device, ALC_EFX_MAJOR_VERSION, 1, &major); + alcGetIntegerv(Device, ALC_EFX_MINOR_VERSION, 1, &minor); + alcGetIntegerv(Device, ALC_MAX_AUXILIARY_SENDS, 1, &sends); + if(getALCError(Device) == AL_NO_ERROR) + { + Printf("EFX Version: "TEXTCOLOR_BLUE"%d.%d\n", major, minor); + Printf("Auxiliary sends: "TEXTCOLOR_BLUE"%d\n", sends); + } + } + Printf("Vendor: "TEXTCOLOR_ORANGE"%s\n", alGetString(AL_VENDOR)); + Printf("Renderer: "TEXTCOLOR_ORANGE"%s\n", alGetString(AL_RENDERER)); + Printf("Version: "TEXTCOLOR_ORANGE"%s\n", alGetString(AL_VERSION)); + Printf("Extensions: "TEXTCOLOR_ORANGE"%s\n", alGetString(AL_EXTENSIONS)); + getALError(); +} + +FString OpenALSoundRenderer::GatherStats() +{ + ALCint updates = 1; + alcGetIntegerv(Device, ALC_REFRESH, 1, &updates); + getALCError(Device); + + ALuint total = Sources.size(); + ALuint used = SfxGroup.size()+Streams.size(); + ALuint unused = FreeSfx.size(); + FString out; + out.Format("%u sources ("TEXTCOLOR_YELLOW"%u"TEXTCOLOR_NORMAL" active, "TEXTCOLOR_YELLOW"%u"TEXTCOLOR_NORMAL" free), Update interval: "TEXTCOLOR_YELLOW"%d"TEXTCOLOR_NORMAL"ms", + total, used, unused, 1000/updates); + return out; +} + +void OpenALSoundRenderer::PrintDriversList() +{ + const ALCchar *drivers = (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") ? + alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER) : + alcGetString(NULL, ALC_DEVICE_SPECIFIER)); + const ALCchar *current = alcGetString(Device, ALC_DEVICE_SPECIFIER); + if(drivers == NULL) + { + Printf(TEXTCOLOR_YELLOW"Failed to retrieve device list: %s\n", alcGetString(NULL, alcGetError(NULL))); + return; + } + + Printf("%c%s%d. %s\n", ' ', (!(*snd_aldevice)[0] ? TEXTCOLOR_BOLD : ""), 0, + "Default"); + for(int i = 1;*drivers;i++) + { + Printf("%c%s%d. %s\n", ((strcmp(current, drivers)==0) ? '*' : ' '), + ((strcmp(*snd_aldevice, drivers)==0) ? TEXTCOLOR_BOLD : ""), i, + drivers); + drivers += strlen(drivers)+1; + } +} + +void OpenALSoundRenderer::PurgeStoppedSources() +{ + // Release channels that are stopped + foreach(ALuint, i, SfxGroup) + { + ALint state = AL_PLAYING; + alGetSourcei(*i, AL_SOURCE_STATE, &state); + if(state == AL_PLAYING || state == AL_PAUSED) + continue; + + FSoundChan *schan = Channels; + while(schan) + { + if(schan->SysChannel != NULL && *i == *((ALuint*)schan->SysChannel)) + { + StopChannel(schan); + break; + } + schan = schan->NextChan; + } + } + getALError(); +} + +void OpenALSoundRenderer::LoadReverb(const ReverbContainer *env) +{ + ALuint &envReverb = EnvEffects[env->ID]; + bool doLoad = (env->Modified || !envReverb); + + if(!envReverb) + { + bool ok = false; + alGenEffects(1, &envReverb); + if(getALError() == AL_NO_ERROR) + { + alEffecti(envReverb, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB); + ok = (alGetError() == AL_NO_ERROR); + if(!ok) + { + alEffecti(envReverb, AL_EFFECT_TYPE, AL_EFFECT_REVERB); + ok = (alGetError() == AL_NO_ERROR); + } + if(!ok) + { + alEffecti(envReverb, AL_EFFECT_TYPE, AL_EFFECT_NULL); + ok = (alGetError() == AL_NO_ERROR); + } + if(!ok) + { + alDeleteEffects(1, &envReverb); + getALError(); + } + } + if(!ok) + { + envReverb = 0; + doLoad = false; + } + } + + if(doLoad) + { + const REVERB_PROPERTIES &props = env->Properties; + ALint type = AL_EFFECT_NULL; + + alGetEffecti(envReverb, AL_EFFECT_TYPE, &type); +#define mB2Gain(x) ((float)pow(10.0, (x)/2000.0)) + if(type == AL_EFFECT_EAXREVERB) + { + ALfloat reflectpan[3] = { props.ReflectionsPan0, + props.ReflectionsPan1, + props.ReflectionsPan2 }; + ALfloat latepan[3] = { props.ReverbPan0, props.ReverbPan1, + props.ReverbPan2 }; +#undef SETPARAM +#define SETPARAM(e,t,v) alEffectf((e), AL_EAXREVERB_##t, clamp((v), AL_EAXREVERB_MIN_##t, AL_EAXREVERB_MAX_##t)) + SETPARAM(envReverb, DENSITY, props.Density/100.0f); + SETPARAM(envReverb, DIFFUSION, props.Diffusion/100.0f); + SETPARAM(envReverb, GAIN, mB2Gain(props.Room)); + SETPARAM(envReverb, GAINHF, mB2Gain(props.RoomHF)); + SETPARAM(envReverb, GAINLF, mB2Gain(props.RoomLF)); + SETPARAM(envReverb, DECAY_TIME, props.DecayTime); + SETPARAM(envReverb, DECAY_HFRATIO, props.DecayHFRatio); + SETPARAM(envReverb, DECAY_LFRATIO, props.DecayLFRatio); + SETPARAM(envReverb, REFLECTIONS_GAIN, mB2Gain(props.Reflections)); + SETPARAM(envReverb, REFLECTIONS_DELAY, props.ReflectionsDelay); + alEffectfv(envReverb, AL_EAXREVERB_REFLECTIONS_PAN, reflectpan); + SETPARAM(envReverb, LATE_REVERB_GAIN, mB2Gain(props.Reverb)); + SETPARAM(envReverb, LATE_REVERB_DELAY, props.ReverbDelay); + alEffectfv(envReverb, AL_EAXREVERB_LATE_REVERB_PAN, latepan); + SETPARAM(envReverb, ECHO_TIME, props.EchoTime); + SETPARAM(envReverb, ECHO_DEPTH, props.EchoDepth); + SETPARAM(envReverb, MODULATION_TIME, props.ModulationTime); + SETPARAM(envReverb, MODULATION_DEPTH, props.ModulationDepth); + SETPARAM(envReverb, AIR_ABSORPTION_GAINHF, mB2Gain(props.AirAbsorptionHF)); + SETPARAM(envReverb, HFREFERENCE, props.HFReference); + SETPARAM(envReverb, LFREFERENCE, props.LFReference); + SETPARAM(envReverb, ROOM_ROLLOFF_FACTOR, props.RoomRolloffFactor); + alEffecti(envReverb, AL_EAXREVERB_DECAY_HFLIMIT, + (props.Flags&REVERB_FLAGS_DECAYHFLIMIT)?AL_TRUE:AL_FALSE); +#undef SETPARAM + } + else if(type == AL_EFFECT_REVERB) + { +#define SETPARAM(e,t,v) alEffectf((e), AL_REVERB_##t, clamp((v), AL_REVERB_MIN_##t, AL_REVERB_MAX_##t)) + SETPARAM(envReverb, DENSITY, props.Density/100.0f); + SETPARAM(envReverb, DIFFUSION, props.Diffusion/100.0f); + SETPARAM(envReverb, GAIN, mB2Gain(props.Room)); + SETPARAM(envReverb, GAINHF, mB2Gain(props.RoomHF)); + SETPARAM(envReverb, DECAY_TIME, props.DecayTime); + SETPARAM(envReverb, DECAY_HFRATIO, props.DecayHFRatio); + SETPARAM(envReverb, REFLECTIONS_GAIN, mB2Gain(props.Reflections)); + SETPARAM(envReverb, REFLECTIONS_DELAY, props.ReflectionsDelay); + SETPARAM(envReverb, LATE_REVERB_GAIN, mB2Gain(props.Reverb)); + SETPARAM(envReverb, LATE_REVERB_DELAY, props.ReverbDelay); + SETPARAM(envReverb, AIR_ABSORPTION_GAINHF, mB2Gain(props.AirAbsorptionHF)); + SETPARAM(envReverb, ROOM_ROLLOFF_FACTOR, props.RoomRolloffFactor); + alEffecti(envReverb, AL_REVERB_DECAY_HFLIMIT, + (props.Flags&REVERB_FLAGS_DECAYHFLIMIT)?AL_TRUE:AL_FALSE); +#undef SETPARAM + } +#undef mB2Gain + } + + alAuxiliaryEffectSloti(EnvSlot, AL_EFFECTSLOT_EFFECT, envReverb); + getALError(); +} + +FSoundChan *OpenALSoundRenderer::FindLowestChannel() +{ + FSoundChan *schan = Channels; + FSoundChan *lowest = NULL; + while(schan) + { + if(schan->SysChannel != NULL) + { + if(!lowest || schan->Priority < lowest->Priority || + (schan->Priority == lowest->Priority && + schan->DistanceSqr > lowest->DistanceSqr)) + lowest = schan; + } + schan = schan->NextChan; + } + return lowest; +} + +#endif // NO_OPENAL diff --git a/src/sound/oalsound.h b/src/sound/oalsound.h new file mode 100644 index 0000000000..08c3c65d12 --- /dev/null +++ b/src/sound/oalsound.h @@ -0,0 +1,211 @@ +#ifndef OALSOUND_H +#define OALSOUND_H + + +#include +#include + +#include "i_sound.h" +#include "s_sound.h" +#include "m_menu.h" + + +#ifndef NO_OPENAL + +#ifdef _WIN32 +#include +#include +#elif defined(__APPLE__) +#include +#include +#else +#include +#include +#endif + +#ifndef ALC_ENUMERATE_ALL_EXT +#define ALC_ENUMERATE_ALL_EXT 1 +#define ALC_DEFAULT_ALL_DEVICES_SPECIFIER 0x1012 +#define ALC_ALL_DEVICES_SPECIFIER 0x1013 +#endif + +#ifndef ALC_EXT_disconnect +#define ALC_EXT_disconnect 1 +#define ALC_CONNECTED 0x313 +#endif + +#ifndef AL_EXT_source_distance_model +#define AL_EXT_source_distance_model 1 +#define AL_SOURCE_DISTANCE_MODEL 0x200 +#endif + +#ifndef AL_EXT_loop_points +#define AL_EXT_loop_points 1 +#define AL_LOOP_POINTS 0x2015 +#endif + +#ifndef AL_EXT_float32 +#define AL_EXT_float32 1 +#define AL_FORMAT_MONO_FLOAT32 0x10010 +#define AL_FORMAT_STEREO_FLOAT32 0x10011 +#endif + +#ifndef AL_EXT_MCFORMATS +#define AL_EXT_MCFORMATS 1 +#define AL_FORMAT_QUAD8 0x1204 +#define AL_FORMAT_QUAD16 0x1205 +#define AL_FORMAT_QUAD32 0x1206 +#define AL_FORMAT_REAR8 0x1207 +#define AL_FORMAT_REAR16 0x1208 +#define AL_FORMAT_REAR32 0x1209 +#define AL_FORMAT_51CHN8 0x120A +#define AL_FORMAT_51CHN16 0x120B +#define AL_FORMAT_51CHN32 0x120C +#define AL_FORMAT_61CHN8 0x120D +#define AL_FORMAT_61CHN16 0x120E +#define AL_FORMAT_61CHN32 0x120F +#define AL_FORMAT_71CHN8 0x1210 +#define AL_FORMAT_71CHN16 0x1211 +#define AL_FORMAT_71CHN32 0x1212 +#endif + +#include "efx.h" + + +class OpenALSoundStream; + +class OpenALSoundRenderer : public SoundRenderer +{ +public: + OpenALSoundRenderer(); + virtual ~OpenALSoundRenderer(); + + virtual void SetSfxVolume(float volume); + virtual void SetMusicVolume(float volume); + virtual SoundHandle LoadSound(BYTE *sfxdata, int length); + virtual SoundHandle LoadSoundRaw(BYTE *sfxdata, int length, int frequency, int channels, int bits, int loopstart); + virtual void UnloadSound(SoundHandle sfx); + virtual unsigned int GetMSLength(SoundHandle sfx); + virtual unsigned int GetSampleLength(SoundHandle sfx); + virtual float GetOutputRate(); + + // Streaming sounds. + virtual SoundStream *CreateStream(SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata); + virtual SoundStream *OpenStream(const char *filename, int flags, int offset, int length); + + // Starts a sound. + virtual FISoundChannel *StartSound(SoundHandle sfx, float vol, int pitch, int chanflags, FISoundChannel *reuse_chan); + virtual FISoundChannel *StartSound3D(SoundHandle sfx, SoundListener *listener, float vol, FRolloffInfo *rolloff, float distscale, int pitch, int priority, const FVector3 &pos, const FVector3 &vel, int channum, int chanflags, FISoundChannel *reuse_chan); + + // Stops a sound channel. + virtual void StopChannel(FISoundChannel *chan); + + // Returns position of sound on this channel, in samples. + virtual unsigned int GetPosition(FISoundChannel *chan); + + // Synchronizes following sound startups. + virtual void Sync(bool sync); + + // Pauses or resumes all sound effect channels. + virtual void SetSfxPaused(bool paused, int slot); + + // Pauses or resumes *every* channel, including environmental reverb. + virtual void SetInactive(bool inactive); + + // Updates the volume, separation, and pitch of a sound channel. + virtual void UpdateSoundParams3D(SoundListener *listener, FISoundChannel *chan, bool areasound, const FVector3 &pos, const FVector3 &vel); + + virtual void UpdateListener(SoundListener *); + virtual void UpdateSounds(); + + virtual short *DecodeSample(int outlen, const void *coded, int sizebytes, ECodecType type); + + virtual void MarkStartTime(FISoundChannel*); + virtual float GetAudibility(FISoundChannel*); + + + virtual bool IsValid(); + virtual void PrintStatus(); + virtual void PrintDriversList(); + virtual FString GatherStats(); + +private: + // EFX Extension function pointer variables. Loaded after context creation + // if EFX is supported. These pointers may be context- or device-dependant, + // thus can't be static + // Effect objects + LPALGENEFFECTS alGenEffects; + LPALDELETEEFFECTS alDeleteEffects; + LPALISEFFECT alIsEffect; + LPALEFFECTI alEffecti; + LPALEFFECTIV alEffectiv; + LPALEFFECTF alEffectf; + LPALEFFECTFV alEffectfv; + LPALGETEFFECTI alGetEffecti; + LPALGETEFFECTIV alGetEffectiv; + LPALGETEFFECTF alGetEffectf; + LPALGETEFFECTFV alGetEffectfv; + // Filter objects + LPALGENFILTERS alGenFilters; + LPALDELETEFILTERS alDeleteFilters; + LPALISFILTER alIsFilter; + LPALFILTERI alFilteri; + LPALFILTERIV alFilteriv; + LPALFILTERF alFilterf; + LPALFILTERFV alFilterfv; + LPALGETFILTERI alGetFilteri; + LPALGETFILTERIV alGetFilteriv; + LPALGETFILTERF alGetFilterf; + LPALGETFILTERFV alGetFilterfv; + // Auxiliary slot objects + LPALGENAUXILIARYEFFECTSLOTS alGenAuxiliaryEffectSlots; + LPALDELETEAUXILIARYEFFECTSLOTS alDeleteAuxiliaryEffectSlots; + LPALISAUXILIARYEFFECTSLOT alIsAuxiliaryEffectSlot; + LPALAUXILIARYEFFECTSLOTI alAuxiliaryEffectSloti; + LPALAUXILIARYEFFECTSLOTIV alAuxiliaryEffectSlotiv; + LPALAUXILIARYEFFECTSLOTF alAuxiliaryEffectSlotf; + LPALAUXILIARYEFFECTSLOTFV alAuxiliaryEffectSlotfv; + LPALGETAUXILIARYEFFECTSLOTI alGetAuxiliaryEffectSloti; + LPALGETAUXILIARYEFFECTSLOTIV alGetAuxiliaryEffectSlotiv; + LPALGETAUXILIARYEFFECTSLOTF alGetAuxiliaryEffectSlotf; + LPALGETAUXILIARYEFFECTSLOTFV alGetAuxiliaryEffectSlotfv; + + + void LoadReverb(const ReverbContainer *env); + void PurgeStoppedSources(); + static FSoundChan *FindLowestChannel(); + + ALCdevice *Device; + ALCcontext *Context; + + bool LoopPoints; + bool SrcDistanceModel; + bool DisconnectNotify; + + std::vector Sources; + + ALfloat SfxVolume; + ALfloat MusicVolume; + + int SFXPaused; + std::vector FreeSfx; + std::vector PausableSfx; + std::vector ReverbSfx; + std::vector SfxGroup; + + const ReverbContainer *PrevEnvironment; + + typedef std::map EffectMap; + ALuint EnvSlot; + EffectMap EnvEffects; + + ALuint EnvFilters[2]; + float LastWaterAbsorb; + + std::vector Streams; + friend class OpenALSoundStream; +}; + +#endif // NO_OPENAL + +#endif diff --git a/zdoom.vcproj b/zdoom.vcproj index 913cff4a99..4efe7e185a 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -5413,6 +5413,18 @@ RelativePath=".\src\sound\fmodsound.h" > + + + + + + From d64fcbd01e797a246a402e490f73223b84826f84 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 15 Sep 2010 13:45:08 +0000 Subject: [PATCH 02/88] - applied Chris's latest OpenAL patch. SVN r2781 (openal) --- src/CMakeLists.txt | 2 +- src/menu/menudef.cpp | 7 ++ src/namedef.h | 1 + src/sound/oalsound.cpp | 255 +++++++++++++++----------------------- src/sound/oalsound.h | 3 +- wadsrc/static/menudef.txt | 75 ++++++++--- 6 files changed, 165 insertions(+), 178 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 488c0c3b9f..af135b72cf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -606,7 +606,7 @@ add_custom_target( revision_check ALL message( STATUS "Fluid synth libs: ${FLUIDSYNTH_LIBRARIES}" ) set( ZDOOM_LIBS ${ZDOOM_LIBS} "${ZLIB_LIBRARIES}" "${JPEG_LIBRARIES}" "${BZIP2_LIBRARIES}" "${FMOD_LIBRARY}" ) -include_directories( "${ZLIB_INCLUDE_DIR}" "${FMOD_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" ) +include_directories( "${ZLIB_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" ) if( FLUIDSYNTH_FOUND ) if( NOT DYN_FLUIDSYNTH) diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index 033ad599ba..467631fed7 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -58,6 +58,8 @@ static FOptionMenuDescriptor DefaultOptionMenuSettings; // contains common setti FOptionMenuSettings OptionSettings; FOptionMap OptionValues; +void I_BuildALDeviceList(FOptionValues *opt); + static void DeinitMenus() { { @@ -1204,6 +1206,11 @@ void M_CreateMenus() { I_BuildMIDIMenuList(*opt); } + opt = OptionValues.CheckKey(NAME_Aldevices); + if (opt != NULL) + { + I_BuildALDeviceList(*opt); + } } //============================================================================= diff --git a/src/namedef.h b/src/namedef.h index 9f7e5a87d1..b70ee784ed 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -498,6 +498,7 @@ xx(Controlmessage) xx(Crosshairs) xx(Colorpickermenu) xx(Mididevices) +xx(Aldevices) xx(CustomizeControls) xx(MessageOptions) xx(AutomapOptions) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 06107751ed..d64b230e9b 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -54,7 +54,7 @@ #include "tempfiles.h" -CVAR (String, snd_aldevice, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CVAR (String, snd_aldevice, "Default", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (Bool, snd_efx, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CUSTOM_CVAR (Float, snd_waterabsorption, 10.0f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) { @@ -64,20 +64,11 @@ CUSTOM_CVAR (Float, snd_waterabsorption, 10.0f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) self = 10.0f; } -int BuildALDeviceList(valueenum_t **menulist) +void I_BuildALDeviceList(FOptionValues *opt) { - std::vector list; - static const char def[] = ""; - - valueenum_t val; - size_t len = strlen(def)+1; - - char *n = new char[len]; - memcpy(n, def, len); - - val.value = n; - val.name = "Default"; - list.push_back(val); + opt->mValues.Resize(1); + opt->mValues[0].TextValue = "Default"; + opt->mValues[0].Text = "Default"; #ifndef NO_OPENAL const ALCchar *names = (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") ? @@ -87,33 +78,13 @@ int BuildALDeviceList(valueenum_t **menulist) Printf("Failed to get device list: %s\n", alcGetString(NULL, alcGetError(NULL))); else while(*names) { - len = strlen(names)+1; + unsigned int i = opt->mValues.Reserve(1); + opt->mValues[i].TextValue = names; + opt->mValues[i].Text = names; - n = new char[len]; - memcpy(n, names, len); - - val.value = n; - val.name = val.value; - list.push_back(val); - - names += len; + names += strlen(names)+1; } #endif - - static const valueenum_t listend = {NULL,NULL}; - list.push_back(listend); - - valueenum_t *newlist = new valueenum_t[list.size()]; - memcpy(&newlist[0], &list[0], list.size()*sizeof(newlist[0])); - - if(*menulist) - { - for(size_t i = 0;(*menulist)[i].value;i++) - delete[] const_cast((*menulist)[i].value); - delete[] *menulist; - } - *menulist = newlist; - return list.size()-1; } #ifndef NO_OPENAL @@ -213,7 +184,7 @@ static float GetRolloff(const FRolloffInfo *rolloff, float distance) #include #include -/* Bad GStreamer, using enums for bit fields... (GStreamerMM probably fixes this) */ +/* Bad GStreamer, using enums for bit fields... */ static GstMessageType operator|(const GstMessageType &a, const GstMessageType &b) { return GstMessageType((unsigned)a|(unsigned)b); } static GstSeekFlags operator|(const GstSeekFlags &a, const GstSeekFlags &b) @@ -449,7 +420,7 @@ class OpenALSoundStream : public SoundStream do { g_usleep(10000); alGetSourcei(self->Source, AL_SOURCE_STATE, &state); - } while(getALError() == AL_NO_ERROR && state == AL_PLAYING); + } while(getALError() == AL_NO_ERROR && state == AL_PLAYING && self->Playing); alSourceRewind(self->Source); getALError(); @@ -509,7 +480,7 @@ class OpenALSoundStream : public SoundStream return GST_FLOW_ERROR; } if(processed > 0 || self->SamplesQueued < MaxSamplesQueued || - state != AL_PLAYING) + state != AL_PLAYING || !self->Playing) break; g_usleep(10000); @@ -585,7 +556,7 @@ class OpenALSoundStream : public SoundStream // "read" the data it wants, up to the remaining amount guint8 *data = &self->MemData[self->MemDataPos]; - size = (std::min)(size, (guint)(self->MemData.size() - self->MemDataPos)); + size = std::min(size, self->MemData.size() - self->MemDataPos); self->MemDataPos += size; GstBuffer *buffer = gst_buffer_new(); @@ -685,20 +656,20 @@ class OpenALSoundStream : public SoundStream Source = Renderer->FreeSfx.back(); Renderer->FreeSfx.pop_back(); - alSource3f(Source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); - alSource3f(Source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); - alSource3f(Source, AL_POSITION, 0.0f, 0.0f, 0.0f); - alSourcef(Source, AL_MAX_GAIN, 1.0f); - alSourcef(Source, AL_GAIN, 1.0f); - alSourcef(Source, AL_PITCH, 1.0f); - alSourcef(Source, AL_ROLLOFF_FACTOR, 0.0f); - alSourcef(Source, AL_SEC_OFFSET, 0.0f); + alSource3f(Source, AL_DIRECTION, 0.f, 0.f, 0.f); + alSource3f(Source, AL_VELOCITY, 0.f, 0.f, 0.f); + alSource3f(Source, AL_POSITION, 0.f, 0.f, 0.f); + alSourcef(Source, AL_MAX_GAIN, 1.f); + alSourcef(Source, AL_GAIN, 1.f); + alSourcef(Source, AL_PITCH, 1.f); + alSourcef(Source, AL_ROLLOFF_FACTOR, 0.f); + alSourcef(Source, AL_SEC_OFFSET, 0.f); alSourcei(Source, AL_SOURCE_RELATIVE, AL_TRUE); alSourcei(Source, AL_LOOPING, AL_FALSE); if(Renderer->EnvSlot) { - alSourcef(Source, AL_ROOM_ROLLOFF_FACTOR, 0.0f); - alSourcef(Source, AL_AIR_ABSORPTION_FACTOR, 0.0f); + alSourcef(Source, AL_ROOM_ROLLOFF_FACTOR, 0.f); + alSourcef(Source, AL_AIR_ABSORPTION_FACTOR, 0.f); alSourcei(Source, AL_DIRECT_FILTER, AL_FILTER_NULL); alSource3i(Source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL); } @@ -810,7 +781,7 @@ class OpenALSoundStream : public SoundStream { if(GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) { - PrintErrMsg("Play Error", msg); + PrintErrMsg("Prepare Error", msg); ret = GST_STATE_CHANGE_FAILURE; break; } @@ -1109,7 +1080,8 @@ public: { if(err) { - Printf("Failed to convert "TEXTCOLOR_BOLD"%s"TEXTCOLOR_NORMAL" to URI: %s\n", filename, err->message); + Printf("Failed to convert "TEXTCOLOR_BOLD"%s"TEXTCOLOR_NORMAL" to URI: %s\n", + filename, err->message); g_error_free(err); } return false; @@ -1190,7 +1162,6 @@ class Decoder const guint8 *MemData; size_t MemDataSize; size_t MemDataPos; - GstCaps *SrcCaps; static void need_memdata(GstAppSrc *appsrc, guint size, gpointer user_data) { @@ -1235,7 +1206,6 @@ class Decoder }; gst_app_src_set_callbacks(appsrc, &callbacks, self, NULL); gst_app_src_set_size(appsrc, self->MemDataSize); - gst_app_src_set_caps(appsrc, self->SrcCaps); gst_app_src_set_stream_type(appsrc, GST_APP_STREAM_TYPE_RANDOM_ACCESS); gst_object_unref(appsrc); @@ -1354,16 +1324,12 @@ public: ALuint OutBits; Decoder() - : gstPipeline(NULL), gstSink(NULL), TagList(NULL), SrcCaps(NULL), + : gstPipeline(NULL), gstSink(NULL), TagList(NULL), OutRate(0), OutChannels(0), OutBits(0) { LoopPts[0] = LoopPts[1] = 0; } virtual ~Decoder() { - if(SrcCaps) - gst_caps_unref(SrcCaps); - SrcCaps = NULL; - if(gstSink) gst_object_unref(gstSink); gstSink = NULL; @@ -1380,22 +1346,6 @@ public: TagList = NULL; } - bool DecodeRaw(const void *data, unsigned int datalen, int rawbits, int rawchannels, int rawrate) - { - GstStructure *structure = gst_structure_new("audio/x-raw-int", - "endianness", G_TYPE_INT, G_BYTE_ORDER, - "width", G_TYPE_INT, rawbits, - "depth", G_TYPE_INT, rawbits, - "signed", G_TYPE_BOOLEAN, ((rawbits==8)?FALSE:TRUE), NULL); - gst_structure_set(structure, "channels", G_TYPE_INT, rawchannels, NULL); - gst_structure_set(structure, "rate", G_TYPE_INT, rawrate, NULL); - - SrcCaps = gst_caps_new_full(structure, NULL); - if(!SrcCaps) - return false; - return Decode(data, datalen); - } - bool Decode(const void *data, unsigned int datalen, int forcebits=0) { MemData = static_cast(data); @@ -1544,7 +1494,7 @@ OpenALSoundRenderer::OpenALSoundRenderer() GSTInited = true; } - if((*snd_aldevice)[0] != 0) + if(snd_aldevice != "Default") { Device = alcOpenDevice(*snd_aldevice); if(!Device) @@ -1823,7 +1773,7 @@ unsigned int OpenALSoundRenderer::GetMSLength(SoundHandle sfx) alGetBufferi(buffer, AL_FREQUENCY, &freq); alGetBufferi(buffer, AL_SIZE, &size); if(getALError() == AL_NO_ERROR) - return (unsigned int)(size / (channels*bits/8) * 1000.0 / freq); + return (unsigned int)(size / (channels*bits/8) * 1000. / freq); } } return 0; @@ -1831,14 +1781,14 @@ unsigned int OpenALSoundRenderer::GetMSLength(SoundHandle sfx) unsigned int OpenALSoundRenderer::GetSampleLength(SoundHandle sfx) { - if(sfx.data) - return getBufferLength(*((ALuint*)sfx.data)); - return 0; + if(!sfx.data) + return 0; + return getBufferLength(*((ALuint*)sfx.data)); } float OpenALSoundRenderer::GetOutputRate() { - ALCint rate = *snd_samplerate; // Default, just in case + ALCint rate = 44100; // Default, just in case alcGetIntegerv(Device, ALC_FREQUENCY, 1, &rate); return (float)rate; } @@ -1870,16 +1820,6 @@ SoundHandle OpenALSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int length, int fre if(channels == 2) format = AL_FORMAT_STEREO8; } - Decoder decoder; - if(format == AL_NONE && decoder.DecodeRaw(sfxdata, length, bits, channels, frequency)) - { - sfxdata = &decoder.OutData[0]; - length = decoder.OutData.size(); - frequency = decoder.OutRate; - bits = decoder.OutBits; - channels = decoder.OutChannels; - format = FormatFromDesc(bits, channels); - } if(format == AL_NONE || frequency <= 0) { Printf("Unhandled format: %d bit, %d channel, %d hz\n", bits, channels, frequency); @@ -1912,7 +1852,7 @@ SoundHandle OpenALSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int length, int fre else if(loopstart > 0) { static bool warned = false; - if(!warned) + if(!warned) Printf("Loop points not supported!\n"); warned = true; } @@ -1952,15 +1892,15 @@ SoundHandle OpenALSoundRenderer::LoadSound(BYTE *sfxdata, int length) return retval; } - if(LoopPoints && decoder.LoopPts[0] > decoder.LoopPts[1]) + if(LoopPoints && decoder.LoopPts[1] > decoder.LoopPts[0]) { alBufferiv(buffer, AL_LOOP_POINTS, decoder.LoopPts); getALError(); } - else if(decoder.LoopPts[0] > decoder.LoopPts[1]) + else if(decoder.LoopPts[1] > decoder.LoopPts[0]) { static bool warned = false; - if(!warned) + if(!warned) Printf("Loop points not supported!\n"); warned = true; } @@ -2006,7 +1946,7 @@ short *OpenALSoundRenderer::DecodeSample(int outlen, const void *coded, int size DPrintf("Failed to decode sample\n"); return NULL; } - if(decoder.OutBits != 16 || decoder.OutChannels != 1) + if(decoder.OutChannels != 1) { DPrintf("Sample is not mono\n"); return NULL; @@ -2086,16 +2026,19 @@ FISoundChannel *OpenALSoundRenderer::StartSound(SoundHandle sfx, float vol, int ALuint buffer = *((ALuint*)sfx.data); ALuint &source = *find(Sources.begin(), Sources.end(), FreeSfx.back()); - alSource3f(source, AL_POSITION, 0.0f, 0.0f, 0.0f); - alSource3f(source, AL_VELOCITY, 0.0f, 0.0f, 0.0f); - alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); + alSource3f(source, AL_POSITION, 0.f, 0.f, 0.f); + alSource3f(source, AL_VELOCITY, 0.f, 0.f, 0.f); + alSource3f(source, AL_DIRECTION, 0.f, 0.f, 0.f); alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); - alSourcei(source, AL_LOOPING, (chanflags&SNDF_LOOP)?AL_TRUE:AL_FALSE); - alSourcef(source, AL_REFERENCE_DISTANCE, 1.0f); - alSourcef(source, AL_MAX_DISTANCE, 1000.0f); - alSourcef(source, AL_ROLLOFF_FACTOR, 0.0f); + + alSourcei(source, AL_LOOPING, (chanflags&SNDF_LOOP) ? AL_TRUE : AL_FALSE); + + alSourcef(source, AL_REFERENCE_DISTANCE, 1.f); + alSourcef(source, AL_MAX_DISTANCE, 1000.f); + alSourcef(source, AL_ROLLOFF_FACTOR, 0.f); alSourcef(source, AL_MAX_GAIN, SfxVolume); alSourcef(source, AL_GAIN, SfxVolume*vol); + if(EnvSlot) { if(!(chanflags&SNDF_NOREVERB)) @@ -2108,25 +2051,26 @@ FISoundChannel *OpenALSoundRenderer::StartSound(SoundHandle sfx, float vol, int { alSourcei(source, AL_DIRECT_FILTER, AL_FILTER_NULL); alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL); - alSourcef(source, AL_AIR_ABSORPTION_FACTOR, 0.0f); + alSourcef(source, AL_AIR_ABSORPTION_FACTOR, 0.f); } - alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, 0.0f); + alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, 0.f); alSourcef(source, AL_PITCH, PITCH(pitch)); } - else if(LastWaterAbsorb > 0.0f && !(chanflags&SNDF_NOREVERB)) + else if(LastWaterAbsorb > 0.f && !(chanflags&SNDF_NOREVERB)) alSourcef(source, AL_PITCH, PITCH(pitch)*PITCH_MULT); else alSourcef(source, AL_PITCH, PITCH(pitch)); + if(!reuse_chan) - alSourcef(source, AL_SEC_OFFSET, 0.0f); + alSourcef(source, AL_SEC_OFFSET, 0.f); else { if((chanflags&SNDF_ABSTIME)) - alSourcef(source, AL_SEC_OFFSET, reuse_chan->StartTime.Lo/1000.0f); + alSourcef(source, AL_SEC_OFFSET, reuse_chan->StartTime.Lo/1000.f); else { // FIXME: set offset based on the current time and the StartTime - alSourcef(source, AL_SEC_OFFSET, 0.0f); + alSourcef(source, AL_SEC_OFFSET, 0.f); } } if(getALError() != AL_NO_ERROR) @@ -2154,10 +2098,10 @@ FISoundChannel *OpenALSoundRenderer::StartSound(SoundHandle sfx, float vol, int else chan->SysChannel = &source; chan->Rolloff.RolloffType = ROLLOFF_Linear; - chan->Rolloff.MaxDistance = 2.0f; - chan->Rolloff.MinDistance = 1.0f; - chan->DistanceScale = 1.0f; - chan->DistanceSqr = (2.0f-vol)*(2.0f-vol); + chan->Rolloff.MaxDistance = 2.f; + chan->Rolloff.MinDistance = 1.f; + chan->DistanceScale = 1.f; + chan->DistanceSqr = (2.f-vol)*(2.f-vol); chan->ManualGain = true; return chan; @@ -2193,14 +2137,14 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener ALuint &source = *find(Sources.begin(), Sources.end(), FreeSfx.back()); alSource3f(source, AL_POSITION, pos[0], pos[1], -pos[2]); alSource3f(source, AL_VELOCITY, vel[0], vel[1], -vel[2]); - alSource3f(source, AL_DIRECTION, 0.0f, 0.0f, 0.0f); + alSource3f(source, AL_DIRECTION, 0.f, 0.f, 0.f); alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); - alSourcei(source, AL_LOOPING, (chanflags&SNDF_LOOP)?AL_TRUE:AL_FALSE); + alSourcei(source, AL_LOOPING, (chanflags&SNDF_LOOP) ? AL_TRUE : AL_FALSE); // Multi-channel sources won't attenuate in OpenAL, and "area sounds" have // special rolloff properties (they have a panning radius of 32 units, but - // starts attenuating at MinDistance). + // start attenuating at MinDistance). if(channels == 1 && !(chanflags&SNDF_AREA)) { if(rolloff->RolloffType == ROLLOFF_Log) @@ -2208,31 +2152,31 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener if(SrcDistanceModel) alSourcei(source, AL_DISTANCE_MODEL, AL_INVERSE_DISTANCE); alSourcef(source, AL_REFERENCE_DISTANCE, rolloff->MinDistance/distscale); - alSourcef(source, AL_MAX_DISTANCE, (1000.0f+rolloff->MinDistance)/distscale); + alSourcef(source, AL_MAX_DISTANCE, (1000.f+rolloff->MinDistance)/distscale); rolloffFactor = rolloff->RolloffFactor; manualGain = false; - gain = 1.0f; + gain = 1.f; } else if(rolloff->RolloffType == ROLLOFF_Linear && SrcDistanceModel) { alSourcei(source, AL_DISTANCE_MODEL, AL_LINEAR_DISTANCE); alSourcef(source, AL_REFERENCE_DISTANCE, rolloff->MinDistance/distscale); alSourcef(source, AL_MAX_DISTANCE, rolloff->MaxDistance/distscale); - rolloffFactor = 1.0f; + rolloffFactor = 1.f; manualGain = false; - gain = 1.0f; + gain = 1.f; } } if(manualGain) { if(SrcDistanceModel) alSourcei(source, AL_DISTANCE_MODEL, AL_NONE); - if((chanflags&SNDF_AREA) && rolloff->MinDistance < 32.0f) - alSourcef(source, AL_REFERENCE_DISTANCE, 32.0f/distscale); + if((chanflags&SNDF_AREA) && rolloff->MinDistance < 32.f) + alSourcef(source, AL_REFERENCE_DISTANCE, 32.f/distscale); else alSourcef(source, AL_REFERENCE_DISTANCE, rolloff->MinDistance/distscale); - alSourcef(source, AL_MAX_DISTANCE, (1000.0f+rolloff->MinDistance)/distscale); - rolloffFactor = 0.0f; + alSourcef(source, AL_MAX_DISTANCE, (1000.f+rolloff->MinDistance)/distscale); + rolloffFactor = 0.f; gain = GetRolloff(rolloff, sqrt(dist_sqr)); } alSourcef(source, AL_ROLLOFF_FACTOR, rolloffFactor); @@ -2251,25 +2195,26 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener { alSourcei(source, AL_DIRECT_FILTER, AL_FILTER_NULL); alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL); - alSourcef(source, AL_AIR_ABSORPTION_FACTOR, 0.0f); + alSourcef(source, AL_AIR_ABSORPTION_FACTOR, 0.f); } alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, rolloffFactor); alSourcef(source, AL_PITCH, PITCH(pitch)); } - else if(LastWaterAbsorb > 0.0f && !(chanflags&SNDF_NOREVERB)) + else if(LastWaterAbsorb > 0.f && !(chanflags&SNDF_NOREVERB)) alSourcef(source, AL_PITCH, PITCH(pitch)*PITCH_MULT); else alSourcef(source, AL_PITCH, PITCH(pitch)); + if(!reuse_chan) - alSourcef(source, AL_SEC_OFFSET, 0.0f); + alSourcef(source, AL_SEC_OFFSET, 0.f); else { if((chanflags&SNDF_ABSTIME)) - alSourcef(source, AL_SEC_OFFSET, reuse_chan->StartTime.Lo/1000.0f); + alSourcef(source, AL_SEC_OFFSET, reuse_chan->StartTime.Lo/1000.f); else { // FIXME: set offset based on the current time and the StartTime - alSourcef(source, AL_SAMPLE_OFFSET, 0.0f); + alSourcef(source, AL_SAMPLE_OFFSET, 0.f); } } if(getALError() != AL_NO_ERROR) @@ -2443,12 +2388,12 @@ void OpenALSoundRenderer::UpdateListener(SoundListener *listener) ALfloat orient[6]; // forward orient[0] = cos(angle); - orient[1] = 0.0f; + orient[1] = 0.f; orient[2] = -sin(angle); // up - orient[3] = 0.0f; - orient[4] = 1.0f; - orient[5] = 0.0f; + orient[3] = 0.f; + orient[4] = 1.f; + orient[5] = 0.f; alListenerfv(AL_ORIENTATION, orient); alListener3f(AL_POSITION, listener->position.X, @@ -2496,8 +2441,8 @@ void OpenALSoundRenderer::UpdateListener(SoundListener *listener) alFilterf(EnvFilters[0], AL_LOWPASS_GAIN, 0.25f); alFilterf(EnvFilters[0], AL_LOWPASS_GAINHF, 0.75f); - alFilterf(EnvFilters[1], AL_LOWPASS_GAIN, 1.0f); - alFilterf(EnvFilters[1], AL_LOWPASS_GAINHF, 1.0f); + alFilterf(EnvFilters[1], AL_LOWPASS_GAIN, 1.f); + alFilterf(EnvFilters[1], AL_LOWPASS_GAINHF, 1.f); // Apply the updated filters on the sources foreach(ALuint, i, ReverbSfx) @@ -2517,21 +2462,21 @@ void OpenALSoundRenderer::UpdateListener(SoundListener *listener) } else { - if(LastWaterAbsorb > 0.0f) + if(LastWaterAbsorb > 0.f) { - LastWaterAbsorb = 0.0f; + LastWaterAbsorb = 0.f; if(EnvSlot != 0) { LoadReverb(env); - alFilterf(EnvFilters[0], AL_LOWPASS_GAIN, 1.0f); - alFilterf(EnvFilters[0], AL_LOWPASS_GAINHF, 1.0f); - alFilterf(EnvFilters[1], AL_LOWPASS_GAIN, 1.0f); - alFilterf(EnvFilters[1], AL_LOWPASS_GAINHF, 1.0f); + alFilterf(EnvFilters[0], AL_LOWPASS_GAIN, 1.f); + alFilterf(EnvFilters[0], AL_LOWPASS_GAINHF, 1.f); + alFilterf(EnvFilters[1], AL_LOWPASS_GAIN, 1.f); + alFilterf(EnvFilters[1], AL_LOWPASS_GAINHF, 1.f); foreach(ALuint, i, ReverbSfx) { - alSourcef(*i, AL_AIR_ABSORPTION_FACTOR, 0.0f); + alSourcef(*i, AL_AIR_ABSORPTION_FACTOR, 0.f); alSourcei(*i, AL_DIRECT_FILTER, EnvFilters[0]); alSource3i(*i, AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); } @@ -2539,7 +2484,7 @@ void OpenALSoundRenderer::UpdateListener(SoundListener *listener) else { foreach(ALuint, i, ReverbSfx) - alSourcef(*i, AL_PITCH, 1.0f); + alSourcef(*i, AL_PITCH, 1.f); } getALError(); } @@ -2581,10 +2526,10 @@ void OpenALSoundRenderer::MarkStartTime(FISoundChannel *chan) float OpenALSoundRenderer::GetAudibility(FISoundChannel *chan) { if(chan == NULL || chan->SysChannel == NULL) - return 0.0f; + return 0.f; ALuint source = *((ALuint*)chan->SysChannel); - ALfloat volume = 0.0f; + ALfloat volume = 0.f; if(!chan->ManualGain) volume = SfxVolume * GetRolloff(&chan->Rolloff, sqrt(chan->DistanceSqr)); @@ -2602,7 +2547,7 @@ void OpenALSoundRenderer::PrintStatus() Printf("Output device: "TEXTCOLOR_ORANGE"%s\n", alcGetString(Device, ALC_DEVICE_SPECIFIER)); getALCError(Device); - ALCint frequency=0, major=0, minor=0, mono=0, stereo=0; + ALCint frequency, major, minor, mono, stereo; alcGetIntegerv(Device, ALC_FREQUENCY, 1, &frequency); alcGetIntegerv(Device, ALC_MAJOR_VERSION, 1, &major); alcGetIntegerv(Device, ALC_MINOR_VERSION, 1, &minor); @@ -2663,11 +2608,11 @@ void OpenALSoundRenderer::PrintDriversList() return; } - Printf("%c%s%d. %s\n", ' ', (!(*snd_aldevice)[0] ? TEXTCOLOR_BOLD : ""), 0, + Printf("%c%s%2d. %s\n", ' ', ((snd_aldevice=="Default") ? TEXTCOLOR_BOLD : ""), 0, "Default"); for(int i = 1;*drivers;i++) { - Printf("%c%s%d. %s\n", ((strcmp(current, drivers)==0) ? '*' : ' '), + Printf("%c%s%2d. %s\n", ((strcmp(current, drivers)==0) ? '*' : ' '), ((strcmp(*snd_aldevice, drivers)==0) ? TEXTCOLOR_BOLD : ""), i, drivers); drivers += strlen(drivers)+1; @@ -2740,7 +2685,7 @@ void OpenALSoundRenderer::LoadReverb(const ReverbContainer *env) ALint type = AL_EFFECT_NULL; alGetEffecti(envReverb, AL_EFFECT_TYPE, &type); -#define mB2Gain(x) ((float)pow(10.0, (x)/2000.0)) +#define mB2Gain(x) ((float)pow(10., (x)/2000.)) if(type == AL_EFFECT_EAXREVERB) { ALfloat reflectpan[3] = { props.ReflectionsPan0, @@ -2750,8 +2695,8 @@ void OpenALSoundRenderer::LoadReverb(const ReverbContainer *env) props.ReverbPan2 }; #undef SETPARAM #define SETPARAM(e,t,v) alEffectf((e), AL_EAXREVERB_##t, clamp((v), AL_EAXREVERB_MIN_##t, AL_EAXREVERB_MAX_##t)) - SETPARAM(envReverb, DENSITY, props.Density/100.0f); - SETPARAM(envReverb, DIFFUSION, props.Diffusion/100.0f); + SETPARAM(envReverb, DENSITY, props.Density/100.f); + SETPARAM(envReverb, DIFFUSION, props.Diffusion/100.f); SETPARAM(envReverb, GAIN, mB2Gain(props.Room)); SETPARAM(envReverb, GAINHF, mB2Gain(props.RoomHF)); SETPARAM(envReverb, GAINLF, mB2Gain(props.RoomLF)); @@ -2779,8 +2724,8 @@ void OpenALSoundRenderer::LoadReverb(const ReverbContainer *env) else if(type == AL_EFFECT_REVERB) { #define SETPARAM(e,t,v) alEffectf((e), AL_REVERB_##t, clamp((v), AL_REVERB_MIN_##t, AL_REVERB_MAX_##t)) - SETPARAM(envReverb, DENSITY, props.Density/100.0f); - SETPARAM(envReverb, DIFFUSION, props.Diffusion/100.0f); + SETPARAM(envReverb, DENSITY, props.Density/100.f); + SETPARAM(envReverb, DIFFUSION, props.Diffusion/100.f); SETPARAM(envReverb, GAIN, mB2Gain(props.Room)); SETPARAM(envReverb, GAINHF, mB2Gain(props.RoomHF)); SETPARAM(envReverb, DECAY_TIME, props.DecayTime); diff --git a/src/sound/oalsound.h b/src/sound/oalsound.h index 08c3c65d12..53bee81814 100644 --- a/src/sound/oalsound.h +++ b/src/sound/oalsound.h @@ -7,8 +7,7 @@ #include "i_sound.h" #include "s_sound.h" -#include "m_menu.h" - +#include "menu/menu.h" #ifndef NO_OPENAL diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index ee624ed751..302c0f1cbd 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -1140,6 +1140,11 @@ OptionString SoundOutputsMac "No sound", "No sound" } +OptionString ALDevices +{ + // filled in by the sound code +} + OptionString OutputFormats { "PCM-8", "8-bit" @@ -1171,6 +1176,52 @@ OptionString Resamplers "Spline", "Spline" } + +OptionString SoundBackends +{ + "fmod", "FMOD" + "openal", "OpenAL" + "null", "No Sound" +} + + +OptionMenu FMODSoundItems +{ + Title "FMOD OPTIONS" + Slider "Underwater cutoff", "snd_waterlp", 0.0, 2000.0, 50.0 + IfOption(Windows) + { + Option "Output system", "snd_output", "SoundOutputsWindows" + } + IfOption(Unix) + { + Option "Output system", "snd_output", "SoundOutputsUnix" + } + IfOption(Mac) + { + Option "Output system", "snd_output", "SoundOutputsMac" + } + Option "Output format", "snd_output_format", "OutputFormats" + Option "Speaker mode", "snd_speakermode", "SpeakerModes" + Option "Resampler", "snd_resampler", "Resamplers" + Option "HRTF filter", "snd_hrtf", "OnOff" + StaticText " " + Option "Buffer size", "snd_buffersize", "BufferSizes" + Option "Buffer count", "snd_buffercount", "BufferCounts" +} + + +OptionMenu OpenALSoundItems +{ + Title "OPENAL OPTIONS" + Option "Playback device", "snd_aldevice", "ALDevices" + Option "Enable EFX", "snd_efx", "OnOff" + StaticText " " + StaticText "Requires EFX", 1 + Slider "Underwater absorption", "snd_waterabsorption", 0.0, 10.0, 0.5 +} + + OptionValue MidiDevices { // filled in by the sound code @@ -1185,28 +1236,14 @@ OptionMenu SoundOptions Option "MIDI device", "snd_mididevice", "MidiDevices" StaticText " " Option "Underwater reverb", "snd_waterreverb", "OnOff" - Slider "Underwater cutoff", "snd_waterlp", 0, 2000, 50 Option "Randomize pitches", "snd_pitched", "OnOff" Slider "Sound channels", "snd_channels", 8, 256, 8 StaticText " " - Command "Restart sound", "snd_reset" + Option "Sound backend", "snd_backend", "SoundBackends" + Submenu "FMOD options", "FMODSoundItems" + Submenu "OpenAL options", "OpenALSoundItems" StaticText " " - IfOption(Windows) - { - Option "Output system", "snd_output", "SoundOutputsWindows" - } - IfOption(Unix) - { - Option "Output system", "snd_output", "SoundOutputsUnix" - } - IfOption(Mac) - { - Option "Output system", "snd_output", "SoundOutputsMac" - } - Option "Output format", "snd_output_format", "OutputFormats" - Option "Speaker mode", "snd_speakermode", "SpeakerModes" - Option "Resampler", "snd_resampler", "Resamplers" - Option "HRTF filter", "snd_hrtf", "OnOff" + Command "Restart sound", "snd_reset" StaticText " " Submenu "Advanced options", "AdvSoundOptions" @@ -1223,8 +1260,6 @@ OptionMenu AdvSoundOptions { Title "ADVANCED SOUND OPTIONS" Option "Sample rate", "snd_samplerate", "SampleRates" - Option "Buffer size", "snd_buffersize", "BufferSizes" - Option "Buffer count", "snd_buffercount", "BufferCounts" StaticText " " StaticText "OPL Synthesis", 1 Option "Only emulate one OPL chip", "opl_onechip", "OnOff" From f3d05e2699388cd50857cb4cc88319be64fcd032 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 7 Nov 2010 07:17:57 +0000 Subject: [PATCH 03/88] - applied Chriss OpenAL patch to make it uzable without GStreamer. SVN r2984 (openal) --- src/CMakeLists.txt | 105 +++++++++++++++--------- src/sound/oalsound.cpp | 178 +++++++++++++++++++++++++++++------------ 2 files changed, 191 insertions(+), 92 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index af135b72cf..11df8be437 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -167,11 +167,15 @@ if( WIN32 ) message( STATUS "Looking for al.h - not found" ) endif( OPENAL_INCLUDE_DIR ) - if( NOT OPENAL_INCLUDE_DIR OR NOT GLIB_INCLUDE_DIR OR NOT GST_INCLUDE_DIR ) + if( NOT OPENAL_INCLUDE_DIR ) set( NO_OPENAL ON ) - else( NOT OPENAL_INCLUDE_DIR OR NOT GLIB_INCLUDE_DIR OR NOT GST_INCLUDE_DIR ) - include_directories( ${OPENAL_INCLUDE_DIR} ${GLIB_INCLUDE_DIR} ${GST_INCLUDE_DIR} ) - endif( NOT OPENAL_INCLUDE_DIR OR NOT GLIB_INCLUDE_DIR OR NOT GST_INCLUDE_DIR ) + else( NOT OPENAL_INCLUDE_DIR ) + include_directories( ${OPENAL_INCLUDE_DIR} ) + if( GLIB_INCLUDE_DIR AND GST_INCLUDE_DIR ) + include_directories( ${OPENAL_INCLUDE_DIR} ${GLIB_INCLUDE_DIR} ${GST_INCLUDE_DIR} ) + set( WITH_GSTREAMER ON ) + endif( GLIB_INCLUDE_DIR AND GST_INCLUDE_DIR ) + endif( NOT OPENAL_INCLUDE_DIR ) endif( NOT NO_OPENAL ) @@ -191,38 +195,51 @@ if( WIN32 ) oleaut32 ) if( NOT NO_OPENAL ) - message( STATUS "Looking for GST libraries" ) + message( STATUS "Looking for OpenAL library" ) find_library( OPENAL_LIBRARY NAMES OpenAL32 PATHS ${OPENAL_SEARCH_PATHS} PATH_SUFFIXES lib ) - find_library( GST_LIBRARY1 NAMES gstapp-0.10 - PATHS ${GST_SEARCH_PATHS} - PATH_SUFFIXES lib ) - find_library( GST_LIBRARY2 NAMES gstaudio-0.10 - PATHS ${GST_SEARCH_PATHS} - PATH_SUFFIXES lib ) - find_library( GST_LIBRARY3 NAMES gstreamer-0.10 - PATHS ${GST_SEARCH_PATHS} - PATH_SUFFIXES lib ) - find_library( GST_LIBRARY4 NAMES gthread-2.0 - PATHS ${GST_SEARCH_PATHS} - PATH_SUFFIXES lib ) - find_library( GST_LIBRARY5 NAMES gmodule-2.0 - PATHS ${GST_SEARCH_PATHS} - PATH_SUFFIXES lib ) - find_library( GST_LIBRARY6 NAMES gobject-2.0 - PATHS ${GST_SEARCH_PATHS} - PATH_SUFFIXES lib ) - find_library( GST_LIBRARY7 NAMES glib-2.0 - PATHS ${GST_SEARCH_PATHS} - PATH_SUFFIXES lib ) - if( OPENAL_LIBRARY AND GST_LIBRARY1 AND GST_LIBRARY2 AND GST_LIBRARY3 AND GST_LIBRARY4 AND GST_LIBRARY5 AND GST_LIBRARY6 AND GST_LIBRARY7 ) - set( ZDOOM_LIBS ${ZDOOM_LIBS} "${OPENAL_LIBRARY}" "${GST_LIBRARY1}" "${GST_LIBRARY2}" "${GST_LIBRARY3}" "${GST_LIBRARY4}" "${GST_LIBRARY5}" "${GST_LIBRARY6}" "${GST_LIBRARY7}" ) - message( STATUS "Looking for GST libraries - found" ) - else( OPENAL_LIBRARY AND GST_LIBRARY1 AND GST_LIBRARY2 AND GST_LIBRARY3 AND GST_LIBRARY4 AND GST_LIBRARY5 AND GST_LIBRARY6 AND GST_LIBRARY7 ) + + if( NOT OPENAL_LIBRARY ) set( NO_OPENAL ON ) - message( STATUS "Looking for GST libraries - not found" ) - endif( OPENAL_LIBRARY AND GST_LIBRARY1 AND GST_LIBRARY2 AND GST_LIBRARY3 AND GST_LIBRARY4 AND GST_LIBRARY5 AND GST_LIBRARY6 AND GST_LIBRARY7 ) + message( STATUS "Looking for OpenAL library - not found" ) + else( NOT OPENAL_LIBRARY ) + set( ZDOOM_LIBS ${ZDOOM_LIBS} "${OPENAL_LIBRARY}" ) + message( STATUS "Looking for OpenAL library - found" ) + endif( NOT OPENAL_LIBRARY ) + + if( WITH_GSTREAMER AND NOT NO_OPENAL ) + message( STATUS "Looking for GST libraries" ) + find_library( GST_LIBRARY1 NAMES gstapp-0.10 + PATHS ${GST_SEARCH_PATHS} + PATH_SUFFIXES lib ) + find_library( GST_LIBRARY2 NAMES gstaudio-0.10 + PATHS ${GST_SEARCH_PATHS} + PATH_SUFFIXES lib ) + find_library( GST_LIBRARY3 NAMES gstreamer-0.10 + PATHS ${GST_SEARCH_PATHS} + PATH_SUFFIXES lib ) + find_library( GST_LIBRARY4 NAMES gthread-2.0 + PATHS ${GST_SEARCH_PATHS} + PATH_SUFFIXES lib ) + find_library( GST_LIBRARY5 NAMES gmodule-2.0 + PATHS ${GST_SEARCH_PATHS} + PATH_SUFFIXES lib ) + find_library( GST_LIBRARY6 NAMES gobject-2.0 + PATHS ${GST_SEARCH_PATHS} + PATH_SUFFIXES lib ) + find_library( GST_LIBRARY7 NAMES glib-2.0 + PATHS ${GST_SEARCH_PATHS} + PATH_SUFFIXES lib ) + + if( GST_LIBRARY1 AND GST_LIBRARY2 AND GST_LIBRARY3 AND GST_LIBRARY4 AND GST_LIBRARY5 AND GST_LIBRARY6 AND GST_LIBRARY7 ) + set( ZDOOM_LIBS ${ZDOOM_LIBS} "${GST_LIBRARY1}" "${GST_LIBRARY2}" "${GST_LIBRARY3}" "${GST_LIBRARY4}" "${GST_LIBRARY5}" "${GST_LIBRARY6}" "${GST_LIBRARY7}" ) + message( STATUS "Looking for GST libraries - found" ) + else( GST_LIBRARY1 AND GST_LIBRARY2 AND GST_LIBRARY3 AND GST_LIBRARY4 AND GST_LIBRARY5 AND GST_LIBRARY6 AND GST_LIBRARY7 ) + set( WITH_GSTREAMER OFF ) + message( STATUS "Looking for GST libraries - not found" ) + endif( GST_LIBRARY1 AND GST_LIBRARY2 AND GST_LIBRARY3 AND GST_LIBRARY4 AND GST_LIBRARY5 AND GST_LIBRARY6 AND GST_LIBRARY7 ) + endif( WITH_GSTREAMER AND NOT NO_OPENAL ) endif( NOT NO_OPENAL ) else( WIN32 ) if( APPLE ) @@ -232,12 +249,13 @@ else( WIN32 ) set( NO_GTK ON ) if( NOT NO_OPENAL ) + set( ZDOOM_LIBS ${ZDOOM_LIBS} "-framework OpenAL") + check_library_exists( gstapp-0.10 gst_app_src_set_callbacks "" HAS_GSTAPP ) check_library_exists( gstaudio-0.10 gst_audio_set_channel_positions "" HAS_GSTAUDIO ) if( HAS_GSTAPP AND HAS_GSTAUDIO ) set( ZDOOM_LIBS ${ZDOOM_LIBS} gstapp-0.10 gst-audio-0.10 "-framework OpenAL") - else( HAS_GSTAPP AND HAS_GSTAUDIO ) - set( NO_OPENAL ON ) + set( WITH_GSTREAMER ON ) endif( HAS_GSTAPP AND HAS_GSTAUDIO ) endif( NOT NO_OPENAL ) else( APPLE ) @@ -266,13 +284,20 @@ else( WIN32 ) endif( GTK2_FOUND ) endif( NOT NO_GTK ) - pkg_check_modules( OPENAL openal gstreamer-app-0.10>=0.10.23 gstreamer-audio-0.10 ) - if( OPENAL_FOUND ) + pkg_check_modules( OPENAL openal ) + if( NOT OPENAL_FOUND ) + set( NO_OPENAL ON ) + else( NOT OPENAL_FOUND ) set( ZDOOM_LIBS ${ZDOOM_LIBS} ${OPENAL_LIBRARIES} ) include_directories( ${OPENAL_INCLUDE_DIRS} ) - else( OPENAL_FOUND ) - set( NO_OPENAL ON ) - endif( OPENAL_FOUND ) + + pkg_check_modules( GSTREAMER gstreamer-app-0.10>=0.10.23 gstreamer-audio-0.10 ) + if( GSTREAMER_FOUND ) + set( ZDOOM_LIBS ${ZDOOM_LIBS} ${GSTREAMER_LIBRARIES} ) + include_directories( ${GSTREAMER_INCLUDE_DIRS} ) + set( WITH_GSTREAMER ON ) + endif( GSTREAMER_FOUND ) + endif( NOT OPENAL_FOUND ) endif( APPLE ) set( NASM_NAMES nasm ) @@ -357,6 +382,8 @@ if( NO_FMOD ) endif( NO_FMOD ) if( NO_OPENAL ) add_definitions( -DNO_OPENAL=1 ) +elseif( WITH_GSTREAMER ) + add_definitions( -DWITH_GSTREAMER=1 ) endif( NO_OPENAL ) # Search for FluidSynth diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index d64b230e9b..7bed39a862 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -177,7 +177,40 @@ static float GetRolloff(const FRolloffInfo *rolloff, float distance) } -/*** GStreamer start ***/ +static ALenum FormatFromDesc(int bits, int channels) +{ + if(bits == 8) + { + if(channels == 1) return AL_FORMAT_MONO8; + if(channels == 2) return AL_FORMAT_STEREO8; + if(channels == 4) return AL_FORMAT_QUAD8; + if(channels == 6) return AL_FORMAT_51CHN8; + if(channels == 7) return AL_FORMAT_61CHN8; + if(channels == 8) return AL_FORMAT_71CHN8; + } + if(bits == 16) + { + if(channels == 1) return AL_FORMAT_MONO16; + if(channels == 2) return AL_FORMAT_STEREO16; + if(channels == 4) return AL_FORMAT_QUAD16; + if(channels == 6) return AL_FORMAT_51CHN16; + if(channels == 7) return AL_FORMAT_61CHN16; + if(channels == 8) return AL_FORMAT_71CHN16; + } + if(bits == 32) + { + if(channels == 1) return AL_FORMAT_MONO_FLOAT32; + if(channels == 2) return AL_FORMAT_STEREO_FLOAT32; + if(channels == 4) return AL_FORMAT_QUAD32; + if(channels == 6) return AL_FORMAT_51CHN32; + if(channels == 7) return AL_FORMAT_61CHN32; + if(channels == 8) return AL_FORMAT_71CHN32; + } + return AL_NONE; +} + + +#ifdef WITH_GSTREAMER #include #include #include @@ -358,38 +391,6 @@ static GstCaps *SupportedBufferFormatCaps(int forcebits=0) return caps; } -static ALenum FormatFromDesc(int bits, int channels) -{ - if(bits == 8) - { - if(channels == 1) return AL_FORMAT_MONO8; - if(channels == 2) return AL_FORMAT_STEREO8; - if(channels == 4) return AL_FORMAT_QUAD8; - if(channels == 6) return AL_FORMAT_51CHN8; - if(channels == 7) return AL_FORMAT_61CHN8; - if(channels == 8) return AL_FORMAT_71CHN8; - } - if(bits == 16) - { - if(channels == 1) return AL_FORMAT_MONO16; - if(channels == 2) return AL_FORMAT_STEREO16; - if(channels == 4) return AL_FORMAT_QUAD16; - if(channels == 6) return AL_FORMAT_51CHN16; - if(channels == 7) return AL_FORMAT_61CHN16; - if(channels == 8) return AL_FORMAT_71CHN16; - } - if(bits == 32) - { - if(channels == 1) return AL_FORMAT_MONO_FLOAT32; - if(channels == 2) return AL_FORMAT_STEREO_FLOAT32; - if(channels == 4) return AL_FORMAT_QUAD32; - if(channels == 6) return AL_FORMAT_51CHN32; - if(channels == 7) return AL_FORMAT_61CHN32; - if(channels == 8) return AL_FORMAT_71CHN32; - } - return AL_NONE; -} - class OpenALSoundStream : public SoundStream { OpenALSoundRenderer *Renderer; @@ -783,18 +784,21 @@ class OpenALSoundStream : public SoundStream { PrintErrMsg("Prepare Error", msg); ret = GST_STATE_CHANGE_FAILURE; + gst_message_unref(msg); break; } - else if(GST_MESSAGE_TYPE(msg) == GST_MESSAGE_TAG) + else if(GST_MESSAGE_TYPE(msg) != GST_MESSAGE_TAG) { - GstTagList *tags = NULL; - gst_message_parse_tag(msg, &tags); - - gst_tag_list_insert(TagList, tags, GST_TAG_MERGE_KEEP); - - gst_tag_list_free(tags); + gst_message_unref(msg); + break; } - else break; + + GstTagList *tags = NULL; + gst_message_parse_tag(msg, &tags); + + gst_tag_list_insert(TagList, tags, GST_TAG_MERGE_KEEP); + + gst_tag_list_free(tags); gst_message_unref(msg); } } @@ -1403,22 +1407,22 @@ public: if(GST_MESSAGE_TYPE(msg) == GST_MESSAGE_EOS) { err = false; + gst_message_unref(msg); break; } - else if(GST_MESSAGE_TYPE(msg) == GST_MESSAGE_TAG) - { - GstTagList *tags = NULL; - gst_message_parse_tag(msg, &tags); - - gst_tag_list_insert(TagList, tags, GST_TAG_MERGE_KEEP); - - gst_tag_list_free(tags); - } - else if(GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) + if(GST_MESSAGE_TYPE(msg) != GST_MESSAGE_TAG) { PrintErrMsg("Decoder Error", msg); + gst_message_unref(msg); break; } + + GstTagList *tags = NULL; + gst_message_parse_tag(msg, &tags); + + gst_tag_list_insert(TagList, tags, GST_TAG_MERGE_KEEP); + + gst_tag_list_free(tags); gst_message_unref(msg); } } @@ -1437,8 +1441,8 @@ public: unsigned int looppt[2] = { 0, 0 }; bool looppt_is_samples[2] = { true, true }; bool has_looppt[2] = { false, false }; - HandleLoopTags(looppt, looppt_is_samples, has_looppt); + HandleLoopTags(looppt, looppt_is_samples, has_looppt); if(has_looppt[0] || has_looppt[1]) { if(!has_looppt[0]) @@ -1467,7 +1471,73 @@ public: return !err; } }; -/*** GStreamer end ***/ +#else /* WITH_GSTREAMER */ +class OpenALSoundStream : public SoundStream +{ + OpenALSoundRenderer *Renderer; + +public: + FTempFileName tmpfile; + ALfloat Volume; + + OpenALSoundStream(OpenALSoundRenderer *renderer) + : Renderer(renderer), Volume(1.0f) + { Renderer->Streams.push_back(this); } + + virtual ~OpenALSoundStream() + { + Renderer->Streams.erase(find(Renderer->Streams.begin(), + Renderer->Streams.end(), this)); + Renderer = NULL; + } + + + virtual bool Play(bool, float) + { return false; } + + virtual void Stop() + { } + + virtual void SetVolume(float vol) + { Volume = vol; } + + virtual bool SetPaused(bool) + { return false; } + + virtual unsigned int GetPosition() + { return 0; } + + virtual bool IsEnded() + { return true; } + + bool Init(const char*) + { return false; } + + bool Init(const BYTE*, unsigned int) + { return false; } + + bool Init(SoundStreamCallback, int, int, int, void*) + { return false; } +}; + +class Decoder +{ +public: + std::vector OutData; + ALint LoopPts[2]; + ALsizei OutRate; + ALuint OutChannels; + ALuint OutBits; + + Decoder() + : OutRate(0), OutChannels(0), OutBits(0) + { LoopPts[0] = LoopPts[1] = 0; } + + bool Decode(const void*, unsigned int, int=0) + { return false; } +}; +#endif /* WITH_GSTREAMER */ + template static void LoadALFunc(const char *name, T *x) @@ -1481,6 +1551,7 @@ OpenALSoundRenderer::OpenALSoundRenderer() Printf("I_InitSound: Initializing OpenAL\n"); +#ifdef WITH_GSTREAMER static bool GSTInited = false; if(!GSTInited) { @@ -1493,6 +1564,7 @@ OpenALSoundRenderer::OpenALSoundRenderer() } GSTInited = true; } +#endif if(snd_aldevice != "Default") { From b31a729ab83aa03bf6f8248c626136e27483fed6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 29 Jun 2013 22:44:46 -0700 Subject: [PATCH 04/88] Fix compilation with OpenAL --- src/sound/oalsound.cpp | 45 +++++++++++++++++++++++++++++------------- src/sound/oalsound.h | 7 +++++-- 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 7bed39a862..bddbcdb483 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -1817,7 +1817,7 @@ void OpenALSoundRenderer::SetSfxVolume(float volume) alSourcef(source, AL_MAX_GAIN, volume); if(schan->ManualGain) volume *= GetRolloff(&schan->Rolloff, sqrt(schan->DistanceSqr)); - alSourcef(source, AL_GAIN, volume); + alSourcef(source, AL_GAIN, volume * ((FSoundChan*)schan)->Volume); } schan = schan->NextChan; } @@ -1866,7 +1866,7 @@ float OpenALSoundRenderer::GetOutputRate() } -SoundHandle OpenALSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int length, int frequency, int channels, int bits, int loopstart) +SoundHandle OpenALSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int length, int frequency, int channels, int bits, int loopstart, int loopend) { SoundHandle retval = { NULL }; @@ -1911,17 +1911,19 @@ SoundHandle OpenALSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int length, int fre return retval; } - if(loopstart > 0 && LoopPoints) + if((loopstart > 0 || loopend > 0) && LoopPoints) { - ALint loops[2] = { - loopstart, - length / (channels*bits/8) - }; + if(loopstart < 0) + loopstart = 0; + if(loopend < loopstart) + loopend = length / (channels*bits/8); + + ALint loops[2] = { loopstart, loopend }; Printf("Setting loop points %d -> %d\n", loops[0], loops[1]); alBufferiv(buffer, AL_LOOP_POINTS, loops); getALError(); } - else if(loopstart > 0) + else if(loopstart > 0 || loopend > 0) { static bool warned = false; if(!warned) @@ -2170,11 +2172,11 @@ FISoundChannel *OpenALSoundRenderer::StartSound(SoundHandle sfx, float vol, int else chan->SysChannel = &source; chan->Rolloff.RolloffType = ROLLOFF_Linear; - chan->Rolloff.MaxDistance = 2.f; + chan->Rolloff.MaxDistance = 1000.f; chan->Rolloff.MinDistance = 1.f; chan->DistanceScale = 1.f; - chan->DistanceSqr = (2.f-vol)*(2.f-vol); - chan->ManualGain = true; + chan->DistanceSqr = 1.f; + chan->ManualGain = false; return chan; } @@ -2321,6 +2323,20 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener return chan; } +void OpenALSoundRenderer::ChannelVolume(FISoundChannel *chan, float volume) +{ + if(chan == NULL || chan->SysChannel == NULL) + return; + + alcSuspendContext(Context); + + ALuint source = *((ALuint*)chan->SysChannel); + + if(chan->ManualGain) + volume *= GetRolloff(&chan->Rolloff, sqrt(chan->DistanceSqr)); + alSourcef(source, AL_GAIN, SfxVolume * volume); +} + void OpenALSoundRenderer::StopChannel(FISoundChannel *chan) { if(chan == NULL || chan->SysChannel == NULL) @@ -2384,7 +2400,7 @@ void OpenALSoundRenderer::SetSfxPaused(bool paused, int slot) } } -void OpenALSoundRenderer::SetInactive(bool inactive) +void OpenALSoundRenderer::SetInactive(EInactiveState) { } @@ -2443,7 +2459,7 @@ void OpenALSoundRenderer::UpdateSoundParams3D(SoundListener *listener, FISoundCh if(chan->ManualGain) { float gain = GetRolloff(&chan->Rolloff, sqrt(chan->DistanceSqr)); - alSourcef(source, AL_GAIN, SfxVolume*gain); + alSourcef(source, AL_GAIN, SfxVolume*gain*((FSoundChan*)chan)->Volume); } getALError(); @@ -2604,7 +2620,8 @@ float OpenALSoundRenderer::GetAudibility(FISoundChannel *chan) ALfloat volume = 0.f; if(!chan->ManualGain) - volume = SfxVolume * GetRolloff(&chan->Rolloff, sqrt(chan->DistanceSqr)); + volume = SfxVolume * ((FSoundChan*)chan)->Volume * + GetRolloff(&chan->Rolloff, sqrt(chan->DistanceSqr)); else { alGetSourcef(source, AL_GAIN, &volume); diff --git a/src/sound/oalsound.h b/src/sound/oalsound.h index 53bee81814..96304db915 100644 --- a/src/sound/oalsound.h +++ b/src/sound/oalsound.h @@ -82,7 +82,7 @@ public: virtual void SetSfxVolume(float volume); virtual void SetMusicVolume(float volume); virtual SoundHandle LoadSound(BYTE *sfxdata, int length); - virtual SoundHandle LoadSoundRaw(BYTE *sfxdata, int length, int frequency, int channels, int bits, int loopstart); + virtual SoundHandle LoadSoundRaw(BYTE *sfxdata, int length, int frequency, int channels, int bits, int loopstart, int loopend); virtual void UnloadSound(SoundHandle sfx); virtual unsigned int GetMSLength(SoundHandle sfx); virtual unsigned int GetSampleLength(SoundHandle sfx); @@ -96,6 +96,9 @@ public: virtual FISoundChannel *StartSound(SoundHandle sfx, float vol, int pitch, int chanflags, FISoundChannel *reuse_chan); virtual FISoundChannel *StartSound3D(SoundHandle sfx, SoundListener *listener, float vol, FRolloffInfo *rolloff, float distscale, int pitch, int priority, const FVector3 &pos, const FVector3 &vel, int channum, int chanflags, FISoundChannel *reuse_chan); + // Changes a channel's volume. + virtual void ChannelVolume(FISoundChannel *chan, float volume); + // Stops a sound channel. virtual void StopChannel(FISoundChannel *chan); @@ -109,7 +112,7 @@ public: virtual void SetSfxPaused(bool paused, int slot); // Pauses or resumes *every* channel, including environmental reverb. - virtual void SetInactive(bool inactive); + virtual void SetInactive(EInactiveState state); // Updates the volume, separation, and pitch of a sound channel. virtual void UpdateSoundParams3D(SoundListener *listener, FISoundChannel *chan, bool areasound, const FVector3 &pos, const FVector3 &vel); From 4f2e367ec6dccdb74b6dcd5f9d725fdf4ca8125f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 30 Jun 2013 01:07:09 -0700 Subject: [PATCH 05/88] Remove GStreamer support --- CMakeLists.txt | 4 +- src/CMakeLists.txt | 144 +---- src/sound/oalsound.cpp | 1278 ---------------------------------------- src/sound/oalsound.h | 12 +- 4 files changed, 14 insertions(+), 1424 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e34ebf779..fcd372d3c2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,8 +16,8 @@ endif( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" S set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}") -option( NO_FMOD "Disable FMODEx sound support" ) -option( NO_OPENAL "Disable OpenAL sound support" ) +option( NO_FMOD "Disable FMODEx sound support" OFF ) +option( NO_OPENAL "Disable OpenAL sound support" OFF ) find_package( BZip2 ) find_package( JPEG ) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9c77b9e3b4..822f103312 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -121,64 +121,6 @@ if( WIN32 ) message( FATAL_ERROR "Could not find DirectX 9 libraries" ) endif( NOT DX_LIBS_FOUND ) - - if( NOT NO_OPENAL ) - SET( GST_SEARCH_PATHS - ENV GSTSDK_DIR - ENV MINGDIR - "C:/Program Files/gstreamer" - "C:/gstreamer" ) - - message( STATUS "Looking for glib.h" ) - find_path( GLIB_INCLUDE_DIR glib.h - PATHS ${GST_SEARCH_PATHS} - PATH_SUFFIXES include include/glib-2.0 ) - if( GLIB_INCLUDE_DIR ) - message(STATUS "Looking for glib.h - found: ${GLIB_INCLUDE_DIR}") - else( GLIB_INCLUDE_DIR ) - message(STATUS "Looking for glib.h - not found") - endif( GLIB_INCLUDE_DIR ) - - message( STATUS "Looking for gst/gst.h" ) - find_path( GST_INCLUDE_DIR gst/gst.h - PATHS ${GST_SEARCH_PATHS} - PATH_SUFFIXES include include/gstreamer-0.10 ) - if( GST_INCLUDE_DIR ) - message( STATUS "Looking for gst/gst.h - found: ${GST_INCLUDE_DIR}" ) - else( GST_INCLUDE_DIR ) - message( STATUS "Looking for gst/gst.h - not found" ) - endif( GST_INCLUDE_DIR ) - - message( STATUS "Looking for al.h" ) - set( OPENAL_SEARCH_PATHS - ENV ALSDK_DIR - ENV MINGDIR - "C:/Program Files/OpenAL 1.1 SDK" - "C:/Program Files (x86)/OpenAL 1.1 SDK" - "E:/Programs/Dev/OpenAL" - "E:/Program Files (x86)/OpenAL 1.1 SDK" ) - - find_path( OPENAL_INCLUDE_DIR al.h - PATHS ${OPENAL_SEARCH_PATHS} - PATH_SUFFIXES include include/AL ) - if( OPENAL_INCLUDE_DIR ) - message( STATUS "Looking for al.h - found: ${OPENAL_INCLUDE_DIR}" ) - else( OPENAL_INCLUDE_DIR ) - message( STATUS "Looking for al.h - not found" ) - endif( OPENAL_INCLUDE_DIR ) - - if( NOT OPENAL_INCLUDE_DIR ) - set( NO_OPENAL ON ) - else( NOT OPENAL_INCLUDE_DIR ) - include_directories( ${OPENAL_INCLUDE_DIR} ) - if( GLIB_INCLUDE_DIR AND GST_INCLUDE_DIR ) - include_directories( ${OPENAL_INCLUDE_DIR} ${GLIB_INCLUDE_DIR} ${GST_INCLUDE_DIR} ) - set( WITH_GSTREAMER ON ) - endif( GLIB_INCLUDE_DIR AND GST_INCLUDE_DIR ) - endif( NOT OPENAL_INCLUDE_DIR ) - endif( NOT NO_OPENAL ) - - set( ZDOOM_LIBS wsock32 winmm @@ -193,71 +135,12 @@ if( WIN32 ) ws2_32 setupapi oleaut32 ) - - if( NOT NO_OPENAL ) - message( STATUS "Looking for OpenAL library" ) - find_library( OPENAL_LIBRARY NAMES OpenAL32 - PATHS ${OPENAL_SEARCH_PATHS} - PATH_SUFFIXES lib ) - - if( NOT OPENAL_LIBRARY ) - set( NO_OPENAL ON ) - message( STATUS "Looking for OpenAL library - not found" ) - else( NOT OPENAL_LIBRARY ) - set( ZDOOM_LIBS ${ZDOOM_LIBS} "${OPENAL_LIBRARY}" ) - message( STATUS "Looking for OpenAL library - found" ) - endif( NOT OPENAL_LIBRARY ) - - if( WITH_GSTREAMER AND NOT NO_OPENAL ) - message( STATUS "Looking for GST libraries" ) - find_library( GST_LIBRARY1 NAMES gstapp-0.10 - PATHS ${GST_SEARCH_PATHS} - PATH_SUFFIXES lib ) - find_library( GST_LIBRARY2 NAMES gstaudio-0.10 - PATHS ${GST_SEARCH_PATHS} - PATH_SUFFIXES lib ) - find_library( GST_LIBRARY3 NAMES gstreamer-0.10 - PATHS ${GST_SEARCH_PATHS} - PATH_SUFFIXES lib ) - find_library( GST_LIBRARY4 NAMES gthread-2.0 - PATHS ${GST_SEARCH_PATHS} - PATH_SUFFIXES lib ) - find_library( GST_LIBRARY5 NAMES gmodule-2.0 - PATHS ${GST_SEARCH_PATHS} - PATH_SUFFIXES lib ) - find_library( GST_LIBRARY6 NAMES gobject-2.0 - PATHS ${GST_SEARCH_PATHS} - PATH_SUFFIXES lib ) - find_library( GST_LIBRARY7 NAMES glib-2.0 - PATHS ${GST_SEARCH_PATHS} - PATH_SUFFIXES lib ) - - if( GST_LIBRARY1 AND GST_LIBRARY2 AND GST_LIBRARY3 AND GST_LIBRARY4 AND GST_LIBRARY5 AND GST_LIBRARY6 AND GST_LIBRARY7 ) - set( ZDOOM_LIBS ${ZDOOM_LIBS} "${GST_LIBRARY1}" "${GST_LIBRARY2}" "${GST_LIBRARY3}" "${GST_LIBRARY4}" "${GST_LIBRARY5}" "${GST_LIBRARY6}" "${GST_LIBRARY7}" ) - message( STATUS "Looking for GST libraries - found" ) - else( GST_LIBRARY1 AND GST_LIBRARY2 AND GST_LIBRARY3 AND GST_LIBRARY4 AND GST_LIBRARY5 AND GST_LIBRARY6 AND GST_LIBRARY7 ) - set( WITH_GSTREAMER OFF ) - message( STATUS "Looking for GST libraries - not found" ) - endif( GST_LIBRARY1 AND GST_LIBRARY2 AND GST_LIBRARY3 AND GST_LIBRARY4 AND GST_LIBRARY5 AND GST_LIBRARY6 AND GST_LIBRARY7 ) - endif( WITH_GSTREAMER AND NOT NO_OPENAL ) - endif( NOT NO_OPENAL ) else( WIN32 ) if( APPLE ) set( FMOD_SEARCH_PATHS "/Developer/FMOD Programmers API Mac/api" ) set( FMOD_INC_PATH_SUFFIXES PATH_SUFFIXES inc ) set( FMOD_LIB_PATH_SUFFIXES PATH_SUFFIXES lib ) set( NO_GTK ON ) - - if( NOT NO_OPENAL ) - set( ZDOOM_LIBS ${ZDOOM_LIBS} "-framework OpenAL") - - check_library_exists( gstapp-0.10 gst_app_src_set_callbacks "" HAS_GSTAPP ) - check_library_exists( gstaudio-0.10 gst_audio_set_channel_positions "" HAS_GSTAUDIO ) - if( HAS_GSTAPP AND HAS_GSTAUDIO ) - set( ZDOOM_LIBS ${ZDOOM_LIBS} gstapp-0.10 gst-audio-0.10 "-framework OpenAL") - set( WITH_GSTREAMER ON ) - endif( HAS_GSTAPP AND HAS_GSTAUDIO ) - endif( NOT NO_OPENAL ) else( APPLE ) option( NO_GTK "Disable GTK+ dialogs (Not applicable to Windows)" ) option( VALGRIND "Add special Valgrind sequences to self-modifying code" ) @@ -284,21 +167,6 @@ else( WIN32 ) endif( GTK2_FOUND ) endif( NOT NO_GTK ) - pkg_check_modules( OPENAL openal ) - if( NOT OPENAL_FOUND ) - set( NO_OPENAL ON ) - else( NOT OPENAL_FOUND ) - set( ZDOOM_LIBS ${ZDOOM_LIBS} ${OPENAL_LIBRARIES} ) - include_directories( ${OPENAL_INCLUDE_DIRS} ) - - pkg_check_modules( GSTREAMER gstreamer-app-0.10>=0.10.23 gstreamer-audio-0.10 ) - if( GSTREAMER_FOUND ) - set( ZDOOM_LIBS ${ZDOOM_LIBS} ${GSTREAMER_LIBRARIES} ) - include_directories( ${GSTREAMER_INCLUDE_DIRS} ) - set( WITH_GSTREAMER ON ) - endif( GSTREAMER_FOUND ) - endif( NOT OPENAL_FOUND ) - # Check for Xcursor library and header files find_library( XCURSOR_LIB Xcursor ) if( XCURSOR_LIB ) @@ -334,6 +202,16 @@ else( WIN32 ) endif( WIN32 ) +if( NOT NO_OPENAL ) + find_package( OpenAL ) + if( OPENAL_FOUND ) + include_directories( ${OPENAL_INCLUDE_DIR} ) + set( ZDOOM_LIBS ${OPENAL_LIBRARY} ${ZDOOM_LIBS} ) + else( OPENAL_FOUND ) + set( NO_OPENAL ON ) + endif( OPENAL_FOUND ) +endif( NOT NO_OPENAL ) + if( NOT NO_FMOD ) # Search for FMOD include files if( NOT WIN32 ) @@ -395,8 +273,6 @@ if( NO_FMOD ) endif( NO_FMOD ) if( NO_OPENAL ) add_definitions( -DNO_OPENAL=1 ) -elseif( WITH_GSTREAMER ) - add_definitions( -DWITH_GSTREAMER=1 ) endif( NO_OPENAL ) # Search for FluidSynth diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index bddbcdb483..5bbd245227 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -210,1268 +210,6 @@ static ALenum FormatFromDesc(int bits, int channels) } -#ifdef WITH_GSTREAMER -#include -#include -#include -#include -#include - -/* Bad GStreamer, using enums for bit fields... */ -static GstMessageType operator|(const GstMessageType &a, const GstMessageType &b) -{ return GstMessageType((unsigned)a|(unsigned)b); } -static GstSeekFlags operator|(const GstSeekFlags &a, const GstSeekFlags &b) -{ return GstSeekFlags((unsigned)a|(unsigned)b); } - -static void PrintErrMsg(const char *str, GstMessage *msg) -{ - GError *error; - gchar *debug; - - gst_message_parse_error(msg, &error, &debug); - Printf("%s: %s\n", str, error->message); - DPrintf("%s\n", debug); - - g_error_free(error); - g_free(debug); -} - -static GstCaps *SupportedBufferFormatCaps(int forcebits=0) -{ - GstStructure *structure; - GstCaps *caps; - - caps = gst_caps_new_empty(); - if(alIsExtensionPresent("AL_EXT_MCFORMATS")) - { - static const struct { - gint count; - GstAudioChannelPosition pos[8]; - } chans[] = { - { 1, - { GST_AUDIO_CHANNEL_POSITION_FRONT_MONO } }, - { 2, - { GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, - GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT } }, - { 4, - { GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, - GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, - GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, - GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT } }, - { 6, - { GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, - GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, - GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, - GST_AUDIO_CHANNEL_POSITION_LFE, - GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, - GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT } }, - { 7, - { GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, - GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, - GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, - GST_AUDIO_CHANNEL_POSITION_LFE, - GST_AUDIO_CHANNEL_POSITION_REAR_CENTER, - GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT, - GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT } }, - { 8, - { GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, - GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, - GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, - GST_AUDIO_CHANNEL_POSITION_LFE, - GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, - GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, - GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT, - GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT } }, - }; - static const char *fmt32[] = { - "AL_FORMAT_MONO_FLOAT32", "AL_FORMAT_STEREO_FLOAT32", "AL_FORMAT_QUAD32", - "AL_FORMAT_51CHN32", "AL_FORMAT_61CHN32", "AL_FORMAT_71CHN32", NULL - }; - static const char *fmt16[] = { - "AL_FORMAT_MONO16", "AL_FORMAT_STEREO16", "AL_FORMAT_QUAD16", - "AL_FORMAT_51CHN16", "AL_FORMAT_61CHN16", "AL_FORMAT_71CHN16", NULL - }; - static const char *fmt8[] = { - "AL_FORMAT_MONO8", "AL_FORMAT_STEREO8", "AL_FORMAT_QUAD8", - "AL_FORMAT_51CHN8", "AL_FORMAT_61CHN8", "AL_FORMAT_71CHN8", NULL - }; - - if(alIsExtensionPresent("AL_EXT_FLOAT32")) - { - for(size_t i = 0;fmt32[i];i++) - { - if(forcebits && forcebits != 32) - break; - - ALenum val = alGetEnumValue(fmt32[i]); - if(getALError() != AL_NO_ERROR || val == 0 || val == -1) - continue; - - structure = gst_structure_new("audio/x-raw-float", - "endianness", G_TYPE_INT, G_BYTE_ORDER, - "width", G_TYPE_INT, 32, NULL); - gst_structure_set(structure, "channels", G_TYPE_INT, - chans[i].count, NULL); - if(chans[i].count > 2) - gst_audio_set_channel_positions(structure, chans[i].pos); - gst_caps_append_structure(caps, structure); - } - } - for(size_t i = 0;fmt16[i];i++) - { - if(forcebits && forcebits != 16) - break; - - ALenum val = alGetEnumValue(fmt16[i]); - if(getALError() != AL_NO_ERROR || val == 0 || val == -1) - continue; - - structure = gst_structure_new("audio/x-raw-int", - "endianness", G_TYPE_INT, G_BYTE_ORDER, - "width", G_TYPE_INT, 16, - "depth", G_TYPE_INT, 16, - "signed", G_TYPE_BOOLEAN, TRUE, NULL); - gst_structure_set(structure, "channels", G_TYPE_INT, - chans[i].count, NULL); - if(chans[i].count > 2) - gst_audio_set_channel_positions(structure, chans[i].pos); - gst_caps_append_structure(caps, structure); - } - for(size_t i = 0;fmt8[i];i++) - { - if(forcebits && forcebits != 8) - break; - - ALenum val = alGetEnumValue(fmt8[i]); - if(getALError() != AL_NO_ERROR || val == 0 || val == -1) - continue; - - structure = gst_structure_new("audio/x-raw-int", - "width", G_TYPE_INT, 8, - "depth", G_TYPE_INT, 8, - "signed", G_TYPE_BOOLEAN, FALSE, NULL); - gst_structure_set(structure, "channels", G_TYPE_INT, - chans[i].count, NULL); - if(chans[i].count > 2) - gst_audio_set_channel_positions(structure, chans[i].pos); - gst_caps_append_structure(caps, structure); - } - } - else - { - if(alIsExtensionPresent("AL_EXT_FLOAT32") && - (!forcebits || forcebits == 32)) - { - structure = gst_structure_new("audio/x-raw-float", - "endianness", G_TYPE_INT, G_BYTE_ORDER, - "width", G_TYPE_INT, 32, - "channels", GST_TYPE_INT_RANGE, 1, 2, NULL); - gst_caps_append_structure(caps, structure); - } - if(!forcebits || forcebits == 16) - { - structure = gst_structure_new("audio/x-raw-int", - "endianness", G_TYPE_INT, G_BYTE_ORDER, - "width", G_TYPE_INT, 16, - "depth", G_TYPE_INT, 16, - "signed", G_TYPE_BOOLEAN, TRUE, - "channels", GST_TYPE_INT_RANGE, 1, 2, NULL); - gst_caps_append_structure(caps, structure); - } - if(!forcebits || forcebits == 8) - { - structure = gst_structure_new("audio/x-raw-int", - "width", G_TYPE_INT, 8, - "depth", G_TYPE_INT, 8, - "signed", G_TYPE_BOOLEAN, FALSE, - "channels", GST_TYPE_INT_RANGE, 1, 2, NULL); - gst_caps_append_structure(caps, structure); - } - } - return caps; -} - -class OpenALSoundStream : public SoundStream -{ - OpenALSoundRenderer *Renderer; - GstElement *gstPipeline; - GstTagList *TagList; - gint64 LoopPts[2]; - ALuint Source; - - bool Playing; - bool Looping; - - // Custom OpenAL sink; this is pretty crappy compared to the real - // openalsink element, but it gets the job done - static const ALsizei MaxSamplesQueued = 32768; - std::vector Buffers; - ALsizei SamplesQueued; - ALsizei SampleRate; - ALenum Format; - - static void sink_eos(GstAppSink *sink, gpointer user_data) - { - OpenALSoundStream *self = static_cast(user_data); - - if(!self->Playing) - return; - - ALint state; - do { - g_usleep(10000); - alGetSourcei(self->Source, AL_SOURCE_STATE, &state); - } while(getALError() == AL_NO_ERROR && state == AL_PLAYING && self->Playing); - - alSourceRewind(self->Source); - getALError(); - } - - static GstFlowReturn sink_preroll(GstAppSink *sink, gpointer user_data) - { - OpenALSoundStream *self = static_cast(user_data); - - // get the buffer from appsink - GstBuffer *buffer = gst_app_sink_pull_preroll(sink); - if(!buffer) return GST_FLOW_ERROR; - - GstCaps *caps = GST_BUFFER_CAPS(buffer); - gint bits = 0, channels = 0, rate = 0, i; - for(i = gst_caps_get_size(caps)-1;i >= 0;i--) - { - GstStructure *struc = gst_caps_get_structure(caps, i); - if(gst_structure_has_field(struc, "width")) - gst_structure_get_int(struc, "width", &bits); - if(gst_structure_has_field(struc, "channels")) - gst_structure_get_int(struc, "channels", &channels); - if(gst_structure_has_field(struc, "rate")) - gst_structure_get_int(struc, "rate", &rate); - } - - self->SampleRate = rate; - self->Format = FormatFromDesc(bits, channels); - - gst_buffer_unref(buffer); - if(self->Format == AL_NONE || self->SampleRate <= 0) - return GST_FLOW_ERROR; - return GST_FLOW_OK; - } - - static GstFlowReturn sink_buffer(GstAppSink *sink, gpointer user_data) - { - OpenALSoundStream *self = static_cast(user_data); - - GstBuffer *buffer = gst_app_sink_pull_buffer(sink); - if(!buffer) return GST_FLOW_ERROR; - - if(GST_BUFFER_SIZE(buffer) == 0) - { - gst_buffer_unref(buffer); - return GST_FLOW_OK; - } - - ALint processed, state; - next_buffer: - do { - alGetSourcei(self->Source, AL_SOURCE_STATE, &state); - alGetSourcei(self->Source, AL_BUFFERS_PROCESSED, &processed); - if(getALError() != AL_NO_ERROR) - { - gst_buffer_unref(buffer); - return GST_FLOW_ERROR; - } - if(processed > 0 || self->SamplesQueued < MaxSamplesQueued || - state != AL_PLAYING || !self->Playing) - break; - - g_usleep(10000); - } while(1); - - if(!self->Playing) - { - gst_buffer_unref(buffer); - return GST_FLOW_OK; - } - - ALuint bufID; - if(processed == 0) - { - alGenBuffers(1, &bufID); - if(getALError() != AL_NO_ERROR) - { - gst_buffer_unref(buffer); - return GST_FLOW_ERROR; - } - self->Buffers.push_back(bufID); - } - else while(1) - { - alSourceUnqueueBuffers(self->Source, 1, &bufID); - if(getALError() != AL_NO_ERROR) - { - gst_buffer_unref(buffer); - return GST_FLOW_ERROR; - } - - self->SamplesQueued -= getBufferLength(bufID); - processed--; - if(self->SamplesQueued < MaxSamplesQueued) - break; - if(processed == 0) - goto next_buffer; - self->Buffers.erase(find(self->Buffers.begin(), self->Buffers.end(), bufID)); - alDeleteBuffers(1, &bufID); - } - - alBufferData(bufID, self->Format, GST_BUFFER_DATA(buffer), - GST_BUFFER_SIZE(buffer), self->SampleRate); - alSourceQueueBuffers(self->Source, 1, &bufID); - gst_buffer_unref(buffer); - - if(getALError() != AL_NO_ERROR) - return GST_FLOW_ERROR; - - self->SamplesQueued += getBufferLength(bufID); - if(state != AL_PLAYING && processed == 0) - { - alSourcePlay(self->Source); - if(getALError() != AL_NO_ERROR) - return GST_FLOW_ERROR; - } - return GST_FLOW_OK; - } - - // Memory-based data source - std::vector MemData; - size_t MemDataPos; - - static void need_memdata(GstAppSrc *appsrc, guint size, gpointer user_data) - { - OpenALSoundStream *self = static_cast(user_data); - - if(self->MemDataPos >= self->MemData.size()) - { - gst_app_src_end_of_stream(appsrc); - return; - } - - // "read" the data it wants, up to the remaining amount - guint8 *data = &self->MemData[self->MemDataPos]; - size = std::min(size, self->MemData.size() - self->MemDataPos); - self->MemDataPos += size; - - GstBuffer *buffer = gst_buffer_new(); - GST_BUFFER_DATA(buffer) = data; - GST_BUFFER_SIZE(buffer) = size; - - // this takes ownership of the buffer; don't unref - gst_app_src_push_buffer(appsrc, buffer); - } - - static gboolean seek_memdata(GstAppSrc *appsrc, guint64 position, gpointer user_data) - { - OpenALSoundStream *self = static_cast(user_data); - - if(position > self->MemData.size()) - return FALSE; - self->MemDataPos = position; - return TRUE; - } - - static void memdata_source(GObject *object, GObject *orig, GParamSpec *pspec, OpenALSoundStream *self) - { - GstElement *elem; - g_object_get(self->gstPipeline, "source", &elem, NULL); - - GstAppSrc *appsrc = GST_APP_SRC(elem); - GstAppSrcCallbacks callbacks = { - need_memdata, NULL, seek_memdata - }; - gst_app_src_set_callbacks(appsrc, &callbacks, self, NULL); - gst_app_src_set_size(appsrc, self->MemData.size()); - gst_app_src_set_stream_type(appsrc, GST_APP_STREAM_TYPE_RANDOM_ACCESS); - - gst_object_unref(appsrc); - } - - // Callback-based data source - SoundStreamCallback Callback; - void *UserData; - int BufferBytes; - GstCaps *SrcCaps; - - static void need_callback(GstAppSrc *appsrc, guint size, gpointer user_data) - { - OpenALSoundStream *self = static_cast(user_data); - - GstBuffer *buffer; - if(!self->Playing) - buffer = gst_buffer_new_and_alloc(0); - else - { - buffer = gst_buffer_new_and_alloc(size); - if(!self->Callback(self, GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer), self->UserData)) - { - gst_buffer_unref(buffer); - - gst_app_src_end_of_stream(appsrc); - return; - } - } - - gst_app_src_push_buffer(appsrc, buffer); - } - - static void callback_source(GObject *object, GObject *orig, GParamSpec *pspec, OpenALSoundStream *self) - { - GstElement *elem; - g_object_get(self->gstPipeline, "source", &elem, NULL); - - GstAppSrc *appsrc = GST_APP_SRC(elem); - GstAppSrcCallbacks callbacks = { - need_callback, NULL, NULL - }; - gst_app_src_set_callbacks(appsrc, &callbacks, self, NULL); - gst_app_src_set_size(appsrc, -1); - gst_app_src_set_max_bytes(appsrc, self->BufferBytes); - gst_app_src_set_stream_type(appsrc, GST_APP_STREAM_TYPE_STREAM); - gst_app_src_set_caps(appsrc, self->SrcCaps); - - gst_object_unref(appsrc); - } - - // General methods - virtual bool SetupSource() - { - // We don't actually use this source if we have an openalsink. However, - // holding on to it helps ensure we don't overrun our allotted voice - // count. - if(Renderer->FreeSfx.size() == 0) - { - FSoundChan *lowest = Renderer->FindLowestChannel(); - if(lowest) Renderer->StopChannel(lowest); - - if(Renderer->FreeSfx.size() == 0) - return false; - } - Source = Renderer->FreeSfx.back(); - Renderer->FreeSfx.pop_back(); - - alSource3f(Source, AL_DIRECTION, 0.f, 0.f, 0.f); - alSource3f(Source, AL_VELOCITY, 0.f, 0.f, 0.f); - alSource3f(Source, AL_POSITION, 0.f, 0.f, 0.f); - alSourcef(Source, AL_MAX_GAIN, 1.f); - alSourcef(Source, AL_GAIN, 1.f); - alSourcef(Source, AL_PITCH, 1.f); - alSourcef(Source, AL_ROLLOFF_FACTOR, 0.f); - alSourcef(Source, AL_SEC_OFFSET, 0.f); - alSourcei(Source, AL_SOURCE_RELATIVE, AL_TRUE); - alSourcei(Source, AL_LOOPING, AL_FALSE); - if(Renderer->EnvSlot) - { - alSourcef(Source, AL_ROOM_ROLLOFF_FACTOR, 0.f); - alSourcef(Source, AL_AIR_ABSORPTION_FACTOR, 0.f); - alSourcei(Source, AL_DIRECT_FILTER, AL_FILTER_NULL); - alSource3i(Source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL); - } - - return (getALError() == AL_NO_ERROR); - } - - bool PipelineSetup() - { - TagList = gst_tag_list_new(); - g_return_val_if_fail(TagList != NULL, false); - - // Flags (can be combined): - // 0x01: video - Render the video stream - // 0x02: audio - Render the audio stream - // 0x04: text - Render subtitles - // 0x08: vis - Render visualisation when no video is present - // 0x10: soft-volume - Use software volume - // 0x20: native-audio - Only use native audio formats - // 0x40: native-video - Only use native video formats - // 0x80: download - Attempt progressive download buffering - int flags = 0x02 | 0x10; - - gstPipeline = gst_element_factory_make("playbin2", NULL); - g_return_val_if_fail(gstPipeline != NULL, false); - - GstElement *sink = gst_element_factory_make("openalsink", NULL); - if(sink != NULL) - { - // Give the sink our device, so it can create its own context and - // source to play with (and not risk cross-contaminating errors) - g_object_set(sink, "device-handle", Renderer->Device, NULL); - } - else - { - static bool warned = false; - if(!warned) - g_warning("Could not create an openalsink\n"); - warned = true; - - sink = gst_element_factory_make("appsink", NULL); - g_return_val_if_fail(sink != NULL, false); - - GstAppSink *appsink = GST_APP_SINK(sink); - GstAppSinkCallbacks callbacks = { - sink_eos, sink_preroll, sink_buffer, NULL - }; - GstCaps *caps = SupportedBufferFormatCaps(); - - gst_app_sink_set_callbacks(appsink, &callbacks, this, NULL); - gst_app_sink_set_drop(appsink, FALSE); - gst_app_sink_set_caps(appsink, caps); - gst_caps_unref(caps); - } - - // This takes ownership of the element; don't unref it - g_object_set(gstPipeline, "audio-sink", sink, NULL); - g_object_set(gstPipeline, "flags", flags, NULL); - return true; - } - - void HandleLoopTags() - { - // FIXME: Sample offsets assume a 44.1khz rate. Need to find some way - // to get the actual rate of the file from GStreamer - bool looppt_is_samples; - unsigned int looppt; - gchar *valstr; - - LoopPts[0] = 0; - if(gst_tag_list_get_string(TagList, "LOOP_START", &valstr)) - { - g_print("Got LOOP_START string: %s\n", valstr); - if(!S_ParseTimeTag(valstr, &looppt_is_samples, &looppt)) - Printf("Invalid LOOP_START tag: '%s'\n", valstr); - else - LoopPts[0] = (looppt_is_samples ? ((gint64)looppt*1000000000/44100) : - ((gint64)looppt*1000000)); - g_free(valstr); - } - LoopPts[1] = -1; - if(gst_tag_list_get_string(TagList, "LOOP_END", &valstr)) - { - g_print("Got LOOP_END string: %s\n", valstr); - if(!S_ParseTimeTag(valstr, &looppt_is_samples, &looppt)) - Printf("Invalid LOOP_END tag: '%s'\n", valstr); - else - { - LoopPts[1] = (looppt_is_samples ? ((gint64)looppt*1000000000/44100) : - ((gint64)looppt*1000000)); - if(LoopPts[1] <= LoopPts[0]) - LoopPts[1] = -1; - } - g_free(valstr); - } - } - - bool PreparePipeline() - { - GstBus *bus = gst_element_get_bus(gstPipeline); - if(!bus) return false; - - GstStateChangeReturn ret = gst_element_set_state(gstPipeline, GST_STATE_PAUSED); - if(ret == GST_STATE_CHANGE_ASYNC) - { - const GstMessageType types = GST_MESSAGE_ERROR | GST_MESSAGE_TAG | GST_MESSAGE_ASYNC_DONE; - GstMessage *msg; - while((msg=gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, types)) != NULL) - { - if(GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) - { - PrintErrMsg("Prepare Error", msg); - ret = GST_STATE_CHANGE_FAILURE; - gst_message_unref(msg); - break; - } - else if(GST_MESSAGE_TYPE(msg) != GST_MESSAGE_TAG) - { - gst_message_unref(msg); - break; - } - - GstTagList *tags = NULL; - gst_message_parse_tag(msg, &tags); - - gst_tag_list_insert(TagList, tags, GST_TAG_MERGE_KEEP); - - gst_tag_list_free(tags); - gst_message_unref(msg); - } - } - else if(ret == GST_STATE_CHANGE_SUCCESS) - { - GstMessage *msg; - while((msg=gst_bus_pop(bus)) != NULL) - { - if(GST_MESSAGE_TYPE(msg) == GST_MESSAGE_TAG) - { - GstTagList *tags = NULL; - gst_message_parse_tag(msg, &tags); - - gst_tag_list_insert(TagList, tags, GST_TAG_MERGE_KEEP); - - gst_tag_list_free(tags); - } - gst_message_unref(msg); - } - } - HandleLoopTags(); - - gst_object_unref(bus); - bus = NULL; - - return (ret != GST_STATE_CHANGE_FAILURE); - } - -public: - FTempFileName tmpfile; - ALfloat Volume; - - OpenALSoundStream(OpenALSoundRenderer *renderer) - : Renderer(renderer), gstPipeline(NULL), TagList(NULL), Source(0), - Playing(false), Looping(false), SamplesQueued(0), Callback(NULL), - UserData(NULL), BufferBytes(0), SrcCaps(NULL), Volume(1.0f) - { - LoopPts[0] = LoopPts[1] = 0; - Renderer->Streams.push_back(this); - } - - virtual ~OpenALSoundStream() - { - Playing = false; - - if(SrcCaps) - gst_caps_unref(SrcCaps); - SrcCaps = NULL; - - if(gstPipeline) - { - gst_element_set_state(gstPipeline, GST_STATE_NULL); - gst_object_unref(gstPipeline); - gstPipeline = NULL; - } - - if(TagList) - gst_tag_list_free(TagList); - TagList = NULL; - - if(Source) - { - alSourceRewind(Source); - alSourcei(Source, AL_BUFFER, 0); - - Renderer->FreeSfx.push_back(Source); - Source = 0; - } - - if(Buffers.size() > 0) - { - alDeleteBuffers(Buffers.size(), &Buffers[0]); - Buffers.clear(); - } - getALError(); - - Renderer->Streams.erase(find(Renderer->Streams.begin(), - Renderer->Streams.end(), this)); - Renderer = NULL; - } - - virtual bool Play(bool looping, float vol) - { - if(Playing) - return true; - - GstBus *bus = gst_element_get_bus(gstPipeline); - if(!bus) return false; - - Looping = looping; - SetVolume(vol); - - if(Looping) - { - const GstSeekFlags flags = GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SEGMENT; - gst_element_seek(gstPipeline, 1.0, GST_FORMAT_TIME, flags, - GST_SEEK_TYPE_NONE, 0, GST_SEEK_TYPE_SET, LoopPts[1]); - } - - // Start playing the stream - Playing = true; - GstStateChangeReturn ret = gst_element_set_state(gstPipeline, GST_STATE_PLAYING); - if(ret == GST_STATE_CHANGE_FAILURE) - Playing = false; - if(ret == GST_STATE_CHANGE_ASYNC) - { - const GstMessageType types = GST_MESSAGE_ERROR | GST_MESSAGE_ASYNC_DONE; - GstMessage *msg; - if((msg=gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, types)) != NULL) - { - if(GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) - { - PrintErrMsg("Play Error", msg); - Playing = false; - } - gst_message_unref(msg); - } - } - - gst_object_unref(bus); - bus = NULL; - - return Playing; - } - - virtual void Stop() - { - GstBus *bus = gst_element_get_bus(gstPipeline); - if(!bus) return; - - // Stop the stream - GstStateChangeReturn ret = gst_element_set_state(gstPipeline, GST_STATE_PAUSED); - if(ret == GST_STATE_CHANGE_ASYNC) - { - Playing = false; - // Wait for the state change before requesting a seek - const GstMessageType types = GST_MESSAGE_ERROR | GST_MESSAGE_ASYNC_DONE; - GstMessage *msg; - if((msg=gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, types)) != NULL) - { - if(GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) - PrintErrMsg("Stop Error", msg); - else if(GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ASYNC_DONE) - ret = GST_STATE_CHANGE_SUCCESS; - gst_message_unref(msg); - } - } - if(ret == GST_STATE_CHANGE_SUCCESS) - { - Playing = false; - - alSourceRewind(Source); - getALError(); - - const GstSeekFlags flags = GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT; - gst_element_seek_simple(gstPipeline, GST_FORMAT_TIME, flags, 0); - } - - gst_object_unref(bus); - bus = NULL; - } - - virtual bool SetPaused(bool paused) - { - GstBus *bus = gst_element_get_bus(gstPipeline); - if(!bus) return false; - - GstStateChangeReturn ret; - ret = gst_element_set_state(gstPipeline, (paused ? GST_STATE_PAUSED : GST_STATE_PLAYING)); - if(ret == GST_STATE_CHANGE_ASYNC) - { - const GstMessageType types = GST_MESSAGE_ERROR | GST_MESSAGE_ASYNC_DONE; - GstMessage *msg; - if((msg=gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, types)) != NULL) - { - if(GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) - { - PrintErrMsg("Pause Error", msg); - ret = GST_STATE_CHANGE_FAILURE; - } - gst_message_unref(msg); - } - } - - if(ret != GST_STATE_CHANGE_FAILURE && paused) - { - alSourcePause(Source); - getALError(); - } - - gst_object_unref(bus); - bus = NULL; - - return (ret != GST_STATE_CHANGE_FAILURE); - } - - virtual void SetVolume(float vol) - { - Volume = vol; - g_object_set(gstPipeline, "volume", (double)(Volume*Renderer->MusicVolume), NULL); - } - - virtual unsigned int GetPosition() - { - GstFormat format = GST_FORMAT_TIME; - gint64 pos; - - // Position will be handled in milliseconds; GStreamer's time format is in nanoseconds - if(gst_element_query_position(gstPipeline, &format, &pos) && format == GST_FORMAT_TIME) - return (unsigned int)(pos / 1000000); - return 0; - } - - virtual bool SetPosition(unsigned int val) - { - gint64 pos = (gint64)val * 1000000; - return gst_element_seek_simple(gstPipeline, GST_FORMAT_TIME, GST_SEEK_FLAG_ACCURATE, pos); - } - - virtual bool IsEnded() - { - GstBus *bus = gst_element_get_bus(gstPipeline); - if(!bus) return true; - - GstMessage *msg; - while((msg=gst_bus_pop(bus)) != NULL) - { - switch(GST_MESSAGE_TYPE(msg)) - { - case GST_MESSAGE_SEGMENT_DONE: - case GST_MESSAGE_EOS: - Playing = false; - if(Looping) - Playing = gst_element_seek(gstPipeline, 1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH | - GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_SEGMENT, - GST_SEEK_TYPE_SET, LoopPts[0], - GST_SEEK_TYPE_SET, LoopPts[1]); - break; - - case GST_MESSAGE_ERROR: - PrintErrMsg("Pipeline Error", msg); - Playing = false; - break; - - case GST_MESSAGE_WARNING: - PrintErrMsg("Pipeline Warning", msg); - break; - - default: - break; - } - - gst_message_unref(msg); - } - - gst_object_unref(bus); - bus = NULL; - - return !Playing; - } - - bool Init(const char *filename) - { - if(!SetupSource() || !PipelineSetup()) - return false; - - GError *err = NULL; - gchar *uri; - if(g_path_is_absolute(filename)) - uri = g_filename_to_uri(filename, NULL, &err); - else if(g_strrstr(filename, "://") != NULL) - uri = g_strdup(filename); - else - { - gchar *curdir = g_get_current_dir(); - gchar *absolute_path = g_strconcat(curdir, G_DIR_SEPARATOR_S, filename, NULL); - uri = g_filename_to_uri(absolute_path, NULL, &err); - g_free(absolute_path); - g_free(curdir); - } - - if(!uri) - { - if(err) - { - Printf("Failed to convert "TEXTCOLOR_BOLD"%s"TEXTCOLOR_NORMAL" to URI: %s\n", - filename, err->message); - g_error_free(err); - } - return false; - } - - g_object_set(gstPipeline, "uri", uri, NULL); - g_free(uri); - - return PreparePipeline(); - } - - bool Init(const BYTE *data, unsigned int datalen) - { - // Can't keep the original pointer since the memory can apparently be - // overwritten at some point (happens with MIDI data, at least) - MemData.resize(datalen); - memcpy(&MemData[0], data, datalen); - MemDataPos = 0; - - if(!SetupSource() || !PipelineSetup()) - return false; - - g_object_set(gstPipeline, "uri", "appsrc://", NULL); - g_signal_connect(gstPipeline, "deep-notify::source", G_CALLBACK(memdata_source), this); - - return PreparePipeline(); - } - - bool Init(SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata) - { - Callback = callback; - UserData = userdata; - BufferBytes = buffbytes; - - GstStructure *structure; - if((flags&Float)) - structure = gst_structure_new("audio/x-raw-float", - "endianness", G_TYPE_INT, G_BYTE_ORDER, - "width", G_TYPE_INT, 32, NULL); - else if((flags&Bits32)) - structure = gst_structure_new("audio/x-raw-int", - "endianness", G_TYPE_INT, G_BYTE_ORDER, - "width", G_TYPE_INT, 32, - "depth", G_TYPE_INT, 32, - "signed", G_TYPE_BOOLEAN, TRUE, NULL); - else if((flags&Bits8)) - structure = gst_structure_new("audio/x-raw-int", - "width", G_TYPE_INT, 8, - "depth", G_TYPE_INT, 8, - "signed", G_TYPE_BOOLEAN, TRUE, NULL); - else - structure = gst_structure_new("audio/x-raw-int", - "endianness", G_TYPE_INT, G_BYTE_ORDER, - "width", G_TYPE_INT, 16, - "depth", G_TYPE_INT, 16, - "signed", G_TYPE_BOOLEAN, TRUE, NULL); - gst_structure_set(structure, "channels", G_TYPE_INT, (flags&Mono)?1:2, NULL); - gst_structure_set(structure, "rate", G_TYPE_INT, samplerate, NULL); - - SrcCaps = gst_caps_new_full(structure, NULL); - - if(!SrcCaps || !SetupSource() || !PipelineSetup()) - return false; - - g_object_set(gstPipeline, "uri", "appsrc://", NULL); - g_signal_connect(gstPipeline, "deep-notify::source", G_CALLBACK(callback_source), this); - - return PreparePipeline(); - } -}; - - -class Decoder -{ - GstElement *gstPipeline, *gstSink; - GstTagList *TagList; - - const guint8 *MemData; - size_t MemDataSize; - size_t MemDataPos; - - static void need_memdata(GstAppSrc *appsrc, guint size, gpointer user_data) - { - Decoder *self = static_cast(user_data); - GstFlowReturn ret; - - if(self->MemDataPos >= self->MemDataSize) - { - gst_app_src_end_of_stream(appsrc); - return; - } - - const guint8 *data = &self->MemData[self->MemDataPos]; - size = (std::min)(size, (guint)(self->MemDataSize - self->MemDataPos)); - self->MemDataPos += size; - - GstBuffer *buffer = gst_buffer_new(); - GST_BUFFER_DATA(buffer) = const_cast(data); - GST_BUFFER_SIZE(buffer) = size; - - gst_app_src_push_buffer(appsrc, buffer); - } - - static gboolean seek_memdata(GstAppSrc *appsrc, guint64 position, gpointer user_data) - { - Decoder *self = static_cast(user_data); - - if(position > self->MemDataSize) - return FALSE; - self->MemDataPos = position; - return TRUE; - } - - static void memdata_source(GObject *object, GObject *orig, GParamSpec *pspec, Decoder *self) - { - GstElement *elem; - g_object_get(self->gstPipeline, "source", &elem, NULL); - - GstAppSrc *appsrc = GST_APP_SRC(elem); - GstAppSrcCallbacks callbacks = { - need_memdata, NULL, seek_memdata - }; - gst_app_src_set_callbacks(appsrc, &callbacks, self, NULL); - gst_app_src_set_size(appsrc, self->MemDataSize); - gst_app_src_set_stream_type(appsrc, GST_APP_STREAM_TYPE_RANDOM_ACCESS); - - gst_object_unref(appsrc); - } - - static GstFlowReturn sink_preroll(GstAppSink *sink, gpointer user_data) - { - Decoder *self = static_cast(user_data); - - GstBuffer *buffer = gst_app_sink_pull_preroll(sink); - if(!buffer) return GST_FLOW_ERROR; - - if(self->OutRate == 0) - { - GstCaps *caps = GST_BUFFER_CAPS(buffer); - - gint channels = 0, rate = 0, bits = 0, i; - for(i = gst_caps_get_size(caps)-1;i >= 0;i--) - { - GstStructure *struc = gst_caps_get_structure(caps, i); - if(gst_structure_has_field(struc, "channels")) - gst_structure_get_int(struc, "channels", &channels); - if(gst_structure_has_field(struc, "rate")) - gst_structure_get_int(struc, "rate", &rate); - if(gst_structure_has_field(struc, "width")) - gst_structure_get_int(struc, "width", &bits); - } - - self->OutChannels = channels; - self->OutBits = bits; - self->OutRate = rate; - } - - gst_buffer_unref(buffer); - if(self->OutRate <= 0) - return GST_FLOW_ERROR; - return GST_FLOW_OK; - } - - static GstFlowReturn sink_buffer(GstAppSink *sink, gpointer user_data) - { - Decoder *self = static_cast(user_data); - - GstBuffer *buffer = gst_app_sink_pull_buffer(sink); - if(!buffer) return GST_FLOW_ERROR; - - guint newsize = GST_BUFFER_SIZE(buffer); - size_t pos = self->OutData.size(); - self->OutData.resize(pos+newsize); - - memcpy(&self->OutData[pos], GST_BUFFER_DATA(buffer), newsize); - - gst_buffer_unref(buffer); - return GST_FLOW_OK; - } - - bool PipelineSetup(int forcebits) - { - if(forcebits && forcebits != 8 && forcebits != 16) - return false; - - TagList = gst_tag_list_new(); - g_return_val_if_fail(TagList != NULL, false); - - gstPipeline = gst_element_factory_make("playbin2", NULL); - g_return_val_if_fail(gstPipeline != NULL, false); - - gstSink = gst_element_factory_make("appsink", NULL); - g_return_val_if_fail(gstSink != NULL, false); - - GstAppSink *appsink = GST_APP_SINK(gstSink); - GstAppSinkCallbacks callbacks = { - NULL, sink_preroll, sink_buffer, NULL - }; - - GstCaps *caps = SupportedBufferFormatCaps(forcebits); - g_object_set(appsink, "sync", FALSE, NULL); - gst_app_sink_set_callbacks(appsink, &callbacks, this, NULL); - gst_app_sink_set_drop(appsink, FALSE); - gst_app_sink_set_caps(appsink, caps); - - g_object_set(gstPipeline, "audio-sink", gst_object_ref(gstSink), NULL); - g_object_set(gstPipeline, "flags", 0x02, NULL); - - gst_caps_unref(caps); - return true; - } - - void HandleLoopTags(unsigned int looppt[2], bool looppt_is_samples[2], bool has_looppt[2]) - { - gchar *valstr; - - if(gst_tag_list_get_string(TagList, "LOOP_START", &valstr)) - { - g_print("Got LOOP_START string: %s\n", valstr); - has_looppt[0] = S_ParseTimeTag(valstr, &looppt_is_samples[0], &looppt[0]); - if(!has_looppt[0]) - Printf("Invalid LOOP_START tag: '%s'\n", valstr); - g_free(valstr); - } - if(gst_tag_list_get_string(TagList, "LOOP_END", &valstr)) - { - g_print("Got LOOP_END string: %s\n", valstr); - has_looppt[1] = S_ParseTimeTag(valstr, &looppt_is_samples[1], &looppt[1]); - if(!has_looppt[1]) - Printf("Invalid LOOP_END tag: '%s'\n", valstr); - g_free(valstr); - } - } - -public: - std::vector OutData; - ALint LoopPts[2]; - ALsizei OutRate; - ALuint OutChannels; - ALuint OutBits; - - Decoder() - : gstPipeline(NULL), gstSink(NULL), TagList(NULL), - OutRate(0), OutChannels(0), OutBits(0) - { LoopPts[0] = LoopPts[1] = 0; } - - virtual ~Decoder() - { - if(gstSink) - gst_object_unref(gstSink); - gstSink = NULL; - - if(gstPipeline) - { - gst_element_set_state(gstPipeline, GST_STATE_NULL); - gst_object_unref(gstPipeline); - gstPipeline = NULL; - } - - if(TagList) - gst_tag_list_free(TagList); - TagList = NULL; - } - - bool Decode(const void *data, unsigned int datalen, int forcebits=0) - { - MemData = static_cast(data); - MemDataSize = datalen; - MemDataPos = 0; - OutData.clear(); - - if(!PipelineSetup(forcebits)) - return false; - - g_object_set(gstPipeline, "uri", "appsrc://", NULL); - g_signal_connect(gstPipeline, "deep-notify::source", G_CALLBACK(memdata_source), this); - - - GstBus *bus = gst_element_get_bus(gstPipeline); - if(!bus) return false; - GstMessage *msg; - - GstStateChangeReturn ret = gst_element_set_state(gstPipeline, GST_STATE_PLAYING); - if(ret == GST_STATE_CHANGE_ASYNC) - { - const GstMessageType types = GST_MESSAGE_ERROR | GST_MESSAGE_TAG | GST_MESSAGE_ASYNC_DONE; - while((msg=gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, types)) != NULL) - { - if(GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ASYNC_DONE) - { - ret = GST_STATE_CHANGE_SUCCESS; - break; - } - else if(GST_MESSAGE_TYPE(msg) == GST_MESSAGE_TAG) - { - GstTagList *tags = NULL; - gst_message_parse_tag(msg, &tags); - - gst_tag_list_insert(TagList, tags, GST_TAG_MERGE_KEEP); - - gst_tag_list_free(tags); - } - else if(GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) - { - ret = GST_STATE_CHANGE_FAILURE; - PrintErrMsg("Decoder Error", msg); - break; - } - gst_message_unref(msg); - } - } - - bool err = true; - if(ret == GST_STATE_CHANGE_SUCCESS) - { - const GstMessageType types = GST_MESSAGE_ERROR | GST_MESSAGE_TAG | GST_MESSAGE_EOS; - while((msg=gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE, types)) != NULL) - { - if(GST_MESSAGE_TYPE(msg) == GST_MESSAGE_EOS) - { - err = false; - gst_message_unref(msg); - break; - } - if(GST_MESSAGE_TYPE(msg) != GST_MESSAGE_TAG) - { - PrintErrMsg("Decoder Error", msg); - gst_message_unref(msg); - break; - } - - GstTagList *tags = NULL; - gst_message_parse_tag(msg, &tags); - - gst_tag_list_insert(TagList, tags, GST_TAG_MERGE_KEEP); - - gst_tag_list_free(tags); - gst_message_unref(msg); - } - } - - if(!err) - { - ALuint FrameSize = OutChannels*OutBits/8; - if(OutData.size() >= FrameSize) - { - // HACK: Evilness abound. Seems GStreamer doesn't like (certain?) - // wave files and produces an extra sample, which can cause an - // audible click at the end. Cut it. - OutData.resize(OutData.size() - FrameSize); - } - - unsigned int looppt[2] = { 0, 0 }; - bool looppt_is_samples[2] = { true, true }; - bool has_looppt[2] = { false, false }; - - HandleLoopTags(looppt, looppt_is_samples, has_looppt); - if(has_looppt[0] || has_looppt[1]) - { - if(!has_looppt[0]) - LoopPts[0] = 0; - else if(looppt_is_samples[0]) - LoopPts[0] = (std::min)((ALint)looppt[0], - (ALint)(OutData.size() / FrameSize)); - else - LoopPts[0] = (std::min)((ALint)((gint64)looppt[0] * OutRate / 1000), - (ALint)(OutData.size() / FrameSize)); - - if(!has_looppt[1]) - LoopPts[1] = OutData.size() / FrameSize; - else if(looppt_is_samples[1]) - LoopPts[1] = (std::min)((ALint)looppt[1], - (ALint)(OutData.size() / FrameSize)); - else - LoopPts[1] = (std::min)((ALint)((gint64)looppt[1] * OutRate / 1000), - (ALint)(OutData.size() / FrameSize)); - } - } - - gst_object_unref(bus); - bus = NULL; - - return !err; - } -}; -#else /* WITH_GSTREAMER */ class OpenALSoundStream : public SoundStream { OpenALSoundRenderer *Renderer; @@ -1536,7 +274,6 @@ public: bool Decode(const void*, unsigned int, int=0) { return false; } }; -#endif /* WITH_GSTREAMER */ template @@ -1551,21 +288,6 @@ OpenALSoundRenderer::OpenALSoundRenderer() Printf("I_InitSound: Initializing OpenAL\n"); -#ifdef WITH_GSTREAMER - static bool GSTInited = false; - if(!GSTInited) - { - GError *error; - if(!gst_init_check(NULL, NULL, &error)) - { - Printf("Failed to initialize GStreamer: %s\n", error->message); - g_error_free(error); - return; - } - GSTInited = true; - } -#endif - if(snd_aldevice != "Default") { Device = alcOpenDevice(*snd_aldevice); diff --git a/src/sound/oalsound.h b/src/sound/oalsound.h index 96304db915..6df71914ad 100644 --- a/src/sound/oalsound.h +++ b/src/sound/oalsound.h @@ -11,16 +11,8 @@ #ifndef NO_OPENAL -#ifdef _WIN32 -#include -#include -#elif defined(__APPLE__) -#include -#include -#else -#include -#include -#endif +#include "al.h" +#include "alc.h" #ifndef ALC_ENUMERATE_ALL_EXT #define ALC_ENUMERATE_ALL_EXT 1 From 5d1cd7b7fec4a59b81246e75797d5da5835404ab Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 30 Jun 2013 01:32:48 -0700 Subject: [PATCH 06/88] Small fixups find -> std::find AL_EXT_loop_points -> AL_SOFT_loop_points --- src/sound/oalsound.cpp | 26 +++++++++++++------------- src/sound/oalsound.h | 6 +++--- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 5bbd245227..805dde2b35 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -224,8 +224,8 @@ public: virtual ~OpenALSoundStream() { - Renderer->Streams.erase(find(Renderer->Streams.begin(), - Renderer->Streams.end(), this)); + Renderer->Streams.erase(std::find(Renderer->Streams.begin(), + Renderer->Streams.end(), this)); Renderer = NULL; } @@ -288,7 +288,7 @@ OpenALSoundRenderer::OpenALSoundRenderer() Printf("I_InitSound: Initializing OpenAL\n"); - if(snd_aldevice != "Default") + if(strcmp(snd_aldevice, "Default") != 0) { Device = alcOpenDevice(*snd_aldevice); if(!Device) @@ -348,7 +348,7 @@ OpenALSoundRenderer::OpenALSoundRenderer() DPrintf(" Extensions: "TEXTCOLOR_ORANGE"%s\n", alGetString(AL_EXTENSIONS)); SrcDistanceModel = alIsExtensionPresent("AL_EXT_source_distance_model"); - LoopPoints = alIsExtensionPresent("AL_EXT_loop_points"); + LoopPoints = alIsExtensionPresent("AL_SOFT_loop_points"); alDopplerFactor(0.5f); alSpeedOfSound(343.3f * 96.0f); @@ -642,7 +642,7 @@ SoundHandle OpenALSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int length, int fre ALint loops[2] = { loopstart, loopend }; Printf("Setting loop points %d -> %d\n", loops[0], loops[1]); - alBufferiv(buffer, AL_LOOP_POINTS, loops); + alBufferiv(buffer, AL_LOOP_POINTS_SOFT, loops); getALError(); } else if(loopstart > 0 || loopend > 0) @@ -690,7 +690,7 @@ SoundHandle OpenALSoundRenderer::LoadSound(BYTE *sfxdata, int length) if(LoopPoints && decoder.LoopPts[1] > decoder.LoopPts[0]) { - alBufferiv(buffer, AL_LOOP_POINTS, decoder.LoopPts); + alBufferiv(buffer, AL_LOOP_POINTS_SOFT, decoder.LoopPts); getALError(); } else if(decoder.LoopPts[1] > decoder.LoopPts[0]) @@ -821,7 +821,7 @@ FISoundChannel *OpenALSoundRenderer::StartSound(SoundHandle sfx, float vol, int } ALuint buffer = *((ALuint*)sfx.data); - ALuint &source = *find(Sources.begin(), Sources.end(), FreeSfx.back()); + ALuint &source = *std::find(Sources.begin(), Sources.end(), FreeSfx.back()); alSource3f(source, AL_POSITION, 0.f, 0.f, 0.f); alSource3f(source, AL_VELOCITY, 0.f, 0.f, 0.f); alSource3f(source, AL_DIRECTION, 0.f, 0.f, 0.f); @@ -930,7 +930,7 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener ALint channels = 1; alGetBufferi(buffer, AL_CHANNELS, &channels); - ALuint &source = *find(Sources.begin(), Sources.end(), FreeSfx.back()); + ALuint &source = *std::find(Sources.begin(), Sources.end(), FreeSfx.back()); alSource3f(source, AL_POSITION, pos[0], pos[1], -pos[2]); alSource3f(source, AL_VELOCITY, vel[0], vel[1], -vel[2]); alSource3f(source, AL_DIRECTION, 0.f, 0.f, 0.f); @@ -1075,12 +1075,12 @@ void OpenALSoundRenderer::StopChannel(FISoundChannel *chan) std::vector::iterator i; - i = find(PausableSfx.begin(), PausableSfx.end(), source); + i = std::find(PausableSfx.begin(), PausableSfx.end(), source); if(i != PausableSfx.end()) PausableSfx.erase(i); - i = find(ReverbSfx.begin(), ReverbSfx.end(), source); + i = std::find(ReverbSfx.begin(), ReverbSfx.end(), source); if(i != ReverbSfx.end()) ReverbSfx.erase(i); - SfxGroup.erase(find(SfxGroup.begin(), SfxGroup.end(), source)); + SfxGroup.erase(std::find(SfxGroup.begin(), SfxGroup.end(), source)); FreeSfx.push_back(source); } @@ -1148,7 +1148,7 @@ void OpenALSoundRenderer::Sync(bool sync) std::vector::iterator i = toplay.begin(); while(i != toplay.end()) { - if(find(PausableSfx.begin(), PausableSfx.end(), *i) != PausableSfx.end()) + if(std::find(PausableSfx.begin(), PausableSfx.end(), *i) != PausableSfx.end()) i = toplay.erase(i); else i++; @@ -1419,7 +1419,7 @@ void OpenALSoundRenderer::PrintDriversList() return; } - Printf("%c%s%2d. %s\n", ' ', ((snd_aldevice=="Default") ? TEXTCOLOR_BOLD : ""), 0, + Printf("%c%s%2d. %s\n", ' ', ((strcmp(snd_aldevice, "Default") == 0) ? TEXTCOLOR_BOLD : ""), 0, "Default"); for(int i = 1;*drivers;i++) { diff --git a/src/sound/oalsound.h b/src/sound/oalsound.h index 6df71914ad..24450c5b12 100644 --- a/src/sound/oalsound.h +++ b/src/sound/oalsound.h @@ -30,9 +30,9 @@ #define AL_SOURCE_DISTANCE_MODEL 0x200 #endif -#ifndef AL_EXT_loop_points -#define AL_EXT_loop_points 1 -#define AL_LOOP_POINTS 0x2015 +#ifndef AL_SOFT_loop_points +#define AL_SOFT_loop_points 1 +#define AL_LOOP_POINTS_SOFT 0x2015 #endif #ifndef AL_EXT_float32 From 99209c4a2a7fb324cf89669f37eee5b8f2dd8abc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 30 Jun 2013 04:47:10 -0700 Subject: [PATCH 07/88] Remove an unnecessary function --- src/sound/oalsound.cpp | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 805dde2b35..541308a64a 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -137,18 +137,6 @@ static ALCenum checkALCError(ALCdevice *device, const char *fn, unsigned int ln) } #define getALCError(d) checkALCError((d), __FILE__, __LINE__) -static ALsizei GetBufferLength(ALuint buffer, const char *fn, unsigned int ln) -{ - ALint bits, channels, size; - alGetBufferi(buffer, AL_BITS, &bits); - alGetBufferi(buffer, AL_CHANNELS, &channels); - alGetBufferi(buffer, AL_SIZE, &size); - if(checkALError(fn, ln) == AL_NO_ERROR) - return (ALsizei)(size / (channels * bits / 8)); - return 0; -} -#define getBufferLength(b) GetBufferLength((b), __FILE__, __LINE__) - extern ReverbContainer *ForcedEnvironment; #define PITCH_MULT (0.7937005f) /* Approx. 4 semitones lower; what Nash suggested */ @@ -575,9 +563,17 @@ unsigned int OpenALSoundRenderer::GetMSLength(SoundHandle sfx) unsigned int OpenALSoundRenderer::GetSampleLength(SoundHandle sfx) { - if(!sfx.data) - return 0; - return getBufferLength(*((ALuint*)sfx.data)); + if(sfx.data) + { + ALuint buffer = *((ALuint*)sfx.data); + ALint bits, channels, size; + alGetBufferi(buffer, AL_BITS, &bits); + alGetBufferi(buffer, AL_CHANNELS, &channels); + alGetBufferi(buffer, AL_SIZE, &size); + if(getALError() == AL_NO_ERROR) + return (ALsizei)(size / (channels * bits / 8)); + } + return 0; } float OpenALSoundRenderer::GetOutputRate() From 69af01d6293b0514f15ed14fddbd728e1ddb67db Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 30 Jun 2013 07:44:19 -0700 Subject: [PATCH 08/88] Use SDL_sound when available to decode files --- FindSDL_sound.cmake | 382 +++++ src/CMakeLists.txt | 13 +- src/sound/oalsdlsound.cpp | 494 ++++++ src/sound/oalsdlsound.h | 66 + src/sound/oalsound.cpp | 3362 ++++++++++++++++++++----------------- src/sound/oalsound.h | 5 +- 6 files changed, 2744 insertions(+), 1578 deletions(-) create mode 100644 FindSDL_sound.cmake create mode 100644 src/sound/oalsdlsound.cpp create mode 100644 src/sound/oalsdlsound.h diff --git a/FindSDL_sound.cmake b/FindSDL_sound.cmake new file mode 100644 index 0000000000..97d2a84c9e --- /dev/null +++ b/FindSDL_sound.cmake @@ -0,0 +1,382 @@ +# - Locates the SDL_sound library +# +# This module depends on SDL being found and +# must be called AFTER FindSDL.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 to override this selectionor 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(SDL_FOUND AND 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 SDL_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 FindSDL.cmake module, but that's kind of painful. + # The solution would be to try something like: + # set(SDL_TRY_COMPILE_LIBRARY_LIST "${SDL_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=${SDL_INCLUDE_DIR}\;${SDL_SOUND_INCLUDE_DIR} + # -DLINK_LIBRARIES:STRING=${SDL_SOUND_LIBRARY}\;${SDL_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} ${SDL_LIBRARY}) + # causes problems when SDL_LIBRARY looks like + # /Library/Frameworks/SDL.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) + foreach(lib ${SDL_SOUND_LIBRARY} ${SDL_LIBRARY}) + set(TMP_TRY_LIBS "${TMP_TRY_LIBS} \"${lib}\"") + endforeach() + + # 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 SDL_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(${SDL_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR}) + add_executable(DetermineSoundLibs DetermineSoundLibs.c) + target_link_libraries(DetermineSoundLibs ${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() + +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_LIBRARY SDL_SOUND_INCLUDE_DIR + VERSION_VAR SDL_SOUND_VERSION_STRING) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 822f103312..786375b3bd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -202,11 +202,22 @@ else( WIN32 ) endif( WIN32 ) +set( OAL_SOURCES sound/oalsound.cpp ) if( NOT NO_OPENAL ) find_package( OpenAL ) if( OPENAL_FOUND ) include_directories( ${OPENAL_INCLUDE_DIR} ) set( ZDOOM_LIBS ${OPENAL_LIBRARY} ${ZDOOM_LIBS} ) + find_package( SDL ) + if( SDL_FOUND ) + find_package( SDL_sound ) + if( SDL_SOUND_FOUND ) + set_source_files_properties( sound/oalsound.cpp PROPERTIES COMPILE_FLAGS "-DWITH_SDL_SOUND=1" ) + set( OAL_SOURCES ${OAL_SOURCES} sound/oalsdlsound.cpp ) + include_directories( ${SDL_SOUND_INCLUDE_DIR} ) + set( ZDOOM_LIBS ${SDL_SOUND_LIBRARIES} ${ZDOOM_LIBS} ) + endif( SDL_SOUND_FOUND ) + endif( SDL_FOUND ) else( OPENAL_FOUND ) set( NO_OPENAL ON ) endif( OPENAL_FOUND ) @@ -900,7 +911,7 @@ add_executable( zdoom WIN32 sound/music_softsynth_mididevice.cpp sound/music_timidity_mididevice.cpp sound/music_win_mididevice.cpp - sound/oalsound.cpp + ${OAL_SOURCES} sound/music_pseudo_mididevice.cpp textures/animations.cpp textures/anim_switches.cpp diff --git a/src/sound/oalsdlsound.cpp b/src/sound/oalsdlsound.cpp new file mode 100644 index 0000000000..6e704cddcb --- /dev/null +++ b/src/sound/oalsdlsound.cpp @@ -0,0 +1,494 @@ +/* +** oalsdlsound.cpp +** Interface for SDL_sound; uses OpenAL +** +**--------------------------------------------------------------------------- +** Copyright 2008-2010 Chris Robinson +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#define USE_WINDOWS_DWORD +#endif + +#include "doomstat.h" +#include "templates.h" +#include "oalsound.h" +#include "oalsdlsound.h" +#include "c_cvars.h" +#include "c_dispatch.h" +#include "i_system.h" +#include "v_text.h" +#include "gi.h" +#include "actor.h" +#include "r_state.h" +#include "w_wad.h" +#include "i_music.h" +#include "i_musicinterns.h" + +#include +#include + + +struct RWSubFile { +private: + FILE *fp; + size_t start; + size_t length; + +public: + RWSubFile(FILE *f, size_t offset, size_t len) + : fp(f), start(offset), length(len) + { + fseek(fp, start, SEEK_SET); + } + ~RWSubFile() + { fclose(fp); } + + static int seek(SDL_RWops *context, int offset, int whence) + { + RWSubFile *self = static_cast(context->hidden.unknown.data1); + + if(whence == SEEK_END) + { + if(offset <= 0) + offset = self->length + offset; + } + else if(whence == SEEK_CUR) + offset = offset + ftell(self->fp) - self->start; + else if(whence != SEEK_SET) + { + SDL_SetError("Invalid seek mode"); + return -1; + } + + if(offset >= 0 && size_t(offset) <= self->length) + { + if(fseek(self->fp, offset + self->start, SEEK_SET) == 0) + return offset; + } + + SDL_SetError("Invalid file seek"); + return -1; + } + + static int read(SDL_RWops *context, void *ptr, int size, int maxnum) + { + RWSubFile *self = static_cast(context->hidden.unknown.data1); + return fread(ptr, size, maxnum, self->fp); + } + + static int write(SDL_RWops *context, const void *ptr, int size, int num) + { + RWSubFile *self = static_cast(context->hidden.unknown.data1); + return fwrite(ptr, size, num, self->fp); + } + + static int close(SDL_RWops *context) + { + RWSubFile *self = static_cast(context->hidden.unknown.data1); + if(context->type != 0xdeadbeef) + { + SDL_SetError("Wrong kind of RWops for RWSubfile::close"); + return -1; + } + + delete self; + SDL_FreeRW(context); + + return 0; + } +}; + + +static ALenum checkALError(const char *fn, unsigned int ln) +{ + ALenum err = alGetError(); + if(err != AL_NO_ERROR) + { + if(strchr(fn, '/')) + fn = strrchr(fn, '/')+1; + else if(strchr(fn, '\\')) + fn = strrchr(fn, '\\')+1; + Printf(">>>>>>>>>>>> Received AL error %s (%#x), %s:%u\n", alGetString(err), err, fn, ln); + } + return err; +} +#define getALError() checkALError(__FILE__, __LINE__) + + +bool OpenALSoundStream::SetupSource() +{ + if(Renderer->FreeSfx.size() == 0) + { + FSoundChan *lowest = Renderer->FindLowestChannel(); + if(lowest) Renderer->StopChannel(lowest); + + if(Renderer->FreeSfx.size() == 0) + return false; + } + Source = Renderer->FreeSfx.back(); + Renderer->FreeSfx.pop_back(); + + alSource3f(Source, AL_DIRECTION, 0.f, 0.f, 0.f); + alSource3f(Source, AL_VELOCITY, 0.f, 0.f, 0.f); + alSource3f(Source, AL_POSITION, 0.f, 0.f, 0.f); + alSourcef(Source, AL_MAX_GAIN, Renderer->MusicVolume); + alSourcef(Source, AL_GAIN, Volume*Renderer->MusicVolume); + alSourcef(Source, AL_PITCH, 1.f); + alSourcef(Source, AL_ROLLOFF_FACTOR, 0.f); + alSourcef(Source, AL_SEC_OFFSET, 0.f); + alSourcei(Source, AL_SOURCE_RELATIVE, AL_TRUE); + alSourcei(Source, AL_LOOPING, AL_FALSE); + if(Renderer->EnvSlot) + { + alSourcef(Source, AL_ROOM_ROLLOFF_FACTOR, 0.f); + alSourcef(Source, AL_AIR_ABSORPTION_FACTOR, 0.f); + alSourcei(Source, AL_DIRECT_FILTER, AL_FILTER_NULL); + alSource3i(Source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL); + } + + alGenBuffers(Buffers.size(), &Buffers[0]); + return (getALError() == AL_NO_ERROR); +} + +OpenALSoundStream::OpenALSoundStream(OpenALSoundRenderer *renderer) + : Renderer(renderer), Sample(NULL), Source(0), Playing(false), + Looping(false), Buffers(4), SampleRate(0), Format(0), + NeedSwab(false), Volume(1.f) +{ + for(size_t i = 0;i < Buffers.size();i++) + Buffers[i] = 0; + Renderer->Streams.push_back(this); +} + +OpenALSoundStream::~OpenALSoundStream() +{ + Playing = false; + + Sound_FreeSample(Sample); + Sample = NULL; + + if(Source) + { + alSourceRewind(Source); + alSourcei(Source, AL_BUFFER, 0); + + Renderer->FreeSfx.push_back(Source); + Source = 0; + } + + if(Buffers.size() > 0) + { + alDeleteBuffers(Buffers.size(), &Buffers[0]); + Buffers.clear(); + } + getALError(); + + Renderer->Streams.erase(std::find(Renderer->Streams.begin(), + Renderer->Streams.end(), this)); + Renderer = NULL; +} + +bool OpenALSoundStream::Play(bool looping, float vol) +{ + if(Playing) + return true; + + alSourceRewind(Source); + alSourcei(Source, AL_BUFFER, 0); + + Looping = looping; + SetVolume(vol); + + for(size_t i = 0;i < Buffers.size();i++) + { + size_t count = Sound_Decode(Sample); + if(count == 0 && Looping) + { + Sound_Seek(Sample, 0); + count = Sound_Decode(Sample); + } + alBufferData(Buffers[i], Format, GetData(count), count, SampleRate); + } + Playing = (getALError() == AL_NO_ERROR); + if(Playing) + { + alSourceQueueBuffers(Source, Buffers.size(), &Buffers[0]); + alSourcePlay(Source); + Playing = (getALError() == AL_NO_ERROR); + } + return Playing; +} + +void OpenALSoundStream::Stop() +{ + alSourceRewind(Source); + alSourcei(Source, AL_BUFFER, 0); +} + +bool OpenALSoundStream::SetPaused(bool paused) +{ + if(paused) alSourcePause(Source); + else alSourcePlay(Source); + return (getALError() == AL_NO_ERROR); +} + +void OpenALSoundStream::SetVolume(float vol) +{ + if(vol >= 0.f) Volume = vol; + alSourcef(Source, AL_GAIN, Volume*Renderer->MusicVolume); +} + +unsigned int OpenALSoundStream::GetPosition() +{ + return 0; +} + +bool OpenALSoundStream::SetPosition(unsigned int val) +{ + return false; +} + +bool OpenALSoundStream::IsEnded() +{ + if(!Playing) + return true; + + ALint processed, state, queued; + alGetSourcei(Source, AL_SOURCE_STATE, &state); + alGetSourcei(Source, AL_BUFFERS_QUEUED, &queued); + alGetSourcei(Source, AL_BUFFERS_PROCESSED, &processed); + while(processed-- > 0) + { + ALuint buf = 0; + alSourceUnqueueBuffers(Source, 1, &buf); + queued--; + + size_t count = Sound_Decode(Sample); + if(count == 0 && Looping) + { + Sound_Seek(Sample, 0); + count = Sound_Decode(Sample); + } + if(count > 0) + { + alBufferData(buf, Format, GetData(count), count, SampleRate); + alSourceQueueBuffers(Source, 1, &buf); + queued++; + } + } + Playing = (getALError() == AL_NO_ERROR && queued > 0); + if(Playing && state != AL_PLAYING && state != AL_PAUSED) + { + alSourcePlay(Source); + Playing = (getALError() == AL_NO_ERROR); + } + + return !Playing; +} + +void *OpenALSoundStream::GetData(size_t bytes) +{ + void *data = Sample->buffer; + if(NeedSwab) + { + short *samples = reinterpret_cast(data); + size_t count = bytes >> 1; + for(size_t i = 0;i < count;i++) + { + short smp = *samples; + *(samples++) = ((smp>>8)&0x00FF) | ((smp<<8)*0xFF00); + } + } + return data; +} + +bool OpenALSoundStream::InitSample() +{ + UInt32 smpsize = 0; + SampleRate = Sample->actual.rate; + + Format = AL_NONE; + if(Sample->actual.format == AUDIO_U8) + { + if(Sample->actual.channels == 1) + Format = AL_FORMAT_MONO8; + else if(Sample->actual.channels == 2) + Format = AL_FORMAT_STEREO8; + smpsize = 1 * Sample->actual.channels; + } + else if(Sample->actual.format == AUDIO_S16LSB || Sample->actual.format == AUDIO_S16MSB) + { + NeedSwab = (Sample->actual.format != AUDIO_S16SYS); + if(Sample->actual.channels == 1) + Format = AL_FORMAT_MONO16; + else if(Sample->actual.channels == 2) + Format = AL_FORMAT_STEREO16; + smpsize = 1 * Sample->actual.channels; + } + + if(Format == AL_NONE) + { + Printf("Unsupported sound format (0x%04x, %d channels)\n", Sample->actual.format, Sample->actual.channels); + return false; + } + + Uint32 bufsize = (UInt32)(BufferTime*SampleRate) * smpsize; + if(Sound_SetBufferSize(Sample, bufsize) == 0) + { + Printf("Failed to set buffer size to %u bytes: %s\n", bufsize, Sound_GetError()); + return false; + } + + return true; +} + +bool OpenALSoundStream::Init(const char *filename, int offset, int length) +{ + if(!SetupSource()) + return false; + + if(offset == 0) + Sample = Sound_NewSampleFromFile(filename, NULL, 0); + else + { + FILE *fp = fopen(filename, "rb"); + if(!fp) + { + Printf("Failed to open %s\n", filename); + return false; + } + + const char *ext = strrchr(filename, '.'); + if(ext) ext++; + + SDL_RWops *ops = SDL_AllocRW(); + ops->seek = RWSubFile::seek; + ops->read = RWSubFile::read; + ops->write = RWSubFile::write; + ops->close = RWSubFile::close; + ops->type = 0xdeadbeef; + ops->hidden.unknown.data1 = new RWSubFile(fp, offset, length); + + Sample = Sound_NewSample(ops, ext, NULL, 0); + } + if(!Sample) + { + Printf("Could not open audio in %s (%s)\n", filename, Sound_GetError()); + return false; + } + + return InitSample(); +} + +bool OpenALSoundStream::Init(const BYTE *data, unsigned int datalen) +{ + if(!SetupSource()) + return false; + + Sample = Sound_NewSample(SDL_RWFromConstMem(data, datalen), NULL, NULL, 0); + if(!Sample) + { + Printf("Could not read audio: %s\n", Sound_GetError()); + return false; + } + + return InitSample(); +} + + +Decoder::Decoder(const void* data, unsigned int datalen) + : Sample(NULL), NeedSwab(false) +{ + Sample = Sound_NewSample(SDL_RWFromConstMem(data, datalen), NULL, NULL, 65536); +} + + +Decoder::~Decoder() +{ + Sound_FreeSample(Sample); + Sample = NULL; +} + +bool Decoder::GetFormat(ALenum *format, ALuint *rate) +{ + ALenum fmt = AL_NONE; + if(Sample->actual.format == AUDIO_U8) + { + if(Sample->actual.channels == 1) + fmt = AL_FORMAT_MONO8; + else if(Sample->actual.channels == 2) + fmt = AL_FORMAT_STEREO8; + } + else if(Sample->actual.format == AUDIO_S16LSB || Sample->actual.format == AUDIO_S16MSB) + { + NeedSwab = (Sample->actual.format != AUDIO_S16SYS); + if(Sample->actual.channels == 1) + fmt = AL_FORMAT_MONO16; + else if(Sample->actual.channels == 2) + fmt = AL_FORMAT_STEREO16; + } + + if(fmt == AL_NONE) + { + Printf("Unsupported sound format (0x%04x, %d channels)\n", Sample->actual.format, Sample->actual.channels); + return false; + } + + *format = fmt; + *rate = Sample->actual.rate; + return true; +} + +void* Decoder::GetData(ALsizei *size) +{ + UInt32 got = Sound_DecodeAll(Sample); + if(got == 0) + { + *size = 0; + return NULL; + } + + void *data = Sample->buffer; + if(NeedSwab) + { + short *samples = reinterpret_cast(data); + size_t count = got >> 1; + for(size_t i = 0;i < count;i++) + { + short smp = *samples; + *(samples++) = ((smp>>8)&0x00FF) | ((smp<<8)*0xFF00); + } + } + + *size = got; + return data; +} diff --git a/src/sound/oalsdlsound.h b/src/sound/oalsdlsound.h new file mode 100644 index 0000000000..847edfb32d --- /dev/null +++ b/src/sound/oalsdlsound.h @@ -0,0 +1,66 @@ +#ifndef OALSDLSOUND_H +#define OALSDLSOUND_H + +#include "oalsound.h" +#include "tempfiles.h" + +#include "SDL_sound.h" + +class OpenALSoundStream : public SoundStream +{ + OpenALSoundRenderer *Renderer; + Sound_Sample *Sample; + ALuint Source; + + bool Playing; + bool Looping; + + static const ALfloat BufferTime = 0.2f; + std::vector Buffers; + + ALuint SampleRate; + ALenum Format; + + bool NeedSwab; + void *GetData(size_t bytes); + + // General methods + bool SetupSource(); + bool InitSample(); + + ALfloat Volume; + +public: + OpenALSoundStream(OpenALSoundRenderer *renderer); + virtual ~OpenALSoundStream(); + + virtual bool Play(bool looping, float vol); + virtual void Stop(); + virtual bool SetPaused(bool paused); + + virtual void SetVolume(float vol); + + virtual unsigned int GetPosition(); + virtual bool SetPosition(unsigned int val); + + virtual bool IsEnded(); + + bool Init(const char *filename, int offset, int length); + bool Init(const BYTE *data, unsigned int datalen); +}; + + +class Decoder +{ + Sound_Sample *Sample; + bool NeedSwab; + +public: + Decoder(const void *data, unsigned int datalen); + virtual ~Decoder(); + + bool GetFormat(ALenum *format, ALuint *rate); + void *GetData(ALsizei *size); +}; + +#endif /* OALSDLSOUND_H */ diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 541308a64a..afcfe9727a 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -1,1575 +1,1787 @@ -/* -** oalsound.cpp -** System interface for sound; uses OpenAL -** -**--------------------------------------------------------------------------- -** Copyright 2008-2010 Chris Robinson -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**--------------------------------------------------------------------------- -** -*/ - -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include -#define USE_WINDOWS_DWORD -#endif - -#include "doomstat.h" -#include "templates.h" -#include "oalsound.h" -#include "c_cvars.h" -#include "c_dispatch.h" -#include "i_system.h" -#include "v_text.h" -#include "gi.h" -#include "actor.h" -#include "r_state.h" -#include "w_wad.h" -#include "i_music.h" -#include "i_musicinterns.h" -#include "tempfiles.h" - - -CVAR (String, snd_aldevice, "Default", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CVAR (Bool, snd_efx, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CUSTOM_CVAR (Float, snd_waterabsorption, 10.0f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - if(*self < 0.0f) - self = 0.0f; - else if(*self > 10.0f) - self = 10.0f; -} - -void I_BuildALDeviceList(FOptionValues *opt) -{ - opt->mValues.Resize(1); - opt->mValues[0].TextValue = "Default"; - opt->mValues[0].Text = "Default"; - -#ifndef NO_OPENAL - const ALCchar *names = (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") ? - alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER) : - alcGetString(NULL, ALC_DEVICE_SPECIFIER)); - if(!names) - Printf("Failed to get device list: %s\n", alcGetString(NULL, alcGetError(NULL))); - else while(*names) - { - unsigned int i = opt->mValues.Reserve(1); - opt->mValues[i].TextValue = names; - opt->mValues[i].Text = names; - - names += strlen(names)+1; - } -#endif -} - -#ifndef NO_OPENAL - -#include -#include -#include -#include - - -EXTERN_CVAR (Int, snd_channels) -EXTERN_CVAR (Int, snd_samplerate) -EXTERN_CVAR (Bool, snd_waterreverb) -EXTERN_CVAR (Bool, snd_pitched) - - -#define foreach(type, name, vec) \ - for(std::vector::iterator (name) = (vec).begin(), \ - (_end_##name) = (vec).end(); \ - (name) != (_end_##name);(name)++) - - -static ALenum checkALError(const char *fn, unsigned int ln) -{ - ALenum err = alGetError(); - if(err != AL_NO_ERROR) - { - if(strchr(fn, '/')) - fn = strrchr(fn, '/')+1; - else if(strchr(fn, '\\')) - fn = strrchr(fn, '\\')+1; - Printf(">>>>>>>>>>>> Received AL error %s (%#x), %s:%u\n", alGetString(err), err, fn, ln); - } - return err; -} -#define getALError() checkALError(__FILE__, __LINE__) - -static ALCenum checkALCError(ALCdevice *device, const char *fn, unsigned int ln) -{ - ALCenum err = alcGetError(device); - if(err != ALC_NO_ERROR) - { - if(strchr(fn, '/')) - fn = strrchr(fn, '/')+1; - else if(strchr(fn, '\\')) - fn = strrchr(fn, '\\')+1; - Printf(">>>>>>>>>>>> Received ALC error %s (%#x), %s:%u\n", alcGetString(device, err), err, fn, ln); - } - return err; -} -#define getALCError(d) checkALCError((d), __FILE__, __LINE__) - -extern ReverbContainer *ForcedEnvironment; - -#define PITCH_MULT (0.7937005f) /* Approx. 4 semitones lower; what Nash suggested */ - -#define PITCH(pitch) (snd_pitched ? (pitch)/128.f : 1.f) - - -static float GetRolloff(const FRolloffInfo *rolloff, float distance) -{ - if(distance <= rolloff->MinDistance) - return 1.f; - // Logarithmic rolloff has no max distance where it goes silent. - if(rolloff->RolloffType == ROLLOFF_Log) - return rolloff->MinDistance / - (rolloff->MinDistance + rolloff->RolloffFactor*(distance-rolloff->MinDistance)); - if(distance >= rolloff->MaxDistance) - return 0.f; - - float volume = (rolloff->MaxDistance - distance) / (rolloff->MaxDistance - rolloff->MinDistance); - if(rolloff->RolloffType == ROLLOFF_Linear) - return volume; - - if(rolloff->RolloffType == ROLLOFF_Custom && S_SoundCurve != NULL) - return S_SoundCurve[int(S_SoundCurveSize * (1.f - volume))] / 127.f; - return (powf(10.f, volume) - 1.f) / 9.f; -} - - -static ALenum FormatFromDesc(int bits, int channels) -{ - if(bits == 8) - { - if(channels == 1) return AL_FORMAT_MONO8; - if(channels == 2) return AL_FORMAT_STEREO8; - if(channels == 4) return AL_FORMAT_QUAD8; - if(channels == 6) return AL_FORMAT_51CHN8; - if(channels == 7) return AL_FORMAT_61CHN8; - if(channels == 8) return AL_FORMAT_71CHN8; - } - if(bits == 16) - { - if(channels == 1) return AL_FORMAT_MONO16; - if(channels == 2) return AL_FORMAT_STEREO16; - if(channels == 4) return AL_FORMAT_QUAD16; - if(channels == 6) return AL_FORMAT_51CHN16; - if(channels == 7) return AL_FORMAT_61CHN16; - if(channels == 8) return AL_FORMAT_71CHN16; - } - if(bits == 32) - { - if(channels == 1) return AL_FORMAT_MONO_FLOAT32; - if(channels == 2) return AL_FORMAT_STEREO_FLOAT32; - if(channels == 4) return AL_FORMAT_QUAD32; - if(channels == 6) return AL_FORMAT_51CHN32; - if(channels == 7) return AL_FORMAT_61CHN32; - if(channels == 8) return AL_FORMAT_71CHN32; - } - return AL_NONE; -} - - -class OpenALSoundStream : public SoundStream -{ - OpenALSoundRenderer *Renderer; - -public: - FTempFileName tmpfile; - ALfloat Volume; - - OpenALSoundStream(OpenALSoundRenderer *renderer) - : Renderer(renderer), Volume(1.0f) - { Renderer->Streams.push_back(this); } - - virtual ~OpenALSoundStream() - { - Renderer->Streams.erase(std::find(Renderer->Streams.begin(), - Renderer->Streams.end(), this)); - Renderer = NULL; - } - - - virtual bool Play(bool, float) - { return false; } - - virtual void Stop() - { } - - virtual void SetVolume(float vol) - { Volume = vol; } - - virtual bool SetPaused(bool) - { return false; } - - virtual unsigned int GetPosition() - { return 0; } - - virtual bool IsEnded() - { return true; } - - bool Init(const char*) - { return false; } - - bool Init(const BYTE*, unsigned int) - { return false; } - - bool Init(SoundStreamCallback, int, int, int, void*) - { return false; } -}; - -class Decoder -{ -public: - std::vector OutData; - ALint LoopPts[2]; - ALsizei OutRate; - ALuint OutChannels; - ALuint OutBits; - - Decoder() - : OutRate(0), OutChannels(0), OutBits(0) - { LoopPts[0] = LoopPts[1] = 0; } - - bool Decode(const void*, unsigned int, int=0) - { return false; } -}; - - -template -static void LoadALFunc(const char *name, T *x) -{ *x = reinterpret_cast(alGetProcAddress(name)); } - -OpenALSoundRenderer::OpenALSoundRenderer() - : Device(NULL), Context(NULL), SrcDistanceModel(false), SFXPaused(0), - PrevEnvironment(NULL), EnvSlot(0) -{ - EnvFilters[0] = EnvFilters[1] = 0; - - Printf("I_InitSound: Initializing OpenAL\n"); - - if(strcmp(snd_aldevice, "Default") != 0) - { - Device = alcOpenDevice(*snd_aldevice); - if(!Device) - Printf(TEXTCOLOR_BLUE" Failed to open device "TEXTCOLOR_BOLD"%s"TEXTCOLOR_BLUE". Trying default.\n", *snd_aldevice); - } - - if(!Device) - { - Device = alcOpenDevice(NULL); - if(!Device) - { - Printf(TEXTCOLOR_RED" Could not open audio device\n"); - return; - } - } - - Printf(" Opened device "TEXTCOLOR_ORANGE"%s\n", alcGetString(Device, ALC_DEVICE_SPECIFIER)); - ALCint major=0, minor=0; - alcGetIntegerv(Device, ALC_MAJOR_VERSION, 1, &major); - alcGetIntegerv(Device, ALC_MINOR_VERSION, 1, &minor); - DPrintf(" ALC Version: "TEXTCOLOR_BLUE"%d.%d\n", major, minor); - DPrintf(" ALC Extensions: "TEXTCOLOR_ORANGE"%s\n", alcGetString(Device, ALC_EXTENSIONS)); - - DisconnectNotify = alcIsExtensionPresent(Device, "ALC_EXT_disconnect"); - - std::vector attribs; - if(*snd_samplerate > 0) - { - attribs.push_back(ALC_FREQUENCY); - attribs.push_back(*snd_samplerate); - } - // Make sure one source is capable of stereo output with the rest doing - // mono, without running out of voices - attribs.push_back(ALC_MONO_SOURCES); - attribs.push_back((std::max)(*snd_channels, 2) - 1); - attribs.push_back(ALC_STEREO_SOURCES); - attribs.push_back(1); - // Other attribs..? - attribs.push_back(0); - - Context = alcCreateContext(Device, &attribs[0]); - if(!Context || alcMakeContextCurrent(Context) == ALC_FALSE) - { - Printf(TEXTCOLOR_RED" Failed to setup context: %s\n", alcGetString(Device, alcGetError(Device))); - if(Context) - alcDestroyContext(Context); - Context = NULL; - alcCloseDevice(Device); - Device = NULL; - return; - } - attribs.clear(); - - DPrintf(" Vendor: "TEXTCOLOR_ORANGE"%s\n", alGetString(AL_VENDOR)); - DPrintf(" Renderer: "TEXTCOLOR_ORANGE"%s\n", alGetString(AL_RENDERER)); - DPrintf(" Version: "TEXTCOLOR_ORANGE"%s\n", alGetString(AL_VERSION)); - DPrintf(" Extensions: "TEXTCOLOR_ORANGE"%s\n", alGetString(AL_EXTENSIONS)); - - SrcDistanceModel = alIsExtensionPresent("AL_EXT_source_distance_model"); - LoopPoints = alIsExtensionPresent("AL_SOFT_loop_points"); - - alDopplerFactor(0.5f); - alSpeedOfSound(343.3f * 96.0f); - alDistanceModel(AL_INVERSE_DISTANCE); - if(SrcDistanceModel) - alEnable(AL_SOURCE_DISTANCE_MODEL); - - ALenum err = getALError(); - if(err != AL_NO_ERROR) - { - alcMakeContextCurrent(NULL); - alcDestroyContext(Context); - Context = NULL; - alcCloseDevice(Device); - Device = NULL; - return; - } - - ALCint numMono=0, numStereo=0; - alcGetIntegerv(Device, ALC_MONO_SOURCES, 1, &numMono); - alcGetIntegerv(Device, ALC_STEREO_SOURCES, 1, &numStereo); - - Sources.resize((std::min)((std::max)(*snd_channels, 2), numMono+numStereo)); - for(size_t i = 0;i < Sources.size();i++) - { - alGenSources(1, &Sources[i]); - if(getALError() != AL_NO_ERROR) - { - Sources.resize(i); - break; - } - FreeSfx.push_back(Sources[i]); - } - if(Sources.size() == 0) - { - Printf(TEXTCOLOR_RED" Error: could not generate any sound sources!\n"); - alcMakeContextCurrent(NULL); - alcDestroyContext(Context); - Context = NULL; - alcCloseDevice(Device); - Device = NULL; - return; - } - DPrintf(" Allocated "TEXTCOLOR_BLUE"%u"TEXTCOLOR_NORMAL" sources\n", Sources.size()); - - LastWaterAbsorb = 0.0f; - if(*snd_efx && alcIsExtensionPresent(Device, "ALC_EXT_EFX")) - { - // EFX function pointers -#define LOAD_FUNC(x) (LoadALFunc(#x, &x)) - LOAD_FUNC(alGenEffects); - LOAD_FUNC(alDeleteEffects); - LOAD_FUNC(alIsEffect); - LOAD_FUNC(alEffecti); - LOAD_FUNC(alEffectiv); - LOAD_FUNC(alEffectf); - LOAD_FUNC(alEffectfv); - LOAD_FUNC(alGetEffecti); - LOAD_FUNC(alGetEffectiv); - LOAD_FUNC(alGetEffectf); - LOAD_FUNC(alGetEffectfv); - - LOAD_FUNC(alGenFilters); - LOAD_FUNC(alDeleteFilters); - LOAD_FUNC(alIsFilter); - LOAD_FUNC(alFilteri); - LOAD_FUNC(alFilteriv); - LOAD_FUNC(alFilterf); - LOAD_FUNC(alFilterfv); - LOAD_FUNC(alGetFilteri); - LOAD_FUNC(alGetFilteriv); - LOAD_FUNC(alGetFilterf); - LOAD_FUNC(alGetFilterfv); - - LOAD_FUNC(alGenAuxiliaryEffectSlots); - LOAD_FUNC(alDeleteAuxiliaryEffectSlots); - LOAD_FUNC(alIsAuxiliaryEffectSlot); - LOAD_FUNC(alAuxiliaryEffectSloti); - LOAD_FUNC(alAuxiliaryEffectSlotiv); - LOAD_FUNC(alAuxiliaryEffectSlotf); - LOAD_FUNC(alAuxiliaryEffectSlotfv); - LOAD_FUNC(alGetAuxiliaryEffectSloti); - LOAD_FUNC(alGetAuxiliaryEffectSlotiv); - LOAD_FUNC(alGetAuxiliaryEffectSlotf); - LOAD_FUNC(alGetAuxiliaryEffectSlotfv); -#undef LOAD_FUNC - if(getALError() == AL_NO_ERROR) - { - ALuint envReverb; - alGenEffects(1, &envReverb); - if(getALError() == AL_NO_ERROR) - { - alEffecti(envReverb, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB); - if(alGetError() == AL_NO_ERROR) - DPrintf(" EAX Reverb found\n"); - alEffecti(envReverb, AL_EFFECT_TYPE, AL_EFFECT_REVERB); - if(alGetError() == AL_NO_ERROR) - DPrintf(" Standard Reverb found\n"); - - alDeleteEffects(1, &envReverb); - getALError(); - } - - alGenAuxiliaryEffectSlots(1, &EnvSlot); - alGenFilters(2, EnvFilters); - if(getALError() == AL_NO_ERROR) - { - alFilteri(EnvFilters[0], AL_FILTER_TYPE, AL_FILTER_LOWPASS); - alFilteri(EnvFilters[1], AL_FILTER_TYPE, AL_FILTER_LOWPASS); - if(getALError() == AL_NO_ERROR) - DPrintf(" Lowpass found\n"); - else - { - alDeleteFilters(2, EnvFilters); - EnvFilters[0] = EnvFilters[1] = 0; - alDeleteAuxiliaryEffectSlots(1, &EnvSlot); - EnvSlot = 0; - getALError(); - } - } - else - { - alDeleteFilters(2, EnvFilters); - alDeleteAuxiliaryEffectSlots(1, &EnvSlot); - EnvFilters[0] = EnvFilters[1] = 0; - EnvSlot = 0; - getALError(); - } - } - } - - if(EnvSlot) - Printf(" EFX enabled\n"); - - snd_sfxvolume.Callback(); -} - -OpenALSoundRenderer::~OpenALSoundRenderer() -{ - if(!Device) - return; - - while(Streams.size() > 0) - delete Streams[0]; - - alDeleteSources(Sources.size(), &Sources[0]); - Sources.clear(); - FreeSfx.clear(); - SfxGroup.clear(); - PausableSfx.clear(); - ReverbSfx.clear(); - - for(EffectMap::iterator i = EnvEffects.begin();i != EnvEffects.end();i++) - { - if(i->second) - alDeleteEffects(1, &(i->second)); - } - EnvEffects.clear(); - - if(EnvSlot) - { - alDeleteAuxiliaryEffectSlots(1, &EnvSlot); - alDeleteFilters(2, EnvFilters); - } - EnvSlot = 0; - EnvFilters[0] = EnvFilters[1] = 0; - - alcMakeContextCurrent(NULL); - alcDestroyContext(Context); - Context = NULL; - alcCloseDevice(Device); - Device = NULL; -} - -void OpenALSoundRenderer::SetSfxVolume(float volume) -{ - SfxVolume = volume; - - FSoundChan *schan = Channels; - while(schan) - { - if(schan->SysChannel != NULL) - { - ALuint source = *((ALuint*)schan->SysChannel); - volume = SfxVolume; - - alcSuspendContext(Context); - alSourcef(source, AL_MAX_GAIN, volume); - if(schan->ManualGain) - volume *= GetRolloff(&schan->Rolloff, sqrt(schan->DistanceSqr)); - alSourcef(source, AL_GAIN, volume * ((FSoundChan*)schan)->Volume); - } - schan = schan->NextChan; - } - - getALError(); -} - -void OpenALSoundRenderer::SetMusicVolume(float volume) -{ - MusicVolume = volume; - foreach(OpenALSoundStream*, i, Streams) - (*i)->SetVolume((*i)->Volume); -} - -unsigned int OpenALSoundRenderer::GetMSLength(SoundHandle sfx) -{ - if(sfx.data) - { - ALuint buffer = *((ALuint*)sfx.data); - if(alIsBuffer(buffer)) - { - ALint bits, channels, freq, size; - alGetBufferi(buffer, AL_BITS, &bits); - alGetBufferi(buffer, AL_CHANNELS, &channels); - alGetBufferi(buffer, AL_FREQUENCY, &freq); - alGetBufferi(buffer, AL_SIZE, &size); - if(getALError() == AL_NO_ERROR) - return (unsigned int)(size / (channels*bits/8) * 1000. / freq); - } - } - return 0; -} - -unsigned int OpenALSoundRenderer::GetSampleLength(SoundHandle sfx) -{ - if(sfx.data) - { - ALuint buffer = *((ALuint*)sfx.data); - ALint bits, channels, size; - alGetBufferi(buffer, AL_BITS, &bits); - alGetBufferi(buffer, AL_CHANNELS, &channels); - alGetBufferi(buffer, AL_SIZE, &size); - if(getALError() == AL_NO_ERROR) - return (ALsizei)(size / (channels * bits / 8)); - } - return 0; -} - -float OpenALSoundRenderer::GetOutputRate() -{ - ALCint rate = 44100; // Default, just in case - alcGetIntegerv(Device, ALC_FREQUENCY, 1, &rate); - return (float)rate; -} - - -SoundHandle OpenALSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int length, int frequency, int channels, int bits, int loopstart, int loopend) -{ - SoundHandle retval = { NULL }; - - if(length == 0) return retval; - - if(bits == -8) - { - // Simple signed->unsigned conversion - for(int i = 0;i < length;i++) - sfxdata[i] ^= 0x80; - bits = -bits; - } - - ALenum format = AL_NONE; - if(bits == 16) - { - if(channels == 1) format = AL_FORMAT_MONO16; - if(channels == 2) format = AL_FORMAT_STEREO16; - } - else if(bits == 8) - { - if(channels == 1) format = AL_FORMAT_MONO8; - if(channels == 2) format = AL_FORMAT_STEREO8; - } - - if(format == AL_NONE || frequency <= 0) - { - Printf("Unhandled format: %d bit, %d channel, %d hz\n", bits, channels, frequency); - return retval; - } - length -= length%(channels*bits/8); - - ALenum err; - ALuint buffer = 0; - alGenBuffers(1, &buffer); - alBufferData(buffer, format, sfxdata, length, frequency); - if((err=getALError()) != AL_NO_ERROR) - { - Printf("Failed to buffer data: %s\n", alGetString(err)); - alDeleteBuffers(1, &buffer); - getALError(); - return retval; - } - - if((loopstart > 0 || loopend > 0) && LoopPoints) - { - if(loopstart < 0) - loopstart = 0; - if(loopend < loopstart) - loopend = length / (channels*bits/8); - - ALint loops[2] = { loopstart, loopend }; - Printf("Setting loop points %d -> %d\n", loops[0], loops[1]); - alBufferiv(buffer, AL_LOOP_POINTS_SOFT, loops); - getALError(); - } - else if(loopstart > 0 || loopend > 0) - { - static bool warned = false; - if(!warned) - Printf("Loop points not supported!\n"); - warned = true; - } - - retval.data = new ALuint(buffer); - return retval; -} - -SoundHandle OpenALSoundRenderer::LoadSound(BYTE *sfxdata, int length) -{ - SoundHandle retval = { NULL }; - - Decoder decoder; - if(!decoder.Decode(sfxdata, length)) - { - DPrintf("Failed to decode sound\n"); - return retval; - } - - ALenum format = FormatFromDesc(decoder.OutBits, decoder.OutChannels); - if(format == AL_NONE) - { - Printf("Unhandled format: %d bit, %d channel\n", decoder.OutBits, decoder.OutChannels); - return retval; - } - - ALenum err; - ALuint buffer = 0; - alGenBuffers(1, &buffer); - alBufferData(buffer, format, &decoder.OutData[0], - decoder.OutData.size(), decoder.OutRate); - if((err=getALError()) != AL_NO_ERROR) - { - Printf("Failed to buffer data: %s\n", alGetString(err)); - alDeleteBuffers(1, &buffer); - getALError(); - return retval; - } - - if(LoopPoints && decoder.LoopPts[1] > decoder.LoopPts[0]) - { - alBufferiv(buffer, AL_LOOP_POINTS_SOFT, decoder.LoopPts); - getALError(); - } - else if(decoder.LoopPts[1] > decoder.LoopPts[0]) - { - static bool warned = false; - if(!warned) - Printf("Loop points not supported!\n"); - warned = true; - } - - retval.data = new ALuint(buffer); - return retval; -} - -void OpenALSoundRenderer::UnloadSound(SoundHandle sfx) -{ - if(!sfx.data) - return; - - FSoundChan *schan = Channels; - while(schan) - { - if(schan->SysChannel) - { - ALint bufID = 0; - alGetSourcei(*((ALuint*)schan->SysChannel), AL_BUFFER, &bufID); - if(bufID == *((ALint*)sfx.data)) - { - FSoundChan *next = schan->NextChan; - StopChannel(schan); - schan = next; - continue; - } - } - schan = schan->NextChan; - } - - alDeleteBuffers(1, ((ALuint*)sfx.data)); - getALError(); - delete ((ALuint*)sfx.data); -} - -short *OpenALSoundRenderer::DecodeSample(int outlen, const void *coded, int sizebytes, ECodecType type) -{ - Decoder decoder; - // Force 16-bit - if(!decoder.Decode(coded, sizebytes, 16)) - { - DPrintf("Failed to decode sample\n"); - return NULL; - } - if(decoder.OutChannels != 1) - { - DPrintf("Sample is not mono\n"); - return NULL; - } - - short *samples = (short*)malloc(outlen); - if((size_t)outlen > decoder.OutData.size()) - { - memcpy(samples, &decoder.OutData[0], decoder.OutData.size()); - memset(&samples[decoder.OutData.size()/sizeof(short)], 0, outlen-decoder.OutData.size()); - } - else - memcpy(samples, &decoder.OutData[0], outlen); - - return samples; -} - -SoundStream *OpenALSoundRenderer::CreateStream(SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata) -{ - OpenALSoundStream *stream = new OpenALSoundStream(this); - if(!stream->Init(callback, buffbytes, flags, samplerate, userdata)) - { - delete stream; - stream = NULL; - } - return stream; -} - -SoundStream *OpenALSoundRenderer::OpenStream(const char *filename, int flags, int offset, int length) -{ - std::auto_ptr stream(new OpenALSoundStream(this)); - - if(offset > 0) - { - // If there's an offset to the start of the data, separate it into its - // own temp file - FILE *infile = fopen(filename, "rb"); - FILE *f = fopen(stream->tmpfile, "wb"); - if(!infile || !f || fseek(infile, offset, SEEK_SET) != 0) - { - if(infile) fclose(infile); - if(f) fclose(f); - return NULL; - } - BYTE buf[1024]; - size_t got; - do { - got = (std::min)(sizeof(buf), (size_t)length); - got = fread(buf, 1, got, infile); - if(got == 0) - break; - } while(fwrite(buf, 1, got, f) == got && (length-=got) > 0); - fclose(f); - fclose(infile); - - filename = stream->tmpfile; - } - - bool ok = ((offset == -1) ? stream->Init((const BYTE*)filename, length) : - stream->Init(filename)); - if(ok == false) - return NULL; - - return stream.release(); -} - -FISoundChannel *OpenALSoundRenderer::StartSound(SoundHandle sfx, float vol, int pitch, int chanflags, FISoundChannel *reuse_chan) -{ - if(FreeSfx.size() == 0) - { - FSoundChan *lowest = FindLowestChannel(); - if(lowest) StopChannel(lowest); - - if(FreeSfx.size() == 0) - return NULL; - } - - ALuint buffer = *((ALuint*)sfx.data); - ALuint &source = *std::find(Sources.begin(), Sources.end(), FreeSfx.back()); - alSource3f(source, AL_POSITION, 0.f, 0.f, 0.f); - alSource3f(source, AL_VELOCITY, 0.f, 0.f, 0.f); - alSource3f(source, AL_DIRECTION, 0.f, 0.f, 0.f); - alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); - - alSourcei(source, AL_LOOPING, (chanflags&SNDF_LOOP) ? AL_TRUE : AL_FALSE); - - alSourcef(source, AL_REFERENCE_DISTANCE, 1.f); - alSourcef(source, AL_MAX_DISTANCE, 1000.f); - alSourcef(source, AL_ROLLOFF_FACTOR, 0.f); - alSourcef(source, AL_MAX_GAIN, SfxVolume); - alSourcef(source, AL_GAIN, SfxVolume*vol); - - if(EnvSlot) - { - if(!(chanflags&SNDF_NOREVERB)) - { - alSourcei(source, AL_DIRECT_FILTER, EnvFilters[0]); - alSource3i(source, AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); - alSourcef(source, AL_AIR_ABSORPTION_FACTOR, LastWaterAbsorb); - } - else - { - alSourcei(source, AL_DIRECT_FILTER, AL_FILTER_NULL); - alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL); - alSourcef(source, AL_AIR_ABSORPTION_FACTOR, 0.f); - } - alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, 0.f); - alSourcef(source, AL_PITCH, PITCH(pitch)); - } - else if(LastWaterAbsorb > 0.f && !(chanflags&SNDF_NOREVERB)) - alSourcef(source, AL_PITCH, PITCH(pitch)*PITCH_MULT); - else - alSourcef(source, AL_PITCH, PITCH(pitch)); - - if(!reuse_chan) - alSourcef(source, AL_SEC_OFFSET, 0.f); - else - { - if((chanflags&SNDF_ABSTIME)) - alSourcef(source, AL_SEC_OFFSET, reuse_chan->StartTime.Lo/1000.f); - else - { - // FIXME: set offset based on the current time and the StartTime - alSourcef(source, AL_SEC_OFFSET, 0.f); - } - } - if(getALError() != AL_NO_ERROR) - return NULL; - - alSourcei(source, AL_BUFFER, buffer); - if((chanflags&SNDF_NOPAUSE) || !SFXPaused) - alSourcePlay(source); - if(getALError() != AL_NO_ERROR) - { - alSourcei(source, AL_BUFFER, 0); - getALError(); - return NULL; - } - - if(!(chanflags&SNDF_NOREVERB)) - ReverbSfx.push_back(source); - if(!(chanflags&SNDF_NOPAUSE)) - PausableSfx.push_back(source); - SfxGroup.push_back(source); - FreeSfx.pop_back(); - - FISoundChannel *chan = reuse_chan; - if(!chan) chan = S_GetChannel(&source); - else chan->SysChannel = &source; - - chan->Rolloff.RolloffType = ROLLOFF_Linear; - chan->Rolloff.MaxDistance = 1000.f; - chan->Rolloff.MinDistance = 1.f; - chan->DistanceScale = 1.f; - chan->DistanceSqr = 1.f; - chan->ManualGain = false; - - return chan; -} - -FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener *listener, float vol, - FRolloffInfo *rolloff, float distscale, int pitch, int priority, const FVector3 &pos, const FVector3 &vel, - int channum, int chanflags, FISoundChannel *reuse_chan) -{ - float dist_sqr = (pos - listener->position).LengthSquared() * - distscale*distscale; - - if(FreeSfx.size() == 0) - { - FSoundChan *lowest = FindLowestChannel(); - if(lowest) - { - if(lowest->Priority < priority || (lowest->Priority == priority && - lowest->DistanceSqr > dist_sqr)) - StopChannel(lowest); - } - if(FreeSfx.size() == 0) - return NULL; - } - - float rolloffFactor, gain; - bool manualGain = true; - - ALuint buffer = *((ALuint*)sfx.data); - ALint channels = 1; - alGetBufferi(buffer, AL_CHANNELS, &channels); - - ALuint &source = *std::find(Sources.begin(), Sources.end(), FreeSfx.back()); - alSource3f(source, AL_POSITION, pos[0], pos[1], -pos[2]); - alSource3f(source, AL_VELOCITY, vel[0], vel[1], -vel[2]); - alSource3f(source, AL_DIRECTION, 0.f, 0.f, 0.f); - alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); - - alSourcei(source, AL_LOOPING, (chanflags&SNDF_LOOP) ? AL_TRUE : AL_FALSE); - - // Multi-channel sources won't attenuate in OpenAL, and "area sounds" have - // special rolloff properties (they have a panning radius of 32 units, but - // start attenuating at MinDistance). - if(channels == 1 && !(chanflags&SNDF_AREA)) - { - if(rolloff->RolloffType == ROLLOFF_Log) - { - if(SrcDistanceModel) - alSourcei(source, AL_DISTANCE_MODEL, AL_INVERSE_DISTANCE); - alSourcef(source, AL_REFERENCE_DISTANCE, rolloff->MinDistance/distscale); - alSourcef(source, AL_MAX_DISTANCE, (1000.f+rolloff->MinDistance)/distscale); - rolloffFactor = rolloff->RolloffFactor; - manualGain = false; - gain = 1.f; - } - else if(rolloff->RolloffType == ROLLOFF_Linear && SrcDistanceModel) - { - alSourcei(source, AL_DISTANCE_MODEL, AL_LINEAR_DISTANCE); - alSourcef(source, AL_REFERENCE_DISTANCE, rolloff->MinDistance/distscale); - alSourcef(source, AL_MAX_DISTANCE, rolloff->MaxDistance/distscale); - rolloffFactor = 1.f; - manualGain = false; - gain = 1.f; - } - } - if(manualGain) - { - if(SrcDistanceModel) - alSourcei(source, AL_DISTANCE_MODEL, AL_NONE); - if((chanflags&SNDF_AREA) && rolloff->MinDistance < 32.f) - alSourcef(source, AL_REFERENCE_DISTANCE, 32.f/distscale); - else - alSourcef(source, AL_REFERENCE_DISTANCE, rolloff->MinDistance/distscale); - alSourcef(source, AL_MAX_DISTANCE, (1000.f+rolloff->MinDistance)/distscale); - rolloffFactor = 0.f; - gain = GetRolloff(rolloff, sqrt(dist_sqr)); - } - alSourcef(source, AL_ROLLOFF_FACTOR, rolloffFactor); - alSourcef(source, AL_MAX_GAIN, SfxVolume); - alSourcef(source, AL_GAIN, SfxVolume * gain); - - if(EnvSlot) - { - if(!(chanflags&SNDF_NOREVERB)) - { - alSourcei(source, AL_DIRECT_FILTER, EnvFilters[0]); - alSource3i(source, AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); - alSourcef(source, AL_AIR_ABSORPTION_FACTOR, LastWaterAbsorb); - } - else - { - alSourcei(source, AL_DIRECT_FILTER, AL_FILTER_NULL); - alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL); - alSourcef(source, AL_AIR_ABSORPTION_FACTOR, 0.f); - } - alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, rolloffFactor); - alSourcef(source, AL_PITCH, PITCH(pitch)); - } - else if(LastWaterAbsorb > 0.f && !(chanflags&SNDF_NOREVERB)) - alSourcef(source, AL_PITCH, PITCH(pitch)*PITCH_MULT); - else - alSourcef(source, AL_PITCH, PITCH(pitch)); - - if(!reuse_chan) - alSourcef(source, AL_SEC_OFFSET, 0.f); - else - { - if((chanflags&SNDF_ABSTIME)) - alSourcef(source, AL_SEC_OFFSET, reuse_chan->StartTime.Lo/1000.f); - else - { - // FIXME: set offset based on the current time and the StartTime - alSourcef(source, AL_SAMPLE_OFFSET, 0.f); - } - } - if(getALError() != AL_NO_ERROR) - return NULL; - - alSourcei(source, AL_BUFFER, buffer); - if((chanflags&SNDF_NOPAUSE) || !SFXPaused) - alSourcePlay(source); - if(getALError() != AL_NO_ERROR) - { - alSourcei(source, AL_BUFFER, 0); - getALError(); - return NULL; - } - - if(!(chanflags&SNDF_NOREVERB)) - ReverbSfx.push_back(source); - if(!(chanflags&SNDF_NOPAUSE)) - PausableSfx.push_back(source); - SfxGroup.push_back(source); - FreeSfx.pop_back(); - - FISoundChannel *chan = reuse_chan; - if(!chan) chan = S_GetChannel(&source); - else chan->SysChannel = &source; - - chan->Rolloff = *rolloff; - chan->DistanceScale = distscale; - chan->DistanceSqr = dist_sqr; - chan->ManualGain = manualGain; - - return chan; -} - -void OpenALSoundRenderer::ChannelVolume(FISoundChannel *chan, float volume) -{ - if(chan == NULL || chan->SysChannel == NULL) - return; - - alcSuspendContext(Context); - - ALuint source = *((ALuint*)chan->SysChannel); - - if(chan->ManualGain) - volume *= GetRolloff(&chan->Rolloff, sqrt(chan->DistanceSqr)); - alSourcef(source, AL_GAIN, SfxVolume * volume); -} - -void OpenALSoundRenderer::StopChannel(FISoundChannel *chan) -{ - if(chan == NULL || chan->SysChannel == NULL) - return; - - ALuint source = *((ALuint*)chan->SysChannel); - // Release first, so it can be properly marked as evicted if it's being - // forcefully killed - S_ChannelEnded(chan); - - alSourceRewind(source); - alSourcei(source, AL_BUFFER, 0); - getALError(); - - std::vector::iterator i; - - i = std::find(PausableSfx.begin(), PausableSfx.end(), source); - if(i != PausableSfx.end()) PausableSfx.erase(i); - i = std::find(ReverbSfx.begin(), ReverbSfx.end(), source); - if(i != ReverbSfx.end()) ReverbSfx.erase(i); - - SfxGroup.erase(std::find(SfxGroup.begin(), SfxGroup.end(), source)); - FreeSfx.push_back(source); -} - -unsigned int OpenALSoundRenderer::GetPosition(FISoundChannel *chan) -{ - if(chan == NULL || chan->SysChannel == NULL) - return 0; - - ALint pos; - alGetSourcei(*((ALuint*)chan->SysChannel), AL_SAMPLE_OFFSET, &pos); - if(getALError() == AL_NO_ERROR) - return pos; - return 0; -} - - -void OpenALSoundRenderer::SetSfxPaused(bool paused, int slot) -{ - int oldslots = SFXPaused; - - if(paused) - { - SFXPaused |= 1 << slot; - if(oldslots == 0 && PausableSfx.size() > 0) - { - alSourcePausev(PausableSfx.size(), &PausableSfx[0]); - getALError(); - PurgeStoppedSources(); - } - } - else - { - SFXPaused &= ~(1 << slot); - if(SFXPaused == 0 && oldslots != 0 && PausableSfx.size() > 0) - { - alSourcePlayv(PausableSfx.size(), &PausableSfx[0]); - getALError(); - } - } -} - -void OpenALSoundRenderer::SetInactive(EInactiveState) -{ -} - -void OpenALSoundRenderer::Sync(bool sync) -{ - if(sync) - { - if(SfxGroup.size() > 0) - { - alSourcePausev(SfxGroup.size(), &SfxGroup[0]); - getALError(); - PurgeStoppedSources(); - } - } - else - { - // Might already be something to handle this; basically, get a vector - // of all values in SfxGroup that are not also in PausableSfx (when - // SFXPaused is non-0). - std::vector toplay = SfxGroup; - if(SFXPaused) - { - std::vector::iterator i = toplay.begin(); - while(i != toplay.end()) - { - if(std::find(PausableSfx.begin(), PausableSfx.end(), *i) != PausableSfx.end()) - i = toplay.erase(i); - else - i++; - } - } - if(toplay.size() > 0) - { - alSourcePlayv(toplay.size(), &toplay[0]); - getALError(); - } - } -} - -void OpenALSoundRenderer::UpdateSoundParams3D(SoundListener *listener, FISoundChannel *chan, bool areasound, const FVector3 &pos, const FVector3 &vel) -{ - if(chan == NULL || chan->SysChannel == NULL) - return; - - alcSuspendContext(Context); - - ALuint source = *((ALuint*)chan->SysChannel); - alSource3f(source, AL_POSITION, pos[0], pos[1], -pos[2]); - alSource3f(source, AL_VELOCITY, vel[0], vel[1], -vel[2]); - - chan->DistanceSqr = (pos - listener->position).LengthSquared() * - chan->DistanceScale*chan->DistanceScale; - // Not all sources can use the distance models provided by OpenAL. - // For the ones that can't, apply the calculated attenuation as the - // source gain. Positions still handle the panning, - if(chan->ManualGain) - { - float gain = GetRolloff(&chan->Rolloff, sqrt(chan->DistanceSqr)); - alSourcef(source, AL_GAIN, SfxVolume*gain*((FSoundChan*)chan)->Volume); - } - - getALError(); -} - -void OpenALSoundRenderer::UpdateListener(SoundListener *listener) -{ - if(!listener->valid) - return; - - alcSuspendContext(Context); - - float angle = listener->angle; - ALfloat orient[6]; - // forward - orient[0] = cos(angle); - orient[1] = 0.f; - orient[2] = -sin(angle); - // up - orient[3] = 0.f; - orient[4] = 1.f; - orient[5] = 0.f; - - alListenerfv(AL_ORIENTATION, orient); - alListener3f(AL_POSITION, listener->position.X, - listener->position.Y, - -listener->position.Z); - alListener3f(AL_VELOCITY, listener->velocity.X, - listener->velocity.Y, - -listener->velocity.Z); - getALError(); - - const ReverbContainer *env = ForcedEnvironment; - if(!env) - { - env = listener->Environment; - if(!env) - env = DefaultEnvironments[0]; - } - if(env != PrevEnvironment || env->Modified) - { - PrevEnvironment = env; - DPrintf("Reverb Environment %s\n", env->Name); - - if(EnvSlot != 0) - LoadReverb(env); - - const_cast(env)->Modified = false; - } - - // NOTE: Moving into and out of water (and changing water absorption) will - // undo pitch variations on sounds if either snd_waterreverb or EFX are - // disabled. - if(listener->underwater || env->SoftwareWater) - { - if(LastWaterAbsorb != *snd_waterabsorption) - { - LastWaterAbsorb = *snd_waterabsorption; - - if(EnvSlot != 0 && *snd_waterreverb) - { - // Find the "Underwater" reverb environment - env = Environments; - while(env && env->ID != 0x1600) - env = env->Next; - LoadReverb(env ? env : DefaultEnvironments[0]); - - alFilterf(EnvFilters[0], AL_LOWPASS_GAIN, 0.25f); - alFilterf(EnvFilters[0], AL_LOWPASS_GAINHF, 0.75f); - alFilterf(EnvFilters[1], AL_LOWPASS_GAIN, 1.f); - alFilterf(EnvFilters[1], AL_LOWPASS_GAINHF, 1.f); - - // Apply the updated filters on the sources - foreach(ALuint, i, ReverbSfx) - { - alSourcef(*i, AL_AIR_ABSORPTION_FACTOR, LastWaterAbsorb); - alSourcei(*i, AL_DIRECT_FILTER, EnvFilters[0]); - alSource3i(*i, AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); - } - } - else - { - foreach(ALuint, i, ReverbSfx) - alSourcef(*i, AL_PITCH, PITCH_MULT); - } - getALError(); - } - } - else - { - if(LastWaterAbsorb > 0.f) - { - LastWaterAbsorb = 0.f; - - if(EnvSlot != 0) - { - LoadReverb(env); - - alFilterf(EnvFilters[0], AL_LOWPASS_GAIN, 1.f); - alFilterf(EnvFilters[0], AL_LOWPASS_GAINHF, 1.f); - alFilterf(EnvFilters[1], AL_LOWPASS_GAIN, 1.f); - alFilterf(EnvFilters[1], AL_LOWPASS_GAINHF, 1.f); - foreach(ALuint, i, ReverbSfx) - { - alSourcef(*i, AL_AIR_ABSORPTION_FACTOR, 0.f); - alSourcei(*i, AL_DIRECT_FILTER, EnvFilters[0]); - alSource3i(*i, AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); - } - } - else - { - foreach(ALuint, i, ReverbSfx) - alSourcef(*i, AL_PITCH, 1.f); - } - getALError(); - } - } -} - -void OpenALSoundRenderer::UpdateSounds() -{ - alcProcessContext(Context); - - if(DisconnectNotify) - { - ALCint connected = ALC_TRUE; - alcGetIntegerv(Device, ALC_CONNECTED, 1, &connected); - if(connected == ALC_FALSE) - { - Printf("Sound device disconnected; restarting...\n"); - static char snd_reset[] = "snd_reset"; - AddCommandString(snd_reset); - return; - } - } - - PurgeStoppedSources(); -} - -bool OpenALSoundRenderer::IsValid() -{ - return Device != NULL; -} - -void OpenALSoundRenderer::MarkStartTime(FISoundChannel *chan) -{ - // FIXME: Get current time (preferably from the audio clock, but the system - // time will have to do) - chan->StartTime.AsOne = 0; -} - -float OpenALSoundRenderer::GetAudibility(FISoundChannel *chan) -{ - if(chan == NULL || chan->SysChannel == NULL) - return 0.f; - - ALuint source = *((ALuint*)chan->SysChannel); - ALfloat volume = 0.f; - - if(!chan->ManualGain) - volume = SfxVolume * ((FSoundChan*)chan)->Volume * - GetRolloff(&chan->Rolloff, sqrt(chan->DistanceSqr)); - else - { - alGetSourcef(source, AL_GAIN, &volume); - getALError(); - } - return volume; -} - - -void OpenALSoundRenderer::PrintStatus() -{ - Printf("Output device: "TEXTCOLOR_ORANGE"%s\n", alcGetString(Device, ALC_DEVICE_SPECIFIER)); - getALCError(Device); - - ALCint frequency, major, minor, mono, stereo; - alcGetIntegerv(Device, ALC_FREQUENCY, 1, &frequency); - alcGetIntegerv(Device, ALC_MAJOR_VERSION, 1, &major); - alcGetIntegerv(Device, ALC_MINOR_VERSION, 1, &minor); - alcGetIntegerv(Device, ALC_MONO_SOURCES, 1, &mono); - alcGetIntegerv(Device, ALC_STEREO_SOURCES, 1, &stereo); - if(getALCError(Device) == AL_NO_ERROR) - { - Printf("Device sample rate: "TEXTCOLOR_BLUE"%d"TEXTCOLOR_NORMAL"hz\n", frequency); - Printf("ALC Version: "TEXTCOLOR_BLUE"%d.%d\n", major, minor); - Printf("ALC Extensions: "TEXTCOLOR_ORANGE"%s\n", alcGetString(Device, ALC_EXTENSIONS)); - Printf("Available sources: "TEXTCOLOR_BLUE"%d"TEXTCOLOR_NORMAL" ("TEXTCOLOR_BLUE"%d"TEXTCOLOR_NORMAL" mono, "TEXTCOLOR_BLUE"%d"TEXTCOLOR_NORMAL" stereo)\n", mono+stereo, mono, stereo); - } - if(!alcIsExtensionPresent(Device, "ALC_EXT_EFX")) - Printf("EFX not found\n"); - else - { - ALCint sends; - alcGetIntegerv(Device, ALC_EFX_MAJOR_VERSION, 1, &major); - alcGetIntegerv(Device, ALC_EFX_MINOR_VERSION, 1, &minor); - alcGetIntegerv(Device, ALC_MAX_AUXILIARY_SENDS, 1, &sends); - if(getALCError(Device) == AL_NO_ERROR) - { - Printf("EFX Version: "TEXTCOLOR_BLUE"%d.%d\n", major, minor); - Printf("Auxiliary sends: "TEXTCOLOR_BLUE"%d\n", sends); - } - } - Printf("Vendor: "TEXTCOLOR_ORANGE"%s\n", alGetString(AL_VENDOR)); - Printf("Renderer: "TEXTCOLOR_ORANGE"%s\n", alGetString(AL_RENDERER)); - Printf("Version: "TEXTCOLOR_ORANGE"%s\n", alGetString(AL_VERSION)); - Printf("Extensions: "TEXTCOLOR_ORANGE"%s\n", alGetString(AL_EXTENSIONS)); - getALError(); -} - -FString OpenALSoundRenderer::GatherStats() -{ - ALCint updates = 1; - alcGetIntegerv(Device, ALC_REFRESH, 1, &updates); - getALCError(Device); - - ALuint total = Sources.size(); - ALuint used = SfxGroup.size()+Streams.size(); - ALuint unused = FreeSfx.size(); - FString out; - out.Format("%u sources ("TEXTCOLOR_YELLOW"%u"TEXTCOLOR_NORMAL" active, "TEXTCOLOR_YELLOW"%u"TEXTCOLOR_NORMAL" free), Update interval: "TEXTCOLOR_YELLOW"%d"TEXTCOLOR_NORMAL"ms", - total, used, unused, 1000/updates); - return out; -} - -void OpenALSoundRenderer::PrintDriversList() -{ - const ALCchar *drivers = (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") ? - alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER) : - alcGetString(NULL, ALC_DEVICE_SPECIFIER)); - const ALCchar *current = alcGetString(Device, ALC_DEVICE_SPECIFIER); - if(drivers == NULL) - { - Printf(TEXTCOLOR_YELLOW"Failed to retrieve device list: %s\n", alcGetString(NULL, alcGetError(NULL))); - return; - } - - Printf("%c%s%2d. %s\n", ' ', ((strcmp(snd_aldevice, "Default") == 0) ? TEXTCOLOR_BOLD : ""), 0, - "Default"); - for(int i = 1;*drivers;i++) - { - Printf("%c%s%2d. %s\n", ((strcmp(current, drivers)==0) ? '*' : ' '), - ((strcmp(*snd_aldevice, drivers)==0) ? TEXTCOLOR_BOLD : ""), i, - drivers); - drivers += strlen(drivers)+1; - } -} - -void OpenALSoundRenderer::PurgeStoppedSources() -{ - // Release channels that are stopped - foreach(ALuint, i, SfxGroup) - { - ALint state = AL_PLAYING; - alGetSourcei(*i, AL_SOURCE_STATE, &state); - if(state == AL_PLAYING || state == AL_PAUSED) - continue; - - FSoundChan *schan = Channels; - while(schan) - { - if(schan->SysChannel != NULL && *i == *((ALuint*)schan->SysChannel)) - { - StopChannel(schan); - break; - } - schan = schan->NextChan; - } - } - getALError(); -} - -void OpenALSoundRenderer::LoadReverb(const ReverbContainer *env) -{ - ALuint &envReverb = EnvEffects[env->ID]; - bool doLoad = (env->Modified || !envReverb); - - if(!envReverb) - { - bool ok = false; - alGenEffects(1, &envReverb); - if(getALError() == AL_NO_ERROR) - { - alEffecti(envReverb, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB); - ok = (alGetError() == AL_NO_ERROR); - if(!ok) - { - alEffecti(envReverb, AL_EFFECT_TYPE, AL_EFFECT_REVERB); - ok = (alGetError() == AL_NO_ERROR); - } - if(!ok) - { - alEffecti(envReverb, AL_EFFECT_TYPE, AL_EFFECT_NULL); - ok = (alGetError() == AL_NO_ERROR); - } - if(!ok) - { - alDeleteEffects(1, &envReverb); - getALError(); - } - } - if(!ok) - { - envReverb = 0; - doLoad = false; - } - } - - if(doLoad) - { - const REVERB_PROPERTIES &props = env->Properties; - ALint type = AL_EFFECT_NULL; - - alGetEffecti(envReverb, AL_EFFECT_TYPE, &type); -#define mB2Gain(x) ((float)pow(10., (x)/2000.)) - if(type == AL_EFFECT_EAXREVERB) - { - ALfloat reflectpan[3] = { props.ReflectionsPan0, - props.ReflectionsPan1, - props.ReflectionsPan2 }; - ALfloat latepan[3] = { props.ReverbPan0, props.ReverbPan1, - props.ReverbPan2 }; -#undef SETPARAM -#define SETPARAM(e,t,v) alEffectf((e), AL_EAXREVERB_##t, clamp((v), AL_EAXREVERB_MIN_##t, AL_EAXREVERB_MAX_##t)) - SETPARAM(envReverb, DENSITY, props.Density/100.f); - SETPARAM(envReverb, DIFFUSION, props.Diffusion/100.f); - SETPARAM(envReverb, GAIN, mB2Gain(props.Room)); - SETPARAM(envReverb, GAINHF, mB2Gain(props.RoomHF)); - SETPARAM(envReverb, GAINLF, mB2Gain(props.RoomLF)); - SETPARAM(envReverb, DECAY_TIME, props.DecayTime); - SETPARAM(envReverb, DECAY_HFRATIO, props.DecayHFRatio); - SETPARAM(envReverb, DECAY_LFRATIO, props.DecayLFRatio); - SETPARAM(envReverb, REFLECTIONS_GAIN, mB2Gain(props.Reflections)); - SETPARAM(envReverb, REFLECTIONS_DELAY, props.ReflectionsDelay); - alEffectfv(envReverb, AL_EAXREVERB_REFLECTIONS_PAN, reflectpan); - SETPARAM(envReverb, LATE_REVERB_GAIN, mB2Gain(props.Reverb)); - SETPARAM(envReverb, LATE_REVERB_DELAY, props.ReverbDelay); - alEffectfv(envReverb, AL_EAXREVERB_LATE_REVERB_PAN, latepan); - SETPARAM(envReverb, ECHO_TIME, props.EchoTime); - SETPARAM(envReverb, ECHO_DEPTH, props.EchoDepth); - SETPARAM(envReverb, MODULATION_TIME, props.ModulationTime); - SETPARAM(envReverb, MODULATION_DEPTH, props.ModulationDepth); - SETPARAM(envReverb, AIR_ABSORPTION_GAINHF, mB2Gain(props.AirAbsorptionHF)); - SETPARAM(envReverb, HFREFERENCE, props.HFReference); - SETPARAM(envReverb, LFREFERENCE, props.LFReference); - SETPARAM(envReverb, ROOM_ROLLOFF_FACTOR, props.RoomRolloffFactor); - alEffecti(envReverb, AL_EAXREVERB_DECAY_HFLIMIT, - (props.Flags&REVERB_FLAGS_DECAYHFLIMIT)?AL_TRUE:AL_FALSE); -#undef SETPARAM - } - else if(type == AL_EFFECT_REVERB) - { -#define SETPARAM(e,t,v) alEffectf((e), AL_REVERB_##t, clamp((v), AL_REVERB_MIN_##t, AL_REVERB_MAX_##t)) - SETPARAM(envReverb, DENSITY, props.Density/100.f); - SETPARAM(envReverb, DIFFUSION, props.Diffusion/100.f); - SETPARAM(envReverb, GAIN, mB2Gain(props.Room)); - SETPARAM(envReverb, GAINHF, mB2Gain(props.RoomHF)); - SETPARAM(envReverb, DECAY_TIME, props.DecayTime); - SETPARAM(envReverb, DECAY_HFRATIO, props.DecayHFRatio); - SETPARAM(envReverb, REFLECTIONS_GAIN, mB2Gain(props.Reflections)); - SETPARAM(envReverb, REFLECTIONS_DELAY, props.ReflectionsDelay); - SETPARAM(envReverb, LATE_REVERB_GAIN, mB2Gain(props.Reverb)); - SETPARAM(envReverb, LATE_REVERB_DELAY, props.ReverbDelay); - SETPARAM(envReverb, AIR_ABSORPTION_GAINHF, mB2Gain(props.AirAbsorptionHF)); - SETPARAM(envReverb, ROOM_ROLLOFF_FACTOR, props.RoomRolloffFactor); - alEffecti(envReverb, AL_REVERB_DECAY_HFLIMIT, - (props.Flags&REVERB_FLAGS_DECAYHFLIMIT)?AL_TRUE:AL_FALSE); -#undef SETPARAM - } -#undef mB2Gain - } - - alAuxiliaryEffectSloti(EnvSlot, AL_EFFECTSLOT_EFFECT, envReverb); - getALError(); -} - -FSoundChan *OpenALSoundRenderer::FindLowestChannel() -{ - FSoundChan *schan = Channels; - FSoundChan *lowest = NULL; - while(schan) - { - if(schan->SysChannel != NULL) - { - if(!lowest || schan->Priority < lowest->Priority || - (schan->Priority == lowest->Priority && - schan->DistanceSqr > lowest->DistanceSqr)) - lowest = schan; - } - schan = schan->NextChan; - } - return lowest; -} - -#endif // NO_OPENAL +/* +** oalsound.cpp +** System interface for sound; uses OpenAL +** +**--------------------------------------------------------------------------- +** Copyright 2008-2010 Chris Robinson +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#define USE_WINDOWS_DWORD +#endif + +#include "doomstat.h" +#include "templates.h" +#include "oalsound.h" +#include "c_cvars.h" +#include "c_dispatch.h" +#include "i_system.h" +#include "v_text.h" +#include "gi.h" +#include "actor.h" +#include "r_state.h" +#include "w_wad.h" +#include "i_music.h" +#include "i_musicinterns.h" +#include "tempfiles.h" + + +CVAR (String, snd_aldevice, "Default", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CVAR (Bool, snd_efx, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +CUSTOM_CVAR (Float, snd_waterabsorption, 10.0f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +{ + if(*self < 0.0f) + self = 0.0f; + else if(*self > 10.0f) + self = 10.0f; +} + +void I_BuildALDeviceList(FOptionValues *opt) +{ + opt->mValues.Resize(1); + opt->mValues[0].TextValue = "Default"; + opt->mValues[0].Text = "Default"; + +#ifndef NO_OPENAL + const ALCchar *names = (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") ? + alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER) : + alcGetString(NULL, ALC_DEVICE_SPECIFIER)); + if(!names) + Printf("Failed to get device list: %s\n", alcGetString(NULL, alcGetError(NULL))); + else while(*names) + { + unsigned int i = opt->mValues.Reserve(1); + opt->mValues[i].TextValue = names; + opt->mValues[i].Text = names; + + names += strlen(names)+1; + } +#endif +} + +#ifndef NO_OPENAL + +#include +#include +#include +#include + +#ifdef WITH_SDL_SOUND +#include "SDL_sound.h" +#endif + +EXTERN_CVAR (Int, snd_channels) +EXTERN_CVAR (Int, snd_samplerate) +EXTERN_CVAR (Bool, snd_waterreverb) +EXTERN_CVAR (Bool, snd_pitched) + + +#define foreach(type, name, vec) \ + for(std::vector::iterator (name) = (vec).begin(), \ + (_end_##name) = (vec).end(); \ + (name) != (_end_##name);(name)++) + + +static ALenum checkALError(const char *fn, unsigned int ln) +{ + ALenum err = alGetError(); + if(err != AL_NO_ERROR) + { + if(strchr(fn, '/')) + fn = strrchr(fn, '/')+1; + else if(strchr(fn, '\\')) + fn = strrchr(fn, '\\')+1; + Printf(">>>>>>>>>>>> Received AL error %s (%#x), %s:%u\n", alGetString(err), err, fn, ln); + } + return err; +} +#define getALError() checkALError(__FILE__, __LINE__) + +static ALCenum checkALCError(ALCdevice *device, const char *fn, unsigned int ln) +{ + ALCenum err = alcGetError(device); + if(err != ALC_NO_ERROR) + { + if(strchr(fn, '/')) + fn = strrchr(fn, '/')+1; + else if(strchr(fn, '\\')) + fn = strrchr(fn, '\\')+1; + Printf(">>>>>>>>>>>> Received ALC error %s (%#x), %s:%u\n", alcGetString(device, err), err, fn, ln); + } + return err; +} +#define getALCError(d) checkALCError((d), __FILE__, __LINE__) + +#ifdef WITH_SDL_SOUND +#include "oalsdlsound.h" +#else + +class OpenALSoundStream : public SoundStream +{ + OpenALSoundRenderer *Renderer; + +public: + ALfloat Volume; + + OpenALSoundStream(OpenALSoundRenderer *renderer) + : Renderer(renderer), Volume(1.0f) + { Renderer->Streams.push_back(this); } + + virtual ~OpenALSoundStream() + { + Renderer->Streams.erase(std::find(Renderer->Streams.begin(), + Renderer->Streams.end(), this)); + Renderer = NULL; + } + + + virtual bool Play(bool, float) + { return false; } + + virtual void Stop() + { } + + virtual void SetVolume(float vol) + { Volume = vol; } + + virtual bool SetPaused(bool) + { return false; } + + virtual unsigned int GetPosition() + { return 0; } + + virtual bool IsEnded() + { return true; } + + bool Init(const char*) + { return false; } + + bool Init(const BYTE*, unsigned int) + { return false; } +}; + +class Decoder +{ +public: + Decoder(const void*, unsigned int) { } + virtual ~Decoder() { } + + bool GetFormat(ALenum*, ALuint*) + { return false; } + void *GetData(ALsizei *size) + { *size = 0; return NULL; } +}; +#endif + +class OpenALCallbackStream : public SoundStream +{ + OpenALSoundRenderer *Renderer; + + SoundStreamCallback Callback; + void *UserData; + + std::vector Data; + + ALsizei SampleRate; + ALenum Format; + + static const int BufferCount = 4; + ALuint Buffers[BufferCount]; + ALuint Source; + + bool Playing; + + bool SetupSource() + { + /* Get a source, killing the farthest, lowest-priority sound if needed */ + if(Renderer->FreeSfx.size() == 0) + { + FSoundChan *lowest = Renderer->FindLowestChannel(); + if(lowest) Renderer->StopChannel(lowest); + + if(Renderer->FreeSfx.size() == 0) + return false; + } + Source = Renderer->FreeSfx.back(); + Renderer->FreeSfx.pop_back(); + + /* Set the default properties for localized playback */ + alSource3f(Source, AL_DIRECTION, 0.f, 0.f, 0.f); + alSource3f(Source, AL_VELOCITY, 0.f, 0.f, 0.f); + alSource3f(Source, AL_POSITION, 0.f, 0.f, 0.f); + alSourcef(Source, AL_MAX_GAIN, 1.f); + alSourcef(Source, AL_GAIN, 1.f); + alSourcef(Source, AL_PITCH, 1.f); + alSourcef(Source, AL_ROLLOFF_FACTOR, 0.f); + alSourcef(Source, AL_SEC_OFFSET, 0.f); + alSourcei(Source, AL_SOURCE_RELATIVE, AL_TRUE); + alSourcei(Source, AL_LOOPING, AL_FALSE); + if(Renderer->EnvSlot) + { + alSourcef(Source, AL_ROOM_ROLLOFF_FACTOR, 0.f); + alSourcef(Source, AL_AIR_ABSORPTION_FACTOR, 0.f); + alSourcei(Source, AL_DIRECT_FILTER, AL_FILTER_NULL); + alSource3i(Source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL); + } + + alGenBuffers(BufferCount, Buffers); + return (getALError() == AL_NO_ERROR); + } + +public: + ALfloat Volume; + + OpenALCallbackStream(OpenALSoundRenderer *renderer) + : Renderer(renderer), Source(0), Playing(false), Volume(1.0f) + { + Renderer->Streams.push_back(this); + memset(Buffers, 0, sizeof(Buffers)); + } + + virtual ~OpenALCallbackStream() + { + if(Source) + { + alSourceRewind(Source); + alSourcei(Source, AL_BUFFER, 0); + + Renderer->FreeSfx.push_back(Source); + Source = 0; + } + + if(Buffers[0]) + { + alDeleteBuffers(BufferCount, &Buffers[0]); + memset(Buffers, 0, sizeof(Buffers)); + } + getALError(); + + Renderer->Streams.erase(std::find(Renderer->Streams.begin(), + Renderer->Streams.end(), this)); + Renderer = NULL; + } + + + virtual bool Play(bool loop, float vol) + { + SetVolume(vol); + + if(Playing) + return true; + + /* Clear the buffer queue, then fill and queue each buffer */ + alSourcei(Source, AL_BUFFER, 0); + for(int i = 0;i < BufferCount;i++) + { + if(!Callback(this, &Data[0], Data.size(), UserData)) + { + if(i == 0) + return false; + break; + } + + alBufferData(Buffers[i], Format, &Data[0], Data.size(), SampleRate); + alSourceQueueBuffers(Source, 1, &Buffers[i]); + } + if(getALError() != AL_NO_ERROR) + return false; + + alSourcePlay(Source); + Playing = (getALError()==AL_NO_ERROR); + + return Playing; + } + + virtual void Stop() + { + if(!Playing) + return; + + alSourceStop(Source); + alSourcei(Source, AL_BUFFER, 0); + getALError(); + + Playing = false; + } + + virtual void SetVolume(float vol) + { + if(vol >= 0.0f) Volume = vol; + alSourcef(Source, AL_GAIN, Renderer->MusicVolume*Volume); + getALError(); + } + + virtual bool SetPaused(bool pause) + { + if(pause) + alSourcePause(Source); + else + alSourcePlay(Source); + return (getALError()==AL_NO_ERROR); + } + + virtual unsigned int GetPosition() + { return 0; } + + virtual bool IsEnded() + { + if(!Playing) + return true; + + ALint state, processed; + alGetSourcei(Source, AL_SOURCE_STATE, &state); + alGetSourcei(Source, AL_BUFFERS_PROCESSED, &processed); + + Playing = (getALError()==AL_NO_ERROR); + if(!Playing) + return true; + + // For each processed buffer in the queue... + while(processed > 0) + { + ALuint bufid; + + // Unqueue the oldest buffer, fill it with more data, and queue it + // on the end + alSourceUnqueueBuffers(Source, 1, &bufid); + processed--; + + if(Callback(this, &Data[0], Data.size(), UserData)) + { + alBufferData(bufid, Format, &Data[0], Data.size(), SampleRate); + alSourceQueueBuffers(Source, 1, &bufid); + } + } + + // If the source is not playing or paused, and there are buffers queued, + // then there was an underrun. Restart the source. + Playing = (getALError()==AL_NO_ERROR); + if(Playing && state != AL_PLAYING && state != AL_PAUSED) + { + ALint queued = 0; + alGetSourcei(Source, AL_BUFFERS_QUEUED, &queued); + + Playing = (getALError() == AL_NO_ERROR) && (queued > 0); + if(Playing) + { + alSourcePlay(Source); + Playing = (getALError()==AL_NO_ERROR); + } + } + + return !Playing; + } + + bool Init(SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata) + { + if(!SetupSource()) + return false; + + Callback = callback; + UserData = userdata; + SampleRate = samplerate; + + Format = AL_NONE; + if((flags&Bits8)) /* Signed or unsigned? We assume unsigned 8-bit... */ + { + if((flags&Mono)) Format = AL_FORMAT_MONO8; + else Format = AL_FORMAT_STEREO8; + } + else if(!(flags&(Bits32|Float))) + { + if((flags&Mono)) Format = AL_FORMAT_MONO16; + else Format = AL_FORMAT_STEREO16; + } + + if(Format == AL_NONE) + { + Printf("Unsupported format: 0x%x\n", flags); + return false; + } + + int smpsize = 1; + if((flags&Bits8)) + smpsize *= 1; + else if((flags&(Bits32|Float))) + smpsize *= 4; + else + smpsize *= 2; + + if((flags&Mono)) + smpsize *= 1; + else + smpsize *= 2; + + buffbytes += smpsize-1; + buffbytes -= buffbytes%smpsize; + Data.resize(buffbytes); + + return true; + } +}; + + +extern ReverbContainer *ForcedEnvironment; + +#define PITCH_MULT (0.7937005f) /* Approx. 4 semitones lower; what Nash suggested */ + +#define PITCH(pitch) (snd_pitched ? (pitch)/128.f : 1.f) + + +static float GetRolloff(const FRolloffInfo *rolloff, float distance) +{ + if(distance <= rolloff->MinDistance) + return 1.f; + // Logarithmic rolloff has no max distance where it goes silent. + if(rolloff->RolloffType == ROLLOFF_Log) + return rolloff->MinDistance / + (rolloff->MinDistance + rolloff->RolloffFactor*(distance-rolloff->MinDistance)); + if(distance >= rolloff->MaxDistance) + return 0.f; + + float volume = (rolloff->MaxDistance - distance) / (rolloff->MaxDistance - rolloff->MinDistance); + if(rolloff->RolloffType == ROLLOFF_Linear) + return volume; + + if(rolloff->RolloffType == ROLLOFF_Custom && S_SoundCurve != NULL) + return S_SoundCurve[int(S_SoundCurveSize * (1.f - volume))] / 127.f; + return (powf(10.f, volume) - 1.f) / 9.f; +} + + +static ALenum FormatFromDesc(int bits, int channels) +{ + if(bits == 8) + { + if(channels == 1) return AL_FORMAT_MONO8; + if(channels == 2) return AL_FORMAT_STEREO8; + if(channels == 4) return AL_FORMAT_QUAD8; + if(channels == 6) return AL_FORMAT_51CHN8; + if(channels == 7) return AL_FORMAT_61CHN8; + if(channels == 8) return AL_FORMAT_71CHN8; + } + if(bits == 16) + { + if(channels == 1) return AL_FORMAT_MONO16; + if(channels == 2) return AL_FORMAT_STEREO16; + if(channels == 4) return AL_FORMAT_QUAD16; + if(channels == 6) return AL_FORMAT_51CHN16; + if(channels == 7) return AL_FORMAT_61CHN16; + if(channels == 8) return AL_FORMAT_71CHN16; + } + if(bits == 32) + { + if(channels == 1) return AL_FORMAT_MONO_FLOAT32; + if(channels == 2) return AL_FORMAT_STEREO_FLOAT32; + if(channels == 4) return AL_FORMAT_QUAD32; + if(channels == 6) return AL_FORMAT_51CHN32; + if(channels == 7) return AL_FORMAT_61CHN32; + if(channels == 8) return AL_FORMAT_71CHN32; + } + return AL_NONE; +} + + +template +static void LoadALFunc(const char *name, T *x) +{ *x = reinterpret_cast(alGetProcAddress(name)); } + +OpenALSoundRenderer::OpenALSoundRenderer() + : Device(NULL), Context(NULL), SrcDistanceModel(false), SFXPaused(0), + PrevEnvironment(NULL), EnvSlot(0) +{ + EnvFilters[0] = EnvFilters[1] = 0; + + Printf("I_InitSound: Initializing OpenAL\n"); + +#ifdef WITH_SDL_SOUND + static bool sdl_sound_inited = false; + if(!sdl_sound_inited) + { + if(Sound_Init() == 0) + { + Printf(TEXTCOLOR_RED" Failed to init SDL_sound: %s\n", Sound_GetError()); + return; + } + sdl_sound_inited = true; + } +#endif + + if(strcmp(snd_aldevice, "Default") != 0) + { + Device = alcOpenDevice(*snd_aldevice); + if(!Device) + Printf(TEXTCOLOR_BLUE" Failed to open device "TEXTCOLOR_BOLD"%s"TEXTCOLOR_BLUE". Trying default.\n", *snd_aldevice); + } + + if(!Device) + { + Device = alcOpenDevice(NULL); + if(!Device) + { + Printf(TEXTCOLOR_RED" Could not open audio device\n"); + return; + } + } + + Printf(" Opened device "TEXTCOLOR_ORANGE"%s\n", alcGetString(Device, ALC_DEVICE_SPECIFIER)); + ALCint major=0, minor=0; + alcGetIntegerv(Device, ALC_MAJOR_VERSION, 1, &major); + alcGetIntegerv(Device, ALC_MINOR_VERSION, 1, &minor); + DPrintf(" ALC Version: "TEXTCOLOR_BLUE"%d.%d\n", major, minor); + DPrintf(" ALC Extensions: "TEXTCOLOR_ORANGE"%s\n", alcGetString(Device, ALC_EXTENSIONS)); + + DisconnectNotify = alcIsExtensionPresent(Device, "ALC_EXT_disconnect"); + + std::vector attribs; + if(*snd_samplerate > 0) + { + attribs.push_back(ALC_FREQUENCY); + attribs.push_back(*snd_samplerate); + } + // Make sure one source is capable of stereo output with the rest doing + // mono, without running out of voices + attribs.push_back(ALC_MONO_SOURCES); + attribs.push_back((std::max)(*snd_channels, 2) - 1); + attribs.push_back(ALC_STEREO_SOURCES); + attribs.push_back(1); + // Other attribs..? + attribs.push_back(0); + + Context = alcCreateContext(Device, &attribs[0]); + if(!Context || alcMakeContextCurrent(Context) == ALC_FALSE) + { + Printf(TEXTCOLOR_RED" Failed to setup context: %s\n", alcGetString(Device, alcGetError(Device))); + if(Context) + alcDestroyContext(Context); + Context = NULL; + alcCloseDevice(Device); + Device = NULL; + return; + } + attribs.clear(); + + DPrintf(" Vendor: "TEXTCOLOR_ORANGE"%s\n", alGetString(AL_VENDOR)); + DPrintf(" Renderer: "TEXTCOLOR_ORANGE"%s\n", alGetString(AL_RENDERER)); + DPrintf(" Version: "TEXTCOLOR_ORANGE"%s\n", alGetString(AL_VERSION)); + DPrintf(" Extensions: "TEXTCOLOR_ORANGE"%s\n", alGetString(AL_EXTENSIONS)); + + SrcDistanceModel = alIsExtensionPresent("AL_EXT_source_distance_model"); + LoopPoints = alIsExtensionPresent("AL_SOFT_loop_points"); + + alDopplerFactor(0.5f); + alSpeedOfSound(343.3f * 96.0f); + alDistanceModel(AL_INVERSE_DISTANCE); + if(SrcDistanceModel) + alEnable(AL_SOURCE_DISTANCE_MODEL); + + ALenum err = getALError(); + if(err != AL_NO_ERROR) + { + alcMakeContextCurrent(NULL); + alcDestroyContext(Context); + Context = NULL; + alcCloseDevice(Device); + Device = NULL; + return; + } + + ALCint numMono=0, numStereo=0; + alcGetIntegerv(Device, ALC_MONO_SOURCES, 1, &numMono); + alcGetIntegerv(Device, ALC_STEREO_SOURCES, 1, &numStereo); + + Sources.resize((std::min)((std::max)(*snd_channels, 2), numMono+numStereo)); + for(size_t i = 0;i < Sources.size();i++) + { + alGenSources(1, &Sources[i]); + if(getALError() != AL_NO_ERROR) + { + Sources.resize(i); + break; + } + FreeSfx.push_back(Sources[i]); + } + if(Sources.size() == 0) + { + Printf(TEXTCOLOR_RED" Error: could not generate any sound sources!\n"); + alcMakeContextCurrent(NULL); + alcDestroyContext(Context); + Context = NULL; + alcCloseDevice(Device); + Device = NULL; + return; + } + DPrintf(" Allocated "TEXTCOLOR_BLUE"%u"TEXTCOLOR_NORMAL" sources\n", Sources.size()); + + LastWaterAbsorb = 0.0f; + if(*snd_efx && alcIsExtensionPresent(Device, "ALC_EXT_EFX")) + { + // EFX function pointers +#define LOAD_FUNC(x) (LoadALFunc(#x, &x)) + LOAD_FUNC(alGenEffects); + LOAD_FUNC(alDeleteEffects); + LOAD_FUNC(alIsEffect); + LOAD_FUNC(alEffecti); + LOAD_FUNC(alEffectiv); + LOAD_FUNC(alEffectf); + LOAD_FUNC(alEffectfv); + LOAD_FUNC(alGetEffecti); + LOAD_FUNC(alGetEffectiv); + LOAD_FUNC(alGetEffectf); + LOAD_FUNC(alGetEffectfv); + + LOAD_FUNC(alGenFilters); + LOAD_FUNC(alDeleteFilters); + LOAD_FUNC(alIsFilter); + LOAD_FUNC(alFilteri); + LOAD_FUNC(alFilteriv); + LOAD_FUNC(alFilterf); + LOAD_FUNC(alFilterfv); + LOAD_FUNC(alGetFilteri); + LOAD_FUNC(alGetFilteriv); + LOAD_FUNC(alGetFilterf); + LOAD_FUNC(alGetFilterfv); + + LOAD_FUNC(alGenAuxiliaryEffectSlots); + LOAD_FUNC(alDeleteAuxiliaryEffectSlots); + LOAD_FUNC(alIsAuxiliaryEffectSlot); + LOAD_FUNC(alAuxiliaryEffectSloti); + LOAD_FUNC(alAuxiliaryEffectSlotiv); + LOAD_FUNC(alAuxiliaryEffectSlotf); + LOAD_FUNC(alAuxiliaryEffectSlotfv); + LOAD_FUNC(alGetAuxiliaryEffectSloti); + LOAD_FUNC(alGetAuxiliaryEffectSlotiv); + LOAD_FUNC(alGetAuxiliaryEffectSlotf); + LOAD_FUNC(alGetAuxiliaryEffectSlotfv); +#undef LOAD_FUNC + if(getALError() == AL_NO_ERROR) + { + ALuint envReverb; + alGenEffects(1, &envReverb); + if(getALError() == AL_NO_ERROR) + { + alEffecti(envReverb, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB); + if(alGetError() == AL_NO_ERROR) + DPrintf(" EAX Reverb found\n"); + alEffecti(envReverb, AL_EFFECT_TYPE, AL_EFFECT_REVERB); + if(alGetError() == AL_NO_ERROR) + DPrintf(" Standard Reverb found\n"); + + alDeleteEffects(1, &envReverb); + getALError(); + } + + alGenAuxiliaryEffectSlots(1, &EnvSlot); + alGenFilters(2, EnvFilters); + if(getALError() == AL_NO_ERROR) + { + alFilteri(EnvFilters[0], AL_FILTER_TYPE, AL_FILTER_LOWPASS); + alFilteri(EnvFilters[1], AL_FILTER_TYPE, AL_FILTER_LOWPASS); + if(getALError() == AL_NO_ERROR) + DPrintf(" Lowpass found\n"); + else + { + alDeleteFilters(2, EnvFilters); + EnvFilters[0] = EnvFilters[1] = 0; + alDeleteAuxiliaryEffectSlots(1, &EnvSlot); + EnvSlot = 0; + getALError(); + } + } + else + { + alDeleteFilters(2, EnvFilters); + alDeleteAuxiliaryEffectSlots(1, &EnvSlot); + EnvFilters[0] = EnvFilters[1] = 0; + EnvSlot = 0; + getALError(); + } + } + } + + if(EnvSlot) + Printf(" EFX enabled\n"); + + snd_sfxvolume.Callback(); +} + +OpenALSoundRenderer::~OpenALSoundRenderer() +{ + if(!Device) + return; + + while(Streams.size() > 0) + delete Streams[0]; + + alDeleteSources(Sources.size(), &Sources[0]); + Sources.clear(); + FreeSfx.clear(); + SfxGroup.clear(); + PausableSfx.clear(); + ReverbSfx.clear(); + + for(EffectMap::iterator i = EnvEffects.begin();i != EnvEffects.end();i++) + { + if(i->second) + alDeleteEffects(1, &(i->second)); + } + EnvEffects.clear(); + + if(EnvSlot) + { + alDeleteAuxiliaryEffectSlots(1, &EnvSlot); + alDeleteFilters(2, EnvFilters); + } + EnvSlot = 0; + EnvFilters[0] = EnvFilters[1] = 0; + + alcMakeContextCurrent(NULL); + alcDestroyContext(Context); + Context = NULL; + alcCloseDevice(Device); + Device = NULL; +} + +void OpenALSoundRenderer::SetSfxVolume(float volume) +{ + SfxVolume = volume; + + FSoundChan *schan = Channels; + while(schan) + { + if(schan->SysChannel != NULL) + { + ALuint source = *((ALuint*)schan->SysChannel); + volume = SfxVolume; + + alcSuspendContext(Context); + alSourcef(source, AL_MAX_GAIN, volume); + if(schan->ManualGain) + volume *= GetRolloff(&schan->Rolloff, sqrt(schan->DistanceSqr)); + alSourcef(source, AL_GAIN, volume * ((FSoundChan*)schan)->Volume); + } + schan = schan->NextChan; + } + + getALError(); +} + +void OpenALSoundRenderer::SetMusicVolume(float volume) +{ + MusicVolume = volume; + foreach(SoundStream*, i, Streams) + (*i)->SetVolume(-1.f); +} + +unsigned int OpenALSoundRenderer::GetMSLength(SoundHandle sfx) +{ + if(sfx.data) + { + ALuint buffer = *((ALuint*)sfx.data); + if(alIsBuffer(buffer)) + { + ALint bits, channels, freq, size; + alGetBufferi(buffer, AL_BITS, &bits); + alGetBufferi(buffer, AL_CHANNELS, &channels); + alGetBufferi(buffer, AL_FREQUENCY, &freq); + alGetBufferi(buffer, AL_SIZE, &size); + if(getALError() == AL_NO_ERROR) + return (unsigned int)(size / (channels*bits/8) * 1000. / freq); + } + } + return 0; +} + +unsigned int OpenALSoundRenderer::GetSampleLength(SoundHandle sfx) +{ + if(sfx.data) + { + ALuint buffer = *((ALuint*)sfx.data); + ALint bits, channels, size; + alGetBufferi(buffer, AL_BITS, &bits); + alGetBufferi(buffer, AL_CHANNELS, &channels); + alGetBufferi(buffer, AL_SIZE, &size); + if(getALError() == AL_NO_ERROR) + return (ALsizei)(size / (channels * bits / 8)); + } + return 0; +} + +float OpenALSoundRenderer::GetOutputRate() +{ + ALCint rate = 44100; // Default, just in case + alcGetIntegerv(Device, ALC_FREQUENCY, 1, &rate); + return (float)rate; +} + + +SoundHandle OpenALSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int length, int frequency, int channels, int bits, int loopstart, int loopend) +{ + SoundHandle retval = { NULL }; + + if(length == 0) return retval; + + if(bits == -8) + { + // Simple signed->unsigned conversion + for(int i = 0;i < length;i++) + sfxdata[i] ^= 0x80; + bits = -bits; + } + + ALenum format = AL_NONE; + if(bits == 16) + { + if(channels == 1) format = AL_FORMAT_MONO16; + if(channels == 2) format = AL_FORMAT_STEREO16; + } + else if(bits == 8) + { + if(channels == 1) format = AL_FORMAT_MONO8; + if(channels == 2) format = AL_FORMAT_STEREO8; + } + + if(format == AL_NONE || frequency <= 0) + { + Printf("Unhandled format: %d bit, %d channel, %d hz\n", bits, channels, frequency); + return retval; + } + length -= length%(channels*bits/8); + + ALenum err; + ALuint buffer = 0; + alGenBuffers(1, &buffer); + alBufferData(buffer, format, sfxdata, length, frequency); + if((err=getALError()) != AL_NO_ERROR) + { + Printf("Failed to buffer data: %s\n", alGetString(err)); + alDeleteBuffers(1, &buffer); + getALError(); + return retval; + } + + if((loopstart > 0 || loopend > 0) && LoopPoints) + { + if(loopstart < 0) + loopstart = 0; + if(loopend < loopstart) + loopend = length / (channels*bits/8); + + ALint loops[2] = { loopstart, loopend }; + Printf("Setting loop points %d -> %d\n", loops[0], loops[1]); + alBufferiv(buffer, AL_LOOP_POINTS_SOFT, loops); + getALError(); + } + else if(loopstart > 0 || loopend > 0) + { + static bool warned = false; + if(!warned) + Printf("Loop points not supported!\n"); + warned = true; + } + + retval.data = new ALuint(buffer); + return retval; +} + +SoundHandle OpenALSoundRenderer::LoadSound(BYTE *sfxdata, int length) +{ + SoundHandle retval = { NULL }; + ALenum format; + ALuint srate; + + Decoder decoder(sfxdata, length); + if(!decoder.GetFormat(&format, &srate)) + return retval; + + ALsizei size; + void *data = decoder.GetData(&size); + if(data == NULL) + return retval; + + ALuint buffer = 0; + alGenBuffers(1, &buffer); + alBufferData(buffer, format, data, size, srate); + + ALenum err; + if((err=getALError()) != AL_NO_ERROR) + { + Printf("Failed to buffer data: %s\n", alGetString(err)); + alDeleteBuffers(1, &buffer); + getALError(); + return retval; + } + + retval.data = new ALuint(buffer); + return retval; +} + +void OpenALSoundRenderer::UnloadSound(SoundHandle sfx) +{ + if(!sfx.data) + return; + + FSoundChan *schan = Channels; + while(schan) + { + if(schan->SysChannel) + { + ALint bufID = 0; + alGetSourcei(*((ALuint*)schan->SysChannel), AL_BUFFER, &bufID); + if(bufID == *((ALint*)sfx.data)) + { + FSoundChan *next = schan->NextChan; + StopChannel(schan); + schan = next; + continue; + } + } + schan = schan->NextChan; + } + + alDeleteBuffers(1, ((ALuint*)sfx.data)); + getALError(); + delete ((ALuint*)sfx.data); +} + +short *OpenALSoundRenderer::DecodeSample(int outlen, const void *coded, int sizebytes, ECodecType type) +{ + short *samples = (short*)malloc(outlen); + memset(samples, 0, outlen); + + Decoder decoder(coded, sizebytes); + ALenum format; + ALuint srate; + + if(!decoder.GetFormat(&format, &srate)) + return samples; + if(format != AL_FORMAT_MONO16) + { + DPrintf("Sample is not 16-bit mono\n"); + return samples; + } + + ALsizei size; + void *data = decoder.GetData(&size); + if(data != NULL) + memcpy(samples, data, std::min(size, outlen)); + + return samples; +} + +SoundStream *OpenALSoundRenderer::CreateStream(SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata) +{ + std::auto_ptr stream(new OpenALCallbackStream(this)); + if(!stream->Init(callback, buffbytes, flags, samplerate, userdata)) + return NULL; + return stream.release(); +} + +SoundStream *OpenALSoundRenderer::OpenStream(const char *filename, int flags, int offset, int length) +{ + std::auto_ptr stream(new OpenALSoundStream(this)); + + bool ok = ((offset == -1) ? stream->Init((const BYTE*)filename, length) : + stream->Init(filename, offset, length)); + if(ok == false) + return NULL; + + return stream.release(); +} + +FISoundChannel *OpenALSoundRenderer::StartSound(SoundHandle sfx, float vol, int pitch, int chanflags, FISoundChannel *reuse_chan) +{ + if(FreeSfx.size() == 0) + { + FSoundChan *lowest = FindLowestChannel(); + if(lowest) StopChannel(lowest); + + if(FreeSfx.size() == 0) + return NULL; + } + + ALuint buffer = *((ALuint*)sfx.data); + ALuint &source = *std::find(Sources.begin(), Sources.end(), FreeSfx.back()); + alSource3f(source, AL_POSITION, 0.f, 0.f, 0.f); + alSource3f(source, AL_VELOCITY, 0.f, 0.f, 0.f); + alSource3f(source, AL_DIRECTION, 0.f, 0.f, 0.f); + alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); + + alSourcei(source, AL_LOOPING, (chanflags&SNDF_LOOP) ? AL_TRUE : AL_FALSE); + + alSourcef(source, AL_REFERENCE_DISTANCE, 1.f); + alSourcef(source, AL_MAX_DISTANCE, 1000.f); + alSourcef(source, AL_ROLLOFF_FACTOR, 0.f); + alSourcef(source, AL_MAX_GAIN, SfxVolume); + alSourcef(source, AL_GAIN, SfxVolume*vol); + + if(EnvSlot) + { + if(!(chanflags&SNDF_NOREVERB)) + { + alSourcei(source, AL_DIRECT_FILTER, EnvFilters[0]); + alSource3i(source, AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); + alSourcef(source, AL_AIR_ABSORPTION_FACTOR, LastWaterAbsorb); + } + else + { + alSourcei(source, AL_DIRECT_FILTER, AL_FILTER_NULL); + alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL); + alSourcef(source, AL_AIR_ABSORPTION_FACTOR, 0.f); + } + alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, 0.f); + alSourcef(source, AL_PITCH, PITCH(pitch)); + } + else if(LastWaterAbsorb > 0.f && !(chanflags&SNDF_NOREVERB)) + alSourcef(source, AL_PITCH, PITCH(pitch)*PITCH_MULT); + else + alSourcef(source, AL_PITCH, PITCH(pitch)); + + if(!reuse_chan) + alSourcef(source, AL_SEC_OFFSET, 0.f); + else + { + if((chanflags&SNDF_ABSTIME)) + alSourcef(source, AL_SEC_OFFSET, reuse_chan->StartTime.Lo/1000.f); + else + { + // FIXME: set offset based on the current time and the StartTime + alSourcef(source, AL_SEC_OFFSET, 0.f); + } + } + if(getALError() != AL_NO_ERROR) + return NULL; + + alSourcei(source, AL_BUFFER, buffer); + if((chanflags&SNDF_NOPAUSE) || !SFXPaused) + alSourcePlay(source); + if(getALError() != AL_NO_ERROR) + { + alSourcei(source, AL_BUFFER, 0); + getALError(); + return NULL; + } + + if(!(chanflags&SNDF_NOREVERB)) + ReverbSfx.push_back(source); + if(!(chanflags&SNDF_NOPAUSE)) + PausableSfx.push_back(source); + SfxGroup.push_back(source); + FreeSfx.pop_back(); + + FISoundChannel *chan = reuse_chan; + if(!chan) chan = S_GetChannel(&source); + else chan->SysChannel = &source; + + chan->Rolloff.RolloffType = ROLLOFF_Linear; + chan->Rolloff.MaxDistance = 1000.f; + chan->Rolloff.MinDistance = 1.f; + chan->DistanceScale = 1.f; + chan->DistanceSqr = 1.f; + chan->ManualGain = false; + + return chan; +} + +FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener *listener, float vol, + FRolloffInfo *rolloff, float distscale, int pitch, int priority, const FVector3 &pos, const FVector3 &vel, + int channum, int chanflags, FISoundChannel *reuse_chan) +{ + float dist_sqr = (pos - listener->position).LengthSquared() * + distscale*distscale; + + if(FreeSfx.size() == 0) + { + FSoundChan *lowest = FindLowestChannel(); + if(lowest) + { + if(lowest->Priority < priority || (lowest->Priority == priority && + lowest->DistanceSqr > dist_sqr)) + StopChannel(lowest); + } + if(FreeSfx.size() == 0) + return NULL; + } + + float rolloffFactor, gain; + bool manualGain = true; + + ALuint buffer = *((ALuint*)sfx.data); + ALint channels = 1; + alGetBufferi(buffer, AL_CHANNELS, &channels); + + ALuint &source = *std::find(Sources.begin(), Sources.end(), FreeSfx.back()); + alSource3f(source, AL_POSITION, pos[0], pos[1], -pos[2]); + alSource3f(source, AL_VELOCITY, vel[0], vel[1], -vel[2]); + alSource3f(source, AL_DIRECTION, 0.f, 0.f, 0.f); + alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); + + alSourcei(source, AL_LOOPING, (chanflags&SNDF_LOOP) ? AL_TRUE : AL_FALSE); + + // Multi-channel sources won't attenuate in OpenAL, and "area sounds" have + // special rolloff properties (they have a panning radius of 32 units, but + // start attenuating at MinDistance). + if(channels == 1 && !(chanflags&SNDF_AREA)) + { + if(rolloff->RolloffType == ROLLOFF_Log) + { + if(SrcDistanceModel) + alSourcei(source, AL_DISTANCE_MODEL, AL_INVERSE_DISTANCE); + alSourcef(source, AL_REFERENCE_DISTANCE, rolloff->MinDistance/distscale); + alSourcef(source, AL_MAX_DISTANCE, (1000.f+rolloff->MinDistance)/distscale); + rolloffFactor = rolloff->RolloffFactor; + manualGain = false; + gain = 1.f; + } + else if(rolloff->RolloffType == ROLLOFF_Linear && SrcDistanceModel) + { + alSourcei(source, AL_DISTANCE_MODEL, AL_LINEAR_DISTANCE); + alSourcef(source, AL_REFERENCE_DISTANCE, rolloff->MinDistance/distscale); + alSourcef(source, AL_MAX_DISTANCE, rolloff->MaxDistance/distscale); + rolloffFactor = 1.f; + manualGain = false; + gain = 1.f; + } + } + if(manualGain) + { + if(SrcDistanceModel) + alSourcei(source, AL_DISTANCE_MODEL, AL_NONE); + if((chanflags&SNDF_AREA) && rolloff->MinDistance < 32.f) + alSourcef(source, AL_REFERENCE_DISTANCE, 32.f/distscale); + else + alSourcef(source, AL_REFERENCE_DISTANCE, rolloff->MinDistance/distscale); + alSourcef(source, AL_MAX_DISTANCE, (1000.f+rolloff->MinDistance)/distscale); + rolloffFactor = 0.f; + gain = GetRolloff(rolloff, sqrt(dist_sqr)); + } + alSourcef(source, AL_ROLLOFF_FACTOR, rolloffFactor); + alSourcef(source, AL_MAX_GAIN, SfxVolume); + alSourcef(source, AL_GAIN, SfxVolume * gain); + + if(EnvSlot) + { + if(!(chanflags&SNDF_NOREVERB)) + { + alSourcei(source, AL_DIRECT_FILTER, EnvFilters[0]); + alSource3i(source, AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); + alSourcef(source, AL_AIR_ABSORPTION_FACTOR, LastWaterAbsorb); + } + else + { + alSourcei(source, AL_DIRECT_FILTER, AL_FILTER_NULL); + alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL); + alSourcef(source, AL_AIR_ABSORPTION_FACTOR, 0.f); + } + alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, rolloffFactor); + alSourcef(source, AL_PITCH, PITCH(pitch)); + } + else if(LastWaterAbsorb > 0.f && !(chanflags&SNDF_NOREVERB)) + alSourcef(source, AL_PITCH, PITCH(pitch)*PITCH_MULT); + else + alSourcef(source, AL_PITCH, PITCH(pitch)); + + if(!reuse_chan) + alSourcef(source, AL_SEC_OFFSET, 0.f); + else + { + if((chanflags&SNDF_ABSTIME)) + alSourcef(source, AL_SEC_OFFSET, reuse_chan->StartTime.Lo/1000.f); + else + { + // FIXME: set offset based on the current time and the StartTime + alSourcef(source, AL_SAMPLE_OFFSET, 0.f); + } + } + if(getALError() != AL_NO_ERROR) + return NULL; + + alSourcei(source, AL_BUFFER, buffer); + if((chanflags&SNDF_NOPAUSE) || !SFXPaused) + alSourcePlay(source); + if(getALError() != AL_NO_ERROR) + { + alSourcei(source, AL_BUFFER, 0); + getALError(); + return NULL; + } + + if(!(chanflags&SNDF_NOREVERB)) + ReverbSfx.push_back(source); + if(!(chanflags&SNDF_NOPAUSE)) + PausableSfx.push_back(source); + SfxGroup.push_back(source); + FreeSfx.pop_back(); + + FISoundChannel *chan = reuse_chan; + if(!chan) chan = S_GetChannel(&source); + else chan->SysChannel = &source; + + chan->Rolloff = *rolloff; + chan->DistanceScale = distscale; + chan->DistanceSqr = dist_sqr; + chan->ManualGain = manualGain; + + return chan; +} + +void OpenALSoundRenderer::ChannelVolume(FISoundChannel *chan, float volume) +{ + if(chan == NULL || chan->SysChannel == NULL) + return; + + alcSuspendContext(Context); + + ALuint source = *((ALuint*)chan->SysChannel); + + if(chan->ManualGain) + volume *= GetRolloff(&chan->Rolloff, sqrt(chan->DistanceSqr)); + alSourcef(source, AL_GAIN, SfxVolume * volume); +} + +void OpenALSoundRenderer::StopChannel(FISoundChannel *chan) +{ + if(chan == NULL || chan->SysChannel == NULL) + return; + + ALuint source = *((ALuint*)chan->SysChannel); + // Release first, so it can be properly marked as evicted if it's being + // forcefully killed + S_ChannelEnded(chan); + + alSourceRewind(source); + alSourcei(source, AL_BUFFER, 0); + getALError(); + + std::vector::iterator i; + + i = std::find(PausableSfx.begin(), PausableSfx.end(), source); + if(i != PausableSfx.end()) PausableSfx.erase(i); + i = std::find(ReverbSfx.begin(), ReverbSfx.end(), source); + if(i != ReverbSfx.end()) ReverbSfx.erase(i); + + SfxGroup.erase(std::find(SfxGroup.begin(), SfxGroup.end(), source)); + FreeSfx.push_back(source); +} + +unsigned int OpenALSoundRenderer::GetPosition(FISoundChannel *chan) +{ + if(chan == NULL || chan->SysChannel == NULL) + return 0; + + ALint pos; + alGetSourcei(*((ALuint*)chan->SysChannel), AL_SAMPLE_OFFSET, &pos); + if(getALError() == AL_NO_ERROR) + return pos; + return 0; +} + + +void OpenALSoundRenderer::SetSfxPaused(bool paused, int slot) +{ + int oldslots = SFXPaused; + + if(paused) + { + SFXPaused |= 1 << slot; + if(oldslots == 0 && PausableSfx.size() > 0) + { + alSourcePausev(PausableSfx.size(), &PausableSfx[0]); + getALError(); + PurgeStoppedSources(); + } + } + else + { + SFXPaused &= ~(1 << slot); + if(SFXPaused == 0 && oldslots != 0 && PausableSfx.size() > 0) + { + alSourcePlayv(PausableSfx.size(), &PausableSfx[0]); + getALError(); + } + } +} + +void OpenALSoundRenderer::SetInactive(EInactiveState) +{ +} + +void OpenALSoundRenderer::Sync(bool sync) +{ + if(sync) + { + if(SfxGroup.size() > 0) + { + alSourcePausev(SfxGroup.size(), &SfxGroup[0]); + getALError(); + PurgeStoppedSources(); + } + } + else + { + // Might already be something to handle this; basically, get a vector + // of all values in SfxGroup that are not also in PausableSfx (when + // SFXPaused is non-0). + std::vector toplay = SfxGroup; + if(SFXPaused) + { + std::vector::iterator i = toplay.begin(); + while(i != toplay.end()) + { + if(std::find(PausableSfx.begin(), PausableSfx.end(), *i) != PausableSfx.end()) + i = toplay.erase(i); + else + i++; + } + } + if(toplay.size() > 0) + { + alSourcePlayv(toplay.size(), &toplay[0]); + getALError(); + } + } +} + +void OpenALSoundRenderer::UpdateSoundParams3D(SoundListener *listener, FISoundChannel *chan, bool areasound, const FVector3 &pos, const FVector3 &vel) +{ + if(chan == NULL || chan->SysChannel == NULL) + return; + + alcSuspendContext(Context); + + ALuint source = *((ALuint*)chan->SysChannel); + alSource3f(source, AL_POSITION, pos[0], pos[1], -pos[2]); + alSource3f(source, AL_VELOCITY, vel[0], vel[1], -vel[2]); + + chan->DistanceSqr = (pos - listener->position).LengthSquared() * + chan->DistanceScale*chan->DistanceScale; + // Not all sources can use the distance models provided by OpenAL. + // For the ones that can't, apply the calculated attenuation as the + // source gain. Positions still handle the panning, + if(chan->ManualGain) + { + float gain = GetRolloff(&chan->Rolloff, sqrt(chan->DistanceSqr)); + alSourcef(source, AL_GAIN, SfxVolume*gain*((FSoundChan*)chan)->Volume); + } + + getALError(); +} + +void OpenALSoundRenderer::UpdateListener(SoundListener *listener) +{ + if(!listener->valid) + return; + + alcSuspendContext(Context); + + float angle = listener->angle; + ALfloat orient[6]; + // forward + orient[0] = cos(angle); + orient[1] = 0.f; + orient[2] = -sin(angle); + // up + orient[3] = 0.f; + orient[4] = 1.f; + orient[5] = 0.f; + + alListenerfv(AL_ORIENTATION, orient); + alListener3f(AL_POSITION, listener->position.X, + listener->position.Y, + -listener->position.Z); + alListener3f(AL_VELOCITY, listener->velocity.X, + listener->velocity.Y, + -listener->velocity.Z); + getALError(); + + const ReverbContainer *env = ForcedEnvironment; + if(!env) + { + env = listener->Environment; + if(!env) + env = DefaultEnvironments[0]; + } + if(env != PrevEnvironment || env->Modified) + { + PrevEnvironment = env; + DPrintf("Reverb Environment %s\n", env->Name); + + if(EnvSlot != 0) + LoadReverb(env); + + const_cast(env)->Modified = false; + } + + // NOTE: Moving into and out of water (and changing water absorption) will + // undo pitch variations on sounds if either snd_waterreverb or EFX are + // disabled. + if(listener->underwater || env->SoftwareWater) + { + if(LastWaterAbsorb != *snd_waterabsorption) + { + LastWaterAbsorb = *snd_waterabsorption; + + if(EnvSlot != 0 && *snd_waterreverb) + { + // Find the "Underwater" reverb environment + env = Environments; + while(env && env->ID != 0x1600) + env = env->Next; + LoadReverb(env ? env : DefaultEnvironments[0]); + + alFilterf(EnvFilters[0], AL_LOWPASS_GAIN, 0.25f); + alFilterf(EnvFilters[0], AL_LOWPASS_GAINHF, 0.75f); + alFilterf(EnvFilters[1], AL_LOWPASS_GAIN, 1.f); + alFilterf(EnvFilters[1], AL_LOWPASS_GAINHF, 1.f); + + // Apply the updated filters on the sources + foreach(ALuint, i, ReverbSfx) + { + alSourcef(*i, AL_AIR_ABSORPTION_FACTOR, LastWaterAbsorb); + alSourcei(*i, AL_DIRECT_FILTER, EnvFilters[0]); + alSource3i(*i, AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); + } + } + else + { + foreach(ALuint, i, ReverbSfx) + alSourcef(*i, AL_PITCH, PITCH_MULT); + } + getALError(); + } + } + else + { + if(LastWaterAbsorb > 0.f) + { + LastWaterAbsorb = 0.f; + + if(EnvSlot != 0) + { + LoadReverb(env); + + alFilterf(EnvFilters[0], AL_LOWPASS_GAIN, 1.f); + alFilterf(EnvFilters[0], AL_LOWPASS_GAINHF, 1.f); + alFilterf(EnvFilters[1], AL_LOWPASS_GAIN, 1.f); + alFilterf(EnvFilters[1], AL_LOWPASS_GAINHF, 1.f); + foreach(ALuint, i, ReverbSfx) + { + alSourcef(*i, AL_AIR_ABSORPTION_FACTOR, 0.f); + alSourcei(*i, AL_DIRECT_FILTER, EnvFilters[0]); + alSource3i(*i, AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); + } + } + else + { + foreach(ALuint, i, ReverbSfx) + alSourcef(*i, AL_PITCH, 1.f); + } + getALError(); + } + } +} + +void OpenALSoundRenderer::UpdateSounds() +{ + alcProcessContext(Context); + + if(DisconnectNotify) + { + ALCint connected = ALC_TRUE; + alcGetIntegerv(Device, ALC_CONNECTED, 1, &connected); + if(connected == ALC_FALSE) + { + Printf("Sound device disconnected; restarting...\n"); + static char snd_reset[] = "snd_reset"; + AddCommandString(snd_reset); + return; + } + } + + PurgeStoppedSources(); +} + +bool OpenALSoundRenderer::IsValid() +{ + return Device != NULL; +} + +void OpenALSoundRenderer::MarkStartTime(FISoundChannel *chan) +{ + // FIXME: Get current time (preferably from the audio clock, but the system + // time will have to do) + chan->StartTime.AsOne = 0; +} + +float OpenALSoundRenderer::GetAudibility(FISoundChannel *chan) +{ + if(chan == NULL || chan->SysChannel == NULL) + return 0.f; + + ALuint source = *((ALuint*)chan->SysChannel); + ALfloat volume = 0.f; + + if(!chan->ManualGain) + volume = SfxVolume * ((FSoundChan*)chan)->Volume * + GetRolloff(&chan->Rolloff, sqrt(chan->DistanceSqr)); + else + { + alGetSourcef(source, AL_GAIN, &volume); + getALError(); + } + return volume; +} + + +void OpenALSoundRenderer::PrintStatus() +{ + Printf("Output device: "TEXTCOLOR_ORANGE"%s\n", alcGetString(Device, ALC_DEVICE_SPECIFIER)); + getALCError(Device); + + ALCint frequency, major, minor, mono, stereo; + alcGetIntegerv(Device, ALC_FREQUENCY, 1, &frequency); + alcGetIntegerv(Device, ALC_MAJOR_VERSION, 1, &major); + alcGetIntegerv(Device, ALC_MINOR_VERSION, 1, &minor); + alcGetIntegerv(Device, ALC_MONO_SOURCES, 1, &mono); + alcGetIntegerv(Device, ALC_STEREO_SOURCES, 1, &stereo); + if(getALCError(Device) == AL_NO_ERROR) + { + Printf("Device sample rate: "TEXTCOLOR_BLUE"%d"TEXTCOLOR_NORMAL"hz\n", frequency); + Printf("ALC Version: "TEXTCOLOR_BLUE"%d.%d\n", major, minor); + Printf("ALC Extensions: "TEXTCOLOR_ORANGE"%s\n", alcGetString(Device, ALC_EXTENSIONS)); + Printf("Available sources: "TEXTCOLOR_BLUE"%d"TEXTCOLOR_NORMAL" ("TEXTCOLOR_BLUE"%d"TEXTCOLOR_NORMAL" mono, "TEXTCOLOR_BLUE"%d"TEXTCOLOR_NORMAL" stereo)\n", mono+stereo, mono, stereo); + } + if(!alcIsExtensionPresent(Device, "ALC_EXT_EFX")) + Printf("EFX not found\n"); + else + { + ALCint sends; + alcGetIntegerv(Device, ALC_EFX_MAJOR_VERSION, 1, &major); + alcGetIntegerv(Device, ALC_EFX_MINOR_VERSION, 1, &minor); + alcGetIntegerv(Device, ALC_MAX_AUXILIARY_SENDS, 1, &sends); + if(getALCError(Device) == AL_NO_ERROR) + { + Printf("EFX Version: "TEXTCOLOR_BLUE"%d.%d\n", major, minor); + Printf("Auxiliary sends: "TEXTCOLOR_BLUE"%d\n", sends); + } + } + Printf("Vendor: "TEXTCOLOR_ORANGE"%s\n", alGetString(AL_VENDOR)); + Printf("Renderer: "TEXTCOLOR_ORANGE"%s\n", alGetString(AL_RENDERER)); + Printf("Version: "TEXTCOLOR_ORANGE"%s\n", alGetString(AL_VERSION)); + Printf("Extensions: "TEXTCOLOR_ORANGE"%s\n", alGetString(AL_EXTENSIONS)); + getALError(); +} + +FString OpenALSoundRenderer::GatherStats() +{ + ALCint updates = 1; + alcGetIntegerv(Device, ALC_REFRESH, 1, &updates); + getALCError(Device); + + ALuint total = Sources.size(); + ALuint used = SfxGroup.size()+Streams.size(); + ALuint unused = FreeSfx.size(); + FString out; + out.Format("%u sources ("TEXTCOLOR_YELLOW"%u"TEXTCOLOR_NORMAL" active, "TEXTCOLOR_YELLOW"%u"TEXTCOLOR_NORMAL" free), Update interval: "TEXTCOLOR_YELLOW"%d"TEXTCOLOR_NORMAL"ms", + total, used, unused, 1000/updates); + return out; +} + +void OpenALSoundRenderer::PrintDriversList() +{ + const ALCchar *drivers = (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") ? + alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER) : + alcGetString(NULL, ALC_DEVICE_SPECIFIER)); + const ALCchar *current = alcGetString(Device, ALC_DEVICE_SPECIFIER); + if(drivers == NULL) + { + Printf(TEXTCOLOR_YELLOW"Failed to retrieve device list: %s\n", alcGetString(NULL, alcGetError(NULL))); + return; + } + + Printf("%c%s%2d. %s\n", ' ', ((strcmp(snd_aldevice, "Default") == 0) ? TEXTCOLOR_BOLD : ""), 0, + "Default"); + for(int i = 1;*drivers;i++) + { + Printf("%c%s%2d. %s\n", ((strcmp(current, drivers)==0) ? '*' : ' '), + ((strcmp(*snd_aldevice, drivers)==0) ? TEXTCOLOR_BOLD : ""), i, + drivers); + drivers += strlen(drivers)+1; + } +} + +void OpenALSoundRenderer::PurgeStoppedSources() +{ + // Release channels that are stopped + foreach(ALuint, i, SfxGroup) + { + ALint state = AL_PLAYING; + alGetSourcei(*i, AL_SOURCE_STATE, &state); + if(state == AL_PLAYING || state == AL_PAUSED) + continue; + + FSoundChan *schan = Channels; + while(schan) + { + if(schan->SysChannel != NULL && *i == *((ALuint*)schan->SysChannel)) + { + StopChannel(schan); + break; + } + schan = schan->NextChan; + } + } + getALError(); +} + +void OpenALSoundRenderer::LoadReverb(const ReverbContainer *env) +{ + ALuint &envReverb = EnvEffects[env->ID]; + bool doLoad = (env->Modified || !envReverb); + + if(!envReverb) + { + bool ok = false; + alGenEffects(1, &envReverb); + if(getALError() == AL_NO_ERROR) + { + alEffecti(envReverb, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB); + ok = (alGetError() == AL_NO_ERROR); + if(!ok) + { + alEffecti(envReverb, AL_EFFECT_TYPE, AL_EFFECT_REVERB); + ok = (alGetError() == AL_NO_ERROR); + } + if(!ok) + { + alEffecti(envReverb, AL_EFFECT_TYPE, AL_EFFECT_NULL); + ok = (alGetError() == AL_NO_ERROR); + } + if(!ok) + { + alDeleteEffects(1, &envReverb); + getALError(); + } + } + if(!ok) + { + envReverb = 0; + doLoad = false; + } + } + + if(doLoad) + { + const REVERB_PROPERTIES &props = env->Properties; + ALint type = AL_EFFECT_NULL; + + alGetEffecti(envReverb, AL_EFFECT_TYPE, &type); +#define mB2Gain(x) ((float)pow(10., (x)/2000.)) + if(type == AL_EFFECT_EAXREVERB) + { + ALfloat reflectpan[3] = { props.ReflectionsPan0, + props.ReflectionsPan1, + props.ReflectionsPan2 }; + ALfloat latepan[3] = { props.ReverbPan0, props.ReverbPan1, + props.ReverbPan2 }; +#undef SETPARAM +#define SETPARAM(e,t,v) alEffectf((e), AL_EAXREVERB_##t, clamp((v), AL_EAXREVERB_MIN_##t, AL_EAXREVERB_MAX_##t)) + SETPARAM(envReverb, DENSITY, props.Density/100.f); + SETPARAM(envReverb, DIFFUSION, props.Diffusion/100.f); + SETPARAM(envReverb, GAIN, mB2Gain(props.Room)); + SETPARAM(envReverb, GAINHF, mB2Gain(props.RoomHF)); + SETPARAM(envReverb, GAINLF, mB2Gain(props.RoomLF)); + SETPARAM(envReverb, DECAY_TIME, props.DecayTime); + SETPARAM(envReverb, DECAY_HFRATIO, props.DecayHFRatio); + SETPARAM(envReverb, DECAY_LFRATIO, props.DecayLFRatio); + SETPARAM(envReverb, REFLECTIONS_GAIN, mB2Gain(props.Reflections)); + SETPARAM(envReverb, REFLECTIONS_DELAY, props.ReflectionsDelay); + alEffectfv(envReverb, AL_EAXREVERB_REFLECTIONS_PAN, reflectpan); + SETPARAM(envReverb, LATE_REVERB_GAIN, mB2Gain(props.Reverb)); + SETPARAM(envReverb, LATE_REVERB_DELAY, props.ReverbDelay); + alEffectfv(envReverb, AL_EAXREVERB_LATE_REVERB_PAN, latepan); + SETPARAM(envReverb, ECHO_TIME, props.EchoTime); + SETPARAM(envReverb, ECHO_DEPTH, props.EchoDepth); + SETPARAM(envReverb, MODULATION_TIME, props.ModulationTime); + SETPARAM(envReverb, MODULATION_DEPTH, props.ModulationDepth); + SETPARAM(envReverb, AIR_ABSORPTION_GAINHF, mB2Gain(props.AirAbsorptionHF)); + SETPARAM(envReverb, HFREFERENCE, props.HFReference); + SETPARAM(envReverb, LFREFERENCE, props.LFReference); + SETPARAM(envReverb, ROOM_ROLLOFF_FACTOR, props.RoomRolloffFactor); + alEffecti(envReverb, AL_EAXREVERB_DECAY_HFLIMIT, + (props.Flags&REVERB_FLAGS_DECAYHFLIMIT)?AL_TRUE:AL_FALSE); +#undef SETPARAM + } + else if(type == AL_EFFECT_REVERB) + { +#define SETPARAM(e,t,v) alEffectf((e), AL_REVERB_##t, clamp((v), AL_REVERB_MIN_##t, AL_REVERB_MAX_##t)) + SETPARAM(envReverb, DENSITY, props.Density/100.f); + SETPARAM(envReverb, DIFFUSION, props.Diffusion/100.f); + SETPARAM(envReverb, GAIN, mB2Gain(props.Room)); + SETPARAM(envReverb, GAINHF, mB2Gain(props.RoomHF)); + SETPARAM(envReverb, DECAY_TIME, props.DecayTime); + SETPARAM(envReverb, DECAY_HFRATIO, props.DecayHFRatio); + SETPARAM(envReverb, REFLECTIONS_GAIN, mB2Gain(props.Reflections)); + SETPARAM(envReverb, REFLECTIONS_DELAY, props.ReflectionsDelay); + SETPARAM(envReverb, LATE_REVERB_GAIN, mB2Gain(props.Reverb)); + SETPARAM(envReverb, LATE_REVERB_DELAY, props.ReverbDelay); + SETPARAM(envReverb, AIR_ABSORPTION_GAINHF, mB2Gain(props.AirAbsorptionHF)); + SETPARAM(envReverb, ROOM_ROLLOFF_FACTOR, props.RoomRolloffFactor); + alEffecti(envReverb, AL_REVERB_DECAY_HFLIMIT, + (props.Flags&REVERB_FLAGS_DECAYHFLIMIT)?AL_TRUE:AL_FALSE); +#undef SETPARAM + } +#undef mB2Gain + } + + alAuxiliaryEffectSloti(EnvSlot, AL_EFFECTSLOT_EFFECT, envReverb); + getALError(); +} + +FSoundChan *OpenALSoundRenderer::FindLowestChannel() +{ + FSoundChan *schan = Channels; + FSoundChan *lowest = NULL; + while(schan) + { + if(schan->SysChannel != NULL) + { + if(!lowest || schan->Priority < lowest->Priority || + (schan->Priority == lowest->Priority && + schan->DistanceSqr > lowest->DistanceSqr)) + lowest = schan; + } + schan = schan->NextChan; + } + return lowest; +} + +#endif // NO_OPENAL diff --git a/src/sound/oalsound.h b/src/sound/oalsound.h index 24450c5b12..9842e63126 100644 --- a/src/sound/oalsound.h +++ b/src/sound/oalsound.h @@ -196,8 +196,9 @@ private: ALuint EnvFilters[2]; float LastWaterAbsorb; - std::vector Streams; - friend class OpenALSoundStream; + std::vector Streams; + friend class OpenALSoundStream; + friend class OpenALCallbackStream; }; #endif // NO_OPENAL From ba3cc38d095e0e7d6191f9a0e4a825509db1ac09 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 30 Jun 2013 08:04:08 -0700 Subject: [PATCH 09/88] Support float stream callbacks with AL_EXT_FLOAT32 --- src/sound/oalsound.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index afcfe9727a..b6ac21b1d4 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -420,6 +420,11 @@ public: if((flags&Mono)) Format = AL_FORMAT_MONO16; else Format = AL_FORMAT_STEREO16; } + else if((flags&Float) && alIsExtensionPresent("AL_EXT_FLOAT32")) + { + if((flags&Mono)) Format = AL_FORMAT_MONO_FLOAT32; + else Format = AL_FORMAT_STEREO_FLOAT32; + } if(Format == AL_NONE) { From c4492f88ee7a3dcb5362774ae2e33e9d08607f28 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 30 Jun 2013 08:04:41 -0700 Subject: [PATCH 10/88] Make sure streams are "pumped" --- src/sound/oalsound.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index b6ac21b1d4..1bccec31de 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -1518,6 +1518,10 @@ void OpenALSoundRenderer::UpdateSounds() { alcProcessContext(Context); + // For some reason this isn't being called? + foreach(SoundStream*, stream, Streams) + (*stream)->IsEnded(); + if(DisconnectNotify) { ALCint connected = ALC_TRUE; From 68988ab93cb685c8b4b87cba0d339634a42af8cf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 30 Jun 2013 08:16:49 -0700 Subject: [PATCH 11/88] Handle S8 and U16 samples from SDL_sound --- src/sound/oalsdlsound.cpp | 72 ++++++++++++++++++++++++++++++++++++--- src/sound/oalsdlsound.h | 4 +++ 2 files changed, 72 insertions(+), 4 deletions(-) diff --git a/src/sound/oalsdlsound.cpp b/src/sound/oalsdlsound.cpp index 6e704cddcb..d0fb88a2f7 100644 --- a/src/sound/oalsdlsound.cpp +++ b/src/sound/oalsdlsound.cpp @@ -182,7 +182,8 @@ bool OpenALSoundStream::SetupSource() OpenALSoundStream::OpenALSoundStream(OpenALSoundRenderer *renderer) : Renderer(renderer), Sample(NULL), Source(0), Playing(false), Looping(false), Buffers(4), SampleRate(0), Format(0), - NeedSwab(false), Volume(1.f) + NeedSwab(false), NeedS8Conv(false), NeedS16Conv(false), + Volume(1.f) { for(size_t i = 0;i < Buffers.size();i++) Buffers[i] = 0; @@ -328,6 +329,19 @@ void *OpenALSoundStream::GetData(size_t bytes) *(samples++) = ((smp>>8)&0x00FF) | ((smp<<8)*0xFF00); } } + if(NeedS8Conv) + { + char *samples = reinterpret_cast(data); + for(size_t i = 0;i < bytes;i++) + samples[i] = samples[i]^0x80; + } + if(NeedS16Conv) + { + short *samples = reinterpret_cast(data); + size_t count = bytes >> 1; + for(size_t i = 0;i < count;i++) + samples[i] = samples[i]^0x8000; + } return data; } @@ -337,7 +351,16 @@ bool OpenALSoundStream::InitSample() SampleRate = Sample->actual.rate; Format = AL_NONE; - if(Sample->actual.format == AUDIO_U8) + if(Sample->actual.format == AUDIO_S8) + { + NeedS8Conv = true; + if(Sample->actual.channels == 1) + Format = AL_FORMAT_MONO8; + else if(Sample->actual.channels == 2) + Format = AL_FORMAT_STEREO8; + smpsize = 1 * Sample->actual.channels; + } + else if(Sample->actual.format == AUDIO_U8) { if(Sample->actual.channels == 1) Format = AL_FORMAT_MONO8; @@ -354,6 +377,16 @@ bool OpenALSoundStream::InitSample() Format = AL_FORMAT_STEREO16; smpsize = 1 * Sample->actual.channels; } + else if(Sample->actual.format == AUDIO_U16LSB || Sample->actual.format == AUDIO_U16MSB) + { + NeedS16Conv = true; + NeedSwab = (Sample->actual.format != AUDIO_U16SYS); + if(Sample->actual.channels == 1) + Format = AL_FORMAT_MONO16; + else if(Sample->actual.channels == 2) + Format = AL_FORMAT_STEREO16; + smpsize = 1 * Sample->actual.channels; + } if(Format == AL_NONE) { @@ -426,7 +459,7 @@ bool OpenALSoundStream::Init(const BYTE *data, unsigned int datalen) Decoder::Decoder(const void* data, unsigned int datalen) - : Sample(NULL), NeedSwab(false) + : Sample(NULL), NeedSwab(false), NeedS8Conv(false), NeedS16Conv(false) { Sample = Sound_NewSample(SDL_RWFromConstMem(data, datalen), NULL, NULL, 65536); } @@ -441,7 +474,15 @@ Decoder::~Decoder() bool Decoder::GetFormat(ALenum *format, ALuint *rate) { ALenum fmt = AL_NONE; - if(Sample->actual.format == AUDIO_U8) + if(Sample->actual.format == AUDIO_S8) + { + NeedS8Conv = true; + if(Sample->actual.channels == 1) + fmt = AL_FORMAT_MONO8; + else if(Sample->actual.channels == 2) + fmt = AL_FORMAT_STEREO8; + } + else if(Sample->actual.format == AUDIO_U8) { if(Sample->actual.channels == 1) fmt = AL_FORMAT_MONO8; @@ -456,6 +497,15 @@ bool Decoder::GetFormat(ALenum *format, ALuint *rate) else if(Sample->actual.channels == 2) fmt = AL_FORMAT_STEREO16; } + else if(Sample->actual.format == AUDIO_U16LSB || Sample->actual.format == AUDIO_U16MSB) + { + NeedS16Conv = true; + NeedSwab = (Sample->actual.format != AUDIO_U16SYS); + if(Sample->actual.channels == 1) + fmt = AL_FORMAT_MONO16; + else if(Sample->actual.channels == 2) + fmt = AL_FORMAT_STEREO16; + } if(fmt == AL_NONE) { @@ -489,6 +539,20 @@ void* Decoder::GetData(ALsizei *size) } } + if(NeedS8Conv) + { + char *samples = reinterpret_cast(data); + for(size_t i = 0;i < got;i++) + samples[i] = samples[i]^0x80; + } + if(NeedS16Conv) + { + short *samples = reinterpret_cast(data); + size_t count = got >> 1; + for(size_t i = 0;i < count;i++) + samples[i] = samples[i]^0x8000; + } + *size = got; return data; } diff --git a/src/sound/oalsdlsound.h b/src/sound/oalsdlsound.h index 847edfb32d..597a825585 100644 --- a/src/sound/oalsdlsound.h +++ b/src/sound/oalsdlsound.h @@ -22,6 +22,8 @@ class OpenALSoundStream : public SoundStream ALenum Format; bool NeedSwab; + bool NeedS8Conv; + bool NeedS16Conv; void *GetData(size_t bytes); // General methods @@ -54,6 +56,8 @@ class Decoder { Sound_Sample *Sample; bool NeedSwab; + bool NeedS8Conv; + bool NeedS16Conv; public: Decoder(const void *data, unsigned int datalen); From 665d685a448523bc6256dc474fc6f827d6d14e1c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 30 Jun 2013 20:31:41 -0700 Subject: [PATCH 12/88] Implement GetStats for OpenAL streams --- src/sound/oalsdlsound.cpp | 35 +++++++++++++++++++++++++++++++++++ src/sound/oalsdlsound.h | 2 ++ src/sound/oalsound.cpp | 38 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 73 insertions(+), 2 deletions(-) diff --git a/src/sound/oalsdlsound.cpp b/src/sound/oalsdlsound.cpp index d0fb88a2f7..6ef7d9118a 100644 --- a/src/sound/oalsdlsound.cpp +++ b/src/sound/oalsdlsound.cpp @@ -345,6 +345,41 @@ void *OpenALSoundStream::GetData(size_t bytes) return data; } +FString OpenALSoundStream::GetStats() +{ + FString stats; + ALfloat volume; + ALint processed; + ALint queued; + ALint state; + ALenum err; + + alGetSourcef(Source, AL_GAIN, &volume); + alGetSourcei(Source, AL_SOURCE_STATE, &state); + alGetSourcei(Source, AL_BUFFERS_QUEUED, &queued); + alGetSourcei(Source, AL_BUFFERS_PROCESSED, &processed); + if((err=alGetError()) != AL_NO_ERROR) + { + stats = "Error getting stats: "; + stats += alGetString(err); + return stats; + } + + stats = (state == AL_INITIAL) ? "Buffering" : (state == AL_STOPPED) ? "Underrun" : + (state == AL_PLAYING || state == AL_PAUSED) ? "Ready" : "Unknown state"; + stats.AppendFormat(",%3d%% buffered", (queued ? 100-(processed*100/queued) : 0)); + stats.AppendFormat(", %d%%", int(volume * 100)); + if(state == AL_PAUSED) + stats += ", paused"; + if(state == AL_PLAYING) + stats += ", playing"; + stats.AppendFormat(", %uHz", SampleRate); + if(!Playing) + stats += " XX"; + return stats; +} + + bool OpenALSoundStream::InitSample() { UInt32 smpsize = 0; diff --git a/src/sound/oalsdlsound.h b/src/sound/oalsdlsound.h index 597a825585..7b7a0ce737 100644 --- a/src/sound/oalsdlsound.h +++ b/src/sound/oalsdlsound.h @@ -47,6 +47,8 @@ public: virtual bool IsEnded(); + virtual FString GetStats(); + bool Init(const char *filename, int offset, int length); bool Init(const BYTE *data, unsigned int datalen); }; diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 1bccec31de..afcaed59f9 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -400,6 +400,40 @@ public: return !Playing; } + FString GetStats() + { + FString stats; + ALfloat volume; + ALint processed; + ALint queued; + ALint state; + ALenum err; + + alGetSourcef(Source, AL_GAIN, &volume); + alGetSourcei(Source, AL_SOURCE_STATE, &state); + alGetSourcei(Source, AL_BUFFERS_QUEUED, &queued); + alGetSourcei(Source, AL_BUFFERS_PROCESSED, &processed); + if((err=alGetError()) != AL_NO_ERROR) + { + stats = "Error getting stats: "; + stats += alGetString(err); + return stats; + } + + stats = (state == AL_INITIAL) ? "Buffering" : (state == AL_STOPPED) ? "Underrun" : + (state == AL_PLAYING || state == AL_PAUSED) ? "Ready" : "Unknown state"; + stats.AppendFormat(",%3d%% buffered", (queued ? 100-(processed*100/queued) : 0)); + stats.AppendFormat(", %d%%", int(volume * 100)); + if(state == AL_PAUSED) + stats += ", paused"; + if(state == AL_PLAYING) + stats += ", playing"; + stats.AppendFormat(", %uHz", SampleRate); + if(!Playing) + stats += " XX"; + return stats; + } + bool Init(SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata) { if(!SetupSource()) @@ -428,8 +462,8 @@ public: if(Format == AL_NONE) { - Printf("Unsupported format: 0x%x\n", flags); - return false; + Printf("Unsupported format: 0x%x\n", flags); + return false; } int smpsize = 1; From 2142e857a95789b87f5808bf7588675362421b75 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Wed, 23 Oct 2013 19:41:58 -0400 Subject: [PATCH 13/88] - Applied VoidMage's OpenAL patch. --- src/sound/oalsound.cpp | 21 ++++++++++++++++++--- src/sound/oalsound.h | 7 +++++-- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 7bed39a862..e3d2d98ba3 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -1866,7 +1866,7 @@ float OpenALSoundRenderer::GetOutputRate() } -SoundHandle OpenALSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int length, int frequency, int channels, int bits, int loopstart) +SoundHandle OpenALSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int length, int frequency, int channels, int bits, int loopstart, int loopend) { SoundHandle retval = { NULL }; @@ -1915,7 +1915,7 @@ SoundHandle OpenALSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int length, int fre { ALint loops[2] = { loopstart, - length / (channels*bits/8) + loopend == -1 ? length / (channels*bits/8) : loopend }; Printf("Setting loop points %d -> %d\n", loops[0], loops[1]); alBufferiv(buffer, AL_LOOP_POINTS, loops); @@ -2346,6 +2346,21 @@ void OpenALSoundRenderer::StopChannel(FISoundChannel *chan) FreeSfx.push_back(source); } +void OpenALSoundRenderer::ChannelVolume(FISoundChannel *chan, float volume) +{ + if (chan != NULL && chan->SysChannel != NULL) + { + ALuint source = *((ALuint*)chan->SysChannel); + + alcSuspendContext(Context); + alSourcef(source, AL_MAX_GAIN, volume); + if(chan->ManualGain) + volume *= GetRolloff(&chan->Rolloff, sqrt(chan->DistanceSqr)); + alSourcef(source, AL_GAIN, volume); + } + getALError(); +} + unsigned int OpenALSoundRenderer::GetPosition(FISoundChannel *chan) { if(chan == NULL || chan->SysChannel == NULL) @@ -2384,7 +2399,7 @@ void OpenALSoundRenderer::SetSfxPaused(bool paused, int slot) } } -void OpenALSoundRenderer::SetInactive(bool inactive) +void OpenALSoundRenderer::SetInactive(SoundRenderer::EInactiveState inactive) { } diff --git a/src/sound/oalsound.h b/src/sound/oalsound.h index 53bee81814..d971e9f6bf 100644 --- a/src/sound/oalsound.h +++ b/src/sound/oalsound.h @@ -82,7 +82,7 @@ public: virtual void SetSfxVolume(float volume); virtual void SetMusicVolume(float volume); virtual SoundHandle LoadSound(BYTE *sfxdata, int length); - virtual SoundHandle LoadSoundRaw(BYTE *sfxdata, int length, int frequency, int channels, int bits, int loopstart); + virtual SoundHandle LoadSoundRaw(BYTE *sfxdata, int length, int frequency, int channels, int bits, int loopstart, int loopend = -1); virtual void UnloadSound(SoundHandle sfx); virtual unsigned int GetMSLength(SoundHandle sfx); virtual unsigned int GetSampleLength(SoundHandle sfx); @@ -99,6 +99,9 @@ public: // Stops a sound channel. virtual void StopChannel(FISoundChannel *chan); + // Changes a channel's volume. + void ChannelVolume (FISoundChannel *chan, float volume); + // Returns position of sound on this channel, in samples. virtual unsigned int GetPosition(FISoundChannel *chan); @@ -109,7 +112,7 @@ public: virtual void SetSfxPaused(bool paused, int slot); // Pauses or resumes *every* channel, including environmental reverb. - virtual void SetInactive(bool inactive); + virtual void SetInactive(SoundRenderer::EInactiveState inactive); // Updates the volume, separation, and pitch of a sound channel. virtual void UpdateSoundParams3D(SoundListener *listener, FISoundChannel *chan, bool areasound, const FVector3 &pos, const FVector3 &vel); From 160e70f8f27394eccd7d757fd73c9665cdfe1d65 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 15 Jun 2014 09:27:00 -0700 Subject: [PATCH 14/88] Fix getting the actual device name --- src/sound/oalsound.cpp | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index afcaed59f9..3c3037f88e 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -591,7 +591,13 @@ OpenALSoundRenderer::OpenALSoundRenderer() } } - Printf(" Opened device "TEXTCOLOR_ORANGE"%s\n", alcGetString(Device, ALC_DEVICE_SPECIFIER)); + const ALCchar *current = NULL; + if(alcIsExtensionPresent(Device, "ALC_ENUMERATE_ALL_EXT")) + current = alcGetString(Device, ALC_ALL_DEVICES_SPECIFIER); + if(alcGetError(Device) != ALC_NO_ERROR || !current) + current = alcGetString(Device, ALC_DEVICE_SPECIFIER); + Printf(" Opened device "TEXTCOLOR_ORANGE"%s\n", current); + ALCint major=0, minor=0; alcGetIntegerv(Device, ALC_MAJOR_VERSION, 1, &major); alcGetIntegerv(Device, ALC_MINOR_VERSION, 1, &minor); @@ -609,7 +615,7 @@ OpenALSoundRenderer::OpenALSoundRenderer() // Make sure one source is capable of stereo output with the rest doing // mono, without running out of voices attribs.push_back(ALC_MONO_SOURCES); - attribs.push_back((std::max)(*snd_channels, 2) - 1); + attribs.push_back(std::max(*snd_channels, 2) - 1); attribs.push_back(ALC_STEREO_SOURCES); attribs.push_back(1); // Other attribs..? @@ -657,7 +663,8 @@ OpenALSoundRenderer::OpenALSoundRenderer() alcGetIntegerv(Device, ALC_MONO_SOURCES, 1, &numMono); alcGetIntegerv(Device, ALC_STEREO_SOURCES, 1, &numStereo); - Sources.resize((std::min)((std::max)(*snd_channels, 2), numMono+numStereo)); + Sources.resize(std::min(std::max(*snd_channels, 2), + numMono+numStereo)); for(size_t i = 0;i < Sources.size();i++) { alGenSources(1, &Sources[i]); @@ -1663,13 +1670,23 @@ void OpenALSoundRenderer::PrintDriversList() const ALCchar *drivers = (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") ? alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER) : alcGetString(NULL, ALC_DEVICE_SPECIFIER)); - const ALCchar *current = alcGetString(Device, ALC_DEVICE_SPECIFIER); if(drivers == NULL) { Printf(TEXTCOLOR_YELLOW"Failed to retrieve device list: %s\n", alcGetString(NULL, alcGetError(NULL))); return; } + const ALCchar *current = NULL; + if(alcIsExtensionPresent(Device, "ALC_ENUMERATE_ALL_EXT")) + current = alcGetString(Device, ALC_ALL_DEVICES_SPECIFIER); + if(alcGetError(Device) != ALC_NO_ERROR || !current) + current = alcGetString(Device, ALC_DEVICE_SPECIFIER); + if(current == NULL) + { + Printf(TEXTCOLOR_YELLOW"Failed to retrieve device name: %s\n", alcGetString(Device, alcGetError(Device))); + return; + } + Printf("%c%s%2d. %s\n", ' ', ((strcmp(snd_aldevice, "Default") == 0) ? TEXTCOLOR_BOLD : ""), 0, "Default"); for(int i = 1;*drivers;i++) From 82de7e6357fde023c81ace8b01574c25ec51dbcb Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 15 Jun 2014 11:36:49 -0700 Subject: [PATCH 15/88] Convert line-endings --- src/CMakeLists.txt | 2072 ++++++++++++++++++++++---------------------- 1 file changed, 1036 insertions(+), 1036 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ed70bda4a2..43572ff14e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,1036 +1,1036 @@ -cmake_minimum_required( VERSION 2.4 ) - -if( COMMAND cmake_policy ) - cmake_policy( SET CMP0003 NEW ) -endif( COMMAND cmake_policy ) - -include( CheckCXXSourceCompiles ) -include( CheckFunctionExists ) -include( CheckCXXCompilerFlag ) -include( FindPkgConfig ) - -if( NOT APPLE ) - option( NO_ASM "Disable assembly code" OFF ) -else( NOT APPLE ) - # At the moment asm code doesn't work with OS X, so disable by default - option( NO_ASM "Disable assembly code" ON ) -endif( NOT APPLE ) -if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" ) - option( NO_STRIP "Do not strip Release or MinSizeRel builds" ) - # At least some versions of Xcode fail if you strip with the linker - # instead of the separate strip utility. - if( APPLE ) - set( NO_STRIP ON ) - endif( APPLE ) -endif( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" ) - -option( DYN_FLUIDSYNTH "Dynamically load fluidsynth" ) - -if( CMAKE_SIZEOF_VOID_P MATCHES "8" ) - set( X64 64 ) -endif( CMAKE_SIZEOF_VOID_P MATCHES "8" ) - -# You can either use "make install" on the FMOD distribution to put it -# in standard system locations, or you can unpack the FMOD distribution -# in the root of the zdoom tree. e.g.: -# zdoom -# docs -# fmodapilinux[64] -or simply- fmod -# jpeg-6b -# ... -# The recommended method is to put it in the zdoom tree, since its -# headers are unversioned. Especially now that we can't work properly -# with anything newer than 4.26.xx, you probably don't want to use -# a system-wide version. - -# Construct version numbers for searching for the FMOD library on Linux. -set( MINOR_VERSIONS "50" "49" "48" "47" "46" "45" "44" "43" "42" "41" - "40" "39" "38" "37" "36" "35" "34" "33" "32" "31" "30" "29" "28" - "27" "26" "25" "24" "23" "22" "21" "20" "21" "19" "18" "17" "16" - "15" "14" "13" "12" "11" "10" "09" "08" "07" "06" "05" "04" "03" - "02" "01" "00" ) -set( MAJOR_VERSIONS "44" "34" "28" "26" "24" "22" "20" ) -set( FMOD_DIR_VERSIONS ${FMOD_DIR_VERSIONS} "../fmod" ) -foreach( majver ${MAJOR_VERSIONS} ) - foreach( minver ${MINOR_VERSIONS} ) - set( FMOD_VERSIONS ${FMOD_VERSIONS} "fmodex${X64}-4.${majver}.${minver}" ) - set( FMOD_DIR_VERSIONS ${FMOD_DIR_VERSIONS} "${CMAKE_HOME_DIRECTORY}/fmodapi4${majver}${minver}linux${X64}" ) - endforeach( minver ${MINOR_VERSIONS} ) - foreach( dir ${FMOD_DIR_VERSIONS} ) - set( FMOD_LOCAL_INC_DIRS ${FMOD_LOCAL_INC_DIRS} "${dir}/api/inc" ) - set( FMOD_LOCAL_LIB_DIRS ${FMOD_LOCAL_LIB_DIRS} "${dir}/api/lib" ) - endforeach( dir ${FMOD_DIR_VERSIONS} ) -endforeach( majver ${MAJOR_VERSIONS} ) - -if( WIN32 ) - if( X64 ) - set( WIN_TYPE Win64 ) - set( XBITS x64 ) - else( X64 ) - set( WIN_TYPE Win32 ) - set( XBITS x86 ) - endif( X64 ) - - add_definitions( -D_WIN32 ) - - set( FMOD_SEARCH_PATHS - "C:/Program Files/FMOD SoundSystem/FMOD Programmers API ${WIN_TYPE}/api" - "C:/Program Files (x86)/FMOD SoundSystem/FMOD Programmers API ${WIN_TYPE}/api" - # This next one is for Randy. - "E:/Software/Dev/FMOD/${WIN_TYPE}/api" - # .. and this one for Graf Zahl - "D:/portable/FMOD SoundSystem 4.26/FMOD Programmers API WIN32/api" - ) - set( FMOD_INC_PATH_SUFFIXES PATH_SUFFIXES inc ) - set( FMOD_LIB_PATH_SUFFIXES PATH_SUFFIXES lib ) - set( NASM_NAMES nasmw nasm ) - - find_path( D3D_INCLUDE_DIR d3d9.h - PATHS ENV DXSDK_DIR - PATH_SUFFIXES Include ) - if( NOT D3D_INCLUDE_DIR ) - message( SEND_ERROR "Could not find DirectX 9 header files" ) - else( NOT D3D_INCLUDE_DIR ) - include_directories( ${D3D_INCLUDE_DIR} ) - endif( NOT D3D_INCLUDE_DIR ) - - find_path( XINPUT_INCLUDE_DIR xinput.h - PATHS ENV DXSDK_DIR - PATH_SUFFIXES Include ) - if( NOT XINPUT_INCLUDE_DIR ) - message( SEND_ERROR "Could not find xinput.h. XInput will be disabled." ) - add_definitions( -DNO_XINPUT ) - else( NOT XINPUT_INCLUDE_DIR ) - include_directories( ${XINPUT_INCLUDE_DIR} ) - endif( NOT XINPUT_INCLUDE_DIR ) - - find_library( DX_ddraw_LIBRARY ddraw - PATHS ENV DXSDK_DIR - PATH_SUFFIXES Lib Lib/${XBITS} ) - find_library( DX_dxguid_LIBRARY dxguid - PATHS ENV DXSDK_DIR - PATH_SUFFIXES Lib Lib/${XBITS} ) - find_library( DX_dinput8_LIBRARY dinput8 - PATHS ENV DXSDK_DIR - PATH_SUFFIXES Lib Lib/${XBITS} ) - - set( DX_LIBS_FOUND YES ) - if( NOT DX_ddraw_LIBRARY ) - set( DX_LIBS_FOUND NO ) - endif( NOT DX_ddraw_LIBRARY ) - if( NOT DX_dxguid_LIBRARY ) - set( DX_LIBS_FOUND NO ) - endif( NOT DX_dxguid_LIBRARY ) - if( NOT DX_dinput8_LIBRARY ) - set( DX_LIBS_FOUND NO ) - endif( NOT DX_dinput8_LIBRARY ) - - if( NOT DX_LIBS_FOUND ) - message( FATAL_ERROR "Could not find DirectX 9 libraries" ) - endif( NOT DX_LIBS_FOUND ) - - set( ZDOOM_LIBS - wsock32 - winmm - "${DX_ddraw_LIBRARY}" - "${DX_dxguid_LIBRARY}" - "${DX_dinput8_LIBRARY}" - ole32 - user32 - gdi32 - comctl32 - comdlg32 - ws2_32 - setupapi - oleaut32 ) -else( WIN32 ) - if( APPLE ) - set( FMOD_SEARCH_PATHS "/Developer/FMOD Programmers API Mac/api" ) - set( FMOD_INC_PATH_SUFFIXES PATH_SUFFIXES inc ) - set( FMOD_LIB_PATH_SUFFIXES PATH_SUFFIXES lib ) - set( NO_GTK ON ) - else( APPLE ) - option( NO_GTK "Disable GTK+ dialogs (Not applicable to Windows)" ) - option( VALGRIND "Add special Valgrind sequences to self-modifying code" ) - - set( FMOD_SEARCH_PATHS - /usr/local/include - /usr/local/include/fmodex - /usr/include - /usr/include/fmodex - /opt/local/include - /opt/local/include/fmodex - /opt/include - /opt/include/fmodex ) - set( FMOD_INC_PATH_SUFFIXES PATH_SUFFIXES fmodex ) - - # Use GTK+ for the IWAD picker, if available. - if( NOT NO_GTK ) - pkg_check_modules( GTK2 gtk+-2.0 ) - if( GTK2_FOUND ) - set( ZDOOM_LIBS ${ZDOOM_LIBS} ${GTK2_LIBRARIES} ) - include_directories( ${GTK2_INCLUDE_DIRS} ) - else( GTK2_FOUND ) - set( NO_GTK ON ) - endif( GTK2_FOUND ) - endif( NOT NO_GTK ) - - # Check for Xcursor library and header files - find_library( XCURSOR_LIB Xcursor ) - if( XCURSOR_LIB ) - find_file( XCURSOR_HEADER "X11/Xcursor/Xcursor.h" ) - if( XCURSOR_HEADER ) - add_definitions( -DUSE_XCURSOR=1 ) - message( STATUS "Found Xcursor at ${XCURSOR_LIB}" ) - set( ZDOOM_LIBS ${ZDOOM_LIBS} ${XCURSOR_LIB} ) - else( XCURSOR_HEADER ) - unset( XCURSOR_LIB ) - endif( XCURSOR_HEADER ) - endif( XCURSOR_LIB ) - endif( APPLE ) - set( NASM_NAMES nasm ) - - if( NO_GTK ) - add_definitions( -DNO_GTK=1 ) - endif( NO_GTK ) - - # Non-Windows version also needs SDL - find_package( SDL ) - if( NOT SDL_FOUND ) - message( SEND_ERROR "SDL is required for building." ) - endif( NOT SDL_FOUND ) - set( ZDOOM_LIBS ${ZDOOM_LIBS} "${SDL_LIBRARY}" ) - include_directories( "${SDL_INCLUDE_DIR}" ) - - find_path( FPU_CONTROL_DIR fpu_control.h ) - if( FPU_CONTROL_DIR ) - include_directories( ${FPU_CONTROL_DIR} ) - add_definitions( -DHAVE_FPU_CONTROL ) - endif( FPU_CONTROL_DIR ) -endif( WIN32 ) - - -set( OAL_SOURCES sound/oalsound.cpp ) -if( NOT NO_OPENAL ) - find_package( OpenAL ) - if( OPENAL_FOUND ) - include_directories( ${OPENAL_INCLUDE_DIR} ) - set( ZDOOM_LIBS ${OPENAL_LIBRARY} ${ZDOOM_LIBS} ) - find_package( SDL ) - if( SDL_FOUND ) - find_package( SDL_sound ) - if( SDL_SOUND_FOUND ) - set_source_files_properties( sound/oalsound.cpp PROPERTIES COMPILE_FLAGS "-DWITH_SDL_SOUND=1" ) - set( OAL_SOURCES ${OAL_SOURCES} sound/oalsdlsound.cpp ) - include_directories( ${SDL_SOUND_INCLUDE_DIR} ) - set( ZDOOM_LIBS ${SDL_SOUND_LIBRARIES} ${ZDOOM_LIBS} ) - endif( SDL_SOUND_FOUND ) - endif( SDL_FOUND ) - else( OPENAL_FOUND ) - set( NO_OPENAL ON ) - endif( OPENAL_FOUND ) -endif( NOT NO_OPENAL ) - -if( NOT NO_FMOD ) - # Search for FMOD include files - if( NOT WIN32 ) - find_path( FMOD_INCLUDE_DIR fmod.hpp - PATHS ${FMOD_LOCAL_INC_DIRS} ) - endif( NOT WIN32 ) - - if( NOT FMOD_INCLUDE_DIR ) - find_path( FMOD_INCLUDE_DIR fmod.hpp - PATHS ${FMOD_SEARCH_PATHS} - ${FMOD_INC_PATH_SUFFIXES} ) - endif( NOT FMOD_INCLUDE_DIR ) - - if( FMOD_INCLUDE_DIR ) - message( STATUS "FMOD include files found at ${FMOD_INCLUDE_DIR}" ) - include_directories( "${FMOD_INCLUDE_DIR}" ) - else( FMOD_INCLUDE_DIR ) - message( STATUS "Could not find FMOD include files" ) - set( NO_FMOD ON ) - endif( FMOD_INCLUDE_DIR ) -endif( NOT NO_FMOD ) - -if( NOT NO_FMOD ) - # Decide on the name of the FMOD library we want to use. - if( NOT FMOD_LIB_NAME AND MSVC ) - set( FMOD_LIB_NAME fmodex${X64}_vc ) - endif( NOT FMOD_LIB_NAME AND MSVC ) - - if( NOT FMOD_LIB_NAME AND BORLAND ) - set( FMOD_LIB_NAME fmodex${X64}_bc ) - endif( NOT FMOD_LIB_NAME AND BORLAND ) - - if( NOT FMOD_LIB_NAME ) - set( FMOD_LIB_NAME fmodex${X64} ) - endif( NOT FMOD_LIB_NAME ) - - # Search for FMOD library - if( WIN32 OR APPLE ) - find_library( FMOD_LIBRARY ${FMOD_LIB_NAME} - PATHS ${FMOD_SEARCH_PATHS} - ${FMOD_LIB_PATH_SUFFIXES} ) - else( WIN32 OR APPLE ) - find_library( FMOD_LIBRARY - NAMES ${FMOD_VERSIONS} - PATHS ${FMOD_LOCAL_LIB_DIRS} ) - endif( WIN32 OR APPLE ) - - if( FMOD_LIBRARY ) - message( STATUS "FMOD library found at ${FMOD_LIBRARY}" ) - set( ZDOOM_LIBS ${ZDOOM_LIBS} "${FMOD_LIBRARY}" ) - else( FMOD_LIBRARY ) - message( STATUS "Could not find FMOD library" ) - set( NO_FMOD ON ) - endif( FMOD_LIBRARY ) -endif( NOT NO_FMOD ) - -if( NO_FMOD ) - add_definitions( -DNO_FMOD=1 ) -endif( NO_FMOD ) -if( NO_OPENAL ) - add_definitions( -DNO_OPENAL=1 ) -endif( NO_OPENAL ) - -# Search for FluidSynth - -find_package( FluidSynth ) - -# Search for NASM - -if( NOT NO_ASM ) - if( UNIX AND X64 ) - find_program( GAS_PATH as ) - - if( GAS_PATH ) - set( ASSEMBLER ${GAS_PATH} ) - else( GAS_PATH ) - message( STATUS "Could not find as. Disabling assembly code." ) - set( NO_ASM ON ) - endif( GAS_PATH ) - else( UNIX AND X64 ) - find_program( NASM_PATH NAMES ${NASM_NAMES} ) - find_program( YASM_PATH yasm ) - - if( X64 ) - if( YASM_PATH ) - set( ASSEMBLER ${YASM_PATH} ) - else( YASM_PATH ) - message( STATUS "Could not find YASM. Disabling assembly code." ) - set( NO_ASM ON ) - endif( YASM_PATH ) - else( X64 ) - if( NASM_PATH ) - set( ASSEMBLER ${NASM_PATH} ) - else( NASM_PATH ) - message( STATUS "Could not find NASM. Disabling assembly code." ) - set( NO_ASM ON ) - endif( NASM_PATH ) - endif( X64 ) - endif( UNIX AND X64 ) - - # I think the only reason there was a version requirement was because the - # executable name for Windows changed from 0.x to 2.0, right? This is - # how to do it in case I need to do something similar later. - - # execute_process( COMMAND ${NASM_PATH} -v - # OUTPUT_VARIABLE NASM_VER_STRING ) - # string( REGEX REPLACE ".*version ([0-9]+[.][0-9]+).*" "\\1" NASM_VER "${NASM_VER_STRING}" ) - # if( NOT NASM_VER LESS 2 ) - # message( SEND_ERROR "NASM version should be 2 or later. (Installed version is ${NASM_VER}.)" ) - # endif( NOT NASM_VER LESS 2 ) -endif( NOT NO_ASM ) - -if( NOT NO_ASM ) - # Valgrind support is meaningless without assembly code. - if( VALGRIND ) - add_definitions( -DVALGRIND_AWARE=1 ) - # If you're Valgrinding, you probably want to keep symbols around. - set( NO_STRIP ON ) - endif( VALGRIND ) - - # Tell CMake how to assemble our files - if( UNIX ) - set( ASM_OUTPUT_EXTENSION .o ) - if( X64 ) - set( ASM_FLAGS ) - set( ASM_SOURCE_EXTENSION .s ) - else( X64 ) - if( APPLE ) - set( ASM_FLAGS -fmacho -DM_TARGET_MACHO ) - else( APPLE ) - set( ASM_FLAGS -felf -DM_TARGET_LINUX ) - endif( APPLE ) - set( ASM_FLAGS "${ASM_FLAGS}" -i${CMAKE_CURRENT_SOURCE_DIR}/ ) - set( ASM_SOURCE_EXTENSION .asm ) - endif( X64 ) - else( UNIX ) - set( ASM_OUTPUT_EXTENSION .obj ) - set( ASM_SOURCE_EXTENSION .asm ) - if( X64 ) - set( ASM_FLAGS -f win64 -DWIN32 -DWIN64 ) - else( X64 ) - set( ASM_FLAGS -f win32 -DWIN32 -i${CMAKE_CURRENT_SOURCE_DIR}/ ) - endif( X64 ) - endif( UNIX ) - if( WIN32 ) - set( FIXRTEXT fixrtext ) - endif( WIN32 ) - message( STATUS "Selected assembler: ${ASSEMBLER}" ) - MACRO( ADD_ASM_FILE indir infile ) - set( ASM_OUTPUT_${infile} "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/zdoom.dir/${indir}/${infile}${ASM_OUTPUT_EXTENSION}" ) - if( WIN32 ) - set( FIXRTEXT_${infile} COMMAND ${FIXRTEXT} "${ASM_OUTPUT_${infile}}" ) - endif( WIN32 ) - add_custom_command( OUTPUT ${ASM_OUTPUT_${infile}} - COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/zdoom.dir/${indir} - COMMAND ${ASSEMBLER} ${ASM_FLAGS} -o"${ASM_OUTPUT_${infile}}" "${CMAKE_CURRENT_SOURCE_DIR}/${indir}/${infile}${ASM_SOURCE_EXTENSION}" - ${FIXRTEXT_${infile}} - DEPENDS ${indir}/${infile}.asm ${FIXRTEXT} ) - set( ASM_SOURCES ${ASM_SOURCES} "${ASM_OUTPUT_${infile}}" ) - ENDMACRO( ADD_ASM_FILE ) -endif( NOT NO_ASM ) - -# Decide on SSE setup - -set( SSE_MATTERS NO ) - -# SSE only matters on 32-bit targets. We check compiler flags to know if we can do it. -if( CMAKE_SIZEOF_VOID_P MATCHES "4" AND NOT CMAKE_OSX_ARCHITECTURES MATCHES ppc ) - CHECK_CXX_COMPILER_FLAG( "-msse2 -mfpmath=sse" CAN_DO_MFPMATH ) - CHECK_CXX_COMPILER_FLAG( -arch:SSE2 CAN_DO_ARCHSSE2 ) - if( CAN_DO_MFPMATH ) - set( SSE1_ENABLE "-msse -mfpmath=sse" ) - set( SSE2_ENABLE "-msse2 -mfpmath=sse" ) - set( SSE_MATTERS YES ) - elseif( CAN_DO_ARCHSSE2 ) - set( SSE1_ENABLE -arch:SSE ) - set( SSE2_ENABLE -arch:SSE2 ) - set( SSE_MATTERS YES ) - endif( CAN_DO_MFPMATH ) -endif( CMAKE_SIZEOF_VOID_P MATCHES "4" AND NOT CMAKE_OSX_ARCHITECTURES MATCHES ppc ) - -if( SSE_MATTERS ) - if( WIN32 ) - set( BACKPATCH 1 CACHE BOOL "Enable backpatching." ) - else( WIN32 ) - CHECK_FUNCTION_EXISTS(mprotect HAVE_MPROTECT) - if( HAVE_MPROTECT ) - set( BACKPATCH 1 CACHE BOOL "Enable backpatching." ) - else( HAVE_MPROTECT ) - set( BACKPATCH 0 ) - endif( HAVE_MPROTECT ) - endif( WIN32 ) - set( SSE 1 CACHE BOOL "Build SSE and SSE2 versions of key code." ) -else( SSE_MATTERS ) - set( BACKPATCH 0 ) -endif( SSE_MATTERS ) - -# Set up flags for GCC - -if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" ) - if( PROFILE ) - set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -pg" ) - set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -pg" ) - set( CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -pg" ) - set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -pg" ) - endif( PROFILE ) - - set( REL_CXX_FLAGS "-fno-rtti" ) - if( NOT PROFILE ) - set( REL_CXX_FLAGS "${REL_CXX_FLAGS} -fomit-frame-pointer" ) - endif( NOT PROFILE ) - set( CMAKE_CXX_FLAGS_RELEASE "${REL_CXX_FLAGS} ${CMAKE_CXX_FLAGS_RELEASE}" ) - set( CMAKE_CXX_FLAGS_MINSIZEREL "${REL_CXX_FLAGS} ${CMAKE_CXX_FLAGS_MINSIZEREL}" ) - set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${REL_CXX_FLAGS} ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}" ) - - set( CMAKE_CXX_FLAGS "-Wall -Wno-unused -Wextra -Wno-missing-field-initializers ${CMAKE_CXX_FLAGS}" ) - - # Remove extra warnings when using the official DirectX headers. - # Also, TDM-GCC 4.4.0 no longer accepts glibc-style printf formats as valid, - # which is a royal pain. The previous version I had been using was fine with them. - if( WIN32 ) - set( CMAKE_CXX_FLAGS "-Wno-unknown-pragmas -Wno-comment -Wno-format ${CMAKE_CXX_FLAGS}" ) - endif( WIN32 ) - - if( NOT NO_STRIP ) - set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} -s" ) - set (CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "${CMAKE_EXE_LINKER_FLAGS_MINSIZEREL} -s" ) - endif( NOT NO_STRIP ) -endif( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" ) - -# Check for functions that may or may not exist. - -CHECK_FUNCTION_EXISTS( filelength FILELENGTH_EXISTS ) -if( FILELENGTH_EXISTS ) - add_definitions( -DHAVE_FILELENGTH=1 ) -endif( FILELENGTH_EXISTS ) - -CHECK_FUNCTION_EXISTS( strupr STRUPR_EXISTS ) -if( NOT STRUPR_EXISTS ) - add_definitions( -DNEED_STRUPR=1 ) -endif( NOT STRUPR_EXISTS ) - -CHECK_FUNCTION_EXISTS( stricmp STRICMP_EXISTS ) -if( NOT STRICMP_EXISTS ) - add_definitions( -Dstricmp=strcasecmp ) -endif( NOT STRICMP_EXISTS ) - -CHECK_FUNCTION_EXISTS( strnicmp STRNICMP_EXISTS ) -if( NOT STRNICMP_EXISTS ) - add_definitions( -Dstrnicmp=strncasecmp ) -endif( NOT STRNICMP_EXISTS ) - -if( NOT MSVC ) - add_definitions( -D__forceinline=inline ) -endif( NOT MSVC ) - -if( UNIX ) - CHECK_LIBRARY_EXISTS( rt clock_gettime "" CLOCK_GETTIME_IN_RT ) - if( NOT CLOCK_GETTIME_IN_RT ) - CHECK_FUNCTION_EXISTS( clock_gettime CLOCK_GETTIME_EXISTS ) - if( NOT CLOCK_GETTIME_EXISTS ) - message( STATUS "Could not find clock_gettime. Timing statistics will not be available." ) - add_definitions( -DNO_CLOCK_GETTIME ) - endif( NOT CLOCK_GETTIME_EXISTS ) - else( NOT CLOCK_GETTIME_IN_RT ) - set( ZDOOM_LIBS ${ZDOOM_LIBS} rt ) - endif( NOT CLOCK_GETTIME_IN_RT ) -endif( UNIX ) - -CHECK_CXX_SOURCE_COMPILES( - "#include - int main() { va_list list1, list2; va_copy(list1, list2); return 0; }" - HAS_VA_COPY ) -if( NOT HAS_VA_COPY ) - CHECK_CXX_SOURCE_COMPILES( - "#include - int main() { va_list list1, list2; __va_copy(list1, list2); return 0; }" - HAS___VA_COPY ) - if( HAS___VA_COPY ) - add_definitions( -Dva_copy=__va_copy ) - else( HAS___VA_COPY ) - add_definitions( -DNO_VA_COPY ) - endif( HAS___VA_COPY ) -endif( NOT HAS_VA_COPY ) - -# Flags - -if( BACKPATCH ) - add_definitions( -DBACKPATCH ) -endif( BACKPATCH ) - -# Update gitinfo.h - -get_target_property( UPDATEREVISION_EXE updaterevision LOCATION ) - -add_custom_target( revision_check ALL - COMMAND ${UPDATEREVISION_EXE} src/gitinfo.h - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - DEPENDS updaterevision ) - -# Libraries ZDoom needs - -message( STATUS "Fluid synth libs: ${FLUIDSYNTH_LIBRARIES}" ) -set( ZDOOM_LIBS ${ZDOOM_LIBS} "${ZLIB_LIBRARIES}" "${JPEG_LIBRARIES}" "${BZIP2_LIBRARIES}" "${FMOD_LIBRARY}" ) -include_directories( "${ZLIB_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" ) - -if( FLUIDSYNTH_FOUND ) - if( NOT DYN_FLUIDSYNTH) - set( ZDOOM_LIBS ${ZDOOM_LIBS} "${FLUIDSYNTH_LIBRARIES}" ) - include_directories( "${FLUIDSYNTH_INCLUDE_DIR}" ) - endif( NOT DYN_FLUIDSYNTH ) -endif( FLUIDSYNTH_FOUND ) - -# Start defining source files for ZDoom - -if( WIN32 ) - set( SYSTEM_SOURCES_DIR win32 ) - set( SYSTEM_SOURCES - win32/eaxedit.cpp - win32/fb_d3d9.cpp - win32/fb_d3d9_wipe.cpp - win32/fb_ddraw.cpp - win32/hardware.cpp - win32/helperthread.cpp - win32/i_cd.cpp - win32/i_crash.cpp - win32/i_input.cpp - win32/i_keyboard.cpp - win32/i_mouse.cpp - win32/i_dijoy.cpp - win32/i_rawps2.cpp - win32/i_xinput.cpp - win32/i_main.cpp - win32/i_movie.cpp - win32/i_system.cpp - win32/st_start.cpp - win32/win32video.cpp ) - if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" ) - # CMake is not set up to compile and link rc files with GCC. :( - add_custom_command( OUTPUT zdoom-rc.o - COMMAND windres -o zdoom-rc.o -i ${CMAKE_CURRENT_SOURCE_DIR}/win32/zdoom.rc - DEPENDS win32/zdoom.rc ) - set( SYSTEM_SOURCES ${SYSTEM_SOURCES} zdoom-rc.o ) - else( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" ) - set( SYSTEM_SOURCES ${SYSTEM_SOURCES} win32/zdoom.rc ) - endif( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" ) -else( WIN32 ) - set( SYSTEM_SOURCES_DIR sdl ) - set( SYSTEM_SOURCES - sdl/crashcatcher.c - sdl/hardware.cpp - sdl/i_cd.cpp - sdl/i_input.cpp - sdl/i_joystick.cpp - sdl/i_main.cpp - sdl/i_movie.cpp - sdl/i_system.cpp - sdl/sdlvideo.cpp - sdl/st_start.cpp ) - if( APPLE ) - set( SYSTEM_SOURCES ${SYSTEM_SOURCES} sdl/SDLMain.m sdl/iwadpicker_cocoa.mm sdl/i_system_cocoa.mm ) - endif( APPLE ) -endif( WIN32 ) - -if( NO_ASM ) - add_definitions( -DNOASM ) -else( NO_ASM ) - if( X64 ) - ADD_ASM_FILE( asm_x86_64 tmap3 ) - else( X64 ) - ADD_ASM_FILE( asm_ia32 a ) - ADD_ASM_FILE( asm_ia32 misc ) - ADD_ASM_FILE( asm_ia32 tmap ) - ADD_ASM_FILE( asm_ia32 tmap2 ) - ADD_ASM_FILE( asm_ia32 tmap3 ) - endif( X64 ) -endif( NO_ASM ) - -get_target_property( LEMON_EXE lemon LOCATION ) -get_target_property( RE2C_EXE re2c LOCATION ) - -add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.c ${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.h - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/xlat/xlat_parser.y . - COMMAND ${LEMON_EXE} xlat_parser.y - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS lemon ${CMAKE_CURRENT_SOURCE_DIR}/xlat/xlat_parser.y ) - -add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h - COMMAND ${RE2C_EXE} --no-generation-date -s -o ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h ${CMAKE_CURRENT_SOURCE_DIR}/sc_man_scanner.re - DEPENDS re2c ${CMAKE_CURRENT_SOURCE_DIR}/sc_man_scanner.re ) - -include_directories( ${CMAKE_CURRENT_BINARY_DIR} ) - -if( SSE_MATTERS ) - if( SSE ) - set( X86_SOURCES nodebuild_classify_sse2.cpp ) - set_source_files_properties( nodebuild_classify_sse2.cpp PROPERTIES COMPILE_FLAGS "${SSE2_ENABLE}" ) - else( SSE ) - add_definitions( -DDISABLE_SSE ) - endif( SSE ) -else( SSE_MATTERS ) - add_definitions( -DDISABLE_SSE ) - set( X86_SOURCES ) -endif( SSE_MATTERS ) - -if( DYN_FLUIDSYNTH ) - add_definitions( -DHAVE_FLUIDSYNTH -DDYN_FLUIDSYNTH ) -elseif( FLUIDSYNTH_FOUND ) - add_definitions( -DHAVE_FLUIDSYNTH ) -endif( DYN_FLUIDSYNTH ) - -# Project files should be aware of the header files. We can GLOB these since -# there's generally a new cpp for every header so this file will get changed -if( WIN32 ) - set( EXTRA_HEADER_DIRS win32/*.h ) -else( WIN32 ) - set( EXTRA_HEADER_DIRS sdl/*.h ) -endif( WIN32 ) -file( GLOB HEADER_FILES - ${EXTRA_HEADER_DIRS} - fragglescript/*.h - g_doom/*.h - g_heretic/*.h - g_hexen/*.h - g_raven/*.h - g_shared/*.h - g_strife/*.h - intermission/*.h - menu/*.h - oplsynth/*.h - r_data/*.h - resourcefiles/*.h - sfmt/*.h - sound/*.h - textures/*.h - thingdef/*.h - xlat/*.h - *.h -) - -add_executable( zdoom WIN32 - ${HEADER_FILES} - autostart.cpp - ${ASM_SOURCES} - ${SYSTEM_SOURCES} - ${X86_SOURCES} - x86.cpp - actorptrselect.cpp - am_map.cpp - b_bot.cpp - b_func.cpp - b_game.cpp - b_move.cpp - b_think.cpp - bbannouncer.cpp - c_bind.cpp - c_cmds.cpp - c_console.cpp - c_cvars.cpp - c_dispatch.cpp - c_expr.cpp - cmdlib.cpp - colormatcher.cpp - compatibility.cpp - configfile.cpp - ct_chat.cpp - d_dehacked.cpp - d_iwad.cpp - d_main.cpp - d_net.cpp - d_netinfo.cpp - d_protocol.cpp - decallib.cpp - dobject.cpp - dobjgc.cpp - dobjtype.cpp - doomdef.cpp - doomstat.cpp - dsectoreffect.cpp - dthinker.cpp - f_wipe.cpp - farchive.cpp - files.cpp - g_game.cpp - g_hub.cpp - g_level.cpp - g_mapinfo.cpp - g_skill.cpp - gameconfigfile.cpp - gi.cpp - gitinfo.cpp - hu_scores.cpp - i_net.cpp - info.cpp - keysections.cpp - lumpconfigfile.cpp - m_alloc.cpp - m_argv.cpp - m_bbox.cpp - m_cheat.cpp - m_joy.cpp - m_misc.cpp - m_png.cpp - m_random.cpp - memarena.cpp - md5.cpp - name.cpp - nodebuild.cpp - nodebuild_classify_nosse2.cpp - nodebuild_events.cpp - nodebuild_extract.cpp - nodebuild_gl.cpp - nodebuild_utility.cpp - p_3dfloors.cpp - p_3dmidtex.cpp - p_acs.cpp - p_buildmap.cpp - p_ceiling.cpp - p_conversation.cpp - p_doors.cpp - p_effect.cpp - p_enemy.cpp - p_floor.cpp - p_glnodes.cpp - p_interaction.cpp - p_lights.cpp - p_linkedsectors.cpp - p_lnspec.cpp - p_map.cpp - p_maputl.cpp - p_mobj.cpp - p_pillar.cpp - p_plats.cpp - p_pspr.cpp - p_saveg.cpp - p_sectors.cpp - p_setup.cpp - p_sight.cpp - p_slopes.cpp - p_spec.cpp - p_states.cpp - p_switch.cpp - p_teleport.cpp - p_terrain.cpp - p_things.cpp - p_tick.cpp - p_trace.cpp - p_udmf.cpp - p_usdf.cpp - p_user.cpp - p_writemap.cpp - p_xlat.cpp - parsecontext.cpp - po_man.cpp - r_swrenderer.cpp - r_utility.cpp - r_3dfloors.cpp - r_bsp.cpp - r_draw.cpp - r_drawt.cpp - r_main.cpp - r_plane.cpp - r_polymost.cpp - r_segs.cpp - r_sky.cpp - r_things.cpp - s_advsound.cpp - s_environment.cpp - s_playlist.cpp - s_sndseq.cpp - s_sound.cpp - sc_man.cpp - st_stuff.cpp - statistics.cpp - stats.cpp - stringtable.cpp - strnatcmp.c - tables.cpp - teaminfo.cpp - tempfiles.cpp - v_blend.cpp - v_collection.cpp - v_draw.cpp - v_font.cpp - v_palette.cpp - v_pfx.cpp - v_text.cpp - v_video.cpp - w_wad.cpp - wi_stuff.cpp - zstrformat.cpp - zstring.cpp - g_doom/a_doommisc.cpp - g_heretic/a_hereticmisc.cpp - g_hexen/a_hexenmisc.cpp - g_raven/a_artitele.cpp - g_raven/a_minotaur.cpp - g_strife/a_strifestuff.cpp - g_strife/strife_sbar.cpp - g_shared/a_action.cpp - g_shared/a_armor.cpp - g_shared/a_artifacts.cpp - g_shared/a_bridge.cpp - g_shared/a_camera.cpp - g_shared/a_debris.cpp - g_shared/a_decals.cpp - g_shared/a_fastprojectile.cpp - g_shared/a_flashfader.cpp - g_shared/a_fountain.cpp - g_shared/a_hatetarget.cpp - g_shared/a_keys.cpp - g_shared/a_lightning.cpp - g_shared/a_mapmarker.cpp - g_shared/a_morph.cpp - g_shared/a_movingcamera.cpp - g_shared/a_pickups.cpp - g_shared/a_puzzleitems.cpp - g_shared/a_quake.cpp - g_shared/a_randomspawner.cpp - g_shared/a_secrettrigger.cpp - g_shared/a_sectoraction.cpp - g_shared/a_setcolor.cpp - g_shared/a_skies.cpp - g_shared/a_soundenvironment.cpp - g_shared/a_soundsequence.cpp - g_shared/a_spark.cpp - g_shared/a_specialspot.cpp - g_shared/a_waterzone.cpp - g_shared/a_weaponpiece.cpp - g_shared/a_weapons.cpp - g_shared/hudmessages.cpp - g_shared/sbarinfo.cpp - g_shared/sbar_mugshot.cpp - g_shared/shared_hud.cpp - g_shared/shared_sbar.cpp - intermission/intermission.cpp - intermission/intermission_parse.cpp - menu/colorpickermenu.cpp - menu/joystickmenu.cpp - menu/listmenu.cpp - menu/loadsavemenu.cpp - menu/menu.cpp - menu/menudef.cpp - menu/menuinput.cpp - menu/messagebox.cpp - menu/optionmenu.cpp - menu/playerdisplay.cpp - menu/playermenu.cpp - menu/readthis.cpp - menu/videomenu.cpp - oplsynth/fmopl.cpp - oplsynth/mlopl.cpp - oplsynth/mlopl_io.cpp - oplsynth/music_opldumper_mididevice.cpp - oplsynth/music_opl_mididevice.cpp - oplsynth/opl_mus_player.cpp - oplsynth/dosbox/opl.cpp - oplsynth/OPL3.cpp - resourcefiles/ancientzip.cpp - resourcefiles/file_7z.cpp - resourcefiles/file_grp.cpp - resourcefiles/file_lump.cpp - resourcefiles/file_rff.cpp - resourcefiles/file_wad.cpp - resourcefiles/file_zip.cpp - resourcefiles/file_pak.cpp - resourcefiles/file_directory.cpp - resourcefiles/resourcefile.cpp - sfmt/SFMT.cpp - sound/fmodsound.cpp - sound/i_music.cpp - sound/i_sound.cpp - sound/music_cd.cpp - sound/music_dumb.cpp - sound/music_gme.cpp - sound/music_mus_midiout.cpp - sound/music_smf_midiout.cpp - sound/music_hmi_midiout.cpp - sound/music_xmi_midiout.cpp - sound/music_midistream.cpp - sound/music_midi_base.cpp - sound/music_midi_timidity.cpp - sound/music_mus_opl.cpp - sound/music_stream.cpp - sound/music_fluidsynth_mididevice.cpp - sound/music_softsynth_mididevice.cpp - sound/music_timidity_mididevice.cpp - sound/music_win_mididevice.cpp - ${OAL_SOURCES} - sound/music_pseudo_mididevice.cpp - textures/animations.cpp - textures/anim_switches.cpp - textures/automaptexture.cpp - textures/bitmap.cpp - textures/buildtexture.cpp - textures/canvastexture.cpp - textures/ddstexture.cpp - textures/flattexture.cpp - textures/imgztexture.cpp - textures/jpegtexture.cpp - textures/multipatchtexture.cpp - textures/patchtexture.cpp - textures/pcxtexture.cpp - textures/pngtexture.cpp - textures/rawpagetexture.cpp - textures/emptytexture.cpp - textures/texture.cpp - textures/texturemanager.cpp - textures/tgatexture.cpp - textures/warptexture.cpp - thingdef/olddecorations.cpp - thingdef/thingdef.cpp - thingdef/thingdef_codeptr.cpp - thingdef/thingdef_data.cpp - thingdef/thingdef_exp.cpp - thingdef/thingdef_expression.cpp - thingdef/thingdef_function.cpp - thingdef/thingdef_parse.cpp - thingdef/thingdef_properties.cpp - thingdef/thingdef_states.cpp - timidity/common.cpp - timidity/instrum.cpp - timidity/instrum_dls.cpp - timidity/instrum_font.cpp - timidity/instrum_sf2.cpp - timidity/mix.cpp - timidity/playmidi.cpp - timidity/resample.cpp - timidity/timidity.cpp - xlat/parse_xlat.cpp - fragglescript/t_fspic.cpp - fragglescript/t_func.cpp - fragglescript/t_load.cpp - fragglescript/t_oper.cpp - fragglescript/t_parse.cpp - fragglescript/t_prepro.cpp - fragglescript/t_script.cpp - fragglescript/t_spec.cpp - fragglescript/t_variable.cpp - fragglescript/t_cmd.cpp - r_data/colormaps.cpp - r_data/sprites.cpp - r_data/voxels.cpp - r_data/renderstyle.cpp - r_data/r_interpolate.cpp - r_data/r_translate.cpp - autozend.cpp -) - -set_source_files_properties( xlat/parse_xlat.cpp PROPERTIES OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.c" ) -set_source_files_properties( sc_man.cpp PROPERTIES OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h" ) - -if(${CMAKE_SYSTEM_NAME} STREQUAL "SunOS") - # [BL] Solaris requires these to be explicitly linked. - set( ZDOOM_LIBS ${ZDOOM_LIBS} nsl socket) -endif(${CMAKE_SYSTEM_NAME} STREQUAL "SunOS") - -target_link_libraries( zdoom ${ZDOOM_LIBS} gme gdtoa dumb lzma ) -include_directories( . - g_doom - g_heretic - g_hexen - g_raven - g_strife - g_shared - oplsynth - sound - textures - thingdef - timidity - xlat - ../game-music-emu/gme - ../gdtoa - ../dumb/include - ${CMAKE_BINARY_DIR}/gdtoa - ${SYSTEM_SOURCES_DIR} ) - -add_dependencies( zdoom revision_check ) - -# RUNTIME_OUTPUT_DIRECTORY does not exist in CMake 2.4. -# Linux distributions are slow to adopt 2.6. :( -set_target_properties( zdoom PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${ZDOOM_OUTPUT_DIR} ) -set_target_properties( zdoom PROPERTIES OUTPUT_NAME ${ZDOOM_EXE_NAME} ) - -if( NOT WIN32 ) - FILE( WRITE ${CMAKE_CURRENT_BINARY_DIR}/link-make "if [ ! -e ${ZDOOM_OUTPUT_DIR}/${ZDOOM_EXE_NAME} ]; then ln -sf ${CMAKE_CURRENT_BINARY_DIR}/${ZDOOM_EXE_NAME} ${ZDOOM_OUTPUT_DIR}/${ZDOOM_EXE_NAME}; fi" ) - add_custom_command( TARGET zdoom POST_BUILD - COMMAND chmod +x ${CMAKE_CURRENT_BINARY_DIR}/link-make - COMMAND /bin/sh -c ${CMAKE_CURRENT_BINARY_DIR}/link-make ) -endif( NOT WIN32 ) -if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" ) - # GCC misoptimizes this file - set_source_files_properties( oplsynth/fmopl.cpp PROPERTIES COMPILE_FLAGS "-fno-tree-dominator-opts -fno-tree-fre" ) - - # Need to enable intrinsics for this file. - if( SSE_MATTERS ) - set_source_files_properties( x86.cpp PROPERTIES COMPILE_FLAGS "-msse2 -mmmx" ) - endif( SSE_MATTERS ) -endif( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" ) - -if( MSVC ) - set_target_properties(zdoom PROPERTIES LINK_FLAGS "/MANIFEST:NO") -endif( MSVC ) +cmake_minimum_required( VERSION 2.4 ) + +if( COMMAND cmake_policy ) + cmake_policy( SET CMP0003 NEW ) +endif( COMMAND cmake_policy ) + +include( CheckCXXSourceCompiles ) +include( CheckFunctionExists ) +include( CheckCXXCompilerFlag ) +include( FindPkgConfig ) + +if( NOT APPLE ) + option( NO_ASM "Disable assembly code" OFF ) +else( NOT APPLE ) + # At the moment asm code doesn't work with OS X, so disable by default + option( NO_ASM "Disable assembly code" ON ) +endif( NOT APPLE ) +if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" ) + option( NO_STRIP "Do not strip Release or MinSizeRel builds" ) + # At least some versions of Xcode fail if you strip with the linker + # instead of the separate strip utility. + if( APPLE ) + set( NO_STRIP ON ) + endif( APPLE ) +endif( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" ) + +option( DYN_FLUIDSYNTH "Dynamically load fluidsynth" ) + +if( CMAKE_SIZEOF_VOID_P MATCHES "8" ) + set( X64 64 ) +endif( CMAKE_SIZEOF_VOID_P MATCHES "8" ) + +# You can either use "make install" on the FMOD distribution to put it +# in standard system locations, or you can unpack the FMOD distribution +# in the root of the zdoom tree. e.g.: +# zdoom +# docs +# fmodapilinux[64] -or simply- fmod +# jpeg-6b +# ... +# The recommended method is to put it in the zdoom tree, since its +# headers are unversioned. Especially now that we can't work properly +# with anything newer than 4.26.xx, you probably don't want to use +# a system-wide version. + +# Construct version numbers for searching for the FMOD library on Linux. +set( MINOR_VERSIONS "50" "49" "48" "47" "46" "45" "44" "43" "42" "41" + "40" "39" "38" "37" "36" "35" "34" "33" "32" "31" "30" "29" "28" + "27" "26" "25" "24" "23" "22" "21" "20" "21" "19" "18" "17" "16" + "15" "14" "13" "12" "11" "10" "09" "08" "07" "06" "05" "04" "03" + "02" "01" "00" ) +set( MAJOR_VERSIONS "44" "34" "28" "26" "24" "22" "20" ) +set( FMOD_DIR_VERSIONS ${FMOD_DIR_VERSIONS} "../fmod" ) +foreach( majver ${MAJOR_VERSIONS} ) + foreach( minver ${MINOR_VERSIONS} ) + set( FMOD_VERSIONS ${FMOD_VERSIONS} "fmodex${X64}-4.${majver}.${minver}" ) + set( FMOD_DIR_VERSIONS ${FMOD_DIR_VERSIONS} "${CMAKE_HOME_DIRECTORY}/fmodapi4${majver}${minver}linux${X64}" ) + endforeach( minver ${MINOR_VERSIONS} ) + foreach( dir ${FMOD_DIR_VERSIONS} ) + set( FMOD_LOCAL_INC_DIRS ${FMOD_LOCAL_INC_DIRS} "${dir}/api/inc" ) + set( FMOD_LOCAL_LIB_DIRS ${FMOD_LOCAL_LIB_DIRS} "${dir}/api/lib" ) + endforeach( dir ${FMOD_DIR_VERSIONS} ) +endforeach( majver ${MAJOR_VERSIONS} ) + +if( WIN32 ) + if( X64 ) + set( WIN_TYPE Win64 ) + set( XBITS x64 ) + else( X64 ) + set( WIN_TYPE Win32 ) + set( XBITS x86 ) + endif( X64 ) + + add_definitions( -D_WIN32 ) + + set( FMOD_SEARCH_PATHS + "C:/Program Files/FMOD SoundSystem/FMOD Programmers API ${WIN_TYPE}/api" + "C:/Program Files (x86)/FMOD SoundSystem/FMOD Programmers API ${WIN_TYPE}/api" + # This next one is for Randy. + "E:/Software/Dev/FMOD/${WIN_TYPE}/api" + # .. and this one for Graf Zahl + "D:/portable/FMOD SoundSystem 4.26/FMOD Programmers API WIN32/api" + ) + set( FMOD_INC_PATH_SUFFIXES PATH_SUFFIXES inc ) + set( FMOD_LIB_PATH_SUFFIXES PATH_SUFFIXES lib ) + set( NASM_NAMES nasmw nasm ) + + find_path( D3D_INCLUDE_DIR d3d9.h + PATHS ENV DXSDK_DIR + PATH_SUFFIXES Include ) + if( NOT D3D_INCLUDE_DIR ) + message( SEND_ERROR "Could not find DirectX 9 header files" ) + else( NOT D3D_INCLUDE_DIR ) + include_directories( ${D3D_INCLUDE_DIR} ) + endif( NOT D3D_INCLUDE_DIR ) + + find_path( XINPUT_INCLUDE_DIR xinput.h + PATHS ENV DXSDK_DIR + PATH_SUFFIXES Include ) + if( NOT XINPUT_INCLUDE_DIR ) + message( SEND_ERROR "Could not find xinput.h. XInput will be disabled." ) + add_definitions( -DNO_XINPUT ) + else( NOT XINPUT_INCLUDE_DIR ) + include_directories( ${XINPUT_INCLUDE_DIR} ) + endif( NOT XINPUT_INCLUDE_DIR ) + + find_library( DX_ddraw_LIBRARY ddraw + PATHS ENV DXSDK_DIR + PATH_SUFFIXES Lib Lib/${XBITS} ) + find_library( DX_dxguid_LIBRARY dxguid + PATHS ENV DXSDK_DIR + PATH_SUFFIXES Lib Lib/${XBITS} ) + find_library( DX_dinput8_LIBRARY dinput8 + PATHS ENV DXSDK_DIR + PATH_SUFFIXES Lib Lib/${XBITS} ) + + set( DX_LIBS_FOUND YES ) + if( NOT DX_ddraw_LIBRARY ) + set( DX_LIBS_FOUND NO ) + endif( NOT DX_ddraw_LIBRARY ) + if( NOT DX_dxguid_LIBRARY ) + set( DX_LIBS_FOUND NO ) + endif( NOT DX_dxguid_LIBRARY ) + if( NOT DX_dinput8_LIBRARY ) + set( DX_LIBS_FOUND NO ) + endif( NOT DX_dinput8_LIBRARY ) + + if( NOT DX_LIBS_FOUND ) + message( FATAL_ERROR "Could not find DirectX 9 libraries" ) + endif( NOT DX_LIBS_FOUND ) + + set( ZDOOM_LIBS + wsock32 + winmm + "${DX_ddraw_LIBRARY}" + "${DX_dxguid_LIBRARY}" + "${DX_dinput8_LIBRARY}" + ole32 + user32 + gdi32 + comctl32 + comdlg32 + ws2_32 + setupapi + oleaut32 ) +else( WIN32 ) + if( APPLE ) + set( FMOD_SEARCH_PATHS "/Developer/FMOD Programmers API Mac/api" ) + set( FMOD_INC_PATH_SUFFIXES PATH_SUFFIXES inc ) + set( FMOD_LIB_PATH_SUFFIXES PATH_SUFFIXES lib ) + set( NO_GTK ON ) + else( APPLE ) + option( NO_GTK "Disable GTK+ dialogs (Not applicable to Windows)" ) + option( VALGRIND "Add special Valgrind sequences to self-modifying code" ) + + set( FMOD_SEARCH_PATHS + /usr/local/include + /usr/local/include/fmodex + /usr/include + /usr/include/fmodex + /opt/local/include + /opt/local/include/fmodex + /opt/include + /opt/include/fmodex ) + set( FMOD_INC_PATH_SUFFIXES PATH_SUFFIXES fmodex ) + + # Use GTK+ for the IWAD picker, if available. + if( NOT NO_GTK ) + pkg_check_modules( GTK2 gtk+-2.0 ) + if( GTK2_FOUND ) + set( ZDOOM_LIBS ${ZDOOM_LIBS} ${GTK2_LIBRARIES} ) + include_directories( ${GTK2_INCLUDE_DIRS} ) + else( GTK2_FOUND ) + set( NO_GTK ON ) + endif( GTK2_FOUND ) + endif( NOT NO_GTK ) + + # Check for Xcursor library and header files + find_library( XCURSOR_LIB Xcursor ) + if( XCURSOR_LIB ) + find_file( XCURSOR_HEADER "X11/Xcursor/Xcursor.h" ) + if( XCURSOR_HEADER ) + add_definitions( -DUSE_XCURSOR=1 ) + message( STATUS "Found Xcursor at ${XCURSOR_LIB}" ) + set( ZDOOM_LIBS ${ZDOOM_LIBS} ${XCURSOR_LIB} ) + else( XCURSOR_HEADER ) + unset( XCURSOR_LIB ) + endif( XCURSOR_HEADER ) + endif( XCURSOR_LIB ) + endif( APPLE ) + set( NASM_NAMES nasm ) + + if( NO_GTK ) + add_definitions( -DNO_GTK=1 ) + endif( NO_GTK ) + + # Non-Windows version also needs SDL + find_package( SDL ) + if( NOT SDL_FOUND ) + message( SEND_ERROR "SDL is required for building." ) + endif( NOT SDL_FOUND ) + set( ZDOOM_LIBS ${ZDOOM_LIBS} "${SDL_LIBRARY}" ) + include_directories( "${SDL_INCLUDE_DIR}" ) + + find_path( FPU_CONTROL_DIR fpu_control.h ) + if( FPU_CONTROL_DIR ) + include_directories( ${FPU_CONTROL_DIR} ) + add_definitions( -DHAVE_FPU_CONTROL ) + endif( FPU_CONTROL_DIR ) +endif( WIN32 ) + + +set( OAL_SOURCES sound/oalsound.cpp ) +if( NOT NO_OPENAL ) + find_package( OpenAL ) + if( OPENAL_FOUND ) + include_directories( ${OPENAL_INCLUDE_DIR} ) + set( ZDOOM_LIBS ${OPENAL_LIBRARY} ${ZDOOM_LIBS} ) + find_package( SDL ) + if( SDL_FOUND ) + find_package( SDL_sound ) + if( SDL_SOUND_FOUND ) + set_source_files_properties( sound/oalsound.cpp PROPERTIES COMPILE_FLAGS "-DWITH_SDL_SOUND=1" ) + set( OAL_SOURCES ${OAL_SOURCES} sound/oalsdlsound.cpp ) + include_directories( ${SDL_SOUND_INCLUDE_DIR} ) + set( ZDOOM_LIBS ${SDL_SOUND_LIBRARIES} ${ZDOOM_LIBS} ) + endif( SDL_SOUND_FOUND ) + endif( SDL_FOUND ) + else( OPENAL_FOUND ) + set( NO_OPENAL ON ) + endif( OPENAL_FOUND ) +endif( NOT NO_OPENAL ) + +if( NOT NO_FMOD ) + # Search for FMOD include files + if( NOT WIN32 ) + find_path( FMOD_INCLUDE_DIR fmod.hpp + PATHS ${FMOD_LOCAL_INC_DIRS} ) + endif( NOT WIN32 ) + + if( NOT FMOD_INCLUDE_DIR ) + find_path( FMOD_INCLUDE_DIR fmod.hpp + PATHS ${FMOD_SEARCH_PATHS} + ${FMOD_INC_PATH_SUFFIXES} ) + endif( NOT FMOD_INCLUDE_DIR ) + + if( FMOD_INCLUDE_DIR ) + message( STATUS "FMOD include files found at ${FMOD_INCLUDE_DIR}" ) + include_directories( "${FMOD_INCLUDE_DIR}" ) + else( FMOD_INCLUDE_DIR ) + message( STATUS "Could not find FMOD include files" ) + set( NO_FMOD ON ) + endif( FMOD_INCLUDE_DIR ) +endif( NOT NO_FMOD ) + +if( NOT NO_FMOD ) + # Decide on the name of the FMOD library we want to use. + if( NOT FMOD_LIB_NAME AND MSVC ) + set( FMOD_LIB_NAME fmodex${X64}_vc ) + endif( NOT FMOD_LIB_NAME AND MSVC ) + + if( NOT FMOD_LIB_NAME AND BORLAND ) + set( FMOD_LIB_NAME fmodex${X64}_bc ) + endif( NOT FMOD_LIB_NAME AND BORLAND ) + + if( NOT FMOD_LIB_NAME ) + set( FMOD_LIB_NAME fmodex${X64} ) + endif( NOT FMOD_LIB_NAME ) + + # Search for FMOD library + if( WIN32 OR APPLE ) + find_library( FMOD_LIBRARY ${FMOD_LIB_NAME} + PATHS ${FMOD_SEARCH_PATHS} + ${FMOD_LIB_PATH_SUFFIXES} ) + else( WIN32 OR APPLE ) + find_library( FMOD_LIBRARY + NAMES ${FMOD_VERSIONS} + PATHS ${FMOD_LOCAL_LIB_DIRS} ) + endif( WIN32 OR APPLE ) + + if( FMOD_LIBRARY ) + message( STATUS "FMOD library found at ${FMOD_LIBRARY}" ) + set( ZDOOM_LIBS ${ZDOOM_LIBS} "${FMOD_LIBRARY}" ) + else( FMOD_LIBRARY ) + message( STATUS "Could not find FMOD library" ) + set( NO_FMOD ON ) + endif( FMOD_LIBRARY ) +endif( NOT NO_FMOD ) + +if( NO_FMOD ) + add_definitions( -DNO_FMOD=1 ) +endif( NO_FMOD ) +if( NO_OPENAL ) + add_definitions( -DNO_OPENAL=1 ) +endif( NO_OPENAL ) + +# Search for FluidSynth + +find_package( FluidSynth ) + +# Search for NASM + +if( NOT NO_ASM ) + if( UNIX AND X64 ) + find_program( GAS_PATH as ) + + if( GAS_PATH ) + set( ASSEMBLER ${GAS_PATH} ) + else( GAS_PATH ) + message( STATUS "Could not find as. Disabling assembly code." ) + set( NO_ASM ON ) + endif( GAS_PATH ) + else( UNIX AND X64 ) + find_program( NASM_PATH NAMES ${NASM_NAMES} ) + find_program( YASM_PATH yasm ) + + if( X64 ) + if( YASM_PATH ) + set( ASSEMBLER ${YASM_PATH} ) + else( YASM_PATH ) + message( STATUS "Could not find YASM. Disabling assembly code." ) + set( NO_ASM ON ) + endif( YASM_PATH ) + else( X64 ) + if( NASM_PATH ) + set( ASSEMBLER ${NASM_PATH} ) + else( NASM_PATH ) + message( STATUS "Could not find NASM. Disabling assembly code." ) + set( NO_ASM ON ) + endif( NASM_PATH ) + endif( X64 ) + endif( UNIX AND X64 ) + + # I think the only reason there was a version requirement was because the + # executable name for Windows changed from 0.x to 2.0, right? This is + # how to do it in case I need to do something similar later. + + # execute_process( COMMAND ${NASM_PATH} -v + # OUTPUT_VARIABLE NASM_VER_STRING ) + # string( REGEX REPLACE ".*version ([0-9]+[.][0-9]+).*" "\\1" NASM_VER "${NASM_VER_STRING}" ) + # if( NOT NASM_VER LESS 2 ) + # message( SEND_ERROR "NASM version should be 2 or later. (Installed version is ${NASM_VER}.)" ) + # endif( NOT NASM_VER LESS 2 ) +endif( NOT NO_ASM ) + +if( NOT NO_ASM ) + # Valgrind support is meaningless without assembly code. + if( VALGRIND ) + add_definitions( -DVALGRIND_AWARE=1 ) + # If you're Valgrinding, you probably want to keep symbols around. + set( NO_STRIP ON ) + endif( VALGRIND ) + + # Tell CMake how to assemble our files + if( UNIX ) + set( ASM_OUTPUT_EXTENSION .o ) + if( X64 ) + set( ASM_FLAGS ) + set( ASM_SOURCE_EXTENSION .s ) + else( X64 ) + if( APPLE ) + set( ASM_FLAGS -fmacho -DM_TARGET_MACHO ) + else( APPLE ) + set( ASM_FLAGS -felf -DM_TARGET_LINUX ) + endif( APPLE ) + set( ASM_FLAGS "${ASM_FLAGS}" -i${CMAKE_CURRENT_SOURCE_DIR}/ ) + set( ASM_SOURCE_EXTENSION .asm ) + endif( X64 ) + else( UNIX ) + set( ASM_OUTPUT_EXTENSION .obj ) + set( ASM_SOURCE_EXTENSION .asm ) + if( X64 ) + set( ASM_FLAGS -f win64 -DWIN32 -DWIN64 ) + else( X64 ) + set( ASM_FLAGS -f win32 -DWIN32 -i${CMAKE_CURRENT_SOURCE_DIR}/ ) + endif( X64 ) + endif( UNIX ) + if( WIN32 ) + set( FIXRTEXT fixrtext ) + endif( WIN32 ) + message( STATUS "Selected assembler: ${ASSEMBLER}" ) + MACRO( ADD_ASM_FILE indir infile ) + set( ASM_OUTPUT_${infile} "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/zdoom.dir/${indir}/${infile}${ASM_OUTPUT_EXTENSION}" ) + if( WIN32 ) + set( FIXRTEXT_${infile} COMMAND ${FIXRTEXT} "${ASM_OUTPUT_${infile}}" ) + endif( WIN32 ) + add_custom_command( OUTPUT ${ASM_OUTPUT_${infile}} + COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/zdoom.dir/${indir} + COMMAND ${ASSEMBLER} ${ASM_FLAGS} -o"${ASM_OUTPUT_${infile}}" "${CMAKE_CURRENT_SOURCE_DIR}/${indir}/${infile}${ASM_SOURCE_EXTENSION}" + ${FIXRTEXT_${infile}} + DEPENDS ${indir}/${infile}.asm ${FIXRTEXT} ) + set( ASM_SOURCES ${ASM_SOURCES} "${ASM_OUTPUT_${infile}}" ) + ENDMACRO( ADD_ASM_FILE ) +endif( NOT NO_ASM ) + +# Decide on SSE setup + +set( SSE_MATTERS NO ) + +# SSE only matters on 32-bit targets. We check compiler flags to know if we can do it. +if( CMAKE_SIZEOF_VOID_P MATCHES "4" AND NOT CMAKE_OSX_ARCHITECTURES MATCHES ppc ) + CHECK_CXX_COMPILER_FLAG( "-msse2 -mfpmath=sse" CAN_DO_MFPMATH ) + CHECK_CXX_COMPILER_FLAG( -arch:SSE2 CAN_DO_ARCHSSE2 ) + if( CAN_DO_MFPMATH ) + set( SSE1_ENABLE "-msse -mfpmath=sse" ) + set( SSE2_ENABLE "-msse2 -mfpmath=sse" ) + set( SSE_MATTERS YES ) + elseif( CAN_DO_ARCHSSE2 ) + set( SSE1_ENABLE -arch:SSE ) + set( SSE2_ENABLE -arch:SSE2 ) + set( SSE_MATTERS YES ) + endif( CAN_DO_MFPMATH ) +endif( CMAKE_SIZEOF_VOID_P MATCHES "4" AND NOT CMAKE_OSX_ARCHITECTURES MATCHES ppc ) + +if( SSE_MATTERS ) + if( WIN32 ) + set( BACKPATCH 1 CACHE BOOL "Enable backpatching." ) + else( WIN32 ) + CHECK_FUNCTION_EXISTS(mprotect HAVE_MPROTECT) + if( HAVE_MPROTECT ) + set( BACKPATCH 1 CACHE BOOL "Enable backpatching." ) + else( HAVE_MPROTECT ) + set( BACKPATCH 0 ) + endif( HAVE_MPROTECT ) + endif( WIN32 ) + set( SSE 1 CACHE BOOL "Build SSE and SSE2 versions of key code." ) +else( SSE_MATTERS ) + set( BACKPATCH 0 ) +endif( SSE_MATTERS ) + +# Set up flags for GCC + +if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" ) + if( PROFILE ) + set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -pg" ) + set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -pg" ) + set( CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -pg" ) + set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -pg" ) + endif( PROFILE ) + + set( REL_CXX_FLAGS "-fno-rtti" ) + if( NOT PROFILE ) + set( REL_CXX_FLAGS "${REL_CXX_FLAGS} -fomit-frame-pointer" ) + endif( NOT PROFILE ) + set( CMAKE_CXX_FLAGS_RELEASE "${REL_CXX_FLAGS} ${CMAKE_CXX_FLAGS_RELEASE}" ) + set( CMAKE_CXX_FLAGS_MINSIZEREL "${REL_CXX_FLAGS} ${CMAKE_CXX_FLAGS_MINSIZEREL}" ) + set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${REL_CXX_FLAGS} ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}" ) + + set( CMAKE_CXX_FLAGS "-Wall -Wno-unused -Wextra -Wno-missing-field-initializers ${CMAKE_CXX_FLAGS}" ) + + # Remove extra warnings when using the official DirectX headers. + # Also, TDM-GCC 4.4.0 no longer accepts glibc-style printf formats as valid, + # which is a royal pain. The previous version I had been using was fine with them. + if( WIN32 ) + set( CMAKE_CXX_FLAGS "-Wno-unknown-pragmas -Wno-comment -Wno-format ${CMAKE_CXX_FLAGS}" ) + endif( WIN32 ) + + if( NOT NO_STRIP ) + set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} -s" ) + set (CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "${CMAKE_EXE_LINKER_FLAGS_MINSIZEREL} -s" ) + endif( NOT NO_STRIP ) +endif( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" ) + +# Check for functions that may or may not exist. + +CHECK_FUNCTION_EXISTS( filelength FILELENGTH_EXISTS ) +if( FILELENGTH_EXISTS ) + add_definitions( -DHAVE_FILELENGTH=1 ) +endif( FILELENGTH_EXISTS ) + +CHECK_FUNCTION_EXISTS( strupr STRUPR_EXISTS ) +if( NOT STRUPR_EXISTS ) + add_definitions( -DNEED_STRUPR=1 ) +endif( NOT STRUPR_EXISTS ) + +CHECK_FUNCTION_EXISTS( stricmp STRICMP_EXISTS ) +if( NOT STRICMP_EXISTS ) + add_definitions( -Dstricmp=strcasecmp ) +endif( NOT STRICMP_EXISTS ) + +CHECK_FUNCTION_EXISTS( strnicmp STRNICMP_EXISTS ) +if( NOT STRNICMP_EXISTS ) + add_definitions( -Dstrnicmp=strncasecmp ) +endif( NOT STRNICMP_EXISTS ) + +if( NOT MSVC ) + add_definitions( -D__forceinline=inline ) +endif( NOT MSVC ) + +if( UNIX ) + CHECK_LIBRARY_EXISTS( rt clock_gettime "" CLOCK_GETTIME_IN_RT ) + if( NOT CLOCK_GETTIME_IN_RT ) + CHECK_FUNCTION_EXISTS( clock_gettime CLOCK_GETTIME_EXISTS ) + if( NOT CLOCK_GETTIME_EXISTS ) + message( STATUS "Could not find clock_gettime. Timing statistics will not be available." ) + add_definitions( -DNO_CLOCK_GETTIME ) + endif( NOT CLOCK_GETTIME_EXISTS ) + else( NOT CLOCK_GETTIME_IN_RT ) + set( ZDOOM_LIBS ${ZDOOM_LIBS} rt ) + endif( NOT CLOCK_GETTIME_IN_RT ) +endif( UNIX ) + +CHECK_CXX_SOURCE_COMPILES( + "#include + int main() { va_list list1, list2; va_copy(list1, list2); return 0; }" + HAS_VA_COPY ) +if( NOT HAS_VA_COPY ) + CHECK_CXX_SOURCE_COMPILES( + "#include + int main() { va_list list1, list2; __va_copy(list1, list2); return 0; }" + HAS___VA_COPY ) + if( HAS___VA_COPY ) + add_definitions( -Dva_copy=__va_copy ) + else( HAS___VA_COPY ) + add_definitions( -DNO_VA_COPY ) + endif( HAS___VA_COPY ) +endif( NOT HAS_VA_COPY ) + +# Flags + +if( BACKPATCH ) + add_definitions( -DBACKPATCH ) +endif( BACKPATCH ) + +# Update gitinfo.h + +get_target_property( UPDATEREVISION_EXE updaterevision LOCATION ) + +add_custom_target( revision_check ALL + COMMAND ${UPDATEREVISION_EXE} src/gitinfo.h + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + DEPENDS updaterevision ) + +# Libraries ZDoom needs + +message( STATUS "Fluid synth libs: ${FLUIDSYNTH_LIBRARIES}" ) +set( ZDOOM_LIBS ${ZDOOM_LIBS} "${ZLIB_LIBRARIES}" "${JPEG_LIBRARIES}" "${BZIP2_LIBRARIES}" "${FMOD_LIBRARY}" ) +include_directories( "${ZLIB_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" ) + +if( FLUIDSYNTH_FOUND ) + if( NOT DYN_FLUIDSYNTH) + set( ZDOOM_LIBS ${ZDOOM_LIBS} "${FLUIDSYNTH_LIBRARIES}" ) + include_directories( "${FLUIDSYNTH_INCLUDE_DIR}" ) + endif( NOT DYN_FLUIDSYNTH ) +endif( FLUIDSYNTH_FOUND ) + +# Start defining source files for ZDoom + +if( WIN32 ) + set( SYSTEM_SOURCES_DIR win32 ) + set( SYSTEM_SOURCES + win32/eaxedit.cpp + win32/fb_d3d9.cpp + win32/fb_d3d9_wipe.cpp + win32/fb_ddraw.cpp + win32/hardware.cpp + win32/helperthread.cpp + win32/i_cd.cpp + win32/i_crash.cpp + win32/i_input.cpp + win32/i_keyboard.cpp + win32/i_mouse.cpp + win32/i_dijoy.cpp + win32/i_rawps2.cpp + win32/i_xinput.cpp + win32/i_main.cpp + win32/i_movie.cpp + win32/i_system.cpp + win32/st_start.cpp + win32/win32video.cpp ) + if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" ) + # CMake is not set up to compile and link rc files with GCC. :( + add_custom_command( OUTPUT zdoom-rc.o + COMMAND windres -o zdoom-rc.o -i ${CMAKE_CURRENT_SOURCE_DIR}/win32/zdoom.rc + DEPENDS win32/zdoom.rc ) + set( SYSTEM_SOURCES ${SYSTEM_SOURCES} zdoom-rc.o ) + else( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" ) + set( SYSTEM_SOURCES ${SYSTEM_SOURCES} win32/zdoom.rc ) + endif( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" ) +else( WIN32 ) + set( SYSTEM_SOURCES_DIR sdl ) + set( SYSTEM_SOURCES + sdl/crashcatcher.c + sdl/hardware.cpp + sdl/i_cd.cpp + sdl/i_input.cpp + sdl/i_joystick.cpp + sdl/i_main.cpp + sdl/i_movie.cpp + sdl/i_system.cpp + sdl/sdlvideo.cpp + sdl/st_start.cpp ) + if( APPLE ) + set( SYSTEM_SOURCES ${SYSTEM_SOURCES} sdl/SDLMain.m sdl/iwadpicker_cocoa.mm sdl/i_system_cocoa.mm ) + endif( APPLE ) +endif( WIN32 ) + +if( NO_ASM ) + add_definitions( -DNOASM ) +else( NO_ASM ) + if( X64 ) + ADD_ASM_FILE( asm_x86_64 tmap3 ) + else( X64 ) + ADD_ASM_FILE( asm_ia32 a ) + ADD_ASM_FILE( asm_ia32 misc ) + ADD_ASM_FILE( asm_ia32 tmap ) + ADD_ASM_FILE( asm_ia32 tmap2 ) + ADD_ASM_FILE( asm_ia32 tmap3 ) + endif( X64 ) +endif( NO_ASM ) + +get_target_property( LEMON_EXE lemon LOCATION ) +get_target_property( RE2C_EXE re2c LOCATION ) + +add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.c ${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.h + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/xlat/xlat_parser.y . + COMMAND ${LEMON_EXE} xlat_parser.y + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS lemon ${CMAKE_CURRENT_SOURCE_DIR}/xlat/xlat_parser.y ) + +add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h + COMMAND ${RE2C_EXE} --no-generation-date -s -o ${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h ${CMAKE_CURRENT_SOURCE_DIR}/sc_man_scanner.re + DEPENDS re2c ${CMAKE_CURRENT_SOURCE_DIR}/sc_man_scanner.re ) + +include_directories( ${CMAKE_CURRENT_BINARY_DIR} ) + +if( SSE_MATTERS ) + if( SSE ) + set( X86_SOURCES nodebuild_classify_sse2.cpp ) + set_source_files_properties( nodebuild_classify_sse2.cpp PROPERTIES COMPILE_FLAGS "${SSE2_ENABLE}" ) + else( SSE ) + add_definitions( -DDISABLE_SSE ) + endif( SSE ) +else( SSE_MATTERS ) + add_definitions( -DDISABLE_SSE ) + set( X86_SOURCES ) +endif( SSE_MATTERS ) + +if( DYN_FLUIDSYNTH ) + add_definitions( -DHAVE_FLUIDSYNTH -DDYN_FLUIDSYNTH ) +elseif( FLUIDSYNTH_FOUND ) + add_definitions( -DHAVE_FLUIDSYNTH ) +endif( DYN_FLUIDSYNTH ) + +# Project files should be aware of the header files. We can GLOB these since +# there's generally a new cpp for every header so this file will get changed +if( WIN32 ) + set( EXTRA_HEADER_DIRS win32/*.h ) +else( WIN32 ) + set( EXTRA_HEADER_DIRS sdl/*.h ) +endif( WIN32 ) +file( GLOB HEADER_FILES + ${EXTRA_HEADER_DIRS} + fragglescript/*.h + g_doom/*.h + g_heretic/*.h + g_hexen/*.h + g_raven/*.h + g_shared/*.h + g_strife/*.h + intermission/*.h + menu/*.h + oplsynth/*.h + r_data/*.h + resourcefiles/*.h + sfmt/*.h + sound/*.h + textures/*.h + thingdef/*.h + xlat/*.h + *.h +) + +add_executable( zdoom WIN32 + ${HEADER_FILES} + autostart.cpp + ${ASM_SOURCES} + ${SYSTEM_SOURCES} + ${X86_SOURCES} + x86.cpp + actorptrselect.cpp + am_map.cpp + b_bot.cpp + b_func.cpp + b_game.cpp + b_move.cpp + b_think.cpp + bbannouncer.cpp + c_bind.cpp + c_cmds.cpp + c_console.cpp + c_cvars.cpp + c_dispatch.cpp + c_expr.cpp + cmdlib.cpp + colormatcher.cpp + compatibility.cpp + configfile.cpp + ct_chat.cpp + d_dehacked.cpp + d_iwad.cpp + d_main.cpp + d_net.cpp + d_netinfo.cpp + d_protocol.cpp + decallib.cpp + dobject.cpp + dobjgc.cpp + dobjtype.cpp + doomdef.cpp + doomstat.cpp + dsectoreffect.cpp + dthinker.cpp + f_wipe.cpp + farchive.cpp + files.cpp + g_game.cpp + g_hub.cpp + g_level.cpp + g_mapinfo.cpp + g_skill.cpp + gameconfigfile.cpp + gi.cpp + gitinfo.cpp + hu_scores.cpp + i_net.cpp + info.cpp + keysections.cpp + lumpconfigfile.cpp + m_alloc.cpp + m_argv.cpp + m_bbox.cpp + m_cheat.cpp + m_joy.cpp + m_misc.cpp + m_png.cpp + m_random.cpp + memarena.cpp + md5.cpp + name.cpp + nodebuild.cpp + nodebuild_classify_nosse2.cpp + nodebuild_events.cpp + nodebuild_extract.cpp + nodebuild_gl.cpp + nodebuild_utility.cpp + p_3dfloors.cpp + p_3dmidtex.cpp + p_acs.cpp + p_buildmap.cpp + p_ceiling.cpp + p_conversation.cpp + p_doors.cpp + p_effect.cpp + p_enemy.cpp + p_floor.cpp + p_glnodes.cpp + p_interaction.cpp + p_lights.cpp + p_linkedsectors.cpp + p_lnspec.cpp + p_map.cpp + p_maputl.cpp + p_mobj.cpp + p_pillar.cpp + p_plats.cpp + p_pspr.cpp + p_saveg.cpp + p_sectors.cpp + p_setup.cpp + p_sight.cpp + p_slopes.cpp + p_spec.cpp + p_states.cpp + p_switch.cpp + p_teleport.cpp + p_terrain.cpp + p_things.cpp + p_tick.cpp + p_trace.cpp + p_udmf.cpp + p_usdf.cpp + p_user.cpp + p_writemap.cpp + p_xlat.cpp + parsecontext.cpp + po_man.cpp + r_swrenderer.cpp + r_utility.cpp + r_3dfloors.cpp + r_bsp.cpp + r_draw.cpp + r_drawt.cpp + r_main.cpp + r_plane.cpp + r_polymost.cpp + r_segs.cpp + r_sky.cpp + r_things.cpp + s_advsound.cpp + s_environment.cpp + s_playlist.cpp + s_sndseq.cpp + s_sound.cpp + sc_man.cpp + st_stuff.cpp + statistics.cpp + stats.cpp + stringtable.cpp + strnatcmp.c + tables.cpp + teaminfo.cpp + tempfiles.cpp + v_blend.cpp + v_collection.cpp + v_draw.cpp + v_font.cpp + v_palette.cpp + v_pfx.cpp + v_text.cpp + v_video.cpp + w_wad.cpp + wi_stuff.cpp + zstrformat.cpp + zstring.cpp + g_doom/a_doommisc.cpp + g_heretic/a_hereticmisc.cpp + g_hexen/a_hexenmisc.cpp + g_raven/a_artitele.cpp + g_raven/a_minotaur.cpp + g_strife/a_strifestuff.cpp + g_strife/strife_sbar.cpp + g_shared/a_action.cpp + g_shared/a_armor.cpp + g_shared/a_artifacts.cpp + g_shared/a_bridge.cpp + g_shared/a_camera.cpp + g_shared/a_debris.cpp + g_shared/a_decals.cpp + g_shared/a_fastprojectile.cpp + g_shared/a_flashfader.cpp + g_shared/a_fountain.cpp + g_shared/a_hatetarget.cpp + g_shared/a_keys.cpp + g_shared/a_lightning.cpp + g_shared/a_mapmarker.cpp + g_shared/a_morph.cpp + g_shared/a_movingcamera.cpp + g_shared/a_pickups.cpp + g_shared/a_puzzleitems.cpp + g_shared/a_quake.cpp + g_shared/a_randomspawner.cpp + g_shared/a_secrettrigger.cpp + g_shared/a_sectoraction.cpp + g_shared/a_setcolor.cpp + g_shared/a_skies.cpp + g_shared/a_soundenvironment.cpp + g_shared/a_soundsequence.cpp + g_shared/a_spark.cpp + g_shared/a_specialspot.cpp + g_shared/a_waterzone.cpp + g_shared/a_weaponpiece.cpp + g_shared/a_weapons.cpp + g_shared/hudmessages.cpp + g_shared/sbarinfo.cpp + g_shared/sbar_mugshot.cpp + g_shared/shared_hud.cpp + g_shared/shared_sbar.cpp + intermission/intermission.cpp + intermission/intermission_parse.cpp + menu/colorpickermenu.cpp + menu/joystickmenu.cpp + menu/listmenu.cpp + menu/loadsavemenu.cpp + menu/menu.cpp + menu/menudef.cpp + menu/menuinput.cpp + menu/messagebox.cpp + menu/optionmenu.cpp + menu/playerdisplay.cpp + menu/playermenu.cpp + menu/readthis.cpp + menu/videomenu.cpp + oplsynth/fmopl.cpp + oplsynth/mlopl.cpp + oplsynth/mlopl_io.cpp + oplsynth/music_opldumper_mididevice.cpp + oplsynth/music_opl_mididevice.cpp + oplsynth/opl_mus_player.cpp + oplsynth/dosbox/opl.cpp + oplsynth/OPL3.cpp + resourcefiles/ancientzip.cpp + resourcefiles/file_7z.cpp + resourcefiles/file_grp.cpp + resourcefiles/file_lump.cpp + resourcefiles/file_rff.cpp + resourcefiles/file_wad.cpp + resourcefiles/file_zip.cpp + resourcefiles/file_pak.cpp + resourcefiles/file_directory.cpp + resourcefiles/resourcefile.cpp + sfmt/SFMT.cpp + sound/fmodsound.cpp + sound/i_music.cpp + sound/i_sound.cpp + sound/music_cd.cpp + sound/music_dumb.cpp + sound/music_gme.cpp + sound/music_mus_midiout.cpp + sound/music_smf_midiout.cpp + sound/music_hmi_midiout.cpp + sound/music_xmi_midiout.cpp + sound/music_midistream.cpp + sound/music_midi_base.cpp + sound/music_midi_timidity.cpp + sound/music_mus_opl.cpp + sound/music_stream.cpp + sound/music_fluidsynth_mididevice.cpp + sound/music_softsynth_mididevice.cpp + sound/music_timidity_mididevice.cpp + sound/music_win_mididevice.cpp + ${OAL_SOURCES} + sound/music_pseudo_mididevice.cpp + textures/animations.cpp + textures/anim_switches.cpp + textures/automaptexture.cpp + textures/bitmap.cpp + textures/buildtexture.cpp + textures/canvastexture.cpp + textures/ddstexture.cpp + textures/flattexture.cpp + textures/imgztexture.cpp + textures/jpegtexture.cpp + textures/multipatchtexture.cpp + textures/patchtexture.cpp + textures/pcxtexture.cpp + textures/pngtexture.cpp + textures/rawpagetexture.cpp + textures/emptytexture.cpp + textures/texture.cpp + textures/texturemanager.cpp + textures/tgatexture.cpp + textures/warptexture.cpp + thingdef/olddecorations.cpp + thingdef/thingdef.cpp + thingdef/thingdef_codeptr.cpp + thingdef/thingdef_data.cpp + thingdef/thingdef_exp.cpp + thingdef/thingdef_expression.cpp + thingdef/thingdef_function.cpp + thingdef/thingdef_parse.cpp + thingdef/thingdef_properties.cpp + thingdef/thingdef_states.cpp + timidity/common.cpp + timidity/instrum.cpp + timidity/instrum_dls.cpp + timidity/instrum_font.cpp + timidity/instrum_sf2.cpp + timidity/mix.cpp + timidity/playmidi.cpp + timidity/resample.cpp + timidity/timidity.cpp + xlat/parse_xlat.cpp + fragglescript/t_fspic.cpp + fragglescript/t_func.cpp + fragglescript/t_load.cpp + fragglescript/t_oper.cpp + fragglescript/t_parse.cpp + fragglescript/t_prepro.cpp + fragglescript/t_script.cpp + fragglescript/t_spec.cpp + fragglescript/t_variable.cpp + fragglescript/t_cmd.cpp + r_data/colormaps.cpp + r_data/sprites.cpp + r_data/voxels.cpp + r_data/renderstyle.cpp + r_data/r_interpolate.cpp + r_data/r_translate.cpp + autozend.cpp +) + +set_source_files_properties( xlat/parse_xlat.cpp PROPERTIES OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.c" ) +set_source_files_properties( sc_man.cpp PROPERTIES OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h" ) + +if(${CMAKE_SYSTEM_NAME} STREQUAL "SunOS") + # [BL] Solaris requires these to be explicitly linked. + set( ZDOOM_LIBS ${ZDOOM_LIBS} nsl socket) +endif(${CMAKE_SYSTEM_NAME} STREQUAL "SunOS") + +target_link_libraries( zdoom ${ZDOOM_LIBS} gme gdtoa dumb lzma ) +include_directories( . + g_doom + g_heretic + g_hexen + g_raven + g_strife + g_shared + oplsynth + sound + textures + thingdef + timidity + xlat + ../game-music-emu/gme + ../gdtoa + ../dumb/include + ${CMAKE_BINARY_DIR}/gdtoa + ${SYSTEM_SOURCES_DIR} ) + +add_dependencies( zdoom revision_check ) + +# RUNTIME_OUTPUT_DIRECTORY does not exist in CMake 2.4. +# Linux distributions are slow to adopt 2.6. :( +set_target_properties( zdoom PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${ZDOOM_OUTPUT_DIR} ) +set_target_properties( zdoom PROPERTIES OUTPUT_NAME ${ZDOOM_EXE_NAME} ) + +if( NOT WIN32 ) + FILE( WRITE ${CMAKE_CURRENT_BINARY_DIR}/link-make "if [ ! -e ${ZDOOM_OUTPUT_DIR}/${ZDOOM_EXE_NAME} ]; then ln -sf ${CMAKE_CURRENT_BINARY_DIR}/${ZDOOM_EXE_NAME} ${ZDOOM_OUTPUT_DIR}/${ZDOOM_EXE_NAME}; fi" ) + add_custom_command( TARGET zdoom POST_BUILD + COMMAND chmod +x ${CMAKE_CURRENT_BINARY_DIR}/link-make + COMMAND /bin/sh -c ${CMAKE_CURRENT_BINARY_DIR}/link-make ) +endif( NOT WIN32 ) +if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" ) + # GCC misoptimizes this file + set_source_files_properties( oplsynth/fmopl.cpp PROPERTIES COMPILE_FLAGS "-fno-tree-dominator-opts -fno-tree-fre" ) + + # Need to enable intrinsics for this file. + if( SSE_MATTERS ) + set_source_files_properties( x86.cpp PROPERTIES COMPILE_FLAGS "-msse2 -mmmx" ) + endif( SSE_MATTERS ) +endif( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" ) + +if( MSVC ) + set_target_properties(zdoom PROPERTIES LINK_FLAGS "/MANIFEST:NO") +endif( MSVC ) From 34c9a4743597f50c474de82ac41778ca53b6f9b8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 17 Jun 2014 23:11:19 -0700 Subject: [PATCH 16/88] Fix some typos --- src/sound/oalsdlsound.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sound/oalsdlsound.cpp b/src/sound/oalsdlsound.cpp index 6ef7d9118a..7aa8574528 100644 --- a/src/sound/oalsdlsound.cpp +++ b/src/sound/oalsdlsound.cpp @@ -326,7 +326,7 @@ void *OpenALSoundStream::GetData(size_t bytes) for(size_t i = 0;i < count;i++) { short smp = *samples; - *(samples++) = ((smp>>8)&0x00FF) | ((smp<<8)*0xFF00); + *(samples++) = ((smp>>8)&0x00FF) | ((smp<<8)&0xFF00); } } if(NeedS8Conv) @@ -410,7 +410,7 @@ bool OpenALSoundStream::InitSample() Format = AL_FORMAT_MONO16; else if(Sample->actual.channels == 2) Format = AL_FORMAT_STEREO16; - smpsize = 1 * Sample->actual.channels; + smpsize = 2 * Sample->actual.channels; } else if(Sample->actual.format == AUDIO_U16LSB || Sample->actual.format == AUDIO_U16MSB) { @@ -420,7 +420,7 @@ bool OpenALSoundStream::InitSample() Format = AL_FORMAT_MONO16; else if(Sample->actual.channels == 2) Format = AL_FORMAT_STEREO16; - smpsize = 1 * Sample->actual.channels; + smpsize = 2 * Sample->actual.channels; } if(Format == AL_NONE) @@ -570,7 +570,7 @@ void* Decoder::GetData(ALsizei *size) for(size_t i = 0;i < count;i++) { short smp = *samples; - *(samples++) = ((smp>>8)&0x00FF) | ((smp<<8)*0xFF00); + *(samples++) = ((smp>>8)&0x00FF) | ((smp<<8)&0xFF00); } } From b94a2949e5f63909597d999104dbfe6d7a440b26 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 18 Jun 2014 23:41:45 -0700 Subject: [PATCH 17/88] Don't use air absorption for being underwater --- src/sound/oalsound.cpp | 72 +++++++++++++++------------------------ src/sound/oalsound.h | 4 +-- wadsrc/static/menudef.txt | 3 -- 3 files changed, 30 insertions(+), 49 deletions(-) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 9fe7980796..475b5a113a 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -56,13 +56,7 @@ CVAR (String, snd_aldevice, "Default", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (Bool, snd_efx, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -CUSTOM_CVAR (Float, snd_waterabsorption, 10.0f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -{ - if(*self < 0.0f) - self = 0.0f; - else if(*self > 10.0f) - self = 10.0f; -} + void I_BuildALDeviceList(FOptionValues *opt) { @@ -687,7 +681,7 @@ OpenALSoundRenderer::OpenALSoundRenderer() } DPrintf(" Allocated "TEXTCOLOR_BLUE"%u"TEXTCOLOR_NORMAL" sources\n", Sources.size()); - LastWaterAbsorb = 0.0f; + WasInWater = false; if(*snd_efx && alcIsExtensionPresent(Device, "ALC_EXT_EFX")) { // EFX function pointers @@ -1095,18 +1089,16 @@ FISoundChannel *OpenALSoundRenderer::StartSound(SoundHandle sfx, float vol, int { alSourcei(source, AL_DIRECT_FILTER, EnvFilters[0]); alSource3i(source, AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); - alSourcef(source, AL_AIR_ABSORPTION_FACTOR, LastWaterAbsorb); } else { alSourcei(source, AL_DIRECT_FILTER, AL_FILTER_NULL); alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL); - alSourcef(source, AL_AIR_ABSORPTION_FACTOR, 0.f); } alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, 0.f); alSourcef(source, AL_PITCH, PITCH(pitch)); } - else if(LastWaterAbsorb > 0.f && !(chanflags&SNDF_NOREVERB)) + else if(WasInWater && !(chanflags&SNDF_NOREVERB)) alSourcef(source, AL_PITCH, PITCH(pitch)*PITCH_MULT); else alSourcef(source, AL_PITCH, PITCH(pitch)); @@ -1239,18 +1231,16 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener { alSourcei(source, AL_DIRECT_FILTER, EnvFilters[0]); alSource3i(source, AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); - alSourcef(source, AL_AIR_ABSORPTION_FACTOR, LastWaterAbsorb); } else { alSourcei(source, AL_DIRECT_FILTER, AL_FILTER_NULL); alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL); - alSourcef(source, AL_AIR_ABSORPTION_FACTOR, 0.f); } alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, rolloffFactor); alSourcef(source, AL_PITCH, PITCH(pitch)); } - else if(LastWaterAbsorb > 0.f && !(chanflags&SNDF_NOREVERB)) + else if(WasInWater && !(chanflags&SNDF_NOREVERB)) alSourcef(source, AL_PITCH, PITCH(pitch)*PITCH_MULT); else alSourcef(source, AL_PITCH, PITCH(pitch)); @@ -1486,14 +1476,13 @@ void OpenALSoundRenderer::UpdateListener(SoundListener *listener) const_cast(env)->Modified = false; } - // NOTE: Moving into and out of water (and changing water absorption) will - // undo pitch variations on sounds if either snd_waterreverb or EFX are - // disabled. + // NOTE: Moving into and out of water will undo pitch variations on sounds + // if either snd_waterreverb or EFX are disabled. if(listener->underwater || env->SoftwareWater) { - if(LastWaterAbsorb != *snd_waterabsorption) + if(!WasInWater) { - LastWaterAbsorb = *snd_waterabsorption; + WasInWater = true; if(EnvSlot != 0 && *snd_waterreverb) { @@ -1503,15 +1492,14 @@ void OpenALSoundRenderer::UpdateListener(SoundListener *listener) env = env->Next; LoadReverb(env ? env : DefaultEnvironments[0]); - alFilterf(EnvFilters[0], AL_LOWPASS_GAIN, 0.25f); - alFilterf(EnvFilters[0], AL_LOWPASS_GAINHF, 0.75f); + alFilterf(EnvFilters[0], AL_LOWPASS_GAIN, 0.1f); + alFilterf(EnvFilters[0], AL_LOWPASS_GAINHF, 1.f); alFilterf(EnvFilters[1], AL_LOWPASS_GAIN, 1.f); alFilterf(EnvFilters[1], AL_LOWPASS_GAINHF, 1.f); // Apply the updated filters on the sources foreach(ALuint, i, ReverbSfx) { - alSourcef(*i, AL_AIR_ABSORPTION_FACTOR, LastWaterAbsorb); alSourcei(*i, AL_DIRECT_FILTER, EnvFilters[0]); alSource3i(*i, AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); } @@ -1524,34 +1512,30 @@ void OpenALSoundRenderer::UpdateListener(SoundListener *listener) getALError(); } } - else + else if(WasInWater) { - if(LastWaterAbsorb > 0.f) + WasInWater = false; + + if(EnvSlot != 0) { - LastWaterAbsorb = 0.f; + LoadReverb(env); - if(EnvSlot != 0) + alFilterf(EnvFilters[0], AL_LOWPASS_GAIN, 1.f); + alFilterf(EnvFilters[0], AL_LOWPASS_GAINHF, 1.f); + alFilterf(EnvFilters[1], AL_LOWPASS_GAIN, 1.f); + alFilterf(EnvFilters[1], AL_LOWPASS_GAINHF, 1.f); + foreach(ALuint, i, ReverbSfx) { - LoadReverb(env); - - alFilterf(EnvFilters[0], AL_LOWPASS_GAIN, 1.f); - alFilterf(EnvFilters[0], AL_LOWPASS_GAINHF, 1.f); - alFilterf(EnvFilters[1], AL_LOWPASS_GAIN, 1.f); - alFilterf(EnvFilters[1], AL_LOWPASS_GAINHF, 1.f); - foreach(ALuint, i, ReverbSfx) - { - alSourcef(*i, AL_AIR_ABSORPTION_FACTOR, 0.f); - alSourcei(*i, AL_DIRECT_FILTER, EnvFilters[0]); - alSource3i(*i, AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); - } + alSourcei(*i, AL_DIRECT_FILTER, EnvFilters[0]); + alSource3i(*i, AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); } - else - { - foreach(ALuint, i, ReverbSfx) - alSourcef(*i, AL_PITCH, 1.f); - } - getALError(); } + else + { + foreach(ALuint, i, ReverbSfx) + alSourcef(*i, AL_PITCH, 1.f); + } + getALError(); } } diff --git a/src/sound/oalsound.h b/src/sound/oalsound.h index 54eb7a599e..5b0345f568 100644 --- a/src/sound/oalsound.h +++ b/src/sound/oalsound.h @@ -191,10 +191,10 @@ private: typedef std::map EffectMap; ALuint EnvSlot; + ALuint EnvFilters[2]; EffectMap EnvEffects; - ALuint EnvFilters[2]; - float LastWaterAbsorb; + bool WasInWater; std::vector Streams; friend class OpenALSoundStream; diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index cefb19febd..dd6ec08d3d 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -1448,9 +1448,6 @@ OptionMenu OpenALSoundItems Title "OPENAL OPTIONS" Option "Playback device", "snd_aldevice", "ALDevices" Option "Enable EFX", "snd_efx", "OnOff" - StaticText " " - StaticText "Requires EFX", 1 - Slider "Underwater absorption", "snd_waterabsorption", 0.0, 10.0, 0.5 } From 5370a1cb46fb795f94601924be8f06a5e7e2de3e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 19 Jun 2014 01:00:46 -0700 Subject: [PATCH 18/88] Add a SoundDecoder base class and a stub method to create one --- src/sound/i_sound.cpp | 23 +++++++++++++++++++++++ src/sound/i_sound.h | 5 +++++ src/sound/i_soundinternal.h | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+) diff --git a/src/sound/i_sound.cpp b/src/sound/i_sound.cpp index c2478ffef4..f657182ef2 100644 --- a/src/sound/i_sound.cpp +++ b/src/sound/i_sound.cpp @@ -520,3 +520,26 @@ SoundHandle SoundRenderer::LoadSoundVoc(BYTE *sfxdata, int length) return retval; } + +SoundDecoder *SoundRenderer::CreateDecoder(BYTE *sfxdata, int length) +{ + return NULL; +} + + +// Default readAll implementation, for decoders that can't do anything better +std::vector SoundDecoder::readAll() +{ + std::vector output; + size_t total = 0; + size_t got; + + output.resize(total+32768); + while((got=read(&output[total], output.size()-total)) > 0) + { + total += got; + output.resize(total*2); + } + output.resize(total); + return output; +} diff --git a/src/sound/i_sound.h b/src/sound/i_sound.h index adce8796b5..fa419cf023 100644 --- a/src/sound/i_sound.h +++ b/src/sound/i_sound.h @@ -82,6 +82,8 @@ public: typedef bool (*SoundStreamCallback)(SoundStream *stream, void *buff, int len, void *userdata); +struct SoundDecoder; + class SoundRenderer { public: @@ -150,6 +152,9 @@ public: virtual short *DecodeSample(int outlen, const void *coded, int sizebytes, ECodecType type); virtual void DrawWaveDebug(int mode); + +protected: + virtual SoundDecoder *CreateDecoder(BYTE *sfxdata, int length); }; extern SoundRenderer *GSnd; diff --git a/src/sound/i_soundinternal.h b/src/sound/i_soundinternal.h index b0f42913a3..c0282ee6be 100644 --- a/src/sound/i_soundinternal.h +++ b/src/sound/i_soundinternal.h @@ -1,6 +1,8 @@ #ifndef __SNDINT_H #define __SNDINT_H +#include + #include "basictypes.h" // For convenience, this structure matches FMOD_REVERB_PROPERTIES. @@ -101,5 +103,39 @@ struct FISoundChannel }; +enum SampleType +{ + SampleType_UInt8, + SampleType_Int16, + SampleType_Float32 +}; +enum ChannelConfig +{ + ChannelConfig_Mono, + ChannelConfig_Stereo, + ChannelConfig_Quad, + ChannelConfig_5point1, + ChannelConfig_7point1 +}; + +struct SoundDecoder +{ + virtual bool open(const char *data, size_t length) = 0; + + virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) = 0; + + virtual size_t read(char *buffer, size_t bytes) = 0; + virtual std::vector readAll(); + virtual bool seek(size_t ms_offset) = 0; + virtual size_t getSampleOffset() = 0; + + SoundDecoder() { } + virtual ~SoundDecoder() { } + +private: + // Make non-copyable + SoundDecoder(const SoundDecoder &rhs); + SoundDecoder& operator=(const SoundDecoder &rhs); +}; #endif From b38589e2dc404fc22897fab5d87ebdccee96a67d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 19 Jun 2014 04:13:42 -0700 Subject: [PATCH 19/88] Implement and use a libsndfile decoder --- FindSndFile.cmake | 29 ++++ src/CMakeLists.txt | 13 ++ src/sound/audio_sndfile_decoder.cpp | 243 ++++++++++++++++++++++++++++ src/sound/i_sound.cpp | 27 +++- src/sound/i_sound.h | 3 +- src/sound/i_soundinternal.h | 63 +++++++- src/sound/oalsound.cpp | 178 ++++++++++++++++---- 7 files changed, 514 insertions(+), 42 deletions(-) create mode 100644 FindSndFile.cmake create mode 100644 src/sound/audio_sndfile_decoder.cpp diff --git a/FindSndFile.cmake b/FindSndFile.cmake new file mode 100644 index 0000000000..ab66fc5c2d --- /dev/null +++ b/FindSndFile.cmake @@ -0,0 +1,29 @@ +# - Try to find SndFile +# Once done this will define +# +# SNDFILE_FOUND - system has SndFile +# SNDFILE_INCLUDE_DIRS - the SndFile include directory +# SNDFILE_LIBRARIES - Link these to use SndFile +# +# Copyright © 2006 Wengo +# Copyright © 2009 Guillaume Martres +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +find_path(SNDFILE_INCLUDE_DIR NAMES sndfile.h) + +find_library(SNDFILE_LIBRARY NAMES sndfile sndfile-1) + +set(SNDFILE_INCLUDE_DIRS ${SNDFILE_INCLUDE_DIR}) +set(SNDFILE_LIBRARIES ${SNDFILE_LIBRARY}) + +INCLUDE(FindPackageHandleStandardArgs) +# handle the QUIETLY and REQUIRED arguments and set SNDFILE_FOUND to TRUE if +# all listed variables are TRUE +FIND_PACKAGE_HANDLE_STANDARD_ARGS(SndFile DEFAULT_MSG SNDFILE_LIBRARY SNDFILE_INCLUDE_DIR) + +# show the SNDFILE_INCLUDE_DIRS and SNDFILE_LIBRARIES variables only in the advanced view +mark_as_advanced(SNDFILE_INCLUDE_DIRS SNDFILE_LIBRARIES) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2a74d865e9..3fa9a0ee2f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -306,6 +306,10 @@ if( NO_OPENAL ) add_definitions( -DNO_OPENAL=1 ) endif( NO_OPENAL ) +# Search for libSndFile + +find_package( SndFile ) + # Search for FluidSynth find_package( FluidSynth ) @@ -556,6 +560,11 @@ message( STATUS "Fluid synth libs: ${FLUIDSYNTH_LIBRARIES}" ) set( ZDOOM_LIBS ${ZDOOM_LIBS} "${ZLIB_LIBRARIES}" "${JPEG_LIBRARIES}" "${BZIP2_LIBRARIES}" "${GME_LIBRARIES}" ) include_directories( "${ZLIB_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" "${GME_INCLUDE_DIR}" ) +if( SNDFILE_FOUND ) + set( ZDOOM_LIBS ${ZDOOM_LIBS} "${SNDFILE_LIBRARIES}" ) + include_directories( "${SNDFILE_INCLUDE_DIRS}" ) +endif( SNDFILE_FOUND ) + if( NOT DYN_FLUIDSYNTH) if( FLUIDSYNTH_FOUND ) set( ZDOOM_LIBS ${ZDOOM_LIBS} "${FLUIDSYNTH_LIBRARIES}" ) @@ -670,6 +679,9 @@ else( SSE_MATTERS ) set( X86_SOURCES ) endif( SSE_MATTERS ) +if( SNDFILE_FOUND ) + add_definitions( -DHAVE_SNDFILE ) +endif( SNDFILE_FOUND ) if( DYN_FLUIDSYNTH ) add_definitions( -DHAVE_FLUIDSYNTH -DDYN_FLUIDSYNTH ) elseif( FLUIDSYNTH_FOUND ) @@ -1033,6 +1045,7 @@ add_executable( zdoom WIN32 resourcefiles/file_directory.cpp resourcefiles/resourcefile.cpp sfmt/SFMT.cpp + sound/audio_sndfile_decoder.cpp sound/fmodsound.cpp sound/i_music.cpp sound/i_sound.cpp diff --git a/src/sound/audio_sndfile_decoder.cpp b/src/sound/audio_sndfile_decoder.cpp new file mode 100644 index 0000000000..dfb49b08c9 --- /dev/null +++ b/src/sound/audio_sndfile_decoder.cpp @@ -0,0 +1,243 @@ +#include "i_soundinternal.h" + +#ifdef HAVE_SNDFILE +sf_count_t SndFileDecoder::file_get_filelen(void *user_data) +{ + SndFileDecoder *self = reinterpret_cast(user_data); + return self->FileLength; +} + +sf_count_t SndFileDecoder::file_seek(sf_count_t offset, int whence, void *user_data) +{ + SndFileDecoder *self = reinterpret_cast(user_data); + + long cur = ftell(self->File); + if(cur < 0 || (unsigned long)cur < self->FileLength) + return -1; + + switch(whence) + { + case SEEK_SET: + if(offset < 0 || offset > (sf_count_t)self->FileLength) + return -1; + cur = offset; + break; + + case SEEK_CUR: + cur -= self->FileOffset; + if((offset > 0 && (sf_count_t)(self->FileLength-cur) < offset) || + (offset < 0 && (sf_count_t)cur < -offset)) + return -1; + cur += offset; + break; + + case SEEK_END: + if(offset > 0 || -offset > (sf_count_t)self->FileLength) + return -1; + cur = self->FileLength + offset; + break; + + default: + return -1; + } + + if(fseek(self->File, cur + self->FileOffset, SEEK_SET) != 0) + return -1; + return cur; +} + +sf_count_t SndFileDecoder::file_read(void *ptr, sf_count_t count, void *user_data) +{ + SndFileDecoder *self = reinterpret_cast(user_data); + + long cur = ftell(self->File); + if(cur < 0 || (unsigned long)cur < self->FileLength) + return -1; + + cur -= self->FileOffset; + if(count > (sf_count_t)(self->FileLength-cur)) + count = self->FileLength-cur; + + return fread(ptr, 1, count, self->File); +} + +sf_count_t SndFileDecoder::file_write(const void *ptr, sf_count_t count, void *user_data) +{ + return -1; +} + +sf_count_t SndFileDecoder::file_tell(void *user_data) +{ + SndFileDecoder *self = reinterpret_cast(user_data); + + long cur = ftell(self->File); + if(cur < 0 || (unsigned long)cur < self->FileLength) + return -1; + return cur - self->FileOffset; +} + + +sf_count_t SndFileDecoder::mem_get_filelen(void *user_data) +{ + SndFileDecoder *self = reinterpret_cast(user_data); + return self->MemLength; +} + +sf_count_t SndFileDecoder::mem_seek(sf_count_t offset, int whence, void *user_data) +{ + SndFileDecoder *self = reinterpret_cast(user_data); + + switch(whence) + { + case SEEK_SET: + if(offset < 0 || offset > (sf_count_t)self->MemLength) + return -1; + self->MemPos = offset; + break; + + case SEEK_CUR: + if((offset > 0 && (sf_count_t)(self->MemLength-self->MemPos) < offset) || + (offset < 0 && (sf_count_t)self->MemPos < -offset)) + return -1; + self->MemPos += offset; + break; + + case SEEK_END: + if(offset > 0 || -offset > (sf_count_t)self->MemLength) + return -1; + self->MemPos = self->MemLength + offset; + break; + + default: + return -1; + } + + return self->MemPos; +} + +sf_count_t SndFileDecoder::mem_read(void *ptr, sf_count_t count, void *user_data) +{ + SndFileDecoder *self = reinterpret_cast(user_data); + + if(count > (sf_count_t)(self->MemLength-self->MemPos)) + count = self->MemLength-self->MemPos; + + memcpy(ptr, self->MemData+self->MemPos, count); + self->MemPos += count; + + return count; +} + +sf_count_t SndFileDecoder::mem_write(const void *ptr, sf_count_t count, void *user_data) +{ + return -1; +} + +sf_count_t SndFileDecoder::mem_tell(void *user_data) +{ + SndFileDecoder *self = reinterpret_cast(user_data); + return self->MemPos; +} + + +SndFileDecoder::~SndFileDecoder() +{ + if(SndFile) + sf_close(SndFile); + SndFile = 0; +} + +bool SndFileDecoder::open(const char *data, size_t length) +{ + SF_VIRTUAL_IO sfio = { mem_get_filelen, mem_seek, mem_read, mem_write, mem_tell }; + + MemData = data; + MemPos = 0; + MemLength = length; + SndFile = sf_open_virtual(&sfio, SFM_READ, &SndInfo, this); + if(SndFile) + { + if(SndInfo.channels != 1 && SndInfo.channels != 2) + { + sf_close(SndFile); + SndFile = 0; + } + } + + return SndFile != 0; +} + +bool SndFileDecoder::open(const char *fname, size_t offset, size_t length) +{ + SF_VIRTUAL_IO sfio = { mem_get_filelen, mem_seek, mem_read, mem_write, mem_tell }; + + FileOffset = offset; + FileLength = length; + File = fopen(fname, "rb"); + if(File) + { + if(fseek(File, offset, SEEK_SET) == 0) + { + SndFile = sf_open_virtual(&sfio, SFM_READ, &SndInfo, this); + if(SndFile) + { + if(SndInfo.channels == 1 || SndInfo.channels == 2) + return true; + + sf_close(SndFile); + SndFile = 0; + } + } + fclose(File); + } + + return false; +} + +void SndFileDecoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) +{ + *samplerate = SndInfo.samplerate; + + if(SndInfo.channels == 2) + *chans = ChannelConfig_Stereo; + else + *chans = ChannelConfig_Mono; + + *type = SampleType_Int16; +} + +size_t SndFileDecoder::read(char *buffer, size_t bytes) +{ + int framesize = 2 * SndInfo.channels; + return sf_readf_short(SndFile, (short*)buffer, bytes/framesize) * framesize; +} + +std::vector SndFileDecoder::readAll() +{ + if(SndInfo.frames <= 0) + return SoundDecoder::readAll(); + + int framesize = 2 * SndInfo.channels; + std::vector output; + + output.resize(SndInfo.frames * framesize); + size_t got = read(&output[0], output.size()); + output.resize(got); + + return output; +} + +bool SndFileDecoder::seek(size_t ms_offset) +{ + size_t smp_offset = (size_t)((double)ms_offset / 1000. * SndInfo.samplerate); + if(sf_seek(SndFile, smp_offset, SEEK_SET) < 0) + return false; + return true; +} + +size_t SndFileDecoder::getSampleOffset() +{ + return sf_seek(SndFile, 0, SEEK_CUR); +} + +#endif diff --git a/src/sound/i_sound.cpp b/src/sound/i_sound.cpp index f657182ef2..da9cb0e66f 100644 --- a/src/sound/i_sound.cpp +++ b/src/sound/i_sound.cpp @@ -521,9 +521,32 @@ SoundHandle SoundRenderer::LoadSoundVoc(BYTE *sfxdata, int length) } -SoundDecoder *SoundRenderer::CreateDecoder(BYTE *sfxdata, int length) +SoundDecoder *SoundRenderer::CreateDecoder(const BYTE *sfxdata, int length) { - return NULL; + SoundDecoder *decoder = NULL; +#ifdef HAVE_SNDFILE + decoder = new SndFileDecoder; + if(!decoder->open((const char*)sfxdata, length)) + { + delete decoder; + decoder = NULL; + } +#endif + return decoder; +} + +SoundDecoder* SoundRenderer::CreateDecoder(const char *fname, int offset, int length) +{ + SoundDecoder *decoder = NULL; +#ifdef HAVE_SNDFILE + decoder = new SndFileDecoder; + if(!decoder->open(fname, offset, length)) + { + delete decoder; + decoder = NULL; + } +#endif + return decoder; } diff --git a/src/sound/i_sound.h b/src/sound/i_sound.h index fa419cf023..b82ea85aac 100644 --- a/src/sound/i_sound.h +++ b/src/sound/i_sound.h @@ -154,7 +154,8 @@ public: virtual void DrawWaveDebug(int mode); protected: - virtual SoundDecoder *CreateDecoder(BYTE *sfxdata, int length); + virtual SoundDecoder *CreateDecoder(const BYTE *sfxdata, int length); + virtual SoundDecoder *CreateDecoder(const char *fname, int offset, int length); }; extern SoundRenderer *GSnd; diff --git a/src/sound/i_soundinternal.h b/src/sound/i_soundinternal.h index c0282ee6be..26a42bc643 100644 --- a/src/sound/i_soundinternal.h +++ b/src/sound/i_soundinternal.h @@ -2,8 +2,10 @@ #define __SNDINT_H #include +#include #include "basictypes.h" +#include "vectors.h" // For convenience, this structure matches FMOD_REVERB_PROPERTIES. // Since I can't very well #include system-specific stuff in the @@ -106,22 +108,16 @@ struct FISoundChannel enum SampleType { SampleType_UInt8, - SampleType_Int16, - SampleType_Float32 + SampleType_Int16 }; enum ChannelConfig { ChannelConfig_Mono, - ChannelConfig_Stereo, - ChannelConfig_Quad, - ChannelConfig_5point1, - ChannelConfig_7point1 + ChannelConfig_Stereo }; struct SoundDecoder { - virtual bool open(const char *data, size_t length) = 0; - virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) = 0; virtual size_t read(char *buffer, size_t bytes) = 0; @@ -132,10 +128,61 @@ struct SoundDecoder SoundDecoder() { } virtual ~SoundDecoder() { } +protected: + virtual bool open(const char *data, size_t length) = 0; + virtual bool open(const char *fname, size_t offset, size_t length) = 0; + friend class SoundRenderer; + private: // Make non-copyable SoundDecoder(const SoundDecoder &rhs); SoundDecoder& operator=(const SoundDecoder &rhs); }; +#ifdef HAVE_SNDFILE +#include "sndfile.h" +struct SndFileDecoder : public SoundDecoder +{ + virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type); + + virtual size_t read(char *buffer, size_t bytes); + virtual std::vector readAll(); + virtual bool seek(size_t ms_offset); + virtual size_t getSampleOffset(); + + SndFileDecoder() : SndFile(0) { } + virtual ~SndFileDecoder(); + +protected: + virtual bool open(const char *data, size_t length); + virtual bool open(const char *fname, size_t offset, size_t length); + +private: + SNDFILE *SndFile; + SF_INFO SndInfo; + + FILE *File; + size_t FileLength; + size_t FileOffset; + static sf_count_t file_get_filelen(void *user_data); + static sf_count_t file_seek(sf_count_t offset, int whence, void *user_data); + static sf_count_t file_read(void *ptr, sf_count_t count, void *user_data); + static sf_count_t file_write(const void *ptr, sf_count_t count, void *user_data); + static sf_count_t file_tell(void *user_data); + + const char *MemData; + size_t MemLength; + size_t MemPos; + static sf_count_t mem_get_filelen(void *user_data); + static sf_count_t mem_seek(sf_count_t offset, int whence, void *user_data); + static sf_count_t mem_read(void *ptr, sf_count_t count, void *user_data); + static sf_count_t mem_write(const void *ptr, sf_count_t count, void *user_data); + static sf_count_t mem_tell(void *user_data); + + // Make non-copyable + SndFileDecoder(const SndFileDecoder &rhs); + SndFileDecoder& operator=(const SndFileDecoder &rhs); +}; +#endif + #endif diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 475b5a113a..37ad877d38 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -212,6 +212,28 @@ class OpenALCallbackStream : public SoundStream ALuint Source; bool Playing; + bool Looping; + ALfloat Volume; + + + std::vector DecoderData; + std::auto_ptr Decoder; + static bool DecoderCallback(SoundStream *_sstream, void *ptr, int length, void *user) + { + OpenALCallbackStream *self = static_cast(_sstream); + if(length < 0) return false; + + size_t got = self->Decoder->read((char*)ptr, length); + if(got < (unsigned int)length) + { + if(!self->Looping || !self->Decoder->seek(0)) + return false; + got += self->Decoder->read((char*)ptr+got, length-got); + } + + return (got == (unsigned int)length); + } + bool SetupSource() { @@ -251,10 +273,8 @@ class OpenALCallbackStream : public SoundStream } public: - ALfloat Volume; - OpenALCallbackStream(OpenALSoundRenderer *renderer) - : Renderer(renderer), Source(0), Playing(false), Volume(1.0f) + : Renderer(renderer), Source(0), Playing(false), Looping(false), Volume(1.0f) { Renderer->Streams.push_back(this); memset(Buffers, 0, sizeof(Buffers)); @@ -479,6 +499,89 @@ public: return true; } + + bool Init(const char *fname, int offset, int length, bool loop) + { + if(!SetupSource()) + return false; + + Decoder.reset(Renderer->CreateDecoder(fname, offset, length)); + if(!Decoder.get()) return false; + + Callback = DecoderCallback; + UserData = NULL; + Format = AL_NONE; + + ChannelConfig chans; + SampleType type; + int srate; + + Decoder->getInfo(&srate, &chans, &type); + if(chans == ChannelConfig_Mono) + { + if(type == SampleType_UInt8) Format = AL_FORMAT_MONO8; + if(type == SampleType_Int16) Format = AL_FORMAT_MONO16; + } + if(chans == ChannelConfig_Stereo) + { + if(type == SampleType_UInt8) Format = AL_FORMAT_STEREO8; + if(type == SampleType_Int16) Format = AL_FORMAT_STEREO16; + } + + if(Format == AL_NONE) + { + Printf("Unsupported audio format (0x%x / 0x%x)\n", chans, type); + return false; + } + SampleRate = srate; + Looping = loop; + + Data.resize((size_t)(0.2 * SampleRate) * 4); + + return true; + } + + bool Init(const BYTE *data, int length, bool loop) + { + if(!SetupSource()) + return false; + + DecoderData.insert(DecoderData.end(), data, data+length); + Decoder.reset(Renderer->CreateDecoder(&DecoderData[0], DecoderData.size())); + if(!Decoder.get()) return false; + + Callback = DecoderCallback; + UserData = NULL; + Format = AL_NONE; + + ChannelConfig chans; + SampleType type; + int srate; + + Decoder->getInfo(&srate, &chans, &type); + if(chans == ChannelConfig_Mono) + { + if(type == SampleType_UInt8) Format = AL_FORMAT_MONO8; + if(type == SampleType_Int16) Format = AL_FORMAT_MONO16; + } + if(chans == ChannelConfig_Stereo) + { + if(type == SampleType_UInt8) Format = AL_FORMAT_STEREO8; + if(type == SampleType_Int16) Format = AL_FORMAT_STEREO16; + } + + if(Format == AL_NONE) + { + Printf("Unsupported audio format (0x%x / 0x%x)\n", chans, type); + return false; + } + SampleRate = srate; + Looping = loop; + + Data.resize((size_t)(0.2 * SampleRate) * 4); + + return true; + } }; @@ -955,21 +1058,37 @@ SoundHandle OpenALSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int length, int fre SoundHandle OpenALSoundRenderer::LoadSound(BYTE *sfxdata, int length) { SoundHandle retval = { NULL }; - ALenum format; - ALuint srate; + ALenum format = AL_NONE; + ChannelConfig chans; + SampleType type; + int srate; - Decoder decoder(sfxdata, length); - if(!decoder.GetFormat(&format, &srate)) - return retval; + std::auto_ptr decoder(CreateDecoder(sfxdata, length)); + if(!decoder.get()) return retval; - ALsizei size; - void *data = decoder.GetData(&size); - if(data == NULL) + decoder->getInfo(&srate, &chans, &type); + if(chans == ChannelConfig_Mono) + { + if(type == SampleType_UInt8) format = AL_FORMAT_MONO8; + if(type == SampleType_Int16) format = AL_FORMAT_MONO16; + } + if(chans == ChannelConfig_Stereo) + { + if(type == SampleType_UInt8) format = AL_FORMAT_STEREO8; + if(type == SampleType_Int16) format = AL_FORMAT_STEREO16; + } + + if(format == AL_NONE) + { + Printf("Unsupported audio format (0x%x / 0x%x)\n", chans, type); return retval; + } + + std::vector data = decoder->readAll(); ALuint buffer = 0; alGenBuffers(1, &buffer); - alBufferData(buffer, format, data, size, srate); + alBufferData(buffer, format, &data[0], data.size(), srate); ALenum err; if((err=getALError()) != AL_NO_ERROR) @@ -1012,29 +1131,25 @@ void OpenALSoundRenderer::UnloadSound(SoundHandle sfx) delete ((ALuint*)sfx.data); } -short *OpenALSoundRenderer::DecodeSample(int outlen, const void *coded, int sizebytes, ECodecType type) +short *OpenALSoundRenderer::DecodeSample(int outlen, const void *coded, int sizebytes, ECodecType ctype) { - short *samples = (short*)malloc(outlen); - memset(samples, 0, outlen); + char *samples = (char*)calloc(1, outlen); + ChannelConfig chans; + SampleType type; + int srate; - Decoder decoder(coded, sizebytes); - ALenum format; - ALuint srate; + std::auto_ptr decoder(CreateDecoder((const BYTE*)coded, sizebytes)); + if(!decoder.get()) return (short*)samples; - if(!decoder.GetFormat(&format, &srate)) - return samples; - if(format != AL_FORMAT_MONO16) + decoder->getInfo(&srate, &chans, &type); + if(chans != ChannelConfig_Mono || type != SampleType_Int16) { DPrintf("Sample is not 16-bit mono\n"); - return samples; + return (short*)samples; } - ALsizei size; - void *data = decoder.GetData(&size); - if(data != NULL) - memcpy(samples, data, std::min(size, outlen)); - - return samples; + decoder->read(samples, outlen); + return (short*)samples; } SoundStream *OpenALSoundRenderer::CreateStream(SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata) @@ -1047,10 +1162,11 @@ SoundStream *OpenALSoundRenderer::CreateStream(SoundStreamCallback callback, int SoundStream *OpenALSoundRenderer::OpenStream(const char *filename, int flags, int offset, int length) { - std::auto_ptr stream(new OpenALSoundStream(this)); + std::auto_ptr stream(new OpenALCallbackStream(this)); - bool ok = ((offset == -1) ? stream->Init((const BYTE*)filename, length) : - stream->Init(filename, offset, length)); + bool loop = (flags&SoundStream::Loop); + bool ok = ((offset == -1) ? stream->Init((const BYTE*)filename, length, loop) : + stream->Init(filename, offset, length, loop)); if(ok == false) return NULL; From 14618cbf30da671965269303445375b7c7ff3d94 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 19 Jun 2014 04:33:00 -0700 Subject: [PATCH 20/88] Remove use of SDL_sound --- FindSDL_sound.cmake | 382 ------------------------ src/CMakeLists.txt | 13 +- src/sound/oalsdlsound.cpp | 593 -------------------------------------- src/sound/oalsdlsound.h | 72 ----- src/sound/oalsound.cpp | 86 +----- 5 files changed, 6 insertions(+), 1140 deletions(-) delete mode 100644 FindSDL_sound.cmake delete mode 100644 src/sound/oalsdlsound.cpp delete mode 100644 src/sound/oalsdlsound.h diff --git a/FindSDL_sound.cmake b/FindSDL_sound.cmake deleted file mode 100644 index 97d2a84c9e..0000000000 --- a/FindSDL_sound.cmake +++ /dev/null @@ -1,382 +0,0 @@ -# - Locates the SDL_sound library -# -# This module depends on SDL being found and -# must be called AFTER FindSDL.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 to override this selectionor 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(SDL_FOUND AND 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 SDL_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 FindSDL.cmake module, but that's kind of painful. - # The solution would be to try something like: - # set(SDL_TRY_COMPILE_LIBRARY_LIST "${SDL_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=${SDL_INCLUDE_DIR}\;${SDL_SOUND_INCLUDE_DIR} - # -DLINK_LIBRARIES:STRING=${SDL_SOUND_LIBRARY}\;${SDL_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} ${SDL_LIBRARY}) - # causes problems when SDL_LIBRARY looks like - # /Library/Frameworks/SDL.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) - foreach(lib ${SDL_SOUND_LIBRARY} ${SDL_LIBRARY}) - set(TMP_TRY_LIBS "${TMP_TRY_LIBS} \"${lib}\"") - endforeach() - - # 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 SDL_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(${SDL_INCLUDE_DIR} ${SDL_SOUND_INCLUDE_DIR}) - add_executable(DetermineSoundLibs DetermineSoundLibs.c) - target_link_libraries(DetermineSoundLibs ${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() - -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_LIBRARY SDL_SOUND_INCLUDE_DIR - VERSION_VAR SDL_SOUND_VERSION_STRING) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3fa9a0ee2f..d4bee329ea 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -222,22 +222,11 @@ else( WIN32 ) endif( WIN32 ) -set( OAL_SOURCES sound/oalsound.cpp ) if( NOT NO_OPENAL ) find_package( OpenAL ) if( OPENAL_FOUND ) include_directories( ${OPENAL_INCLUDE_DIR} ) set( ZDOOM_LIBS ${OPENAL_LIBRARY} ${ZDOOM_LIBS} ) - find_package( SDL ) - if( SDL_FOUND ) - find_package( SDL_sound ) - if( SDL_SOUND_FOUND ) - set_source_files_properties( sound/oalsound.cpp PROPERTIES COMPILE_FLAGS "-DWITH_SDL_SOUND=1" ) - set( OAL_SOURCES ${OAL_SOURCES} sound/oalsdlsound.cpp ) - include_directories( ${SDL_SOUND_INCLUDE_DIR} ) - set( ZDOOM_LIBS ${SDL_SOUND_LIBRARIES} ${ZDOOM_LIBS} ) - endif( SDL_SOUND_FOUND ) - endif( SDL_FOUND ) else( OPENAL_FOUND ) set( NO_OPENAL ON ) endif( OPENAL_FOUND ) @@ -1065,7 +1054,7 @@ add_executable( zdoom WIN32 sound/music_softsynth_mididevice.cpp sound/music_timidity_mididevice.cpp sound/music_win_mididevice.cpp - ${OAL_SOURCES} + sound/oalsound.cpp sound/music_pseudo_mididevice.cpp textures/animations.cpp textures/anim_switches.cpp diff --git a/src/sound/oalsdlsound.cpp b/src/sound/oalsdlsound.cpp deleted file mode 100644 index 7aa8574528..0000000000 --- a/src/sound/oalsdlsound.cpp +++ /dev/null @@ -1,593 +0,0 @@ -/* -** oalsdlsound.cpp -** Interface for SDL_sound; uses OpenAL -** -**--------------------------------------------------------------------------- -** Copyright 2008-2010 Chris Robinson -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**--------------------------------------------------------------------------- -** -*/ - -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include -#define USE_WINDOWS_DWORD -#endif - -#include "doomstat.h" -#include "templates.h" -#include "oalsound.h" -#include "oalsdlsound.h" -#include "c_cvars.h" -#include "c_dispatch.h" -#include "i_system.h" -#include "v_text.h" -#include "gi.h" -#include "actor.h" -#include "r_state.h" -#include "w_wad.h" -#include "i_music.h" -#include "i_musicinterns.h" - -#include -#include - - -struct RWSubFile { -private: - FILE *fp; - size_t start; - size_t length; - -public: - RWSubFile(FILE *f, size_t offset, size_t len) - : fp(f), start(offset), length(len) - { - fseek(fp, start, SEEK_SET); - } - ~RWSubFile() - { fclose(fp); } - - static int seek(SDL_RWops *context, int offset, int whence) - { - RWSubFile *self = static_cast(context->hidden.unknown.data1); - - if(whence == SEEK_END) - { - if(offset <= 0) - offset = self->length + offset; - } - else if(whence == SEEK_CUR) - offset = offset + ftell(self->fp) - self->start; - else if(whence != SEEK_SET) - { - SDL_SetError("Invalid seek mode"); - return -1; - } - - if(offset >= 0 && size_t(offset) <= self->length) - { - if(fseek(self->fp, offset + self->start, SEEK_SET) == 0) - return offset; - } - - SDL_SetError("Invalid file seek"); - return -1; - } - - static int read(SDL_RWops *context, void *ptr, int size, int maxnum) - { - RWSubFile *self = static_cast(context->hidden.unknown.data1); - return fread(ptr, size, maxnum, self->fp); - } - - static int write(SDL_RWops *context, const void *ptr, int size, int num) - { - RWSubFile *self = static_cast(context->hidden.unknown.data1); - return fwrite(ptr, size, num, self->fp); - } - - static int close(SDL_RWops *context) - { - RWSubFile *self = static_cast(context->hidden.unknown.data1); - if(context->type != 0xdeadbeef) - { - SDL_SetError("Wrong kind of RWops for RWSubfile::close"); - return -1; - } - - delete self; - SDL_FreeRW(context); - - return 0; - } -}; - - -static ALenum checkALError(const char *fn, unsigned int ln) -{ - ALenum err = alGetError(); - if(err != AL_NO_ERROR) - { - if(strchr(fn, '/')) - fn = strrchr(fn, '/')+1; - else if(strchr(fn, '\\')) - fn = strrchr(fn, '\\')+1; - Printf(">>>>>>>>>>>> Received AL error %s (%#x), %s:%u\n", alGetString(err), err, fn, ln); - } - return err; -} -#define getALError() checkALError(__FILE__, __LINE__) - - -bool OpenALSoundStream::SetupSource() -{ - if(Renderer->FreeSfx.size() == 0) - { - FSoundChan *lowest = Renderer->FindLowestChannel(); - if(lowest) Renderer->StopChannel(lowest); - - if(Renderer->FreeSfx.size() == 0) - return false; - } - Source = Renderer->FreeSfx.back(); - Renderer->FreeSfx.pop_back(); - - alSource3f(Source, AL_DIRECTION, 0.f, 0.f, 0.f); - alSource3f(Source, AL_VELOCITY, 0.f, 0.f, 0.f); - alSource3f(Source, AL_POSITION, 0.f, 0.f, 0.f); - alSourcef(Source, AL_MAX_GAIN, Renderer->MusicVolume); - alSourcef(Source, AL_GAIN, Volume*Renderer->MusicVolume); - alSourcef(Source, AL_PITCH, 1.f); - alSourcef(Source, AL_ROLLOFF_FACTOR, 0.f); - alSourcef(Source, AL_SEC_OFFSET, 0.f); - alSourcei(Source, AL_SOURCE_RELATIVE, AL_TRUE); - alSourcei(Source, AL_LOOPING, AL_FALSE); - if(Renderer->EnvSlot) - { - alSourcef(Source, AL_ROOM_ROLLOFF_FACTOR, 0.f); - alSourcef(Source, AL_AIR_ABSORPTION_FACTOR, 0.f); - alSourcei(Source, AL_DIRECT_FILTER, AL_FILTER_NULL); - alSource3i(Source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL); - } - - alGenBuffers(Buffers.size(), &Buffers[0]); - return (getALError() == AL_NO_ERROR); -} - -OpenALSoundStream::OpenALSoundStream(OpenALSoundRenderer *renderer) - : Renderer(renderer), Sample(NULL), Source(0), Playing(false), - Looping(false), Buffers(4), SampleRate(0), Format(0), - NeedSwab(false), NeedS8Conv(false), NeedS16Conv(false), - Volume(1.f) -{ - for(size_t i = 0;i < Buffers.size();i++) - Buffers[i] = 0; - Renderer->Streams.push_back(this); -} - -OpenALSoundStream::~OpenALSoundStream() -{ - Playing = false; - - Sound_FreeSample(Sample); - Sample = NULL; - - if(Source) - { - alSourceRewind(Source); - alSourcei(Source, AL_BUFFER, 0); - - Renderer->FreeSfx.push_back(Source); - Source = 0; - } - - if(Buffers.size() > 0) - { - alDeleteBuffers(Buffers.size(), &Buffers[0]); - Buffers.clear(); - } - getALError(); - - Renderer->Streams.erase(std::find(Renderer->Streams.begin(), - Renderer->Streams.end(), this)); - Renderer = NULL; -} - -bool OpenALSoundStream::Play(bool looping, float vol) -{ - if(Playing) - return true; - - alSourceRewind(Source); - alSourcei(Source, AL_BUFFER, 0); - - Looping = looping; - SetVolume(vol); - - for(size_t i = 0;i < Buffers.size();i++) - { - size_t count = Sound_Decode(Sample); - if(count == 0 && Looping) - { - Sound_Seek(Sample, 0); - count = Sound_Decode(Sample); - } - alBufferData(Buffers[i], Format, GetData(count), count, SampleRate); - } - Playing = (getALError() == AL_NO_ERROR); - if(Playing) - { - alSourceQueueBuffers(Source, Buffers.size(), &Buffers[0]); - alSourcePlay(Source); - Playing = (getALError() == AL_NO_ERROR); - } - return Playing; -} - -void OpenALSoundStream::Stop() -{ - alSourceRewind(Source); - alSourcei(Source, AL_BUFFER, 0); -} - -bool OpenALSoundStream::SetPaused(bool paused) -{ - if(paused) alSourcePause(Source); - else alSourcePlay(Source); - return (getALError() == AL_NO_ERROR); -} - -void OpenALSoundStream::SetVolume(float vol) -{ - if(vol >= 0.f) Volume = vol; - alSourcef(Source, AL_GAIN, Volume*Renderer->MusicVolume); -} - -unsigned int OpenALSoundStream::GetPosition() -{ - return 0; -} - -bool OpenALSoundStream::SetPosition(unsigned int val) -{ - return false; -} - -bool OpenALSoundStream::IsEnded() -{ - if(!Playing) - return true; - - ALint processed, state, queued; - alGetSourcei(Source, AL_SOURCE_STATE, &state); - alGetSourcei(Source, AL_BUFFERS_QUEUED, &queued); - alGetSourcei(Source, AL_BUFFERS_PROCESSED, &processed); - while(processed-- > 0) - { - ALuint buf = 0; - alSourceUnqueueBuffers(Source, 1, &buf); - queued--; - - size_t count = Sound_Decode(Sample); - if(count == 0 && Looping) - { - Sound_Seek(Sample, 0); - count = Sound_Decode(Sample); - } - if(count > 0) - { - alBufferData(buf, Format, GetData(count), count, SampleRate); - alSourceQueueBuffers(Source, 1, &buf); - queued++; - } - } - Playing = (getALError() == AL_NO_ERROR && queued > 0); - if(Playing && state != AL_PLAYING && state != AL_PAUSED) - { - alSourcePlay(Source); - Playing = (getALError() == AL_NO_ERROR); - } - - return !Playing; -} - -void *OpenALSoundStream::GetData(size_t bytes) -{ - void *data = Sample->buffer; - if(NeedSwab) - { - short *samples = reinterpret_cast(data); - size_t count = bytes >> 1; - for(size_t i = 0;i < count;i++) - { - short smp = *samples; - *(samples++) = ((smp>>8)&0x00FF) | ((smp<<8)&0xFF00); - } - } - if(NeedS8Conv) - { - char *samples = reinterpret_cast(data); - for(size_t i = 0;i < bytes;i++) - samples[i] = samples[i]^0x80; - } - if(NeedS16Conv) - { - short *samples = reinterpret_cast(data); - size_t count = bytes >> 1; - for(size_t i = 0;i < count;i++) - samples[i] = samples[i]^0x8000; - } - return data; -} - -FString OpenALSoundStream::GetStats() -{ - FString stats; - ALfloat volume; - ALint processed; - ALint queued; - ALint state; - ALenum err; - - alGetSourcef(Source, AL_GAIN, &volume); - alGetSourcei(Source, AL_SOURCE_STATE, &state); - alGetSourcei(Source, AL_BUFFERS_QUEUED, &queued); - alGetSourcei(Source, AL_BUFFERS_PROCESSED, &processed); - if((err=alGetError()) != AL_NO_ERROR) - { - stats = "Error getting stats: "; - stats += alGetString(err); - return stats; - } - - stats = (state == AL_INITIAL) ? "Buffering" : (state == AL_STOPPED) ? "Underrun" : - (state == AL_PLAYING || state == AL_PAUSED) ? "Ready" : "Unknown state"; - stats.AppendFormat(",%3d%% buffered", (queued ? 100-(processed*100/queued) : 0)); - stats.AppendFormat(", %d%%", int(volume * 100)); - if(state == AL_PAUSED) - stats += ", paused"; - if(state == AL_PLAYING) - stats += ", playing"; - stats.AppendFormat(", %uHz", SampleRate); - if(!Playing) - stats += " XX"; - return stats; -} - - -bool OpenALSoundStream::InitSample() -{ - UInt32 smpsize = 0; - SampleRate = Sample->actual.rate; - - Format = AL_NONE; - if(Sample->actual.format == AUDIO_S8) - { - NeedS8Conv = true; - if(Sample->actual.channels == 1) - Format = AL_FORMAT_MONO8; - else if(Sample->actual.channels == 2) - Format = AL_FORMAT_STEREO8; - smpsize = 1 * Sample->actual.channels; - } - else if(Sample->actual.format == AUDIO_U8) - { - if(Sample->actual.channels == 1) - Format = AL_FORMAT_MONO8; - else if(Sample->actual.channels == 2) - Format = AL_FORMAT_STEREO8; - smpsize = 1 * Sample->actual.channels; - } - else if(Sample->actual.format == AUDIO_S16LSB || Sample->actual.format == AUDIO_S16MSB) - { - NeedSwab = (Sample->actual.format != AUDIO_S16SYS); - if(Sample->actual.channels == 1) - Format = AL_FORMAT_MONO16; - else if(Sample->actual.channels == 2) - Format = AL_FORMAT_STEREO16; - smpsize = 2 * Sample->actual.channels; - } - else if(Sample->actual.format == AUDIO_U16LSB || Sample->actual.format == AUDIO_U16MSB) - { - NeedS16Conv = true; - NeedSwab = (Sample->actual.format != AUDIO_U16SYS); - if(Sample->actual.channels == 1) - Format = AL_FORMAT_MONO16; - else if(Sample->actual.channels == 2) - Format = AL_FORMAT_STEREO16; - smpsize = 2 * Sample->actual.channels; - } - - if(Format == AL_NONE) - { - Printf("Unsupported sound format (0x%04x, %d channels)\n", Sample->actual.format, Sample->actual.channels); - return false; - } - - Uint32 bufsize = (UInt32)(BufferTime*SampleRate) * smpsize; - if(Sound_SetBufferSize(Sample, bufsize) == 0) - { - Printf("Failed to set buffer size to %u bytes: %s\n", bufsize, Sound_GetError()); - return false; - } - - return true; -} - -bool OpenALSoundStream::Init(const char *filename, int offset, int length) -{ - if(!SetupSource()) - return false; - - if(offset == 0) - Sample = Sound_NewSampleFromFile(filename, NULL, 0); - else - { - FILE *fp = fopen(filename, "rb"); - if(!fp) - { - Printf("Failed to open %s\n", filename); - return false; - } - - const char *ext = strrchr(filename, '.'); - if(ext) ext++; - - SDL_RWops *ops = SDL_AllocRW(); - ops->seek = RWSubFile::seek; - ops->read = RWSubFile::read; - ops->write = RWSubFile::write; - ops->close = RWSubFile::close; - ops->type = 0xdeadbeef; - ops->hidden.unknown.data1 = new RWSubFile(fp, offset, length); - - Sample = Sound_NewSample(ops, ext, NULL, 0); - } - if(!Sample) - { - Printf("Could not open audio in %s (%s)\n", filename, Sound_GetError()); - return false; - } - - return InitSample(); -} - -bool OpenALSoundStream::Init(const BYTE *data, unsigned int datalen) -{ - if(!SetupSource()) - return false; - - Sample = Sound_NewSample(SDL_RWFromConstMem(data, datalen), NULL, NULL, 0); - if(!Sample) - { - Printf("Could not read audio: %s\n", Sound_GetError()); - return false; - } - - return InitSample(); -} - - -Decoder::Decoder(const void* data, unsigned int datalen) - : Sample(NULL), NeedSwab(false), NeedS8Conv(false), NeedS16Conv(false) -{ - Sample = Sound_NewSample(SDL_RWFromConstMem(data, datalen), NULL, NULL, 65536); -} - - -Decoder::~Decoder() -{ - Sound_FreeSample(Sample); - Sample = NULL; -} - -bool Decoder::GetFormat(ALenum *format, ALuint *rate) -{ - ALenum fmt = AL_NONE; - if(Sample->actual.format == AUDIO_S8) - { - NeedS8Conv = true; - if(Sample->actual.channels == 1) - fmt = AL_FORMAT_MONO8; - else if(Sample->actual.channels == 2) - fmt = AL_FORMAT_STEREO8; - } - else if(Sample->actual.format == AUDIO_U8) - { - if(Sample->actual.channels == 1) - fmt = AL_FORMAT_MONO8; - else if(Sample->actual.channels == 2) - fmt = AL_FORMAT_STEREO8; - } - else if(Sample->actual.format == AUDIO_S16LSB || Sample->actual.format == AUDIO_S16MSB) - { - NeedSwab = (Sample->actual.format != AUDIO_S16SYS); - if(Sample->actual.channels == 1) - fmt = AL_FORMAT_MONO16; - else if(Sample->actual.channels == 2) - fmt = AL_FORMAT_STEREO16; - } - else if(Sample->actual.format == AUDIO_U16LSB || Sample->actual.format == AUDIO_U16MSB) - { - NeedS16Conv = true; - NeedSwab = (Sample->actual.format != AUDIO_U16SYS); - if(Sample->actual.channels == 1) - fmt = AL_FORMAT_MONO16; - else if(Sample->actual.channels == 2) - fmt = AL_FORMAT_STEREO16; - } - - if(fmt == AL_NONE) - { - Printf("Unsupported sound format (0x%04x, %d channels)\n", Sample->actual.format, Sample->actual.channels); - return false; - } - - *format = fmt; - *rate = Sample->actual.rate; - return true; -} - -void* Decoder::GetData(ALsizei *size) -{ - UInt32 got = Sound_DecodeAll(Sample); - if(got == 0) - { - *size = 0; - return NULL; - } - - void *data = Sample->buffer; - if(NeedSwab) - { - short *samples = reinterpret_cast(data); - size_t count = got >> 1; - for(size_t i = 0;i < count;i++) - { - short smp = *samples; - *(samples++) = ((smp>>8)&0x00FF) | ((smp<<8)&0xFF00); - } - } - - if(NeedS8Conv) - { - char *samples = reinterpret_cast(data); - for(size_t i = 0;i < got;i++) - samples[i] = samples[i]^0x80; - } - if(NeedS16Conv) - { - short *samples = reinterpret_cast(data); - size_t count = got >> 1; - for(size_t i = 0;i < count;i++) - samples[i] = samples[i]^0x8000; - } - - *size = got; - return data; -} diff --git a/src/sound/oalsdlsound.h b/src/sound/oalsdlsound.h deleted file mode 100644 index 7b7a0ce737..0000000000 --- a/src/sound/oalsdlsound.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef OALSDLSOUND_H -#define OALSDLSOUND_H - -#include "oalsound.h" -#include "tempfiles.h" - -#include "SDL_sound.h" - -class OpenALSoundStream : public SoundStream -{ - OpenALSoundRenderer *Renderer; - Sound_Sample *Sample; - ALuint Source; - - bool Playing; - bool Looping; - - static const ALfloat BufferTime = 0.2f; - std::vector Buffers; - - ALuint SampleRate; - ALenum Format; - - bool NeedSwab; - bool NeedS8Conv; - bool NeedS16Conv; - void *GetData(size_t bytes); - - // General methods - bool SetupSource(); - bool InitSample(); - - ALfloat Volume; - -public: - OpenALSoundStream(OpenALSoundRenderer *renderer); - virtual ~OpenALSoundStream(); - - virtual bool Play(bool looping, float vol); - virtual void Stop(); - virtual bool SetPaused(bool paused); - - virtual void SetVolume(float vol); - - virtual unsigned int GetPosition(); - virtual bool SetPosition(unsigned int val); - - virtual bool IsEnded(); - - virtual FString GetStats(); - - bool Init(const char *filename, int offset, int length); - bool Init(const BYTE *data, unsigned int datalen); -}; - - -class Decoder -{ - Sound_Sample *Sample; - bool NeedSwab; - bool NeedS8Conv; - bool NeedS16Conv; - -public: - Decoder(const void *data, unsigned int datalen); - virtual ~Decoder(); - - bool GetFormat(ALenum *format, ALuint *rate); - void *GetData(ALsizei *size); -}; - -#endif /* OALSDLSOUND_H */ diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 37ad877d38..66c80faf27 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -88,9 +88,6 @@ void I_BuildALDeviceList(FOptionValues *opt) #include #include -#ifdef WITH_SDL_SOUND -#include "SDL_sound.h" -#endif EXTERN_CVAR (Int, snd_channels) EXTERN_CVAR (Int, snd_samplerate) @@ -134,68 +131,8 @@ static ALCenum checkALCError(ALCdevice *device, const char *fn, unsigned int ln) } #define getALCError(d) checkALCError((d), __FILE__, __LINE__) -#ifdef WITH_SDL_SOUND -#include "oalsdlsound.h" -#else class OpenALSoundStream : public SoundStream -{ - OpenALSoundRenderer *Renderer; - -public: - ALfloat Volume; - - OpenALSoundStream(OpenALSoundRenderer *renderer) - : Renderer(renderer), Volume(1.0f) - { Renderer->Streams.push_back(this); } - - virtual ~OpenALSoundStream() - { - Renderer->Streams.erase(std::find(Renderer->Streams.begin(), - Renderer->Streams.end(), this)); - Renderer = NULL; - } - - - virtual bool Play(bool, float) - { return false; } - - virtual void Stop() - { } - - virtual void SetVolume(float vol) - { Volume = vol; } - - virtual bool SetPaused(bool) - { return false; } - - virtual unsigned int GetPosition() - { return 0; } - - virtual bool IsEnded() - { return true; } - - bool Init(const char*) - { return false; } - - bool Init(const BYTE*, unsigned int) - { return false; } -}; - -class Decoder -{ -public: - Decoder(const void*, unsigned int) { } - virtual ~Decoder() { } - - bool GetFormat(ALenum*, ALuint*) - { return false; } - void *GetData(ALsizei *size) - { *size = 0; return NULL; } -}; -#endif - -class OpenALCallbackStream : public SoundStream { OpenALSoundRenderer *Renderer; @@ -220,7 +157,7 @@ class OpenALCallbackStream : public SoundStream std::auto_ptr Decoder; static bool DecoderCallback(SoundStream *_sstream, void *ptr, int length, void *user) { - OpenALCallbackStream *self = static_cast(_sstream); + OpenALSoundStream *self = static_cast(_sstream); if(length < 0) return false; size_t got = self->Decoder->read((char*)ptr, length); @@ -273,14 +210,14 @@ class OpenALCallbackStream : public SoundStream } public: - OpenALCallbackStream(OpenALSoundRenderer *renderer) + OpenALSoundStream(OpenALSoundRenderer *renderer) : Renderer(renderer), Source(0), Playing(false), Looping(false), Volume(1.0f) { Renderer->Streams.push_back(this); memset(Buffers, 0, sizeof(Buffers)); } - virtual ~OpenALCallbackStream() + virtual ~OpenALSoundStream() { if(Source) { @@ -658,19 +595,6 @@ OpenALSoundRenderer::OpenALSoundRenderer() Printf("I_InitSound: Initializing OpenAL\n"); -#ifdef WITH_SDL_SOUND - static bool sdl_sound_inited = false; - if(!sdl_sound_inited) - { - if(Sound_Init() == 0) - { - Printf(TEXTCOLOR_RED" Failed to init SDL_sound: %s\n", Sound_GetError()); - return; - } - sdl_sound_inited = true; - } -#endif - if(strcmp(snd_aldevice, "Default") != 0) { Device = alcOpenDevice(*snd_aldevice); @@ -1154,7 +1078,7 @@ short *OpenALSoundRenderer::DecodeSample(int outlen, const void *coded, int size SoundStream *OpenALSoundRenderer::CreateStream(SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata) { - std::auto_ptr stream(new OpenALCallbackStream(this)); + std::auto_ptr stream(new OpenALSoundStream(this)); if(!stream->Init(callback, buffbytes, flags, samplerate, userdata)) return NULL; return stream.release(); @@ -1162,7 +1086,7 @@ SoundStream *OpenALSoundRenderer::CreateStream(SoundStreamCallback callback, int SoundStream *OpenALSoundRenderer::OpenStream(const char *filename, int flags, int offset, int length) { - std::auto_ptr stream(new OpenALCallbackStream(this)); + std::auto_ptr stream(new OpenALSoundStream(this)); bool loop = (flags&SoundStream::Loop); bool ok = ((offset == -1) ? stream->Init((const BYTE*)filename, length, loop) : From 77b1febd0eab6458b55a37a77a2f6b3beb88f277 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 19 Jun 2014 06:34:40 -0700 Subject: [PATCH 21/88] Add an mp3 decoder using libmpg123 Does not currently handle direct file sources --- FindMPG123.cmake | 28 +++++ src/CMakeLists.txt | 13 ++- src/sound/audio_mpg123_decoder.cpp | 167 +++++++++++++++++++++++++++++ src/sound/i_sound.cpp | 62 ++++++++++- src/sound/i_soundinternal.h | 32 ++++++ 5 files changed, 296 insertions(+), 6 deletions(-) create mode 100644 FindMPG123.cmake create mode 100644 src/sound/audio_mpg123_decoder.cpp diff --git a/FindMPG123.cmake b/FindMPG123.cmake new file mode 100644 index 0000000000..9b871d439e --- /dev/null +++ b/FindMPG123.cmake @@ -0,0 +1,28 @@ +# - Find mpg123 +# Find the native mpg123 includes and library +# +# MPG123_INCLUDE_DIR - where to find mpg123.h +# MPG123_LIBRARIES - List of libraries when using mpg123. +# MPG123_FOUND - True if mpg123 found. + +IF(MPG123_INCLUDE_DIR AND MPG123_LIBRARIES) + # Already in cache, be silent + SET(MPG123_FIND_QUIETLY TRUE) +ENDIF(MPG123_INCLUDE_DIR AND MPG123_LIBRARIES) + +FIND_PATH(MPG123_INCLUDE_DIR mpg123.h + PATHS "${MPG123_DIR}" + PATH_SUFFIXES include + ) + +FIND_LIBRARY(MPG123_LIBRARIES NAMES mpg123 mpg123-0 + PATHS "${MPG123_DIR}" + PATH_SUFFIXES lib + ) + +MARK_AS_ADVANCED(MPG123_LIBRARIES MPG123_INCLUDE_DIR) + +# handle the QUIETLY and REQUIRED arguments and set MPG123_FOUND to TRUE if +# all listed variables are TRUE +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(MPG123 DEFAULT_MSG MPG123_LIBRARIES MPG123_INCLUDE_DIR) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d4bee329ea..90e5be0fde 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -299,6 +299,10 @@ endif( NO_OPENAL ) find_package( SndFile ) +# Search for libmpg123 + +find_package( MPG123 ) + # Search for FluidSynth find_package( FluidSynth ) @@ -553,7 +557,10 @@ if( SNDFILE_FOUND ) set( ZDOOM_LIBS ${ZDOOM_LIBS} "${SNDFILE_LIBRARIES}" ) include_directories( "${SNDFILE_INCLUDE_DIRS}" ) endif( SNDFILE_FOUND ) - +if( MPG123_FOUND ) + set( ZDOOM_LIBS ${ZDOOM_LIBS} "${MPG123_LIBRARIES}" ) + include_directories( "${MPG123_INCLUDE_DIR}" ) +endif( MPG123_FOUND ) if( NOT DYN_FLUIDSYNTH) if( FLUIDSYNTH_FOUND ) set( ZDOOM_LIBS ${ZDOOM_LIBS} "${FLUIDSYNTH_LIBRARIES}" ) @@ -671,6 +678,9 @@ endif( SSE_MATTERS ) if( SNDFILE_FOUND ) add_definitions( -DHAVE_SNDFILE ) endif( SNDFILE_FOUND ) +if( MPG123_FOUND ) + add_definitions( -DHAVE_MPG123 ) +endif( MPG123_FOUND ) if( DYN_FLUIDSYNTH ) add_definitions( -DHAVE_FLUIDSYNTH -DDYN_FLUIDSYNTH ) elseif( FLUIDSYNTH_FOUND ) @@ -1034,6 +1044,7 @@ add_executable( zdoom WIN32 resourcefiles/file_directory.cpp resourcefiles/resourcefile.cpp sfmt/SFMT.cpp + sound/audio_mpg123_decoder.cpp sound/audio_sndfile_decoder.cpp sound/fmodsound.cpp sound/i_music.cpp diff --git a/src/sound/audio_mpg123_decoder.cpp b/src/sound/audio_mpg123_decoder.cpp new file mode 100644 index 0000000000..f0d9a188c1 --- /dev/null +++ b/src/sound/audio_mpg123_decoder.cpp @@ -0,0 +1,167 @@ +#include "i_soundinternal.h" + +#ifdef HAVE_MPG123 +static bool inited = false; + + +off_t MPG123Decoder::mem_lseek(void *handle, off_t offset, int whence) +{ + MPG123Decoder *self = reinterpret_cast(handle); + + switch(whence) + { + case SEEK_SET: + if(offset < 0 || offset > (off_t)self->MemLength) + return -1; + self->MemPos = offset; + break; + + case SEEK_CUR: + if((offset > 0 && (off_t)(self->MemLength-self->MemPos) < offset) || + (offset < 0 && (off_t)self->MemPos < -offset)) + return -1; + self->MemPos += offset; + break; + + case SEEK_END: + if(offset > 0 || -offset > (off_t)self->MemLength) + return -1; + self->MemPos = self->MemLength + offset; + break; + + default: + return -1; + } + + return self->MemPos; +} + +ssize_t MPG123Decoder::mem_read(void *handle, void *buffer, size_t bytes) +{ + MPG123Decoder *self = reinterpret_cast(handle); + + if(bytes > self->MemLength-self->MemPos) + bytes = self->MemLength-self->MemPos; + + memcpy(buffer, self->MemData+self->MemPos, bytes); + self->MemPos += bytes; + + return bytes; +} + + +MPG123Decoder::~MPG123Decoder() +{ + if(MPG123) + { + mpg123_close(MPG123); + mpg123_delete(MPG123); + MPG123 = 0; + } +} + +bool MPG123Decoder::open(const char *data, size_t length) +{ + if(!inited) + { + if(mpg123_init() != MPG123_OK) + return false; + inited = true; + } + + MemData = data; + MemPos = 0; + MemLength = length; + + MPG123 = mpg123_new(NULL, NULL); + if(mpg123_replace_reader_handle(MPG123, mem_read, mem_lseek, NULL) == MPG123_OK && + mpg123_open_handle(MPG123, this) == MPG123_OK) + { + int enc, channels; + long srate; + + if(mpg123_getformat(MPG123, &srate, &channels, &enc) == MPG123_OK) + { + if((channels == 1 || channels == 2) && srate > 0 && + mpg123_format_none(MPG123) == MPG123_OK && + mpg123_format(MPG123, srate, channels, MPG123_ENC_SIGNED_16) == MPG123_OK) + { + // All OK + Done = false; + return true; + } + } + mpg123_close(MPG123); + } + mpg123_delete(MPG123); + MPG123 = 0; + + return false; +} + +void MPG123Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) +{ + int enc = 0, channels = 0; + long srate = 0; + + mpg123_getformat(MPG123, &srate, &channels, &enc); + + *samplerate = srate; + + if(channels == 2) + *chans = ChannelConfig_Stereo; + else + *chans = ChannelConfig_Mono; + + *type = SampleType_Int16; +} + +size_t MPG123Decoder::read(char *buffer, size_t bytes) +{ + size_t amt = 0; + while(!Done && bytes > 0) + { + size_t got = 0; + int ret = mpg123_read(MPG123, (unsigned char*)buffer, bytes, &got); + + bytes -= got; + buffer += got; + amt += got; + + if(ret == MPG123_NEW_FORMAT || ret == MPG123_DONE || got == 0) + { + Done = true; + break; + } + } + return amt; +} + +bool MPG123Decoder::open(const char *fname, size_t offset, size_t length) +{ + return false; +} + +bool MPG123Decoder::seek(size_t ms_offset) +{ + int enc, channels; + long srate; + + if(mpg123_getformat(MPG123, &srate, &channels, &enc) == MPG123_OK) + { + size_t smp_offset = (size_t)((double)ms_offset / 1000. * srate); + if(mpg123_seek(MPG123, smp_offset, SEEK_SET) >= 0) + { + Done = false; + return true; + } + } + return false; +} + +size_t MPG123Decoder::getSampleOffset() +{ + return mpg123_tell(MPG123); +} + +#endif diff --git a/src/sound/i_sound.cpp b/src/sound/i_sound.cpp index da9cb0e66f..7b66f9770f 100644 --- a/src/sound/i_sound.cpp +++ b/src/sound/i_sound.cpp @@ -524,12 +524,64 @@ SoundHandle SoundRenderer::LoadSoundVoc(BYTE *sfxdata, int length) SoundDecoder *SoundRenderer::CreateDecoder(const BYTE *sfxdata, int length) { SoundDecoder *decoder = NULL; -#ifdef HAVE_SNDFILE - decoder = new SndFileDecoder; - if(!decoder->open((const char*)sfxdata, length)) +#ifdef HAVE_MPG123 + int mpg_start = -1; + int mpg_len = -1; + + // Check for an ID3 tag to identify an mp3 (and skip the tag) + if(length > 10 && memcmp(sfxdata, "ID3", 3) == 0 && + sfxdata[3] <= 4 && sfxdata[4] != 0xff && + (sfxdata[5]&0x0f) == 0 && (sfxdata[6]&0x80) == 0 && + (sfxdata[7]&0x80) == 0 && (sfxdata[8]&0x80) == 0 && + (sfxdata[9]&0x80) == 0) { - delete decoder; - decoder = NULL; + // ID3v2 + mpg_start = (sfxdata[6]<<21) | (sfxdata[7]<<14) | + (sfxdata[8]<< 7) | (sfxdata[9] ); + mpg_start += ((sfxdata[5]&0x10) ? 20 : 10); + mpg_len = length - mpg_start; + } + else if(length > 128 && memcmp(sfxdata+length-128, "TAG", 3) == 0) + { + // ID3v1 + mpg_start = 0; + mpg_len = length - 128; + } + else if(length > 3) + { + // No ID3 tag. Check for a frame header + if((sfxdata[0] == 0xff && sfxdata[1]>>1 == 0x7d) || // MPEG-1 + (sfxdata[0] == 0xff && sfxdata[1]>>1 == 0x79)) // MPEG-2 + { + int brate_idx = (sfxdata[2]>>4) & 0x0f; + int srate_idx = (sfxdata[2]>>2) & 0x03; + if(brate_idx != 0 && brate_idx != 15 && srate_idx != 3) + { + mpg_start = 0; + mpg_len = length; + } + } + } + + if(mpg_start >= 0 && mpg_len > 0 && mpg_start < length && mpg_len <= length-mpg_start) + { + decoder = new MPG123Decoder; + if(!decoder->open((const char*)sfxdata+mpg_start, mpg_len)) + { + delete decoder; + decoder = NULL; + } + } +#endif +#ifdef HAVE_SNDFILE + if(!decoder) + { + decoder = new SndFileDecoder; + if(!decoder->open((const char*)sfxdata, length)) + { + delete decoder; + decoder = NULL; + } } #endif return decoder; diff --git a/src/sound/i_soundinternal.h b/src/sound/i_soundinternal.h index 26a42bc643..4351fe0fe7 100644 --- a/src/sound/i_soundinternal.h +++ b/src/sound/i_soundinternal.h @@ -139,6 +139,38 @@ private: SoundDecoder& operator=(const SoundDecoder &rhs); }; +#ifdef HAVE_MPG123 +#include "mpg123.h" +struct MPG123Decoder : public SoundDecoder +{ + virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type); + + virtual size_t read(char *buffer, size_t bytes); + virtual bool seek(size_t ms_offset); + virtual size_t getSampleOffset(); + + MPG123Decoder() : MPG123(0) { } + virtual ~MPG123Decoder(); + +protected: + virtual bool open(const char *data, size_t length); + virtual bool open(const char *fname, size_t offset, size_t length); + +private: + mpg123_handle *MPG123; + bool Done; + + const char *MemData; + size_t MemLength; + size_t MemPos; + static off_t mem_lseek(void *handle, off_t offset, int whence); + static ssize_t mem_read(void *handle, void *buffer, size_t bytes); + + // Make non-copyable + MPG123Decoder(const MPG123Decoder &rhs); + MPG123Decoder& operator=(const MPG123Decoder &rhs); +}; +#endif #ifdef HAVE_SNDFILE #include "sndfile.h" struct SndFileDecoder : public SoundDecoder From 73d51a4446d038234b17bf7636a2bf9f8f8fbefa Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 19 Jun 2014 17:19:59 -0700 Subject: [PATCH 22/88] Check for ID3 tags in MPG123Decoder::open --- src/sound/audio_mpg123_decoder.cpp | 84 +++++++++++++++++++++--------- src/sound/i_sound.cpp | 49 ++--------------- 2 files changed, 64 insertions(+), 69 deletions(-) diff --git a/src/sound/audio_mpg123_decoder.cpp b/src/sound/audio_mpg123_decoder.cpp index f0d9a188c1..4cc1a813bc 100644 --- a/src/sound/audio_mpg123_decoder.cpp +++ b/src/sound/audio_mpg123_decoder.cpp @@ -69,32 +69,68 @@ bool MPG123Decoder::open(const char *data, size_t length) inited = true; } - MemData = data; - MemPos = 0; - MemLength = length; - - MPG123 = mpg123_new(NULL, NULL); - if(mpg123_replace_reader_handle(MPG123, mem_read, mem_lseek, NULL) == MPG123_OK && - mpg123_open_handle(MPG123, this) == MPG123_OK) + // Check for ID3 tags and skip them + if(length > 10 && memcmp(data, "ID3", 3) == 0 && + (BYTE)data[3] <= 4 && (BYTE)data[4] != 0xff && + (data[5]&0x0f) == 0 && (data[6]&0x80) == 0 && + (data[7]&0x80) == 0 && (data[8]&0x80) == 0 && + (data[9]&0x80) == 0) { - int enc, channels; - long srate; - - if(mpg123_getformat(MPG123, &srate, &channels, &enc) == MPG123_OK) - { - if((channels == 1 || channels == 2) && srate > 0 && - mpg123_format_none(MPG123) == MPG123_OK && - mpg123_format(MPG123, srate, channels, MPG123_ENC_SIGNED_16) == MPG123_OK) - { - // All OK - Done = false; - return true; - } - } - mpg123_close(MPG123); + // ID3v2 + int start_offset; + start_offset = (data[6]<<21) | (data[7]<<14) | + (data[8]<< 7) | (data[9] ); + start_offset += ((data[5]&0x10) ? 20 : 10); + length -= start_offset; + data += start_offset; + } + + if(length > 128 && memcmp(data+length-128, "TAG", 3) == 0) // ID3v1 + length -= 128; + + // Check for a frame header + bool frame_ok = false; + if(length > 3) + { + if((BYTE)data[0] == 0xff && + ((data[1]&0xfe) == 0xfa/*MPEG-1*/ || (data[1]&0xfe) == 0xf2/*MPEG-2*/)) + { + int brate_idx = (data[2]>>4) & 0x0f; + int srate_idx = (data[2]>>2) & 0x03; + if(brate_idx != 0 && brate_idx != 15 && srate_idx != 3) + frame_ok = true; + } + } + + if(frame_ok) + { + MemData = data; + MemPos = 0; + MemLength = length; + + MPG123 = mpg123_new(NULL, NULL); + if(mpg123_replace_reader_handle(MPG123, mem_read, mem_lseek, NULL) == MPG123_OK && + mpg123_open_handle(MPG123, this) == MPG123_OK) + { + int enc, channels; + long srate; + + if(mpg123_getformat(MPG123, &srate, &channels, &enc) == MPG123_OK) + { + if((channels == 1 || channels == 2) && srate > 0 && + mpg123_format_none(MPG123) == MPG123_OK && + mpg123_format(MPG123, srate, channels, MPG123_ENC_SIGNED_16) == MPG123_OK) + { + // All OK + Done = false; + return true; + } + } + mpg123_close(MPG123); + } + mpg123_delete(MPG123); + MPG123 = 0; } - mpg123_delete(MPG123); - MPG123 = 0; return false; } diff --git a/src/sound/i_sound.cpp b/src/sound/i_sound.cpp index 7b66f9770f..6d8129aede 100644 --- a/src/sound/i_sound.cpp +++ b/src/sound/i_sound.cpp @@ -525,52 +525,11 @@ SoundDecoder *SoundRenderer::CreateDecoder(const BYTE *sfxdata, int length) { SoundDecoder *decoder = NULL; #ifdef HAVE_MPG123 - int mpg_start = -1; - int mpg_len = -1; - - // Check for an ID3 tag to identify an mp3 (and skip the tag) - if(length > 10 && memcmp(sfxdata, "ID3", 3) == 0 && - sfxdata[3] <= 4 && sfxdata[4] != 0xff && - (sfxdata[5]&0x0f) == 0 && (sfxdata[6]&0x80) == 0 && - (sfxdata[7]&0x80) == 0 && (sfxdata[8]&0x80) == 0 && - (sfxdata[9]&0x80) == 0) + decoder = new MPG123Decoder; + if(!decoder->open((const char*)sfxdata, length)) { - // ID3v2 - mpg_start = (sfxdata[6]<<21) | (sfxdata[7]<<14) | - (sfxdata[8]<< 7) | (sfxdata[9] ); - mpg_start += ((sfxdata[5]&0x10) ? 20 : 10); - mpg_len = length - mpg_start; - } - else if(length > 128 && memcmp(sfxdata+length-128, "TAG", 3) == 0) - { - // ID3v1 - mpg_start = 0; - mpg_len = length - 128; - } - else if(length > 3) - { - // No ID3 tag. Check for a frame header - if((sfxdata[0] == 0xff && sfxdata[1]>>1 == 0x7d) || // MPEG-1 - (sfxdata[0] == 0xff && sfxdata[1]>>1 == 0x79)) // MPEG-2 - { - int brate_idx = (sfxdata[2]>>4) & 0x0f; - int srate_idx = (sfxdata[2]>>2) & 0x03; - if(brate_idx != 0 && brate_idx != 15 && srate_idx != 3) - { - mpg_start = 0; - mpg_len = length; - } - } - } - - if(mpg_start >= 0 && mpg_len > 0 && mpg_start < length && mpg_len <= length-mpg_start) - { - decoder = new MPG123Decoder; - if(!decoder->open((const char*)sfxdata+mpg_start, mpg_len)) - { - delete decoder; - decoder = NULL; - } + delete decoder; + decoder = NULL; } #endif #ifdef HAVE_SNDFILE From b1c98acf33c962c7c05be1152fa1ae4bd5daaeb5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 19 Jun 2014 17:50:03 -0700 Subject: [PATCH 23/88] Close the file handle in the sndfile decoder --- src/sound/audio_sndfile_decoder.cpp | 16 ++++++++++------ src/sound/i_soundinternal.h | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/sound/audio_sndfile_decoder.cpp b/src/sound/audio_sndfile_decoder.cpp index dfb49b08c9..b71a41721e 100644 --- a/src/sound/audio_sndfile_decoder.cpp +++ b/src/sound/audio_sndfile_decoder.cpp @@ -145,6 +145,9 @@ SndFileDecoder::~SndFileDecoder() if(SndFile) sf_close(SndFile); SndFile = 0; + if(File) + fclose(File); + File = 0; } bool SndFileDecoder::open(const char *data, size_t length) @@ -157,14 +160,14 @@ bool SndFileDecoder::open(const char *data, size_t length) SndFile = sf_open_virtual(&sfio, SFM_READ, &SndInfo, this); if(SndFile) { - if(SndInfo.channels != 1 && SndInfo.channels != 2) - { - sf_close(SndFile); - SndFile = 0; - } + if(SndInfo.channels == 1 || SndInfo.channels == 2) + return true; + + sf_close(SndFile); + SndFile = 0; } - return SndFile != 0; + return false; } bool SndFileDecoder::open(const char *fname, size_t offset, size_t length) @@ -189,6 +192,7 @@ bool SndFileDecoder::open(const char *fname, size_t offset, size_t length) } } fclose(File); + File = 0; } return false; diff --git a/src/sound/i_soundinternal.h b/src/sound/i_soundinternal.h index 4351fe0fe7..2b3544521a 100644 --- a/src/sound/i_soundinternal.h +++ b/src/sound/i_soundinternal.h @@ -182,7 +182,7 @@ struct SndFileDecoder : public SoundDecoder virtual bool seek(size_t ms_offset); virtual size_t getSampleOffset(); - SndFileDecoder() : SndFile(0) { } + SndFileDecoder() : SndFile(0), File(0) { } virtual ~SndFileDecoder(); protected: From eeae36fbf7f1b980ed7abc47e7631ec679025e9a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 19 Jun 2014 17:53:37 -0700 Subject: [PATCH 24/88] Rename the decoder sources --- src/CMakeLists.txt | 4 ++-- src/sound/{audio_mpg123_decoder.cpp => mpg123_decoder.cpp} | 0 src/sound/{audio_sndfile_decoder.cpp => sndfile_decoder.cpp} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename src/sound/{audio_mpg123_decoder.cpp => mpg123_decoder.cpp} (100%) rename src/sound/{audio_sndfile_decoder.cpp => sndfile_decoder.cpp} (100%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 90e5be0fde..5b819f29e6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1044,11 +1044,10 @@ add_executable( zdoom WIN32 resourcefiles/file_directory.cpp resourcefiles/resourcefile.cpp sfmt/SFMT.cpp - sound/audio_mpg123_decoder.cpp - sound/audio_sndfile_decoder.cpp sound/fmodsound.cpp sound/i_music.cpp sound/i_sound.cpp + sound/mpg123_decoder.cpp sound/music_cd.cpp sound/music_dumb.cpp sound/music_gme.cpp @@ -1066,6 +1065,7 @@ add_executable( zdoom WIN32 sound/music_timidity_mididevice.cpp sound/music_win_mididevice.cpp sound/oalsound.cpp + sound/sndfile_decoder.cpp sound/music_pseudo_mididevice.cpp textures/animations.cpp textures/anim_switches.cpp diff --git a/src/sound/audio_mpg123_decoder.cpp b/src/sound/mpg123_decoder.cpp similarity index 100% rename from src/sound/audio_mpg123_decoder.cpp rename to src/sound/mpg123_decoder.cpp diff --git a/src/sound/audio_sndfile_decoder.cpp b/src/sound/sndfile_decoder.cpp similarity index 100% rename from src/sound/audio_sndfile_decoder.cpp rename to src/sound/sndfile_decoder.cpp From 1310a4a8146819ef5b45f1335c21942abf51575c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 19 Jun 2014 18:30:19 -0700 Subject: [PATCH 25/88] Fix libsndfile file handler --- src/sound/sndfile_decoder.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/sound/sndfile_decoder.cpp b/src/sound/sndfile_decoder.cpp index b71a41721e..d90e74abc9 100644 --- a/src/sound/sndfile_decoder.cpp +++ b/src/sound/sndfile_decoder.cpp @@ -12,8 +12,7 @@ sf_count_t SndFileDecoder::file_seek(sf_count_t offset, int whence, void *user_d SndFileDecoder *self = reinterpret_cast(user_data); long cur = ftell(self->File); - if(cur < 0 || (unsigned long)cur < self->FileLength) - return -1; + if(cur < 0) return -1; switch(whence) { @@ -51,8 +50,7 @@ sf_count_t SndFileDecoder::file_read(void *ptr, sf_count_t count, void *user_dat SndFileDecoder *self = reinterpret_cast(user_data); long cur = ftell(self->File); - if(cur < 0 || (unsigned long)cur < self->FileLength) - return -1; + if(cur < 0) return -1; cur -= self->FileOffset; if(count > (sf_count_t)(self->FileLength-cur)) @@ -172,7 +170,7 @@ bool SndFileDecoder::open(const char *data, size_t length) bool SndFileDecoder::open(const char *fname, size_t offset, size_t length) { - SF_VIRTUAL_IO sfio = { mem_get_filelen, mem_seek, mem_read, mem_write, mem_tell }; + SF_VIRTUAL_IO sfio = { file_get_filelen, file_seek, file_read, file_write, file_tell }; FileOffset = offset; FileLength = length; From 364065f1217eb6ca38817c7c3edfb80e35005ae2 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 19 Jun 2014 20:14:16 -0700 Subject: [PATCH 26/88] Handle file sources with mpg123 --- src/sound/i_sound.cpp | 8 ++ src/sound/i_soundinternal.h | 8 +- src/sound/mpg123_decoder.cpp | 147 +++++++++++++++++++++++++++++++++-- 3 files changed, 157 insertions(+), 6 deletions(-) diff --git a/src/sound/i_sound.cpp b/src/sound/i_sound.cpp index 6d8129aede..af23b34c4f 100644 --- a/src/sound/i_sound.cpp +++ b/src/sound/i_sound.cpp @@ -549,6 +549,14 @@ SoundDecoder *SoundRenderer::CreateDecoder(const BYTE *sfxdata, int length) SoundDecoder* SoundRenderer::CreateDecoder(const char *fname, int offset, int length) { SoundDecoder *decoder = NULL; +#ifdef HAVE_MPG123 + decoder = new MPG123Decoder; + if(!decoder->open(fname, offset, length)) + { + delete decoder; + decoder = NULL; + } +#endif #ifdef HAVE_SNDFILE decoder = new SndFileDecoder; if(!decoder->open(fname, offset, length)) diff --git a/src/sound/i_soundinternal.h b/src/sound/i_soundinternal.h index 2b3544521a..dd9fb35f8a 100644 --- a/src/sound/i_soundinternal.h +++ b/src/sound/i_soundinternal.h @@ -149,7 +149,7 @@ struct MPG123Decoder : public SoundDecoder virtual bool seek(size_t ms_offset); virtual size_t getSampleOffset(); - MPG123Decoder() : MPG123(0) { } + MPG123Decoder() : MPG123(0), File(0) { } virtual ~MPG123Decoder(); protected: @@ -160,6 +160,12 @@ private: mpg123_handle *MPG123; bool Done; + FILE *File; + size_t FileLength; + size_t FileOffset; + static off_t file_lseek(void *handle, off_t offset, int whence); + static ssize_t file_read(void *handle, void *buffer, size_t bytes); + const char *MemData; size_t MemLength; size_t MemPos; diff --git a/src/sound/mpg123_decoder.cpp b/src/sound/mpg123_decoder.cpp index 4cc1a813bc..bacb7df46a 100644 --- a/src/sound/mpg123_decoder.cpp +++ b/src/sound/mpg123_decoder.cpp @@ -4,6 +4,59 @@ static bool inited = false; +off_t MPG123Decoder::file_lseek(void *handle, off_t offset, int whence) +{ + MPG123Decoder *self = reinterpret_cast(handle); + + long cur = ftell(self->File); + if(cur < 0) return -1; + + switch(whence) + { + case SEEK_SET: + if(offset < 0 || offset > (off_t)self->FileLength) + return -1; + cur = offset; + break; + + case SEEK_CUR: + cur -= self->FileOffset; + if((offset > 0 && (off_t)(self->FileLength-cur) < offset) || + (offset < 0 && (off_t)cur < -offset)) + return -1; + cur += offset; + break; + + case SEEK_END: + if(offset > 0 || -offset > (off_t)self->FileLength) + return -1; + cur = self->FileLength + offset; + break; + + default: + return -1; + } + + if(fseek(self->File, cur + self->FileOffset, SEEK_SET) != 0) + return -1; + return cur; +} + +ssize_t MPG123Decoder::file_read(void *handle, void *buffer, size_t bytes) +{ + MPG123Decoder *self = reinterpret_cast(handle); + + long cur = ftell(self->File); + if(cur < 0) return -1; + + cur -= self->FileOffset; + if(bytes > (size_t)(self->FileLength-cur)) + bytes = self->FileLength-cur; + + return fread(buffer, 1, bytes, self->File); +} + + off_t MPG123Decoder::mem_lseek(void *handle, off_t offset, int whence) { MPG123Decoder *self = reinterpret_cast(handle); @@ -58,6 +111,9 @@ MPG123Decoder::~MPG123Decoder() mpg123_delete(MPG123); MPG123 = 0; } + if(File) + fclose(File); + File = 0; } bool MPG123Decoder::open(const char *data, size_t length) @@ -135,6 +191,92 @@ bool MPG123Decoder::open(const char *data, size_t length) return false; } +bool MPG123Decoder::open(const char *fname, size_t offset, size_t length) +{ + if(!inited) + { + if(mpg123_init() != MPG123_OK) + return false; + inited = true; + } + + FileLength = length; + FileOffset = offset; + File = fopen(fname, "rb"); + if(!File || fseek(File, FileOffset, SEEK_SET) != 0) + return false; + + char data[10]; + if(file_read(this, data, 10) != 10) + return false; + + // Check for ID3 tags and skip them + if(memcmp(data, "ID3", 3) == 0 && + (BYTE)data[3] <= 4 && (BYTE)data[4] != 0xff && + (data[5]&0x0f) == 0 && (data[6]&0x80) == 0 && + (data[7]&0x80) == 0 && (data[8]&0x80) == 0 && + (data[9]&0x80) == 0) + { + // ID3v2 + int start_offset; + start_offset = (data[6]<<21) | (data[7]<<14) | + (data[8]<< 7) | (data[9] ); + start_offset += ((data[5]&0x10) ? 20 : 10); + offset += start_offset; + length -= start_offset; + } + + if(file_lseek(this, -128, SEEK_END) > 0 && memcmp(data, "TAG", 3) == 0) // ID3v1 + length -= 128; + + FileLength = length; + FileOffset = offset; + if(file_lseek(this, 0, SEEK_SET) != 0) + return false; + + // Check for a frame header + bool frame_ok = false; + if(file_read(this, data, 3) != 3) + { + if((BYTE)data[0] == 0xff && + ((data[1]&0xfe) == 0xfa/*MPEG-1*/ || (data[1]&0xfe) == 0xf2/*MPEG-2*/)) + { + int brate_idx = (data[2]>>4) & 0x0f; + int srate_idx = (data[2]>>2) & 0x03; + if(brate_idx != 0 && brate_idx != 15 && srate_idx != 3) + frame_ok = (file_lseek(this, 0, SEEK_SET) == 0); + } + } + + if(frame_ok) + { + MPG123 = mpg123_new(NULL, NULL); + if(mpg123_replace_reader_handle(MPG123, file_read, file_lseek, NULL) == MPG123_OK && + mpg123_open_handle(MPG123, this) == MPG123_OK) + { + int enc, channels; + long srate; + + if(mpg123_getformat(MPG123, &srate, &channels, &enc) == MPG123_OK) + { + if((channels == 1 || channels == 2) && srate > 0 && + mpg123_format_none(MPG123) == MPG123_OK && + mpg123_format(MPG123, srate, channels, MPG123_ENC_SIGNED_16) == MPG123_OK) + { + // All OK + Done = false; + return true; + } + } + mpg123_close(MPG123); + } + mpg123_delete(MPG123); + MPG123 = 0; + } + + return false; +} + void MPG123Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) { int enc = 0, channels = 0; @@ -173,11 +315,6 @@ size_t MPG123Decoder::read(char *buffer, size_t bytes) return amt; } -bool MPG123Decoder::open(const char *fname, size_t offset, size_t length) -{ - return false; -} - bool MPG123Decoder::seek(size_t ms_offset) { int enc, channels; From e39165655da2e06612e2818bf0aa8aff93be9332 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 19 Jun 2014 21:51:16 -0700 Subject: [PATCH 27/88] Don't call the sfx volume cvar callback in the OpenALSoundRenderer constructor I_InitSound already does that after creating it. --- src/sound/oalsound.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 66c80faf27..34c68591e4 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -796,8 +796,6 @@ OpenALSoundRenderer::OpenALSoundRenderer() if(EnvSlot) Printf(" EFX enabled\n"); - - snd_sfxvolume.Callback(); } OpenALSoundRenderer::~OpenALSoundRenderer() From 07a50c604e34d1808ecce5b34def000dae6d5a60 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 19 Jun 2014 22:13:20 -0700 Subject: [PATCH 28/88] Use the correct formatter type --- src/sound/oalsound.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 34c68591e4..aaaca9ebb3 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -706,7 +706,7 @@ OpenALSoundRenderer::OpenALSoundRenderer() Device = NULL; return; } - DPrintf(" Allocated "TEXTCOLOR_BLUE"%u"TEXTCOLOR_NORMAL" sources\n", Sources.size()); + DPrintf(" Allocated "TEXTCOLOR_BLUE"%zu"TEXTCOLOR_NORMAL" sources\n", Sources.size()); WasInWater = false; if(*snd_efx && alcIsExtensionPresent(Device, "ALC_EXT_EFX")) From 73d8659f231fd6cae35fd68af4aefee8bdaabc3c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 19 Jun 2014 22:21:05 -0700 Subject: [PATCH 29/88] Remove an unnecessary cast --- src/sound/oalsound.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index aaaca9ebb3..06dc6f911d 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -851,7 +851,7 @@ void OpenALSoundRenderer::SetSfxVolume(float volume) alSourcef(source, AL_MAX_GAIN, volume); if(schan->ManualGain) volume *= GetRolloff(&schan->Rolloff, sqrt(schan->DistanceSqr)); - alSourcef(source, AL_GAIN, volume * ((FSoundChan*)schan)->Volume); + alSourcef(source, AL_GAIN, volume * schan->Volume); } schan = schan->NextChan; } From a661797aa87d19e6346fb4cdb8ec6a4d87fa4257 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 19 Jun 2014 22:31:19 -0700 Subject: [PATCH 30/88] Be less noisey about loop points --- src/sound/oalsound.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 06dc6f911d..166afb25c7 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -961,7 +961,7 @@ SoundHandle OpenALSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int length, int fre loopend = length / (channels*bits/8); ALint loops[2] = { loopstart, loopend }; - Printf("Setting loop points %d -> %d\n", loops[0], loops[1]); + DPrintf("Setting loop points %d -> %d\n", loops[0], loops[1]); alBufferiv(buffer, AL_LOOP_POINTS_SOFT, loops); getALError(); } From 72ddc0d935c588e26dbbfa7cab32a3f7c389f41b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 19 Jun 2014 22:33:39 -0700 Subject: [PATCH 31/88] Remove a non-existent friend class --- src/sound/oalsound.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sound/oalsound.h b/src/sound/oalsound.h index 5b0345f568..2931e75316 100644 --- a/src/sound/oalsound.h +++ b/src/sound/oalsound.h @@ -198,7 +198,6 @@ private: std::vector Streams; friend class OpenALSoundStream; - friend class OpenALCallbackStream; }; #endif // NO_OPENAL From 9f493fca5ff6dad77739362ea676082e5ec7316e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 19 Jun 2014 22:40:45 -0700 Subject: [PATCH 32/88] Move the generic DecodeSample implementation to the base class --- src/sound/i_sound.cpp | 21 +++++++++++++++++++-- src/sound/oalsound.cpp | 20 -------------------- src/sound/oalsound.h | 2 -- 3 files changed, 19 insertions(+), 24 deletions(-) diff --git a/src/sound/i_sound.cpp b/src/sound/i_sound.cpp index af23b34c4f..b533ff2dd0 100644 --- a/src/sound/i_sound.cpp +++ b/src/sound/i_sound.cpp @@ -48,6 +48,7 @@ extern HINSTANCE g_hInst; #include #include #include +#include #include "doomtype.h" #include @@ -338,9 +339,25 @@ FString SoundRenderer::GatherStats () return "No stats for this sound renderer."; } -short *SoundRenderer::DecodeSample(int outlen, const void *coded, int sizebytes, ECodecType type) +short *SoundRenderer::DecodeSample(int outlen, const void *coded, int sizebytes, ECodecType ctype) { - return NULL; + short *samples = (short*)calloc(1, outlen); + ChannelConfig chans; + SampleType type; + int srate; + + std::auto_ptr decoder(CreateDecoder((const BYTE*)coded, sizebytes)); + if(!decoder.get()) return samples; + + decoder->getInfo(&srate, &chans, &type); + if(chans != ChannelConfig_Mono || type != SampleType_Int16) + { + DPrintf("Sample is not 16-bit mono\n"); + return samples; + } + + decoder->read((char*)samples, outlen); + return samples; } void SoundRenderer::DrawWaveDebug(int mode) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 166afb25c7..5383d34b1c 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -1053,26 +1053,6 @@ void OpenALSoundRenderer::UnloadSound(SoundHandle sfx) delete ((ALuint*)sfx.data); } -short *OpenALSoundRenderer::DecodeSample(int outlen, const void *coded, int sizebytes, ECodecType ctype) -{ - char *samples = (char*)calloc(1, outlen); - ChannelConfig chans; - SampleType type; - int srate; - - std::auto_ptr decoder(CreateDecoder((const BYTE*)coded, sizebytes)); - if(!decoder.get()) return (short*)samples; - - decoder->getInfo(&srate, &chans, &type); - if(chans != ChannelConfig_Mono || type != SampleType_Int16) - { - DPrintf("Sample is not 16-bit mono\n"); - return (short*)samples; - } - - decoder->read(samples, outlen); - return (short*)samples; -} SoundStream *OpenALSoundRenderer::CreateStream(SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata) { diff --git a/src/sound/oalsound.h b/src/sound/oalsound.h index 2931e75316..3c3771358d 100644 --- a/src/sound/oalsound.h +++ b/src/sound/oalsound.h @@ -112,8 +112,6 @@ public: virtual void UpdateListener(SoundListener *); virtual void UpdateSounds(); - virtual short *DecodeSample(int outlen, const void *coded, int sizebytes, ECodecType type); - virtual void MarkStartTime(FISoundChannel*); virtual float GetAudibility(FISoundChannel*); From e2708c8b3e056d8bf39e79035721ab7d900d743d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 19 Jun 2014 22:46:46 -0700 Subject: [PATCH 33/88] Cleanup creating decoders --- src/sound/i_sound.cpp | 45 ++++++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/src/sound/i_sound.cpp b/src/sound/i_sound.cpp index b533ff2dd0..88cece9d44 100644 --- a/src/sound/i_sound.cpp +++ b/src/sound/i_sound.cpp @@ -543,22 +543,19 @@ SoundDecoder *SoundRenderer::CreateDecoder(const BYTE *sfxdata, int length) SoundDecoder *decoder = NULL; #ifdef HAVE_MPG123 decoder = new MPG123Decoder; - if(!decoder->open((const char*)sfxdata, length)) - { - delete decoder; - decoder = NULL; - } + if(decoder->open((const char*)sfxdata, length)) + return decoder; + + delete decoder; + decoder = NULL; #endif #ifdef HAVE_SNDFILE - if(!decoder) - { - decoder = new SndFileDecoder; - if(!decoder->open((const char*)sfxdata, length)) - { - delete decoder; - decoder = NULL; - } - } + decoder = new SndFileDecoder; + if(decoder->open((const char*)sfxdata, length)) + return decoder; + + delete decoder; + decoder = NULL; #endif return decoder; } @@ -568,19 +565,19 @@ SoundDecoder* SoundRenderer::CreateDecoder(const char *fname, int offset, int le SoundDecoder *decoder = NULL; #ifdef HAVE_MPG123 decoder = new MPG123Decoder; - if(!decoder->open(fname, offset, length)) - { - delete decoder; - decoder = NULL; - } + if(decoder->open(fname, offset, length)) + return decoder; + + delete decoder; + decoder = NULL; #endif #ifdef HAVE_SNDFILE decoder = new SndFileDecoder; - if(!decoder->open(fname, offset, length)) - { - delete decoder; - decoder = NULL; - } + if(decoder->open(fname, offset, length)) + return decoder; + + delete decoder; + decoder = NULL; #endif return decoder; } From 4f6861d7984d1737103f64fa00aab77d9c4e0667 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 19 Jun 2014 23:03:13 -0700 Subject: [PATCH 34/88] Move specific decoder classes to separate headers --- src/sound/i_sound.cpp | 3 ++ src/sound/i_soundinternal.h | 84 ----------------------------------- src/sound/mpg123_decoder.cpp | 2 +- src/sound/mpg123_decoder.h | 48 ++++++++++++++++++++ src/sound/sndfile_decoder.cpp | 2 +- src/sound/sndfile_decoder.h | 55 +++++++++++++++++++++++ 6 files changed, 108 insertions(+), 86 deletions(-) create mode 100644 src/sound/mpg123_decoder.h create mode 100644 src/sound/sndfile_decoder.h diff --git a/src/sound/i_sound.cpp b/src/sound/i_sound.cpp index 88cece9d44..ec20711067 100644 --- a/src/sound/i_sound.cpp +++ b/src/sound/i_sound.cpp @@ -56,6 +56,9 @@ extern HINSTANCE g_hInst; #include "fmodsound.h" #include "oalsound.h" +#include "mpg123_decoder.h" +#include "sndfile_decoder.h" + #include "m_swap.h" #include "stats.h" #include "files.h" diff --git a/src/sound/i_soundinternal.h b/src/sound/i_soundinternal.h index dd9fb35f8a..14dadf3e2c 100644 --- a/src/sound/i_soundinternal.h +++ b/src/sound/i_soundinternal.h @@ -139,88 +139,4 @@ private: SoundDecoder& operator=(const SoundDecoder &rhs); }; -#ifdef HAVE_MPG123 -#include "mpg123.h" -struct MPG123Decoder : public SoundDecoder -{ - virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type); - - virtual size_t read(char *buffer, size_t bytes); - virtual bool seek(size_t ms_offset); - virtual size_t getSampleOffset(); - - MPG123Decoder() : MPG123(0), File(0) { } - virtual ~MPG123Decoder(); - -protected: - virtual bool open(const char *data, size_t length); - virtual bool open(const char *fname, size_t offset, size_t length); - -private: - mpg123_handle *MPG123; - bool Done; - - FILE *File; - size_t FileLength; - size_t FileOffset; - static off_t file_lseek(void *handle, off_t offset, int whence); - static ssize_t file_read(void *handle, void *buffer, size_t bytes); - - const char *MemData; - size_t MemLength; - size_t MemPos; - static off_t mem_lseek(void *handle, off_t offset, int whence); - static ssize_t mem_read(void *handle, void *buffer, size_t bytes); - - // Make non-copyable - MPG123Decoder(const MPG123Decoder &rhs); - MPG123Decoder& operator=(const MPG123Decoder &rhs); -}; -#endif -#ifdef HAVE_SNDFILE -#include "sndfile.h" -struct SndFileDecoder : public SoundDecoder -{ - virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type); - - virtual size_t read(char *buffer, size_t bytes); - virtual std::vector readAll(); - virtual bool seek(size_t ms_offset); - virtual size_t getSampleOffset(); - - SndFileDecoder() : SndFile(0), File(0) { } - virtual ~SndFileDecoder(); - -protected: - virtual bool open(const char *data, size_t length); - virtual bool open(const char *fname, size_t offset, size_t length); - -private: - SNDFILE *SndFile; - SF_INFO SndInfo; - - FILE *File; - size_t FileLength; - size_t FileOffset; - static sf_count_t file_get_filelen(void *user_data); - static sf_count_t file_seek(sf_count_t offset, int whence, void *user_data); - static sf_count_t file_read(void *ptr, sf_count_t count, void *user_data); - static sf_count_t file_write(const void *ptr, sf_count_t count, void *user_data); - static sf_count_t file_tell(void *user_data); - - const char *MemData; - size_t MemLength; - size_t MemPos; - static sf_count_t mem_get_filelen(void *user_data); - static sf_count_t mem_seek(sf_count_t offset, int whence, void *user_data); - static sf_count_t mem_read(void *ptr, sf_count_t count, void *user_data); - static sf_count_t mem_write(const void *ptr, sf_count_t count, void *user_data); - static sf_count_t mem_tell(void *user_data); - - // Make non-copyable - SndFileDecoder(const SndFileDecoder &rhs); - SndFileDecoder& operator=(const SndFileDecoder &rhs); -}; -#endif - #endif diff --git a/src/sound/mpg123_decoder.cpp b/src/sound/mpg123_decoder.cpp index bacb7df46a..c3a811b407 100644 --- a/src/sound/mpg123_decoder.cpp +++ b/src/sound/mpg123_decoder.cpp @@ -1,4 +1,4 @@ -#include "i_soundinternal.h" +#include "mpg123_decoder.h" #ifdef HAVE_MPG123 static bool inited = false; diff --git a/src/sound/mpg123_decoder.h b/src/sound/mpg123_decoder.h new file mode 100644 index 0000000000..216eae2f94 --- /dev/null +++ b/src/sound/mpg123_decoder.h @@ -0,0 +1,48 @@ +#ifndef MPG123_DECODER_H +#define MPG123_DECODER_H + +#include "i_soundinternal.h" + +#ifdef HAVE_MPG123 + +#include "mpg123.h" + +struct MPG123Decoder : public SoundDecoder +{ + virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type); + + virtual size_t read(char *buffer, size_t bytes); + virtual bool seek(size_t ms_offset); + virtual size_t getSampleOffset(); + + MPG123Decoder() : MPG123(0), File(0) { } + virtual ~MPG123Decoder(); + +protected: + virtual bool open(const char *data, size_t length); + virtual bool open(const char *fname, size_t offset, size_t length); + +private: + mpg123_handle *MPG123; + bool Done; + + FILE *File; + size_t FileLength; + size_t FileOffset; + static off_t file_lseek(void *handle, off_t offset, int whence); + static ssize_t file_read(void *handle, void *buffer, size_t bytes); + + const char *MemData; + size_t MemLength; + size_t MemPos; + static off_t mem_lseek(void *handle, off_t offset, int whence); + static ssize_t mem_read(void *handle, void *buffer, size_t bytes); + + // Make non-copyable + MPG123Decoder(const MPG123Decoder &rhs); + MPG123Decoder& operator=(const MPG123Decoder &rhs); +}; + +#endif + +#endif /* MPG123_DECODER_H */ diff --git a/src/sound/sndfile_decoder.cpp b/src/sound/sndfile_decoder.cpp index d90e74abc9..534cf343fb 100644 --- a/src/sound/sndfile_decoder.cpp +++ b/src/sound/sndfile_decoder.cpp @@ -1,4 +1,4 @@ -#include "i_soundinternal.h" +#include "sndfile_decoder.h" #ifdef HAVE_SNDFILE sf_count_t SndFileDecoder::file_get_filelen(void *user_data) diff --git a/src/sound/sndfile_decoder.h b/src/sound/sndfile_decoder.h new file mode 100644 index 0000000000..ec59af98f2 --- /dev/null +++ b/src/sound/sndfile_decoder.h @@ -0,0 +1,55 @@ +#ifndef SNDFILE_DECODER_H +#define SNDFILE_DECODER_H + +#include "i_soundinternal.h" + +#ifdef HAVE_SNDFILE + +#include "sndfile.h" + +struct SndFileDecoder : public SoundDecoder +{ + virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type); + + virtual size_t read(char *buffer, size_t bytes); + virtual std::vector readAll(); + virtual bool seek(size_t ms_offset); + virtual size_t getSampleOffset(); + + SndFileDecoder() : SndFile(0), File(0) { } + virtual ~SndFileDecoder(); + +protected: + virtual bool open(const char *data, size_t length); + virtual bool open(const char *fname, size_t offset, size_t length); + +private: + SNDFILE *SndFile; + SF_INFO SndInfo; + + FILE *File; + size_t FileLength; + size_t FileOffset; + static sf_count_t file_get_filelen(void *user_data); + static sf_count_t file_seek(sf_count_t offset, int whence, void *user_data); + static sf_count_t file_read(void *ptr, sf_count_t count, void *user_data); + static sf_count_t file_write(const void *ptr, sf_count_t count, void *user_data); + static sf_count_t file_tell(void *user_data); + + const char *MemData; + size_t MemLength; + size_t MemPos; + static sf_count_t mem_get_filelen(void *user_data); + static sf_count_t mem_seek(sf_count_t offset, int whence, void *user_data); + static sf_count_t mem_read(void *ptr, sf_count_t count, void *user_data); + static sf_count_t mem_write(const void *ptr, sf_count_t count, void *user_data); + static sf_count_t mem_tell(void *user_data); + + // Make non-copyable + SndFileDecoder(const SndFileDecoder &rhs); + SndFileDecoder& operator=(const SndFileDecoder &rhs); +}; + +#endif + +#endif /* SNDFILE_DECODER_H */ From 0f234fb36dc29af4e37111f990901c6a0870c49f Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 19 Jun 2014 23:10:36 -0700 Subject: [PATCH 35/88] Remove an unused function --- src/sound/oalsound.cpp | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 5383d34b1c..f51796d7ec 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -550,39 +550,6 @@ static float GetRolloff(const FRolloffInfo *rolloff, float distance) } -static ALenum FormatFromDesc(int bits, int channels) -{ - if(bits == 8) - { - if(channels == 1) return AL_FORMAT_MONO8; - if(channels == 2) return AL_FORMAT_STEREO8; - if(channels == 4) return AL_FORMAT_QUAD8; - if(channels == 6) return AL_FORMAT_51CHN8; - if(channels == 7) return AL_FORMAT_61CHN8; - if(channels == 8) return AL_FORMAT_71CHN8; - } - if(bits == 16) - { - if(channels == 1) return AL_FORMAT_MONO16; - if(channels == 2) return AL_FORMAT_STEREO16; - if(channels == 4) return AL_FORMAT_QUAD16; - if(channels == 6) return AL_FORMAT_51CHN16; - if(channels == 7) return AL_FORMAT_61CHN16; - if(channels == 8) return AL_FORMAT_71CHN16; - } - if(bits == 32) - { - if(channels == 1) return AL_FORMAT_MONO_FLOAT32; - if(channels == 2) return AL_FORMAT_STEREO_FLOAT32; - if(channels == 4) return AL_FORMAT_QUAD32; - if(channels == 6) return AL_FORMAT_51CHN32; - if(channels == 7) return AL_FORMAT_61CHN32; - if(channels == 8) return AL_FORMAT_71CHN32; - } - return AL_NONE; -} - - template static void LoadALFunc(const char *name, T *x) { *x = reinterpret_cast(alGetProcAddress(name)); } From 42fdc3c0593682288f296fa5da1bd68fe37a9649 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 19 Jun 2014 23:49:46 -0700 Subject: [PATCH 36/88] Use structs to store available extensions --- src/sound/oalsound.cpp | 25 ++++++++++++------------- src/sound/oalsound.h | 13 +++++++++---- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index f51796d7ec..492357fc2e 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -555,8 +555,7 @@ static void LoadALFunc(const char *name, T *x) { *x = reinterpret_cast(alGetProcAddress(name)); } OpenALSoundRenderer::OpenALSoundRenderer() - : Device(NULL), Context(NULL), SrcDistanceModel(false), SFXPaused(0), - PrevEnvironment(NULL), EnvSlot(0) + : Device(NULL), Context(NULL), SFXPaused(0), PrevEnvironment(NULL), EnvSlot(0) { EnvFilters[0] = EnvFilters[1] = 0; @@ -592,8 +591,6 @@ OpenALSoundRenderer::OpenALSoundRenderer() DPrintf(" ALC Version: "TEXTCOLOR_BLUE"%d.%d\n", major, minor); DPrintf(" ALC Extensions: "TEXTCOLOR_ORANGE"%s\n", alcGetString(Device, ALC_EXTENSIONS)); - DisconnectNotify = alcIsExtensionPresent(Device, "ALC_EXT_disconnect"); - std::vector attribs; if(*snd_samplerate > 0) { @@ -627,13 +624,15 @@ OpenALSoundRenderer::OpenALSoundRenderer() DPrintf(" Version: "TEXTCOLOR_ORANGE"%s\n", alGetString(AL_VERSION)); DPrintf(" Extensions: "TEXTCOLOR_ORANGE"%s\n", alGetString(AL_EXTENSIONS)); - SrcDistanceModel = alIsExtensionPresent("AL_EXT_source_distance_model"); - LoopPoints = alIsExtensionPresent("AL_SOFT_loop_points"); + ALC.EXT_EFX = alcIsExtensionPresent(Device, "ALC_EXT_EFX"); + ALC.EXT_disconnect = alcIsExtensionPresent(Device, "ALC_EXT_disconnect");; + AL.EXT_source_distance_model = alIsExtensionPresent("AL_EXT_source_distance_model"); + AL.SOFT_loop_points = alIsExtensionPresent("AL_SOFT_loop_points"); alDopplerFactor(0.5f); alSpeedOfSound(343.3f * 96.0f); alDistanceModel(AL_INVERSE_DISTANCE); - if(SrcDistanceModel) + if(AL.EXT_source_distance_model) alEnable(AL_SOURCE_DISTANCE_MODEL); ALenum err = getALError(); @@ -676,7 +675,7 @@ OpenALSoundRenderer::OpenALSoundRenderer() DPrintf(" Allocated "TEXTCOLOR_BLUE"%zu"TEXTCOLOR_NORMAL" sources\n", Sources.size()); WasInWater = false; - if(*snd_efx && alcIsExtensionPresent(Device, "ALC_EXT_EFX")) + if(*snd_efx && ALC.EXT_EFX) { // EFX function pointers #define LOAD_FUNC(x) (LoadALFunc(#x, &x)) @@ -920,7 +919,7 @@ SoundHandle OpenALSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int length, int fre return retval; } - if((loopstart > 0 || loopend > 0) && LoopPoints) + if((loopstart > 0 || loopend > 0) && AL.SOFT_loop_points) { if(loopstart < 0) loopstart = 0; @@ -1176,7 +1175,7 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener { if(rolloff->RolloffType == ROLLOFF_Log) { - if(SrcDistanceModel) + if(AL.EXT_source_distance_model) alSourcei(source, AL_DISTANCE_MODEL, AL_INVERSE_DISTANCE); alSourcef(source, AL_REFERENCE_DISTANCE, rolloff->MinDistance/distscale); alSourcef(source, AL_MAX_DISTANCE, (1000.f+rolloff->MinDistance)/distscale); @@ -1184,7 +1183,7 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener manualGain = false; gain = 1.f; } - else if(rolloff->RolloffType == ROLLOFF_Linear && SrcDistanceModel) + else if(rolloff->RolloffType == ROLLOFF_Linear && AL.EXT_source_distance_model) { alSourcei(source, AL_DISTANCE_MODEL, AL_LINEAR_DISTANCE); alSourcef(source, AL_REFERENCE_DISTANCE, rolloff->MinDistance/distscale); @@ -1196,7 +1195,7 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener } if(manualGain) { - if(SrcDistanceModel) + if(AL.EXT_source_distance_model) alSourcei(source, AL_DISTANCE_MODEL, AL_NONE); if((chanflags&SNDF_AREA) && rolloff->MinDistance < 32.f) alSourcef(source, AL_REFERENCE_DISTANCE, 32.f/distscale); @@ -1532,7 +1531,7 @@ void OpenALSoundRenderer::UpdateSounds() foreach(SoundStream*, stream, Streams) (*stream)->IsEnded(); - if(DisconnectNotify) + if(ALC.EXT_disconnect) { ALCint connected = ALC_TRUE; alcGetIntegerv(Device, ALC_CONNECTED, 1, &connected); diff --git a/src/sound/oalsound.h b/src/sound/oalsound.h index 3c3771358d..db559ebb70 100644 --- a/src/sound/oalsound.h +++ b/src/sound/oalsound.h @@ -122,6 +122,15 @@ public: virtual FString GatherStats(); private: + struct { + bool EXT_EFX; + bool EXT_disconnect; + } ALC; + struct { + bool EXT_source_distance_model; + bool SOFT_loop_points; + } AL; + // EFX Extension function pointer variables. Loaded after context creation // if EFX is supported. These pointers may be context- or device-dependant, // thus can't be static @@ -170,10 +179,6 @@ private: ALCdevice *Device; ALCcontext *Context; - bool LoopPoints; - bool SrcDistanceModel; - bool DisconnectNotify; - std::vector Sources; ALfloat SfxVolume; From 906b828d877b14efa2fc10570d10a3a3b5167c8b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 20 Jun 2014 00:41:19 -0700 Subject: [PATCH 37/88] Partially implement OpenALSoundRenderer::SetInactive --- src/sound/oalsound.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 492357fc2e..f058a53a64 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -1350,8 +1350,20 @@ void OpenALSoundRenderer::SetSfxPaused(bool paused, int slot) } } -void OpenALSoundRenderer::SetInactive(SoundRenderer::EInactiveState) +void OpenALSoundRenderer::SetInactive(SoundRenderer::EInactiveState state) { + switch(state) + { + case SoundRenderer::INACTIVE_Active: + alListenerf(AL_GAIN, 1.0f); + break; + + /* FIXME: This doesn't stop anything. */ + case SoundRenderer::INACTIVE_Complete: + case SoundRenderer::INACTIVE_Mute: + alListenerf(AL_GAIN, 0.0f); + break; + } } void OpenALSoundRenderer::Sync(bool sync) From fb07f7ef076dae6fd4f3c2da7742a536d72ce7fc Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 20 Jun 2014 01:12:47 -0700 Subject: [PATCH 38/88] Cast OpenAL IDs to/from void* --- src/sound/oalsound.cpp | 50 ++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index f058a53a64..64fb24ff03 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -95,6 +95,9 @@ EXTERN_CVAR (Bool, snd_waterreverb) EXTERN_CVAR (Bool, snd_pitched) +#define MAKE_PTRID(x) ((void*)(uintptr_t)(x)) +#define GET_PTRID(x) ((uint32)(uintptr_t)(x)) + #define foreach(type, name, vec) \ for(std::vector::iterator (name) = (vec).begin(), \ (_end_##name) = (vec).end(); \ @@ -810,7 +813,7 @@ void OpenALSoundRenderer::SetSfxVolume(float volume) { if(schan->SysChannel != NULL) { - ALuint source = *((ALuint*)schan->SysChannel); + ALuint source = GET_PTRID(schan->SysChannel); volume = SfxVolume; alcSuspendContext(Context); @@ -836,7 +839,7 @@ unsigned int OpenALSoundRenderer::GetMSLength(SoundHandle sfx) { if(sfx.data) { - ALuint buffer = *((ALuint*)sfx.data); + ALuint buffer = GET_PTRID(sfx.data); if(alIsBuffer(buffer)) { ALint bits, channels, freq, size; @@ -855,7 +858,7 @@ unsigned int OpenALSoundRenderer::GetSampleLength(SoundHandle sfx) { if(sfx.data) { - ALuint buffer = *((ALuint*)sfx.data); + ALuint buffer = GET_PTRID(sfx.data); ALint bits, channels, size; alGetBufferi(buffer, AL_BITS, &bits); alGetBufferi(buffer, AL_CHANNELS, &channels); @@ -939,7 +942,7 @@ SoundHandle OpenALSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int length, int fre warned = true; } - retval.data = new ALuint(buffer); + retval.data = MAKE_PTRID(buffer); return retval; } @@ -987,7 +990,7 @@ SoundHandle OpenALSoundRenderer::LoadSound(BYTE *sfxdata, int length) return retval; } - retval.data = new ALuint(buffer); + retval.data = MAKE_PTRID(buffer); return retval; } @@ -996,14 +999,15 @@ void OpenALSoundRenderer::UnloadSound(SoundHandle sfx) if(!sfx.data) return; + ALuint buffer = GET_PTRID(sfx.data); FSoundChan *schan = Channels; while(schan) { if(schan->SysChannel) { ALint bufID = 0; - alGetSourcei(*((ALuint*)schan->SysChannel), AL_BUFFER, &bufID); - if(bufID == *((ALint*)sfx.data)) + alGetSourcei(GET_PTRID(schan->SysChannel), AL_BUFFER, &bufID); + if((ALuint)bufID == buffer) { FSoundChan *next = schan->NextChan; StopChannel(schan); @@ -1014,9 +1018,8 @@ void OpenALSoundRenderer::UnloadSound(SoundHandle sfx) schan = schan->NextChan; } - alDeleteBuffers(1, ((ALuint*)sfx.data)); + alDeleteBuffers(1, &buffer); getALError(); - delete ((ALuint*)sfx.data); } @@ -1052,8 +1055,8 @@ FISoundChannel *OpenALSoundRenderer::StartSound(SoundHandle sfx, float vol, int return NULL; } - ALuint buffer = *((ALuint*)sfx.data); - ALuint &source = *std::find(Sources.begin(), Sources.end(), FreeSfx.back()); + ALuint buffer = GET_PTRID(sfx.data); + ALuint source = FreeSfx.back(); alSource3f(source, AL_POSITION, 0.f, 0.f, 0.f); alSource3f(source, AL_VELOCITY, 0.f, 0.f, 0.f); alSource3f(source, AL_DIRECTION, 0.f, 0.f, 0.f); @@ -1120,8 +1123,8 @@ FISoundChannel *OpenALSoundRenderer::StartSound(SoundHandle sfx, float vol, int FreeSfx.pop_back(); FISoundChannel *chan = reuse_chan; - if(!chan) chan = S_GetChannel(&source); - else chan->SysChannel = &source; + if(!chan) chan = S_GetChannel(MAKE_PTRID(source)); + else chan->SysChannel = MAKE_PTRID(source); chan->Rolloff.RolloffType = ROLLOFF_Linear; chan->Rolloff.MaxDistance = 1000.f; @@ -1156,11 +1159,11 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener float rolloffFactor, gain; bool manualGain = true; - ALuint buffer = *((ALuint*)sfx.data); + ALuint buffer = GET_PTRID(sfx.data); ALint channels = 1; alGetBufferi(buffer, AL_CHANNELS, &channels); - ALuint &source = *std::find(Sources.begin(), Sources.end(), FreeSfx.back()); + ALuint source = FreeSfx.back(); alSource3f(source, AL_POSITION, pos[0], pos[1], -pos[2]); alSource3f(source, AL_VELOCITY, vel[0], vel[1], -vel[2]); alSource3f(source, AL_DIRECTION, 0.f, 0.f, 0.f); @@ -1262,8 +1265,8 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener FreeSfx.pop_back(); FISoundChannel *chan = reuse_chan; - if(!chan) chan = S_GetChannel(&source); - else chan->SysChannel = &source; + if(!chan) chan = S_GetChannel(MAKE_PTRID(source)); + else chan->SysChannel = MAKE_PTRID(source); chan->Rolloff = *rolloff; chan->DistanceScale = distscale; @@ -1280,8 +1283,7 @@ void OpenALSoundRenderer::ChannelVolume(FISoundChannel *chan, float volume) alcSuspendContext(Context); - ALuint source = *((ALuint*)chan->SysChannel); - + ALuint source = GET_PTRID(chan->SysChannel); if(chan->ManualGain) volume *= GetRolloff(&chan->Rolloff, sqrt(chan->DistanceSqr)); alSourcef(source, AL_GAIN, SfxVolume * volume); @@ -1292,7 +1294,7 @@ void OpenALSoundRenderer::StopChannel(FISoundChannel *chan) if(chan == NULL || chan->SysChannel == NULL) return; - ALuint source = *((ALuint*)chan->SysChannel); + ALuint source = GET_PTRID(chan->SysChannel); // Release first, so it can be properly marked as evicted if it's being // forcefully killed S_ChannelEnded(chan); @@ -1318,7 +1320,7 @@ unsigned int OpenALSoundRenderer::GetPosition(FISoundChannel *chan) return 0; ALint pos; - alGetSourcei(*((ALuint*)chan->SysChannel), AL_SAMPLE_OFFSET, &pos); + alGetSourcei(GET_PTRID(chan->SysChannel), AL_SAMPLE_OFFSET, &pos); if(getALError() == AL_NO_ERROR) return pos; return 0; @@ -1409,7 +1411,7 @@ void OpenALSoundRenderer::UpdateSoundParams3D(SoundListener *listener, FISoundCh alcSuspendContext(Context); - ALuint source = *((ALuint*)chan->SysChannel); + ALuint source = GET_PTRID(chan->SysChannel); alSource3f(source, AL_POSITION, pos[0], pos[1], -pos[2]); alSource3f(source, AL_VELOCITY, vel[0], vel[1], -vel[2]); @@ -1576,7 +1578,7 @@ float OpenALSoundRenderer::GetAudibility(FISoundChannel *chan) if(chan == NULL || chan->SysChannel == NULL) return 0.f; - ALuint source = *((ALuint*)chan->SysChannel); + ALuint source = GET_PTRID(chan->SysChannel); ALfloat volume = 0.f; if(!chan->ManualGain) @@ -1691,7 +1693,7 @@ void OpenALSoundRenderer::PurgeStoppedSources() FSoundChan *schan = Channels; while(schan) { - if(schan->SysChannel != NULL && *i == *((ALuint*)schan->SysChannel)) + if(schan->SysChannel != NULL && *i == GET_PTRID(schan->SysChannel)) { StopChannel(schan); break; From ef7ce41d0786c8c56b1cca7e5e4317fefa593ca8 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 20 Jun 2014 01:17:48 -0700 Subject: [PATCH 39/88] Don't purge sources in an initial state --- src/sound/oalsound.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 64fb24ff03..d62439506c 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -1685,9 +1685,9 @@ void OpenALSoundRenderer::PurgeStoppedSources() // Release channels that are stopped foreach(ALuint, i, SfxGroup) { - ALint state = AL_PLAYING; + ALint state = AL_INITIAL; alGetSourcei(*i, AL_SOURCE_STATE, &state); - if(state == AL_PLAYING || state == AL_PAUSED) + if(state == AL_INITIAL || state == AL_PLAYING || state == AL_PAUSED) continue; FSoundChan *schan = Channels; From f0c9aae6706c770327788599739e50eb992850ad Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 20 Jun 2014 04:38:48 -0700 Subject: [PATCH 40/88] Rework manual rolloff handling For distance models OpenAL doesn't handle, alter the source's distance to get the appropriate attenuation instead of the source's gain. --- src/sound/i_soundinternal.h | 2 +- src/sound/oalsound.cpp | 169 +++++++++++++++++++----------------- 2 files changed, 92 insertions(+), 79 deletions(-) diff --git a/src/sound/i_soundinternal.h b/src/sound/i_soundinternal.h index 14dadf3e2c..64e065b6ee 100644 --- a/src/sound/i_soundinternal.h +++ b/src/sound/i_soundinternal.h @@ -101,7 +101,7 @@ struct FISoundChannel FRolloffInfo Rolloff; float DistanceScale; float DistanceSqr; - bool ManualGain; + bool ManualRolloff; }; diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index d62439506c..571345f237 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -818,8 +818,6 @@ void OpenALSoundRenderer::SetSfxVolume(float volume) alcSuspendContext(Context); alSourcef(source, AL_MAX_GAIN, volume); - if(schan->ManualGain) - volume *= GetRolloff(&schan->Rolloff, sqrt(schan->DistanceSqr)); alSourcef(source, AL_GAIN, volume * schan->Volume); } schan = schan->NextChan; @@ -1126,12 +1124,12 @@ FISoundChannel *OpenALSoundRenderer::StartSound(SoundHandle sfx, float vol, int if(!chan) chan = S_GetChannel(MAKE_PTRID(source)); else chan->SysChannel = MAKE_PTRID(source); - chan->Rolloff.RolloffType = ROLLOFF_Linear; - chan->Rolloff.MaxDistance = 1000.f; + chan->Rolloff.RolloffType = ROLLOFF_Log; + chan->Rolloff.RolloffFactor = 0.f; chan->Rolloff.MinDistance = 1.f; chan->DistanceScale = 1.f; - chan->DistanceSqr = 1.f; - chan->ManualGain = false; + chan->DistanceSqr = 0.f; + chan->ManualRolloff = false; return chan; } @@ -1140,8 +1138,7 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener FRolloffInfo *rolloff, float distscale, int pitch, int priority, const FVector3 &pos, const FVector3 &vel, int channum, int chanflags, FISoundChannel *reuse_chan) { - float dist_sqr = (pos - listener->position).LengthSquared() * - distscale*distscale; + float dist_sqr = (pos - listener->position).LengthSquared(); if(FreeSfx.size() == 0) { @@ -1156,61 +1153,80 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener return NULL; } - float rolloffFactor, gain; - bool manualGain = true; + float rolloffFactor = 1.f; + bool manualRolloff = true; ALuint buffer = GET_PTRID(sfx.data); - ALint channels = 1; - alGetBufferi(buffer, AL_CHANNELS, &channels); - ALuint source = FreeSfx.back(); - alSource3f(source, AL_POSITION, pos[0], pos[1], -pos[2]); - alSource3f(source, AL_VELOCITY, vel[0], vel[1], -vel[2]); - alSource3f(source, AL_DIRECTION, 0.f, 0.f, 0.f); - alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); - - alSourcei(source, AL_LOOPING, (chanflags&SNDF_LOOP) ? AL_TRUE : AL_FALSE); - - // Multi-channel sources won't attenuate in OpenAL, and "area sounds" have - // special rolloff properties (they have a panning radius of 32 units, but - // start attenuating at MinDistance). - if(channels == 1 && !(chanflags&SNDF_AREA)) - { - if(rolloff->RolloffType == ROLLOFF_Log) - { - if(AL.EXT_source_distance_model) - alSourcei(source, AL_DISTANCE_MODEL, AL_INVERSE_DISTANCE); - alSourcef(source, AL_REFERENCE_DISTANCE, rolloff->MinDistance/distscale); - alSourcef(source, AL_MAX_DISTANCE, (1000.f+rolloff->MinDistance)/distscale); - rolloffFactor = rolloff->RolloffFactor; - manualGain = false; - gain = 1.f; - } - else if(rolloff->RolloffType == ROLLOFF_Linear && AL.EXT_source_distance_model) - { - alSourcei(source, AL_DISTANCE_MODEL, AL_LINEAR_DISTANCE); - alSourcef(source, AL_REFERENCE_DISTANCE, rolloff->MinDistance/distscale); - alSourcef(source, AL_MAX_DISTANCE, rolloff->MaxDistance/distscale); - rolloffFactor = 1.f; - manualGain = false; - gain = 1.f; - } - } - if(manualGain) + if(rolloff->RolloffType == ROLLOFF_Log) { if(AL.EXT_source_distance_model) - alSourcei(source, AL_DISTANCE_MODEL, AL_NONE); - if((chanflags&SNDF_AREA) && rolloff->MinDistance < 32.f) - alSourcef(source, AL_REFERENCE_DISTANCE, 32.f/distscale); - else - alSourcef(source, AL_REFERENCE_DISTANCE, rolloff->MinDistance/distscale); + alSourcei(source, AL_DISTANCE_MODEL, AL_INVERSE_DISTANCE); + alSourcef(source, AL_REFERENCE_DISTANCE, rolloff->MinDistance/distscale); alSourcef(source, AL_MAX_DISTANCE, (1000.f+rolloff->MinDistance)/distscale); - rolloffFactor = 0.f; - gain = GetRolloff(rolloff, sqrt(dist_sqr)); + alSourcef(source, AL_ROLLOFF_FACTOR, rolloff->RolloffFactor); + rolloffFactor = rolloff->RolloffFactor; + manualRolloff = false; } - alSourcef(source, AL_ROLLOFF_FACTOR, rolloffFactor); + else if(rolloff->RolloffType == ROLLOFF_Linear && AL.EXT_source_distance_model) + { + alSourcei(source, AL_DISTANCE_MODEL, AL_LINEAR_DISTANCE); + alSourcef(source, AL_REFERENCE_DISTANCE, rolloff->MinDistance/distscale); + alSourcef(source, AL_MAX_DISTANCE, rolloff->MaxDistance/distscale); + alSourcef(source, AL_ROLLOFF_FACTOR, 1.f); + manualRolloff = false; + } + if(manualRolloff) + { + // How manual rolloff works: + // + // If a sound is using Custom or Doom style rolloff, or Linear style + // when AL_EXT_source_distance_model is not supported, we have to play + // around a bit to get appropriate distance attenation. What we do is + // calculate the attenuation that should be applied, then given an + // Inverse Distance rolloff model with OpenAL, reverse the calculation + // to get the distance needed for that much attenuation. The Inverse + // Distance calculation is: + // + // Gain = MinDist / (MinDist + RolloffFactor*(Distance - MinDist)) + // + // Thus, the reverse is: + // + // Distance = (MinDist/Gain - MinDist)/RolloffFactor + MinDist + // + // This can be simplified by using a MinDist and RolloffFactor of 1, + // which makes it: + // + // Distance = 1.0f/Gain; + // + // The source position is then set that many units away from the + // listener position, and OpenAL takes care of the rest. + if(AL.EXT_source_distance_model) + alSourcei(source, AL_DISTANCE_MODEL, AL_INVERSE_DISTANCE); + alSourcef(source, AL_REFERENCE_DISTANCE, 1.f); + alSourcef(source, AL_MAX_DISTANCE, 100000.f); + alSourcef(source, AL_ROLLOFF_FACTOR, 1.f); + + FVector3 dir = pos - listener->position; + if(dir.DoesNotApproximatelyEqual(FVector3(0.f, 0.f, 0.f))) + { + float gain = GetRolloff(rolloff, sqrt(dist_sqr) * distscale); + dir.Resize((gain > 0.00001f) ? 1.f/gain : 100000.f); + } + dir += listener->position; + + alSource3f(source, AL_POSITION, dir[0], dir[1], -dir[2]); + } + else + alSource3f(source, AL_POSITION, pos[0], pos[1], -pos[2]); + alSource3f(source, AL_VELOCITY, vel[0], vel[1], -vel[2]); + alSource3f(source, AL_DIRECTION, 0.f, 0.f, 0.f); + + alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); + alSourcei(source, AL_LOOPING, (chanflags&SNDF_LOOP) ? AL_TRUE : AL_FALSE); + alSourcef(source, AL_MAX_GAIN, SfxVolume); - alSourcef(source, AL_GAIN, SfxVolume * gain); + alSourcef(source, AL_GAIN, SfxVolume); if(EnvSlot) { @@ -1271,7 +1287,7 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener chan->Rolloff = *rolloff; chan->DistanceScale = distscale; chan->DistanceSqr = dist_sqr; - chan->ManualGain = manualGain; + chan->ManualRolloff = manualRolloff; return chan; } @@ -1284,8 +1300,6 @@ void OpenALSoundRenderer::ChannelVolume(FISoundChannel *chan, float volume) alcSuspendContext(Context); ALuint source = GET_PTRID(chan->SysChannel); - if(chan->ManualGain) - volume *= GetRolloff(&chan->Rolloff, sqrt(chan->DistanceSqr)); alSourcef(source, AL_GAIN, SfxVolume * volume); } @@ -1411,21 +1425,24 @@ void OpenALSoundRenderer::UpdateSoundParams3D(SoundListener *listener, FISoundCh alcSuspendContext(Context); + FVector3 dir = pos - listener->position; + chan->DistanceSqr = dir.LengthSquared(); + ALuint source = GET_PTRID(chan->SysChannel); - alSource3f(source, AL_POSITION, pos[0], pos[1], -pos[2]); - alSource3f(source, AL_VELOCITY, vel[0], vel[1], -vel[2]); - - chan->DistanceSqr = (pos - listener->position).LengthSquared() * - chan->DistanceScale*chan->DistanceScale; - // Not all sources can use the distance models provided by OpenAL. - // For the ones that can't, apply the calculated attenuation as the - // source gain. Positions still handle the panning, - if(chan->ManualGain) + if(chan->ManualRolloff) { - float gain = GetRolloff(&chan->Rolloff, sqrt(chan->DistanceSqr)); - alSourcef(source, AL_GAIN, SfxVolume*gain*((FSoundChan*)chan)->Volume); - } + if(dir.DoesNotApproximatelyEqual(FVector3(0.f, 0.f, 0.f))) + { + float gain = GetRolloff(&chan->Rolloff, sqrt(chan->DistanceSqr) * chan->DistanceScale); + dir.Resize((gain > 0.00001f) ? 1.f/gain : 100000.f); + } + dir += listener->position; + alSource3f(source, AL_POSITION, dir[0], dir[1], -dir[2]); + } + else + alSource3f(source, AL_POSITION, pos[0], pos[1], -pos[2]); + alSource3f(source, AL_VELOCITY, vel[0], vel[1], -vel[2]); getALError(); } @@ -1581,14 +1598,10 @@ float OpenALSoundRenderer::GetAudibility(FISoundChannel *chan) ALuint source = GET_PTRID(chan->SysChannel); ALfloat volume = 0.f; - if(!chan->ManualGain) - volume = SfxVolume * ((FSoundChan*)chan)->Volume * - GetRolloff(&chan->Rolloff, sqrt(chan->DistanceSqr)); - else - { - alGetSourcef(source, AL_GAIN, &volume); - getALError(); - } + alGetSourcef(source, AL_GAIN, &volume); + getALError(); + + volume *= GetRolloff(&chan->Rolloff, sqrt(chan->DistanceSqr) * chan->DistanceScale); return volume; } From 845e369b875114b0a14cf30fc6810435b620237d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 20 Jun 2014 05:03:20 -0700 Subject: [PATCH 41/88] Don't set a room rolloff factor The reverb engine already handles an initial attenuation based on the attenuation of the dry path. --- src/sound/oalsound.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 571345f237..22d54ca6b9 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -1153,9 +1153,7 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener return NULL; } - float rolloffFactor = 1.f; bool manualRolloff = true; - ALuint buffer = GET_PTRID(sfx.data); ALuint source = FreeSfx.back(); if(rolloff->RolloffType == ROLLOFF_Log) @@ -1165,7 +1163,6 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener alSourcef(source, AL_REFERENCE_DISTANCE, rolloff->MinDistance/distscale); alSourcef(source, AL_MAX_DISTANCE, (1000.f+rolloff->MinDistance)/distscale); alSourcef(source, AL_ROLLOFF_FACTOR, rolloff->RolloffFactor); - rolloffFactor = rolloff->RolloffFactor; manualRolloff = false; } else if(rolloff->RolloffType == ROLLOFF_Linear && AL.EXT_source_distance_model) @@ -1240,7 +1237,7 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener alSourcei(source, AL_DIRECT_FILTER, AL_FILTER_NULL); alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL); } - alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, rolloffFactor); + alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, 0.f); alSourcef(source, AL_PITCH, PITCH(pitch)); } else if(WasInWater && !(chanflags&SNDF_NOREVERB)) From a434af92ee6b59a61ba9b9e987791b4bc86cad35 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 22 Jun 2014 19:35:09 -0700 Subject: [PATCH 42/88] Handle sounds marked as 'area sounds' Note, the area radius is 128 units for it to actually do something, unlike FMOD where it's only 32. --- src/sound/oalsound.cpp | 43 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 22d54ca6b9..1930a8346d 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -527,6 +527,8 @@ public: extern ReverbContainer *ForcedEnvironment; +#define AREA_SOUND_RADIUS (128.f) + #define PITCH_MULT (0.7937005f) /* Approx. 4 semitones lower; what Nash suggested */ #define PITCH(pitch) (snd_pitched ? (pitch)/128.f : 1.f) @@ -1210,10 +1212,28 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener float gain = GetRolloff(rolloff, sqrt(dist_sqr) * distscale); dir.Resize((gain > 0.00001f) ? 1.f/gain : 100000.f); } + if((chanflags&SNDF_AREA) && dist_sqr < AREA_SOUND_RADIUS*AREA_SOUND_RADIUS) + { + FVector3 near(0.f, !(dir.Y>=0.f) ? -1.f : 1.f, 0.f); + float a = sqrt(dist_sqr) / AREA_SOUND_RADIUS; + dir = near + (dir-near)*a; + } dir += listener->position; alSource3f(source, AL_POSITION, dir[0], dir[1], -dir[2]); } + else if((chanflags&SNDF_AREA) && dist_sqr < AREA_SOUND_RADIUS*AREA_SOUND_RADIUS) + { + FVector3 dir = pos - listener->position; + + float mindist = rolloff->MinDistance/distscale; + FVector3 near(0.f, !(dir.Y>=0.f) ? -mindist : mindist, 0.f); + float a = sqrt(dist_sqr) / AREA_SOUND_RADIUS; + dir = near + (dir-near)*a; + + dir += listener->position; + alSource3f(source, AL_POSITION, dir[0], dir[1], -dir[2]); + } else alSource3f(source, AL_POSITION, pos[0], pos[1], -pos[2]); alSource3f(source, AL_VELOCITY, vel[0], vel[1], -vel[2]); @@ -1425,7 +1445,6 @@ void OpenALSoundRenderer::UpdateSoundParams3D(SoundListener *listener, FISoundCh FVector3 dir = pos - listener->position; chan->DistanceSqr = dir.LengthSquared(); - ALuint source = GET_PTRID(chan->SysChannel); if(chan->ManualRolloff) { if(dir.DoesNotApproximatelyEqual(FVector3(0.f, 0.f, 0.f))) @@ -1433,12 +1452,24 @@ void OpenALSoundRenderer::UpdateSoundParams3D(SoundListener *listener, FISoundCh float gain = GetRolloff(&chan->Rolloff, sqrt(chan->DistanceSqr) * chan->DistanceScale); dir.Resize((gain > 0.00001f) ? 1.f/gain : 100000.f); } - dir += listener->position; - - alSource3f(source, AL_POSITION, dir[0], dir[1], -dir[2]); + if(areasound && chan->DistanceSqr < AREA_SOUND_RADIUS*AREA_SOUND_RADIUS) + { + FVector3 near(0.f, !(dir.Y>=0.f) ? -1.f : 1.f, 0.f); + float a = sqrt(chan->DistanceSqr) / AREA_SOUND_RADIUS; + dir = near + (dir-near)*a; + } } - else - alSource3f(source, AL_POSITION, pos[0], pos[1], -pos[2]); + else if(areasound && chan->DistanceSqr < AREA_SOUND_RADIUS*AREA_SOUND_RADIUS) + { + float mindist = chan->Rolloff.MinDistance / chan->DistanceScale; + FVector3 near(0.f, !(dir.Y>=0.f) ? -mindist : mindist, 0.f); + float a = sqrt(chan->DistanceSqr) / AREA_SOUND_RADIUS; + dir = near + (dir-near)*a; + } + dir += listener->position; + + ALuint source = GET_PTRID(chan->SysChannel); + alSource3f(source, AL_POSITION, dir[0], dir[1], -dir[2]); alSource3f(source, AL_VELOCITY, vel[0], vel[1], -vel[2]); getALError(); } From b2f9430fb15fe4c95f9faf73e74c60338e04f622 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 22 Jun 2014 19:38:47 -0700 Subject: [PATCH 43/88] Use the correct diffusion value for reverb I don't know what the Density and Diffusion values correspond to, but EnvDiffusion is the actual diffusion setting. --- src/sound/oalsound.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 1930a8346d..0353b17bb2 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -1797,8 +1797,7 @@ void OpenALSoundRenderer::LoadReverb(const ReverbContainer *env) props.ReverbPan2 }; #undef SETPARAM #define SETPARAM(e,t,v) alEffectf((e), AL_EAXREVERB_##t, clamp((v), AL_EAXREVERB_MIN_##t, AL_EAXREVERB_MAX_##t)) - SETPARAM(envReverb, DENSITY, props.Density/100.f); - SETPARAM(envReverb, DIFFUSION, props.Diffusion/100.f); + SETPARAM(envReverb, DIFFUSION, props.EnvDiffusion); SETPARAM(envReverb, GAIN, mB2Gain(props.Room)); SETPARAM(envReverb, GAINHF, mB2Gain(props.RoomHF)); SETPARAM(envReverb, GAINLF, mB2Gain(props.RoomLF)); @@ -1826,8 +1825,7 @@ void OpenALSoundRenderer::LoadReverb(const ReverbContainer *env) else if(type == AL_EFFECT_REVERB) { #define SETPARAM(e,t,v) alEffectf((e), AL_REVERB_##t, clamp((v), AL_REVERB_MIN_##t, AL_REVERB_MAX_##t)) - SETPARAM(envReverb, DENSITY, props.Density/100.f); - SETPARAM(envReverb, DIFFUSION, props.Diffusion/100.f); + SETPARAM(envReverb, DIFFUSION, props.EnvDiffusion); SETPARAM(envReverb, GAIN, mB2Gain(props.Room)); SETPARAM(envReverb, GAINHF, mB2Gain(props.RoomHF)); SETPARAM(envReverb, DECAY_TIME, props.DecayTime); From 075c5d872dd93cc6c44978b6ce0594372576f21d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 22 Jun 2014 22:22:45 -0700 Subject: [PATCH 44/88] Always use the pitch multiplier when underwater --- src/sound/oalsound.cpp | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 0353b17bb2..8bb4be5bc7 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -1083,9 +1083,8 @@ FISoundChannel *OpenALSoundRenderer::StartSound(SoundHandle sfx, float vol, int alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL); } alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, 0.f); - alSourcef(source, AL_PITCH, PITCH(pitch)); } - else if(WasInWater && !(chanflags&SNDF_NOREVERB)) + if(WasInWater && !(chanflags&SNDF_NOREVERB)) alSourcef(source, AL_PITCH, PITCH(pitch)*PITCH_MULT); else alSourcef(source, AL_PITCH, PITCH(pitch)); @@ -1258,9 +1257,8 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener alSource3i(source, AL_AUXILIARY_SEND_FILTER, 0, 0, AL_FILTER_NULL); } alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, 0.f); - alSourcef(source, AL_PITCH, PITCH(pitch)); } - else if(WasInWater && !(chanflags&SNDF_NOREVERB)) + if(WasInWater && !(chanflags&SNDF_NOREVERB)) alSourcef(source, AL_PITCH, PITCH(pitch)*PITCH_MULT); else alSourcef(source, AL_PITCH, PITCH(pitch)); @@ -1519,8 +1517,7 @@ void OpenALSoundRenderer::UpdateListener(SoundListener *listener) const_cast(env)->Modified = false; } - // NOTE: Moving into and out of water will undo pitch variations on sounds - // if either snd_waterreverb or EFX are disabled. + // NOTE: Moving into and out of water will undo pitch variations on sounds. if(listener->underwater || env->SoftwareWater) { if(!WasInWater) @@ -1530,13 +1527,11 @@ void OpenALSoundRenderer::UpdateListener(SoundListener *listener) if(EnvSlot != 0 && *snd_waterreverb) { // Find the "Underwater" reverb environment - env = Environments; - while(env && env->ID != 0x1600) - env = env->Next; + env = S_FindEnvironment(0x1600); LoadReverb(env ? env : DefaultEnvironments[0]); - alFilterf(EnvFilters[0], AL_LOWPASS_GAIN, 0.1f); - alFilterf(EnvFilters[0], AL_LOWPASS_GAINHF, 1.f); + alFilterf(EnvFilters[0], AL_LOWPASS_GAIN, 1.f); + alFilterf(EnvFilters[0], AL_LOWPASS_GAINHF, 0.125f); alFilterf(EnvFilters[1], AL_LOWPASS_GAIN, 1.f); alFilterf(EnvFilters[1], AL_LOWPASS_GAINHF, 1.f); @@ -1547,11 +1542,9 @@ void OpenALSoundRenderer::UpdateListener(SoundListener *listener) alSource3i(*i, AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); } } - else - { - foreach(ALuint, i, ReverbSfx) - alSourcef(*i, AL_PITCH, PITCH_MULT); - } + + foreach(ALuint, i, ReverbSfx) + alSourcef(*i, AL_PITCH, PITCH_MULT); getALError(); } } @@ -1573,11 +1566,9 @@ void OpenALSoundRenderer::UpdateListener(SoundListener *listener) alSource3i(*i, AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); } } - else - { - foreach(ALuint, i, ReverbSfx) - alSourcef(*i, AL_PITCH, 1.f); - } + + foreach(ALuint, i, ReverbSfx) + alSourcef(*i, AL_PITCH, 1.f); getALError(); } } From 0017e1e6e833ef2490ba16dffafde57aeea7b39e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 25 Jun 2014 04:25:36 -0700 Subject: [PATCH 45/88] Use a FileReader to handle music resources and audio decoding Instead of the previous method where there'd be a filename and offset, and/or a memory pointer, this uses a class to access resource data regardless of its underlying form. --- src/files.cpp | 56 ++++++ src/files.h | 18 ++ src/oplsynth/opl_mus_player.cpp | 29 ++-- src/oplsynth/opl_mus_player.h | 2 +- src/s_sound.cpp | 21 +-- src/sound/fmodsound.cpp | 235 ++++++++++++++++++-------- src/sound/fmodsound.h | 5 +- src/sound/i_music.cpp | 235 +++++++++----------------- src/sound/i_music.h | 4 +- src/sound/i_musicinterns.h | 19 ++- src/sound/i_sound.cpp | 37 ++-- src/sound/i_sound.h | 10 +- src/sound/i_soundinternal.h | 5 +- src/sound/mpg123_decoder.cpp | 197 +++------------------ src/sound/mpg123_decoder.h | 16 +- src/sound/music_cd.cpp | 21 +-- src/sound/music_dumb.cpp | 95 +++++------ src/sound/music_gme.cpp | 37 ++-- src/sound/music_hmi_midiout.cpp | 15 +- src/sound/music_mus_midiout.cpp | 28 +-- src/sound/music_mus_opl.cpp | 4 +- src/sound/music_pseudo_mididevice.cpp | 13 +- src/sound/music_smf_midiout.cpp | 24 +-- src/sound/music_stream.cpp | 9 +- src/sound/music_xmi_midiout.cpp | 22 +-- src/sound/oalsound.cpp | 60 +------ src/sound/oalsound.h | 2 +- src/sound/sndfile_decoder.cpp | 162 ++---------------- src/sound/sndfile_decoder.h | 18 +- 29 files changed, 550 insertions(+), 849 deletions(-) diff --git a/src/files.cpp b/src/files.cpp index d7dfc2cbe7..78936eba9e 100644 --- a/src/files.cpp +++ b/src/files.cpp @@ -527,3 +527,59 @@ char *MemoryReader::Gets(char *strbuf, int len) { return GetsFromBuffer(bufptr, strbuf, len); } + +//========================================================================== +// +// MemoryArrayReader +// +// reads data from an array of memory +// +//========================================================================== + +MemoryArrayReader::MemoryArrayReader (const char *buffer, long length) +{ + buf.Resize(length); + memcpy(&buf[0], buffer, length); + Length=length; + FilePos=0; +} + +MemoryArrayReader::~MemoryArrayReader () +{ +} + +long MemoryArrayReader::Tell () const +{ + return FilePos; +} + +long MemoryArrayReader::Seek (long offset, int origin) +{ + switch (origin) + { + case SEEK_CUR: + offset+=FilePos; + break; + + case SEEK_END: + offset+=Length; + break; + + } + FilePos=clamp(offset,0,Length-1); + return 0; +} + +long MemoryArrayReader::Read (void *buffer, long len) +{ + if (len>Length-FilePos) len=Length-FilePos; + if (len<0) len=0; + memcpy(buffer,&buf[FilePos],len); + FilePos+=len; + return len; +} + +char *MemoryArrayReader::Gets(char *strbuf, int len) +{ + return GetsFromBuffer((char*)&buf[0], strbuf, len); +} diff --git a/src/files.h b/src/files.h index ebe9665a44..52cda93f5a 100644 --- a/src/files.h +++ b/src/files.h @@ -335,6 +335,24 @@ protected: const char * bufptr; }; +class MemoryArrayReader : public FileReader +{ +public: + MemoryArrayReader (const char *buffer, long length); + ~MemoryArrayReader (); + + virtual long Tell () const; + virtual long Seek (long offset, int origin); + virtual long Read (void *buffer, long len); + virtual char *Gets(char *strbuf, int len); + virtual const char *GetBuffer() const { return (char*)&buf[0]; } + TArray &GetArray() { return buf; } + + void UpdateLength() { Length = buf.Size(); } + +protected: + TArray buf; +}; #endif diff --git a/src/oplsynth/opl_mus_player.cpp b/src/oplsynth/opl_mus_player.cpp index a528c10e2b..f9b46a08de 100644 --- a/src/oplsynth/opl_mus_player.cpp +++ b/src/oplsynth/opl_mus_player.cpp @@ -52,29 +52,22 @@ void OPLmusicBlock::Restart() LastOffset = 0; } -OPLmusicFile::OPLmusicFile (FILE *file, BYTE *musiccache, int len) - : ScoreLen (len) +OPLmusicFile::OPLmusicFile (FileReader *reader) + : ScoreLen (reader->GetLength()) { if (io == NULL) { return; } - scoredata = new BYTE[len]; + scoredata = new BYTE[ScoreLen]; - if (file) - { - if (fread (scoredata, 1, len, file) != (size_t)len) - { -fail: delete[] scoredata; - scoredata = NULL; - return; - } - } - else - { - memcpy(scoredata, &musiccache[0], len); - } + if (reader->Read(scoredata, ScoreLen) != ScoreLen) + { +fail: delete[] scoredata; + scoredata = NULL; + return; + } if (0 == (NumChips = io->OPLinit(NumChips))) { @@ -100,7 +93,7 @@ fail: delete[] scoredata; { RawPlayer = DosBox1; SamplesPerTick = OPL_SAMPLE_RATE / 1000; - ScoreLen = MIN(len - 24, LittleLong(((DWORD *)scoredata)[4])) + 24; + ScoreLen = MIN(ScoreLen - 24, LittleLong(((DWORD *)scoredata)[4])) + 24; } else if (((DWORD *)scoredata)[2] == MAKE_ID(2,0,0,0)) { @@ -120,7 +113,7 @@ fail: delete[] scoredata; RawPlayer = DosBox2; SamplesPerTick = OPL_SAMPLE_RATE / 1000; int headersize = 0x1A + scoredata[0x19]; - ScoreLen = MIN(len - headersize, LittleLong(((DWORD *)scoredata)[3]) * 2) + headersize; + ScoreLen = MIN(ScoreLen - headersize, LittleLong(((DWORD *)scoredata)[3]) * 2) + headersize; } else { diff --git a/src/oplsynth/opl_mus_player.h b/src/oplsynth/opl_mus_player.h index b0eb4b6c8a..8e675c5d87 100644 --- a/src/oplsynth/opl_mus_player.h +++ b/src/oplsynth/opl_mus_player.h @@ -29,7 +29,7 @@ protected: class OPLmusicFile : public OPLmusicBlock { public: - OPLmusicFile(FILE *file, BYTE *musiccache, int len); + OPLmusicFile(FileReader *reader); OPLmusicFile(const OPLmusicFile *source, const char *filename); virtual ~OPLmusicFile(); diff --git a/src/s_sound.cpp b/src/s_sound.cpp index d1c3139672..c84c539caf 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -26,6 +26,7 @@ #include #endif #include +#include #include "i_system.h" #include "i_sound.h" @@ -2435,7 +2436,7 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) else { int lumpnum = -1; - int offset = 0, length = 0; + int length = 0; int device = MDEV_DEFAULT; MusInfo *handle = NULL; FName musicasname = musicname; @@ -2456,6 +2457,7 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) musicname += 7; } + std::auto_ptr reader; if (!FileExists (musicname)) { if ((lumpnum = Wads.CheckNumForFullName (musicname, true, ns_music)) == -1) @@ -2485,8 +2487,6 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) // shut down old music before reallocating and overwriting the cache! S_StopMusic (true); - offset = -1; // this tells the low level code that the music - // is being used from memory length = Wads.LumpLength (lumpnum); if (length == 0) { @@ -2494,15 +2494,16 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) } musiccache.Resize(length); Wads.ReadLump(lumpnum, &musiccache[0]); + + reader.reset(new MemoryReader((const char*)&musiccache[0], musiccache.Size())); } else { - offset = Wads.GetLumpOffset (lumpnum); - length = Wads.LumpLength (lumpnum); - if (length == 0) + if (Wads.LumpLength (lumpnum) == 0) { return false; } + reader.reset(Wads.ReopenLumpNum(lumpnum)); } } } @@ -2525,15 +2526,9 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) { mus_playing.handle = handle; } - else if (offset != -1) - { - mus_playing.handle = I_RegisterSong (lumpnum != -1 ? - Wads.GetWadFullName (Wads.GetLumpFile (lumpnum)) : - musicname, NULL, offset, length, device); - } else { - mus_playing.handle = I_RegisterSong (NULL, &musiccache[0], -1, length, device); + mus_playing.handle = I_RegisterSong (reader, device); } } diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index 0814013007..fa442603e9 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -62,6 +62,7 @@ extern HWND Window; #include "v_palette.h" #include "cmdlib.h" #include "s_sound.h" +#include "files.h" #if FMOD_VERSION > 0x42899 && FMOD_VERSION < 0x43600 #error You are trying to compile with an unsupported version of FMOD. @@ -310,6 +311,13 @@ public: SetStream(stream); } + FMODStreamCapsule(FMOD::Sound *stream, FMODSoundRenderer *owner, std::auto_ptr reader) + : Owner(owner), Stream(NULL), Channel(NULL), + UserData(NULL), Callback(NULL), Reader(reader), Ended(false) + { + SetStream(stream); + } + FMODStreamCapsule(void *udata, SoundStreamCallback callback, FMODSoundRenderer *owner) : Owner(owner), Stream(NULL), Channel(NULL), UserData(udata), Callback(callback), Ended(false) @@ -594,6 +602,7 @@ private: FMOD::Channel *Channel; void *UserData; SoundStreamCallback Callback; + std::auto_ptr Reader; FString URL; bool Ended; bool JustStarted; @@ -1600,83 +1609,173 @@ static void SetCustomLoopPts(FMOD::Sound *sound) //========================================================================== // -// FMODSoundRenderer :: OpenStream +// open_reader_callback +// close_reader_callback +// read_reader_callback +// seek_reader_callback // -// Creates a streaming sound from a file on disk. +// FMOD_CREATESOUNDEXINFO callbacks to handle reading resource data from a +// FileReader. // //========================================================================== -SoundStream *FMODSoundRenderer::OpenStream(const char *filename_or_data, int flags, int offset, int length) +static FMOD_RESULT F_CALLBACK open_reader_callback(const char *name, int unicode, unsigned int *filesize, void **handle, void **userdata) { - FMOD_MODE mode; - FMOD_CREATESOUNDEXINFO exinfo; - FMOD::Sound *stream; - FMOD_RESULT result; - bool url; - FString patches; + char *endptr = NULL; + QWORD val = strtoull(name, &endptr, 0); + if(!endptr || *endptr != '\0') + { + Printf("Invalid name in callback: %s\n", name); + return FMOD_ERR_FILE_NOTFOUND; + } - InitCreateSoundExInfo(&exinfo); - mode = FMOD_SOFTWARE | FMOD_2D | FMOD_CREATESTREAM; - if (flags & SoundStream::Loop) - { - mode |= FMOD_LOOP_NORMAL; - } - if (offset == -1) - { - mode |= FMOD_OPENMEMORY; - offset = 0; - } - exinfo.length = length; - exinfo.fileoffset = offset; - if ((*snd_midipatchset)[0] != '\0') - { + FileReader *reader = reinterpret_cast((uintptr_t)val); + *filesize = reader->GetLength(); + *handle = reader; + *userdata = reader; + return FMOD_OK; +} + +static FMOD_RESULT F_CALLBACK close_reader_callback(void *handle, void *userdata) +{ + return FMOD_OK; +} + +static FMOD_RESULT F_CALLBACK read_reader_callback(void *handle, void *buffer, unsigned int sizebytes, unsigned int *bytesread, void *userdata) +{ + FileReader *reader = reinterpret_cast(handle); + *bytesread = reader->Read(buffer, sizebytes); + if(*bytesread > 0) return FMOD_OK; + return FMOD_ERR_FILE_EOF; +} + +static FMOD_RESULT F_CALLBACK seek_reader_callback(void *handle, unsigned int pos, void *userdata) +{ + FileReader *reader = reinterpret_cast(handle); + if(reader->Seek(pos, SEEK_SET) == 0) + return FMOD_OK; + return FMOD_ERR_FILE_COULDNOTSEEK; +} + + +//========================================================================== +// +// FMODSoundRenderer :: OpenStream +// +// Creates a streaming sound from a FileReader. +// +//========================================================================== + +SoundStream *FMODSoundRenderer::OpenStream(std::auto_ptr reader, int flags) +{ + FMOD_MODE mode; + FMOD_CREATESOUNDEXINFO exinfo; + FMOD::Sound *stream; + FMOD_RESULT result; + FString patches; + FString name; + + InitCreateSoundExInfo(&exinfo); + exinfo.useropen = open_reader_callback; + exinfo.userclose = close_reader_callback; + exinfo.userread = read_reader_callback; + exinfo.userseek = seek_reader_callback; + + mode = FMOD_SOFTWARE | FMOD_2D | FMOD_CREATESTREAM; + if(flags & SoundStream::Loop) + mode |= FMOD_LOOP_NORMAL; + if((*snd_midipatchset)[0] != '\0') + { #ifdef _WIN32 - // If the path does not contain any path separators, automatically - // prepend $PROGDIR to the path. - if (strcspn(snd_midipatchset, ":/\\") == strlen(snd_midipatchset)) - { - patches << "$PROGDIR/" << snd_midipatchset; - patches = NicePath(patches); - } - else + // If the path does not contain any path separators, automatically + // prepend $PROGDIR to the path. + if (strcspn(snd_midipatchset, ":/\\") == strlen(snd_midipatchset)) + { + patches << "$PROGDIR/" << snd_midipatchset; + patches = NicePath(patches); + } + else #endif - { - patches = NicePath(snd_midipatchset); - } - exinfo.dlsname = patches; - } + { + patches = NicePath(snd_midipatchset); + } + exinfo.dlsname = patches; + } - url = (offset == 0 && length == 0 && strstr(filename_or_data, "://") > filename_or_data); - if (url) - { - // Use a larger buffer for URLs so that it's less likely to be effected - // by hiccups in the data rate from the remote server. - Sys->setStreamBufferSize(64*1024, FMOD_TIMEUNIT_RAWBYTES); - } - result = Sys->createSound(filename_or_data, mode, &exinfo, &stream); - if (url) - { - // Restore standard buffer size. - Sys->setStreamBufferSize(16*1024, FMOD_TIMEUNIT_RAWBYTES); - } - if (result == FMOD_ERR_FORMAT && exinfo.dlsname != NULL) - { - // FMOD_ERR_FORMAT could refer to either the main sound file or - // to the DLS instrument set. Try again without special DLS - // instruments to see if that lets it succeed. - exinfo.dlsname = NULL; - result = Sys->createSound(filename_or_data, mode, &exinfo, &stream); - if (result == FMOD_OK) - { - Printf("%s is an unsupported format.\n", *snd_midipatchset); - } - } - if (result == FMOD_OK) - { - SetCustomLoopPts(stream); - return new FMODStreamCapsule(stream, this, url ? filename_or_data : NULL); - } - return NULL; + name.Format("0x%I64x", (QWORD)reader.get()); + result = Sys->createSound(name, mode, &exinfo, &stream); + if(result == FMOD_ERR_FORMAT && exinfo.dlsname != NULL) + { + // FMOD_ERR_FORMAT could refer to either the main sound file or + // to the DLS instrument set. Try again without special DLS + // instruments to see if that lets it succeed. + exinfo.dlsname = NULL; + result = Sys->createSound(name, mode, &exinfo, &stream); + if (result == FMOD_OK) + { + Printf("%s is an unsupported format.\n", *snd_midipatchset); + } + } + if(result != FMOD_OK) + return NULL; + + SetCustomLoopPts(stream); + return new FMODStreamCapsule(stream, this, reader); +} + +SoundStream *FMODSoundRenderer::OpenStream(const char *url, int flags) +{ + FMOD_MODE mode; + FMOD_CREATESOUNDEXINFO exinfo; + FMOD::Sound *stream; + FMOD_RESULT result; + FString patches; + + InitCreateSoundExInfo(&exinfo); + mode = FMOD_SOFTWARE | FMOD_2D | FMOD_CREATESTREAM; + if(flags & SoundStream::Loop) + mode |= FMOD_LOOP_NORMAL; + if((*snd_midipatchset)[0] != '\0') + { +#ifdef _WIN32 + // If the path does not contain any path separators, automatically + // prepend $PROGDIR to the path. + if (strcspn(snd_midipatchset, ":/\\") == strlen(snd_midipatchset)) + { + patches << "$PROGDIR/" << snd_midipatchset; + patches = NicePath(patches); + } + else +#endif + { + patches = NicePath(snd_midipatchset); + } + exinfo.dlsname = patches; + } + + // Use a larger buffer for URLs so that it's less likely to be effected + // by hiccups in the data rate from the remote server. + Sys->setStreamBufferSize(64*1024, FMOD_TIMEUNIT_RAWBYTES); + + result = Sys->createSound(url, mode, &exinfo, &stream); + if(result == FMOD_ERR_FORMAT && exinfo.dlsname != NULL) + { + exinfo.dlsname = NULL; + result = Sys->createSound(url, mode, &exinfo, &stream); + if(result == FMOD_OK) + { + Printf("%s is an unsupported format.\n", *snd_midipatchset); + } + } + + // Restore standard buffer size. + Sys->setStreamBufferSize(16*1024, FMOD_TIMEUNIT_RAWBYTES); + + if(result != FMOD_OK) + return NULL; + + SetCustomLoopPts(stream); + return new FMODStreamCapsule(stream, this, url); } //========================================================================== diff --git a/src/sound/fmodsound.h b/src/sound/fmodsound.h index 00b4913654..c4c0399461 100644 --- a/src/sound/fmodsound.h +++ b/src/sound/fmodsound.h @@ -24,9 +24,8 @@ public: // Streaming sounds. SoundStream *CreateStream (SoundStreamCallback callback, int buffsamples, int flags, int samplerate, void *userdata); - SoundStream *OpenStream (const char *filename, int flags, int offset, int length); - long PlayStream (SoundStream *stream, int volume); - void StopStream (SoundStream *stream); + SoundStream *OpenStream (std::auto_ptr reader, int flags); + SoundStream *OpenStream (const char *url, int flags); // Starts a sound. FISoundChannel *StartSound (SoundHandle sfx, float vol, int pitch, int chanflags, FISoundChannel *reuse_chan); diff --git a/src/sound/i_music.cpp b/src/sound/i_music.cpp index 93802c8e89..1067b2b831 100644 --- a/src/sound/i_music.cpp +++ b/src/sound/i_music.cpp @@ -100,7 +100,7 @@ EXTERN_CVAR (Int, snd_mididevice) static bool MusicDown = true; -static BYTE *ungzip(BYTE *data, int *size); +static bool ungzip(BYTE *data, int size, TArray &newdata); MusInfo *currSong; int nomusic = 0; @@ -302,21 +302,21 @@ MusInfo *MusInfo::GetWaveDumper(const char *filename, int rate) // //========================================================================== -static MIDIStreamer *CreateMIDIStreamer(FILE *file, BYTE *musiccache, int len, EMidiDevice devtype, EMIDIType miditype) +static MIDIStreamer *CreateMIDIStreamer(std::auto_ptr &reader, EMidiDevice devtype, EMIDIType miditype) { switch (miditype) { case MIDI_MUS: - return new MUSSong2(file, musiccache, len, devtype); + return new MUSSong2(reader, devtype); case MIDI_MIDI: - return new MIDISong2(file, musiccache, len, devtype); + return new MIDISong2(reader, devtype); case MIDI_HMI: - return new HMISong(file, musiccache, len, devtype); + return new HMISong(reader, devtype); case MIDI_XMI: - return new XMISong(file, musiccache, len, devtype); + return new XMISong(reader, devtype); default: return NULL; @@ -378,13 +378,11 @@ static EMIDIType IdentifyMIDIType(DWORD *id, int size) // //========================================================================== -MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int len, int device) +MusInfo *I_RegisterSong (std::auto_ptr reader, int device) { - FILE *file; MusInfo *info = NULL; const char *fmt; DWORD id[32/4]; - BYTE *ungzipped; int i; if (nomusic) @@ -392,47 +390,10 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int return 0; } - if (offset != -1) - { - file = fopen (filename, "rb"); - if (file == NULL) - { - return 0; - } - - if (len == 0 && offset == 0) - { - fseek (file, 0, SEEK_END); - len = ftell (file); - fseek (file, 0, SEEK_SET); - } - else - { - fseek (file, offset, SEEK_SET); - } - if (len < 32) - { - return 0; - } - if (fread (id, 4, 32/4, file) != 32/4) - { - fclose (file); - return 0; - } - fseek (file, -32, SEEK_CUR); - } - else - { - file = NULL; - if (len < 32) - { - return 0; - } - for (i = 0; i < 32/4; ++i) - { - id[i] = ((DWORD *)musiccache)[i]; - } - } + if(reader->Read(id, 32) != 32 || reader->Seek(-32, SEEK_CUR) != 0) + { + return 0; + } #ifndef _WIN32 // non-Windows platforms don't support MDEV_MMAPI so map to MDEV_FMOD @@ -440,39 +401,34 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int device = MDEV_FMOD; #endif - // Check for gzip compression. Some formats are expected to have players - // that can handle it, so it simplifies things if we make all songs - // gzippable. - ungzipped = NULL; - if ((id[0] & MAKE_ID(255,255,255,0)) == GZIP_ID) - { - if (offset != -1) - { - BYTE *gzipped = new BYTE[len]; - if (fread(gzipped, 1, len, file) != (size_t)len) - { - delete[] gzipped; - fclose(file); - return NULL; - } - ungzipped = ungzip(gzipped, &len); - delete[] gzipped; - } - else - { - ungzipped = ungzip(musiccache, &len); - } - if (ungzipped == NULL) - { - fclose(file); - return NULL; - } - musiccache = ungzipped; - for (i = 0; i < 32/4; ++i) - { - id[i] = ((DWORD *)musiccache)[i]; - } - } + // Check for gzip compression. Some formats are expected to have players + // that can handle it, so it simplifies things if we make all songs + // gzippable. + if ((id[0] & MAKE_ID(255,255,255,0)) == GZIP_ID) + { + int len = reader->GetLength(); + BYTE *gzipped = new BYTE[len]; + if (reader->Read(gzipped, len) != len) + { + delete[] gzipped; + return NULL; + } + + std::auto_ptr reader2(new MemoryArrayReader(NULL, 0)); + if(!ungzip(gzipped, len, reader2->GetArray())) + { + delete[] gzipped; + return 0; + } + delete[] gzipped; + reader2->UpdateLength(); + + reader.reset(reader2.release()); + if(reader->Read(id, 32) != 32 || reader->Seek(-32, SEEK_CUR) != 0) + { + return 0; + } + } EMIDIType miditype = IdentifyMIDIType(id, sizeof(id)); if (miditype != MIDI_NOTMIDI) @@ -480,7 +436,7 @@ MusInfo *I_RegisterSong (const char *filename, BYTE *musiccache, int offset, int EMidiDevice devtype = (EMidiDevice)device; retry_as_fmod: - info = CreateMIDIStreamer(file, musiccache, len, devtype, miditype); + info = CreateMIDIStreamer(reader, devtype, miditype); if (info != NULL && !info->IsValid()) { delete info; @@ -494,7 +450,7 @@ retry_as_fmod: #ifdef _WIN32 if (info == NULL && devtype != MDEV_MMAPI && snd_mididevice >= 0) { - info = CreateMIDIStreamer(file, musiccache, len, MDEV_MMAPI, miditype); + info = CreateMIDIStreamer(reader, MDEV_MMAPI, miditype); } #endif } @@ -505,74 +461,57 @@ retry_as_fmod: (id[0] == MAKE_ID('D','B','R','A') && id[1] == MAKE_ID('W','O','P','L')) || // DosBox Raw OPL (id[0] == MAKE_ID('A','D','L','I') && *((BYTE *)id + 4) == 'B')) // Martin Fernandez's modified IMF { - info = new OPLMUSSong (file, musiccache, len); + info = new OPLMUSSong (reader); } // Check for game music else if ((fmt = GME_CheckFormat(id[0])) != NULL && fmt[0] != '\0') { - info = GME_OpenSong(file, musiccache, len, fmt); + info = GME_OpenSong(reader, fmt); } // Check for module formats else { - info = MOD_OpenSong(file, musiccache, len); + info = MOD_OpenSong(reader); } - if (info == NULL) - { - // Check for CDDA "format" - if (id[0] == (('R')|(('I')<<8)|(('F')<<16)|(('F')<<24))) - { - if (file != NULL) - { - DWORD subid; + if (info == NULL) + { + // Check for CDDA "format" + if (id[0] == (('R')|(('I')<<8)|(('F')<<16)|(('F')<<24))) + { + DWORD subid; - fseek (file, 8, SEEK_CUR); - if (fread (&subid, 4, 1, file) != 1) - { - fclose (file); - return 0; - } - fseek (file, -12, SEEK_CUR); + reader->Seek(8, SEEK_CUR); + if (reader->Read (&subid, 4) != 4) + { + return 0; + } + reader->Seek(-12, SEEK_CUR); - if (subid == (('C')|(('D')<<8)|(('D')<<16)|(('A')<<24))) - { - // This is a CDDA file - info = new CDDAFile (file, len); - } - } - } + if (subid == (('C')|(('D')<<8)|(('D')<<16)|(('A')<<24))) + { + // This is a CDDA file + info = new CDDAFile (reader); + } + } - // no FMOD => no modules/streams - // 1024 bytes is an arbitrary restriction. It's assumed that anything - // smaller than this can't possibly be a valid music file if it hasn't - // been identified already, so don't even bother trying to load it. - // Of course MIDIs shorter than 1024 bytes should pass. - if (info == NULL && (len >= 1024 || id[0] == MAKE_ID('M','T','h','d'))) - { - // Let FMOD figure out what it is. - if (file != NULL) - { - fclose (file); - file = NULL; - } - info = new StreamSong (offset >= 0 ? filename : (const char *)musiccache, offset, len); - } - } + // no FMOD => no modules/streams + // 1024 bytes is an arbitrary restriction. It's assumed that anything + // smaller than this can't possibly be a valid music file if it hasn't + // been identified already, so don't even bother trying to load it. + // Of course MIDIs shorter than 1024 bytes should pass. + if (info == NULL && (reader->GetLength() >= 1024 || id[0] == MAKE_ID('M','T','h','d'))) + { + // Let FMOD figure out what it is. + info = new StreamSong (reader); + } + } if (info && !info->IsValid ()) { delete info; info = NULL; } - if (file != NULL) - { - fclose (file); - } - if (ungzipped != NULL) - { - delete[] ungzipped; - } return info; } @@ -606,7 +545,7 @@ MusInfo *I_RegisterURLSong (const char *url) { StreamSong *song; - song = new StreamSong(url, 0, 0); + song = new StreamSong(url); if (song->IsValid()) { return song; @@ -624,13 +563,12 @@ MusInfo *I_RegisterURLSong (const char *url) // //========================================================================== -BYTE *ungzip(BYTE *data, int *complen) +static bool ungzip(BYTE *data, int complen, TArray &newdata) { - const BYTE *max = data + *complen - 8; + const BYTE *max = data + complen - 8; const BYTE *compstart = data + 10; BYTE flags = data[3]; unsigned isize; - BYTE *newdata; z_stream stream; int err; @@ -659,16 +597,16 @@ BYTE *ungzip(BYTE *data, int *complen) } if (compstart >= max - 1) { - return NULL; + return false; } // Decompress - isize = LittleLong(*(DWORD *)(data + *complen - 4)); - newdata = new BYTE[isize]; + isize = LittleLong(*(DWORD *)(data + complen - 4)); + newdata.Resize(isize); stream.next_in = (Bytef *)compstart; stream.avail_in = (uInt)(max - compstart); - stream.next_out = newdata; + stream.next_out = &newdata[0]; stream.avail_out = isize; stream.zalloc = (alloc_func)0; stream.zfree = (free_func)0; @@ -676,25 +614,20 @@ BYTE *ungzip(BYTE *data, int *complen) err = inflateInit2(&stream, -MAX_WBITS); if (err != Z_OK) { - delete[] newdata; - return NULL; + return false; } - err = inflate(&stream, Z_FINISH); if (err != Z_STREAM_END) { inflateEnd(&stream); - delete[] newdata; - return NULL; + return false; } err = inflateEnd(&stream); if (err != Z_OK) { - delete[] newdata; - return NULL; + return false; } - *complen = isize; - return newdata; + return true; } //========================================================================== diff --git a/src/sound/i_music.h b/src/sound/i_music.h index d587d31290..5948ceb7c5 100644 --- a/src/sound/i_music.h +++ b/src/sound/i_music.h @@ -34,6 +34,8 @@ #ifndef __I_MUSIC_H__ #define __I_MUSIC_H__ +#include + #include "doomdef.h" class FileReader; @@ -52,7 +54,7 @@ void I_SetMusicVolume (float volume); // Registers a song handle to song data. class MusInfo; -MusInfo *I_RegisterSong (const char *file, BYTE *musiccache, int offset, int length, int device); +MusInfo *I_RegisterSong (std::auto_ptr reader, int device); MusInfo *I_RegisterCDSong (int track, int cdid = 0); MusInfo *I_RegisterURLSong (const char *url); diff --git a/src/sound/i_musicinterns.h b/src/sound/i_musicinterns.h index fa04cfa512..43e52a722e 100644 --- a/src/sound/i_musicinterns.h +++ b/src/sound/i_musicinterns.h @@ -501,7 +501,7 @@ protected: class MUSSong2 : public MIDIStreamer { public: - MUSSong2(FILE *file, BYTE *musiccache, int length, EMidiDevice type); + MUSSong2(std::auto_ptr reader, EMidiDevice type); ~MUSSong2(); MusInfo *GetOPLDumper(const char *filename); @@ -527,7 +527,7 @@ protected: class MIDISong2 : public MIDIStreamer { public: - MIDISong2(FILE *file, BYTE *musiccache, int length, EMidiDevice type); + MIDISong2(std::auto_ptr reader, EMidiDevice type); ~MIDISong2(); MusInfo *GetOPLDumper(const char *filename); @@ -584,7 +584,7 @@ protected: class HMISong : public MIDIStreamer { public: - HMISong(FILE *file, BYTE *musiccache, int length, EMidiDevice type); + HMISong(std::auto_ptr reader, EMidiDevice type); ~HMISong(); MusInfo *GetOPLDumper(const char *filename); @@ -627,7 +627,7 @@ protected: class XMISong : public MIDIStreamer { public: - XMISong(FILE *file, BYTE *musiccache, int length, EMidiDevice type); + XMISong(std::auto_ptr reader, EMidiDevice type); ~XMISong(); MusInfo *GetOPLDumper(const char *filename); @@ -666,7 +666,8 @@ protected: class StreamSong : public MusInfo { public: - StreamSong (const char *file, int offset, int length); + StreamSong (std::auto_ptr reader); + StreamSong (const char *url); ~StreamSong (); void Play (bool looping, int subsong); void Pause (); @@ -689,7 +690,7 @@ protected: class OPLMUSSong : public StreamSong { public: - OPLMUSSong (FILE *file, BYTE *musiccache, int length); + OPLMUSSong (std::auto_ptr reader); ~OPLMUSSong (); void Play (bool looping, int subsong); bool IsPlaying (); @@ -738,17 +739,17 @@ protected: class CDDAFile : public CDSong { public: - CDDAFile (FILE *file, int length); + CDDAFile (std::auto_ptr reader); }; // Module played via foo_dumb ----------------------------------------------- -MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int len); +MusInfo *MOD_OpenSong(std::auto_ptr &reader); // Music played via Game Music Emu ------------------------------------------ const char *GME_CheckFormat(uint32 header); -MusInfo *GME_OpenSong(FILE *file, BYTE *musiccache, int len, const char *fmt); +MusInfo *GME_OpenSong(std::auto_ptr &reader, const char *fmt); // -------------------------------------------------------------------------- diff --git a/src/sound/i_sound.cpp b/src/sound/i_sound.cpp index ec20711067..9d45ebc685 100644 --- a/src/sound/i_sound.cpp +++ b/src/sound/i_sound.cpp @@ -172,7 +172,7 @@ public: { return NULL; } - SoundStream *OpenStream (const char *filename, int flags, int offset, int length) + SoundStream *OpenStream (std::auto_ptr reader, int flags) { return NULL; } @@ -344,12 +344,13 @@ FString SoundRenderer::GatherStats () short *SoundRenderer::DecodeSample(int outlen, const void *coded, int sizebytes, ECodecType ctype) { + MemoryReader reader((const char*)coded, sizebytes); short *samples = (short*)calloc(1, outlen); ChannelConfig chans; SampleType type; int srate; - std::auto_ptr decoder(CreateDecoder((const BYTE*)coded, sizebytes)); + std::auto_ptr decoder(CreateDecoder(&reader)); if(!decoder.get()) return samples; decoder->getInfo(&srate, &chans, &type); @@ -540,44 +541,30 @@ SoundHandle SoundRenderer::LoadSoundVoc(BYTE *sfxdata, int length) return retval; } - -SoundDecoder *SoundRenderer::CreateDecoder(const BYTE *sfxdata, int length) +SoundStream *SoundRenderer::OpenStream(const char *url, int flags) { - SoundDecoder *decoder = NULL; -#ifdef HAVE_MPG123 - decoder = new MPG123Decoder; - if(decoder->open((const char*)sfxdata, length)) - return decoder; - - delete decoder; - decoder = NULL; -#endif -#ifdef HAVE_SNDFILE - decoder = new SndFileDecoder; - if(decoder->open((const char*)sfxdata, length)) - return decoder; - - delete decoder; - decoder = NULL; -#endif - return decoder; + return 0; } -SoundDecoder* SoundRenderer::CreateDecoder(const char *fname, int offset, int length) +SoundDecoder *SoundRenderer::CreateDecoder(FileReader *reader) { SoundDecoder *decoder = NULL; + int pos = reader->Tell(); + #ifdef HAVE_MPG123 decoder = new MPG123Decoder; - if(decoder->open(fname, offset, length)) + if(decoder->open(reader)) return decoder; + reader->Seek(pos, SEEK_SET); delete decoder; decoder = NULL; #endif #ifdef HAVE_SNDFILE decoder = new SndFileDecoder; - if(decoder->open(fname, offset, length)) + if(decoder->open(reader)) return decoder; + reader->Seek(pos, SEEK_SET); delete decoder; decoder = NULL; diff --git a/src/sound/i_sound.h b/src/sound/i_sound.h index b82ea85aac..29dd947f05 100644 --- a/src/sound/i_sound.h +++ b/src/sound/i_sound.h @@ -35,9 +35,13 @@ #ifndef __I_SOUND__ #define __I_SOUND__ +#include + #include "doomtype.h" #include "i_soundinternal.h" +class FileReader; + enum ECodecType { CODEC_Unknown, @@ -103,7 +107,8 @@ public: // Streaming sounds. virtual SoundStream *CreateStream (SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata) = 0; - virtual SoundStream *OpenStream (const char *filename, int flags, int offset, int length) = 0; + virtual SoundStream *OpenStream (std::auto_ptr reader, int flags) = 0; + virtual SoundStream *OpenStream (const char *url, int flags); // Starts a sound. virtual FISoundChannel *StartSound (SoundHandle sfx, float vol, int pitch, int chanflags, FISoundChannel *reuse_chan) = 0; @@ -154,8 +159,7 @@ public: virtual void DrawWaveDebug(int mode); protected: - virtual SoundDecoder *CreateDecoder(const BYTE *sfxdata, int length); - virtual SoundDecoder *CreateDecoder(const char *fname, int offset, int length); + virtual SoundDecoder *CreateDecoder(FileReader *reader); }; extern SoundRenderer *GSnd; diff --git a/src/sound/i_soundinternal.h b/src/sound/i_soundinternal.h index 64e065b6ee..0a7e8b0e0b 100644 --- a/src/sound/i_soundinternal.h +++ b/src/sound/i_soundinternal.h @@ -7,6 +7,8 @@ #include "basictypes.h" #include "vectors.h" +class FileReader; + // For convenience, this structure matches FMOD_REVERB_PROPERTIES. // Since I can't very well #include system-specific stuff in the // main game files, I duplicate it here. @@ -129,8 +131,7 @@ struct SoundDecoder virtual ~SoundDecoder() { } protected: - virtual bool open(const char *data, size_t length) = 0; - virtual bool open(const char *fname, size_t offset, size_t length) = 0; + virtual bool open(FileReader *reader) = 0; friend class SoundRenderer; private: diff --git a/src/sound/mpg123_decoder.cpp b/src/sound/mpg123_decoder.cpp index c3a811b407..63ccb6922c 100644 --- a/src/sound/mpg123_decoder.cpp +++ b/src/sound/mpg123_decoder.cpp @@ -1,4 +1,5 @@ #include "mpg123_decoder.h" +#include "files.h" #ifdef HAVE_MPG123 static bool inited = false; @@ -7,99 +8,30 @@ static bool inited = false; off_t MPG123Decoder::file_lseek(void *handle, off_t offset, int whence) { MPG123Decoder *self = reinterpret_cast(handle); + FileReader *reader = self->Reader; - long cur = ftell(self->File); - if(cur < 0) return -1; - - switch(whence) + if(whence == SEEK_SET) + offset += self->StartOffset; + else if(whence == SEEK_CUR) { - case SEEK_SET: - if(offset < 0 || offset > (off_t)self->FileLength) - return -1; - cur = offset; - break; - - case SEEK_CUR: - cur -= self->FileOffset; - if((offset > 0 && (off_t)(self->FileLength-cur) < offset) || - (offset < 0 && (off_t)cur < -offset)) - return -1; - cur += offset; - break; - - case SEEK_END: - if(offset > 0 || -offset > (off_t)self->FileLength) - return -1; - cur = self->FileLength + offset; - break; - - default: + if(offset < 0 && reader->Tell()+offset < self->StartOffset) + return -1; + } + else if(whence == SEEK_END) + { + if(offset < 0 && reader->GetLength()+offset < self->StartOffset) return -1; } - if(fseek(self->File, cur + self->FileOffset, SEEK_SET) != 0) + if(reader->Seek(offset, whence) != 0) return -1; - return cur; + return reader->Tell() - self->StartOffset; } ssize_t MPG123Decoder::file_read(void *handle, void *buffer, size_t bytes) { - MPG123Decoder *self = reinterpret_cast(handle); - - long cur = ftell(self->File); - if(cur < 0) return -1; - - cur -= self->FileOffset; - if(bytes > (size_t)(self->FileLength-cur)) - bytes = self->FileLength-cur; - - return fread(buffer, 1, bytes, self->File); -} - - -off_t MPG123Decoder::mem_lseek(void *handle, off_t offset, int whence) -{ - MPG123Decoder *self = reinterpret_cast(handle); - - switch(whence) - { - case SEEK_SET: - if(offset < 0 || offset > (off_t)self->MemLength) - return -1; - self->MemPos = offset; - break; - - case SEEK_CUR: - if((offset > 0 && (off_t)(self->MemLength-self->MemPos) < offset) || - (offset < 0 && (off_t)self->MemPos < -offset)) - return -1; - self->MemPos += offset; - break; - - case SEEK_END: - if(offset > 0 || -offset > (off_t)self->MemLength) - return -1; - self->MemPos = self->MemLength + offset; - break; - - default: - return -1; - } - - return self->MemPos; -} - -ssize_t MPG123Decoder::mem_read(void *handle, void *buffer, size_t bytes) -{ - MPG123Decoder *self = reinterpret_cast(handle); - - if(bytes > self->MemLength-self->MemPos) - bytes = self->MemLength-self->MemPos; - - memcpy(buffer, self->MemData+self->MemPos, bytes); - self->MemPos += bytes; - - return bytes; + FileReader *reader = reinterpret_cast(handle)->Reader; + return reader->Read(buffer, bytes); } @@ -111,12 +43,9 @@ MPG123Decoder::~MPG123Decoder() mpg123_delete(MPG123); MPG123 = 0; } - if(File) - fclose(File); - File = 0; } -bool MPG123Decoder::open(const char *data, size_t length) +bool MPG123Decoder::open(FileReader *reader) { if(!inited) { @@ -125,91 +54,14 @@ bool MPG123Decoder::open(const char *data, size_t length) inited = true; } - // Check for ID3 tags and skip them - if(length > 10 && memcmp(data, "ID3", 3) == 0 && - (BYTE)data[3] <= 4 && (BYTE)data[4] != 0xff && - (data[5]&0x0f) == 0 && (data[6]&0x80) == 0 && - (data[7]&0x80) == 0 && (data[8]&0x80) == 0 && - (data[9]&0x80) == 0) - { - // ID3v2 - int start_offset; - start_offset = (data[6]<<21) | (data[7]<<14) | - (data[8]<< 7) | (data[9] ); - start_offset += ((data[5]&0x10) ? 20 : 10); - length -= start_offset; - data += start_offset; - } - - if(length > 128 && memcmp(data+length-128, "TAG", 3) == 0) // ID3v1 - length -= 128; - - // Check for a frame header - bool frame_ok = false; - if(length > 3) - { - if((BYTE)data[0] == 0xff && - ((data[1]&0xfe) == 0xfa/*MPEG-1*/ || (data[1]&0xfe) == 0xf2/*MPEG-2*/)) - { - int brate_idx = (data[2]>>4) & 0x0f; - int srate_idx = (data[2]>>2) & 0x03; - if(brate_idx != 0 && brate_idx != 15 && srate_idx != 3) - frame_ok = true; - } - } - - if(frame_ok) - { - MemData = data; - MemPos = 0; - MemLength = length; - - MPG123 = mpg123_new(NULL, NULL); - if(mpg123_replace_reader_handle(MPG123, mem_read, mem_lseek, NULL) == MPG123_OK && - mpg123_open_handle(MPG123, this) == MPG123_OK) - { - int enc, channels; - long srate; - - if(mpg123_getformat(MPG123, &srate, &channels, &enc) == MPG123_OK) - { - if((channels == 1 || channels == 2) && srate > 0 && - mpg123_format_none(MPG123) == MPG123_OK && - mpg123_format(MPG123, srate, channels, MPG123_ENC_SIGNED_16) == MPG123_OK) - { - // All OK - Done = false; - return true; - } - } - mpg123_close(MPG123); - } - mpg123_delete(MPG123); - MPG123 = 0; - } - - return false; -} - -bool MPG123Decoder::open(const char *fname, size_t offset, size_t length) -{ - if(!inited) - { - if(mpg123_init() != MPG123_OK) - return false; - inited = true; - } - - FileLength = length; - FileOffset = offset; - File = fopen(fname, "rb"); - if(!File || fseek(File, FileOffset, SEEK_SET) != 0) - return false; + Reader = reader; + StartOffset = 0; char data[10]; if(file_read(this, data, 10) != 10) return false; + int start_offset = 0; // Check for ID3 tags and skip them if(memcmp(data, "ID3", 3) == 0 && (BYTE)data[3] <= 4 && (BYTE)data[4] != 0xff && @@ -218,25 +70,18 @@ bool MPG123Decoder::open(const char *fname, size_t offset, size_t length) (data[9]&0x80) == 0) { // ID3v2 - int start_offset; start_offset = (data[6]<<21) | (data[7]<<14) | (data[8]<< 7) | (data[9] ); start_offset += ((data[5]&0x10) ? 20 : 10); - offset += start_offset; - length -= start_offset; } - if(file_lseek(this, -128, SEEK_END) > 0 && memcmp(data, "TAG", 3) == 0) // ID3v1 - length -= 128; - - FileLength = length; - FileOffset = offset; + StartOffset = start_offset; if(file_lseek(this, 0, SEEK_SET) != 0) return false; // Check for a frame header bool frame_ok = false; - if(file_read(this, data, 3) != 3) + if(file_read(this, data, 3) == 3) { if((BYTE)data[0] == 0xff && ((data[1]&0xfe) == 0xfa/*MPEG-1*/ || (data[1]&0xfe) == 0xf2/*MPEG-2*/)) diff --git a/src/sound/mpg123_decoder.h b/src/sound/mpg123_decoder.h index 216eae2f94..0d8d2e7ab8 100644 --- a/src/sound/mpg123_decoder.h +++ b/src/sound/mpg123_decoder.h @@ -15,29 +15,21 @@ struct MPG123Decoder : public SoundDecoder virtual bool seek(size_t ms_offset); virtual size_t getSampleOffset(); - MPG123Decoder() : MPG123(0), File(0) { } + MPG123Decoder() : MPG123(0) { } virtual ~MPG123Decoder(); protected: - virtual bool open(const char *data, size_t length); - virtual bool open(const char *fname, size_t offset, size_t length); + virtual bool open(FileReader *reader); private: mpg123_handle *MPG123; bool Done; - FILE *File; - size_t FileLength; - size_t FileOffset; + FileReader *Reader; + int StartOffset; static off_t file_lseek(void *handle, off_t offset, int whence); static ssize_t file_read(void *handle, void *buffer, size_t bytes); - const char *MemData; - size_t MemLength; - size_t MemPos; - static off_t mem_lseek(void *handle, off_t offset, int whence); - static ssize_t mem_read(void *handle, void *buffer, size_t bytes); - // Make non-copyable MPG123Decoder(const MPG123Decoder &rhs); MPG123Decoder& operator=(const MPG123Decoder &rhs); diff --git a/src/sound/music_cd.cpp b/src/sound/music_cd.cpp index 5b400ba821..a271d1b228 100644 --- a/src/sound/music_cd.cpp +++ b/src/sound/music_cd.cpp @@ -1,5 +1,6 @@ #include "i_musicinterns.h" #include "i_cd.h" +#include "files.h" void CDSong::Play (bool looping, int subsong) { @@ -78,31 +79,31 @@ bool CDSong::IsPlaying () return m_Status != STATE_Stopped; } -CDDAFile::CDDAFile (FILE *file, int length) +CDDAFile::CDDAFile (std::auto_ptr reader) : CDSong () { DWORD chunk; WORD track; DWORD discid; - long endpos = ftell (file) + length - 8; + long endpos = reader->Tell() + reader->GetLength() - 8; // I_RegisterSong already identified this as a CDDA file, so we // just need to check the contents we're interested in. - fseek (file, 12, SEEK_CUR); + reader->Seek(12, SEEK_CUR); - while (ftell (file) < endpos) + while (reader->Tell() < endpos) { - fread (&chunk, 4, 1, file); + reader->Read(&chunk, 4); if (chunk != (('f')|(('m')<<8)|(('t')<<16)|((' ')<<24))) { - fread (&chunk, 4, 1, file); - fseek (file, chunk, SEEK_CUR); + reader->Read(&chunk, 4); + reader->Seek(chunk, SEEK_CUR); } else { - fseek (file, 6, SEEK_CUR); - fread (&track, 2, 1, file); - fread (&discid, 4, 1, file); + reader->Seek(6, SEEK_CUR); + reader->Read(&track, 2); + reader->Read(&discid, 4); if (CD_InitID (discid) && CD_CheckTrack (track)) { diff --git a/src/sound/music_dumb.cpp b/src/sound/music_dumb.cpp index 8405228a3c..bcacefe401 100644 --- a/src/sound/music_dumb.cpp +++ b/src/sound/music_dumb.cpp @@ -30,6 +30,7 @@ #include "c_cvars.h" #include "i_sound.h" #include "i_system.h" +#include "files.h" #undef CDECL // w32api's windef.h defines this #include "../dumb/include/dumb.h" @@ -512,31 +513,24 @@ static DUMBFILE_SYSTEM mem_dfs = { // //========================================================================== -DUMBFILE *dumb_read_allfile(dumbfile_mem_status *filestate, BYTE *start, FILE *file, BYTE *musiccache, int lenhave, int lenfull) +DUMBFILE *dumb_read_allfile(dumbfile_mem_status *filestate, BYTE *start, std::auto_ptr &reader, int lenhave, int lenfull) { filestate->size = lenfull; filestate->offset = 0; if (lenhave >= lenfull) - { filestate->ptr = (BYTE *)start; - return dumbfile_open_ex(filestate, &mem_dfs); - } - if (musiccache != NULL) - { - filestate->ptr = (BYTE *)musiccache; - } - else - { - BYTE *mem = new BYTE[lenfull]; - memcpy(mem, start, lenhave); - if (fread(mem + lenhave, 1, lenfull - lenhave, file) != (size_t)(lenfull - lenhave)) - { - delete[] mem; - return NULL; - } - filestate->ptr = mem; - } - return dumbfile_open_ex(filestate, &mem_dfs); + else + { + BYTE *mem = new BYTE[lenfull]; + memcpy(mem, start, lenhave); + if (reader->Read(mem + lenhave, lenfull - lenhave) != (lenfull - lenhave)) + { + delete[] mem; + return NULL; + } + filestate->ptr = mem; + } + return dumbfile_open_ex(filestate, &mem_dfs); } //========================================================================== @@ -856,7 +850,7 @@ static void MOD_SetAutoChip(DUH *duh) // //========================================================================== -MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int size) +MusInfo *MOD_OpenSong(std::auto_ptr &reader) { DUH *duh = 0; int headsize; @@ -880,40 +874,36 @@ MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int size) atterm(dumb_exit); + int size = reader->GetLength(); + fpos = reader->Tell(); + filestate.ptr = start; filestate.offset = 0; headsize = MIN((int)sizeof(start), size); - if (musiccache != NULL) - { - memcpy(start, musiccache, headsize); - } - else - { - fpos = ftell(file); - if ((size_t)headsize != fread(start, 1, headsize, file)) - { - return NULL; - } - } + + if (headsize != reader->Read(start, headsize)) + { + return NULL; + } if (size >= 4 && dstart[0] == MAKE_ID('I','M','P','M')) { is_it = true; - if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size))) + if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size))) { duh = dumb_read_it_quick(f); } } else if (size >= 17 && !memcmp(start, "Extended Module: ", 17)) { - if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size))) + if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size))) { duh = dumb_read_xm_quick(f); } } else if (size >= 0x30 && dstart[11] == MAKE_ID('S','C','R','M')) { - if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size))) + if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size))) { duh = dumb_read_s3m_quick(f); } @@ -924,7 +914,7 @@ MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int size) !memcmp( &start[20], "BMOD2STM", 8 ) || !memcmp( &start[20], "WUZAMOD!", 8 ) ) ) { - if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size))) + if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size))) { duh = dumb_read_stm_quick(f); } @@ -933,21 +923,21 @@ MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int size) ((start[0] == 0x69 && start[1] == 0x66) || (start[0] == 0x4A && start[1] == 0x4E))) { - if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size))) + if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size))) { duh = dumb_read_669_quick(f); } } else if (size >= 0x30 && dstart[11] == MAKE_ID('P','T','M','F')) { - if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size))) + if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size))) { duh = dumb_read_ptm_quick(f); } } else if (size >= 4 && dstart[0] == MAKE_ID('P','S','M',' ')) { - if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size))) + if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size))) { duh = dumb_read_psm_quick(f, 0/*start_order*/); /*start_order = 0;*/ @@ -955,14 +945,14 @@ MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int size) } else if (size >= 4 && dstart[0] == (DWORD)MAKE_ID('P','S','M',254)) { - if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size))) + if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size))) { duh = dumb_read_old_psm_quick(f); } } else if (size >= 3 && start[0] == 'M' && start[1] == 'T' && start[2] == 'M') { - if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size))) + if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size))) { duh = dumb_read_mtm_quick(f); } @@ -972,7 +962,7 @@ MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int size) dstart[2] == MAKE_ID('A','M',' ',' ') || dstart[2] == MAKE_ID('A','M','F','F'))) { - if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size))) + if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size))) { duh = dumb_read_riff_quick(f); } @@ -981,7 +971,7 @@ MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int size) !memcmp( start, "ASYLUM Music Format", 19 ) && !memcmp( start + 19, " V1.0", 5 ) ) { - if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size))) + if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size))) { duh = dumb_read_asy_quick(f); } @@ -990,7 +980,7 @@ MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int size) dstart[0] == MAKE_ID('O','K','T','A') && dstart[1] == MAKE_ID('S','O','N','G')) { - if ((f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size))) + if ((f = dumb_read_allfile(&filestate, start, reader, headsize, size))) { duh = dumb_read_okt_quick(f); } @@ -1001,12 +991,9 @@ MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int size) is_dos = false; if (filestate.ptr == (BYTE *)start) { - if (!(f = dumb_read_allfile(&filestate, start, file, musiccache, headsize, size))) + if (!(f = dumb_read_allfile(&filestate, start, reader, headsize, size))) { - if (file != NULL) - { - fseek(file, fpos, SEEK_SET); - } + reader->Seek(fpos, SEEK_SET); return NULL; } } @@ -1053,15 +1040,13 @@ MusInfo *MOD_OpenSong(FILE *file, BYTE *musiccache, int size) else { // Reposition file pointer for other codecs to do their checks. - if (file != NULL) - { - fseek(file, fpos, SEEK_SET); - } + reader->Seek(fpos, SEEK_SET); } - if (filestate.ptr != (BYTE *)start && filestate.ptr != musiccache) + if (filestate.ptr != (BYTE *)start) { delete[] const_cast(filestate.ptr); } + if(state) reader.reset(); return state; } diff --git a/src/sound/music_gme.cpp b/src/sound/music_gme.cpp index 7f017b7d2c..7db5110b79 100644 --- a/src/sound/music_gme.cpp +++ b/src/sound/music_gme.cpp @@ -42,6 +42,7 @@ #include "critsec.h" #include #include "v_text.h" +#include "files.h" // MACROS ------------------------------------------------------------------ @@ -104,7 +105,7 @@ const char *GME_CheckFormat(uint32 id) // //========================================================================== -MusInfo *GME_OpenSong(FILE *file, BYTE *musiccache, int len, const char *fmt) +MusInfo *GME_OpenSong(std::auto_ptr &reader, const char *fmt) { gme_type_t type; gme_err_t err; @@ -123,31 +124,29 @@ MusInfo *GME_OpenSong(FILE *file, BYTE *musiccache, int len, const char *fmt) { return NULL; } - if (musiccache != NULL) - { - song = musiccache; - } - else - { - song = new BYTE[len]; - if (fread(song, 1, len, file) != (size_t)len) - { - delete[] song; - gme_delete(emu); - return NULL; - } - } + + int fpos = reader->Tell(); + int len = reader->GetLength(); + song = new BYTE[len]; + if (reader->Read(song, len) != len) + { + delete[] song; + gme_delete(emu); + reader->Seek(fpos, SEEK_SET); + return NULL; + } + err = gme_load_data(emu, song, len); - if (song != musiccache) - { - delete[] song; - } + delete[] song; + if (err != NULL) { Printf("Failed loading song: %s\n", err); gme_delete(emu); + reader->Seek(fpos, SEEK_SET); return NULL; } + reader.reset(); return new GMESong(emu, sample_rate); } diff --git a/src/sound/music_hmi_midiout.cpp b/src/sound/music_hmi_midiout.cpp index 15b50da87f..9df28d6346 100644 --- a/src/sound/music_hmi_midiout.cpp +++ b/src/sound/music_hmi_midiout.cpp @@ -38,6 +38,7 @@ #include "templates.h" #include "doomdef.h" #include "m_swap.h" +#include "files.h" // MACROS ------------------------------------------------------------------ @@ -127,7 +128,7 @@ extern char MIDI_CommonLengths[15]; // //========================================================================== -HMISong::HMISong (FILE *file, BYTE *musiccache, int len, EMidiDevice type) +HMISong::HMISong (std::auto_ptr reader, EMidiDevice type) : MIDIStreamer(type), MusHeader(0), Tracks(0) { #ifdef _WIN32 @@ -136,6 +137,7 @@ HMISong::HMISong (FILE *file, BYTE *musiccache, int len, EMidiDevice type) return; } #endif + int len = reader->GetLength(); if (len < 0x100) { // Way too small to be HMI. return; @@ -143,15 +145,8 @@ HMISong::HMISong (FILE *file, BYTE *musiccache, int len, EMidiDevice type) MusHeader = new BYTE[len]; SongLen = len; NumTracks = 0; - if (file != NULL) - { - if (fread(MusHeader, 1, len, file) != (size_t)len) - return; - } - else - { - memcpy(MusHeader, musiccache, len); - } + if (reader->Read(MusHeader, len) != len) + return; // Do some validation of the MIDI file if (memcmp(MusHeader, HMI_SONG_MAGIC, sizeof(HMI_SONG_MAGIC)) == 0) diff --git a/src/sound/music_mus_midiout.cpp b/src/sound/music_mus_midiout.cpp index ee84239d6d..e7e0894bbd 100644 --- a/src/sound/music_mus_midiout.cpp +++ b/src/sound/music_mus_midiout.cpp @@ -42,6 +42,7 @@ #include "templates.h" #include "doomdef.h" #include "m_swap.h" +#include "files.h" // MACROS ------------------------------------------------------------------ @@ -91,7 +92,7 @@ static const BYTE CtrlTranslate[15] = // //========================================================================== -MUSSong2::MUSSong2 (FILE *file, BYTE *musiccache, int len, EMidiDevice type) +MUSSong2::MUSSong2 (std::auto_ptr reader, EMidiDevice type) : MIDIStreamer(type), MusHeader(0), MusBuffer(0) { #ifdef _WIN32 @@ -104,11 +105,7 @@ MUSSong2::MUSSong2 (FILE *file, BYTE *musiccache, int len, EMidiDevice type) BYTE front[32]; int start; - if (file == NULL) - { - memcpy(front, musiccache, sizeof(front)); - } - else if (fread(front, 1, sizeof(front), file) != sizeof(front)) + if (reader->Read(front, sizeof(front)) != sizeof(front)) { return; } @@ -124,24 +121,17 @@ MUSSong2::MUSSong2 (FILE *file, BYTE *musiccache, int len, EMidiDevice type) } // Read the remainder of the song. - len = int(len - start); + int len = int(reader->GetLength() - start); if (len < (int)sizeof(MusHeader)) { // It's too short. return; } MusHeader = (MUSHeader *)new BYTE[len]; - if (file == NULL) - { - memcpy(MusHeader, musiccache + start, len); - } - else - { - memcpy(MusHeader, front + start, sizeof(front) - start); - if (fread((BYTE *)MusHeader + sizeof(front) - start, 1, len - (sizeof(front) - start), file) != (size_t)(len - (32 - start))) - { - return; - } - } + memcpy(MusHeader, front + start, sizeof(front) - start); + if (reader->Read((BYTE *)MusHeader + sizeof(front) - start, len - (sizeof(front) - start)) != (len - (32 - start))) + { + return; + } // Do some validation of the MUS file. if (LittleShort(MusHeader->NumChans) > 15) diff --git a/src/sound/music_mus_opl.cpp b/src/sound/music_mus_opl.cpp index fb0d78df5f..c8b694a21a 100644 --- a/src/sound/music_mus_opl.cpp +++ b/src/sound/music_mus_opl.cpp @@ -22,11 +22,11 @@ CUSTOM_CVAR (Int, opl_numchips, 2, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR(Int, opl_core, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -OPLMUSSong::OPLMUSSong (FILE *file, BYTE *musiccache, int len) +OPLMUSSong::OPLMUSSong (std::auto_ptr reader) { int samples = int(OPL_SAMPLE_RATE / 14); - Music = new OPLmusicFile (file, musiccache, len); + Music = new OPLmusicFile (reader.get()); m_Stream = GSnd->CreateStream (FillStream, samples*4, (opl_core == 0 ? SoundStream::Mono : 0) | SoundStream::Float, int(OPL_SAMPLE_RATE), this); diff --git a/src/sound/music_pseudo_mididevice.cpp b/src/sound/music_pseudo_mididevice.cpp index 6c1c90b4cb..ba52f0a082 100644 --- a/src/sound/music_pseudo_mididevice.cpp +++ b/src/sound/music_pseudo_mididevice.cpp @@ -38,6 +38,7 @@ #include "templates.h" #include "doomdef.h" #include "m_swap.h" +#include "files.h" // MACROS ------------------------------------------------------------------ @@ -253,10 +254,12 @@ int FMODMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWORD), v bool FMODMIDIDevice::Preprocess(MIDIStreamer *song, bool looping) { - TArray midi; + std::auto_ptr reader(new MemoryArrayReader(NULL, 0)); + song->CreateSMF(reader->GetArray(), looping ? 0 : 1); + reader->UpdateLength(); - song->CreateSMF(midi, looping ? 0 : 1); - bLooping = looping; - Stream = GSnd->OpenStream((char *)&midi[0], looping ? SoundStream::Loop : 0, -1, midi.Size()); - return false; + bLooping = looping; + Stream = GSnd->OpenStream(std::auto_ptr(reader.release()), + looping ? SoundStream::Loop : 0); + return false; } diff --git a/src/sound/music_smf_midiout.cpp b/src/sound/music_smf_midiout.cpp index 6fd51f1490..6f73277d33 100644 --- a/src/sound/music_smf_midiout.cpp +++ b/src/sound/music_smf_midiout.cpp @@ -41,6 +41,7 @@ #include "templates.h" #include "doomdef.h" #include "m_swap.h" +#include "files.h" // MACROS ------------------------------------------------------------------ @@ -101,7 +102,7 @@ char MIDI_CommonLengths[15] = { 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // //========================================================================== -MIDISong2::MIDISong2 (FILE *file, BYTE *musiccache, int len, EMidiDevice type) +MIDISong2::MIDISong2 (std::auto_ptr reader, EMidiDevice type) : MIDIStreamer(type), MusHeader(0), Tracks(0) { int p; @@ -113,17 +114,10 @@ MIDISong2::MIDISong2 (FILE *file, BYTE *musiccache, int len, EMidiDevice type) return; } #endif - MusHeader = new BYTE[len]; - SongLen = len; - if (file != NULL) - { - if (fread(MusHeader, 1, len, file) != (size_t)len) - return; - } - else - { - memcpy(MusHeader, musiccache, len); - } + SongLen = reader->GetLength(); + MusHeader = new BYTE[SongLen]; + if (reader->Read(MusHeader, SongLen) != SongLen) + return; // Do some validation of the MIDI file if (MusHeader[4] != 0 || MusHeader[5] != 0 || MusHeader[6] != 0 || MusHeader[7] != 6) @@ -153,7 +147,7 @@ MIDISong2::MIDISong2 (FILE *file, BYTE *musiccache, int len, EMidiDevice type) Tracks = new TrackInfo[NumTracks]; // Gather information about each track - for (i = 0, p = 14; i < NumTracks && p < len + 8; ++i) + for (i = 0, p = 14; i < NumTracks && p < SongLen + 8; ++i) { DWORD chunkLen = (MusHeader[p+4]<<24) | @@ -161,9 +155,9 @@ MIDISong2::MIDISong2 (FILE *file, BYTE *musiccache, int len, EMidiDevice type) (MusHeader[p+6]<<8) | (MusHeader[p+7]); - if (chunkLen + p + 8 > (DWORD)len) + if (chunkLen + p + 8 > (DWORD)SongLen) { // Track too long, so truncate it - chunkLen = len - p - 8; + chunkLen = SongLen - p - 8; } if (MusHeader[p+0] == 'M' && diff --git a/src/sound/music_stream.cpp b/src/sound/music_stream.cpp index 72c825a28a..1f528c3091 100644 --- a/src/sound/music_stream.cpp +++ b/src/sound/music_stream.cpp @@ -52,9 +52,14 @@ StreamSong::~StreamSong () } } -StreamSong::StreamSong (const char *filename_or_data, int offset, int len) +StreamSong::StreamSong (std::auto_ptr reader) { - m_Stream = GSnd->OpenStream (filename_or_data, SoundStream::Loop, offset, len); + m_Stream = GSnd->OpenStream (reader, SoundStream::Loop); +} + +StreamSong::StreamSong (const char *url) +{ + m_Stream = GSnd->OpenStream (url, SoundStream::Loop); } bool StreamSong::IsPlaying () diff --git a/src/sound/music_xmi_midiout.cpp b/src/sound/music_xmi_midiout.cpp index fe1761181c..f50e8669d4 100644 --- a/src/sound/music_xmi_midiout.cpp +++ b/src/sound/music_xmi_midiout.cpp @@ -38,6 +38,7 @@ #include "templates.h" #include "doomdef.h" #include "m_swap.h" +#include "files.h" // MACROS ------------------------------------------------------------------ @@ -107,7 +108,7 @@ extern char MIDI_CommonLengths[15]; // //========================================================================== -XMISong::XMISong (FILE *file, BYTE *musiccache, int len, EMidiDevice type) +XMISong::XMISong (std::auto_ptr reader, EMidiDevice type) : MIDIStreamer(type), MusHeader(0), Songs(0) { #ifdef _WIN32 @@ -116,20 +117,13 @@ XMISong::XMISong (FILE *file, BYTE *musiccache, int len, EMidiDevice type) return; } #endif - MusHeader = new BYTE[len]; - SongLen = len; - if (file != NULL) - { - if (fread(MusHeader, 1, len, file) != (size_t)len) - return; - } - else - { - memcpy(MusHeader, musiccache, len); - } + SongLen = reader->GetLength(); + MusHeader = new BYTE[SongLen]; + if (reader->Read(MusHeader, SongLen) != SongLen) + return; // Find all the songs in this file. - NumSongs = FindXMIDforms(MusHeader, len, NULL); + NumSongs = FindXMIDforms(MusHeader, SongLen, NULL); if (NumSongs == 0) { return; @@ -147,7 +141,7 @@ XMISong::XMISong (FILE *file, BYTE *musiccache, int len, EMidiDevice type) Songs = new TrackInfo[NumSongs]; memset(Songs, 0, sizeof(*Songs) * NumSongs); - FindXMIDforms(MusHeader, len, Songs); + FindXMIDforms(MusHeader, SongLen, Songs); CurrSong = Songs; DPrintf("XMI song count: %d\n", NumSongs); } diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 8bb4be5bc7..706c26ae74 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -156,6 +156,7 @@ class OpenALSoundStream : public SoundStream ALfloat Volume; + std::auto_ptr Reader; std::vector DecoderData; std::auto_ptr Decoder; static bool DecoderCallback(SoundStream *_sstream, void *ptr, int length, void *user) @@ -440,54 +441,13 @@ public: return true; } - bool Init(const char *fname, int offset, int length, bool loop) + bool Init(std::auto_ptr reader, bool loop) { if(!SetupSource()) return false; - Decoder.reset(Renderer->CreateDecoder(fname, offset, length)); - if(!Decoder.get()) return false; - - Callback = DecoderCallback; - UserData = NULL; - Format = AL_NONE; - - ChannelConfig chans; - SampleType type; - int srate; - - Decoder->getInfo(&srate, &chans, &type); - if(chans == ChannelConfig_Mono) - { - if(type == SampleType_UInt8) Format = AL_FORMAT_MONO8; - if(type == SampleType_Int16) Format = AL_FORMAT_MONO16; - } - if(chans == ChannelConfig_Stereo) - { - if(type == SampleType_UInt8) Format = AL_FORMAT_STEREO8; - if(type == SampleType_Int16) Format = AL_FORMAT_STEREO16; - } - - if(Format == AL_NONE) - { - Printf("Unsupported audio format (0x%x / 0x%x)\n", chans, type); - return false; - } - SampleRate = srate; - Looping = loop; - - Data.resize((size_t)(0.2 * SampleRate) * 4); - - return true; - } - - bool Init(const BYTE *data, int length, bool loop) - { - if(!SetupSource()) - return false; - - DecoderData.insert(DecoderData.end(), data, data+length); - Decoder.reset(Renderer->CreateDecoder(&DecoderData[0], DecoderData.size())); + Reader = reader; + Decoder.reset(Renderer->CreateDecoder(Reader.get())); if(!Decoder.get()) return false; Callback = DecoderCallback; @@ -949,12 +909,13 @@ SoundHandle OpenALSoundRenderer::LoadSoundRaw(BYTE *sfxdata, int length, int fre SoundHandle OpenALSoundRenderer::LoadSound(BYTE *sfxdata, int length) { SoundHandle retval = { NULL }; + MemoryReader reader((const char*)sfxdata, length); ALenum format = AL_NONE; ChannelConfig chans; SampleType type; int srate; - std::auto_ptr decoder(CreateDecoder(sfxdata, length)); + std::auto_ptr decoder(CreateDecoder(&reader)); if(!decoder.get()) return retval; decoder->getInfo(&srate, &chans, &type); @@ -1031,15 +992,12 @@ SoundStream *OpenALSoundRenderer::CreateStream(SoundStreamCallback callback, int return stream.release(); } -SoundStream *OpenALSoundRenderer::OpenStream(const char *filename, int flags, int offset, int length) +SoundStream *OpenALSoundRenderer::OpenStream(std::auto_ptr reader, int flags) { std::auto_ptr stream(new OpenALSoundStream(this)); - bool loop = (flags&SoundStream::Loop); - bool ok = ((offset == -1) ? stream->Init((const BYTE*)filename, length, loop) : - stream->Init(filename, offset, length, loop)); - if(ok == false) - return NULL; + bool ok = stream->Init(reader, (flags&SoundStream::Loop)); + if(ok == false) return NULL; return stream.release(); } diff --git a/src/sound/oalsound.h b/src/sound/oalsound.h index db559ebb70..f9ff49a6ec 100644 --- a/src/sound/oalsound.h +++ b/src/sound/oalsound.h @@ -82,7 +82,7 @@ public: // Streaming sounds. virtual SoundStream *CreateStream(SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata); - virtual SoundStream *OpenStream(const char *filename, int flags, int offset, int length); + virtual SoundStream *OpenStream(std::auto_ptr reader, int flags); // Starts a sound. virtual FISoundChannel *StartSound(SoundHandle sfx, float vol, int pitch, int chanflags, FISoundChannel *reuse_chan); diff --git a/src/sound/sndfile_decoder.cpp b/src/sound/sndfile_decoder.cpp index 534cf343fb..922fc8b1ce 100644 --- a/src/sound/sndfile_decoder.cpp +++ b/src/sound/sndfile_decoder.cpp @@ -1,62 +1,26 @@ #include "sndfile_decoder.h" +#include "files.h" #ifdef HAVE_SNDFILE sf_count_t SndFileDecoder::file_get_filelen(void *user_data) { - SndFileDecoder *self = reinterpret_cast(user_data); - return self->FileLength; + FileReader *reader = reinterpret_cast(user_data)->Reader; + return reader->GetLength(); } sf_count_t SndFileDecoder::file_seek(sf_count_t offset, int whence, void *user_data) { - SndFileDecoder *self = reinterpret_cast(user_data); + FileReader *reader = reinterpret_cast(user_data)->Reader; - long cur = ftell(self->File); - if(cur < 0) return -1; - - switch(whence) - { - case SEEK_SET: - if(offset < 0 || offset > (sf_count_t)self->FileLength) - return -1; - cur = offset; - break; - - case SEEK_CUR: - cur -= self->FileOffset; - if((offset > 0 && (sf_count_t)(self->FileLength-cur) < offset) || - (offset < 0 && (sf_count_t)cur < -offset)) - return -1; - cur += offset; - break; - - case SEEK_END: - if(offset > 0 || -offset > (sf_count_t)self->FileLength) - return -1; - cur = self->FileLength + offset; - break; - - default: - return -1; - } - - if(fseek(self->File, cur + self->FileOffset, SEEK_SET) != 0) + if(reader->Seek(offset, whence) != 0) return -1; - return cur; + return reader->Tell(); } sf_count_t SndFileDecoder::file_read(void *ptr, sf_count_t count, void *user_data) { - SndFileDecoder *self = reinterpret_cast(user_data); - - long cur = ftell(self->File); - if(cur < 0) return -1; - - cur -= self->FileOffset; - if(count > (sf_count_t)(self->FileLength-cur)) - count = self->FileLength-cur; - - return fread(ptr, 1, count, self->File); + FileReader *reader = reinterpret_cast(user_data)->Reader; + return reader->Read(ptr, count); } sf_count_t SndFileDecoder::file_write(const void *ptr, sf_count_t count, void *user_data) @@ -66,75 +30,8 @@ sf_count_t SndFileDecoder::file_write(const void *ptr, sf_count_t count, void *u sf_count_t SndFileDecoder::file_tell(void *user_data) { - SndFileDecoder *self = reinterpret_cast(user_data); - - long cur = ftell(self->File); - if(cur < 0 || (unsigned long)cur < self->FileLength) - return -1; - return cur - self->FileOffset; -} - - -sf_count_t SndFileDecoder::mem_get_filelen(void *user_data) -{ - SndFileDecoder *self = reinterpret_cast(user_data); - return self->MemLength; -} - -sf_count_t SndFileDecoder::mem_seek(sf_count_t offset, int whence, void *user_data) -{ - SndFileDecoder *self = reinterpret_cast(user_data); - - switch(whence) - { - case SEEK_SET: - if(offset < 0 || offset > (sf_count_t)self->MemLength) - return -1; - self->MemPos = offset; - break; - - case SEEK_CUR: - if((offset > 0 && (sf_count_t)(self->MemLength-self->MemPos) < offset) || - (offset < 0 && (sf_count_t)self->MemPos < -offset)) - return -1; - self->MemPos += offset; - break; - - case SEEK_END: - if(offset > 0 || -offset > (sf_count_t)self->MemLength) - return -1; - self->MemPos = self->MemLength + offset; - break; - - default: - return -1; - } - - return self->MemPos; -} - -sf_count_t SndFileDecoder::mem_read(void *ptr, sf_count_t count, void *user_data) -{ - SndFileDecoder *self = reinterpret_cast(user_data); - - if(count > (sf_count_t)(self->MemLength-self->MemPos)) - count = self->MemLength-self->MemPos; - - memcpy(ptr, self->MemData+self->MemPos, count); - self->MemPos += count; - - return count; -} - -sf_count_t SndFileDecoder::mem_write(const void *ptr, sf_count_t count, void *user_data) -{ - return -1; -} - -sf_count_t SndFileDecoder::mem_tell(void *user_data) -{ - SndFileDecoder *self = reinterpret_cast(user_data); - return self->MemPos; + FileReader *reader = reinterpret_cast(user_data)->Reader; + return reader->Tell(); } @@ -143,18 +40,13 @@ SndFileDecoder::~SndFileDecoder() if(SndFile) sf_close(SndFile); SndFile = 0; - if(File) - fclose(File); - File = 0; } -bool SndFileDecoder::open(const char *data, size_t length) +bool SndFileDecoder::open(FileReader *reader) { - SF_VIRTUAL_IO sfio = { mem_get_filelen, mem_seek, mem_read, mem_write, mem_tell }; + SF_VIRTUAL_IO sfio = { file_get_filelen, file_seek, file_read, file_write, file_tell }; - MemData = data; - MemPos = 0; - MemLength = length; + Reader = reader; SndFile = sf_open_virtual(&sfio, SFM_READ, &SndInfo, this); if(SndFile) { @@ -168,34 +60,6 @@ bool SndFileDecoder::open(const char *data, size_t length) return false; } -bool SndFileDecoder::open(const char *fname, size_t offset, size_t length) -{ - SF_VIRTUAL_IO sfio = { file_get_filelen, file_seek, file_read, file_write, file_tell }; - - FileOffset = offset; - FileLength = length; - File = fopen(fname, "rb"); - if(File) - { - if(fseek(File, offset, SEEK_SET) == 0) - { - SndFile = sf_open_virtual(&sfio, SFM_READ, &SndInfo, this); - if(SndFile) - { - if(SndInfo.channels == 1 || SndInfo.channels == 2) - return true; - - sf_close(SndFile); - SndFile = 0; - } - } - fclose(File); - File = 0; - } - - return false; -} - void SndFileDecoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) { *samplerate = SndInfo.samplerate; diff --git a/src/sound/sndfile_decoder.h b/src/sound/sndfile_decoder.h index ec59af98f2..f329ab8765 100644 --- a/src/sound/sndfile_decoder.h +++ b/src/sound/sndfile_decoder.h @@ -16,35 +16,23 @@ struct SndFileDecoder : public SoundDecoder virtual bool seek(size_t ms_offset); virtual size_t getSampleOffset(); - SndFileDecoder() : SndFile(0), File(0) { } + SndFileDecoder() : SndFile(0) { } virtual ~SndFileDecoder(); protected: - virtual bool open(const char *data, size_t length); - virtual bool open(const char *fname, size_t offset, size_t length); + virtual bool open(FileReader *reader); private: SNDFILE *SndFile; SF_INFO SndInfo; - FILE *File; - size_t FileLength; - size_t FileOffset; + FileReader *Reader; static sf_count_t file_get_filelen(void *user_data); static sf_count_t file_seek(sf_count_t offset, int whence, void *user_data); static sf_count_t file_read(void *ptr, sf_count_t count, void *user_data); static sf_count_t file_write(const void *ptr, sf_count_t count, void *user_data); static sf_count_t file_tell(void *user_data); - const char *MemData; - size_t MemLength; - size_t MemPos; - static sf_count_t mem_get_filelen(void *user_data); - static sf_count_t mem_seek(sf_count_t offset, int whence, void *user_data); - static sf_count_t mem_read(void *ptr, sf_count_t count, void *user_data); - static sf_count_t mem_write(const void *ptr, sf_count_t count, void *user_data); - static sf_count_t mem_tell(void *user_data); - // Make non-copyable SndFileDecoder(const SndFileDecoder &rhs); SndFileDecoder& operator=(const SndFileDecoder &rhs); From 9c12abeb2d17ff4de8796d122c33c71cb061818c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 25 Jun 2014 04:52:23 -0700 Subject: [PATCH 46/88] Better report the amount buffered in an OpenAL stream --- src/sound/oalsound.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 706c26ae74..127233057d 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -359,15 +359,13 @@ public: { FString stats; ALfloat volume; - ALint processed; - ALint queued; + ALint boffset; ALint state; ALenum err; alGetSourcef(Source, AL_GAIN, &volume); + alGetSourcei(Source, AL_BYTE_OFFSET, &boffset); alGetSourcei(Source, AL_SOURCE_STATE, &state); - alGetSourcei(Source, AL_BUFFERS_QUEUED, &queued); - alGetSourcei(Source, AL_BUFFERS_PROCESSED, &processed); if((err=alGetError()) != AL_NO_ERROR) { stats = "Error getting stats: "; @@ -377,7 +375,7 @@ public: stats = (state == AL_INITIAL) ? "Buffering" : (state == AL_STOPPED) ? "Underrun" : (state == AL_PLAYING || state == AL_PAUSED) ? "Ready" : "Unknown state"; - stats.AppendFormat(",%3d%% buffered", (queued ? 100-(processed*100/queued) : 0)); + stats.AppendFormat(",%3lu%% buffered", 100 - 100*boffset/(BufferCount*Data.size())); stats.AppendFormat(", %d%%", int(volume * 100)); if(state == AL_PAUSED) stats += ", paused"; From 7f5b5381101512467617be8da623633d94f5b80d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 25 Jun 2014 04:59:18 -0700 Subject: [PATCH 47/88] Implement SetPosition for OpenAL streams --- src/sound/oalsound.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 127233057d..f1e3c9cfa1 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -303,8 +303,21 @@ public: return (getALError()==AL_NO_ERROR); } + virtual bool SetPosition(unsigned int ms_pos) + { + if(!Decoder->seek(ms_pos)) + return false; + + alSourceStop(Source); + getALError(); + return true; + } + virtual unsigned int GetPosition() - { return 0; } + { + // FIXME: Decoder position - amount buffered + source offset + return 0; + } virtual bool IsEnded() { From 3d33f565a458ab586d0ffbe49611332ae4bbdd6b Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 25 Jun 2014 16:20:26 -0700 Subject: [PATCH 48/88] Use a proper, more unique, pointer formatter for the open callback --- src/sound/fmodsound.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index fa442603e9..709b87c59c 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -1621,15 +1621,13 @@ static void SetCustomLoopPts(FMOD::Sound *sound) static FMOD_RESULT F_CALLBACK open_reader_callback(const char *name, int unicode, unsigned int *filesize, void **handle, void **userdata) { - char *endptr = NULL; - QWORD val = strtoull(name, &endptr, 0); - if(!endptr || *endptr != '\0') + FileReader *reader = NULL; + if(sscanf(name, "_FileReader_%p", &reader) != 1) { Printf("Invalid name in callback: %s\n", name); return FMOD_ERR_FILE_NOTFOUND; } - FileReader *reader = reinterpret_cast((uintptr_t)val); *filesize = reader->GetLength(); *handle = reader; *userdata = reader; @@ -1702,7 +1700,7 @@ SoundStream *FMODSoundRenderer::OpenStream(std::auto_ptr reader, int exinfo.dlsname = patches; } - name.Format("0x%I64x", (QWORD)reader.get()); + name.Format("_FileReader_%p", reader.get()); result = Sys->createSound(name, mode, &exinfo, &stream); if(result == FMOD_ERR_FORMAT && exinfo.dlsname != NULL) { From fd25ec2a625459c2fed7b34a5a28a1e860dc94e6 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 25 Jun 2014 20:03:24 -0700 Subject: [PATCH 49/88] Implement GetPosition for OpenAL streams, and display it in the stats --- src/sound/oalsound.cpp | 87 +++++++++++++++++++++++++++++++----------- 1 file changed, 65 insertions(+), 22 deletions(-) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index f1e3c9cfa1..f04990fa7e 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -146,6 +146,7 @@ class OpenALSoundStream : public SoundStream ALsizei SampleRate; ALenum Format; + ALsizei FrameSize; static const int BufferCount = 4; ALuint Buffers[BufferCount]; @@ -308,15 +309,31 @@ public: if(!Decoder->seek(ms_pos)) return false; + // Stop the source so that all buffers become processed, then call + // IsEnded() to refill and restart the source queue with the new + // position. alSourceStop(Source); getALError(); - return true; + return !IsEnded(); } virtual unsigned int GetPosition() { - // FIXME: Decoder position - amount buffered + source offset - return 0; + ALint offset, queued, state; + alGetSourcei(Source, AL_SAMPLE_OFFSET, &offset); + alGetSourcei(Source, AL_BUFFERS_QUEUED, &queued); + alGetSourcei(Source, AL_SOURCE_STATE, &state); + if(getALError() != AL_NO_ERROR) + return 0; + + size_t pos = Decoder->getSampleOffset(); + if(state != AL_STOPPED) + { + size_t rem = queued*(Data.size()/FrameSize) - offset; + if(pos > rem) pos -= rem; + else pos = 0; + } + return (unsigned int)(pos * 1000.0 / SampleRate); } virtual bool IsEnded() @@ -372,12 +389,17 @@ public: { FString stats; ALfloat volume; - ALint boffset; + ALint offset; + ALint processed; + ALint queued; ALint state; + size_t pos; ALenum err; alGetSourcef(Source, AL_GAIN, &volume); - alGetSourcei(Source, AL_BYTE_OFFSET, &boffset); + alGetSourcei(Source, AL_SAMPLE_OFFSET, &offset); + alGetSourcei(Source, AL_BUFFERS_PROCESSED, &processed); + alGetSourcei(Source, AL_BUFFERS_QUEUED, &queued); alGetSourcei(Source, AL_SOURCE_STATE, &state); if((err=alGetError()) != AL_NO_ERROR) { @@ -388,8 +410,18 @@ public: stats = (state == AL_INITIAL) ? "Buffering" : (state == AL_STOPPED) ? "Underrun" : (state == AL_PLAYING || state == AL_PAUSED) ? "Ready" : "Unknown state"; - stats.AppendFormat(",%3lu%% buffered", 100 - 100*boffset/(BufferCount*Data.size())); - stats.AppendFormat(", %d%%", int(volume * 100)); + + pos = Decoder->getSampleOffset(); + if(state == AL_STOPPED) + offset = BufferCount * (Data.size()/FrameSize); + else + { + size_t rem = queued*(Data.size()/FrameSize) - offset; + if(pos > rem) pos -= rem; + else pos = 0; + } + stats.AppendFormat(",%3lu%% buffered", 100 - 100*offset/(BufferCount*(Data.size()/FrameSize))); + stats.AppendFormat(", %zu ms", pos); if(state == AL_PAUSED) stats += ", paused"; if(state == AL_PLAYING) @@ -415,16 +447,22 @@ public: if((flags&Mono)) Format = AL_FORMAT_MONO8; else Format = AL_FORMAT_STEREO8; } - else if(!(flags&(Bits32|Float))) + else if((flags&Float)) + { + if(alIsExtensionPresent("AL_EXT_FLOAT32")) + { + if((flags&Mono)) Format = AL_FORMAT_MONO_FLOAT32; + else Format = AL_FORMAT_STEREO_FLOAT32; + } + } + else if((flags&Bits32)) + { + } + else { if((flags&Mono)) Format = AL_FORMAT_MONO16; else Format = AL_FORMAT_STEREO16; } - else if((flags&Float) && alIsExtensionPresent("AL_EXT_FLOAT32")) - { - if((flags&Mono)) Format = AL_FORMAT_MONO_FLOAT32; - else Format = AL_FORMAT_STEREO_FLOAT32; - } if(Format == AL_NONE) { @@ -432,21 +470,21 @@ public: return false; } - int smpsize = 1; + FrameSize = 1; if((flags&Bits8)) - smpsize *= 1; + FrameSize *= 1; else if((flags&(Bits32|Float))) - smpsize *= 4; + FrameSize *= 4; else - smpsize *= 2; + FrameSize *= 2; if((flags&Mono)) - smpsize *= 1; + FrameSize *= 1; else - smpsize *= 2; + FrameSize *= 2; - buffbytes += smpsize-1; - buffbytes -= buffbytes%smpsize; + buffbytes += FrameSize-1; + buffbytes -= buffbytes%FrameSize; Data.resize(buffbytes); return true; @@ -464,6 +502,7 @@ public: Callback = DecoderCallback; UserData = NULL; Format = AL_NONE; + FrameSize = 1; ChannelConfig chans; SampleType type; @@ -474,12 +513,16 @@ public: { if(type == SampleType_UInt8) Format = AL_FORMAT_MONO8; if(type == SampleType_Int16) Format = AL_FORMAT_MONO16; + FrameSize *= 1; } if(chans == ChannelConfig_Stereo) { if(type == SampleType_UInt8) Format = AL_FORMAT_STEREO8; if(type == SampleType_Int16) Format = AL_FORMAT_STEREO16; + FrameSize *= 2; } + if(type == SampleType_UInt8) FrameSize *= 1; + if(type == SampleType_Int16) FrameSize *= 2; if(Format == AL_NONE) { @@ -489,7 +532,7 @@ public: SampleRate = srate; Looping = loop; - Data.resize((size_t)(0.2 * SampleRate) * 4); + Data.resize((size_t)(0.2 * SampleRate) * FrameSize); return true; } From c6bb52c866dce8248e6a136f3f59f21708530bac Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 25 Jun 2014 21:14:35 -0700 Subject: [PATCH 50/88] Get the length from sounds when possible --- src/sound/i_soundinternal.h | 1 + src/sound/mpg123_decoder.cpp | 6 ++++++ src/sound/mpg123_decoder.h | 1 + src/sound/oalsound.cpp | 10 ++++++++-- src/sound/sndfile_decoder.cpp | 5 +++++ src/sound/sndfile_decoder.h | 1 + 6 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/sound/i_soundinternal.h b/src/sound/i_soundinternal.h index 0a7e8b0e0b..499fe80a6e 100644 --- a/src/sound/i_soundinternal.h +++ b/src/sound/i_soundinternal.h @@ -126,6 +126,7 @@ struct SoundDecoder virtual std::vector readAll(); virtual bool seek(size_t ms_offset) = 0; virtual size_t getSampleOffset() = 0; + virtual size_t getSampleLength() { return 0; } SoundDecoder() { } virtual ~SoundDecoder() { } diff --git a/src/sound/mpg123_decoder.cpp b/src/sound/mpg123_decoder.cpp index 63ccb6922c..969706a98e 100644 --- a/src/sound/mpg123_decoder.cpp +++ b/src/sound/mpg123_decoder.cpp @@ -182,4 +182,10 @@ size_t MPG123Decoder::getSampleOffset() return mpg123_tell(MPG123); } +size_t MPG123Decoder::getSampleLength() +{ + off_t len = mpg123_length(MPG123); + return (len > 0) ? len : 0; +} + #endif diff --git a/src/sound/mpg123_decoder.h b/src/sound/mpg123_decoder.h index 0d8d2e7ab8..8b2b64fa79 100644 --- a/src/sound/mpg123_decoder.h +++ b/src/sound/mpg123_decoder.h @@ -14,6 +14,7 @@ struct MPG123Decoder : public SoundDecoder virtual size_t read(char *buffer, size_t bytes); virtual bool seek(size_t ms_offset); virtual size_t getSampleOffset(); + virtual size_t getSampleLength(); MPG123Decoder() : MPG123(0) { } virtual ~MPG123Decoder(); diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index f04990fa7e..27f7d47553 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -388,12 +388,12 @@ public: FString GetStats() { FString stats; + size_t pos, len; ALfloat volume; ALint offset; ALint processed; ALint queued; ALint state; - size_t pos; ALenum err; alGetSourcef(Source, AL_GAIN, &volume); @@ -412,16 +412,22 @@ public: (state == AL_PLAYING || state == AL_PAUSED) ? "Ready" : "Unknown state"; pos = Decoder->getSampleOffset(); + len = Decoder->getSampleLength(); if(state == AL_STOPPED) offset = BufferCount * (Data.size()/FrameSize); else { size_t rem = queued*(Data.size()/FrameSize) - offset; if(pos > rem) pos -= rem; + else if(len > 0) pos += len - rem; else pos = 0; } + pos = (size_t)(pos * 1000.0 / SampleRate); + len = (size_t)(len * 1000.0 / SampleRate); stats.AppendFormat(",%3lu%% buffered", 100 - 100*offset/(BufferCount*(Data.size()/FrameSize))); - stats.AppendFormat(", %zu ms", pos); + stats.AppendFormat(", %zu.%03zu", pos/1000, pos%1000); + if(len > 0) + stats.AppendFormat(" / %zu.%03zu", len/1000, len%1000); if(state == AL_PAUSED) stats += ", paused"; if(state == AL_PLAYING) diff --git a/src/sound/sndfile_decoder.cpp b/src/sound/sndfile_decoder.cpp index 922fc8b1ce..efcc6cf40d 100644 --- a/src/sound/sndfile_decoder.cpp +++ b/src/sound/sndfile_decoder.cpp @@ -106,4 +106,9 @@ size_t SndFileDecoder::getSampleOffset() return sf_seek(SndFile, 0, SEEK_CUR); } +size_t SndFileDecoder::getSampleLength() +{ + return (SndInfo.frames > 0) ? SndInfo.frames : 0; +} + #endif diff --git a/src/sound/sndfile_decoder.h b/src/sound/sndfile_decoder.h index f329ab8765..6c4dd3edac 100644 --- a/src/sound/sndfile_decoder.h +++ b/src/sound/sndfile_decoder.h @@ -15,6 +15,7 @@ struct SndFileDecoder : public SoundDecoder virtual std::vector readAll(); virtual bool seek(size_t ms_offset); virtual size_t getSampleOffset(); + virtual size_t getSampleLength(); SndFileDecoder() : SndFile(0) { } virtual ~SndFileDecoder(); From a6900b48baa584d83239a9234ded3b6f42eaff4e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 25 Jun 2014 21:48:13 -0700 Subject: [PATCH 51/88] Use AL_SOFT_deferred_updates to sync updates when availeble --- src/sound/oalsound.cpp | 40 +++++++++++++++++++++++++++++++++------- src/sound/oalsound.h | 3 +++ 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 27f7d47553..9167167887 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -135,6 +135,20 @@ static ALCenum checkALCError(ALCdevice *device, const char *fn, unsigned int ln) #define getALCError(d) checkALCError((d), __FILE__, __LINE__) +// Fallback methods for when AL_SOFT_deferred_updates isn't available. In most +// cases these don't actually do anything, except on some Creative drivers +// where they act as appropriate fallbacks. +static ALvoid AL_APIENTRY _wrap_DeferUpdatesSOFT(void) +{ + alcSuspendContext(alcGetCurrentContext()); +} + +static ALvoid AL_APIENTRY _wrap_ProcessUpdatesSOFT(void) +{ + alcProcessContext(alcGetCurrentContext()); +} + + class OpenALSoundStream : public SoundStream { OpenALSoundRenderer *Renderer; @@ -579,6 +593,7 @@ template static void LoadALFunc(const char *name, T *x) { *x = reinterpret_cast(alGetProcAddress(name)); } +#define LOAD_FUNC(x) (LoadALFunc(#x, &x)) OpenALSoundRenderer::OpenALSoundRenderer() : Device(NULL), Context(NULL), SFXPaused(0), PrevEnvironment(NULL), EnvSlot(0) { @@ -652,6 +667,7 @@ OpenALSoundRenderer::OpenALSoundRenderer() ALC.EXT_EFX = alcIsExtensionPresent(Device, "ALC_EXT_EFX"); ALC.EXT_disconnect = alcIsExtensionPresent(Device, "ALC_EXT_disconnect");; AL.EXT_source_distance_model = alIsExtensionPresent("AL_EXT_source_distance_model"); + AL.SOFT_deferred_updates = alIsExtensionPresent("AL_SOFT_deferred_updates"); AL.SOFT_loop_points = alIsExtensionPresent("AL_SOFT_loop_points"); alDopplerFactor(0.5f); @@ -660,6 +676,17 @@ OpenALSoundRenderer::OpenALSoundRenderer() if(AL.EXT_source_distance_model) alEnable(AL_SOURCE_DISTANCE_MODEL); + if(AL.SOFT_deferred_updates) + { + LOAD_FUNC(alDeferUpdatesSOFT); + LOAD_FUNC(alProcessUpdatesSOFT); + } + else + { + alDeferUpdatesSOFT = _wrap_DeferUpdatesSOFT; + alProcessUpdatesSOFT = _wrap_ProcessUpdatesSOFT; + } + ALenum err = getALError(); if(err != AL_NO_ERROR) { @@ -703,7 +730,6 @@ OpenALSoundRenderer::OpenALSoundRenderer() if(*snd_efx && ALC.EXT_EFX) { // EFX function pointers -#define LOAD_FUNC(x) (LoadALFunc(#x, &x)) LOAD_FUNC(alGenEffects); LOAD_FUNC(alDeleteEffects); LOAD_FUNC(alIsEffect); @@ -739,7 +765,6 @@ OpenALSoundRenderer::OpenALSoundRenderer() LOAD_FUNC(alGetAuxiliaryEffectSlotiv); LOAD_FUNC(alGetAuxiliaryEffectSlotf); LOAD_FUNC(alGetAuxiliaryEffectSlotfv); -#undef LOAD_FUNC if(getALError() == AL_NO_ERROR) { ALuint envReverb; @@ -788,6 +813,7 @@ OpenALSoundRenderer::OpenALSoundRenderer() if(EnvSlot) Printf(" EFX enabled\n"); } +#undef LOAD_FUNC OpenALSoundRenderer::~OpenALSoundRenderer() { @@ -838,7 +864,7 @@ void OpenALSoundRenderer::SetSfxVolume(float volume) ALuint source = GET_PTRID(schan->SysChannel); volume = SfxVolume; - alcSuspendContext(Context); + alDeferUpdatesSOFT(); alSourcef(source, AL_MAX_GAIN, volume); alSourcef(source, AL_GAIN, volume * schan->Volume); } @@ -1330,7 +1356,7 @@ void OpenALSoundRenderer::ChannelVolume(FISoundChannel *chan, float volume) if(chan == NULL || chan->SysChannel == NULL) return; - alcSuspendContext(Context); + alDeferUpdatesSOFT(); ALuint source = GET_PTRID(chan->SysChannel); alSourcef(source, AL_GAIN, SfxVolume * volume); @@ -1456,7 +1482,7 @@ void OpenALSoundRenderer::UpdateSoundParams3D(SoundListener *listener, FISoundCh if(chan == NULL || chan->SysChannel == NULL) return; - alcSuspendContext(Context); + alDeferUpdatesSOFT(); FVector3 dir = pos - listener->position; chan->DistanceSqr = dir.LengthSquared(); @@ -1495,7 +1521,7 @@ void OpenALSoundRenderer::UpdateListener(SoundListener *listener) if(!listener->valid) return; - alcSuspendContext(Context); + alDeferUpdatesSOFT(); float angle = listener->angle; ALfloat orient[6]; @@ -1593,7 +1619,7 @@ void OpenALSoundRenderer::UpdateListener(SoundListener *listener) void OpenALSoundRenderer::UpdateSounds() { - alcProcessContext(Context); + alProcessUpdatesSOFT(); // For some reason this isn't being called? foreach(SoundStream*, stream, Streams) diff --git a/src/sound/oalsound.h b/src/sound/oalsound.h index f9ff49a6ec..9b468336c2 100644 --- a/src/sound/oalsound.h +++ b/src/sound/oalsound.h @@ -128,6 +128,7 @@ private: } ALC; struct { bool EXT_source_distance_model; + bool SOFT_deferred_updates; bool SOFT_loop_points; } AL; @@ -171,6 +172,8 @@ private: LPALGETAUXILIARYEFFECTSLOTF alGetAuxiliaryEffectSlotf; LPALGETAUXILIARYEFFECTSLOTFV alGetAuxiliaryEffectSlotfv; + ALvoid (AL_APIENTRY*alDeferUpdatesSOFT)(void); + ALvoid (AL_APIENTRY*alProcessUpdatesSOFT)(void); void LoadReverb(const ReverbContainer *env); void PurgeStoppedSources(); From 0adfdf31dda641827a69557ef67da3795b8b9b05 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 25 Jun 2014 21:50:52 -0700 Subject: [PATCH 52/88] Fix calling SetPosition when not playing --- src/sound/oalsound.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 9167167887..db4c459ebb 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -323,6 +323,8 @@ public: if(!Decoder->seek(ms_pos)) return false; + if(!Playing) + return true; // Stop the source so that all buffers become processed, then call // IsEnded() to refill and restart the source queue with the new // position. From 1a40c95f84eb0114ac25e1b4b7a0f77eddb4eaef Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 26 Jun 2014 16:58:18 -0700 Subject: [PATCH 53/88] Rename some FMOD references to be generic sound system Since they relates to other sound backends as well, there's no need to single out FMOD in these places. --- src/s_advsound.cpp | 2 +- src/s_sound.cpp | 2 +- src/s_sound.h | 2 +- src/sound/i_music.cpp | 16 ++++++++-------- src/sound/i_musicinterns.h | 10 +++++----- src/sound/music_dumb.cpp | 4 ++-- src/sound/music_midi_base.cpp | 2 +- src/sound/music_midi_timidity.cpp | 2 +- src/sound/music_midistream.cpp | 12 ++++++------ src/sound/music_pseudo_mididevice.cpp | 8 ++++---- wadsrc/static/menudef.txt | 2 +- 11 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/s_advsound.cpp b/src/s_advsound.cpp index c2d567f299..4206d35002 100644 --- a/src/s_advsound.cpp +++ b/src/s_advsound.cpp @@ -1367,7 +1367,7 @@ static void S_AddSNDINFO (int lump) FName nm = sc.String; sc.MustGetString(); if (sc.Compare("timidity")) MidiDevices[nm] = MDEV_TIMIDITY; - else if (sc.Compare("fmod")) MidiDevices[nm] = MDEV_FMOD; + else if (sc.Compare("fmod") || sc.Compare("sndsys")) MidiDevices[nm] = MDEV_SNDSYS; else if (sc.Compare("standard")) MidiDevices[nm] = MDEV_MMAPI; else if (sc.Compare("opl")) MidiDevices[nm] = MDEV_OPL; else if (sc.Compare("default")) MidiDevices[nm] = MDEV_DEFAULT; diff --git a/src/s_sound.cpp b/src/s_sound.cpp index c84c539caf..a549215009 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -1326,7 +1326,7 @@ sfxinfo_t *S_LoadSound(sfxinfo_t *sfx) } // If the sound is raw, just load it as such. // Otherwise, try the sound as DMX format. - // If that fails, let FMOD try and figure it out. + // If that fails, let the sound system try and figure it out. else if (sfx->bLoadRAW || (((BYTE *)sfxdata)[0] == 3 && ((BYTE *)sfxdata)[1] == 0 && len <= size - 8)) { diff --git a/src/s_sound.h b/src/s_sound.h index 346e51ce1e..df3b87de82 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -389,7 +389,7 @@ enum EMidiDevice MDEV_DEFAULT = -1, MDEV_MMAPI = 0, MDEV_OPL = 1, - MDEV_FMOD = 2, + MDEV_SNDSYS = 2, MDEV_TIMIDITY = 3, MDEV_FLUIDSYNTH = 4, MDEV_GUS = 5, diff --git a/src/sound/i_music.cpp b/src/sound/i_music.cpp index 1067b2b831..36ec7598a6 100644 --- a/src/sound/i_music.cpp +++ b/src/sound/i_music.cpp @@ -396,9 +396,9 @@ MusInfo *I_RegisterSong (std::auto_ptr reader, int device) } #ifndef _WIN32 - // non-Windows platforms don't support MDEV_MMAPI so map to MDEV_FMOD + // non-Windows platforms don't support MDEV_MMAPI so map to MDEV_SNDSYS if (device == MDEV_MMAPI) - device = MDEV_FMOD; + device = MDEV_SNDSYS; #endif // Check for gzip compression. Some formats are expected to have players @@ -435,17 +435,17 @@ MusInfo *I_RegisterSong (std::auto_ptr reader, int device) { EMidiDevice devtype = (EMidiDevice)device; -retry_as_fmod: +retry_as_sndsys: info = CreateMIDIStreamer(reader, devtype, miditype); if (info != NULL && !info->IsValid()) { delete info; info = NULL; } - if (info == NULL && devtype != MDEV_FMOD && snd_mididevice < 0) + if (info == NULL && devtype != MDEV_SNDSYS && snd_mididevice < 0) { - devtype = MDEV_FMOD; - goto retry_as_fmod; + devtype = MDEV_SNDSYS; + goto retry_as_sndsys; } #ifdef _WIN32 if (info == NULL && devtype != MDEV_MMAPI && snd_mididevice >= 0) @@ -495,14 +495,14 @@ retry_as_fmod: } } - // no FMOD => no modules/streams + // no support in sound system => no modules/streams // 1024 bytes is an arbitrary restriction. It's assumed that anything // smaller than this can't possibly be a valid music file if it hasn't // been identified already, so don't even bother trying to load it. // Of course MIDIs shorter than 1024 bytes should pass. if (info == NULL && (reader->GetLength() >= 1024 || id[0] == MAKE_ID('M','T','h','d'))) { - // Let FMOD figure out what it is. + // Let the sound system figure out what it is. info = new StreamSong (reader); } } diff --git a/src/sound/i_musicinterns.h b/src/sound/i_musicinterns.h index 43e52a722e..698a8b5a8f 100644 --- a/src/sound/i_musicinterns.h +++ b/src/sound/i_musicinterns.h @@ -169,16 +169,16 @@ protected: bool bLooping; }; -// FMOD pseudo-MIDI device -------------------------------------------------- +// Sound System pseudo-MIDI device ------------------------------------------ -class FMODMIDIDevice : public PseudoMIDIDevice +class SndSysMIDIDevice : public PseudoMIDIDevice { public: int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata); bool Preprocess(MIDIStreamer *song, bool looping); }; -// MIDI file played with TiMidity++ and possibly streamed through FMOD ------ +// MIDI file played with TiMidity++ and possibly streamed through the Sound System class TimidityPPMIDIDevice : public PseudoMIDIDevice { @@ -661,7 +661,7 @@ protected: EventSource EventDue; }; -// Anything supported by FMOD out of the box -------------------------------- +// Anything supported by the sound system out of the box -------------------- class StreamSong : public MusInfo { @@ -685,7 +685,7 @@ protected: SoundStream *m_Stream; }; -// MUS file played by a software OPL2 synth and streamed through FMOD ------- +// MUS file played by a software OPL2 synth and streamed through the sound system class OPLMUSSong : public StreamSong { diff --git a/src/sound/music_dumb.cpp b/src/sound/music_dumb.cpp index bcacefe401..97ad2b5ea2 100644 --- a/src/sound/music_dumb.cpp +++ b/src/sound/music_dumb.cpp @@ -1004,8 +1004,8 @@ MusInfo *MOD_OpenSong(std::auto_ptr &reader) // No way to get the filename, so we can't check for a .mod extension, and // therefore, trying to load an old 15-instrument SoundTracker module is not // safe. We'll restrict MOD loading to 31-instrument modules with known - // signatures and let FMOD worry about 15-instrument ones. (Assuming it even - // supports them; I have not checked.) + // signatures and let the sound system worry about 15-instrument ones. + // (Assuming it even supports them) duh = dumb_read_mod_quick(f, TRUE); } diff --git a/src/sound/music_midi_base.cpp b/src/sound/music_midi_base.cpp index 78b88b92f9..c33434aabc 100644 --- a/src/sound/music_midi_base.cpp +++ b/src/sound/music_midi_base.cpp @@ -33,7 +33,7 @@ static void AddDefaultMidiDevices(FOptionValues *opt) pair[p+1].Value = -3.0; pair[p+2].Text = "TiMidity++"; pair[p+2].Value = -2.0; - pair[p+3].Text = "FMOD"; + pair[p+3].Text = "Sound System"; pair[p+3].Value = -1.0; } diff --git a/src/sound/music_midi_timidity.cpp b/src/sound/music_midi_timidity.cpp index 4acda49b96..3c780d4598 100644 --- a/src/sound/music_midi_timidity.cpp +++ b/src/sound/music_midi_timidity.cpp @@ -608,7 +608,7 @@ int TimidityPPMIDIDevice::Resume() { if (LaunchTimidity()) { - // Assume success if not mixing with FMOD + // Assume success if not mixing with the sound system if (Stream == NULL || Stream->Play(true, timidity_mastervolume)) { Started = true; diff --git a/src/sound/music_midistream.cpp b/src/sound/music_midistream.cpp index ba00779038..b7fb54bf22 100644 --- a/src/sound/music_midistream.cpp +++ b/src/sound/music_midistream.cpp @@ -214,13 +214,13 @@ EMidiDevice MIDIStreamer::SelectMIDIDevice(EMidiDevice device) - if explicitly selected by $mididevice - when snd_mididevice is -2 and no midi device is set for the song - - FMod: + - Sound System: - if explicitly selected by $mididevice - when snd_mididevice is -1 and no midi device is set for the song - as fallback when both OPL and Timidity failed unless snd_mididevice is >= 0 - MMAPI (Win32 only): - - if explicitly selected by $mididevice (non-Win32 redirects this to FMOD) + - if explicitly selected by $mididevice (non-Win32 redirects this to Sound System) - when snd_mididevice is >= 0 and no midi device is set for the song - as fallback when both OPL and Timidity failed and snd_mididevice is >= 0 */ @@ -232,7 +232,7 @@ EMidiDevice MIDIStreamer::SelectMIDIDevice(EMidiDevice device) } switch (snd_mididevice) { - case -1: return MDEV_FMOD; + case -1: return MDEV_SNDSYS; case -2: return MDEV_TIMIDITY; case -3: return MDEV_OPL; case -4: return MDEV_GUS; @@ -243,7 +243,7 @@ EMidiDevice MIDIStreamer::SelectMIDIDevice(EMidiDevice device) #ifdef _WIN32 return MDEV_MMAPI; #else - return MDEV_FMOD; + return MDEV_SNDSYS; #endif } } @@ -270,8 +270,8 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype) const return new FluidSynthMIDIDevice; #endif - case MDEV_FMOD: - return new FMODMIDIDevice; + case MDEV_SNDSYS: + return new SndSysMIDIDevice; case MDEV_GUS: return new TimidityMIDIDevice; diff --git a/src/sound/music_pseudo_mididevice.cpp b/src/sound/music_pseudo_mididevice.cpp index ba52f0a082..422f039cef 100644 --- a/src/sound/music_pseudo_mididevice.cpp +++ b/src/sound/music_pseudo_mididevice.cpp @@ -235,24 +235,24 @@ FString PseudoMIDIDevice::GetStats() //========================================================================== // -// FMODMIDIDevice :: Open +// SndSysMIDIDevice :: Open // //========================================================================== -int FMODMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata) +int SndSysMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata) { return 0; } //========================================================================== // -// FMODMIDIDevice :: Preprocess +// SndSysMIDIDevice :: Preprocess // // Create a standard MIDI file and stream it. // //========================================================================== -bool FMODMIDIDevice::Preprocess(MIDIStreamer *song, bool looping) +bool SndSysMIDIDevice::Preprocess(MIDIStreamer *song, bool looping) { std::auto_ptr reader(new MemoryArrayReader(NULL, 0)); song->CreateSMF(reader->GetArray(), looping ? 0 : 1); diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index dd6ec08d3d..52a77475cd 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -1526,7 +1526,7 @@ OptionMenu AdvSoundOptions OptionValue ModReplayers { - 0.0, "FMOD" + 0.0, "Sound System" 1.0, "foo_dumb" } From a16f9d061ce05582faa94af36f29c8936bf0256d Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 27 Jun 2014 01:29:34 -0700 Subject: [PATCH 54/88] Work around a libsndfile bug related to converting float samples to shorts Do the conversion ourselves to ensure it's properly clamped. --- src/sound/sndfile_decoder.cpp | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/sound/sndfile_decoder.cpp b/src/sound/sndfile_decoder.cpp index efcc6cf40d..26f9fd91da 100644 --- a/src/sound/sndfile_decoder.cpp +++ b/src/sound/sndfile_decoder.cpp @@ -74,8 +74,30 @@ void SndFileDecoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType * size_t SndFileDecoder::read(char *buffer, size_t bytes) { - int framesize = 2 * SndInfo.channels; - return sf_readf_short(SndFile, (short*)buffer, bytes/framesize) * framesize; + short *out = (short*)buffer; + size_t frames = bytes / SndInfo.channels / 2; + size_t total = 0; + + // It seems libsndfile has a bug with converting float samples from Vorbis + // to the 16-bit shorts we use, which causes some PCM samples to overflow + // and wrap, creating static. So instead, read the samples as floats and + // convert to short ourselves. + // Use a loop to convert a handful of samples at a time, avoiding a heap + // allocation for temporary storage. 64 at a time works, though maybe it + // could be more. + while(total < frames) + { + size_t todo = std::min(frames-total, 64/SndInfo.channels); + float tmp[64]; + + size_t got = sf_readf_float(SndFile, tmp, todo); + if(got < todo) frames = total + got; + + for(size_t i = 0;i < got*SndInfo.channels;i++) + *out++ = (short)((std::min)((std::max)(tmp[i] * 32767.f, -32768.f), 32767.f)); + total += got; + } + return total * SndInfo.channels * 2; } std::vector SndFileDecoder::readAll() From 6f8545e694ae334184dff5181e24ddce0dd41683 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 27 Jun 2014 21:51:05 -0700 Subject: [PATCH 55/88] Use a TArray for SoundDecoder::readAll --- src/sound/i_sound.cpp | 12 ++++++------ src/sound/i_soundinternal.h | 3 ++- src/sound/oalsound.cpp | 4 ++-- src/sound/sndfile_decoder.cpp | 10 +++++----- src/sound/sndfile_decoder.h | 2 +- 5 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/sound/i_sound.cpp b/src/sound/i_sound.cpp index 9d45ebc685..97267d62c1 100644 --- a/src/sound/i_sound.cpp +++ b/src/sound/i_sound.cpp @@ -574,18 +574,18 @@ SoundDecoder *SoundRenderer::CreateDecoder(FileReader *reader) // Default readAll implementation, for decoders that can't do anything better -std::vector SoundDecoder::readAll() +TArray SoundDecoder::readAll() { - std::vector output; + TArray output; size_t total = 0; size_t got; - output.resize(total+32768); - while((got=read(&output[total], output.size()-total)) > 0) + output.Resize(total+32768); + while((got=read(&output[total], output.Size()-total)) > 0) { total += got; - output.resize(total*2); + output.Resize(total*2); } - output.resize(total); + output.Resize(total); return output; } diff --git a/src/sound/i_soundinternal.h b/src/sound/i_soundinternal.h index 499fe80a6e..218c6724b9 100644 --- a/src/sound/i_soundinternal.h +++ b/src/sound/i_soundinternal.h @@ -6,6 +6,7 @@ #include "basictypes.h" #include "vectors.h" +#include "tarray.h" class FileReader; @@ -123,7 +124,7 @@ struct SoundDecoder virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) = 0; virtual size_t read(char *buffer, size_t bytes) = 0; - virtual std::vector readAll(); + virtual TArray readAll(); virtual bool seek(size_t ms_offset) = 0; virtual size_t getSampleOffset() = 0; virtual size_t getSampleLength() { return 0; } diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index db4c459ebb..0b0dd5f590 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -1024,11 +1024,11 @@ SoundHandle OpenALSoundRenderer::LoadSound(BYTE *sfxdata, int length) return retval; } - std::vector data = decoder->readAll(); + TArray data = decoder->readAll(); ALuint buffer = 0; alGenBuffers(1, &buffer); - alBufferData(buffer, format, &data[0], data.size(), srate); + alBufferData(buffer, format, &data[0], data.Size(), srate); ALenum err; if((err=getALError()) != AL_NO_ERROR) diff --git a/src/sound/sndfile_decoder.cpp b/src/sound/sndfile_decoder.cpp index 26f9fd91da..0cf6a5fa84 100644 --- a/src/sound/sndfile_decoder.cpp +++ b/src/sound/sndfile_decoder.cpp @@ -100,17 +100,17 @@ size_t SndFileDecoder::read(char *buffer, size_t bytes) return total * SndInfo.channels * 2; } -std::vector SndFileDecoder::readAll() +TArray SndFileDecoder::readAll() { if(SndInfo.frames <= 0) return SoundDecoder::readAll(); int framesize = 2 * SndInfo.channels; - std::vector output; + TArray output; - output.resize(SndInfo.frames * framesize); - size_t got = read(&output[0], output.size()); - output.resize(got); + output.Resize(SndInfo.frames * framesize); + size_t got = read(&output[0], output.Size()); + output.Resize(got); return output; } diff --git a/src/sound/sndfile_decoder.h b/src/sound/sndfile_decoder.h index 6c4dd3edac..f53f7e52a3 100644 --- a/src/sound/sndfile_decoder.h +++ b/src/sound/sndfile_decoder.h @@ -12,7 +12,7 @@ struct SndFileDecoder : public SoundDecoder virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type); virtual size_t read(char *buffer, size_t bytes); - virtual std::vector readAll(); + virtual TArray readAll(); virtual bool seek(size_t ms_offset); virtual size_t getSampleOffset(); virtual size_t getSampleLength(); From d55dfcdb1dd2dd834bb1598709d6dba97bec4eaf Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 27 Jun 2014 22:05:11 -0700 Subject: [PATCH 56/88] Pass the correct size to LoadSoundVoc --- src/s_sound.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/s_sound.cpp b/src/s_sound.cpp index a549215009..9f4c83e011 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -1322,7 +1322,7 @@ sfxinfo_t *S_LoadSound(sfxinfo_t *sfx) // If the sound is voc, use the custom loader. if (strncmp ((const char *)sfxstart, "Creative Voice File", 19) == 0) { - sfx->data = GSnd->LoadSoundVoc(sfxstart, len); + sfx->data = GSnd->LoadSoundVoc(sfxstart, size); } // If the sound is raw, just load it as such. // Otherwise, try the sound as DMX format. From a630c47e6a8692fb03e03cbf1a9a52d4b079e4f4 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 27 Jun 2014 22:09:03 -0700 Subject: [PATCH 57/88] Remove a redundant call --- src/s_sound.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 9f4c83e011..de0e7b9876 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -1350,8 +1350,7 @@ sfxinfo_t *S_LoadSound(sfxinfo_t *sfx) } else { - len = Wads.LumpLength (sfx->lumpnum); - sfx->data = GSnd->LoadSound(sfxstart, len); + sfx->data = GSnd->LoadSound(sfxstart, size); } if (sfxdata != NULL) From c73d97af44c306c8df7f940bb305b2b2087ac40e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 28 Jun 2014 00:33:15 -0700 Subject: [PATCH 58/88] Use TArray and TMap instead of std::vector and std::map --- src/sound/oalsound.cpp | 169 ++++++++++++++++++++--------------------- src/sound/oalsound.h | 21 ++--- src/tarray.h | 11 +++ 3 files changed, 105 insertions(+), 96 deletions(-) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 0b0dd5f590..3272a95666 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -98,11 +98,6 @@ EXTERN_CVAR (Bool, snd_pitched) #define MAKE_PTRID(x) ((void*)(uintptr_t)(x)) #define GET_PTRID(x) ((uint32)(uintptr_t)(x)) -#define foreach(type, name, vec) \ - for(std::vector::iterator (name) = (vec).begin(), \ - (_end_##name) = (vec).end(); \ - (name) != (_end_##name);(name)++) - static ALenum checkALError(const char *fn, unsigned int ln) { @@ -194,16 +189,15 @@ class OpenALSoundStream : public SoundStream bool SetupSource() { /* Get a source, killing the farthest, lowest-priority sound if needed */ - if(Renderer->FreeSfx.size() == 0) + if(Renderer->FreeSfx.Size() == 0) { FSoundChan *lowest = Renderer->FindLowestChannel(); if(lowest) Renderer->StopChannel(lowest); - if(Renderer->FreeSfx.size() == 0) + if(Renderer->FreeSfx.Size() == 0) return false; } - Source = Renderer->FreeSfx.back(); - Renderer->FreeSfx.pop_back(); + Renderer->FreeSfx.Pop(Source); /* Set the default properties for localized playback */ alSource3f(Source, AL_DIRECTION, 0.f, 0.f, 0.f); @@ -232,7 +226,7 @@ public: OpenALSoundStream(OpenALSoundRenderer *renderer) : Renderer(renderer), Source(0), Playing(false), Looping(false), Volume(1.0f) { - Renderer->Streams.push_back(this); + Renderer->Streams.Push(this); memset(Buffers, 0, sizeof(Buffers)); } @@ -243,7 +237,7 @@ public: alSourceRewind(Source); alSourcei(Source, AL_BUFFER, 0); - Renderer->FreeSfx.push_back(Source); + Renderer->FreeSfx.Push(Source); Source = 0; } @@ -254,8 +248,7 @@ public: } getALError(); - Renderer->Streams.erase(std::find(Renderer->Streams.begin(), - Renderer->Streams.end(), this)); + Renderer->Streams.Delete(Renderer->Streams.Find(this)); Renderer = NULL; } @@ -704,19 +697,18 @@ OpenALSoundRenderer::OpenALSoundRenderer() alcGetIntegerv(Device, ALC_MONO_SOURCES, 1, &numMono); alcGetIntegerv(Device, ALC_STEREO_SOURCES, 1, &numStereo); - Sources.resize(std::min(std::max(*snd_channels, 2), - numMono+numStereo)); - for(size_t i = 0;i < Sources.size();i++) + Sources.Resize(std::min(std::max(*snd_channels, 2), numMono+numStereo)); + for(size_t i = 0;i < Sources.Size();i++) { alGenSources(1, &Sources[i]); if(getALError() != AL_NO_ERROR) { - Sources.resize(i); + Sources.Resize(i); + Sources.ShrinkToFit(); break; } - FreeSfx.push_back(Sources[i]); } - if(Sources.size() == 0) + if(Sources.Size() == 0) { Printf(TEXTCOLOR_RED" Error: could not generate any sound sources!\n"); alcMakeContextCurrent(NULL); @@ -726,7 +718,8 @@ OpenALSoundRenderer::OpenALSoundRenderer() Device = NULL; return; } - DPrintf(" Allocated "TEXTCOLOR_BLUE"%zu"TEXTCOLOR_NORMAL" sources\n", Sources.size()); + FreeSfx = Sources; + DPrintf(" Allocated "TEXTCOLOR_BLUE"%u"TEXTCOLOR_NORMAL" sources\n", Sources.Size()); WasInWater = false; if(*snd_efx && ALC.EXT_EFX) @@ -822,22 +815,24 @@ OpenALSoundRenderer::~OpenALSoundRenderer() if(!Device) return; - while(Streams.size() > 0) + while(Streams.Size() > 0) delete Streams[0]; - alDeleteSources(Sources.size(), &Sources[0]); - Sources.clear(); - FreeSfx.clear(); - SfxGroup.clear(); - PausableSfx.clear(); - ReverbSfx.clear(); + alDeleteSources(Sources.Size(), &Sources[0]); + Sources.Clear(); + FreeSfx.Clear(); + SfxGroup.Clear(); + PausableSfx.Clear(); + ReverbSfx.Clear(); - for(EffectMap::iterator i = EnvEffects.begin();i != EnvEffects.end();i++) + if(EnvEffects.CountUsed() > 0) { - if(i->second) - alDeleteEffects(1, &(i->second)); + EffectMapIter iter(EnvEffects); + EffectMap::Pair *pair; + while(iter.NextPair(pair)) + alDeleteEffects(1, &(pair->Value)); } - EnvEffects.clear(); + EnvEffects.Clear(); if(EnvSlot) { @@ -879,8 +874,8 @@ void OpenALSoundRenderer::SetSfxVolume(float volume) void OpenALSoundRenderer::SetMusicVolume(float volume) { MusicVolume = volume; - foreach(SoundStream*, i, Streams) - (*i)->SetVolume(-1.f); + for(uint32 i = 0;i < Streams.Size();++i) + Streams[i]->SetVolume(-1.f); } unsigned int OpenALSoundRenderer::GetMSLength(SoundHandle sfx) @@ -1092,17 +1087,17 @@ SoundStream *OpenALSoundRenderer::OpenStream(std::auto_ptr reader, i FISoundChannel *OpenALSoundRenderer::StartSound(SoundHandle sfx, float vol, int pitch, int chanflags, FISoundChannel *reuse_chan) { - if(FreeSfx.size() == 0) + if(FreeSfx.Size() == 0) { FSoundChan *lowest = FindLowestChannel(); if(lowest) StopChannel(lowest); - if(FreeSfx.size() == 0) + if(FreeSfx.Size() == 0) return NULL; } ALuint buffer = GET_PTRID(sfx.data); - ALuint source = FreeSfx.back(); + ALuint source = FreeSfx.Last(); alSource3f(source, AL_POSITION, 0.f, 0.f, 0.f); alSource3f(source, AL_VELOCITY, 0.f, 0.f, 0.f); alSource3f(source, AL_DIRECTION, 0.f, 0.f, 0.f); @@ -1161,11 +1156,11 @@ FISoundChannel *OpenALSoundRenderer::StartSound(SoundHandle sfx, float vol, int } if(!(chanflags&SNDF_NOREVERB)) - ReverbSfx.push_back(source); + ReverbSfx.Push(source); if(!(chanflags&SNDF_NOPAUSE)) - PausableSfx.push_back(source); - SfxGroup.push_back(source); - FreeSfx.pop_back(); + PausableSfx.Push(source); + SfxGroup.Push(source); + FreeSfx.Pop(); FISoundChannel *chan = reuse_chan; if(!chan) chan = S_GetChannel(MAKE_PTRID(source)); @@ -1187,7 +1182,7 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener { float dist_sqr = (pos - listener->position).LengthSquared(); - if(FreeSfx.size() == 0) + if(FreeSfx.Size() == 0) { FSoundChan *lowest = FindLowestChannel(); if(lowest) @@ -1196,13 +1191,13 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener lowest->DistanceSqr > dist_sqr)) StopChannel(lowest); } - if(FreeSfx.size() == 0) + if(FreeSfx.Size() == 0) return NULL; } bool manualRolloff = true; ALuint buffer = GET_PTRID(sfx.data); - ALuint source = FreeSfx.back(); + ALuint source = FreeSfx.Last(); if(rolloff->RolloffType == ROLLOFF_Log) { if(AL.EXT_source_distance_model) @@ -1335,11 +1330,11 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener } if(!(chanflags&SNDF_NOREVERB)) - ReverbSfx.push_back(source); + ReverbSfx.Push(source); if(!(chanflags&SNDF_NOPAUSE)) - PausableSfx.push_back(source); - SfxGroup.push_back(source); - FreeSfx.pop_back(); + PausableSfx.Push(source); + SfxGroup.Push(source); + FreeSfx.Pop(); FISoundChannel *chan = reuse_chan; if(!chan) chan = S_GetChannel(MAKE_PTRID(source)); @@ -1378,15 +1373,14 @@ void OpenALSoundRenderer::StopChannel(FISoundChannel *chan) alSourcei(source, AL_BUFFER, 0); getALError(); - std::vector::iterator i; + uint32 i; + if((i=PausableSfx.Find(source)) < PausableSfx.Size()) + PausableSfx.Delete(i); + if((i=ReverbSfx.Find(source)) < ReverbSfx.Size()) + ReverbSfx.Delete(i); - i = std::find(PausableSfx.begin(), PausableSfx.end(), source); - if(i != PausableSfx.end()) PausableSfx.erase(i); - i = std::find(ReverbSfx.begin(), ReverbSfx.end(), source); - if(i != ReverbSfx.end()) ReverbSfx.erase(i); - - SfxGroup.erase(std::find(SfxGroup.begin(), SfxGroup.end(), source)); - FreeSfx.push_back(source); + SfxGroup.Delete(SfxGroup.Find(source)); + FreeSfx.Push(source); } unsigned int OpenALSoundRenderer::GetPosition(FISoundChannel *chan) @@ -1409,9 +1403,9 @@ void OpenALSoundRenderer::SetSfxPaused(bool paused, int slot) if(paused) { SFXPaused |= 1 << slot; - if(oldslots == 0 && PausableSfx.size() > 0) + if(oldslots == 0 && PausableSfx.Size() > 0) { - alSourcePausev(PausableSfx.size(), &PausableSfx[0]); + alSourcePausev(PausableSfx.Size(), &PausableSfx[0]); getALError(); PurgeStoppedSources(); } @@ -1419,9 +1413,9 @@ void OpenALSoundRenderer::SetSfxPaused(bool paused, int slot) else { SFXPaused &= ~(1 << slot); - if(SFXPaused == 0 && oldslots != 0 && PausableSfx.size() > 0) + if(SFXPaused == 0 && oldslots != 0 && PausableSfx.Size() > 0) { - alSourcePlayv(PausableSfx.size(), &PausableSfx[0]); + alSourcePlayv(PausableSfx.Size(), &PausableSfx[0]); getALError(); } } @@ -1447,9 +1441,9 @@ void OpenALSoundRenderer::Sync(bool sync) { if(sync) { - if(SfxGroup.size() > 0) + if(SfxGroup.Size() > 0) { - alSourcePausev(SfxGroup.size(), &SfxGroup[0]); + alSourcePausev(SfxGroup.Size(), &SfxGroup[0]); getALError(); PurgeStoppedSources(); } @@ -1459,21 +1453,22 @@ void OpenALSoundRenderer::Sync(bool sync) // Might already be something to handle this; basically, get a vector // of all values in SfxGroup that are not also in PausableSfx (when // SFXPaused is non-0). - std::vector toplay = SfxGroup; + TArray toplay = SfxGroup; if(SFXPaused) { - std::vector::iterator i = toplay.begin(); - while(i != toplay.end()) + uint32 i = 0; + while(i < toplay.Size()) { - if(std::find(PausableSfx.begin(), PausableSfx.end(), *i) != PausableSfx.end()) - i = toplay.erase(i); + uint32 p = PausableSfx.Find(toplay[i]); + if(p < PausableSfx.Size()) + toplay.Delete(i); else i++; } } - if(toplay.size() > 0) + if(toplay.Size() > 0) { - alSourcePlayv(toplay.size(), &toplay[0]); + alSourcePlayv(toplay.Size(), &toplay[0]); getALError(); } } @@ -1582,15 +1577,15 @@ void OpenALSoundRenderer::UpdateListener(SoundListener *listener) alFilterf(EnvFilters[1], AL_LOWPASS_GAINHF, 1.f); // Apply the updated filters on the sources - foreach(ALuint, i, ReverbSfx) + for(uint32 i = 0;i < ReverbSfx.Size();++i) { - alSourcei(*i, AL_DIRECT_FILTER, EnvFilters[0]); - alSource3i(*i, AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); + alSourcei(ReverbSfx[i], AL_DIRECT_FILTER, EnvFilters[0]); + alSource3i(ReverbSfx[i], AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); } } - foreach(ALuint, i, ReverbSfx) - alSourcef(*i, AL_PITCH, PITCH_MULT); + for(uint32 i = 0;i < ReverbSfx.Size();++i) + alSourcef(ReverbSfx[i], AL_PITCH, PITCH_MULT); getALError(); } } @@ -1606,15 +1601,15 @@ void OpenALSoundRenderer::UpdateListener(SoundListener *listener) alFilterf(EnvFilters[0], AL_LOWPASS_GAINHF, 1.f); alFilterf(EnvFilters[1], AL_LOWPASS_GAIN, 1.f); alFilterf(EnvFilters[1], AL_LOWPASS_GAINHF, 1.f); - foreach(ALuint, i, ReverbSfx) + for(uint32 i = 0;i < ReverbSfx.Size();++i) { - alSourcei(*i, AL_DIRECT_FILTER, EnvFilters[0]); - alSource3i(*i, AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); + alSourcei(ReverbSfx[i], AL_DIRECT_FILTER, EnvFilters[0]); + alSource3i(ReverbSfx[i], AL_AUXILIARY_SEND_FILTER, EnvSlot, 0, EnvFilters[1]); } } - foreach(ALuint, i, ReverbSfx) - alSourcef(*i, AL_PITCH, 1.f); + for(uint32 i = 0;i < ReverbSfx.Size();++i) + alSourcef(ReverbSfx[i], AL_PITCH, 1.f); getALError(); } } @@ -1624,8 +1619,8 @@ void OpenALSoundRenderer::UpdateSounds() alProcessUpdatesSOFT(); // For some reason this isn't being called? - foreach(SoundStream*, stream, Streams) - (*stream)->IsEnded(); + for(uint32 i = 0;i < Streams.Size();++i) + Streams[i]->IsEnded(); if(ALC.EXT_disconnect) { @@ -1716,9 +1711,10 @@ FString OpenALSoundRenderer::GatherStats() alcGetIntegerv(Device, ALC_REFRESH, 1, &updates); getALCError(Device); - ALuint total = Sources.size(); - ALuint used = SfxGroup.size()+Streams.size(); - ALuint unused = FreeSfx.size(); + uint32 total = Sources.Size(); + uint32 used = SfxGroup.Size()+Streams.Size(); + uint32 unused = FreeSfx.Size(); + FString out; out.Format("%u sources ("TEXTCOLOR_YELLOW"%u"TEXTCOLOR_NORMAL" active, "TEXTCOLOR_YELLOW"%u"TEXTCOLOR_NORMAL" free), Update interval: "TEXTCOLOR_YELLOW"%d"TEXTCOLOR_NORMAL"ms", total, used, unused, 1000/updates); @@ -1761,17 +1757,18 @@ void OpenALSoundRenderer::PrintDriversList() void OpenALSoundRenderer::PurgeStoppedSources() { // Release channels that are stopped - foreach(ALuint, i, SfxGroup) + for(uint32 i = 0;i < SfxGroup.Size();++i) { + ALuint src = SfxGroup[i]; ALint state = AL_INITIAL; - alGetSourcei(*i, AL_SOURCE_STATE, &state); + alGetSourcei(src, AL_SOURCE_STATE, &state); if(state == AL_INITIAL || state == AL_PLAYING || state == AL_PAUSED) continue; FSoundChan *schan = Channels; while(schan) { - if(schan->SysChannel != NULL && *i == GET_PTRID(schan->SysChannel)) + if(schan->SysChannel != NULL && src == GET_PTRID(schan->SysChannel)) { StopChannel(schan); break; diff --git a/src/sound/oalsound.h b/src/sound/oalsound.h index 9b468336c2..8c92707248 100644 --- a/src/sound/oalsound.h +++ b/src/sound/oalsound.h @@ -182,27 +182,28 @@ private: ALCdevice *Device; ALCcontext *Context; - std::vector Sources; + TArray Sources; ALfloat SfxVolume; ALfloat MusicVolume; int SFXPaused; - std::vector FreeSfx; - std::vector PausableSfx; - std::vector ReverbSfx; - std::vector SfxGroup; + TArray FreeSfx; + TArray PausableSfx; + TArray ReverbSfx; + TArray SfxGroup; const ReverbContainer *PrevEnvironment; - typedef std::map EffectMap; - ALuint EnvSlot; + typedef TMap EffectMap; + typedef TMapIterator EffectMapIter; + ALuint EnvSlot; ALuint EnvFilters[2]; - EffectMap EnvEffects; + EffectMap EnvEffects; - bool WasInWater; + bool WasInWater; - std::vector Streams; + TArray Streams; friend class OpenALSoundStream; }; diff --git a/src/tarray.h b/src/tarray.h index d32a688dfa..dac824800f 100644 --- a/src/tarray.h +++ b/src/tarray.h @@ -136,6 +136,17 @@ public: return Array[Count-1]; } + unsigned int Find(const T& item) const + { + unsigned int i; + for(i = 0;i < Count;++i) + { + if(Array[i] == item) + break; + } + return i; + } + unsigned int Push (const T &item) { Grow (1); From 7908116fefc035b173ff7826d3be7b550d0bf362 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 28 Jun 2014 00:37:12 -0700 Subject: [PATCH 59/88] Use a separate function to update an openal stream's volume --- src/sound/oalsound.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 3272a95666..ecc4a97ea3 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -297,7 +297,12 @@ public: virtual void SetVolume(float vol) { - if(vol >= 0.0f) Volume = vol; + Volume = vol; + UpdateVolume(); + } + + void UpdateVolume() + { alSourcef(Source, AL_GAIN, Renderer->MusicVolume*Volume); getALError(); } @@ -875,7 +880,7 @@ void OpenALSoundRenderer::SetMusicVolume(float volume) { MusicVolume = volume; for(uint32 i = 0;i < Streams.Size();++i) - Streams[i]->SetVolume(-1.f); + Streams[i]->UpdateVolume(); } unsigned int OpenALSoundRenderer::GetMSLength(SoundHandle sfx) From afcada4a3b094bc6275a55a135b96dcbd8d04631 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 28 Jun 2014 00:46:45 -0700 Subject: [PATCH 60/88] Remove an unused field --- src/sound/oalsound.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index ecc4a97ea3..131d41e6f6 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -167,7 +167,6 @@ class OpenALSoundStream : public SoundStream std::auto_ptr Reader; - std::vector DecoderData; std::auto_ptr Decoder; static bool DecoderCallback(SoundStream *_sstream, void *ptr, int length, void *user) { From 7f3be7bf14eddcec82e89e01f0a25b83b1a64ea1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 28 Jun 2014 01:25:25 -0700 Subject: [PATCH 61/88] Show the name of unsupported sound formats with OpenAL --- src/sound/i_sound.cpp | 21 +++++++++++++++++++++ src/sound/i_soundinternal.h | 3 +++ src/sound/oalsound.cpp | 6 ++++-- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/sound/i_sound.cpp b/src/sound/i_sound.cpp index 97267d62c1..852d50a6b7 100644 --- a/src/sound/i_sound.cpp +++ b/src/sound/i_sound.cpp @@ -304,6 +304,27 @@ void I_ShutdownSound() } } +const char *GetSampleTypeName(enum SampleType type) +{ + switch(type) + { + case SampleType_UInt8: return "Unsigned 8-bit"; + case SampleType_Int16: return "Signed 16-bit"; + } + return "(invalid sample type)"; +} + +const char *GetChannelConfigName(enum ChannelConfig chan) +{ + switch(chan) + { + case ChannelConfig_Mono: return "Mono"; + case ChannelConfig_Stereo: return "Stereo"; + } + return "(invalid channel config)"; +} + + CCMD (snd_status) { GSnd->PrintStatus (); diff --git a/src/sound/i_soundinternal.h b/src/sound/i_soundinternal.h index 218c6724b9..4f4c62b937 100644 --- a/src/sound/i_soundinternal.h +++ b/src/sound/i_soundinternal.h @@ -119,6 +119,9 @@ enum ChannelConfig ChannelConfig_Stereo }; +const char *GetSampleTypeName(enum SampleType type); +const char *GetChannelConfigName(enum ChannelConfig chan); + struct SoundDecoder { virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) = 0; diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 131d41e6f6..24ca27aa49 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -545,7 +545,8 @@ public: if(Format == AL_NONE) { - Printf("Unsupported audio format (0x%x / 0x%x)\n", chans, type); + Printf("Unsupported audio format: %s, %s\n", GetChannelConfigName(chans), + GetSampleTypeName(type)); return false; } SampleRate = srate; @@ -1019,7 +1020,8 @@ SoundHandle OpenALSoundRenderer::LoadSound(BYTE *sfxdata, int length) if(format == AL_NONE) { - Printf("Unsupported audio format (0x%x / 0x%x)\n", chans, type); + Printf("Unsupported audio format: %s, %s\n", GetChannelConfigName(chans), + GetSampleTypeName(type)); return retval; } From 6e64545725061138a45bfad04fc33688d56f2836 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 28 Jun 2014 01:28:43 -0700 Subject: [PATCH 62/88] Simplify some branching --- src/s_sound.cpp | 51 +++++++++++++++++-------------------------------- 1 file changed, 18 insertions(+), 33 deletions(-) diff --git a/src/s_sound.cpp b/src/s_sound.cpp index de0e7b9876..6c27a76f56 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -1312,51 +1312,36 @@ sfxinfo_t *S_LoadSound(sfxinfo_t *sfx) int size = Wads.LumpLength(sfx->lumpnum); if (size > 0) { - BYTE *sfxdata; - BYTE *sfxstart; FWadLump wlump = Wads.OpenLumpNum(sfx->lumpnum); - sfxstart = sfxdata = new BYTE[size]; + BYTE *sfxdata = new BYTE[size]; wlump.Read(sfxdata, size); - SDWORD len = LittleLong(((SDWORD *)sfxdata)[1]); + SDWORD dmxlen = LittleLong(((SDWORD *)sfxdata)[1]); // If the sound is voc, use the custom loader. - if (strncmp ((const char *)sfxstart, "Creative Voice File", 19) == 0) - { - sfx->data = GSnd->LoadSoundVoc(sfxstart, size); - } // If the sound is raw, just load it as such. // Otherwise, try the sound as DMX format. // If that fails, let the sound system try and figure it out. - else if (sfx->bLoadRAW || - (((BYTE *)sfxdata)[0] == 3 && ((BYTE *)sfxdata)[1] == 0 && len <= size - 8)) + if (strncmp ((const char *)sfxdata, "Creative Voice File", 19) == 0) { - int frequency; - - if (sfx->bLoadRAW) - { - len = Wads.LumpLength (sfx->lumpnum); - frequency = (sfx->bForce22050 ? 22050 : 11025); - } - else - { - frequency = LittleShort(((WORD *)sfxdata)[1]); - if (frequency == 0) - { - frequency = 11025; - } - sfxstart = sfxdata + 8; - } - sfx->data = GSnd->LoadSoundRaw(sfxstart, len, frequency, 1, 8, sfx->LoopStart); + sfx->data = GSnd->LoadSoundVoc(sfxdata, size); + } + else if (sfx->bLoadRAW) + { + int frequency = (sfx->bForce22050 ? 22050 : 11025); + sfx->data = GSnd->LoadSoundRaw(sfxdata, size, frequency, 1, 8, sfx->LoopStart); + } + else if (((BYTE *)sfxdata)[0] == 3 && ((BYTE *)sfxdata)[1] == 0 && dmxlen <= size - 8) + { + int frequency = LittleShort(((WORD *)sfxdata)[1]); + if (frequency == 0) frequency = 11025; + sfx->data = GSnd->LoadSoundRaw(sfxdata+8, dmxlen, frequency, 1, 8, sfx->LoopStart); } else { - sfx->data = GSnd->LoadSound(sfxstart, size); - } - - if (sfxdata != NULL) - { - delete[] sfxdata; + sfx->data = GSnd->LoadSound(sfxdata, size); } + + delete[] sfxdata; } if (!sfx->data.isValid()) From ae95a2d5cfcc0f4ee7de04158d8c64925e42d990 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 28 Jun 2014 05:41:11 -0700 Subject: [PATCH 63/88] Fix creating effect map entries TMap apparently doesn't clear the memory for new entries like std::map... --- src/sound/oalsound.cpp | 92 +++++++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 45 deletions(-) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 24ca27aa49..8aebdc4e4f 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -1787,36 +1787,38 @@ void OpenALSoundRenderer::PurgeStoppedSources() void OpenALSoundRenderer::LoadReverb(const ReverbContainer *env) { - ALuint &envReverb = EnvEffects[env->ID]; + ALuint *envReverb = EnvEffects.CheckKey(env->ID); bool doLoad = (env->Modified || !envReverb); if(!envReverb) { bool ok = false; - alGenEffects(1, &envReverb); + + envReverb = &EnvEffects.Insert(env->ID, 0); + alGenEffects(1, envReverb); if(getALError() == AL_NO_ERROR) { - alEffecti(envReverb, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB); + alEffecti(*envReverb, AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB); ok = (alGetError() == AL_NO_ERROR); if(!ok) { - alEffecti(envReverb, AL_EFFECT_TYPE, AL_EFFECT_REVERB); + alEffecti(*envReverb, AL_EFFECT_TYPE, AL_EFFECT_REVERB); ok = (alGetError() == AL_NO_ERROR); } if(!ok) { - alEffecti(envReverb, AL_EFFECT_TYPE, AL_EFFECT_NULL); + alEffecti(*envReverb, AL_EFFECT_TYPE, AL_EFFECT_NULL); ok = (alGetError() == AL_NO_ERROR); } if(!ok) { - alDeleteEffects(1, &envReverb); + alDeleteEffects(1, envReverb); getALError(); } } if(!ok) { - envReverb = 0; + *envReverb = 0; doLoad = false; } } @@ -1826,7 +1828,7 @@ void OpenALSoundRenderer::LoadReverb(const ReverbContainer *env) const REVERB_PROPERTIES &props = env->Properties; ALint type = AL_EFFECT_NULL; - alGetEffecti(envReverb, AL_EFFECT_TYPE, &type); + alGetEffecti(*envReverb, AL_EFFECT_TYPE, &type); #define mB2Gain(x) ((float)pow(10., (x)/2000.)) if(type == AL_EFFECT_EAXREVERB) { @@ -1837,53 +1839,53 @@ void OpenALSoundRenderer::LoadReverb(const ReverbContainer *env) props.ReverbPan2 }; #undef SETPARAM #define SETPARAM(e,t,v) alEffectf((e), AL_EAXREVERB_##t, clamp((v), AL_EAXREVERB_MIN_##t, AL_EAXREVERB_MAX_##t)) - SETPARAM(envReverb, DIFFUSION, props.EnvDiffusion); - SETPARAM(envReverb, GAIN, mB2Gain(props.Room)); - SETPARAM(envReverb, GAINHF, mB2Gain(props.RoomHF)); - SETPARAM(envReverb, GAINLF, mB2Gain(props.RoomLF)); - SETPARAM(envReverb, DECAY_TIME, props.DecayTime); - SETPARAM(envReverb, DECAY_HFRATIO, props.DecayHFRatio); - SETPARAM(envReverb, DECAY_LFRATIO, props.DecayLFRatio); - SETPARAM(envReverb, REFLECTIONS_GAIN, mB2Gain(props.Reflections)); - SETPARAM(envReverb, REFLECTIONS_DELAY, props.ReflectionsDelay); - alEffectfv(envReverb, AL_EAXREVERB_REFLECTIONS_PAN, reflectpan); - SETPARAM(envReverb, LATE_REVERB_GAIN, mB2Gain(props.Reverb)); - SETPARAM(envReverb, LATE_REVERB_DELAY, props.ReverbDelay); - alEffectfv(envReverb, AL_EAXREVERB_LATE_REVERB_PAN, latepan); - SETPARAM(envReverb, ECHO_TIME, props.EchoTime); - SETPARAM(envReverb, ECHO_DEPTH, props.EchoDepth); - SETPARAM(envReverb, MODULATION_TIME, props.ModulationTime); - SETPARAM(envReverb, MODULATION_DEPTH, props.ModulationDepth); - SETPARAM(envReverb, AIR_ABSORPTION_GAINHF, mB2Gain(props.AirAbsorptionHF)); - SETPARAM(envReverb, HFREFERENCE, props.HFReference); - SETPARAM(envReverb, LFREFERENCE, props.LFReference); - SETPARAM(envReverb, ROOM_ROLLOFF_FACTOR, props.RoomRolloffFactor); - alEffecti(envReverb, AL_EAXREVERB_DECAY_HFLIMIT, - (props.Flags&REVERB_FLAGS_DECAYHFLIMIT)?AL_TRUE:AL_FALSE); + SETPARAM(*envReverb, DIFFUSION, props.EnvDiffusion); + SETPARAM(*envReverb, GAIN, mB2Gain(props.Room)); + SETPARAM(*envReverb, GAINHF, mB2Gain(props.RoomHF)); + SETPARAM(*envReverb, GAINLF, mB2Gain(props.RoomLF)); + SETPARAM(*envReverb, DECAY_TIME, props.DecayTime); + SETPARAM(*envReverb, DECAY_HFRATIO, props.DecayHFRatio); + SETPARAM(*envReverb, DECAY_LFRATIO, props.DecayLFRatio); + SETPARAM(*envReverb, REFLECTIONS_GAIN, mB2Gain(props.Reflections)); + SETPARAM(*envReverb, REFLECTIONS_DELAY, props.ReflectionsDelay); + alEffectfv(*envReverb, AL_EAXREVERB_REFLECTIONS_PAN, reflectpan); + SETPARAM(*envReverb, LATE_REVERB_GAIN, mB2Gain(props.Reverb)); + SETPARAM(*envReverb, LATE_REVERB_DELAY, props.ReverbDelay); + alEffectfv(*envReverb, AL_EAXREVERB_LATE_REVERB_PAN, latepan); + SETPARAM(*envReverb, ECHO_TIME, props.EchoTime); + SETPARAM(*envReverb, ECHO_DEPTH, props.EchoDepth); + SETPARAM(*envReverb, MODULATION_TIME, props.ModulationTime); + SETPARAM(*envReverb, MODULATION_DEPTH, props.ModulationDepth); + SETPARAM(*envReverb, AIR_ABSORPTION_GAINHF, mB2Gain(props.AirAbsorptionHF)); + SETPARAM(*envReverb, HFREFERENCE, props.HFReference); + SETPARAM(*envReverb, LFREFERENCE, props.LFReference); + SETPARAM(*envReverb, ROOM_ROLLOFF_FACTOR, props.RoomRolloffFactor); + alEffecti(*envReverb, AL_EAXREVERB_DECAY_HFLIMIT, + (props.Flags&REVERB_FLAGS_DECAYHFLIMIT)?AL_TRUE:AL_FALSE); #undef SETPARAM } else if(type == AL_EFFECT_REVERB) { #define SETPARAM(e,t,v) alEffectf((e), AL_REVERB_##t, clamp((v), AL_REVERB_MIN_##t, AL_REVERB_MAX_##t)) - SETPARAM(envReverb, DIFFUSION, props.EnvDiffusion); - SETPARAM(envReverb, GAIN, mB2Gain(props.Room)); - SETPARAM(envReverb, GAINHF, mB2Gain(props.RoomHF)); - SETPARAM(envReverb, DECAY_TIME, props.DecayTime); - SETPARAM(envReverb, DECAY_HFRATIO, props.DecayHFRatio); - SETPARAM(envReverb, REFLECTIONS_GAIN, mB2Gain(props.Reflections)); - SETPARAM(envReverb, REFLECTIONS_DELAY, props.ReflectionsDelay); - SETPARAM(envReverb, LATE_REVERB_GAIN, mB2Gain(props.Reverb)); - SETPARAM(envReverb, LATE_REVERB_DELAY, props.ReverbDelay); - SETPARAM(envReverb, AIR_ABSORPTION_GAINHF, mB2Gain(props.AirAbsorptionHF)); - SETPARAM(envReverb, ROOM_ROLLOFF_FACTOR, props.RoomRolloffFactor); - alEffecti(envReverb, AL_REVERB_DECAY_HFLIMIT, - (props.Flags&REVERB_FLAGS_DECAYHFLIMIT)?AL_TRUE:AL_FALSE); + SETPARAM(*envReverb, DIFFUSION, props.EnvDiffusion); + SETPARAM(*envReverb, GAIN, mB2Gain(props.Room)); + SETPARAM(*envReverb, GAINHF, mB2Gain(props.RoomHF)); + SETPARAM(*envReverb, DECAY_TIME, props.DecayTime); + SETPARAM(*envReverb, DECAY_HFRATIO, props.DecayHFRatio); + SETPARAM(*envReverb, REFLECTIONS_GAIN, mB2Gain(props.Reflections)); + SETPARAM(*envReverb, REFLECTIONS_DELAY, props.ReflectionsDelay); + SETPARAM(*envReverb, LATE_REVERB_GAIN, mB2Gain(props.Reverb)); + SETPARAM(*envReverb, LATE_REVERB_DELAY, props.ReverbDelay); + SETPARAM(*envReverb, AIR_ABSORPTION_GAINHF, mB2Gain(props.AirAbsorptionHF)); + SETPARAM(*envReverb, ROOM_ROLLOFF_FACTOR, props.RoomRolloffFactor); + alEffecti(*envReverb, AL_REVERB_DECAY_HFLIMIT, + (props.Flags&REVERB_FLAGS_DECAYHFLIMIT)?AL_TRUE:AL_FALSE); #undef SETPARAM } #undef mB2Gain } - alAuxiliaryEffectSloti(EnvSlot, AL_EFFECTSLOT_EFFECT, envReverb); + alAuxiliaryEffectSloti(EnvSlot, AL_EFFECTSLOT_EFFECT, *envReverb); getALError(); } From 90fa215da2c797ab02c9292a598dbd5a3ccfdb6c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 28 Jun 2014 23:30:58 -0700 Subject: [PATCH 64/88] Replace another std::vector with a TArray --- src/sound/oalsound.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 8aebdc4e4f..d1acbba5e5 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -151,7 +151,7 @@ class OpenALSoundStream : public SoundStream SoundStreamCallback Callback; void *UserData; - std::vector Data; + TArray Data; ALsizei SampleRate; ALenum Format; @@ -263,14 +263,14 @@ public: alSourcei(Source, AL_BUFFER, 0); for(int i = 0;i < BufferCount;i++) { - if(!Callback(this, &Data[0], Data.size(), UserData)) + if(!Callback(this, &Data[0], Data.Size(), UserData)) { if(i == 0) return false; break; } - alBufferData(Buffers[i], Format, &Data[0], Data.size(), SampleRate); + alBufferData(Buffers[i], Format, &Data[0], Data.Size(), SampleRate); alSourceQueueBuffers(Source, 1, &Buffers[i]); } if(getALError() != AL_NO_ERROR) @@ -342,7 +342,7 @@ public: size_t pos = Decoder->getSampleOffset(); if(state != AL_STOPPED) { - size_t rem = queued*(Data.size()/FrameSize) - offset; + size_t rem = queued*(Data.Size()/FrameSize) - offset; if(pos > rem) pos -= rem; else pos = 0; } @@ -372,9 +372,9 @@ public: alSourceUnqueueBuffers(Source, 1, &bufid); processed--; - if(Callback(this, &Data[0], Data.size(), UserData)) + if(Callback(this, &Data[0], Data.Size(), UserData)) { - alBufferData(bufid, Format, &Data[0], Data.size(), SampleRate); + alBufferData(bufid, Format, &Data[0], Data.Size(), SampleRate); alSourceQueueBuffers(Source, 1, &bufid); } } @@ -427,17 +427,17 @@ public: pos = Decoder->getSampleOffset(); len = Decoder->getSampleLength(); if(state == AL_STOPPED) - offset = BufferCount * (Data.size()/FrameSize); + offset = BufferCount * (Data.Size()/FrameSize); else { - size_t rem = queued*(Data.size()/FrameSize) - offset; + size_t rem = queued*(Data.Size()/FrameSize) - offset; if(pos > rem) pos -= rem; else if(len > 0) pos += len - rem; else pos = 0; } pos = (size_t)(pos * 1000.0 / SampleRate); len = (size_t)(len * 1000.0 / SampleRate); - stats.AppendFormat(",%3lu%% buffered", 100 - 100*offset/(BufferCount*(Data.size()/FrameSize))); + stats.AppendFormat(",%3u%% buffered", 100 - 100*offset/(BufferCount*(Data.Size()/FrameSize))); stats.AppendFormat(", %zu.%03zu", pos/1000, pos%1000); if(len > 0) stats.AppendFormat(" / %zu.%03zu", len/1000, len%1000); @@ -504,7 +504,7 @@ public: buffbytes += FrameSize-1; buffbytes -= buffbytes%FrameSize; - Data.resize(buffbytes); + Data.Resize(buffbytes); return true; } @@ -552,7 +552,7 @@ public: SampleRate = srate; Looping = loop; - Data.resize((size_t)(0.2 * SampleRate) * FrameSize); + Data.Resize((size_t)(0.2 * SampleRate) * FrameSize); return true; } From d43226631d0bc01b0bac242d5f1297774ea326e9 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 15 Jul 2014 23:04:53 -0700 Subject: [PATCH 65/88] Set reverb density based on the environment size --- src/sound/oalsound.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index d1acbba5e5..f7b3ee8cd5 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -1840,6 +1840,7 @@ void OpenALSoundRenderer::LoadReverb(const ReverbContainer *env) #undef SETPARAM #define SETPARAM(e,t,v) alEffectf((e), AL_EAXREVERB_##t, clamp((v), AL_EAXREVERB_MIN_##t, AL_EAXREVERB_MAX_##t)) SETPARAM(*envReverb, DIFFUSION, props.EnvDiffusion); + SETPARAM(*envReverb, DENSITY, powf(props.EnvSize, 3.0f) * 0.0625f); SETPARAM(*envReverb, GAIN, mB2Gain(props.Room)); SETPARAM(*envReverb, GAINHF, mB2Gain(props.RoomHF)); SETPARAM(*envReverb, GAINLF, mB2Gain(props.RoomLF)); @@ -1868,6 +1869,7 @@ void OpenALSoundRenderer::LoadReverb(const ReverbContainer *env) { #define SETPARAM(e,t,v) alEffectf((e), AL_REVERB_##t, clamp((v), AL_REVERB_MIN_##t, AL_REVERB_MAX_##t)) SETPARAM(*envReverb, DIFFUSION, props.EnvDiffusion); + SETPARAM(*envReverb, DENSITY, powf(props.EnvSize, 3.0f) * 0.0625f); SETPARAM(*envReverb, GAIN, mB2Gain(props.Room)); SETPARAM(*envReverb, GAINHF, mB2Gain(props.RoomHF)); SETPARAM(*envReverb, DECAY_TIME, props.DecayTime); From 77cce303eff2cfde5e1e9bae4170ff2223e66895 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Tue, 9 Sep 2014 15:11:26 -0700 Subject: [PATCH 66/88] Fix merge conflict properly --- src/s_sound.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 6c27a76f56..531766a7a5 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -1327,8 +1327,7 @@ sfxinfo_t *S_LoadSound(sfxinfo_t *sfx) } else if (sfx->bLoadRAW) { - int frequency = (sfx->bForce22050 ? 22050 : 11025); - sfx->data = GSnd->LoadSoundRaw(sfxdata, size, frequency, 1, 8, sfx->LoopStart); + sfx->data = GSnd->LoadSoundRaw(sfxdata, size, sfx->RawRate, 1, 8, sfx->LoopStart); } else if (((BYTE *)sfxdata)[0] == 3 && ((BYTE *)sfxdata)[1] == 0 && dmxlen <= size - 8) { From ca22f2dd3f1fccbf89566a7141b99f1b40ef247a Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 11 Sep 2014 14:16:56 -0700 Subject: [PATCH 67/88] Fix a PrintMidiDevice call --- src/sound/music_midi_base.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sound/music_midi_base.cpp b/src/sound/music_midi_base.cpp index c33434aabc..649f9002ec 100644 --- a/src/sound/music_midi_base.cpp +++ b/src/sound/music_midi_base.cpp @@ -172,7 +172,7 @@ CCMD (snd_listmididevices) PrintMidiDevice (-4, "Gravis Ultrasound Emulation", MOD_SWSYNTH, 0); PrintMidiDevice (-3, "Emulated OPL FM Synth", MOD_FMSYNTH, 0); PrintMidiDevice (-2, "TiMidity++", MOD_SWSYNTH, 0); - PrintMidiDevice (-1, "Sound System", 0); + PrintMidiDevice (-1, "Sound System", 0, 0); if (nummididevices != 0) { for (id = 0; id < nummididevices; ++id) From 713846f27a05c2dbe1ce5475fa34327ffc825e70 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 12 Sep 2014 04:26:54 -0700 Subject: [PATCH 68/88] Fix use of ssize_t with MSVC --- src/sound/mpg123_decoder.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sound/mpg123_decoder.h b/src/sound/mpg123_decoder.h index 8b2b64fa79..95d3d5ec86 100644 --- a/src/sound/mpg123_decoder.h +++ b/src/sound/mpg123_decoder.h @@ -5,6 +5,9 @@ #ifdef HAVE_MPG123 +#ifdef _MSC_VER +typedef SSIZE_T ssize_t; +#endif #include "mpg123.h" struct MPG123Decoder : public SoundDecoder From 1baf355ecd3d8f8b2fad918be5f9cf724fe6263e Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Fri, 12 Sep 2014 19:36:13 -0700 Subject: [PATCH 69/88] Use the properly-sized type for ssize_t --- src/sound/mpg123_decoder.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sound/mpg123_decoder.h b/src/sound/mpg123_decoder.h index 95d3d5ec86..1d5b883ead 100644 --- a/src/sound/mpg123_decoder.h +++ b/src/sound/mpg123_decoder.h @@ -6,7 +6,7 @@ #ifdef HAVE_MPG123 #ifdef _MSC_VER -typedef SSIZE_T ssize_t; +typedef int ssize_t; #endif #include "mpg123.h" From ce678caab60f3cee8510ce5e596024b6ba83d6c5 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sat, 13 Sep 2014 11:51:53 -0700 Subject: [PATCH 70/88] Include algorithm for std::min/max --- src/sound/sndfile_decoder.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sound/sndfile_decoder.cpp b/src/sound/sndfile_decoder.cpp index 0cf6a5fa84..4f86515b1a 100644 --- a/src/sound/sndfile_decoder.cpp +++ b/src/sound/sndfile_decoder.cpp @@ -2,6 +2,9 @@ #include "files.h" #ifdef HAVE_SNDFILE + +#include + sf_count_t SndFileDecoder::file_get_filelen(void *user_data) { FileReader *reader = reinterpret_cast(user_data)->Reader; From 4b68891de75fd209dcfe656c9c6441d48f99b64c Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Sun, 14 Sep 2014 11:15:32 -0700 Subject: [PATCH 71/88] Rename 'near', because microsoft --- src/sound/oalsound.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index f7b3ee8cd5..3ff95851fe 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -1260,9 +1260,9 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener } if((chanflags&SNDF_AREA) && dist_sqr < AREA_SOUND_RADIUS*AREA_SOUND_RADIUS) { - FVector3 near(0.f, !(dir.Y>=0.f) ? -1.f : 1.f, 0.f); + FVector3 amb(0.f, !(dir.Y>=0.f) ? -1.f : 1.f, 0.f); float a = sqrt(dist_sqr) / AREA_SOUND_RADIUS; - dir = near + (dir-near)*a; + dir = amb + (dir-amb)*a; } dir += listener->position; @@ -1273,9 +1273,9 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener FVector3 dir = pos - listener->position; float mindist = rolloff->MinDistance/distscale; - FVector3 near(0.f, !(dir.Y>=0.f) ? -mindist : mindist, 0.f); + FVector3 amb(0.f, !(dir.Y>=0.f) ? -mindist : mindist, 0.f); float a = sqrt(dist_sqr) / AREA_SOUND_RADIUS; - dir = near + (dir-near)*a; + dir = amb + (dir-amb)*a; dir += listener->position; alSource3f(source, AL_POSITION, dir[0], dir[1], -dir[2]); @@ -1499,17 +1499,17 @@ void OpenALSoundRenderer::UpdateSoundParams3D(SoundListener *listener, FISoundCh } if(areasound && chan->DistanceSqr < AREA_SOUND_RADIUS*AREA_SOUND_RADIUS) { - FVector3 near(0.f, !(dir.Y>=0.f) ? -1.f : 1.f, 0.f); + FVector3 amb(0.f, !(dir.Y>=0.f) ? -1.f : 1.f, 0.f); float a = sqrt(chan->DistanceSqr) / AREA_SOUND_RADIUS; - dir = near + (dir-near)*a; + dir = amb + (dir-amb)*a; } } else if(areasound && chan->DistanceSqr < AREA_SOUND_RADIUS*AREA_SOUND_RADIUS) { float mindist = chan->Rolloff.MinDistance / chan->DistanceScale; - FVector3 near(0.f, !(dir.Y>=0.f) ? -mindist : mindist, 0.f); + FVector3 amb(0.f, !(dir.Y>=0.f) ? -mindist : mindist, 0.f); float a = sqrt(chan->DistanceSqr) / AREA_SOUND_RADIUS; - dir = near + (dir-near)*a; + dir = amb + (dir-amb)*a; } dir += listener->position; From 1d20152aee85b0311eeb19ef0fd3ab3ca684aac1 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 15 Jan 2015 13:25:02 -0800 Subject: [PATCH 72/88] Fix an errant use of FMODMIDIDevice --- src/sound/music_midistream.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sound/music_midistream.cpp b/src/sound/music_midistream.cpp index b973cca408..6c85c06af8 100644 --- a/src/sound/music_midistream.cpp +++ b/src/sound/music_midistream.cpp @@ -285,8 +285,8 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype) const catch (CRecoverableError &err) { // The creation of an OPL MIDI device can abort with an error if no GENMIDI lump can be found. - Printf("Unable to create OPL MIDI device: %s\nFalling back to FModEx playback", err.GetMessage()); - return new FMODMIDIDevice; + Printf("Unable to create OPL MIDI device: %s\nFalling back to Sound System playback", err.GetMessage()); + return new SndSysMIDIDevice; } case MDEV_TIMIDITY: From 9eda15c280994411982bc2a370ba9316efa7db55 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 25 Mar 2015 20:33:24 +0100 Subject: [PATCH 73/88] - fixed: The recent ANIMDEFS extension missed adjusting the call to AddSimpleAnim for ANIMATED-defined animations. --- src/textures/animations.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/textures/animations.cpp b/src/textures/animations.cpp index 684869cf07..ffff062c63 100644 --- a/src/textures/animations.cpp +++ b/src/textures/animations.cpp @@ -253,7 +253,8 @@ void FTextureManager::InitAnimated (void) } // Speed is stored as tics, but we want ms so scale accordingly. - AddSimpleAnim (pic1, pic2 - pic1 + 1, animtype, Scale (animspeed, 1000, 35)); + FAnimDef *adef = AddSimpleAnim (pic1, pic2 - pic1 + 1, Scale (animspeed, 1000, 35)); + if (adef != NULL) adef->AnimType = animtype; } } } From 98b2475fb87c6029ea5fd65ff17969694db0ee3a Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Wed, 25 Mar 2015 17:28:05 -0400 Subject: [PATCH 74/88] - Fixed: Loading music from an external file was broken. --- src/s_sound.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 5aca0ee57d..87e804fb8b 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -2482,6 +2482,11 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) } } } + else + { + // Load an external file. + reader.reset(new FileReader(musicname)); + } // shutdown old music S_StopMusic (true); From c91745c71451150634ecd64a890ecb7635a5a56f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 24 Apr 2015 17:42:56 +0200 Subject: [PATCH 75/88] - some fixes to make OpenAL branch compile with VC++ 2013 and OpenAL support. --- FindMPG123.cmake | 2 +- src/sound/i_musicinterns.h | 1 + src/sound/sndfile_decoder.cpp | 12 ++++++------ 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/FindMPG123.cmake b/FindMPG123.cmake index 9b871d439e..a9b6dd8b22 100644 --- a/FindMPG123.cmake +++ b/FindMPG123.cmake @@ -20,7 +20,7 @@ FIND_LIBRARY(MPG123_LIBRARIES NAMES mpg123 mpg123-0 PATH_SUFFIXES lib ) -MARK_AS_ADVANCED(MPG123_LIBRARIES MPG123_INCLUDE_DIR) +# MARK_AS_ADVANCED(MPG123_LIBRARIES MPG123_INCLUDE_DIR) # handle the QUIETLY and REQUIRED arguments and set MPG123_FOUND to TRUE if # all listed variables are TRUE diff --git a/src/sound/i_musicinterns.h b/src/sound/i_musicinterns.h index 2f30b95ab0..62561aa95d 100644 --- a/src/sound/i_musicinterns.h +++ b/src/sound/i_musicinterns.h @@ -23,6 +23,7 @@ #include "i_sound.h" #include "i_music.h" #include "s_sound.h" +#include "files.h" void I_InitMusicWin32 (); void I_ShutdownMusicWin32 (); diff --git a/src/sound/sndfile_decoder.cpp b/src/sound/sndfile_decoder.cpp index 4f86515b1a..1eba863d48 100644 --- a/src/sound/sndfile_decoder.cpp +++ b/src/sound/sndfile_decoder.cpp @@ -15,7 +15,7 @@ sf_count_t SndFileDecoder::file_seek(sf_count_t offset, int whence, void *user_d { FileReader *reader = reinterpret_cast(user_data)->Reader; - if(reader->Seek(offset, whence) != 0) + if(reader->Seek((long)offset, whence) != 0) return -1; return reader->Tell(); } @@ -23,7 +23,7 @@ sf_count_t SndFileDecoder::file_seek(sf_count_t offset, int whence, void *user_d sf_count_t SndFileDecoder::file_read(void *ptr, sf_count_t count, void *user_data) { FileReader *reader = reinterpret_cast(user_data)->Reader; - return reader->Read(ptr, count); + return reader->Read(ptr, (long)count); } sf_count_t SndFileDecoder::file_write(const void *ptr, sf_count_t count, void *user_data) @@ -93,7 +93,7 @@ size_t SndFileDecoder::read(char *buffer, size_t bytes) size_t todo = std::min(frames-total, 64/SndInfo.channels); float tmp[64]; - size_t got = sf_readf_float(SndFile, tmp, todo); + size_t got = (size_t)sf_readf_float(SndFile, tmp, todo); if(got < todo) frames = total + got; for(size_t i = 0;i < got*SndInfo.channels;i++) @@ -111,7 +111,7 @@ TArray SndFileDecoder::readAll() int framesize = 2 * SndInfo.channels; TArray output; - output.Resize(SndInfo.frames * framesize); + output.Resize((unsigned)(SndInfo.frames * framesize)); size_t got = read(&output[0], output.Size()); output.Resize(got); @@ -128,12 +128,12 @@ bool SndFileDecoder::seek(size_t ms_offset) size_t SndFileDecoder::getSampleOffset() { - return sf_seek(SndFile, 0, SEEK_CUR); + return (size_t)sf_seek(SndFile, 0, SEEK_CUR); } size_t SndFileDecoder::getSampleLength() { - return (SndInfo.frames > 0) ? SndInfo.frames : 0; + return (size_t)((SndInfo.frames > 0) ? SndInfo.frames : 0); } #endif From 0da6939e848eb44cc5934a4e8a441c7a59b89ffe Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 24 Apr 2015 22:30:28 +0200 Subject: [PATCH 76/88] - unmark OpenAL as 'advanced' in CMake so we can set its include and library paths in the IDE without having to enable the advanced display which isn't really helpful. --- src/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 50acfe2cb7..7ea29f012c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -215,6 +215,7 @@ endif( WIN32 ) if( NOT NO_OPENAL ) find_package( OpenAL ) + mark_as_advanced(CLEAR OPENAL_LIBRARY OPENAL_INCLUDE_DIR) if( OPENAL_FOUND ) include_directories( ${OPENAL_INCLUDE_DIR} ) set( ZDOOM_LIBS ${OPENAL_LIBRARY} ${ZDOOM_LIBS} ) From dccd35ef294c1b67f5d0e38d4eaa31ffe2ef7cfa Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 25 Apr 2015 10:26:14 +0200 Subject: [PATCH 77/88] - uncoupled OpenAL music updates from UpdateSounds. UpdateSounds will not be called during screen wipes and the entire setup of this function suggests that this is not advisable at all. The OpenAL stream updates were done deep inside this function implicitly. This caused music to stop while a wipe was in progress. So in order to allow uninterrupted music playback during screen wipes the music updates need to be handled separately from sound updates and be called both in the main loop and the wipe loop. I think that the OpenAL music updating should be offloaded to a separate thread but at least it's working now without causing interruptions during wipes. --- src/d_main.cpp | 2 ++ src/s_sound.cpp | 46 +++++++++++++++++++++++++++--------------- src/s_sound.h | 1 + src/sound/i_sound.h | 1 + src/sound/oalsound.cpp | 11 ++++++---- src/sound/oalsound.h | 1 + 6 files changed, 42 insertions(+), 20 deletions(-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 9b46d42c23..9ddc17cd58 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -905,6 +905,7 @@ void D_Display () } while (diff < 1); wipestart = nowtime; done = screen->WipeDo (1); + S_UpdateMusic(); // OpenAL needs this to keep the music running, thanks to a complete lack of a sane streaming implementation using callbacks. :( C_DrawConsole (hw2d); // console and M_Drawer (); // menu are drawn even on top of wipes screen->Update (); // page flip or blit buffer @@ -1003,6 +1004,7 @@ void D_DoomLoop () // Update display, next frame, with current state. I_StartTic (); D_Display (); + S_UpdateMusic(); // OpenAL needs this to keep the music running, thanks to a complete lack of a sane streaming implementation using callbacks. :( } catch (CRecoverableError &error) { diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 316f31a2ea..3c820ff009 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -1914,29 +1914,32 @@ void S_UpdateSounds (AActor *listenactor) S_ActivatePlayList(false); } - // should never happen - S_SetListener(listener, listenactor); - - for (FSoundChan *chan = Channels; chan != NULL; chan = chan->NextChan) + if (listenactor != NULL) { - if ((chan->ChanFlags & (CHAN_EVICTED | CHAN_IS3D)) == CHAN_IS3D) + // should never happen + S_SetListener(listener, listenactor); + + for (FSoundChan *chan = Channels; chan != NULL; chan = chan->NextChan) { - CalcPosVel(chan, &pos, &vel); - GSnd->UpdateSoundParams3D(&listener, chan, !!(chan->ChanFlags & CHAN_AREA), pos, vel); + if ((chan->ChanFlags & (CHAN_EVICTED | CHAN_IS3D)) == CHAN_IS3D) + { + CalcPosVel(chan, &pos, &vel); + GSnd->UpdateSoundParams3D(&listener, chan, !!(chan->ChanFlags & CHAN_AREA), pos, vel); + } + chan->ChanFlags &= ~CHAN_JUSTSTARTED; } - chan->ChanFlags &= ~CHAN_JUSTSTARTED; - } - SN_UpdateActiveSequences(); + SN_UpdateActiveSequences(); - GSnd->UpdateListener(&listener); - GSnd->UpdateSounds(); + GSnd->UpdateListener(&listener); + GSnd->UpdateSounds(); - if (level.time >= RestartEvictionsAt) - { - RestartEvictionsAt = 0; - S_RestoreEvictedChannels(); + if (level.time >= RestartEvictionsAt) + { + RestartEvictionsAt = 0; + S_RestoreEvictedChannels(); + } } } @@ -2605,6 +2608,17 @@ void S_StopMusic (bool force) } } +//========================================================================== +// +// +// +//========================================================================== + +void S_UpdateMusic() +{ + GSnd->UpdateMusic(); +} + //========================================================================== // // CCMD playsound diff --git a/src/s_sound.h b/src/s_sound.h index 71b770cbca..49fb81fb35 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -329,6 +329,7 @@ int S_GetMusic (char **name); // Stops the music for sure. void S_StopMusic (bool force); +void S_UpdateMusic(); // Stop and resume music, during game PAUSE. void S_PauseSound (bool notmusic, bool notsfx); diff --git a/src/sound/i_sound.h b/src/sound/i_sound.h index 29dd947f05..ab8ec2964b 100644 --- a/src/sound/i_sound.h +++ b/src/sound/i_sound.h @@ -149,6 +149,7 @@ public: virtual void UpdateListener (SoundListener *) = 0; virtual void UpdateSounds () = 0; + virtual void UpdateMusic() {} virtual bool IsValid () = 0; virtual void PrintStatus () = 0; diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 3ff95851fe..c4f46b95e8 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -1624,10 +1624,6 @@ void OpenALSoundRenderer::UpdateSounds() { alProcessUpdatesSOFT(); - // For some reason this isn't being called? - for(uint32 i = 0;i < Streams.Size();++i) - Streams[i]->IsEnded(); - if(ALC.EXT_disconnect) { ALCint connected = ALC_TRUE; @@ -1644,6 +1640,13 @@ void OpenALSoundRenderer::UpdateSounds() PurgeStoppedSources(); } +void OpenALSoundRenderer::UpdateMusic() +{ + // For some reason this isn't being called? + for(uint32 i = 0;i < Streams.Size();++i) + Streams[i]->IsEnded(); +} + bool OpenALSoundRenderer::IsValid() { return Device != NULL; diff --git a/src/sound/oalsound.h b/src/sound/oalsound.h index 8c92707248..9ae2db7b20 100644 --- a/src/sound/oalsound.h +++ b/src/sound/oalsound.h @@ -111,6 +111,7 @@ public: virtual void UpdateListener(SoundListener *); virtual void UpdateSounds(); + virtual void UpdateMusic(); virtual void MarkStartTime(FISoundChannel*); virtual float GetAudibility(FISoundChannel*); From 12118550d29a54e9e43c45a036cb9049e0fd5c93 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 25 Apr 2015 10:34:47 +0200 Subject: [PATCH 78/88] - fixed some warnings in OpenAL code. --- src/sound/oalsound.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index c4f46b95e8..6d5b05d1ee 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -664,11 +664,11 @@ OpenALSoundRenderer::OpenALSoundRenderer() DPrintf(" Version: "TEXTCOLOR_ORANGE"%s\n", alGetString(AL_VERSION)); DPrintf(" Extensions: "TEXTCOLOR_ORANGE"%s\n", alGetString(AL_EXTENSIONS)); - ALC.EXT_EFX = alcIsExtensionPresent(Device, "ALC_EXT_EFX"); - ALC.EXT_disconnect = alcIsExtensionPresent(Device, "ALC_EXT_disconnect");; - AL.EXT_source_distance_model = alIsExtensionPresent("AL_EXT_source_distance_model"); - AL.SOFT_deferred_updates = alIsExtensionPresent("AL_SOFT_deferred_updates"); - AL.SOFT_loop_points = alIsExtensionPresent("AL_SOFT_loop_points"); + ALC.EXT_EFX = !!alcIsExtensionPresent(Device, "ALC_EXT_EFX"); + ALC.EXT_disconnect = !!alcIsExtensionPresent(Device, "ALC_EXT_disconnect");; + AL.EXT_source_distance_model = !!alIsExtensionPresent("AL_EXT_source_distance_model"); + AL.SOFT_deferred_updates = !!alIsExtensionPresent("AL_SOFT_deferred_updates"); + AL.SOFT_loop_points = !!alIsExtensionPresent("AL_SOFT_loop_points"); alDopplerFactor(0.5f); alSpeedOfSound(343.3f * 96.0f); @@ -1085,9 +1085,7 @@ SoundStream *OpenALSoundRenderer::OpenStream(std::auto_ptr reader, i { std::auto_ptr stream(new OpenALSoundStream(this)); - bool ok = stream->Init(reader, (flags&SoundStream::Loop)); - if(ok == false) return NULL; - + if (!stream->Init(reader, !!(flags&SoundStream::Loop))) return NULL; return stream.release(); } @@ -1186,7 +1184,7 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener FRolloffInfo *rolloff, float distscale, int pitch, int priority, const FVector3 &pos, const FVector3 &vel, int channum, int chanflags, FISoundChannel *reuse_chan) { - float dist_sqr = (pos - listener->position).LengthSquared(); + float dist_sqr = (float)(pos - listener->position).LengthSquared(); if(FreeSfx.Size() == 0) { @@ -1488,7 +1486,7 @@ void OpenALSoundRenderer::UpdateSoundParams3D(SoundListener *listener, FISoundCh alDeferUpdatesSOFT(); FVector3 dir = pos - listener->position; - chan->DistanceSqr = dir.LengthSquared(); + chan->DistanceSqr = (float)dir.LengthSquared(); if(chan->ManualRolloff) { From d880783784391346de9a96df831d11bc76216093 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 25 Apr 2015 12:25:10 +0200 Subject: [PATCH 79/88] - make OpenAL and the decoder libraries delay loaded so that ZDoom can still start without them being present. This required the addition of a few exception handlers so to avoid #ifdef overuse I also added some #defines for non-Windows systems that allow using __try and __except directly in the code without #ifdef'ing them out. --- src/CMakeLists.txt | 4 +- src/sound/except.h | 34 ++++++++++++++++ src/sound/fmodsound.cpp | 36 +++------------- src/sound/i_sound.cpp | 25 ++++++------ src/sound/mpg123_decoder.cpp | 21 ++++++++-- src/sound/oalsound.cpp | 77 ++++++++++++++++++++++------------- src/sound/oalsound.h | 2 + src/sound/sndfile_decoder.cpp | 35 +++++++++++----- 8 files changed, 148 insertions(+), 86 deletions(-) create mode 100644 src/sound/except.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7ea29f012c..b75b679c44 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1200,9 +1200,9 @@ endif( NOT ZDOOM_OUTPUT_OLDSTYLE OR NO_GENERATOR_EXPRESSIONS ) if( MSVC ) option( ZDOOM_GENERATE_MAPFILE "Generate .map file for debugging." OFF ) if( ZDOOM_GENERATE_MAPFILE ) - set_target_properties(zdoom PROPERTIES LINK_FLAGS "/MANIFEST:NO /DELAYLOAD:\"fmodex${X64}.dll\" /MAP") + set_target_properties(zdoom PROPERTIES LINK_FLAGS "/MANIFEST:NO /DELAYLOAD:\"fmodex${X64}.dll\" /DELAYLOAD:\"openal32.dll\" /DELAYLOAD:\"libmpg123-0.dll\" /DELAYLOAD:\"libsndfile-1.dll\" /MAP") else( ZDOOM_GENERATE_MAPFILE ) - set_target_properties(zdoom PROPERTIES LINK_FLAGS "/MANIFEST:NO /DELAYLOAD:\"fmodex${X64}.dll\"") + set_target_properties(zdoom PROPERTIES LINK_FLAGS "/MANIFEST:NO /DELAYLOAD:\"fmodex${X64}.dll\" /DELAYLOAD:\"openal32.dll\" /DELAYLOAD:\"libmpg123-0.dll\" /DELAYLOAD:\"libsndfile-1.dll\"") endif( ZDOOM_GENERATE_MAPFILE ) add_custom_command(TARGET zdoom POST_BUILD diff --git a/src/sound/except.h b/src/sound/except.h new file mode 100644 index 0000000000..10b4841309 --- /dev/null +++ b/src/sound/except.h @@ -0,0 +1,34 @@ +#ifndef __EXCEPT_H +#define __EXCEPT_H + +#ifdef _MSC_VER +//========================================================================== +// +// CheckException +// +//========================================================================== + +#ifndef FACILITY_VISUALCPP +#define FACILITY_VISUALCPP ((LONG)0x6d) +#endif +#define VcppException(sev,err) ((sev) | (FACILITY_VISUALCPP<<16) | err) + +inline int CheckException(DWORD code) +{ + if (code == VcppException(ERROR_SEVERITY_ERROR,ERROR_MOD_NOT_FOUND) || + code == VcppException(ERROR_SEVERITY_ERROR,ERROR_PROC_NOT_FOUND)) + { + return EXCEPTION_EXECUTE_HANDLER; + } + return EXCEPTION_CONTINUE_SEARCH; +} + + +#else + +#define __try +#define __except(a) if (0) + +#endif + +#endif \ No newline at end of file diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index e54569e79b..5c06f53014 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -52,6 +52,7 @@ extern HWND Window; #include #endif +#include "except.h" #include "templates.h" #include "fmodsound.h" #include "c_cvars.h" @@ -629,30 +630,6 @@ bool FMODSoundRenderer::IsValid() return InitSuccess; } -#ifdef _MSC_VER -//========================================================================== -// -// CheckException -// -//========================================================================== - -#ifndef FACILITY_VISUALCPP -#define FACILITY_VISUALCPP ((LONG)0x6d) -#endif -#define VcppException(sev,err) ((sev) | (FACILITY_VISUALCPP<<16) | err) - -static int CheckException(DWORD code) -{ - if (code == VcppException(ERROR_SEVERITY_ERROR,ERROR_MOD_NOT_FOUND) || - code == VcppException(ERROR_SEVERITY_ERROR,ERROR_PROC_NOT_FOUND)) - { - return EXCEPTION_EXECUTE_HANDLER; - } - return EXCEPTION_CONTINUE_SEARCH; -} - -#endif - //========================================================================== // // FMODSoundRenderer :: Init @@ -690,12 +667,12 @@ bool FMODSoundRenderer::Init() Printf("I_InitSound: Initializing FMOD\n"); + HMODULE a = GetModuleHandle("fmodex.dll"); + // Create a System object and initialize. -#ifdef _MSC_VER - __try { -#endif - result = FMOD::System_Create(&Sys); -#ifdef _MSC_VER + __try + { + result = FMOD::System_Create(&Sys); } __except(CheckException(GetExceptionCode())) { @@ -707,7 +684,6 @@ bool FMODSoundRenderer::Init() ".dll\n"); return false; } -#endif if (result != FMOD_OK) { Sys = NULL; diff --git a/src/sound/i_sound.cpp b/src/sound/i_sound.cpp index efac427b53..8904fc7c48 100644 --- a/src/sound/i_sound.cpp +++ b/src/sound/i_sound.cpp @@ -53,6 +53,7 @@ extern HINSTANCE g_hInst; #include "doomtype.h" #include +#include "except.h" #include "fmodsound.h" #include "oalsound.h" @@ -574,22 +575,22 @@ SoundDecoder *SoundRenderer::CreateDecoder(FileReader *reader) int pos = reader->Tell(); #ifdef HAVE_MPG123 - decoder = new MPG123Decoder; - if(decoder->open(reader)) - return decoder; - reader->Seek(pos, SEEK_SET); + decoder = new MPG123Decoder; + if (decoder->open(reader)) + return decoder; + reader->Seek(pos, SEEK_SET); - delete decoder; - decoder = NULL; + delete decoder; + decoder = NULL; #endif #ifdef HAVE_SNDFILE - decoder = new SndFileDecoder; - if(decoder->open(reader)) - return decoder; - reader->Seek(pos, SEEK_SET); + decoder = new SndFileDecoder; + if (decoder->open(reader)) + return decoder; + reader->Seek(pos, SEEK_SET); - delete decoder; - decoder = NULL; + delete decoder; + decoder = NULL; #endif return decoder; } diff --git a/src/sound/mpg123_decoder.cpp b/src/sound/mpg123_decoder.cpp index 969706a98e..551fe84346 100644 --- a/src/sound/mpg123_decoder.cpp +++ b/src/sound/mpg123_decoder.cpp @@ -1,3 +1,10 @@ +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#define USE_WINDOWS_DWORD +#endif +#include "except.h" + #include "mpg123_decoder.h" #include "files.h" @@ -49,9 +56,17 @@ bool MPG123Decoder::open(FileReader *reader) { if(!inited) { - if(mpg123_init() != MPG123_OK) - return false; - inited = true; + __try + { + if(mpg123_init() != MPG123_OK) + return false; + inited = true; + } + __except (CheckException(GetExceptionCode())) + { + // this means that the delay loaded decoder DLL was not found. + return false; + } } Reader = reader; diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 6d5b05d1ee..3f61578a87 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -38,6 +38,7 @@ #define USE_WINDOWS_DWORD #endif +#include "except.h" #include "doomstat.h" #include "templates.h" #include "oalsound.h" @@ -65,19 +66,25 @@ void I_BuildALDeviceList(FOptionValues *opt) opt->mValues[0].Text = "Default"; #ifndef NO_OPENAL - const ALCchar *names = (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") ? - alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER) : - alcGetString(NULL, ALC_DEVICE_SPECIFIER)); - if(!names) - Printf("Failed to get device list: %s\n", alcGetString(NULL, alcGetError(NULL))); - else while(*names) - { - unsigned int i = opt->mValues.Reserve(1); - opt->mValues[i].TextValue = names; - opt->mValues[i].Text = names; + __try + { + const ALCchar *names = (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") ? + alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER) : + alcGetString(NULL, ALC_DEVICE_SPECIFIER)); + if (!names) + Printf("Failed to get device list: %s\n", alcGetString(NULL, alcGetError(NULL))); + else while (*names) + { + unsigned int i = opt->mValues.Reserve(1); + opt->mValues[i].TextValue = names; + opt->mValues[i].Text = names; - names += strlen(names)+1; - } + names += strlen(names) + 1; + } + } + __except (CheckException(GetExceptionCode())) + { + } #endif } @@ -588,6 +595,34 @@ static float GetRolloff(const FRolloffInfo *rolloff, float distance) return (powf(10.f, volume) - 1.f) / 9.f; } +ALCdevice *OpenALSoundRenderer::InitDevice() +{ + ALCdevice *device = NULL; + __try + { + if(strcmp(snd_aldevice, "Default") != 0) + { + device = alcOpenDevice(*snd_aldevice); + if(!device) + Printf(TEXTCOLOR_BLUE" Failed to open device "TEXTCOLOR_BOLD"%s"TEXTCOLOR_BLUE". Trying default.\n", *snd_aldevice); + } + + if(!device) + { + device = alcOpenDevice(NULL); + if(!device) + { + Printf(TEXTCOLOR_RED" Could not open audio device\n"); + } + } + } + __except(CheckException(GetExceptionCode())) + { + Printf(TEXTCOLOR_ORANGE"Failed to load openal32.dll\n"); + } + return device; +} + template static void LoadALFunc(const char *name, T *x) @@ -601,22 +636,8 @@ OpenALSoundRenderer::OpenALSoundRenderer() Printf("I_InitSound: Initializing OpenAL\n"); - if(strcmp(snd_aldevice, "Default") != 0) - { - Device = alcOpenDevice(*snd_aldevice); - if(!Device) - Printf(TEXTCOLOR_BLUE" Failed to open device "TEXTCOLOR_BOLD"%s"TEXTCOLOR_BLUE". Trying default.\n", *snd_aldevice); - } - - if(!Device) - { - Device = alcOpenDevice(NULL); - if(!Device) - { - Printf(TEXTCOLOR_RED" Could not open audio device\n"); - return; - } - } + Device = InitDevice(); + if (Device == NULL) return; const ALCchar *current = NULL; if(alcIsExtensionPresent(Device, "ALC_ENUMERATE_ALL_EXT")) diff --git a/src/sound/oalsound.h b/src/sound/oalsound.h index 9ae2db7b20..e6de8ce6d9 100644 --- a/src/sound/oalsound.h +++ b/src/sound/oalsound.h @@ -206,6 +206,8 @@ private: TArray Streams; friend class OpenALSoundStream; + + ALCdevice *InitDevice(); }; #endif // NO_OPENAL diff --git a/src/sound/sndfile_decoder.cpp b/src/sound/sndfile_decoder.cpp index 1eba863d48..4a477baf8a 100644 --- a/src/sound/sndfile_decoder.cpp +++ b/src/sound/sndfile_decoder.cpp @@ -1,3 +1,10 @@ +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#define USE_WINDOWS_DWORD +#endif +#include "except.h" + #include "sndfile_decoder.h" #include "files.h" @@ -47,19 +54,25 @@ SndFileDecoder::~SndFileDecoder() bool SndFileDecoder::open(FileReader *reader) { - SF_VIRTUAL_IO sfio = { file_get_filelen, file_seek, file_read, file_write, file_tell }; + __try + { + SF_VIRTUAL_IO sfio = { file_get_filelen, file_seek, file_read, file_write, file_tell }; - Reader = reader; - SndFile = sf_open_virtual(&sfio, SFM_READ, &SndInfo, this); - if(SndFile) - { - if(SndInfo.channels == 1 || SndInfo.channels == 2) - return true; - - sf_close(SndFile); - SndFile = 0; - } + Reader = reader; + SndFile = sf_open_virtual(&sfio, SFM_READ, &SndInfo, this); + if (SndFile) + { + if (SndInfo.channels == 1 || SndInfo.channels == 2) + return true; + sf_close(SndFile); + SndFile = 0; + } + } + __except (CheckException(GetExceptionCode())) + { + // this means that the delay loaded decoder DLL was not found. + } return false; } From 6bb79be85c940793d50e5c25fabba73e6d309094 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sat, 25 Apr 2015 17:50:57 +0200 Subject: [PATCH 80/88] - got rid of std::auto_ptr, courtesy of Blzut3's patch. --- src/s_sound.cpp | 11 ++-- src/sound/fmodsound.cpp | 13 ++-- src/sound/fmodsound.h | 2 +- src/sound/i_music.cpp | 82 +++++++++++++---------- src/sound/i_music.h | 4 +- src/sound/i_musicinterns.h | 18 ++--- src/sound/i_sound.cpp | 10 +-- src/sound/i_sound.h | 4 +- src/sound/i_soundinternal.h | 1 - src/sound/music_cd.cpp | 20 +++--- src/sound/music_dumb.cpp | 17 +++-- src/sound/music_gme.cpp | 13 ++-- src/sound/music_hmi_midiout.cpp | 6 +- src/sound/music_mus_midiout.cpp | 8 +-- src/sound/music_mus_opl.cpp | 4 +- src/sound/music_pseudo_mididevice.cpp | 5 +- src/sound/music_smf_midiout.cpp | 6 +- src/sound/music_stream.cpp | 2 +- src/sound/music_xmi_midiout.cpp | 6 +- src/sound/oalsound.cpp | 94 +++++++++++++++------------ src/sound/oalsound.h | 6 +- src/sound/sndfile_decoder.cpp | 16 ++--- 22 files changed, 181 insertions(+), 167 deletions(-) diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 3c820ff009..070ba56584 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -26,7 +26,6 @@ #include #endif #include -#include #include "i_system.h" #include "i_sound.h" @@ -2434,7 +2433,7 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) musicname += 7; } - std::auto_ptr reader; + FileReader *reader = NULL; if (!FileExists (musicname)) { if ((lumpnum = Wads.CheckNumForFullName (musicname, true, ns_music)) == -1) @@ -2472,7 +2471,7 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) musiccache.Resize(length); Wads.ReadLump(lumpnum, &musiccache[0]); - reader.reset(new MemoryReader((const char*)&musiccache[0], musiccache.Size())); + reader = new MemoryReader((const char*)&musiccache[0], musiccache.Size()); } else { @@ -2480,14 +2479,14 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) { return false; } - reader.reset(Wads.ReopenLumpNum(lumpnum)); + reader = Wads.ReopenLumpNum(lumpnum); } } } else { // Load an external file. - reader.reset(new FileReader(musicname)); + reader = new FileReader(musicname); } // shutdown old music @@ -2500,6 +2499,7 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) mus_playing.name = musicname; mus_playing.baseorder = order; LastSong = musicname; + delete reader; return true; } @@ -2507,6 +2507,7 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) if (handle != NULL) { mus_playing.handle = handle; + delete reader; } else { diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index 5c06f53014..44a42819f3 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -304,12 +304,12 @@ class FMODStreamCapsule : public SoundStream public: FMODStreamCapsule(FMOD::Sound *stream, FMODSoundRenderer *owner, const char *url) : Owner(owner), Stream(NULL), Channel(NULL), - UserData(NULL), Callback(NULL), URL(url), Ended(false) + UserData(NULL), Callback(NULL), URL(url), Reader(NULL), Ended(false) { SetStream(stream); } - FMODStreamCapsule(FMOD::Sound *stream, FMODSoundRenderer *owner, std::auto_ptr reader) + FMODStreamCapsule(FMOD::Sound *stream, FMODSoundRenderer *owner, FileReader *reader) : Owner(owner), Stream(NULL), Channel(NULL), UserData(NULL), Callback(NULL), Reader(reader), Ended(false) { @@ -318,7 +318,7 @@ public: FMODStreamCapsule(void *udata, SoundStreamCallback callback, FMODSoundRenderer *owner) : Owner(owner), Stream(NULL), Channel(NULL), - UserData(udata), Callback(callback), Ended(false) + UserData(udata), Callback(callback), Reader(NULL), Ended(false) {} ~FMODStreamCapsule() @@ -331,6 +331,7 @@ public: { Stream->release(); } + delete Reader; } void SetStream(FMOD::Sound *stream) @@ -600,7 +601,7 @@ private: FMOD::Channel *Channel; void *UserData; SoundStreamCallback Callback; - std::auto_ptr Reader; + FileReader *Reader; FString URL; bool Ended; bool JustStarted; @@ -1645,7 +1646,7 @@ static FMOD_RESULT F_CALLBACK seek_reader_callback(void *handle, unsigned int po // //========================================================================== -SoundStream *FMODSoundRenderer::OpenStream(std::auto_ptr reader, int flags) +SoundStream *FMODSoundRenderer::OpenStream(FileReader *reader, int flags) { FMOD_MODE mode; FMOD_CREATESOUNDEXINFO exinfo; @@ -1681,7 +1682,7 @@ SoundStream *FMODSoundRenderer::OpenStream(std::auto_ptr reader, int exinfo.dlsname = patches; } - name.Format("_FileReader_%p", reader.get()); + name.Format("_FileReader_%p", reader); result = Sys->createSound(name, mode, &exinfo, &stream); if(result == FMOD_ERR_FORMAT && exinfo.dlsname != NULL) { diff --git a/src/sound/fmodsound.h b/src/sound/fmodsound.h index c4c0399461..8963f7d3b7 100644 --- a/src/sound/fmodsound.h +++ b/src/sound/fmodsound.h @@ -24,7 +24,7 @@ public: // Streaming sounds. SoundStream *CreateStream (SoundStreamCallback callback, int buffsamples, int flags, int samplerate, void *userdata); - SoundStream *OpenStream (std::auto_ptr reader, int flags); + SoundStream *OpenStream (FileReader *reader, int flags); SoundStream *OpenStream (const char *url, int flags); // Starts a sound. diff --git a/src/sound/i_music.cpp b/src/sound/i_music.cpp index 770869f7af..3f8fac0da6 100644 --- a/src/sound/i_music.cpp +++ b/src/sound/i_music.cpp @@ -301,7 +301,7 @@ MusInfo *MusInfo::GetWaveDumper(const char *filename, int rate) // //========================================================================== -static MIDIStreamer *CreateMIDIStreamer(std::auto_ptr &reader, EMidiDevice devtype, EMIDIType miditype) +static MIDIStreamer *CreateMIDIStreamer(FileReader &reader, EMidiDevice devtype, EMIDIType miditype) { switch (miditype) { @@ -377,22 +377,23 @@ static EMIDIType IdentifyMIDIType(DWORD *id, int size) // //========================================================================== -MusInfo *I_RegisterSong (std::auto_ptr reader, int device) +MusInfo *I_RegisterSong (FileReader *reader, int device) { MusInfo *info = NULL; const char *fmt; DWORD id[32/4]; - int i; if (nomusic) { + delete reader; return 0; } - if(reader->Read(id, 32) != 32 || reader->Seek(-32, SEEK_CUR) != 0) - { - return 0; - } + if(reader->Read(id, 32) != 32 || reader->Seek(-32, SEEK_CUR) != 0) + { + delete reader; + return 0; + } #ifndef _WIN32 // non-Windows platforms don't support MDEV_MMAPI so map to MDEV_SNDSYS @@ -403,31 +404,35 @@ MusInfo *I_RegisterSong (std::auto_ptr reader, int device) // Check for gzip compression. Some formats are expected to have players // that can handle it, so it simplifies things if we make all songs // gzippable. - if ((id[0] & MAKE_ID(255,255,255,0)) == GZIP_ID) - { - int len = reader->GetLength(); - BYTE *gzipped = new BYTE[len]; - if (reader->Read(gzipped, len) != len) - { - delete[] gzipped; - return NULL; - } + if ((id[0] & MAKE_ID(255, 255, 255, 0)) == GZIP_ID) + { + int len = reader->GetLength(); + BYTE *gzipped = new BYTE[len]; + if (reader->Read(gzipped, len) != len) + { + delete[] gzipped; + delete reader; + return NULL; + } + delete reader; - std::auto_ptr reader2(new MemoryArrayReader(NULL, 0)); - if(!ungzip(gzipped, len, reader2->GetArray())) - { - delete[] gzipped; - return 0; - } - delete[] gzipped; - reader2->UpdateLength(); + MemoryArrayReader *memreader = new MemoryArrayReader(NULL, 0); + if (!ungzip(gzipped, len, memreader->GetArray())) + { + delete[] gzipped; + delete memreader; + return 0; + } + delete[] gzipped; + memreader->UpdateLength(); - reader.reset(reader2.release()); - if(reader->Read(id, 32) != 32 || reader->Seek(-32, SEEK_CUR) != 0) - { - return 0; - } - } + if (memreader->Read(id, 32) != 32 || memreader->Seek(-32, SEEK_CUR) != 0) + { + delete memreader; + return 0; + } + reader = memreader; + } EMIDIType miditype = IdentifyMIDIType(id, sizeof(id)); if (miditype != MIDI_NOTMIDI) @@ -435,7 +440,7 @@ MusInfo *I_RegisterSong (std::auto_ptr reader, int device) EMidiDevice devtype = (EMidiDevice)device; retry_as_sndsys: - info = CreateMIDIStreamer(reader, devtype, miditype); + info = CreateMIDIStreamer(*reader, devtype, miditype); if (info != NULL && !info->IsValid()) { delete info; @@ -449,7 +454,7 @@ retry_as_sndsys: #ifdef _WIN32 if (info == NULL && devtype != MDEV_MMAPI && snd_mididevice >= 0) { - info = CreateMIDIStreamer(reader, MDEV_MMAPI, miditype); + info = CreateMIDIStreamer(*reader, MDEV_MMAPI, miditype); } #endif } @@ -460,17 +465,17 @@ retry_as_sndsys: (id[0] == MAKE_ID('D','B','R','A') && id[1] == MAKE_ID('W','O','P','L')) || // DosBox Raw OPL (id[0] == MAKE_ID('A','D','L','I') && *((BYTE *)id + 4) == 'B')) // Martin Fernandez's modified IMF { - info = new OPLMUSSong (reader); + info = new OPLMUSSong (*reader); } // Check for game music else if ((fmt = GME_CheckFormat(id[0])) != NULL && fmt[0] != '\0') { - info = GME_OpenSong(reader, fmt); + info = GME_OpenSong(*reader, fmt); } // Check for module formats else { - info = MOD_OpenSong(reader); + info = MOD_OpenSong(*reader); } if (info == NULL) @@ -483,6 +488,7 @@ retry_as_sndsys: reader->Seek(8, SEEK_CUR); if (reader->Read (&subid, 4) != 4) { + delete reader; return 0; } reader->Seek(-12, SEEK_CUR); @@ -490,7 +496,7 @@ retry_as_sndsys: if (subid == (('C')|(('D')<<8)|(('D')<<16)|(('A')<<24))) { // This is a CDDA file - info = new CDDAFile (reader); + info = new CDDAFile (*reader); } } @@ -503,9 +509,13 @@ retry_as_sndsys: { // Let the sound system figure out what it is. info = new StreamSong (reader); + // Assumed ownership + reader = NULL; } } + if (reader != NULL) delete reader; + if (info && !info->IsValid ()) { delete info; diff --git a/src/sound/i_music.h b/src/sound/i_music.h index 5948ceb7c5..f6a6dbadd8 100644 --- a/src/sound/i_music.h +++ b/src/sound/i_music.h @@ -34,8 +34,6 @@ #ifndef __I_MUSIC_H__ #define __I_MUSIC_H__ -#include - #include "doomdef.h" class FileReader; @@ -54,7 +52,7 @@ void I_SetMusicVolume (float volume); // Registers a song handle to song data. class MusInfo; -MusInfo *I_RegisterSong (std::auto_ptr reader, int device); +MusInfo *I_RegisterSong (FileReader *reader, int device); MusInfo *I_RegisterCDSong (int track, int cdid = 0); MusInfo *I_RegisterURLSong (const char *url); diff --git a/src/sound/i_musicinterns.h b/src/sound/i_musicinterns.h index 62561aa95d..77aa313122 100644 --- a/src/sound/i_musicinterns.h +++ b/src/sound/i_musicinterns.h @@ -501,7 +501,7 @@ protected: class MUSSong2 : public MIDIStreamer { public: - MUSSong2(std::auto_ptr reader, EMidiDevice type); + MUSSong2(FileReader &reader, EMidiDevice type); ~MUSSong2(); MusInfo *GetOPLDumper(const char *filename); @@ -527,7 +527,7 @@ protected: class MIDISong2 : public MIDIStreamer { public: - MIDISong2(std::auto_ptr reader, EMidiDevice type); + MIDISong2(FileReader &reader, EMidiDevice type); ~MIDISong2(); MusInfo *GetOPLDumper(const char *filename); @@ -584,7 +584,7 @@ protected: class HMISong : public MIDIStreamer { public: - HMISong(std::auto_ptr reader, EMidiDevice type); + HMISong(FileReader &reader, EMidiDevice type); ~HMISong(); MusInfo *GetOPLDumper(const char *filename); @@ -627,7 +627,7 @@ protected: class XMISong : public MIDIStreamer { public: - XMISong(std::auto_ptr reader, EMidiDevice type); + XMISong(FileReader &reader, EMidiDevice type); ~XMISong(); MusInfo *GetOPLDumper(const char *filename); @@ -666,7 +666,7 @@ protected: class StreamSong : public MusInfo { public: - StreamSong (std::auto_ptr reader); + StreamSong (FileReader *reader); StreamSong (const char *url); ~StreamSong (); void Play (bool looping, int subsong); @@ -690,7 +690,7 @@ protected: class OPLMUSSong : public StreamSong { public: - OPLMUSSong (std::auto_ptr reader); + OPLMUSSong (FileReader &reader); ~OPLMUSSong (); void Play (bool looping, int subsong); bool IsPlaying (); @@ -739,17 +739,17 @@ protected: class CDDAFile : public CDSong { public: - CDDAFile (std::auto_ptr reader); + CDDAFile (FileReader &reader); }; // Module played via foo_dumb ----------------------------------------------- -MusInfo *MOD_OpenSong(std::auto_ptr &reader); +MusInfo *MOD_OpenSong(FileReader &reader); // Music played via Game Music Emu ------------------------------------------ const char *GME_CheckFormat(uint32 header); -MusInfo *GME_OpenSong(std::auto_ptr &reader, const char *fmt); +MusInfo *GME_OpenSong(FileReader &reader, const char *fmt); // -------------------------------------------------------------------------- diff --git a/src/sound/i_sound.cpp b/src/sound/i_sound.cpp index 8904fc7c48..04643dcbab 100644 --- a/src/sound/i_sound.cpp +++ b/src/sound/i_sound.cpp @@ -48,7 +48,6 @@ extern HINSTANCE g_hInst; #include #include #include -#include #include "doomtype.h" #include @@ -173,8 +172,9 @@ public: { return NULL; } - SoundStream *OpenStream (std::auto_ptr reader, int flags) + SoundStream *OpenStream (FileReader *reader, int flags) { + delete reader; return NULL; } @@ -372,17 +372,19 @@ short *SoundRenderer::DecodeSample(int outlen, const void *coded, int sizebytes, SampleType type; int srate; - std::auto_ptr decoder(CreateDecoder(&reader)); - if(!decoder.get()) return samples; + SoundDecoder *decoder = CreateDecoder(&reader); + if(!decoder) return samples; decoder->getInfo(&srate, &chans, &type); if(chans != ChannelConfig_Mono || type != SampleType_Int16) { DPrintf("Sample is not 16-bit mono\n"); + delete decoder; return samples; } decoder->read((char*)samples, outlen); + delete decoder; return samples; } diff --git a/src/sound/i_sound.h b/src/sound/i_sound.h index ab8ec2964b..cf60e54640 100644 --- a/src/sound/i_sound.h +++ b/src/sound/i_sound.h @@ -35,8 +35,6 @@ #ifndef __I_SOUND__ #define __I_SOUND__ -#include - #include "doomtype.h" #include "i_soundinternal.h" @@ -107,7 +105,7 @@ public: // Streaming sounds. virtual SoundStream *CreateStream (SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata) = 0; - virtual SoundStream *OpenStream (std::auto_ptr reader, int flags) = 0; + virtual SoundStream *OpenStream (FileReader *reader, int flags) = 0; virtual SoundStream *OpenStream (const char *url, int flags); // Starts a sound. diff --git a/src/sound/i_soundinternal.h b/src/sound/i_soundinternal.h index 4f4c62b937..60acc43c07 100644 --- a/src/sound/i_soundinternal.h +++ b/src/sound/i_soundinternal.h @@ -1,7 +1,6 @@ #ifndef __SNDINT_H #define __SNDINT_H -#include #include #include "basictypes.h" diff --git a/src/sound/music_cd.cpp b/src/sound/music_cd.cpp index a271d1b228..1d04f53114 100644 --- a/src/sound/music_cd.cpp +++ b/src/sound/music_cd.cpp @@ -79,31 +79,31 @@ bool CDSong::IsPlaying () return m_Status != STATE_Stopped; } -CDDAFile::CDDAFile (std::auto_ptr reader) +CDDAFile::CDDAFile (FileReader &reader) : CDSong () { DWORD chunk; WORD track; DWORD discid; - long endpos = reader->Tell() + reader->GetLength() - 8; + long endpos = reader.Tell() + reader.GetLength() - 8; // I_RegisterSong already identified this as a CDDA file, so we // just need to check the contents we're interested in. - reader->Seek(12, SEEK_CUR); + reader.Seek(12, SEEK_CUR); - while (reader->Tell() < endpos) + while (reader.Tell() < endpos) { - reader->Read(&chunk, 4); + reader.Read(&chunk, 4); if (chunk != (('f')|(('m')<<8)|(('t')<<16)|((' ')<<24))) { - reader->Read(&chunk, 4); - reader->Seek(chunk, SEEK_CUR); + reader.Read(&chunk, 4); + reader.Seek(chunk, SEEK_CUR); } else { - reader->Seek(6, SEEK_CUR); - reader->Read(&track, 2); - reader->Read(&discid, 4); + reader.Seek(6, SEEK_CUR); + reader.Read(&track, 2); + reader.Read(&discid, 4); if (CD_InitID (discid) && CD_CheckTrack (track)) { diff --git a/src/sound/music_dumb.cpp b/src/sound/music_dumb.cpp index 92566246d1..8b196e7cda 100644 --- a/src/sound/music_dumb.cpp +++ b/src/sound/music_dumb.cpp @@ -532,7 +532,7 @@ static DUMBFILE_SYSTEM mem_dfs = { // //========================================================================== -DUMBFILE *dumb_read_allfile(dumbfile_mem_status *filestate, BYTE *start, std::auto_ptr &reader, int lenhave, int lenfull) +DUMBFILE *dumb_read_allfile(dumbfile_mem_status *filestate, BYTE *start, FileReader &reader, int lenhave, int lenfull) { filestate->size = lenfull; filestate->offset = 0; @@ -542,7 +542,7 @@ DUMBFILE *dumb_read_allfile(dumbfile_mem_status *filestate, BYTE *start, std::au { BYTE *mem = new BYTE[lenfull]; memcpy(mem, start, lenhave); - if (reader->Read(mem + lenhave, lenfull - lenhave) != (lenfull - lenhave)) + if (reader.Read(mem + lenhave, lenfull - lenhave) != (lenfull - lenhave)) { delete[] mem; return NULL; @@ -747,7 +747,7 @@ static void MOD_SetAutoChip(DUH *duh) // //========================================================================== -MusInfo *MOD_OpenSong(std::auto_ptr &reader) +MusInfo *MOD_OpenSong(FileReader &reader) { DUH *duh = 0; int headsize; @@ -771,14 +771,14 @@ MusInfo *MOD_OpenSong(std::auto_ptr &reader) atterm(dumb_exit); - int size = reader->GetLength(); - fpos = reader->Tell(); + int size = reader.GetLength(); + fpos = reader.Tell(); filestate.ptr = start; filestate.offset = 0; headsize = MIN((int)sizeof(start), size); - if (headsize != reader->Read(start, headsize)) + if (headsize != reader.Read(start, headsize)) { return NULL; } @@ -890,7 +890,7 @@ MusInfo *MOD_OpenSong(std::auto_ptr &reader) { if (!(f = dumb_read_allfile(&filestate, start, reader, headsize, size))) { - reader->Seek(fpos, SEEK_SET); + reader.Seek(fpos, SEEK_SET); return NULL; } } @@ -931,13 +931,12 @@ MusInfo *MOD_OpenSong(std::auto_ptr &reader) else { // Reposition file pointer for other codecs to do their checks. - reader->Seek(fpos, SEEK_SET); + reader.Seek(fpos, SEEK_SET); } if (filestate.ptr != (BYTE *)start) { delete[] const_cast(filestate.ptr); } - if(state) reader.reset(); return state; } diff --git a/src/sound/music_gme.cpp b/src/sound/music_gme.cpp index 7db5110b79..973092ee52 100644 --- a/src/sound/music_gme.cpp +++ b/src/sound/music_gme.cpp @@ -105,7 +105,7 @@ const char *GME_CheckFormat(uint32 id) // //========================================================================== -MusInfo *GME_OpenSong(std::auto_ptr &reader, const char *fmt) +MusInfo *GME_OpenSong(FileReader &reader, const char *fmt) { gme_type_t type; gme_err_t err; @@ -125,14 +125,14 @@ MusInfo *GME_OpenSong(std::auto_ptr &reader, const char *fmt) return NULL; } - int fpos = reader->Tell(); - int len = reader->GetLength(); + int fpos = reader.Tell(); + int len = reader.GetLength(); song = new BYTE[len]; - if (reader->Read(song, len) != len) + if (reader.Read(song, len) != len) { delete[] song; gme_delete(emu); - reader->Seek(fpos, SEEK_SET); + reader.Seek(fpos, SEEK_SET); return NULL; } @@ -143,10 +143,9 @@ MusInfo *GME_OpenSong(std::auto_ptr &reader, const char *fmt) { Printf("Failed loading song: %s\n", err); gme_delete(emu); - reader->Seek(fpos, SEEK_SET); + reader.Seek(fpos, SEEK_SET); return NULL; } - reader.reset(); return new GMESong(emu, sample_rate); } diff --git a/src/sound/music_hmi_midiout.cpp b/src/sound/music_hmi_midiout.cpp index 9df28d6346..5fef706dd8 100644 --- a/src/sound/music_hmi_midiout.cpp +++ b/src/sound/music_hmi_midiout.cpp @@ -128,7 +128,7 @@ extern char MIDI_CommonLengths[15]; // //========================================================================== -HMISong::HMISong (std::auto_ptr reader, EMidiDevice type) +HMISong::HMISong (FileReader &reader, EMidiDevice type) : MIDIStreamer(type), MusHeader(0), Tracks(0) { #ifdef _WIN32 @@ -137,7 +137,7 @@ HMISong::HMISong (std::auto_ptr reader, EMidiDevice type) return; } #endif - int len = reader->GetLength(); + int len = reader.GetLength(); if (len < 0x100) { // Way too small to be HMI. return; @@ -145,7 +145,7 @@ HMISong::HMISong (std::auto_ptr reader, EMidiDevice type) MusHeader = new BYTE[len]; SongLen = len; NumTracks = 0; - if (reader->Read(MusHeader, len) != len) + if (reader.Read(MusHeader, len) != len) return; // Do some validation of the MIDI file diff --git a/src/sound/music_mus_midiout.cpp b/src/sound/music_mus_midiout.cpp index e7e0894bbd..5f7d2d5031 100644 --- a/src/sound/music_mus_midiout.cpp +++ b/src/sound/music_mus_midiout.cpp @@ -92,7 +92,7 @@ static const BYTE CtrlTranslate[15] = // //========================================================================== -MUSSong2::MUSSong2 (std::auto_ptr reader, EMidiDevice type) +MUSSong2::MUSSong2 (FileReader &reader, EMidiDevice type) : MIDIStreamer(type), MusHeader(0), MusBuffer(0) { #ifdef _WIN32 @@ -105,7 +105,7 @@ MUSSong2::MUSSong2 (std::auto_ptr reader, EMidiDevice type) BYTE front[32]; int start; - if (reader->Read(front, sizeof(front)) != sizeof(front)) + if (reader.Read(front, sizeof(front)) != sizeof(front)) { return; } @@ -121,14 +121,14 @@ MUSSong2::MUSSong2 (std::auto_ptr reader, EMidiDevice type) } // Read the remainder of the song. - int len = int(reader->GetLength() - start); + int len = int(reader.GetLength() - start); if (len < (int)sizeof(MusHeader)) { // It's too short. return; } MusHeader = (MUSHeader *)new BYTE[len]; memcpy(MusHeader, front + start, sizeof(front) - start); - if (reader->Read((BYTE *)MusHeader + sizeof(front) - start, len - (sizeof(front) - start)) != (len - (32 - start))) + if (reader.Read((BYTE *)MusHeader + sizeof(front) - start, len - (sizeof(front) - start)) != (len - (32 - start))) { return; } diff --git a/src/sound/music_mus_opl.cpp b/src/sound/music_mus_opl.cpp index c8b694a21a..3b5012ad94 100644 --- a/src/sound/music_mus_opl.cpp +++ b/src/sound/music_mus_opl.cpp @@ -22,11 +22,11 @@ CUSTOM_CVAR (Int, opl_numchips, 2, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR(Int, opl_core, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) -OPLMUSSong::OPLMUSSong (std::auto_ptr reader) +OPLMUSSong::OPLMUSSong (FileReader &reader) { int samples = int(OPL_SAMPLE_RATE / 14); - Music = new OPLmusicFile (reader.get()); + Music = new OPLmusicFile (&reader); m_Stream = GSnd->CreateStream (FillStream, samples*4, (opl_core == 0 ? SoundStream::Mono : 0) | SoundStream::Float, int(OPL_SAMPLE_RATE), this); diff --git a/src/sound/music_pseudo_mididevice.cpp b/src/sound/music_pseudo_mididevice.cpp index 422f039cef..14a1758713 100644 --- a/src/sound/music_pseudo_mididevice.cpp +++ b/src/sound/music_pseudo_mididevice.cpp @@ -254,12 +254,11 @@ int SndSysMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWORD), bool SndSysMIDIDevice::Preprocess(MIDIStreamer *song, bool looping) { - std::auto_ptr reader(new MemoryArrayReader(NULL, 0)); + MemoryArrayReader *reader = new MemoryArrayReader(NULL, 0); song->CreateSMF(reader->GetArray(), looping ? 0 : 1); reader->UpdateLength(); bLooping = looping; - Stream = GSnd->OpenStream(std::auto_ptr(reader.release()), - looping ? SoundStream::Loop : 0); + Stream = GSnd->OpenStream(reader, looping ? SoundStream::Loop : 0); return false; } diff --git a/src/sound/music_smf_midiout.cpp b/src/sound/music_smf_midiout.cpp index 6f73277d33..d5d307ec7e 100644 --- a/src/sound/music_smf_midiout.cpp +++ b/src/sound/music_smf_midiout.cpp @@ -102,7 +102,7 @@ char MIDI_CommonLengths[15] = { 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // //========================================================================== -MIDISong2::MIDISong2 (std::auto_ptr reader, EMidiDevice type) +MIDISong2::MIDISong2 (FileReader &reader, EMidiDevice type) : MIDIStreamer(type), MusHeader(0), Tracks(0) { int p; @@ -114,9 +114,9 @@ MIDISong2::MIDISong2 (std::auto_ptr reader, EMidiDevice type) return; } #endif - SongLen = reader->GetLength(); + SongLen = reader.GetLength(); MusHeader = new BYTE[SongLen]; - if (reader->Read(MusHeader, SongLen) != SongLen) + if (reader.Read(MusHeader, SongLen) != SongLen) return; // Do some validation of the MIDI file diff --git a/src/sound/music_stream.cpp b/src/sound/music_stream.cpp index 1f528c3091..7505cb89b5 100644 --- a/src/sound/music_stream.cpp +++ b/src/sound/music_stream.cpp @@ -52,7 +52,7 @@ StreamSong::~StreamSong () } } -StreamSong::StreamSong (std::auto_ptr reader) +StreamSong::StreamSong (FileReader *reader) { m_Stream = GSnd->OpenStream (reader, SoundStream::Loop); } diff --git a/src/sound/music_xmi_midiout.cpp b/src/sound/music_xmi_midiout.cpp index f50e8669d4..6c179a16a0 100644 --- a/src/sound/music_xmi_midiout.cpp +++ b/src/sound/music_xmi_midiout.cpp @@ -108,7 +108,7 @@ extern char MIDI_CommonLengths[15]; // //========================================================================== -XMISong::XMISong (std::auto_ptr reader, EMidiDevice type) +XMISong::XMISong (FileReader &reader, EMidiDevice type) : MIDIStreamer(type), MusHeader(0), Songs(0) { #ifdef _WIN32 @@ -117,9 +117,9 @@ XMISong::XMISong (std::auto_ptr reader, EMidiDevice type) return; } #endif - SongLen = reader->GetLength(); + SongLen = reader.GetLength(); MusHeader = new BYTE[SongLen]; - if (reader->Read(MusHeader, SongLen) != SongLen) + if (reader.Read(MusHeader, SongLen) != SongLen) return; // Find all the songs in this file. diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 3f61578a87..5745f97984 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -82,19 +82,14 @@ void I_BuildALDeviceList(FOptionValues *opt) names += strlen(names) + 1; } } - __except (CheckException(GetExceptionCode())) - { - } + __except (CheckException(GetExceptionCode())) + { + } #endif } #ifndef NO_OPENAL -#include -#include -#include -#include - EXTERN_CVAR (Int, snd_channels) EXTERN_CVAR (Int, snd_samplerate) @@ -173,8 +168,8 @@ class OpenALSoundStream : public SoundStream ALfloat Volume; - std::auto_ptr Reader; - std::auto_ptr Decoder; + FileReader *Reader; + SoundDecoder *Decoder; static bool DecoderCallback(SoundStream *_sstream, void *ptr, int length, void *user) { OpenALSoundStream *self = static_cast(_sstream); @@ -230,7 +225,7 @@ class OpenALSoundStream : public SoundStream public: OpenALSoundStream(OpenALSoundRenderer *renderer) - : Renderer(renderer), Source(0), Playing(false), Looping(false), Volume(1.0f) + : Renderer(renderer), Source(0), Playing(false), Looping(false), Volume(1.0f), Reader(NULL), Decoder(NULL) { Renderer->Streams.Push(this); memset(Buffers, 0, sizeof(Buffers)); @@ -256,6 +251,9 @@ public: Renderer->Streams.Delete(Renderer->Streams.Find(this)); Renderer = NULL; + + delete Decoder; + delete Reader; } @@ -516,14 +514,19 @@ public: return true; } - bool Init(std::auto_ptr reader, bool loop) + bool Init(FileReader *reader, bool loop) { if(!SetupSource()) + { + delete reader; return false; + } + if(Decoder) delete Decoder; + if(Reader) delete Reader; Reader = reader; - Decoder.reset(Renderer->CreateDecoder(Reader.get())); - if(!Decoder.get()) return false; + Decoder = Renderer->CreateDecoder(Reader); + if(!Decoder) return false; Callback = DecoderCallback; UserData = NULL; @@ -615,12 +618,12 @@ ALCdevice *OpenALSoundRenderer::InitDevice() Printf(TEXTCOLOR_RED" Could not open audio device\n"); } } - } - __except(CheckException(GetExceptionCode())) - { - Printf(TEXTCOLOR_ORANGE"Failed to load openal32.dll\n"); - } - return device; + } + __except(CheckException(GetExceptionCode())) + { + Printf(TEXTCOLOR_ORANGE"Failed to load openal32.dll\n"); + } + return device; } @@ -652,20 +655,20 @@ OpenALSoundRenderer::OpenALSoundRenderer() DPrintf(" ALC Version: "TEXTCOLOR_BLUE"%d.%d\n", major, minor); DPrintf(" ALC Extensions: "TEXTCOLOR_ORANGE"%s\n", alcGetString(Device, ALC_EXTENSIONS)); - std::vector attribs; + TArray attribs; if(*snd_samplerate > 0) { - attribs.push_back(ALC_FREQUENCY); - attribs.push_back(*snd_samplerate); + attribs.Push(ALC_FREQUENCY); + attribs.Push(*snd_samplerate); } // Make sure one source is capable of stereo output with the rest doing // mono, without running out of voices - attribs.push_back(ALC_MONO_SOURCES); - attribs.push_back(std::max(*snd_channels, 2) - 1); - attribs.push_back(ALC_STEREO_SOURCES); - attribs.push_back(1); + attribs.Push(ALC_MONO_SOURCES); + attribs.Push(MAX(*snd_channels, 2) - 1); + attribs.Push(ALC_STEREO_SOURCES); + attribs.Push(1); // Other attribs..? - attribs.push_back(0); + attribs.Push(0); Context = alcCreateContext(Device, &attribs[0]); if(!Context || alcMakeContextCurrent(Context) == ALC_FALSE) @@ -678,7 +681,7 @@ OpenALSoundRenderer::OpenALSoundRenderer() Device = NULL; return; } - attribs.clear(); + attribs.Clear(); DPrintf(" Vendor: "TEXTCOLOR_ORANGE"%s\n", alGetString(AL_VENDOR)); DPrintf(" Renderer: "TEXTCOLOR_ORANGE"%s\n", alGetString(AL_RENDERER)); @@ -723,7 +726,7 @@ OpenALSoundRenderer::OpenALSoundRenderer() alcGetIntegerv(Device, ALC_MONO_SOURCES, 1, &numMono); alcGetIntegerv(Device, ALC_STEREO_SOURCES, 1, &numStereo); - Sources.Resize(std::min(std::max(*snd_channels, 2), numMono+numStereo)); + Sources.Resize(MIN(MAX(*snd_channels, 2), numMono+numStereo)); for(size_t i = 0;i < Sources.Size();i++) { alGenSources(1, &Sources[i]); @@ -1024,8 +1027,8 @@ SoundHandle OpenALSoundRenderer::LoadSound(BYTE *sfxdata, int length) SampleType type; int srate; - std::auto_ptr decoder(CreateDecoder(&reader)); - if(!decoder.get()) return retval; + SoundDecoder *decoder = CreateDecoder(&reader); + if(!decoder) return retval; decoder->getInfo(&srate, &chans, &type); if(chans == ChannelConfig_Mono) @@ -1043,6 +1046,7 @@ SoundHandle OpenALSoundRenderer::LoadSound(BYTE *sfxdata, int length) { Printf("Unsupported audio format: %s, %s\n", GetChannelConfigName(chans), GetSampleTypeName(type)); + delete decoder; return retval; } @@ -1058,10 +1062,12 @@ SoundHandle OpenALSoundRenderer::LoadSound(BYTE *sfxdata, int length) Printf("Failed to buffer data: %s\n", alGetString(err)); alDeleteBuffers(1, &buffer); getALError(); + delete decoder; return retval; } retval.data = MAKE_PTRID(buffer); + delete decoder; return retval; } @@ -1096,18 +1102,24 @@ void OpenALSoundRenderer::UnloadSound(SoundHandle sfx) SoundStream *OpenALSoundRenderer::CreateStream(SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata) { - std::auto_ptr stream(new OpenALSoundStream(this)); - if(!stream->Init(callback, buffbytes, flags, samplerate, userdata)) - return NULL; - return stream.release(); + OpenALSoundStream *stream = new OpenALSoundStream(this); + if (!stream->Init(callback, buffbytes, flags, samplerate, userdata)) + { + delete stream; + return NULL; + } + return stream; } -SoundStream *OpenALSoundRenderer::OpenStream(std::auto_ptr reader, int flags) +SoundStream *OpenALSoundRenderer::OpenStream(FileReader *reader, int flags) { - std::auto_ptr stream(new OpenALSoundStream(this)); - - if (!stream->Init(reader, !!(flags&SoundStream::Loop))) return NULL; - return stream.release(); + OpenALSoundStream *stream = new OpenALSoundStream(this); + if (!stream->Init(reader, !!(flags&SoundStream::Loop))) + { + delete stream; + return NULL; + } + return stream; } FISoundChannel *OpenALSoundRenderer::StartSound(SoundHandle sfx, float vol, int pitch, int chanflags, FISoundChannel *reuse_chan) diff --git a/src/sound/oalsound.h b/src/sound/oalsound.h index e6de8ce6d9..4f6bae3968 100644 --- a/src/sound/oalsound.h +++ b/src/sound/oalsound.h @@ -1,10 +1,6 @@ #ifndef OALSOUND_H #define OALSOUND_H - -#include -#include - #include "i_sound.h" #include "s_sound.h" #include "menu/menu.h" @@ -82,7 +78,7 @@ public: // Streaming sounds. virtual SoundStream *CreateStream(SoundStreamCallback callback, int buffbytes, int flags, int samplerate, void *userdata); - virtual SoundStream *OpenStream(std::auto_ptr reader, int flags); + virtual SoundStream *OpenStream(FileReader *reader, int flags); // Starts a sound. virtual FISoundChannel *StartSound(SoundHandle sfx, float vol, int pitch, int chanflags, FISoundChannel *reuse_chan); diff --git a/src/sound/sndfile_decoder.cpp b/src/sound/sndfile_decoder.cpp index 4a477baf8a..a5b10faf32 100644 --- a/src/sound/sndfile_decoder.cpp +++ b/src/sound/sndfile_decoder.cpp @@ -6,12 +6,12 @@ #include "except.h" #include "sndfile_decoder.h" +#include "templates.h" #include "files.h" +#include "xs_Float.h" #ifdef HAVE_SNDFILE -#include - sf_count_t SndFileDecoder::file_get_filelen(void *user_data) { FileReader *reader = reinterpret_cast(user_data)->Reader; @@ -69,10 +69,10 @@ bool SndFileDecoder::open(FileReader *reader) SndFile = 0; } } - __except (CheckException(GetExceptionCode())) - { - // this means that the delay loaded decoder DLL was not found. - } + __except (CheckException(GetExceptionCode())) + { + // this means that the delay loaded decoder DLL was not found. + } return false; } @@ -103,14 +103,14 @@ size_t SndFileDecoder::read(char *buffer, size_t bytes) // could be more. while(total < frames) { - size_t todo = std::min(frames-total, 64/SndInfo.channels); + size_t todo = MIN(frames-total, 64/SndInfo.channels); float tmp[64]; size_t got = (size_t)sf_readf_float(SndFile, tmp, todo); if(got < todo) frames = total + got; for(size_t i = 0;i < got*SndInfo.channels;i++) - *out++ = (short)((std::min)((std::max)(tmp[i] * 32767.f, -32768.f), 32767.f)); + *out++ = (short)xs_CRoundToInt(clamp(tmp[i] * 32767.f, -32768.f, 32767.f)); total += got; } return total * SndInfo.channels * 2; From 46e975418d9776de580b9e404fe2a100b464d6ae Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Apr 2015 08:48:49 +0200 Subject: [PATCH 81/88] - fixeed: Sound sequence overrides took the parameter from the wrong data structure. --- src/p_mobj.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 5921f97e70..e2aa677649 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -4749,7 +4749,7 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position) // [RH] sound sequence overriders if (mentry->Type == NULL && mentry->Special == SMT_SSeqOverride) { - int type = mentry->Args[0]; + int type = mthing->args[0]; if (type == 255) type = -1; if (type > 63) { From 8e70a9b894cf4696c9b20c695a1863536987e7b4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Apr 2015 09:58:10 +0200 Subject: [PATCH 82/88] - added a NULL check to FMODStreamCapsule destructor, just to be safe. --- src/sound/fmodsound.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index 44a42819f3..9559e2b70f 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -331,7 +331,10 @@ public: { Stream->release(); } - delete Reader; + if (Reader != NULL) + { + delete Reader; + } } void SetStream(FMOD::Sound *stream) From aecff68a4d78154ac5f9a48b12fed79716f204f0 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Apr 2015 12:13:21 +0200 Subject: [PATCH 83/88] - cleanup of sound system startup and menu handling: * added global functions that check whether FMod and OpenAL are present, without initializing the sound backend. * make sound init code more fault tolerant. It will now try to switch between FMod and OpenAL if the currently active one cannot be found but the other one can. * added 'ifoption' checks for sound backend to menu code. * only show sound backends which are present and hide the options for the ones which are not. --- src/menu/menudef.cpp | 21 +++++++++++++-- src/sound/fmodsound.cpp | 54 +++++++++++++++++++++++++++++++------ src/sound/i_sound.cpp | 57 ++++++++++++++++++++++++++++++++------- src/sound/i_sound.h | 3 +++ src/sound/oalsound.cpp | 39 ++++++++++++++++++++++----- wadsrc/static/menudef.txt | 44 +++++++++++++++++++++++++++--- 6 files changed, 188 insertions(+), 30 deletions(-) diff --git a/src/menu/menudef.cpp b/src/menu/menudef.cpp index b1db3cf2ef..819ba96ba7 100644 --- a/src/menu/menudef.cpp +++ b/src/menu/menudef.cpp @@ -49,6 +49,7 @@ #include "i_music.h" #include "m_joy.h" #include "gi.h" +#include "i_sound.h" #include "optionmenuitems.h" @@ -170,6 +171,14 @@ static bool CheckSkipOptionBlock(FScanner &sc) filter = true; #endif } + else if (sc.Compare("OpenAL")) + { + filter |= IsOpenALPresent(); + } + else if (sc.Compare("FModEx")) + { + filter |= IsFModExPresent(); + } } while (sc.CheckString(",")); sc.MustGetStringName(")"); @@ -591,7 +600,11 @@ static void ParseOptionSettings(FScanner &sc) while (!sc.CheckString("}")) { sc.MustGetString(); - if (sc.Compare("ifgame")) + if (sc.Compare("else")) + { + SkipSubBlock(sc); + } + else if (sc.Compare("ifgame")) { if (!CheckSkipGameBlock(sc)) { @@ -628,7 +641,11 @@ static void ParseOptionMenuBody(FScanner &sc, FOptionMenuDescriptor *desc) while (!sc.CheckString("}")) { sc.MustGetString(); - if (sc.Compare("ifgame")) + if (sc.Compare("else")) + { + SkipSubBlock(sc); + } + else if (sc.Compare("ifgame")) { if (!CheckSkipGameBlock(sc)) { diff --git a/src/sound/fmodsound.cpp b/src/sound/fmodsound.cpp index 9559e2b70f..73e4195557 100644 --- a/src/sound/fmodsound.cpp +++ b/src/sound/fmodsound.cpp @@ -671,14 +671,8 @@ bool FMODSoundRenderer::Init() Printf("I_InitSound: Initializing FMOD\n"); - HMODULE a = GetModuleHandle("fmodex.dll"); - - // Create a System object and initialize. - __try - { - result = FMOD::System_Create(&Sys); - } - __except(CheckException(GetExceptionCode())) + // This is just for safety. Normally this should never be called if FMod Ex cannot be found. + if (!IsFModExPresent()) { Sys = NULL; Printf(TEXTCOLOR_ORANGE"Failed to load fmodex" @@ -688,6 +682,9 @@ bool FMODSoundRenderer::Init() ".dll\n"); return false; } + + // Create a System object and initialize. + result = FMOD::System_Create(&Sys); if (result != FMOD_OK) { Sys = NULL; @@ -3177,3 +3174,44 @@ FMOD_RESULT FMODSoundRenderer::SetSystemReverbProperties(const REVERB_PROPERTIES } #endif // NO_FMOD + + +//========================================================================== +// +// IsFModExPresent +// +// Check if FMod can be used +// +//========================================================================== + +bool IsFModExPresent() +{ +#ifdef NO_FMOD + return false; +#elif !defined _WIN32 + return true; // on non-Windows we cannot delay load the library so it has to be present. +#else + static bool cached_result; + static bool done = false; + + if (!done) + { + done = true; + + FMOD::System *Sys; + FMOD_RESULT result; + __try + { + result = FMOD::System_Create(&Sys); + } + __except (CheckException(GetExceptionCode())) + { + // FMod could not be delay loaded + return false; + } + if (result == FMOD_OK) Sys->release(); + cached_result = true; + } + return cached_result; +#endif +} diff --git a/src/sound/i_sound.cpp b/src/sound/i_sound.cpp index 04643dcbab..0a14adc29c 100644 --- a/src/sound/i_sound.cpp +++ b/src/sound/i_sound.cpp @@ -83,13 +83,15 @@ CVAR (Int, snd_buffersize, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (String, snd_output, "default", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) #ifndef NO_FMOD -CVAR (String, snd_backend, "fmod", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +#define DEF_BACKEND "fmod" #elif !defined(NO_OPENAL) -CVAR (String, snd_backend, "openal", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +#define DEF_BACKEND "openal" #else -CVAR (String, snd_backend, "null", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +#define DEF_BACKEND "null" #endif +CVAR(String, snd_backend, DEF_BACKEND, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) + // killough 2/21/98: optionally use varying pitched sounds CVAR (Bool, snd_pitched, false, CVAR_ARCHIVE) @@ -256,6 +258,7 @@ void I_InitSound () nosound = !!Args->CheckParm ("-nosound"); nosfx = !!Args->CheckParm ("-nosfx"); + GSnd = NULL; if (nosound) { GSnd = new NullSoundRenderer; @@ -263,16 +266,50 @@ void I_InitSound () return; } - if(stricmp(snd_backend, "null") == 0) + // This has been extended to allow falling back from FMod to OpenAL and vice versa if the currently active sound system cannot be found. + if (stricmp(snd_backend, "null") == 0) + { GSnd = new NullSoundRenderer; -#ifndef NO_FMOD + } else if(stricmp(snd_backend, "fmod") == 0) - GSnd = new FMODSoundRenderer; -#endif -#ifndef NO_OPENAL + { + #ifndef NO_FMOD + if (IsFModExPresent()) + { + GSnd = new FMODSoundRenderer; + } + #endif + #ifndef NO_OPENAL + if ((!GSnd || !GSnd->IsValid()) && IsOpenALPresent()) + { + Printf (TEXTCOLOR_RED"FMod Ex Sound init failed. Trying OpenAL.\n"); + GSnd = new OpenALSoundRenderer; + snd_backend = "openal"; + } + #endif + } else if(stricmp(snd_backend, "openal") == 0) - GSnd = new OpenALSoundRenderer; -#endif + { + #ifndef NO_OPENAL + if (IsOpenALPresent()) + { + GSnd = new OpenALSoundRenderer; + } + #endif + #ifndef NO_FMOD + if ((!GSnd || !GSnd->IsValid()) && IsFModExPresent()) + { + Printf (TEXTCOLOR_RED"OpenAL Sound init failed. Trying FMod Ex.\n"); + GSnd = new FMODSoundRenderer; + snd_backend = "fmod"; + } + #endif + } + else + { + Printf (TEXTCOLOR_RED"%s: Unknown sound system specified\n", *snd_backend); + snd_backend = "null"; + } if (!GSnd || !GSnd->IsValid ()) { I_CloseSound(); diff --git a/src/sound/i_sound.h b/src/sound/i_sound.h index cf60e54640..153fe38634 100644 --- a/src/sound/i_sound.h +++ b/src/sound/i_sound.h @@ -175,4 +175,7 @@ FISoundChannel *S_GetChannel(void *syschan); extern ReverbContainer *DefaultEnvironments[26]; +bool IsFModExPresent(); +bool IsOpenALPresent(); + #endif diff --git a/src/sound/oalsound.cpp b/src/sound/oalsound.cpp index 5745f97984..6d7cb210e6 100644 --- a/src/sound/oalsound.cpp +++ b/src/sound/oalsound.cpp @@ -59,6 +59,36 @@ CVAR (String, snd_aldevice, "Default", CVAR_ARCHIVE|CVAR_GLOBALCONFIG) CVAR (Bool, snd_efx, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +bool IsOpenALPresent() +{ +#ifdef NO_OPENAL + return false; +#elif !defined _WIN32 + return true; // on non-Windows we cannot delay load the library so it has to be present. +#else + static bool cached_result; + static bool done = false; + + if (!done) + { + done = true; + + __try + { + // just call one function from the API to force loading the DLL + alcGetError(NULL); + } + __except (CheckException(GetExceptionCode())) + { + // FMod could not be delay loaded + return false; + } + cached_result = true; + } + return cached_result; +#endif +} + void I_BuildALDeviceList(FOptionValues *opt) { opt->mValues.Resize(1); @@ -66,7 +96,7 @@ void I_BuildALDeviceList(FOptionValues *opt) opt->mValues[0].Text = "Default"; #ifndef NO_OPENAL - __try + if (IsOpenALPresent()) { const ALCchar *names = (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") ? alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER) : @@ -82,9 +112,6 @@ void I_BuildALDeviceList(FOptionValues *opt) names += strlen(names) + 1; } } - __except (CheckException(GetExceptionCode())) - { - } #endif } @@ -601,7 +628,7 @@ static float GetRolloff(const FRolloffInfo *rolloff, float distance) ALCdevice *OpenALSoundRenderer::InitDevice() { ALCdevice *device = NULL; - __try + if (IsOpenALPresent()) { if(strcmp(snd_aldevice, "Default") != 0) { @@ -619,7 +646,7 @@ ALCdevice *OpenALSoundRenderer::InitDevice() } } } - __except(CheckException(GetExceptionCode())) + else { Printf(TEXTCOLOR_ORANGE"Failed to load openal32.dll\n"); } diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index c7ce861d58..f15f91dff3 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -1450,11 +1450,22 @@ OptionString Resamplers OptionString SoundBackends { - "fmod", "FMOD" + "fmod", "FMOD Ex" "openal", "OpenAL" "null", "No Sound" } +OptionString SoundBackendsFModOnly +{ + "fmod", "FMOD Ex" + "null", "No Sound" +} + +OptionString SoundBackendsOpenALOnly +{ + "openal", "OpenAL" + "null", "No Sound" +} OptionMenu FMODSoundItems { @@ -1507,9 +1518,34 @@ OptionMenu SoundOptions Option "Randomize pitches", "snd_pitched", "OnOff" Slider "Sound channels", "snd_channels", 8, 256, 8, 0 StaticText " " - Option "Sound backend", "snd_backend", "SoundBackends" - Submenu "FMOD options", "FMODSoundItems" - Submenu "OpenAL options", "OpenALSoundItems" + + ifoption(fmodex) + { + ifoption(openal) + { + Option "Sound backend", "snd_backend", "SoundBackends" + } + else + { + Option "Sound backend", "snd_backend", "SoundBackendsFModOnly" + } + } + else + { + ifoption(openal) + { + Option "Sound backend", "snd_backend", "SoundBackendsOpenALOnly" + } + } + + ifoption(fmodex) + { + Submenu "FMOD options", "FMODSoundItems" + } + ifoption(openal) + { + Submenu "OpenAL options", "OpenALSoundItems" + } StaticText " " Command "Restart sound", "snd_reset" From 4294b94728bee8e70d0b493fe1e15f7e27fc56ae Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Apr 2015 22:09:19 +0200 Subject: [PATCH 84/88] - since Wads.ReopenLumpNum already performs caching on the lump data it is not really necessary anymore to maintain a separate musiccache, so this code can be removed. --- src/s_sound.cpp | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) diff --git a/src/s_sound.cpp b/src/s_sound.cpp index 070ba56584..e34edf1177 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -2331,8 +2331,6 @@ bool S_StartMusic (const char *m_id) // specified, it will only be played if the specified CD is in a drive. //========================================================================== -TArray musiccache; - bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) { if (!force && PlayList) @@ -2456,31 +2454,11 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) } if (handle == NULL) { - if (!Wads.IsUncompressedFile(lumpnum)) + if (Wads.LumpLength (lumpnum) == 0) { - // We must cache the music data and use it from memory. - - // shut down old music before reallocating and overwriting the cache! - S_StopMusic (true); - - length = Wads.LumpLength (lumpnum); - if (length == 0) - { - return false; - } - musiccache.Resize(length); - Wads.ReadLump(lumpnum, &musiccache[0]); - - reader = new MemoryReader((const char*)&musiccache[0], musiccache.Size()); - } - else - { - if (Wads.LumpLength (lumpnum) == 0) - { - return false; - } - reader = Wads.ReopenLumpNum(lumpnum); + return false; } + reader = Wads.ReopenLumpNum(lumpnum); } } else From 13fb76db21144e1f89245b075ef4fec13a1bfd09 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 26 Apr 2015 23:28:05 +0200 Subject: [PATCH 85/88] - changed lump reader setup for music so that for uncompressed data it opens a new FILE instead of caching the lump. This reinstates behavior of pre-OpenAL versions but still uses the FileReader interface to keep the simplified code of the OpenAL branch. --- src/s_sound.cpp | 6 +++++- src/w_wad.cpp | 39 +++++++++++++++++++++++++++++++++++++++ src/w_wad.h | 2 ++ 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/s_sound.cpp b/src/s_sound.cpp index e34edf1177..bacd5aa946 100644 --- a/src/s_sound.cpp +++ b/src/s_sound.cpp @@ -2458,7 +2458,11 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force) { return false; } - reader = Wads.ReopenLumpNum(lumpnum); + reader = Wads.ReopenLumpNumNewFile(lumpnum); + if (reader == NULL) + { + return false; + } } } else diff --git a/src/w_wad.cpp b/src/w_wad.cpp index 2b3413460d..efeb38571c 100644 --- a/src/w_wad.cpp +++ b/src/w_wad.cpp @@ -1228,6 +1228,17 @@ FWadLump *FWadCollection::ReopenLumpNum (int lump) return new FWadLump(LumpInfo[lump].lump, true); } +FWadLump *FWadCollection::ReopenLumpNumNewFile (int lump) +{ + if ((unsigned)lump >= (unsigned)LumpInfo.Size()) + { + return NULL; + } + + return new FWadLump(lump, LumpInfo[lump].lump); +} + + //========================================================================== // // GetFileReader @@ -1417,6 +1428,34 @@ FWadLump::FWadLump(FResourceLump *lump, bool alwayscache) } } +FWadLump::FWadLump(int lumpnum, FResourceLump *lump) +: FileReader() +{ + FileReader *f = lump->GetReader(); + + if (f != NULL && f->GetFile() != NULL) + { + // Uncompressed lump in a file. For this we will have to open a new FILE, since we need it for streaming + int fileno = Wads.GetLumpFile(lumpnum); + const char *filename = Wads.GetWadFullName(fileno); + File = fopen(filename, "rb"); + if (File != NULL) + { + Length = lump->LumpSize; + StartPos = FilePos = lump->GetFileOffset(); + Lump = NULL; + CloseOnDestruct = true; + Seek(0, SEEK_SET); + return; + } + } + File = NULL; + Length = lump->LumpSize; + StartPos = FilePos = 0; + Lump = lump; + Lump->CacheLump(); +} + FWadLump::~FWadLump() { if (Lump != NULL) diff --git a/src/w_wad.h b/src/w_wad.h index 63912373e4..323f12df24 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -112,6 +112,7 @@ public: private: FWadLump (FResourceLump *Lump, bool alwayscache = false); + FWadLump(int lumpnum, FResourceLump *lump); FResourceLump *Lump; @@ -185,6 +186,7 @@ public: FWadLump OpenLumpNum (int lump); FWadLump OpenLumpName (const char *name) { return OpenLumpNum (GetNumForName (name)); } FWadLump *ReopenLumpNum (int lump); // Opens a new, independent FILE + FWadLump *ReopenLumpNumNewFile (int lump); // Opens a new, independent FILE FileReader * GetFileReader(int wadnum); // Gets a FileReader object to the entire WAD From 0380ba642b8e9bd66214154cfbc3f30ee6d8dbf3 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 26 Apr 2015 20:43:01 -0500 Subject: [PATCH 86/88] Blur de hur --- src/sound/i_sound.cpp | 6 +++--- zdoom.vcproj | 32 ++++++++++++++++---------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/sound/i_sound.cpp b/src/sound/i_sound.cpp index 0a14adc29c..78c4526e86 100644 --- a/src/sound/i_sound.cpp +++ b/src/sound/i_sound.cpp @@ -639,11 +639,11 @@ SoundDecoder *SoundRenderer::CreateDecoder(FileReader *reader) TArray SoundDecoder::readAll() { TArray output; - size_t total = 0; - size_t got; + unsigned total = 0; + unsigned got; output.Resize(total+32768); - while((got=read(&output[total], output.Size()-total)) > 0) + while((got=(unsigned)read(&output[total], output.Size()-total)) > 0) { total += got; output.Resize(total*2); diff --git a/zdoom.vcproj b/zdoom.vcproj index c7e3217752..d802fc61c3 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -57,7 +57,7 @@ OmitFramePointers="true" WholeProgramOptimization="false" AdditionalIncludeDirectories="src\win32;src\sound;src;zlib;src\g_shared;src\g_doom;src\g_raven;src\g_heretic;src\g_hexen;src\g_strife;"jpeg-6b";"game-music-emu";gdtoa;bzip2;lzma\C" - PreprocessorDefinitions="NDEBUG,WIN32,_WIN32,_WINDOWS,HAVE_STRUPR,HAVE_FILELENGTH;NO_VA_COPY,BACKPATCH,HAVE_FLUIDSYNTH,DYN_FLUIDSYNTH" + PreprocessorDefinitions="NDEBUG,WIN32,_WIN32,_WINDOWS,HAVE_STRUPR,HAVE_FILELENGTH;NO_VA_COPY,BACKPATCH,HAVE_FLUIDSYNTH,DYN_FLUIDSYNTH,NO_OPENAL" StringPooling="true" ExceptionHandling="1" RuntimeLibrary="0" @@ -180,7 +180,7 @@ FavorSizeOrSpeed="1" OmitFramePointers="true" AdditionalIncludeDirectories="src\win32;src\sound;src;zlib;src\g_shared;src\g_doom;src\g_raven;src\g_heretic;src\g_hexen;src\g_strife;"jpeg-6b";game-music-emu;gdtoa;bzip2;lzma\C" - PreprocessorDefinitions="NDEBUG,WIN32,_WIN32,_WINDOWS,HAVE_STRUPR,HAVE_FILELENGTH;NO_VA_COPY" + PreprocessorDefinitions="NDEBUG,WIN32,_WIN32,_WINDOWS,HAVE_STRUPR,HAVE_FILELENGTH;NO_VA_COPY,NO_OPENAL" StringPooling="true" RuntimeLibrary="0" EnableFunctionLevelLinking="false" @@ -290,7 +290,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="src\win32;src\sound;src;zlib;src\g_shared;src\g_doom;src\g_raven;src\g_heretic;src\g_hexen;src\g_strife;"jpeg-6b";"game-music-emu";gdtoa;bzip2;lzma\C" - PreprocessorDefinitions="WIN32,_DEBUG,_WIN32,_WINDOWS,_CRTDBG_MAP_ALLOC,HAVE_STRUPR,HAVE_FILELENGTH;NO_VA_COPY,BACKPATCH,HAVE_FLUIDSYNTH,DYN_FLUIDSYNTH" + PreprocessorDefinitions="WIN32,_DEBUG,_WIN32,_WINDOWS,_CRTDBG_MAP_ALLOC,HAVE_STRUPR,HAVE_FILELENGTH;NO_VA_COPY,BACKPATCH,HAVE_FLUIDSYNTH,DYN_FLUIDSYNTH,NO_OPENAL" MinimalRebuild="true" RuntimeLibrary="1" EnableFunctionLevelLinking="true" @@ -398,7 +398,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="src\win32;src\sound;src;zlib;src\g_shared;src\g_doom;src\g_raven;src\g_heretic;src\g_hexen;src\g_strife;"jpeg-6b";game-music-emu;gdtoa;bzip2;lzma\C" - PreprocessorDefinitions="WIN32,_DEBUG,_WIN32,_WINDOWS,_CRTDBG_MAP_ALLOC,HAVE_STRUPR,HAVE_FILELENGTH;NO_VA_COPY" + PreprocessorDefinitions="WIN32,_DEBUG,_WIN32,_WINDOWS,_CRTDBG_MAP_ALLOC,HAVE_STRUPR,HAVE_FILELENGTH;NO_VA_COPY,NO_OPENAL" MinimalRebuild="true" RuntimeLibrary="1" EnableFunctionLevelLinking="true" @@ -2481,6 +2481,10 @@ + + @@ -2493,18 +2497,6 @@ RelativePath=".\src\sound\fmodsound.h" > - - - - - - @@ -2605,6 +2597,14 @@ RelativePath=".\src\sound\music_xmi_midiout.cpp" > + + + + From 68e43fe65d326f3f6a925bb8e9bc16e98dcd7c4a Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 26 Apr 2015 20:53:16 -0500 Subject: [PATCH 87/88] You never want to blindly switch between widechar and ANSI functions --- src/win32/i_system.cpp | 6 +++--- src/win32/i_system.h | 13 ++++--------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/win32/i_system.cpp b/src/win32/i_system.cpp index d25229b672..1d2bae8e1e 100644 --- a/src/win32/i_system.cpp +++ b/src/win32/i_system.cpp @@ -1601,19 +1601,19 @@ unsigned int I_MakeRNGSeed() FString I_GetLongPathName(FString shortpath) { static TOptWin32Proc - GetLongPathName("kernel32.dll", "GetLongPathNameA", NULL); + GetLongPathNameA("kernel32.dll", "GetLongPathNameA"); // Doesn't exist on NT4 if (GetLongPathName == NULL) return shortpath; - DWORD buffsize = GetLongPathName.Call(shortpath.GetChars(), NULL, 0); + DWORD buffsize = GetLongPathNameA.Call(shortpath.GetChars(), NULL, 0); if (buffsize == 0) { // nothing to change (it doesn't exist, maybe?) return shortpath; } TCHAR *buff = new TCHAR[buffsize]; - DWORD buffsize2 = GetLongPathName.Call(shortpath.GetChars(), buff, buffsize); + DWORD buffsize2 = GetLongPathNameA.Call(shortpath.GetChars(), buff, buffsize); if (buffsize2 >= buffsize) { // Failure! Just return the short path delete[] buff; diff --git a/src/win32/i_system.h b/src/win32/i_system.h index 6872ca232c..566ca19778 100644 --- a/src/win32/i_system.h +++ b/src/win32/i_system.h @@ -56,25 +56,20 @@ extern os_t OSPlatform; template class TOptWin32Proc { - static Proto GetOptionalWin32Proc(const char* module, const char* function, const char* alt) + static Proto GetOptionalWin32Proc(const char* module, const char* function) { HMODULE hmodule = GetModuleHandle(module); if (hmodule == NULL) return NULL; - Proto ret = (Proto)GetProcAddress(hmodule, function); - if(ret != NULL || alt == NULL) - return ret; - - // Lookup alternate function name (ex. ProcW -> ProcA) - return (Proto)GetProcAddress(hmodule, alt); + return (Proto)GetProcAddress(hmodule, function); } public: const Proto Call; - TOptWin32Proc(const char* module, const char* function, const char* alt=NULL) - : Call(GetOptionalWin32Proc(module, function, alt)) {} + TOptWin32Proc(const char* module, const char* function) + : Call(GetOptionalWin32Proc(module, function)) {} // Wrapper object can be tested against NULL, but not directly called. operator const void*() const { return Call; } From 020808ff40801bca57db005bc7fb804285fa8217 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Mon, 27 Apr 2015 08:57:36 +0200 Subject: [PATCH 88/88] - updated pistol pickup sprite with one from original beta graphics. --- wadsrc/static/sprites/pista0.png | Bin 377 -> 297 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/wadsrc/static/sprites/pista0.png b/wadsrc/static/sprites/pista0.png index 9e3a4a05242a9e3fb25cab0c3fcce08d02cb0797..74ff02360e95494dfa244cb90a2d5f5d570be7d2 100644 GIT binary patch delta 284 zcmey#w311&Gr-TCmrII^fq{Y7)59eQNXr5-KL<0A)DJdUJ5f=*-ZH=^#8sT1-P+n( zT3XuK*%>HjZf>rxudlAIuB@z_oSYmT9i5$>U0+|HpPwHd9`5h&@9yqiUS2LNEX+Lh z^Io6^#*!evU9Q7kczn8^WH*Ciaf4?asMvF-~FG&+iNALtKYojm5xS#859;=;zP&b<`@kK^Q?FKeJr=whU%BYVwsq0Uo%41} zFLY)1ZI_GE6wh~@64f+zZmrsUnUPmB=!RXuf>mlo6Y7#aYHMCTV%zj+wc5W+ fE?#qs^ZWQ8Z(%LUV65i`I*Y;6)z4*}Q$iB}uDNG* delta 365 zcmV-z0h0cy0{H?ViBL{Q4GJ0x0000DNk~Le0000R0000F2m=5B03uC9>X9KAe_c>a zR7C*){{R307Y_#;8ygD?3nL>VCnqO2KPN9YA0HPBOG`@!2M0GdH%CWDLqkJHPct(s z6HiZ16B83JFE39!D^ou&Q&&4HBM(0-8$U-YBP$Pke`9ZRS7&QagM)(`5m%=G0004W zQchC6iZbb;=G8(caBX&clLkXrHtv5yEKJS_z@00000 LNkvXXu0mjf0F8rV