SDL_mixer: WavPack support, using versions 4.x and 5.x of the wavpack library.

From ad1713caa2d9516d77d2d998021bf0902146d99d Mon Sep 17 00:00:00 2001
From: Ozkan Sezer <[EMAIL REDACTED]>
Date: Sat, 10 Dec 2022 07:03:10 +0300
Subject: [PATCH] WavPack support, using versions 4.x and 5.x of the wavpack
 library.

NOTES / TODO:

* DSD files loading is disabled for the moment: needs special care.

* Hybrid mode file support: For correction file (*.wvc) discovery:
  - the file must be loaded with Mix_LoadMUS, not Mix_LoadMUS_RW,
  - Mix_Init must be called with MIX_INIT_WAVPACK flag, beforehand.
  Otherwise, the file will be decoded in lossy mode, not lossless.

* Channel mapping corrections _might_ (or might not) be needed for
  wavpack files with more than 2 channels.

- Dynamic loading of windows wavpack dlls named 'wavpackdll.dll'
  (as available from official wavpack site) is not coded in cmake
  and autotools build systems.  It shall need manually specifying
  with the WAVPACK_DYNAMIC macro define, if really wanted.

Co-authored-by: Anonymous Maarten <anonymous.maarten@gmail.com>
---
 .github/workflows/main.yml      |   3 +
 .gitmodules                     |   4 +
 CMakeLists.txt                  |  47 +++
 Makefile.os2                    |  11 +-
 SDL2_mixerConfig.cmake.in       |   6 +
 build-scripts/android-prefab.sh |   4 +
 cmake/Findwavpack.cmake         |  37 ++
 configure                       | 307 ++++++++++++++--
 configure.ac                    |  65 ++++
 external/wavpack                |   1 +
 include/SDL_mixer.h             |   8 +-
 playmus.c                       |   5 +-
 src/codecs/music_wavpack.c      | 600 ++++++++++++++++++++++++++++++++
 src/codecs/music_wavpack.h      |  28 ++
 src/mixer.c                     |  11 +
 src/music.c                     |  15 +
 src/music.h                     |   1 +
 17 files changed, 1126 insertions(+), 27 deletions(-)
 create mode 100644 cmake/Findwavpack.cmake
 create mode 160000 external/wavpack
 create mode 100644 src/codecs/music_wavpack.c
 create mode 100644 src/codecs/music_wavpack.h

diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index e380dd96..d794d3e8 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -43,6 +43,7 @@ jobs:
           ${{ matrix.platform.msys-env }}-libxmp
           ${{ matrix.platform.msys-env }}-mpg123
           ${{ matrix.platform.msys-env }}-opusfile
+          ${{ matrix.platform.msys-env }}-wavpack
           ${{ matrix.platform.msys-env }}-ninja
           ${{ matrix.platform.msys-env }}-pkg-config
     - name: Setup Macos dependencies
@@ -61,6 +62,7 @@ jobs:
           libxmp \
           mpg123 \
           opusfile \
+          wavpack \
           ${NULL+}
     - name: Setup Linux dependencies
       if: runner.os == 'Linux'
@@ -77,6 +79,7 @@ jobs:
           libopusfile-dev \
           libvorbis-dev \
           libxmp-dev \
+          libwavpack-dev \
           ninja-build \
           pkg-config \
           ${NULL+}
diff --git a/.gitmodules b/.gitmodules
index 3620577e..78669f4b 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -30,3 +30,7 @@
 	path = external/libxmp
 	url = https://github.com/libsdl-org/libxmp.git
 	branch = pre4.5.1-SDL-2
+[submodule "external/wavpack"]
+	path = external/wavpack
+	url = https://github.com/libsdl-org/wavpack.git
+	branch = 5.6.0-sdl
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 002eec82..b4b7880c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -153,6 +153,9 @@ cmake_dependent_option(SDL2MIXER_VORBIS_VORBISFILE_SHARED "Dynamically load vorb
 
 option(SDL2MIXER_WAVE "Enable streaming WAVE music" ON)
 
+option(SDL2MIXER_WAVPACK "Enable WavPack music" ON)
+cmake_dependent_option(SDL2MIXER_WAVPACK_SHARED "Dynamically load WavPack library" "${SDL2MIXER_DEPS_SHARED}" SDL2MIXER_WAVPACK OFF)
+
 if(SDL2MIXER_VORBIS_TREMOR OR SDL2MIXER_VORBIS_VORBISFILE OR SDL2MIXER_FLAC_LIBFLAC OR SDL2MIXER_OPUS)
     set(SDL2MIXER_OGG TRUE)
     set(SDL2MIXER_OGG_install FALSE)
@@ -199,6 +202,7 @@ add_library(SDL2_mixer
     src/codecs/music_opus.c
     src/codecs/music_timidity.c
     src/codecs/music_wav.c
+    src/codecs/music_wavpack.c
     src/codecs/music_xmp.c
     src/effect_position.c
     src/effect_stereoreverse.c
@@ -751,6 +755,48 @@ if(SDL2MIXER_WAVE)
     target_compile_definitions(SDL2_mixer PRIVATE MUSIC_WAV)
 endif()
 
+if(SDL2MIXER_WAVPACK)
+    target_compile_definitions(SDL2_mixer PRIVATE MUSIC_WAVPACK)
+    if(SDL2MIXER_VENDORED)
+        message(STATUS "Using vendored WevPack")
+        sdl_check_project_in_subfolder(external/wavpack WavPack SDL2MIXER_VENDORED)
+        set(WAVPACK_BUILD_PROGRAMS FALSE CACHE BOOL "Don't build WavPack programs")
+        set(WAVPACK_BUILD_COOLEDIT_PLUGIN OFF CACHE BOOL "Don't build WavPack CoolEdit plugin")
+        set(WAVPACK_BUILD_WINAMP_PLUGIN OFF CACHE BOOL "Don't build WavPack WinAMP plugin")
+        set(WAVPACK_BUILD_DOCS OFF CACHE BOOL "Don't build WavPack documentation")
+        set(BUILD_SHARED_LIBS "${SDL2MIXER_WAVPACK_SHARED}")
+        add_subdirectory(external/wavpack EXCLUDE_FROM_ALL)
+        if(SDL2MIXER_WAVPACK_SHARED OR NOT SDL2MIXER_BUILD_SHARED_LIBS)
+            list(APPEND INSTALL_EXTRA_TARGETS wavpack)
+        endif()
+        if(NOT SDL2MIXER_WAVPACK_SHARED)
+            list(APPEND PC_LIBS -l$<TARGET_FILE_BASE_NAME:WavPack::WavPack>)
+        endif()
+        target_compile_definitions(SDL2_mixer PRIVATE HAVE_WAVPACK_H)
+    else()
+        message(STATUS "Using system WavPack")
+        find_package(wavpack REQUIRED)
+        if(NOT SDL2MIXER_WAVPACK_SHARED)
+            list(APPEND PC_REQUIRES wavpack)
+        endif()
+    endif()
+    if(SDL2MIXER_WAVPACK_SHARED)
+        target_include_directories(SDL2_mixer PRIVATE
+            $<TARGET_PROPERTY:WavPack::WavPack,INCLUDE_DIRECTORIES>
+            $<TARGET_PROPERTY:WavPack::WavPack,INTERFACE_INCLUDE_DIRECTORIES>
+            $<TARGET_PROPERTY:WavPack::WavPack,INTERFACE_SYSTEM_INCLUDE_DIRECTORIES>
+        )
+        target_get_dynamic_library(dynamic_wavpack WavPack::WavPack)
+        message(STATUS "Dynamic WavPack: ${dynamic_wavpack}")
+        target_compile_definitions(SDL2_mixer PRIVATE "WAVPACK_DYNAMIC=\"${dynamic_wavpack}\"")
+        if(SDL2MIXER_VENDORED)
+            add_dependencies(SDL2_mixer WavPack::WavPack)
+        endif()
+    else()
+        target_link_libraries(SDL2_mixer PRIVATE WavPack::WavPack)
+    endif()
+endif()
+
 if(SDL2MIXER_INSTALL)
     install(
         TARGETS SDL2_mixer
@@ -809,6 +855,7 @@ if(SDL2MIXER_INSTALL)
                 cmake/FindMPG123.cmake
                 cmake/FindVorbis.cmake
                 cmake/Findtremor.cmake
+                cmake/Findwavpack.cmake
             DESTINATION "${SDLMIXER_INSTALL_CMAKEDIR}"
             COMPONENT devel
         )
diff --git a/Makefile.os2 b/Makefile.os2
index 4b2e5307..8d6ba48e 100644
--- a/Makefile.os2
+++ b/Makefile.os2
@@ -35,6 +35,8 @@ USE_OPUS=yes
 USE_MPG123=yes
 # mp3 music support (using dr_mp3)
 USE_DRMP3=no
+# wavpack music support
+USE_WAVPACK=yes
 # midi music support (using timidity)
 USE_TIMIDITY=yes
 # midi music support (using fluidsynth)
@@ -53,8 +55,8 @@ SRCS = utils.c effect_position.c effects_internal.c effect_stereoreverse.c mixer
 # codec sources:
 SRCS+= load_aiff.c load_voc.c music_wav.c &
        music_ogg.c music_ogg_stb.c music_opus.c &
-       music_flac.c music_drflac.c mp3utils.c &
-       music_mpg123.c music_drmp3.c &
+       music_flac.c music_drflac.c music_wavpack.c &
+       mp3utils.c music_mpg123.c music_drmp3.c &
        music_xmp.c music_modplug.c &
        music_fluidsynth.c music_timidity.c
 # timidity sources:
@@ -118,6 +120,11 @@ LIBS+= FLAC.lib
 CFLAGS+= -DMUSIC_FLAC_DRFLAC
 !endif
 
+!ifeq USE_WAVPACK yes
+CFLAGS+= -DMUSIC_WAVPACK
+LIBS+= wavpack.lib
+!endif
+
 !ifeq USE_OPUS yes
 CFLAGS+= -DMUSIC_OPUS
 LIBS+= opusfile.lib opus.lib
diff --git a/SDL2_mixerConfig.cmake.in b/SDL2_mixerConfig.cmake.in
index d65a43ce..107e9e58 100644
--- a/SDL2_mixerConfig.cmake.in
+++ b/SDL2_mixerConfig.cmake.in
@@ -38,6 +38,8 @@ set(SDL2MIXER_VORBIS_VORBISFILE     @SDL2MIXER_VORBIS_VORBISFILE@)
 
 set(SDL2MIXER_WAVE                  @SDL2MIXER_WAVE@)
 
+set(SDL2MIXER_WAVPACK               @SDL2MIXER_WAVPACK@)
+
 set(SDL2MIXER_SDL2_REQUIRED_VERSION @SDL_REQUIRED_VERSION@)
 
 if(NOT SDL2MIXER_VENDORED)
@@ -85,6 +87,10 @@ include(CMakeFindDependencyMacro)
         find_dependency(vorbisfile)
     endif()
 
+    if(SDL2MIXER_WAVPACK AND NOT SDL2MIXER_VENDORED AND NOT TARGET WavPack::WavPack)
+        find_dependency(wavpack)
+    endif()
+
     if((NOT SDL2MIXER_VENDORED AND SDL2MIXER_MOD_MODPLUG) OR (HAIKU AND SDL2MIXER_MIDI_NATIVE))
         include(CheckLanguage)
         check_language(CXX)
diff --git a/build-scripts/android-prefab.sh b/build-scripts/android-prefab.sh
index 0a2ca3f9..c9c75422 100755
--- a/build-scripts/android-prefab.sh
+++ b/build-scripts/android-prefab.sh
@@ -81,6 +81,7 @@ build_cmake_projects() {
                 -DSDL2MIXER_MIDI_TIMIDITY=ON \
                 -DSDL2MIXER_OPUS=ON \
                 -DSDL2MIXER_VORBIS=STB \
+                -DSDL2MIXER_WAVPACK=ON \
                 -DCMAKE_TOOLCHAIN_FILE="$ANDROID_NDK_HOME/build/cmake/android.toolchain.cmake" \
                 -DSDL${sdlmixer_major}_DIR="${sdl_build_root}/build_${android_abi}/prefix/lib/cmake/SDL${sdlmixer_major}" \
                 -DANDROID_PLATFORM=${ANDROID_PLATFORM} \
@@ -336,6 +337,9 @@ cp "${sdlmixer_root}/external/opusfile/COPYING" "${aar_metainfdir_path}/LICENSE.
 create_shared_module external_libxmp libxmp ""
 tail -n15 "${sdlmixer_root}/external/libxmp/README" >"${aar_metainfdir_path}/LICENSE.libxmp.txt"
 
+create_shared_module external_libwavpack libwavpack ""
+tail -n15 "${sdlmixer_root}/external/wavpack/COPYING" >"${aar_metainfdir_path}/LICENSE.wavpack.txt"
+
 pushd "${aar_root}"
     aar_filename="SDL${sdlmixer_major}_mixer-${sdlmixer_version}.aar"
     zip -r "${aar_filename}" AndroidManifest.xml prefab META-INF
diff --git a/cmake/Findwavpack.cmake b/cmake/Findwavpack.cmake
new file mode 100644
index 00000000..7fc0672d
--- /dev/null
+++ b/cmake/Findwavpack.cmake
@@ -0,0 +1,37 @@
+include(FindPackageHandleStandardArgs)
+
+if(WIN32)
+    set(wavpack_find_names wavpack wavpackdll)
+else()
+    set(wavpack_find_names wavpack)
+endif()
+find_library(wavpack_LIBRARY
+    NAMES ${wavpack_find_names}
+)
+
+find_path(wavpack_INCLUDE_PATH
+    NAMES wavpack/wavpack.h
+)
+
+set(wavpack_COMPILE_OPTIONS "" CACHE STRING "Extra compile options of wavpack")
+
+set(wavpack_LINK_LIBRARIES "" CACHE STRING "Extra link libraries of wavpack")
+
+set(wavpack_LINK_FLAGS "" CACHE STRING "Extra link flags of wavpack")
+
+find_package_handle_standard_args(wavpack
+    REQUIRED_VARS wavpack_LIBRARY wavpack_INCLUDE_PATH
+)
+
+if (wavpack_FOUND)
+    if (NOT TARGET WavPack::WavPack)
+        add_library(WavPack::WavPack UNKNOWN IMPORTED)
+        set_target_properties(WavPack::WavPack PROPERTIES
+            IMPORTED_LOCATION "${wavpack_LIBRARY}"
+            INTERFACE_INCLUDE_DIRECTORIES "${wavpack_INCLUDE_PATH}"
+            INTERFACE_COMPILE_OPTIONS "${wavpack_COMPILE_OPTIONS}"
+            INTERFACE_LINK_LIBRARIES "${wavpack_LINK_LIBRARIES}"
+            INTERFACE_LINK_FLAGS "${wavpack_LINK_FLAGS}"
+        )
+    endif()
+endif()
diff --git a/configure b/configure
index df42fc86..0af81e43 100755
--- a/configure
+++ b/configure
@@ -800,6 +800,7 @@ ac_includes_default="\
 ac_header_c_list=
 ac_subst_vars='LTLIBOBJS
 LIBOBJS
+SDL2MIXER_WAVPACK
 SDL2MIXER_WAVE
 SDL2MIXER_VORBIS_VORBISFILE
 SDL2MIXER_VORBIS_TREMOR
@@ -831,6 +832,8 @@ VERSION_OBJECTS
 OBJECTS
 ac_aux_dir
 cmake_prefix_relpath
+WAVPACK_LIBS
+WAVPACK_CFLAGS
 OPUSFILE_LIBS
 OPUSFILE_CFLAGS
 MPG123_LIBS
@@ -994,6 +997,8 @@ enable_music_mp3_mpg123
 enable_music_mp3_mpg123_shared
 enable_music_opus
 enable_music_opus_shared
+enable_music_wavpack
+enable_music_wavpack_shared
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1027,7 +1032,9 @@ FLAC_LIBS
 MPG123_CFLAGS
 MPG123_LIBS
 OPUSFILE_CFLAGS
-OPUSFILE_LIBS'
+OPUSFILE_LIBS
+WAVPACK_CFLAGS
+WAVPACK_LIBS'
 
 
 # Initialize some variables set by options.
@@ -1706,6 +1713,9 @@ Optional Features:
   --enable-music-opus     enable Opus music [default=yes]
   --enable-music-opus-shared
                           dynamically load opusfile library [default=yes]
+  --enable-music-wavpack  enable WavPack music [default=yes]
+  --enable-music-wavpack-shared
+                          dynamically load WavPack library [default=yes]
 
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
@@ -1761,6 +1771,10 @@ Some influential environment variables:
               C compiler flags for OPUSFILE, overriding pkg-config
   OPUSFILE_LIBS
               linker flags for OPUSFILE, overriding pkg-config
+  WAVPACK_CFLAGS
+              C compiler flags for WAVPACK, overriding pkg-config
+  WAVPACK_LIBS
+              linker flags for WAVPACK, overriding pkg-config
 
 Use these variables to override the choices made by `configure' or to help
 it to find libraries and programs with nonstandard names/locations.
@@ -4936,13 +4950,13 @@ then :
 else $as_nop
   lt_cv_nm_interface="BSD nm"
   echo "int some_variable = 0;" > conftest.$ac_ext
-  (eval echo "\"\$as_me:4939: $ac_compile\"" >&5)
+  (eval echo "\"\$as_me:4953: $ac_compile\"" >&5)
   (eval "$ac_compile" 2>conftest.err)
   cat conftest.err >&5
-  (eval echo "\"\$as_me:4942: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
+  (eval echo "\"\$as_me:4956: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
   (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
   cat conftest.err >&5
-  (eval echo "\"\$as_me:4945: output\"" >&5)
+  (eval echo "\"\$as_me:4959: output\"" >&5)
   cat conftest.out >&5
   if $GREP 'External.*some_variable' conftest.out > /dev/null; then
     lt_cv_nm_interface="MS dumpbin"
@@ -6201,7 +6215,7 @@ ia64-*-hpux*)
   ;;
 *-*-irix6*)
   # Find out which ABI we are using.
-  echo '#line 6204 "configure"' > conftest.$ac_ext
+  echo '#line 6218 "configure"' > conftest.$ac_ext
   if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
   (eval $ac_compile) 2>&5
   ac_status=$?
@@ -7874,11 +7888,11 @@ else $as_nop
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:7877: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:7891: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:7881: \$? = $ac_status" >&5
+   echo "$as_me:7895: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -8224,11 +8238,11 @@ else $as_nop
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:8227: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:8241: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:8231: \$? = $ac_status" >&5
+   echo "$as_me:8245: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -8331,11 +8345,11 @@ else $as_nop
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:8334: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:8348: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:8338: \$? = $ac_status" >&5
+   echo "$as_me:8352: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -8387,11 +8401,11 @@ else $as_nop
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:8390: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:8404: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:8394: \$? = $ac_status" >&5
+   echo "$as_me:8408: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -10830,7 +10844,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 10833 "configure"
+#line 10847 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -10927,7 +10941,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 10930 "configure"
+#line 10944 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -14626,11 +14640,11 @@ else $as_nop
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:14629: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:14643: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>conftest.err)
    ac_status=$?
    cat conftest.err >&5
-   echo "$as_me:14633: \$? = $ac_status" >&5
+   echo "$as_me:14647: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s "$ac_outfile"; then
      # The compiler can only warn and ignore the option if not recognized
      # So say no if there are warnings other than the usual output.
@@ -14727,11 +14741,11 @@ else $as_nop
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:14730: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:14744: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:14734: \$? = $ac_status" >&5
+   echo "$as_me:14748: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -14780,11 +14794,11 @@ else $as_nop
    -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
    -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
    -e 's:$: $lt_compiler_flag:'`
-   (eval echo "\"\$as_me:14783: $lt_compile\"" >&5)
+   (eval echo "\"\$as_me:14797: $lt_compile\"" >&5)
    (eval "$lt_compile" 2>out/conftest.err)
    ac_status=$?
    cat out/conftest.err >&5
-   echo "$as_me:14787: \$? = $ac_status" >&5
+   echo "$as_me:14801: \$? = $ac_status" >&5
    if (exit $ac_status) && test -s out/conftest2.$ac_objext
    then
      # The compiler can only warn and ignore the option if not recognized
@@ -19059,6 +19073,256 @@ printf "%s\n" "$as_me: WARNING: Opus support disabled" >&2;}
     fi
 fi
 
+SDL2MIXER_WAVPACK=0
+# Check whether --enable-music-wavpack was given.
+if test ${enable_music_wavpack+y}
+then :
+  enableval=$enable_music_wavpack;
+else $as_nop
+  enable_music_wavpack=yes
+fi
+
+# Check whether --enable-music-wavpack-shared was given.
+if test ${enable_music_wavpack_shared+y}
+then :
+  enableval=$enable_music_wavpack_shared;
+else $as_nop
+  enable_music_wavpack_shared=yes
+fi
+
+if test x$enable_music_wavpack = xyes; then
+    LIBS_SAVED="$LIBS"
+
+pkg_failed=no
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wavpack >= 4.0" >&5
+printf %s "checking for wavpack >= 4.0... " >&6; }
+
+if test -n "$WAVPACK_CFLAGS"; then
+    pkg_cv_WAVPACK_CFLAGS="$WAVPACK_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"wavpack >= 4.0\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "wavpack >= 4.0") 2>&5
+  ac_status=$?
+  printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_WAVPACK_CFLAGS=`$PKG_CONFIG --cflags "wavpack >= 4.0" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+if test -n "$WAVPACK_LIBS"; then
+    pkg_cv_WAVPACK_LIBS="$WAVPACK_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"wavpack >= 4.0\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "wavpack >= 4.0") 2>&5
+  ac_status=$?
+  printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_WAVPACK_LIBS=`$PKG_CONFIG --libs "wavpack >= 4.0" 2>/dev/null`
+		      test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
+fi
+ else
+    pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+        { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
+fi
+        if test $_pkg_short_errors_supported = yes; then
+	        WAVPACK_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "wavpack >= 4.0" 2>&1`
+        else
+	        WAVPACK_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "wavpack >= 4.0" 2>&1`
+        fi
+	# Put the nasty error message in config.log where it belongs
+	echo "$WAVPACK_PKG_ERRORS" >&5
+
+	            ac_fn_c_check_header_compile "$LINENO" "wavpack.h" "ac_cv_header_wavpack_h" "$ac_includes_default"
+if test "x$ac_cv_header_wavpack_h" = xyes
+then :
+  have_wavpack_hdr=yes;have_wavpack_hdr2=yes
+fi
+
+            ac_fn_c_check_header_compile "$LINENO" "wavpack/wavpack.h" "ac_cv_header_wavpack_wavpack_h" "$ac_includes_default"
+if test "x$ac_cv_header_wavpack_wavpack_h" = xyes
+then :
+  have_wavpack_hdr=yes
+fi
+
+            { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for WavpackOpenFileInputEx in -lwavpack" >&5
+printf %s "checking for WavpackOpenFileInputEx in -lwavpack... " >&6; }
+if test ${ac_cv_lib_wavpack_WavpackOpenFileInputEx+y}
+then :
+  printf %s "(cached) " >&6
+else $as_nop
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lwavpack -lm $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+char WavpackOpenFileInputEx ();
+int
+main (void)
+{
+return WavpackOpenFileInputEx ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+  ac_cv_lib_wavpack_WavpackOpenFileInputEx=yes
+else $as_nop
+  ac_cv_lib_wavpack_WavpackOpenFileInputEx=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_wavpack_WavpackOpenFileInputEx" >&5
+printf "%s\n" "$ac_cv_lib_wavpack_WavpackOpenFileInputEx" >&6; }
+if test "x$ac_cv_lib_wavpack_WavpackOpenFileInputEx" = xyes
+then :
+  have_wavpack_lib=yes;WAVPACK_LIBS="-lwavpack"
+fi
+
+
+elif test $pkg_failed = untried; then
+        { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+	            ac_fn_c_check_header_compile "$LINENO" "wavpack.h" "ac_cv_header_wavpack_h" "$ac_includes_default"
+if test "x$ac_cv_header_wavpack_h" = xyes
+then :
+  have_wavpack_hdr=yes;have_wavpack_hdr2=yes
+fi
+
+            ac_fn_c_check_header_compile "$LINENO" "wavpack/wavpack.h" "ac_cv_header_wavpack_wavpack_h" "$ac_includes_default"
+if test "x$ac_cv_header_wavpack_wavpack_h" = xyes
+then :
+  have_wavpack_hdr=yes
+fi
+
+            { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for WavpackOpenFileInputEx in -lwavpack" >&5
+printf %s "checking for WavpackOpenFileInputEx in -lwavpack... " >&6; }
+if test ${ac_cv_lib_wavpack_WavpackOpenFileInputEx+y}
+then :
+  printf %s "(cached) " >&6
+else $as_nop
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lwavpack -lm $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+char WavpackOpenFileInputEx ();
+int
+main (void)
+{
+return WavpackOpenFileInputEx ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"
+then :
+  ac_cv_lib_wavpack_WavpackOpenFileInputEx=yes
+else $as_nop
+  ac_cv_lib_wavpack_WavpackOpenFileInputEx=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_wavpack_WavpackOpenFileInputEx" >&5
+printf "%s\n" "$ac_cv_lib_wavpack_WavpackOpenFileInputEx" >&6; }
+if test "x$ac_cv_lib_wavpack_WavpackOpenFileInputEx" = xyes
+then :
+  have_wavpack_lib=yes;WAVPACK_LIBS="-lwavpack"
+fi
+
+
+else
+	WAVPACK_CFLAGS=$pkg_cv_WAVPACK_CFLAGS
+	WAVPACK_LIBS=$pkg_cv_WAVPACK_LIBS
+        { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+	            have_wavpack_hdr=yes
+            have_wavpack_lib=yes
+            have_wavpack_pc=yes
+
+fi
+    if test x$have_wavpack_pc = xyes; then
+        CFLAGS_SAVED="$CFLAGS"
+        CFLAGS="$CFLAGS $WAVPACK_CFLAGS"
+        ac_fn_c_check_header_compile "$LINENO" "wavpack.h" "ac_cv_header_wavpack_h" "$ac_includes_default"
+if test "x$ac_cv_header_wavpack_h" = xyes
+then :
+  have_wavpack_hdr2=yes
+fi
+
+        CFLAGS="$CFLAGS_SAVED"
+    fi
+    LIBS="$LIBS_SAVED"
+
+    if test x$have_wavpack_hdr = xyes -a x$have_wavpack_lib = xyes; then
+        have_wavpack=yes
+        case "$host" in
+            *-*-darwin*)
+                wavpack_lib=`find_lib libwavpack.dylib`
+                ;;
+            *-*-cygwin* | *-*-mingw*)
+                wavpack_lib=`find_lib "libwavpack*.dll"`
+                ;;
+            *)
+                wavpack_lib=`find_lib "libwavpack[0-9]*.so.*"`
+                if test x$wavpack_lib = x; then
+                    wavpack_lib=`find_lib "libwavpack.so.*"`
+                fi
+                ;;
+        esac
+        EXTRA_CFLAGS="$EXTRA_CFLAGS -DMUSIC_WAVPACK $WAVPACK_CFLAGS"
+        if test x$have_wavpack_hdr2 = xyes; then
+            EXTRA_CFLAGS="$EXTRA_CFLAGS -DHAVE_WAVPACK_H"
+        fi
+        if test x$enable_music_wavpack_shared = xyes && test x$wavpack_lib != x; then
+            echo "-- dynamic wavpack -> $wavpack_lib"
+            EXTRA_CFLAGS="$EXTRA_CFLAGS -DWAVPACK_DYNAMIC=\\\"$wavpack_lib\\\""
+        else
+            MIXER_LIBS="$MIXER_LIBS $WAVPACK_LIBS"
+            if test x$have_wavpack_pc = xyes; then
+                PC_REQUIRES="$PC_REQUIRES wavpack"
+            else
+                PC_LIBS="$PC_LIBS $WAVPACK_LIBS"
+            fi
+        fi
+        SDL2MIXER_WAVPACK=1
+    else
+        { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: *** Unable to find WavPack library (http://www.wavpack.com)" >&5
+printf "%s\n" "$as_me: WARNING: *** Unable to find WavPack library (http://www.wavpack.com)" >&2;}
+        { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: WavPack support disabled" >&5
+printf "%s\n" "$as_me: WARNING: WavPack support disabled" >&2;}
+    fi
+fi
+
 CheckNoUndef
 
 MIXER_LIBS="$MIXER_LIBS $LIBM"
@@ -19234,6 +19498,7 @@ done
 
 
 
+
 
 
 ac_config_files="$ac_config_files Makefile SDL2_mixer.spec SDL2_mixer.pc sdl2_mixer-config.cmake sdl2_mixer-config-version.cmake"
diff --git a/configure.ac b/configure.ac
index 742a5bec..64d68e39 100644
--- a/configure.ac
+++ b/configure.ac
@@ -905,6 +905,70 @@ if test x$enable_music_opus = xyes; then
     fi
 fi
 
+SDL2MIXER_WAVPACK=0
+AC_ARG_ENABLE([music-wavpack],
+[AS_HELP_STRING([--enable-music-wavpack], [enable WavPack music [default=yes]])],
+              [], [enable_music_wavpack=yes])
+AC_ARG_ENABLE([music-wavpack-shared],
+[AS_HELP_STRING([--enable-music-wavpack-shared], [dynamically load WavPack library [default=yes]])],
+              [], [enable_music_wavpack_shared=yes])
+if test x$enable_music_wavpack = xyes; then
+    LIBS_SAVED="$LIBS"
+    PKG_CHECK_MODULES([WAVPACK], [wavpack >= 4.0], [dnl
+            have_wavpack_hdr=yes
+            have_wavpack_lib=yes
+            have_wavpack_pc=yes
+        ], [dnl
+            AC_CHECK_HEADER([wavpack.h], [have_wavpack_hdr=yes;have_wavpack_hdr2=yes])
+            AC_CHECK_HEADER([wavpack/wavpack.h], [have_wavpack_hdr=yes])
+            AC_CHECK_LIB([wavpack], [WavpackOpenFileInputEx], [have_wavpack_lib=yes;WAVPACK_LIBS="-lwavpack"], [], [-lm])
+        ])
+    if test x$have_wavpack_pc = xyes; then
+        CFLAGS_SAVED="$CFLAGS"
+        CFLAGS="$CFLAGS $WAVPACK_CFLAGS"
+        AC_CHECK_HEADER([wavpack.h], [have_wavpack_hdr2=yes])
+        CFLAGS="$CFLAGS_SAVED"
+    fi
+    LIBS="$LIBS_SAVED"
+
+    if test x$have_wavpack_hdr = xyes -a x$have_wavpack_lib = xyes; then
+        have_wavpack=yes
+        case "$host" in
+            *-*-darwin*)
+                wavpack_lib=[`find_lib libwavpack.dylib`]
+                ;;
+            *-*-cygwin* | *-*-mingw*)
+                wavpack_lib=[`find_lib "libwavpack*.dll"`]
+                ;;
+            *)
+                wavpack_lib=[`find_lib "libwavpack[0-9]*.so.*"`]
+                if test x$wavpack_lib = x; then
+                    wavpack_lib=[`find_lib "libwavpack.so.*"`]
+                fi
+                ;;
+        esac
+        EXTRA_CFLAGS="$EXTRA_CFLAGS -DMUSIC_WAVPACK $WAVPACK_CFLAGS"
+        if test x$have_wavpack_hdr2 = xyes; then
+            EXTRA_CFLAGS="$EXTRA_CFLAGS -DHAVE_WAVPACK_H"
+        fi
+        if test x$enable_music_wavpack_shared = xyes && test x$wavpack_lib != x; then
+            echo "-- dynamic wavpack -> $wavpack_lib"
+            EXTRA_CFLAGS="$EXTRA_CFLAGS -DWAVPACK_DYNAMIC=\\\"$wavpack_lib\\\""
+        else
+            MIXER_LIBS="$MIXER_LIBS $WAVPACK_LIBS"
+            if test x$have_wavpack_pc = xyes; then
+                PC_REQUIRES="$PC_REQUIRES wavpack"
+            else
+                PC_LIBS="$PC_LIBS $WAVPACK_LIBS"
+            fi
+        fi
+        SDL2MIXER_WAVPACK=1
+    else
+        AC_MSG_WARN([*** Unable to find WavPack library (http://www.wavpack.com)])
+        AC_MSG_WARN([WavPack support disabled])
+    fi
+fi
+
 dnl check for LD --no-undefined option
 CheckNoUndef
 
@@ -993,6 +1057,7 @@ AC_SUBST(SDL2MIXER_VORBIS_STB)
 AC_SUBST(SDL2MIXER_VORBIS_TREMOR)
 AC_SUBST(SDL2MIXER_VORBIS_VORBISFILE)
 AC_SUBST(SDL2MIXER_WAVE)
+AC_SUBST(SDL2MIXER_WAVPACK)
 
 AC_CONFIG_FILES([
 Makefile
diff --git a/external/wavpack b/external/wavpack
new file mode 160000
index 00000000..7c4391c0
--- /dev/null
+++ b/external/wavpack
@@ -0,0 +1 @@
+Subproject commit 7c4391c076f68a8d4e07383dcf52aa0806da0388
diff --git a/include/SDL_mixer.h b/include/SDL_mixer.h
index b0f937dc..4231e2ae 100644
--- a/include/SDL_mixer.h
+++ b/include/SDL_mixer.h
@@ -112,7 +112,8 @@ typedef enum
     MIX_INIT_MP3    = 0x00000008,
     MIX_INIT_OGG    = 0x00000010,
     MIX_INIT_MID    = 0x00000020,
-    MIX_INIT_OPUS   = 0x00000040
+    MIX_INIT_OPUS   = 0x00000040,
+    MIX_INIT_WAVPACK= 0x00000080
 } MIX_InitFlags;
 
 /**
@@ -137,6 +138,7 @@ typedef enum
  * - `MIX_INIT_OGG`
  * - `MIX_INIT_MID`
  * - `MIX_INIT_OPUS`
+ * - `MIX_INIT_WAVPACK`
  *
  * 

(Patch may be truncated, please check the link at the top of this post.)