shithub: pt2-clone

Download patch

ref: fade190b505076ed4e2ff6112228d8196b8c4ee8
parent: 1f54ee34fac0fc161f68e7e159a40773a86e45c3
author: Olav Sørensen <olav.sorensen@live.no>
date: Fri May 12 18:52:07 EDT 2023

Pushed v1.58 code (mega-commit again, sorry)

- Added support for loading FLAC samples
- The IFF sample saver was writing somewhat broken files for non-looped samples
- The "UPSAMP" button in Edit Op. was showing the wrong status text
- Small code refactor for how the song is timed/ticked. Longer song-to-WAV renders may have a filesize change of a few bytes, but this is actually more correct.
- Increased number of precision bits for song BPM, playback time counter and audio->video syncing. This is a minor change and does very little in practice as the previous precision was already quite good.
- Audio/video sync timestamps are reset every half an hour to prevent possible sync drifting after several hours of playing a song without a single song stop (resets timestamp) in-between
- The HPC timers are reset every half an hour instead of every hour. The video (if no vsync) and the scopes use these timers. This hopefully fixes potential timing drifting issues that were still lingering.
- Code refactoring for module/sample loaders
- Windows/macOS: Updated SDL to v2.26.5

--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,11 +2,15 @@
 
 project(pt2-clone)
 
+option(EXTERNAL_LIBFLAC "use external(system) flac library" OFF)
+
 find_package(SDL2 REQUIRED)
 set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${pt2-clone_SOURCE_DIR}/release/other/")
 
 file(GLOB pt2-clone_SRC
     "${pt2-clone_SOURCE_DIR}/src/*.c"
+    "${pt2-clone_SOURCE_DIR}/src/modloaders/*.c"
+    "${pt2-clone_SOURCE_DIR}/src/smploaders/*.c"
     "${pt2-clone_SOURCE_DIR}/src/gfx/*.c"
 )
 
@@ -22,6 +26,22 @@
 
 target_link_libraries(pt2-clone
     PRIVATE m ${SDL2_LIBRARIES})
+    
+target_compile_definitions(pt2-clone
+    PRIVATE HAS_LIBFLAC)
+    
+if(EXTERNAL_LIBFLAC)
+    find_package(PkgConfig REQUIRED)
+    pkg_check_modules(FLAC REQUIRED IMPORTED_TARGET flac)
+    target_compile_definitions(pt2-clone
+        PRIVATE EXTERNAL_LIBFLAC)
+    target_link_libraries(pt2-clone
+        PRIVATE PkgConfig::FLAC)
+else()
+    file(GLOB flac_SRCS
+        "${pt2-clone_SOURCE_DIR}/src/libflac/*.c")
+    target_sources(pt2-clone PRIVATE ${flac_SRCS})
+endif()
 
 install(TARGETS pt2-clone
     RUNTIME DESTINATION bin)
--- a/HOW-TO-COMPILE.txt
+++ b/HOW-TO-COMPILE.txt
@@ -32,8 +32,7 @@
 
 == COMPILING ON MAC OS X 10.15 OR NEWER ==
  1. Download and install the "Command Line Tools" XCode package (google it)
- 2. Download the SDL 2.0.14 framework here:
-    https://www.libsdl.org/release/SDL2-2.0.14.dmg
+ 2. Download the SDL 2 framework at https://www.libsdl.org
  3. Inside the package, copy SDL2.framework to /Library/Frameworks/
  4. Compile the PT2 clone:      (folder: "pt2-clone")
     chmod +x make-macos.sh      (only needed once)
--- /dev/null
+++ b/make-linux-noflac.sh
@@ -1,0 +1,9 @@
+#!/bin/bash
+
+rm release/other/pt2-clone &> /dev/null
+
+echo Compiling, please wait...
+gcc -DNDEBUG src/gfx/*.c src/modloaders/*.c src/smploaders/*.c src/*.c -lSDL2 -lm -Wshadow -Winit-self -Wall -Wno-missing-field-initializers -Wno-unused-result -Wno-strict-aliasing -Wextra -Wunused -Wunreachable-code -Wswitch-default -Wno-stringop-overflow -march=native -mtune=native -O3 -o release/other/pt2-clone
+rm src/gfx/*.o src/*.o &> /dev/null
+
+echo Done. The executable can be found in \'release/other\' if everything went well.
--- a/make-linux.sh
+++ b/make-linux.sh
@@ -3,7 +3,7 @@
 rm release/other/pt2-clone &> /dev/null
 
 echo Compiling, please wait...
-gcc -DNDEBUG src/gfx/*.c src/*.c -lSDL2 -lm -Wall -Wno-unused-result -Wc++-compat -Wshadow -Winit-self -Wextra -Wunused -Wunreachable-code -Wredundant-decls -Wswitch-default -march=native -mtune=native -O3 -o release/other/pt2-clone
+gcc -DNDEBUG -DHAS_LIBFLAC src/gfx/*.c src/modloaders/*.c src/libflac/*.c src/smploaders/*.c src/*.c -lSDL2 -lm -Wshadow -Winit-self -Wall -Wno-missing-field-initializers -Wno-unused-result -Wno-strict-aliasing -Wextra -Wunused -Wunreachable-code -Wswitch-default -Wno-stringop-overflow -march=native -mtune=native -O3 -o release/other/pt2-clone
 rm src/gfx/*.o src/*.o &> /dev/null
 
 echo Done. The executable can be found in \'release/other\' if everything went well.
--- a/make-macos.sh
+++ b/make-macos.sh
@@ -36,12 +36,12 @@
 #
 function compile() {
     rm $1 &> /dev/null
-    clang $VERBOSE $CFLAGS -F /Library/Frameworks -g0 -DNDEBUG src/gfx/*.c src/*.c -Wall -Winit-self -Wextra -Wunused -Wredundant-decls -Wswitch-default  $LDFLAGS -L /Library/Frameworks -framework SDL2 -framework Cocoa -lm -o $1
+    clang $VERBOSE $CFLAGS -F /Library/Frameworks -g0 -DNDEBUG -DHAS_LIBFLAC src/gfx/*.c src/modloaders/*.c src/libflac/*.c src/smploaders/*.c src/*.c -Wall -Winit-self -Wextra -Wunused -Wredundant-decls -Wswitch-default  $LDFLAGS -L /Library/Frameworks -framework SDL2 -framework Cocoa -lm -o $1
     return $?
 }
 
 echo Compiling x86_64 binary, please wait patiently...
-CFLAGS="-target x86_64-apple-macos10.9 -mmacosx-version-min=10.9 -arch x86_64 -mmmx -mfpmath=sse -msse2 -O3"
+CFLAGS="-target x86_64-apple-macos10.11 -mmacosx-version-min=10.11 -arch x86_64 -mmmx -mfpmath=sse -msse2 -O3"
 LDFLAGS=
 export SDKROOT=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk
 compile $TARGET_X86_64
--- a/release/LICENSES.txt
+++ b/release/LICENSES.txt
@@ -2,7 +2,7 @@
 ---------------------- Source code (BSD 3-clause license) ----------------------
 --------------------------------------------------------------------------------
 
-Copyright (c) 2010-2021, Olav Sørensen
+Copyright (c) 2010-2023, Olav Sørensen
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
--- a/release/help.txt
+++ b/release/help.txt
@@ -89,15 +89,17 @@
    If you press ctrl+z, the current sample's data+attributes will be restored.
    Now you don't need to reload a sample when you make a change you regret!
    
- * WAV sample loader.
+ * WAV sample loader
    Supports: 8-bit, 16-bit, 24-bit, 32-bit and 32-bit/64-bit floating point
-   The WAV samples are mixed to mono and quantized to 8-bit.
-   It also attempts to load the "SMPL" chunk to get loop points and
-   volume from sampler WAVs and Open ModPlug Tracker and the like.
+   Stereo WAV samples are mixed to mono.
    
- * AIFF sample loader.
+ * AIFF sample loader
    Supports: 8-bit, 16-bit, 24-bit and 32-bit
-   The AIFF samples are mixed to mono and quantized to 8-bit.
+   Stereo AIFF samples are mixed to mono.
+   
+ * FLAC sample loader
+   Supports: 8-bit, 16-bit and 24-bit
+   Stereo FLAC samples are mixed to mono.
    
  * PAGE UP/DOWN and HOME/END works in POS-ED, DISK OP. and the pattern editor
    (and HOME/END works while editing strings)
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_assert.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_assert.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -125,12 +125,10 @@
     const struct SDL_AssertData *next;
 } SDL_AssertData;
 
-#if (SDL_ASSERT_LEVEL > 0)
-
 /* Never call this directly. Use the SDL_assert* macros. */
 extern DECLSPEC SDL_AssertState SDLCALL SDL_ReportAssertion(SDL_AssertData *,
-                                                             const char *,
-                                                             const char *, int)
+                                                            const char *,
+                                                            const char *, int)
 #if defined(__clang__)
 #if __has_feature(attribute_analyzer_noreturn)
 /* this tells Clang's static analysis that we're a custom assert function,
@@ -151,9 +149,7 @@
 #define SDL_enabled_assert(condition) \
     do { \
         while ( !(condition) ) { \
-            static struct SDL_AssertData sdl_assert_data = { \
-                0, 0, #condition, 0, 0, 0, 0 \
-            }; \
+            static struct SDL_AssertData sdl_assert_data = { 0, 0, #condition, 0, 0, 0, 0 }; \
             const SDL_AssertState sdl_assert_state = SDL_ReportAssertion(&sdl_assert_data, SDL_FUNCTION, SDL_FILE, SDL_LINE); \
             if (sdl_assert_state == SDL_ASSERTION_RETRY) { \
                 continue; /* go again. */ \
@@ -163,8 +159,6 @@
             break; /* not retrying. */ \
         } \
     } while (SDL_NULL_WHILE_LOOP_CONDITION)
-
-#endif  /* enabled assertions support code */
 
 /* Enable various levels of assertions. */
 #if SDL_ASSERT_LEVEL == 0   /* assertions disabled */
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_atomic.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_atomic.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_audio.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_audio.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_bits.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_bits.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_blendmode.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_blendmode.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_clipboard.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_clipboard.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_config.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_config.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_config_macosx.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_config_macosx.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_copying.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_copying.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_cpuinfo.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_cpuinfo.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_endian.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_endian.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_error.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_error.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_events.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_events.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_filesystem.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_filesystem.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_gamecontroller.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_gamecontroller.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_gesture.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_gesture.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_guid.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_guid.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_haptic.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_haptic.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_hidapi.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_hidapi.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_hints.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_hints.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_joystick.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_joystick.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_keyboard.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_keyboard.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_keycode.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_keycode.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_loadso.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_loadso.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_locale.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_locale.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_log.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_log.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_main.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_main.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_messagebox.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_messagebox.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_metal.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_metal.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_misc.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_misc.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_mouse.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_mouse.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_mutex.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_mutex.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_name.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_name.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_opengl.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_opengl.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_opengles.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_opengles.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_opengles2.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_opengles2.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_pixels.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_pixels.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_platform.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_platform.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_power.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_power.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_quit.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_quit.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_rect.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_rect.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_render.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_render.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_revision.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_revision.h
@@ -1,7 +1,7 @@
 /* Generated by updaterev.sh, do not edit */
 #ifdef SDL_VENDOR_INFO
-#define SDL_REVISION "SDL-release-2.26.2-0-gf070c83a6 (" SDL_VENDOR_INFO ")"
+#define SDL_REVISION "SDL-release-2.26.5-0-gac13ca9ab (" SDL_VENDOR_INFO ")"
 #else
-#define SDL_REVISION "SDL-release-2.26.2-0-gf070c83a6"
+#define SDL_REVISION "SDL-release-2.26.5-0-gac13ca9ab"
 #endif
 #define SDL_REVISION_NUMBER 0
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_rwops.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_rwops.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_scancode.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_scancode.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_sensor.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_sensor.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_shape.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_shape.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_stdinc.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_stdinc.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_surface.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_surface.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_system.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_system.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_syswm.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_syswm.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_thread.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_thread.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_timer.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_timer.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_touch.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_touch.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_types.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_types.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_version.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_version.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -59,7 +59,7 @@
 */
 #define SDL_MAJOR_VERSION   2
 #define SDL_MINOR_VERSION   26
-#define SDL_PATCHLEVEL      2
+#define SDL_PATCHLEVEL      5
 
 /**
  * Macro to determine SDL version program was compiled against.
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_video.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/SDL_video.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/begin_code.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/begin_code.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/close_code.h
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Headers/close_code.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Resources/Info.plist
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Resources/Info.plist
@@ -3,7 +3,7 @@
 <plist version="1.0">
 <dict>
 	<key>BuildMachineOSBuild</key>
-	<string>22A400</string>
+	<string>22D68</string>
 	<key>CFBundleDevelopmentRegion</key>
 	<string>English</string>
 	<key>CFBundleExecutable</key>
@@ -19,7 +19,7 @@
 	<key>CFBundlePackageType</key>
 	<string>FMWK</string>
 	<key>CFBundleShortVersionString</key>
-	<string>2.26.2</string>
+	<string>2.26.5</string>
 	<key>CFBundleSignature</key>
 	<string>SDLX</string>
 	<key>CFBundleSupportedPlatforms</key>
@@ -27,24 +27,24 @@
 		<string>MacOSX</string>
 	</array>
 	<key>CFBundleVersion</key>
-	<string>2.26.2</string>
+	<string>2.26.5</string>
 	<key>DTCompiler</key>
 	<string>com.apple.compilers.llvm.clang.1_0</string>
 	<key>DTPlatformBuild</key>
-	<string>14B47b</string>
+	<string></string>
 	<key>DTPlatformName</key>
 	<string>macosx</string>
 	<key>DTPlatformVersion</key>
-	<string>13.0</string>
+	<string>13.3</string>
 	<key>DTSDKBuild</key>
-	<string>22A372</string>
+	<string>22E245</string>
 	<key>DTSDKName</key>
-	<string>macosx13.0</string>
+	<string>macosx13.3</string>
 	<key>DTXcode</key>
-	<string>1410</string>
+	<string>1430</string>
 	<key>DTXcodeBuild</key>
-	<string>14B47b</string>
+	<string>14E222b</string>
 	<key>LSMinimumSystemVersion</key>
-	<string>10.9</string>
+	<string>10.11</string>
 </dict>
 </plist>
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Resources/License.txt
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Resources/License.txt
@@ -1,6 +1,6 @@
 
 Simple DirectMedia Layer
-Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
   
 This software is provided 'as-is', without any express or implied
 warranty.  In no event will the authors be held liable for any damages
binary files a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Resources/default.metallib b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/Resources/default.metallib differ
binary files a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/SDL2 b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/SDL2 differ
--- a/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/_CodeSignature/CodeResources
+++ b/release/macos/pt2-clone-macos.app/Contents/Frameworks/SDL2.framework/Versions/A/_CodeSignature/CodeResources
@@ -14,11 +14,11 @@
 		</data>
 		<key>Resources/Info.plist</key>
 		<data>
-		0srrtdsGkAsDsNfVa8G4uQTmX18=
+		ECcyTBfZPucOFnTMf7BSonyduBg=
 		</data>
 		<key>Resources/License.txt</key>
 		<data>
-		VoVWJNSXNFkj10nxdQKhgCnXJjE=
+		fCUUBjJ4JuUAC8MRSCszNcY21v8=
 		</data>
 		<key>Resources/ReadMe.txt</key>
 		<data>
@@ -26,7 +26,7 @@
 		</data>
 		<key>Resources/default.metallib</key>
 		<data>
-		IJbnxEB8M5Bm2m634ZoP3yyZ7hc=
+		07w7GQmm31+NEK8ne4mSo7m70Do=
 		</data>
 	</dict>
 	<key>files2</key>
@@ -35,11 +35,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			AglD0HQ7wpywki02o+5BHIzEnL0=
+			hzPz83uejvKAqzL0Xoi6aO8h8jw=
 			</data>
 			<key>hash2</key>
 			<data>
-			rEJ7JEx5CQypooSpXSwzBg0rnDQ0Y7Ctkcgr6WARMso=
+			9u/or17IhYmY6rFVU14yva0lEIgG9DmS4LbiwXBLBL8=
 			</data>
 		</dict>
 		<key>Headers/SDL_assert.h</key>
@@ -46,11 +46,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			B9H6Q9JU0i9oid03T1/Ca86gZUU=
+			bOToHmbN+xx6t5JDrzQswLbnEZM=
 			</data>
 			<key>hash2</key>
 			<data>
-			uqj30tfXL8YY+MVK9XMh/XKClSKrCsikaNhPIt2HSYM=
+			2yPzeIi/yrrj/kXEyXW4yRLtxPe1iXPO7joeTUBcZaM=
 			</data>
 		</dict>
 		<key>Headers/SDL_atomic.h</key>
@@ -57,11 +57,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			S7vGRTzBHVXKyXwYhhvUpfME4bs=
+			TaFJjJYsOXON8iaLEX5xgfJH0FI=
 			</data>
 			<key>hash2</key>
 			<data>
-			yyqMgvtuNLSklwq2qM62TTuiLks55E6BNKOB08e6EzQ=
+			nmWpPus/eISidEuuFqvVp/7XY07q4kHIRaT63X/reVA=
 			</data>
 		</dict>
 		<key>Headers/SDL_audio.h</key>
@@ -68,11 +68,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			y0WyGUpd2J2rVMxjUi3zQZoj9ok=
+			16xbool8mbuYWNC2lmIqMxUmlZQ=
 			</data>
 			<key>hash2</key>
 			<data>
-			UYQL32SIkpxyWOGt7YsCsrwbchOvuBsgcFhTnyFcC/I=
+			fqqrBPvDux0Z4lIvqQKdhOVSZRLcTBx0Qva8cbLp418=
 			</data>
 		</dict>
 		<key>Headers/SDL_bits.h</key>
@@ -79,11 +79,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			6MCXzkSXZ4Ba7/9ksdUPcPxqpLc=
+			Y7zU8XCX6cvmN/FK9COruPP8VGs=
 			</data>
 			<key>hash2</key>
 			<data>
-			moRKyE7GpCyBzoyt2Eib7jqJ/ZMO1vTCWSjtHxP3Few=
+			5bLOm9HAk5AScYemc5V1usN7NqP685ZYN5MOBjzC2IE=
 			</data>
 		</dict>
 		<key>Headers/SDL_blendmode.h</key>
@@ -90,11 +90,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			R0DC+lE1tBOALESAuGbbBcDXF24=
+			zzSdvjZ9hKJxyC3VzOOwKmq61/U=
 			</data>
 			<key>hash2</key>
 			<data>
-			RenGdg0rma2j6y9cRvHsTayslInVYfxWvAS3fGUv+Aw=
+			BD+r9teOyEpTHM6NwvtQPhrazAj5e2wzwqQ/EqWKgVg=
 			</data>
 		</dict>
 		<key>Headers/SDL_clipboard.h</key>
@@ -101,11 +101,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			ceGtYOxEwS1RedUOwdih3hKfH+A=
+			pFjnEWnFn2vCXZrSDQ6m8N6h0MM=
 			</data>
 			<key>hash2</key>
 			<data>
-			a8VSyIYIzoTtxU9DbVNg5BVixZOBXKcUC5fEd1tx6CI=
+			t9Fr9UxC9zwgfkCY5P5DW9k3TndMFRn+tU/heffUOQk=
 			</data>
 		</dict>
 		<key>Headers/SDL_config.h</key>
@@ -112,11 +112,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			6XTkjBo2D+0gCdBLcSva+glQ00M=
+			B13VD2wcb7zADcKXB+B/kBYhpHw=
 			</data>
 			<key>hash2</key>
 			<data>
-			VIvoehwuIKTef6WBop2Nd0NS05vrTj3rIQMzU50wCuo=
+			LmXzL1O6PasyaBOUhPezJnqtqwCV9rqOyiJNEvGKgHo=
 			</data>
 		</dict>
 		<key>Headers/SDL_config_macosx.h</key>
@@ -123,11 +123,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			/stAi8zarCwB82aVod/XjUMQ+iA=
+			/CrGe7lmePlmR7DD9sqN4LHqM/0=
 			</data>
 			<key>hash2</key>
 			<data>
-			m9snGVWdu+ENVdM/pHMcW3pAamzZLd6luJ4XG9xnysM=
+			EpnSzka/wAuxi4wcgIktwQnuYWsMAATYMt6yDmo4zOg=
 			</data>
 		</dict>
 		<key>Headers/SDL_copying.h</key>
@@ -134,11 +134,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			topzn4TKpy+ywX5uHtzXPOb/EWk=
+			OzEuv+IaGVfj3A2BEoXc87vV+Wk=
 			</data>
 			<key>hash2</key>
 			<data>
-			nXmV15qsx3hLFUWnzkeUClLg3jiNhHqPhtRo9asqkPI=
+			5zsYMLhj8aKXm4gWJoGHC55ipiUi1OIxXdOtUIHQQw4=
 			</data>
 		</dict>
 		<key>Headers/SDL_cpuinfo.h</key>
@@ -145,11 +145,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			nVyTcSRv2DDGuZGjPqBHG5K4zL4=
+			4/UkY/aNgAY5RsZ61XSnwtCXW9I=
 			</data>
 			<key>hash2</key>
 			<data>
-			AXd36RR4RyCehVoWL5YrmtyPjhYxnzEe0OROTFQNheE=
+			pWPZkQcmPyAzgZNKcmiYutw8VFjBcHOinO+VVKIBeN0=
 			</data>
 		</dict>
 		<key>Headers/SDL_endian.h</key>
@@ -156,11 +156,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			3SKom++C+iyjKSaAzELahcbZb9w=
+			MHpy1KvnqOf64f2781BUtUz0DEI=
 			</data>
 			<key>hash2</key>
 			<data>
-			itvFDymfM/B7KSiRLqeXPtmP1Pae7Hr6PKV536yb19k=
+			AmEG80oborsu7cRbeBBS2zyDKvyxTT2kh0M7rYrm2HI=
 			</data>
 		</dict>
 		<key>Headers/SDL_error.h</key>
@@ -167,11 +167,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			49T3z69eEOBmcFSD+a3fLxkRZOI=
+			6cwM6B1MfW2wTFB+g6c1GO9UH7g=
 			</data>
 			<key>hash2</key>
 			<data>
-			opYHpNi3KkdFqGsd3UAYaRbjKh6kPnu16gD/ZZQ/jt8=
+			ULQrtxP4RfbnV5GGj3i+PrYSI/rzDYskl0XQtCd72SU=
 			</data>
 		</dict>
 		<key>Headers/SDL_events.h</key>
@@ -178,11 +178,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			K0YDSorL3ZvxUfH/7EH3fBfzKLc=
+			feHsZTKREoq2xXa4dv/4lzZqzUc=
 			</data>
 			<key>hash2</key>
 			<data>
-			I5uNKrvrtaO88Gr7+QFZQjkDkbQNNWcBW22I09tejrM=
+			FVz2yvXnjsUNWBsWQOcBqaZrXCCdohSRWDh1l3SKqRY=
 			</data>
 		</dict>
 		<key>Headers/SDL_filesystem.h</key>
@@ -189,11 +189,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			dle2+b1LyoxJP6xuUUP52U8bqdY=
+			sicIJ2kroxv3QVkoKklHGN3tbWo=
 			</data>
 			<key>hash2</key>
 			<data>
-			mcXsf10CuoR8UoMDC9syqfGvRSyI2Auu+ugBHNEC2ug=
+			k3ybgbDF/Ap8kf4vKxLVZnRXoXtZwpFb4Nsk8GWqDCY=
 			</data>
 		</dict>
 		<key>Headers/SDL_gamecontroller.h</key>
@@ -200,11 +200,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			H0C0bgSTULk4TImchHfrYnmns7I=
+			RMJ7KpEMN4aYVe8PvF0XyjhXVOc=
 			</data>
 			<key>hash2</key>
 			<data>
-			1qemfRSfK6FrKGSL+1bTrustEUjrWDCedKTdrDYSfcs=
+			dJDgv9TNy/SgR2cADGxsSrwu1NZX2fYO830svryW4uc=
 			</data>
 		</dict>
 		<key>Headers/SDL_gesture.h</key>
@@ -211,11 +211,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			eOm09gklTuHk4CAnY8+N+AOWU1w=
+			iBwReSkmy4b/H3FD3mZZtLNdCMk=
 			</data>
 			<key>hash2</key>
 			<data>
-			3Jzx8qKPiLBEeimWYGEMjqACvDfAm8j8qVyKZPyot6o=
+			H7K4JyorBvI9vlJegmEZ6NvapE7/l/2bhOGeQ9zudiE=
 			</data>
 		</dict>
 		<key>Headers/SDL_guid.h</key>
@@ -222,11 +222,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			crNLOtYvZUPZiAe8ZhVvIlKHL1k=
+			jTpr9nvDtYvix2njIOclQs9xYuk=
 			</data>
 			<key>hash2</key>
 			<data>
-			8faGizimrTUdyyQeGyHX3YXB92lt5jgs6kJpGEpBoKY=
+			ifUKQBbQRJdNqsJBO7Mor3KqQyqDulvyNC82/RWPXhs=
 			</data>
 		</dict>
 		<key>Headers/SDL_haptic.h</key>
@@ -233,11 +233,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			2P/RhAx7yVVau0ImN4IRu0PKJwM=
+			+Wt7zxeuXghMudXSohdJr12ueGM=
 			</data>
 			<key>hash2</key>
 			<data>
-			Irx+pJE/K0azzSlTpm9Rst1n2EmNLTpbLY3kmpEinJ0=
+			VhCeKNAvsH+lrvZW9g65G84lg0FofrbORvS0TqPWaRQ=
 			</data>
 		</dict>
 		<key>Headers/SDL_hidapi.h</key>
@@ -244,11 +244,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			gerk57ttnkfcx6wYtwW4C8Utt60=
+			CBwPZQMZ5wsa03aBND8rQvsLfUg=
 			</data>
 			<key>hash2</key>
 			<data>
-			KYySNLgkVh6cIAiPYvDk/Yk2SvQafFytdHZOKvxzZOw=
+			CJEdgW9T0b2VRNRFaEZqPeCTg3FjsEFOHZvwuJbVHX0=
 			</data>
 		</dict>
 		<key>Headers/SDL_hints.h</key>
@@ -255,11 +255,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			JvGUtUGDdOD/IR6T8E+i/mJrG3w=
+			j33d96aUBrEwCVm9GpDBW1CXvVo=
 			</data>
 			<key>hash2</key>
 			<data>
-			DewV5qVFqCCDp3whs2d4873EyxDB/EU/7/0WCVf/KJ8=
+			WiHkNUFgiALKRxAIDQuaaU+Y6gKgtqw8YmZHPMtPyK4=
 			</data>
 		</dict>
 		<key>Headers/SDL_joystick.h</key>
@@ -266,11 +266,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			ZAJQHBdcuYDS3gUN2eAuQCr64Hs=
+			85/bNiER9h5QVoRQLNEZGF5VD3E=
 			</data>
 			<key>hash2</key>
 			<data>
-			YBrgL7qhSrwv7dy9AvltBQDYnEiKnkouVo351bFvJ5Y=
+			l5rSDksaaBXPl3GCffxGblOMgjvcufJSuuCglByf2yM=
 			</data>
 		</dict>
 		<key>Headers/SDL_keyboard.h</key>
@@ -277,11 +277,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			daaK2d9/FS98QIeRbwHDjK6MbM4=
+			4jiEP+XRfvz8VFmNWlHkcsMS2nI=
 			</data>
 			<key>hash2</key>
 			<data>
-			BOPhdmyBg4iHctggySFsXHD+2dk0qPQ1glPpc56gEoI=
+			EPdkxf3E/uXb/dm3gpxepX+d5JNWswuHP+PG/c33p84=
 			</data>
 		</dict>
 		<key>Headers/SDL_keycode.h</key>
@@ -288,11 +288,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			L6VgO8ptH7uIWMYxqiYDitWP2+0=
+			h18H9W8J7wesaRF2OApJEb2RFrY=
 			</data>
 			<key>hash2</key>
 			<data>
-			o+cvRpzlGHktvrWgdp69oT8gP310gr6qMuoz/bkvsJU=
+			zv9BVIERwcpba8USfGXPAzRO/qMWBbB5bWLDqEwWSYU=
 			</data>
 		</dict>
 		<key>Headers/SDL_loadso.h</key>
@@ -299,11 +299,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			BnfRn8au8VfS8nOYd+Og6CqxQtQ=
+			1fe02ZD9+yDX75ZVM1rk7RqDLCc=
 			</data>
 			<key>hash2</key>
 			<data>
-			ViHwtMagclIe0iTK9fUbYuesvQ1nv8rC+9675X5dk3Y=
+			eOcuzAcWhFDvl3bV+3m54GtOrTQztPLIiFHK6NOQuZM=
 			</data>
 		</dict>
 		<key>Headers/SDL_locale.h</key>
@@ -310,11 +310,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			B7JrCP37jV9Gs+1YoxkyXgaA3/0=
+			UOhBMG0JOnoQAEGMY7S6as755IY=
 			</data>
 			<key>hash2</key>
 			<data>
-			NfBH1vQU0RfPYtW0AzShJFmv8MulTUzc/kAQZ9C6ygw=
+			yM4RN7sKzLhnVlwbW1pJX3S6YLZl2LM/0qsLyQf5GXM=
 			</data>
 		</dict>
 		<key>Headers/SDL_log.h</key>
@@ -321,11 +321,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			aaLQi9U7ijhEeR6nQB97Eb5kLcY=
+			Ij4wEHg0aIMC28dTUSur/CAxQss=
 			</data>
 			<key>hash2</key>
 			<data>
-			HiRdEa7+l/wQ6D1HrCHHIIWuTmbSu/TDzwJZPE4T414=
+			A1Xc1+qvTtDHCz8f4e6oWq8SlifqizcVZ1Q37GJkhG0=
 			</data>
 		</dict>
 		<key>Headers/SDL_main.h</key>
@@ -332,11 +332,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			emJAoBEVFAWXHbDxAd6xuMN3B9E=
+			kDbuJzb/pBtb1iutYnW/hASbKgw=
 			</data>
 			<key>hash2</key>
 			<data>
-			VLGRF5preUhSrfraafaOj7fNn5NobRQZaHw4Un/7tfQ=
+			oIwpcrlXtl8XSnVMj+EmGESlisYv8O//EaDdoAd2xm0=
 			</data>
 		</dict>
 		<key>Headers/SDL_messagebox.h</key>
@@ -343,11 +343,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			Jyd+Z0oJkOyu7GqxrGoj92kX33E=
+			TZHRdWCuyxbRdc1GZjnTjHdKV5A=
 			</data>
 			<key>hash2</key>
 			<data>
-			b/2BVaUV14/zSF4P4vqsBKHdmHO39bcQh+Iw5cIjiUs=
+			Y+cutYk+JQOcbC9kbCdqbLr4oIBCxcX8HIzKJW+MOTE=
 			</data>
 		</dict>
 		<key>Headers/SDL_metal.h</key>
@@ -354,11 +354,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			tLVDtVwn6Vghxf+0jMCFWUhlFKM=
+			yggpDR8fWdb4ZAxZDLO7ztOMa84=
 			</data>
 			<key>hash2</key>
 			<data>
-			FJtCkZuzke2ER0mLBojAKoC0o6omQ3VOpuZJFnNnEPI=
+			aVk9kP7LRPopLu52brj5b7qNwMeUyUOwDPVyXwOm4O0=
 			</data>
 		</dict>
 		<key>Headers/SDL_misc.h</key>
@@ -365,11 +365,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			GDQyA6cRKZi3FJ3qPXMgIG19Xic=
+			wkzkXLc/0JwEBj+pVGBGODS/N7g=
 			</data>
 			<key>hash2</key>
 			<data>
-			ouIje4tauHjysbz3ObtyFzAB6lTCyhdwb4ndhQ3Z9n4=
+			qClRwcNymRF0gmpjyJ+EQ7fChV48OUN8NAAM2x8NsRM=
 			</data>
 		</dict>
 		<key>Headers/SDL_mouse.h</key>
@@ -376,11 +376,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			nrOK2z4t0YZ5ivxuTWB+9cXUf68=
+			wWyr5YJRLgkouejijZizd1f54ZE=
 			</data>
 			<key>hash2</key>
 			<data>
-			a1uWINzkYwydY2X/EhrWYcmHb2VG1Jy3C5nU6xOJAnk=
+			TN4Ft0Tl8FBtChEmqaC9q+ihzrGRO2+oE6f4FPqM754=
 			</data>
 		</dict>
 		<key>Headers/SDL_mutex.h</key>
@@ -387,11 +387,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			aG58/w/wU0G8N8tgCdD8ecbbbe4=
+			LOlLQylQ4fAuTL6ywn5mc7YHggg=
 			</data>
 			<key>hash2</key>
 			<data>
-			XUDMtaFm4qzh0iFhMP4Gnl9H7BDRtZnfFZx6UVvw6uQ=
+			Xe+WvrizruQy0+uhYKV3UHknz8I5FnrW8AnSAwZJOfw=
 			</data>
 		</dict>
 		<key>Headers/SDL_name.h</key>
@@ -398,11 +398,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			gOOcQtMKUerG67yCwPV+v0SxzCw=
+			86Aic9zf8RE0YQGymeyFxdGck34=
 			</data>
 			<key>hash2</key>
 			<data>
-			1axhwEeJjGS3A6JMrU9788wocEZRLyZNcaB/B6XRAMs=
+			U6Hh9de6D0JfccwHBmoAy/zaFw30VuNT1ofo30X7cCw=
 			</data>
 		</dict>
 		<key>Headers/SDL_opengl.h</key>
@@ -409,11 +409,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			dND0TDSXp8qXiMvjDaExf8CcXPE=
+			a83WQIdV8u+rut4US8joNjpA6kA=
 			</data>
 			<key>hash2</key>
 			<data>
-			B7dxqoi7VAFjjBzltB+JD02GXld/vb8xR+ugbv0XoK4=
+			HxWMmpZ2o+Z1atgt7Ou2sf5/4s2raLbApxzyqqzQcGY=
 			</data>
 		</dict>
 		<key>Headers/SDL_opengl_glext.h</key>
@@ -431,11 +431,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			gNgYlz+/uLgvjec6r0AW7Be2DJI=
+			Vc//lrKlqY/bME9ocSWczplleP4=
 			</data>
 			<key>hash2</key>
 			<data>
-			gpV8CPolshDeFDmSwWdoE1szEa7jY6uW06q61w+0g8k=
+			hJHBadVAgpV3dIMW++DPSJKqsNOCvkA8qNrMoFbXd5g=
 			</data>
 		</dict>
 		<key>Headers/SDL_opengles2.h</key>
@@ -442,11 +442,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			JAC+taTpU61KVFADpZvYguHPY/A=
+			gyrJUUv02Am+DYc5V42xH7EQev4=
 			</data>
 			<key>hash2</key>
 			<data>
-			4VPaduWoVpL5jy0A9S+tAoRXm0of4K+lqTZ2HRlDNT8=
+			T7CsPQJXfeZ3+pVjGLqzKBfEjyHX2Ne0vV44iZMKDgs=
 			</data>
 		</dict>
 		<key>Headers/SDL_opengles2_gl2.h</key>
@@ -497,11 +497,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			APvnWU71OTgg8nF2ZBdVu+N0OGo=
+			4PRTgauh2fx03ubJfuuHNOPhN28=
 			</data>
 			<key>hash2</key>
 			<data>
-			6VtEW9W48E5QT0eLhrzHm6TM2ZuskMlgjcaAwsilSlY=
+			GZQPt4sz55DRDRzw6E2c1WMjhNqInkQA3gxLQiTPQlw=
 			</data>
 		</dict>
 		<key>Headers/SDL_platform.h</key>
@@ -508,11 +508,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			xmppb22E9NRaDsdV/+utqvl2WLA=
+			Ey0u3gHjhY9CsV6rnGPL6l/Lqx4=
 			</data>
 			<key>hash2</key>
 			<data>
-			Y47cCReGiXXhqbPUw+8afBULSs6C1ywdEmYFPe3GSj8=
+			n9zH0IFb2hWb/ZQ3TBMQxLzDre/VQcI6Obhdmq8O7QU=
 			</data>
 		</dict>
 		<key>Headers/SDL_power.h</key>
@@ -519,11 +519,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			CZt1YqOCoPff+ZX5nsgeLs2abiM=
+			smMe7j3MNIT7wXXFRtMvGPFulso=
 			</data>
 			<key>hash2</key>
 			<data>
-			WuENeZEjbiPGXwmzKPi9End4ZRDqxD7gCGDnrgDjgJc=
+			mwBQ8l0GVg+f+/FeIU3sMgo9JAY7X3uq4NPwOc27IL8=
 			</data>
 		</dict>
 		<key>Headers/SDL_quit.h</key>
@@ -530,11 +530,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			tPbozXmJ7atsNAXI2sOnYySxxE0=
+			xxqxk2GqAVUt7s8YiRcGMegy160=
 			</data>
 			<key>hash2</key>
 			<data>
-			2OKt3rHgSNG9eTiP7SP0r7oy3zP+xN2i4s6r9i2FLOg=
+			cd4fDfe+MqMZ35xoFn5VPkGBafcN9tPvL9J74IeKtXI=
 			</data>
 		</dict>
 		<key>Headers/SDL_rect.h</key>
@@ -541,11 +541,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			iHOu4GrnG9wq51NGY+KM2d+2M0g=
+			AtB+xgoXRW94PDzzbBVBYyAW0gI=
 			</data>
 			<key>hash2</key>
 			<data>
-			Tntu1hV6+rDYjtkylyY+L1sksaom8tHOa/2CWh+sgtg=
+			rFxcleBxja/rwskrEIytxw3evL+Drkx3YsihtllIw78=
 			</data>
 		</dict>
 		<key>Headers/SDL_render.h</key>
@@ -552,11 +552,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			r+PPy63R1+ody+tZP2dbPGfmw6k=
+			wLdzEIMoOvdQScGrBT0EjqjYTso=
 			</data>
 			<key>hash2</key>
 			<data>
-			xW+/PQfQdyngWTar5nwag9GAO381W0WHFlh4lXmL/Nc=
+			xu0LmkwhR+b10K+nmKQ5XVpWOfKEHEEVTq0Ryswak3c=
 			</data>
 		</dict>
 		<key>Headers/SDL_revision.h</key>
@@ -563,11 +563,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			UPmbb5qt2EuGr24iZ1eyLvlBdiE=
+			XNd3ECdYFSFaaMv/uj3NwyatWcY=
 			</data>
 			<key>hash2</key>
 			<data>
-			iKXWp49rXQJuyDY9YmtbDqMGLR13eoyKE5GYpgrQ8wc=
+			FzAYjxrloDaswbapi8PCqNyMRjro8m4e4gSgAHWrJ8o=
 			</data>
 		</dict>
 		<key>Headers/SDL_rwops.h</key>
@@ -574,11 +574,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			L/Twsg6Wmiwo1H5Qs8STE8WIR24=
+			sCmzKOj8q3vee6JV6acptKOzBoQ=
 			</data>
 			<key>hash2</key>
 			<data>
-			km34IYEvTAj4qaziyAtJzgUinazvYYMTaAF2iFAKo9w=
+			j6rnTfnMJaCsq2CviHQP8obbVNgrElC0OXJBt3ltyVg=
 			</data>
 		</dict>
 		<key>Headers/SDL_scancode.h</key>
@@ -585,11 +585,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			8jfEeSeObKCo0FSuBdhCcOhGJY0=
+			JPnDQuCIC32+ugD3OX3igjdGfmE=
 			</data>
 			<key>hash2</key>
 			<data>
-			ea3lLDAd+NprFdQG6SDrWrbe+Eqk2deHZKcR4UYyqoo=
+			vC/EC0A66ywzXwlp8iGE7nlOpWGZ18iHhEdS7BsM3VU=
 			</data>
 		</dict>
 		<key>Headers/SDL_sensor.h</key>
@@ -596,11 +596,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			Wh0+8q+dAxu+zZXO1RTF/DO3iTs=
+			Pf6/Yj0hIgsUlhqj4UGylm+TjQs=
 			</data>
 			<key>hash2</key>
 			<data>
-			9KGbZIyc+S3T17HB/5k6xyDNONycVPbYpf5isAvhmCo=
+			5fAvXcuJcCx8/Et36VSkGacoiTENdiTe2BanIplHa2Y=
 			</data>
 		</dict>
 		<key>Headers/SDL_shape.h</key>
@@ -607,11 +607,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			UWs6SO78LJYdrBlGs1tY10DrJUI=
+			Hv8O7XLnXLIVAOf6cjF56yyrRkg=
 			</data>
 			<key>hash2</key>
 			<data>
-			CFJEICmokjpIcOYx1hTgGJ8fqLjaj+k9VuxREOUDJaA=
+			XFA3qPWL1vJ3EQtae2baJlOZ9ESEmhB1FMYI3fITLZY=
 			</data>
 		</dict>
 		<key>Headers/SDL_stdinc.h</key>
@@ -618,11 +618,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			vd3+T3ZYbYucuC3PVrlzpjJK02I=
+			5MtebnJHZfnCFhT9MeT6pg3EoPI=
 			</data>
 			<key>hash2</key>
 			<data>
-			IjvC4HnVYMawfQP4Gu8y0Y2oOUqct7p+z6lxIDDGKZ8=
+			qf4ijhTzMO4g9aKUrU+z10KfGRbOKVg3jIUS7TKrovA=
 			</data>
 		</dict>
 		<key>Headers/SDL_surface.h</key>
@@ -629,11 +629,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			bc5QzhwXbUo4XnD7q4NOSWOuTxs=
+			Toy3u0xKUfSMmknlIToaUmf5vwE=
 			</data>
 			<key>hash2</key>
 			<data>
-			xouGGI808iRhAh/0XTNJv2QTIUi3LPrZW5oHvGDm/7E=
+			CDctL0QJDSDvlB+uXO69kLW2uA0Xdc0xiJBN8h3pX74=
 			</data>
 		</dict>
 		<key>Headers/SDL_system.h</key>
@@ -640,11 +640,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			s6lznhqSlL+KFtBJSEELBCTTp1U=
+			I1i3X5zfVBg7YFzag2Dj43RzuUI=
 			</data>
 			<key>hash2</key>
 			<data>
-			AlgtfPI6N0Jukp6N7fmTnNV3AzBzEBj5HZREFJSkMmY=
+			mt328KSVoSMSjZ4Wy268tC04JQmyCAsDM60TWeG3K4s=
 			</data>
 		</dict>
 		<key>Headers/SDL_syswm.h</key>
@@ -651,11 +651,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			oxVccR9E/ARZqqPl+BjVMKNdDNw=
+			7sdDIYSuCZbE13gdwZ+rmiqUBEk=
 			</data>
 			<key>hash2</key>
 			<data>
-			LRcM/Fhcqwv6Qf3YhgaLGkkEuFqXFTvl6pWfaQCNw9g=
+			6QWGeehhVCpiwN9fQv1by5vpdNg8JqxY1XgR48Fxpdc=
 			</data>
 		</dict>
 		<key>Headers/SDL_thread.h</key>
@@ -662,11 +662,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			dn5FB3QZEtYrriL/kUTOyAj9jwE=
+			bCVCxCLiY7Rkx02GC2u37KSejsU=
 			</data>
 			<key>hash2</key>
 			<data>
-			xEW2ytplQOQ2uIOG2QNBUsTI8kSuUC18NfQ8BnenZYI=
+			Qhsj5cNniFikrpQc/wnB/IipdeR8tFkywQAEwSyernM=
 			</data>
 		</dict>
 		<key>Headers/SDL_timer.h</key>
@@ -673,11 +673,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			Ltnz4OrvTc2eABw8uX/0L/nuca4=
+			Nstsm7GCSSnoH66923lImFIE0fY=
 			</data>
 			<key>hash2</key>
 			<data>
-			W+hRt3f94ZHPIpQ4xN7D/U0OVtTTZBAA9Nphtq8fgeg=
+			6jmEztIQClT68gsMRHHP9tVPF5TxqLfBgmkTqOA00fs=
 			</data>
 		</dict>
 		<key>Headers/SDL_touch.h</key>
@@ -684,11 +684,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			rwC4gDU7l5kY0ZZEIhd7RT3axUU=
+			LWDPymUVgQxlg3DwBCJ8klXPq6U=
 			</data>
 			<key>hash2</key>
 			<data>
-			DVFA8C77fiVhyFFtqV/lglia5PShpk967pt+huaItwo=
+			y/Kqn35XtKznNX9foqsPjC+jlnbRvBuF8A1MzKIjBmY=
 			</data>
 		</dict>
 		<key>Headers/SDL_types.h</key>
@@ -695,11 +695,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			ARZgD/WKM8LbXYcplBCyws5jmmo=
+			8xeioL5fy1QauaS4i9g5UdMotoM=
 			</data>
 			<key>hash2</key>
 			<data>
-			vvFj+McRdgHRX9HrooW/E7jX5C74rxEwVv18wMyvSC0=
+			Em64WSsB0scWcgjtDOAhVyy4XoRBRciw+YaG3vyn6hM=
 			</data>
 		</dict>
 		<key>Headers/SDL_version.h</key>
@@ -706,11 +706,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			LblCHIN3YDAC5u7sKKVT9KXuhhQ=
+			QDqwH27Tmjz8nMPphdVAZqPqGt0=
 			</data>
 			<key>hash2</key>
 			<data>
-			m2YnnxZ3NFLyWa40RPyHe4X7MfV68puUdm1SdheubMY=
+			nk6h9XDXojUkw/F8Ff7er08rfzKTzlMT0jLr2lPMgv8=
 			</data>
 		</dict>
 		<key>Headers/SDL_video.h</key>
@@ -717,11 +717,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			4jGRWrhQFyHkch8stq/9q4W1Ojs=
+			YAMYz1pUQobEWpC1EuOB5YmsIZc=
 			</data>
 			<key>hash2</key>
 			<data>
-			K3iiENHlz4P96m4GXYFrijlVAWWUeCWFdFm78pPl4Nk=
+			bFi0k6PF8xpOpR6X0Wsidxl7LIWX2hVGjSysd6roB6A=
 			</data>
 		</dict>
 		<key>Headers/SDL_vulkan.h</key>
@@ -739,11 +739,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			u4PDdbvfemkyR1H1QsODd6pLFRA=
+			f6TnCZT882PpPk816tLLYBb5tJM=
 			</data>
 			<key>hash2</key>
 			<data>
-			mOMdpMYdVHyciBhBNbcuPQFKemkQLlxtdYNQI3z2snE=
+			G4bzpDXzXe091TEGmuQxF+N64ZDTNg32tUjyDAYJXmE=
 			</data>
 		</dict>
 		<key>Headers/close_code.h</key>
@@ -750,11 +750,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			l886gK0WewF9TLQ2N3wuuk5YOK8=
+			pzX1cw2hHQdMFCO0VcO1VVsfXUo=
 			</data>
 			<key>hash2</key>
 			<data>
-			9JEAM14hpDRV6tDnQvfIFtBJQXHOEJSONje5q/PKlTo=
+			+ybA2nqIwfLyUQ9Pf9ZLXUyXMGNS3xZMEowuIcqIrRQ=
 			</data>
 		</dict>
 		<key>Resources/CMake/sdl2-config-version.cmake</key>
@@ -783,11 +783,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			0srrtdsGkAsDsNfVa8G4uQTmX18=
+			ECcyTBfZPucOFnTMf7BSonyduBg=
 			</data>
 			<key>hash2</key>
 			<data>
-			dsUxoQk9XWlOiWXn9Ywz3s9X2VDH0jsvImZxBCRK3ck=
+			4i5aYnvsU/2ssKdrpU5A9mYIX4q4fzaqinS7xOcPTyY=
 			</data>
 		</dict>
 		<key>Resources/License.txt</key>
@@ -794,11 +794,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			VoVWJNSXNFkj10nxdQKhgCnXJjE=
+			fCUUBjJ4JuUAC8MRSCszNcY21v8=
 			</data>
 			<key>hash2</key>
 			<data>
-			IY4SCBLx/QICUzUIfTw/MBGoah4TzstyMeoTfwWSuDM=
+			d+3CuMuNTuvjYs+HODz44b3nsOHwwJqlcyQOq7qhAPc=
 			</data>
 		</dict>
 		<key>Resources/ReadMe.txt</key>
@@ -816,11 +816,11 @@
 		<dict>
 			<key>hash</key>
 			<data>
-			IJbnxEB8M5Bm2m634ZoP3yyZ7hc=
+			07w7GQmm31+NEK8ne4mSo7m70Do=
 			</data>
 			<key>hash2</key>
 			<data>
-			jER7vdakln2mbSKeyf0qvxSSq/5YH3yog8/x0a3iGGw=
+			vmrmeHQ4l7Q4flA5dILQw27M4T0Sc70MQIfP+lFY/do=
 			</data>
 		</dict>
 	</dict>
--- a/release/macos/pt2-clone-macos.app/Contents/Info.plist
+++ b/release/macos/pt2-clone-macos.app/Contents/Info.plist
@@ -46,7 +46,7 @@
     <string>Copyright © Olav "8bitbubsy" Sørensen
 https://16-bits.org</string>
     <key>LSMinimumSystemVersion</key>
-    <string>10.9</string>
+    <string>10.11</string>
     <key>CGDisableCoalescedUpdates</key>
     <true/>
     <key>NSHighResolutionCapable</key>
binary files a/release/win32/SDL2.dll b/release/win32/SDL2.dll differ
binary files a/release/win64/SDL2.dll b/release/win64/SDL2.dll differ
--- /dev/null
+++ b/src/libflac/COPYING.txt
@@ -1,0 +1,29 @@
+Copyright (C) 2000-2009  Josh Coalson
+Copyright (C) 2011-2016  Xiph.Org Foundation
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+- Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+- 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.
+
+- Neither the name of the Xiph.org Foundation nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+``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 FOUNDATION OR
+CONTRIBUTORS 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.
--- /dev/null
+++ b/src/libflac/FLAC/callback.h
@@ -1,0 +1,185 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2004-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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.
+ */
+
+#ifndef FLAC__CALLBACK_H
+#define FLAC__CALLBACK_H
+
+#include "ordinals.h"
+#include <stdlib.h> /* for size_t */
+
+/** \file include/FLAC/callback.h
+ *
+ *  \brief
+ *  This module defines the structures for describing I/O callbacks
+ *  to the other FLAC interfaces.
+ *
+ *  See the detailed documentation for callbacks in the
+ *  \link flac_callbacks callbacks \endlink module.
+ */
+
+/** \defgroup flac_callbacks FLAC/callback.h: I/O callback structures
+ *  \ingroup flac
+ *
+ *  \brief
+ *  This module defines the structures for describing I/O callbacks
+ *  to the other FLAC interfaces.
+ *
+ *  The purpose of the I/O callback functions is to create a common way
+ *  for the metadata interfaces to handle I/O.
+ *
+ *  Originally the metadata interfaces required filenames as the way of
+ *  specifying FLAC files to operate on.  This is problematic in some
+ *  environments so there is an additional option to specify a set of
+ *  callbacks for doing I/O on the FLAC file, instead of the filename.
+ *
+ *  In addition to the callbacks, a FLAC__IOHandle type is defined as an
+ *  opaque structure for a data source.
+ *
+ *  The callback function prototypes are similar (but not identical) to the
+ *  stdio functions fread, fwrite, fseek, ftell, feof, and fclose.  If you use
+ *  stdio streams to implement the callbacks, you can pass fread, fwrite, and
+ *  fclose anywhere a FLAC__IOCallback_Read, FLAC__IOCallback_Write, or
+ *  FLAC__IOCallback_Close is required, and a FILE* anywhere a FLAC__IOHandle
+ *  is required.  \warning You generally CANNOT directly use fseek or ftell
+ *  for FLAC__IOCallback_Seek or FLAC__IOCallback_Tell since on most systems
+ *  these use 32-bit offsets and FLAC requires 64-bit offsets to deal with
+ *  large files.  You will have to find an equivalent function (e.g. ftello),
+ *  or write a wrapper.  The same is true for feof() since this is usually
+ *  implemented as a macro, not as a function whose address can be taken.
+ *
+ * \{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** This is the opaque handle type used by the callbacks.  Typically
+ *  this is a \c FILE* or address of a file descriptor.
+ */
+typedef void* FLAC__IOHandle;
+
+/** Signature for the read callback.
+ *  The signature and semantics match POSIX fread() implementations
+ *  and can generally be used interchangeably.
+ *
+ * \param  ptr      The address of the read buffer.
+ * \param  size     The size of the records to be read.
+ * \param  nmemb    The number of records to be read.
+ * \param  handle   The handle to the data source.
+ * \retval size_t
+ *    The number of records read.
+ */
+typedef size_t (*FLAC__IOCallback_Read) (void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle);
+
+/** Signature for the write callback.
+ *  The signature and semantics match POSIX fwrite() implementations
+ *  and can generally be used interchangeably.
+ *
+ * \param  ptr      The address of the write buffer.
+ * \param  size     The size of the records to be written.
+ * \param  nmemb    The number of records to be written.
+ * \param  handle   The handle to the data source.
+ * \retval size_t
+ *    The number of records written.
+ */
+typedef size_t (*FLAC__IOCallback_Write) (const void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle);
+
+/** Signature for the seek callback.
+ *  The signature and semantics mostly match POSIX fseek() WITH ONE IMPORTANT
+ *  EXCEPTION: the offset is a 64-bit type whereas fseek() is generally 'long'
+ *  and 32-bits wide.
+ *
+ * \param  handle   The handle to the data source.
+ * \param  offset   The new position, relative to \a whence
+ * \param  whence   \c SEEK_SET, \c SEEK_CUR, or \c SEEK_END
+ * \retval int
+ *    \c 0 on success, \c -1 on error.
+ */
+typedef int (*FLAC__IOCallback_Seek) (FLAC__IOHandle handle, FLAC__int64 offset, int whence);
+
+/** Signature for the tell callback.
+ *  The signature and semantics mostly match POSIX ftell() WITH ONE IMPORTANT
+ *  EXCEPTION: the offset is a 64-bit type whereas ftell() is generally 'long'
+ *  and 32-bits wide.
+ *
+ * \param  handle   The handle to the data source.
+ * \retval FLAC__int64
+ *    The current position on success, \c -1 on error.
+ */
+typedef FLAC__int64 (*FLAC__IOCallback_Tell) (FLAC__IOHandle handle);
+
+/** Signature for the EOF callback.
+ *  The signature and semantics mostly match POSIX feof() but WATCHOUT:
+ *  on many systems, feof() is a macro, so in this case a wrapper function
+ *  must be provided instead.
+ *
+ * \param  handle   The handle to the data source.
+ * \retval int
+ *    \c 0 if not at end of file, nonzero if at end of file.
+ */
+typedef int (*FLAC__IOCallback_Eof) (FLAC__IOHandle handle);
+
+/** Signature for the close callback.
+ *  The signature and semantics match POSIX fclose() implementations
+ *  and can generally be used interchangeably.
+ *
+ * \param  handle   The handle to the data source.
+ * \retval int
+ *    \c 0 on success, \c EOF on error.
+ */
+typedef int (*FLAC__IOCallback_Close) (FLAC__IOHandle handle);
+
+/** A structure for holding a set of callbacks.
+ *  Each FLAC interface that requires a FLAC__IOCallbacks structure will
+ *  describe which of the callbacks are required.  The ones that are not
+ *  required may be set to NULL.
+ *
+ *  If the seek requirement for an interface is optional, you can signify that
+ *  a data source is not seekable by setting the \a seek field to \c NULL.
+ */
+typedef struct {
+	FLAC__IOCallback_Read read;
+	FLAC__IOCallback_Write write;
+	FLAC__IOCallback_Seek seek;
+	FLAC__IOCallback_Tell tell;
+	FLAC__IOCallback_Eof eof;
+	FLAC__IOCallback_Close close;
+} FLAC__IOCallbacks;
+
+/* \} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+++ b/src/libflac/FLAC/export.h
@@ -1,0 +1,70 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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.
+ */
+
+#ifndef FLAC__EXPORT_H
+#define FLAC__EXPORT_H
+
+/** \file include/FLAC/export.h
+ *
+ *  \brief
+ *  This module contains #defines and symbols for exporting function
+ *  calls, and providing version information and compiled-in features.
+ *
+ *  See the \link flac_export export \endlink module.
+ */
+
+/** \defgroup flac_export FLAC/export.h: export symbols
+ *  \ingroup flac
+ *
+ *  \brief
+ *  This module contains #defines and symbols for exporting function
+ *  calls, and providing version information and compiled-in features.
+ *
+ *  If you are compiling with MSVC and will link to the static library
+ *  (libFLAC.lib) you should define FLAC__NO_DLL in your project to
+ *  make sure the symbols are exported properly.
+ *
+ * \{
+ */
+
+#define FLAC_API
+
+/** These #defines will mirror the libtool-based library version number, see
+ * http://www.gnu.org/software/libtool/manual/libtool.html#Libtool-versioning
+ */
+#define FLAC_API_VERSION_CURRENT 11
+#define FLAC_API_VERSION_REVISION 0 /**< see above */
+#define FLAC_API_VERSION_AGE 3 /**< see above */
+
+/* \} */
+
+#endif
--- /dev/null
+++ b/src/libflac/FLAC/format.h
@@ -1,0 +1,1025 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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.
+ */
+
+#ifndef FLAC__FORMAT_H
+#define FLAC__FORMAT_H
+
+#include "export.h"
+#include "ordinals.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file include/FLAC/format.h
+ *
+ *  \brief
+ *  This module contains structure definitions for the representation
+ *  of FLAC format components in memory.  These are the basic
+ *  structures used by the rest of the interfaces.
+ *
+ *  See the detailed documentation in the
+ *  \link flac_format format \endlink module.
+ */
+
+/** \defgroup flac_format FLAC/format.h: format components
+ *  \ingroup flac
+ *
+ *  \brief
+ *  This module contains structure definitions for the representation
+ *  of FLAC format components in memory.  These are the basic
+ *  structures used by the rest of the interfaces.
+ *
+ *  First, you should be familiar with the
+ *  <A HREF="../format.html">FLAC format</A>.  Many of the values here
+ *  follow directly from the specification.  As a user of libFLAC, the
+ *  interesting parts really are the structures that describe the frame
+ *  header and metadata blocks.
+ *
+ *  The format structures here are very primitive, designed to store
+ *  information in an efficient way.  Reading information from the
+ *  structures is easy but creating or modifying them directly is
+ *  more complex.  For the most part, as a user of a library, editing
+ *  is not necessary; however, for metadata blocks it is, so there are
+ *  convenience functions provided in the \link flac_metadata metadata
+ *  module \endlink to simplify the manipulation of metadata blocks.
+ *
+ * \note
+ * It's not the best convention, but symbols ending in _LEN are in bits
+ * and _LENGTH are in bytes.  _LENGTH symbols are \#defines instead of
+ * global variables because they are usually used when declaring byte
+ * arrays and some compilers require compile-time knowledge of array
+ * sizes when declared on the stack.
+ *
+ * \{
+ */
+
+
+/*
+	Most of the values described in this file are defined by the FLAC
+	format specification.  There is nothing to tune here.
+*/
+
+/** The largest legal metadata type code. */
+#define FLAC__MAX_METADATA_TYPE_CODE (126u)
+
+/** The minimum block size, in samples, permitted by the format. */
+#define FLAC__MIN_BLOCK_SIZE (16u)
+
+/** The maximum block size, in samples, permitted by the format. */
+#define FLAC__MAX_BLOCK_SIZE (65535u)
+
+/** The maximum block size, in samples, permitted by the FLAC subset for
+ *  sample rates up to 48kHz. */
+#define FLAC__SUBSET_MAX_BLOCK_SIZE_48000HZ (4608u)
+
+/** The maximum number of channels permitted by the format. */
+#define FLAC__MAX_CHANNELS (8u)
+
+/** The minimum sample resolution permitted by the format. */
+#define FLAC__MIN_BITS_PER_SAMPLE (4u)
+
+/** The maximum sample resolution permitted by the format. */
+#define FLAC__MAX_BITS_PER_SAMPLE (32u)
+
+/** The maximum sample resolution permitted by libFLAC.
+ *
+ * \warning
+ * FLAC__MAX_BITS_PER_SAMPLE is the limit of the FLAC format.  However,
+ * the reference encoder/decoder is currently limited to 24 bits because
+ * of prevalent 32-bit math, so make sure and use this value when
+ * appropriate.
+ */
+#define FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE (24u)
+
+/** The maximum sample rate permitted by the format.  The value is
+ *  ((2 ^ 16) - 1) * 10; see <A HREF="../format.html">FLAC format</A>
+ *  as to why.
+ */
+#define FLAC__MAX_SAMPLE_RATE (655350u)
+
+/** The maximum LPC order permitted by the format. */
+#define FLAC__MAX_LPC_ORDER (32u)
+
+/** The maximum LPC order permitted by the FLAC subset for sample rates
+ *  up to 48kHz. */
+#define FLAC__SUBSET_MAX_LPC_ORDER_48000HZ (12u)
+
+/** The minimum quantized linear predictor coefficient precision
+ *  permitted by the format.
+ */
+#define FLAC__MIN_QLP_COEFF_PRECISION (5u)
+
+/** The maximum quantized linear predictor coefficient precision
+ *  permitted by the format.
+ */
+#define FLAC__MAX_QLP_COEFF_PRECISION (15u)
+
+/** The maximum order of the fixed predictors permitted by the format. */
+#define FLAC__MAX_FIXED_ORDER (4u)
+
+/** The maximum Rice partition order permitted by the format. */
+#define FLAC__MAX_RICE_PARTITION_ORDER (15u)
+
+/** The maximum Rice partition order permitted by the FLAC Subset. */
+#define FLAC__SUBSET_MAX_RICE_PARTITION_ORDER (8u)
+
+/** The version string of the release, stamped onto the libraries and binaries.
+ *
+ * \note
+ * This does not correspond to the shared library version number, which
+ * is used to determine binary compatibility.
+ */
+extern FLAC_API const char *FLAC__VERSION_STRING;
+
+/** The vendor string inserted by the encoder into the VORBIS_COMMENT block.
+ *  This is a NUL-terminated ASCII string; when inserted into the
+ *  VORBIS_COMMENT the trailing null is stripped.
+ */
+extern FLAC_API const char *FLAC__VENDOR_STRING;
+
+/** The byte string representation of the beginning of a FLAC stream. */
+extern FLAC_API const FLAC__byte FLAC__STREAM_SYNC_STRING[4]; /* = "fLaC" */
+
+/** The 32-bit integer big-endian representation of the beginning of
+ *  a FLAC stream.
+ */
+extern FLAC_API const uint32_t FLAC__STREAM_SYNC; /* = 0x664C6143 */
+
+/** The length of the FLAC signature in bits. */
+extern FLAC_API const uint32_t FLAC__STREAM_SYNC_LEN; /* = 32 bits */
+
+/** The length of the FLAC signature in bytes. */
+#define FLAC__STREAM_SYNC_LENGTH (4u)
+
+
+/*****************************************************************************
+ *
+ * Subframe structures
+ *
+ *****************************************************************************/
+
+/*****************************************************************************/
+
+/** An enumeration of the available entropy coding methods. */
+typedef enum {
+	FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE = 0,
+	/**< Residual is coded by partitioning into contexts, each with it's own
+	 * 4-bit Rice parameter. */
+
+	FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2 = 1
+	/**< Residual is coded by partitioning into contexts, each with it's own
+	 * 5-bit Rice parameter. */
+} FLAC__EntropyCodingMethodType;
+
+/** Maps a FLAC__EntropyCodingMethodType to a C string.
+ *
+ *  Using a FLAC__EntropyCodingMethodType as the index to this array will
+ *  give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__EntropyCodingMethodTypeString[];
+
+
+/** Contents of a Rice partitioned residual
+ */
+typedef struct {
+
+	uint32_t *parameters;
+	/**< The Rice parameters for each context. */
+
+	uint32_t *raw_bits;
+	/**< Widths for escape-coded partitions.  Will be non-zero for escaped
+	 * partitions and zero for unescaped partitions.
+	 */
+
+	uint32_t capacity_by_order;
+	/**< The capacity of the \a parameters and \a raw_bits arrays
+	 * specified as an order, i.e. the number of array elements
+	 * allocated is 2 ^ \a capacity_by_order.
+	 */
+} FLAC__EntropyCodingMethod_PartitionedRiceContents;
+
+/** Header for a Rice partitioned residual.  (c.f. <A HREF="../format.html#partitioned_rice">format specification</A>)
+ */
+typedef struct {
+
+	uint32_t order;
+	/**< The partition order, i.e. # of contexts = 2 ^ \a order. */
+
+	const FLAC__EntropyCodingMethod_PartitionedRiceContents *contents;
+	/**< The context's Rice parameters and/or raw bits. */
+
+} FLAC__EntropyCodingMethod_PartitionedRice;
+
+extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN; /**< == 4 (bits) */
+extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN; /**< == 4 (bits) */
+extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN; /**< == 5 (bits) */
+extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN; /**< == 5 (bits) */
+
+extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER;
+/**< == (1<<FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN)-1 */
+extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER;
+/**< == (1<<FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN)-1 */
+
+/** Header for the entropy coding method.  (c.f. <A HREF="../format.html#residual">format specification</A>)
+ */
+typedef struct {
+	FLAC__EntropyCodingMethodType type;
+	union {
+		FLAC__EntropyCodingMethod_PartitionedRice partitioned_rice;
+	} data;
+} FLAC__EntropyCodingMethod;
+
+extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_TYPE_LEN; /**< == 2 (bits) */
+
+/*****************************************************************************/
+
+/** An enumeration of the available subframe types. */
+typedef enum {
+	FLAC__SUBFRAME_TYPE_CONSTANT = 0, /**< constant signal */
+	FLAC__SUBFRAME_TYPE_VERBATIM = 1, /**< uncompressed signal */
+	FLAC__SUBFRAME_TYPE_FIXED = 2, /**< fixed polynomial prediction */
+	FLAC__SUBFRAME_TYPE_LPC = 3 /**< linear prediction */
+} FLAC__SubframeType;
+
+/** Maps a FLAC__SubframeType to a C string.
+ *
+ *  Using a FLAC__SubframeType as the index to this array will
+ *  give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__SubframeTypeString[];
+
+
+/** CONSTANT subframe.  (c.f. <A HREF="../format.html#subframe_constant">format specification</A>)
+ */
+typedef struct {
+	FLAC__int32 value; /**< The constant signal value. */
+} FLAC__Subframe_Constant;
+
+
+/** VERBATIM subframe.  (c.f. <A HREF="../format.html#subframe_verbatim">format specification</A>)
+ */
+typedef struct {
+	const FLAC__int32 *data; /**< A pointer to verbatim signal. */
+} FLAC__Subframe_Verbatim;
+
+
+/** FIXED subframe.  (c.f. <A HREF="../format.html#subframe_fixed">format specification</A>)
+ */
+typedef struct {
+	FLAC__EntropyCodingMethod entropy_coding_method;
+	/**< The residual coding method. */
+
+	uint32_t order;
+	/**< The polynomial order. */
+
+	FLAC__int32 warmup[FLAC__MAX_FIXED_ORDER];
+	/**< Warmup samples to prime the predictor, length == order. */
+
+	const FLAC__int32 *residual;
+	/**< The residual signal, length == (blocksize minus order) samples. */
+} FLAC__Subframe_Fixed;
+
+
+/** LPC subframe.  (c.f. <A HREF="../format.html#subframe_lpc">format specification</A>)
+ */
+typedef struct {
+	FLAC__EntropyCodingMethod entropy_coding_method;
+	/**< The residual coding method. */
+
+	uint32_t order;
+	/**< The FIR order. */
+
+	uint32_t qlp_coeff_precision;
+	/**< Quantized FIR filter coefficient precision in bits. */
+
+	int quantization_level;
+	/**< The qlp coeff shift needed. */
+
+	FLAC__int32 qlp_coeff[FLAC__MAX_LPC_ORDER];
+	/**< FIR filter coefficients. */
+
+	FLAC__int32 warmup[FLAC__MAX_LPC_ORDER];
+	/**< Warmup samples to prime the predictor, length == order. */
+
+	const FLAC__int32 *residual;
+	/**< The residual signal, length == (blocksize minus order) samples. */
+} FLAC__Subframe_LPC;
+
+extern FLAC_API const uint32_t FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN; /**< == 4 (bits) */
+extern FLAC_API const uint32_t FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN; /**< == 5 (bits) */
+
+
+/** FLAC subframe structure.  (c.f. <A HREF="../format.html#subframe">format specification</A>)
+ */
+typedef struct {
+	FLAC__SubframeType type;
+	union {
+		FLAC__Subframe_Constant constant;
+		FLAC__Subframe_Fixed fixed;
+		FLAC__Subframe_LPC lpc;
+		FLAC__Subframe_Verbatim verbatim;
+	} data;
+	uint32_t wasted_bits;
+} FLAC__Subframe;
+
+/** == 1 (bit)
+ *
+ * This used to be a zero-padding bit (hence the name
+ * FLAC__SUBFRAME_ZERO_PAD_LEN) but is now a reserved bit.  It still has a
+ * mandatory value of \c 0 but in the future may take on the value \c 0 or \c 1
+ * to mean something else.
+ */
+extern FLAC_API const uint32_t FLAC__SUBFRAME_ZERO_PAD_LEN;
+extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_LEN; /**< == 6 (bits) */
+extern FLAC_API const uint32_t FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN; /**< == 1 (bit) */
+
+extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK; /**< = 0x00 */
+extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK; /**< = 0x02 */
+extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK; /**< = 0x10 */
+extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK; /**< = 0x40 */
+
+/*****************************************************************************/
+
+
+/*****************************************************************************
+ *
+ * Frame structures
+ *
+ *****************************************************************************/
+
+/** An enumeration of the available channel assignments. */
+typedef enum {
+	FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT = 0, /**< independent channels */
+	FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE = 1, /**< left+side stereo */
+	FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE = 2, /**< right+side stereo */
+	FLAC__CHANNEL_ASSIGNMENT_MID_SIDE = 3 /**< mid+side stereo */
+} FLAC__ChannelAssignment;
+
+/** Maps a FLAC__ChannelAssignment to a C string.
+ *
+ *  Using a FLAC__ChannelAssignment as the index to this array will
+ *  give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__ChannelAssignmentString[];
+
+/** An enumeration of the possible frame numbering methods. */
+typedef enum {
+	FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER, /**< number contains the frame number */
+	FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER /**< number contains the sample number of first sample in frame */
+} FLAC__FrameNumberType;
+
+/** Maps a FLAC__FrameNumberType to a C string.
+ *
+ *  Using a FLAC__FrameNumberType as the index to this array will
+ *  give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__FrameNumberTypeString[];
+
+
+/** FLAC frame header structure.  (c.f. <A HREF="../format.html#frame_header">format specification</A>)
+ */
+typedef struct {
+	uint32_t blocksize;
+	/**< The number of samples per subframe. */
+
+	uint32_t sample_rate;
+	/**< The sample rate in Hz. */
+
+	uint32_t channels;
+	/**< The number of channels (== number of subframes). */
+
+	FLAC__ChannelAssignment channel_assignment;
+	/**< The channel assignment for the frame. */
+
+	uint32_t bits_per_sample;
+	/**< The sample resolution. */
+
+	FLAC__FrameNumberType number_type;
+	/**< The numbering scheme used for the frame.  As a convenience, the
+	 * decoder will always convert a frame number to a sample number because
+	 * the rules are complex. */
+
+	union {
+		FLAC__uint32 frame_number;
+		FLAC__uint64 sample_number;
+	} number;
+	/**< The frame number or sample number of first sample in frame;
+	 * use the \a number_type value to determine which to use. */
+
+	FLAC__uint8 crc;
+	/**< CRC-8 (polynomial = x^8 + x^2 + x^1 + x^0, initialized with 0)
+	 * of the raw frame header bytes, meaning everything before the CRC byte
+	 * including the sync code.
+	 */
+} FLAC__FrameHeader;
+
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_SYNC; /**< == 0x3ffe; the frame header sync code */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_SYNC_LEN; /**< == 14 (bits) */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_RESERVED_LEN; /**< == 1 (bits) */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN; /**< == 1 (bits) */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_BLOCK_SIZE_LEN; /**< == 4 (bits) */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_SAMPLE_RATE_LEN; /**< == 4 (bits) */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN; /**< == 4 (bits) */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN; /**< == 3 (bits) */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_ZERO_PAD_LEN; /**< == 1 (bit) */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_CRC_LEN; /**< == 8 (bits) */
+
+
+/** FLAC frame footer structure.  (c.f. <A HREF="../format.html#frame_footer">format specification</A>)
+ */
+typedef struct {
+	FLAC__uint16 crc;
+	/**< CRC-16 (polynomial = x^16 + x^15 + x^2 + x^0, initialized with
+	 * 0) of the bytes before the crc, back to and including the frame header
+	 * sync code.
+	 */
+} FLAC__FrameFooter;
+
+extern FLAC_API const uint32_t FLAC__FRAME_FOOTER_CRC_LEN; /**< == 16 (bits) */
+
+
+/** FLAC frame structure.  (c.f. <A HREF="../format.html#frame">format specification</A>)
+ */
+typedef struct {
+	FLAC__FrameHeader header;
+	FLAC__Subframe subframes[FLAC__MAX_CHANNELS];
+	FLAC__FrameFooter footer;
+} FLAC__Frame;
+
+/*****************************************************************************/
+
+
+/*****************************************************************************
+ *
+ * Meta-data structures
+ *
+ *****************************************************************************/
+
+/** An enumeration of the available metadata block types. */
+typedef enum {
+
+	FLAC__METADATA_TYPE_STREAMINFO = 0,
+	/**< <A HREF="../format.html#metadata_block_streaminfo">STREAMINFO</A> block */
+
+	FLAC__METADATA_TYPE_PADDING = 1,
+	/**< <A HREF="../format.html#metadata_block_padding">PADDING</A> block */
+
+	FLAC__METADATA_TYPE_APPLICATION = 2,
+	/**< <A HREF="../format.html#metadata_block_application">APPLICATION</A> block */
+
+	FLAC__METADATA_TYPE_SEEKTABLE = 3,
+	/**< <A HREF="../format.html#metadata_block_seektable">SEEKTABLE</A> block */
+
+	FLAC__METADATA_TYPE_VORBIS_COMMENT = 4,
+	/**< <A HREF="../format.html#metadata_block_vorbis_comment">VORBISCOMMENT</A> block (a.k.a. FLAC tags) */
+
+	FLAC__METADATA_TYPE_CUESHEET = 5,
+	/**< <A HREF="../format.html#metadata_block_cuesheet">CUESHEET</A> block */
+
+	FLAC__METADATA_TYPE_PICTURE = 6,
+	/**< <A HREF="../format.html#metadata_block_picture">PICTURE</A> block */
+
+	FLAC__METADATA_TYPE_UNDEFINED = 7,
+	/**< marker to denote beginning of undefined type range; this number will increase as new metadata types are added */
+
+	FLAC__MAX_METADATA_TYPE = FLAC__MAX_METADATA_TYPE_CODE,
+	/**< No type will ever be greater than this. There is not enough room in the protocol block. */
+} FLAC__MetadataType;
+
+/** Maps a FLAC__MetadataType to a C string.
+ *
+ *  Using a FLAC__MetadataType as the index to this array will
+ *  give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__MetadataTypeString[];
+
+
+/** FLAC STREAMINFO structure.  (c.f. <A HREF="../format.html#metadata_block_streaminfo">format specification</A>)
+ */
+typedef struct {
+	uint32_t min_blocksize, max_blocksize;
+	uint32_t min_framesize, max_framesize;
+	uint32_t sample_rate;
+	uint32_t channels;
+	uint32_t bits_per_sample;
+	FLAC__uint64 total_samples;
+	FLAC__byte md5sum[16];
+} FLAC__StreamMetadata_StreamInfo;
+
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN; /**< == 16 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN; /**< == 16 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN; /**< == 24 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN; /**< == 24 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN; /**< == 20 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN; /**< == 3 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN; /**< == 5 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN; /**< == 36 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN; /**< == 128 (bits) */
+
+/** The total stream length of the STREAMINFO block in bytes. */
+#define FLAC__STREAM_METADATA_STREAMINFO_LENGTH (34u)
+
+/** FLAC PADDING structure.  (c.f. <A HREF="../format.html#metadata_block_padding">format specification</A>)
+ */
+typedef struct {
+	int dummy;
+	/**< Conceptually this is an empty struct since we don't store the
+	 * padding bytes.  Empty structs are not allowed by some C compilers,
+	 * hence the dummy.
+	 */
+} FLAC__StreamMetadata_Padding;
+
+
+/** FLAC APPLICATION structure.  (c.f. <A HREF="../format.html#metadata_block_application">format specification</A>)
+ */
+typedef struct {
+	FLAC__byte id[4];
+	FLAC__byte *data;
+} FLAC__StreamMetadata_Application;
+
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_APPLICATION_ID_LEN; /**< == 32 (bits) */
+
+/** SeekPoint structure used in SEEKTABLE blocks.  (c.f. <A HREF="../format.html#seekpoint">format specification</A>)
+ */
+typedef struct {
+	FLAC__uint64 sample_number;
+	/**<  The sample number of the target frame. */
+
+	FLAC__uint64 stream_offset;
+	/**< The offset, in bytes, of the target frame with respect to
+	 * beginning of the first frame. */
+
+	uint32_t frame_samples;
+	/**< The number of samples in the target frame. */
+} FLAC__StreamMetadata_SeekPoint;
+
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN; /**< == 64 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN; /**< == 64 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN; /**< == 16 (bits) */
+
+/** The total stream length of a seek point in bytes. */
+#define FLAC__STREAM_METADATA_SEEKPOINT_LENGTH (18u)
+
+/** The value used in the \a sample_number field of
+ *  FLAC__StreamMetadataSeekPoint used to indicate a placeholder
+ *  point (== 0xffffffffffffffff).
+ */
+extern FLAC_API const FLAC__uint64 FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+
+
+/** FLAC SEEKTABLE structure.  (c.f. <A HREF="../format.html#metadata_block_seektable">format specification</A>)
+ *
+ * \note From the format specification:
+ * - The seek points must be sorted by ascending sample number.
+ * - Each seek point's sample number must be the first sample of the
+ *   target frame.
+ * - Each seek point's sample number must be unique within the table.
+ * - Existence of a SEEKTABLE block implies a correct setting of
+ *   total_samples in the stream_info block.
+ * - Behavior is undefined when more than one SEEKTABLE block is
+ *   present in a stream.
+ */
+typedef struct {
+	uint32_t num_points;
+	FLAC__StreamMetadata_SeekPoint *points;
+} FLAC__StreamMetadata_SeekTable;
+
+
+/** Vorbis comment entry structure used in VORBIS_COMMENT blocks.  (c.f. <A HREF="../format.html#metadata_block_vorbis_comment">format specification</A>)
+ *
+ *  For convenience, the APIs maintain a trailing NUL character at the end of
+ *  \a entry which is not counted toward \a length, i.e.
+ *  \code strlen(entry) == length \endcode
+ */
+typedef struct {
+	FLAC__uint32 length;
+	FLAC__byte *entry;
+} FLAC__StreamMetadata_VorbisComment_Entry;
+
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN; /**< == 32 (bits) */
+
+
+/** FLAC VORBIS_COMMENT structure.  (c.f. <A HREF="../format.html#metadata_block_vorbis_comment">format specification</A>)
+ */
+typedef struct {
+	FLAC__StreamMetadata_VorbisComment_Entry vendor_string;
+	FLAC__uint32 num_comments;
+	FLAC__StreamMetadata_VorbisComment_Entry *comments;
+} FLAC__StreamMetadata_VorbisComment;
+
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN; /**< == 32 (bits) */
+
+
+/** FLAC CUESHEET track index structure.  (See the
+ * <A HREF="../format.html#cuesheet_track_index">format specification</A> for
+ * the full description of each field.)
+ */
+typedef struct {
+	FLAC__uint64 offset;
+	/**< Offset in samples, relative to the track offset, of the index
+	 * point.
+	 */
+
+	FLAC__byte number;
+	/**< The index point number. */
+} FLAC__StreamMetadata_CueSheet_Index;
+
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN; /**< == 64 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN; /**< == 8 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN; /**< == 3*8 (bits) */
+
+
+/** FLAC CUESHEET track structure.  (See the
+ * <A HREF="../format.html#cuesheet_track">format specification</A> for
+ * the full description of each field.)
+ */
+typedef struct {
+	FLAC__uint64 offset;
+	/**< Track offset in samples, relative to the beginning of the FLAC audio stream. */
+
+	FLAC__byte number;
+	/**< The track number. */
+
+	char isrc[13];
+	/**< Track ISRC.  This is a 12-digit alphanumeric code plus a trailing \c NUL byte */
+
+	uint32_t type:1;
+	/**< The track type: 0 for audio, 1 for non-audio. */
+
+	uint32_t pre_emphasis:1;
+	/**< The pre-emphasis flag: 0 for no pre-emphasis, 1 for pre-emphasis. */
+
+	FLAC__byte num_indices;
+	/**< The number of track index points. */
+
+	FLAC__StreamMetadata_CueSheet_Index *indices;
+	/**< NULL if num_indices == 0, else pointer to array of index points. */
+
+} FLAC__StreamMetadata_CueSheet_Track;
+
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN; /**< == 64 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN; /**< == 8 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN; /**< == 12*8 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN; /**< == 1 (bit) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN; /**< == 1 (bit) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN; /**< == 6+13*8 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN; /**< == 8 (bits) */
+
+
+/** FLAC CUESHEET structure.  (See the
+ * <A HREF="../format.html#metadata_block_cuesheet">format specification</A>
+ * for the full description of each field.)
+ */
+typedef struct {
+	char media_catalog_number[129];
+	/**< Media catalog number, in ASCII printable characters 0x20-0x7e.  In
+	 * general, the media catalog number may be 0 to 128 bytes long; any
+	 * unused characters should be right-padded with NUL characters.
+	 */
+
+	FLAC__uint64 lead_in;
+	/**< The number of lead-in samples. */
+
+	FLAC__bool is_cd;
+	/**< \c true if CUESHEET corresponds to a Compact Disc, else \c false. */
+
+	uint32_t num_tracks;
+	/**< The number of tracks. */
+
+	FLAC__StreamMetadata_CueSheet_Track *tracks;
+	/**< NULL if num_tracks == 0, else pointer to array of tracks. */
+
+} FLAC__StreamMetadata_CueSheet;
+
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN; /**< == 128*8 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN; /**< == 64 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN; /**< == 1 (bit) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN; /**< == 7+258*8 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN; /**< == 8 (bits) */
+
+
+/** An enumeration of the PICTURE types (see FLAC__StreamMetadataPicture and id3 v2.4 APIC tag). */
+typedef enum {
+	FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER = 0, /**< Other */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD = 1, /**< 32x32 pixels 'file icon' (PNG only) */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON = 2, /**< Other file icon */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER = 3, /**< Cover (front) */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_BACK_COVER = 4, /**< Cover (back) */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_LEAFLET_PAGE = 5, /**< Leaflet page */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_MEDIA = 6, /**< Media (e.g. label side of CD) */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_LEAD_ARTIST = 7, /**< Lead artist/lead performer/soloist */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_ARTIST = 8, /**< Artist/performer */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_CONDUCTOR = 9, /**< Conductor */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_BAND = 10, /**< Band/Orchestra */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_COMPOSER = 11, /**< Composer */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_LYRICIST = 12, /**< Lyricist/text writer */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_RECORDING_LOCATION = 13, /**< Recording Location */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_DURING_RECORDING = 14, /**< During recording */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_DURING_PERFORMANCE = 15, /**< During performance */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_VIDEO_SCREEN_CAPTURE = 16, /**< Movie/video screen capture */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_FISH = 17, /**< A bright coloured fish */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_ILLUSTRATION = 18, /**< Illustration */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_BAND_LOGOTYPE = 19, /**< Band/artist logotype */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_PUBLISHER_LOGOTYPE = 20, /**< Publisher/Studio logotype */
+	FLAC__STREAM_METADATA_PICTURE_TYPE_UNDEFINED
+} FLAC__StreamMetadata_Picture_Type;
+
+/** Maps a FLAC__StreamMetadata_Picture_Type to a C string.
+ *
+ *  Using a FLAC__StreamMetadata_Picture_Type as the index to this array
+ *  will give the string equivalent.  The contents should not be
+ *  modified.
+ */
+extern FLAC_API const char * const FLAC__StreamMetadata_Picture_TypeString[];
+
+/** FLAC PICTURE structure.  (See the
+ * <A HREF="../format.html#metadata_block_picture">format specification</A>
+ * for the full description of each field.)
+ */
+typedef struct {
+	FLAC__StreamMetadata_Picture_Type type;
+	/**< The kind of picture stored. */
+
+	char *mime_type;
+	/**< Picture data's MIME type, in ASCII printable characters
+	 * 0x20-0x7e, NUL terminated.  For best compatibility with players,
+	 * use picture data of MIME type \c image/jpeg or \c image/png.  A
+	 * MIME type of '-->' is also allowed, in which case the picture
+	 * data should be a complete URL.  In file storage, the MIME type is
+	 * stored as a 32-bit length followed by the ASCII string with no NUL
+	 * terminator, but is converted to a plain C string in this structure
+	 * for convenience.
+	 */
+
+	FLAC__byte *description;
+	/**< Picture's description in UTF-8, NUL terminated.  In file storage,
+	 * the description is stored as a 32-bit length followed by the UTF-8
+	 * string with no NUL terminator, but is converted to a plain C string
+	 * in this structure for convenience.
+	 */
+
+	FLAC__uint32 width;
+	/**< Picture's width in pixels. */
+
+	FLAC__uint32 height;
+	/**< Picture's height in pixels. */
+
+	FLAC__uint32 depth;
+	/**< Picture's color depth in bits-per-pixel. */
+
+	FLAC__uint32 colors;
+	/**< For indexed palettes (like GIF), picture's number of colors (the
+	 * number of palette entries), or \c 0 for non-indexed (i.e. 2^depth).
+	 */
+
+	FLAC__uint32 data_length;
+	/**< Length of binary picture data in bytes. */
+
+	FLAC__byte *data;
+	/**< Binary picture data. */
+
+} FLAC__StreamMetadata_Picture;
+
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_TYPE_LEN; /**< == 32 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN; /**< == 32 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN; /**< == 32 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN; /**< == 32 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN; /**< == 32 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN; /**< == 32 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_COLORS_LEN; /**< == 32 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN; /**< == 32 (bits) */
+
+
+/** Structure that is used when a metadata block of unknown type is loaded.
+ *  The contents are opaque.  The structure is used only internally to
+ *  correctly handle unknown metadata.
+ */
+typedef struct {
+	FLAC__byte *data;
+} FLAC__StreamMetadata_Unknown;
+
+
+/** FLAC metadata block structure.  (c.f. <A HREF="../format.html#metadata_block">format specification</A>)
+ */
+typedef struct {
+	FLAC__MetadataType type;
+	/**< The type of the metadata block; used determine which member of the
+	 * \a data union to dereference.  If type >= FLAC__METADATA_TYPE_UNDEFINED
+	 * then \a data.unknown must be used. */
+
+	FLAC__bool is_last;
+	/**< \c true if this metadata block is the last, else \a false */
+
+	uint32_t length;
+	/**< Length, in bytes, of the block data as it appears in the stream. */
+
+	union {
+		FLAC__StreamMetadata_StreamInfo stream_info;
+		FLAC__StreamMetadata_Padding padding;
+		FLAC__StreamMetadata_Application application;
+		FLAC__StreamMetadata_SeekTable seek_table;
+		FLAC__StreamMetadata_VorbisComment vorbis_comment;
+		FLAC__StreamMetadata_CueSheet cue_sheet;
+		FLAC__StreamMetadata_Picture picture;
+		FLAC__StreamMetadata_Unknown unknown;
+	} data;
+	/**< Polymorphic block data; use the \a type value to determine which
+	 * to use. */
+} FLAC__StreamMetadata;
+
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_IS_LAST_LEN; /**< == 1 (bit) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_TYPE_LEN; /**< == 7 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_LENGTH_LEN; /**< == 24 (bits) */
+
+/** The total stream length of a metadata block header in bytes. */
+#define FLAC__STREAM_METADATA_HEADER_LENGTH (4u)
+
+/*****************************************************************************/
+
+
+/*****************************************************************************
+ *
+ * Utility functions
+ *
+ *****************************************************************************/
+
+/** Tests that a sample rate is valid for FLAC.
+ *
+ * \param sample_rate  The sample rate to test for compliance.
+ * \retval FLAC__bool
+ *    \c true if the given sample rate conforms to the specification, else
+ *    \c false.
+ */
+FLAC_API FLAC__bool FLAC__format_sample_rate_is_valid(uint32_t sample_rate);
+
+/** Tests that a blocksize at the given sample rate is valid for the FLAC
+ *  subset.
+ *
+ * \param blocksize    The blocksize to test for compliance.
+ * \param sample_rate  The sample rate is needed, since the valid subset
+ *                     blocksize depends on the sample rate.
+ * \retval FLAC__bool
+ *    \c true if the given blocksize conforms to the specification for the
+ *    subset at the given sample rate, else \c false.
+ */
+FLAC_API FLAC__bool FLAC__format_blocksize_is_subset(uint32_t blocksize, uint32_t sample_rate);
+
+/** Tests that a sample rate is valid for the FLAC subset.  The subset rules
+ *  for valid sample rates are slightly more complex since the rate has to
+ *  be expressible completely in the frame header.
+ *
+ * \param sample_rate  The sample rate to test for compliance.
+ * \retval FLAC__bool
+ *    \c true if the given sample rate conforms to the specification for the
+ *    subset, else \c false.
+ */
+FLAC_API FLAC__bool FLAC__format_sample_rate_is_subset(uint32_t sample_rate);
+
+/** Check a Vorbis comment entry name to see if it conforms to the Vorbis
+ *  comment specification.
+ *
+ *  Vorbis comment names must be composed only of characters from
+ *  [0x20-0x3C,0x3E-0x7D].
+ *
+ * \param name       A NUL-terminated string to be checked.
+ * \assert
+ *    \code name != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if entry name is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_name_is_legal(const char *name);
+
+/** Check a Vorbis comment entry value to see if it conforms to the Vorbis
+ *  comment specification.
+ *
+ *  Vorbis comment values must be valid UTF-8 sequences.
+ *
+ * \param value      A string to be checked.
+ * \param length     A the length of \a value in bytes.  May be
+ *                   \c (uint32_t)(-1) to indicate that \a value is a plain
+ *                   UTF-8 NUL-terminated string.
+ * \assert
+ *    \code value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if entry name is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_value_is_legal(const FLAC__byte *value, uint32_t length);
+
+/** Check a Vorbis comment entry to see if it conforms to the Vorbis
+ *  comment specification.
+ *
+ *  Vorbis comment entries must be of the form 'name=value', and 'name' and
+ *  'value' must be legal according to
+ *  FLAC__format_vorbiscomment_entry_name_is_legal() and
+ *  FLAC__format_vorbiscomment_entry_value_is_legal() respectively.
+ *
+ * \param entry      An entry to be checked.
+ * \param length     The length of \a entry in bytes.
+ * \assert
+ *    \code value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if entry name is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_is_legal(const FLAC__byte *entry, uint32_t length);
+
+/** Check a seek table to see if it conforms to the FLAC specification.
+ *  See the format specification for limits on the contents of the
+ *  seek table.
+ *
+ * \param seek_table  A pointer to a seek table to be checked.
+ * \assert
+ *    \code seek_table != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if seek table is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__format_seektable_is_legal(const FLAC__StreamMetadata_SeekTable *seek_table);
+
+/** Sort a seek table's seek points according to the format specification.
+ *  This includes a "unique-ification" step to remove duplicates, i.e.
+ *  seek points with identical \a sample_number values.  Duplicate seek
+ *  points are converted into placeholder points and sorted to the end of
+ *  the table.
+ *
+ * \param seek_table  A pointer to a seek table to be sorted.
+ * \assert
+ *    \code seek_table != NULL \endcode
+ * \retval uint32_t
+ *    The number of duplicate seek points converted into placeholders.
+ */
+FLAC_API uint32_t FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *seek_table);
+
+/** Check a cue sheet to see if it conforms to the FLAC specification.
+ *  See the format specification for limits on the contents of the
+ *  cue sheet.
+ *
+ * \param cue_sheet  A pointer to an existing cue sheet to be checked.
+ * \param check_cd_da_subset  If \c true, check CUESHEET against more
+ *                   stringent requirements for a CD-DA (audio) disc.
+ * \param violation  Address of a pointer to a string.  If there is a
+ *                   violation, a pointer to a string explanation of the
+ *                   violation will be returned here. \a violation may be
+ *                   \c NULL if you don't need the returned string.  Do not
+ *                   free the returned string; it will always point to static
+ *                   data.
+ * \assert
+ *    \code cue_sheet != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if cue sheet is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__format_cuesheet_is_legal(const FLAC__StreamMetadata_CueSheet *cue_sheet, FLAC__bool check_cd_da_subset, const char **violation);
+
+/** Check picture data to see if it conforms to the FLAC specification.
+ *  See the format specification for limits on the contents of the
+ *  PICTURE block.
+ *
+ * \param picture    A pointer to existing picture data to be checked.
+ * \param violation  Address of a pointer to a string.  If there is a
+ *                   violation, a pointer to a string explanation of the
+ *                   violation will be returned here. \a violation may be
+ *                   \c NULL if you don't need the returned string.  Do not
+ *                   free the returned string; it will always point to static
+ *                   data.
+ * \assert
+ *    \code picture != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if picture data is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__format_picture_is_legal(const FLAC__StreamMetadata_Picture *picture, const char **violation);
+
+/* \} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+++ b/src/libflac/FLAC/metadata.h
@@ -1,0 +1,2182 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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.
+ */
+
+#ifndef FLAC__METADATA_H
+#define FLAC__METADATA_H
+
+#include <sys/types.h> /* for off_t */
+#include "export.h"
+#include "callback.h"
+#include "format.h"
+
+/* --------------------------------------------------------------------
+   (For an example of how all these routines are used, see the source
+   code for the unit tests in src/test_libFLAC/metadata_*.c, or
+   metaflac in src/metaflac/)
+   ------------------------------------------------------------------*/
+
+/** \file include/FLAC/metadata.h
+ *
+ *  \brief
+ *  This module provides functions for creating and manipulating FLAC
+ *  metadata blocks in memory, and three progressively more powerful
+ *  interfaces for traversing and editing metadata in FLAC files.
+ *
+ *  See the detailed documentation for each interface in the
+ *  \link flac_metadata metadata \endlink module.
+ */
+
+/** \defgroup flac_metadata FLAC/metadata.h: metadata interfaces
+ *  \ingroup flac
+ *
+ *  \brief
+ *  This module provides functions for creating and manipulating FLAC
+ *  metadata blocks in memory, and three progressively more powerful
+ *  interfaces for traversing and editing metadata in native FLAC files.
+ *  Note that currently only the Chain interface (level 2) supports Ogg
+ *  FLAC files, and it is read-only i.e. no writing back changed
+ *  metadata to file.
+ *
+ *  There are three metadata interfaces of increasing complexity:
+ *
+ *  Level 0:
+ *  Read-only access to the STREAMINFO, VORBIS_COMMENT, CUESHEET, and
+ *  PICTURE blocks.
+ *
+ *  Level 1:
+ *  Read-write access to all metadata blocks.  This level is write-
+ *  efficient in most cases (more on this below), and uses less memory
+ *  than level 2.
+ *
+ *  Level 2:
+ *  Read-write access to all metadata blocks.  This level is write-
+ *  efficient in all cases, but uses more memory since all metadata for
+ *  the whole file is read into memory and manipulated before writing
+ *  out again.
+ *
+ *  What do we mean by efficient?  Since FLAC metadata appears at the
+ *  beginning of the file, when writing metadata back to a FLAC file
+ *  it is possible to grow or shrink the metadata such that the entire
+ *  file must be rewritten.  However, if the size remains the same during
+ *  changes or PADDING blocks are utilized, only the metadata needs to be
+ *  overwritten, which is much faster.
+ *
+ *  Efficient means the whole file is rewritten at most one time, and only
+ *  when necessary.  Level 1 is not efficient only in the case that you
+ *  cause more than one metadata block to grow or shrink beyond what can
+ *  be accommodated by padding.  In this case you should probably use level
+ *  2, which allows you to edit all the metadata for a file in memory and
+ *  write it out all at once.
+ *
+ *  All levels know how to skip over and not disturb an ID3v2 tag at the
+ *  front of the file.
+ *
+ *  All levels access files via their filenames.  In addition, level 2
+ *  has additional alternative read and write functions that take an I/O
+ *  handle and callbacks, for situations where access by filename is not
+ *  possible.
+ *
+ *  In addition to the three interfaces, this module defines functions for
+ *  creating and manipulating various metadata objects in memory.  As we see
+ *  from the Format module, FLAC metadata blocks in memory are very primitive
+ *  structures for storing information in an efficient way.  Reading
+ *  information from the structures is easy but creating or modifying them
+ *  directly is more complex.  The metadata object routines here facilitate
+ *  this by taking care of the consistency and memory management drudgery.
+ *
+ *  Unless you will be using the level 1 or 2 interfaces to modify existing
+ *  metadata however, you will not probably not need these.
+ *
+ *  From a dependency standpoint, none of the encoders or decoders require
+ *  the metadata module.  This is so that embedded users can strip out the
+ *  metadata module from libFLAC to reduce the size and complexity.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** \defgroup flac_metadata_level0 FLAC/metadata.h: metadata level 0 interface
+ *  \ingroup flac_metadata
+ *
+ *  \brief
+ *  The level 0 interface consists of individual routines to read the
+ *  STREAMINFO, VORBIS_COMMENT, CUESHEET, and PICTURE blocks, requiring
+ *  only a filename.
+ *
+ *  They try to skip any ID3v2 tag at the head of the file.
+ *
+ * \{
+ */
+
+/** Read the STREAMINFO metadata block of the given FLAC file.  This function
+ *  will try to skip any ID3v2 tag at the head of the file.
+ *
+ * \param filename    The path to the FLAC file to read.
+ * \param streaminfo  A pointer to space for the STREAMINFO block.  Since
+ *                    FLAC__StreamMetadata is a simple structure with no
+ *                    memory allocation involved, you pass the address of
+ *                    an existing structure.  It need not be initialized.
+ * \assert
+ *    \code filename != NULL \endcode
+ *    \code streaminfo != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if a valid STREAMINFO block was read from \a filename.  Returns
+ *    \c false if there was a memory allocation error, a file decoder error,
+ *    or the file contained no STREAMINFO block.  (A memory allocation error
+ *    is possible because this function must set up a file decoder.)
+ */
+FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__StreamMetadata *streaminfo);
+
+/** Read the VORBIS_COMMENT metadata block of the given FLAC file.  This
+ *  function will try to skip any ID3v2 tag at the head of the file.
+ *
+ * \param filename    The path to the FLAC file to read.
+ * \param tags        The address where the returned pointer will be
+ *                    stored.  The \a tags object must be deleted by
+ *                    the caller using FLAC__metadata_object_delete().
+ * \assert
+ *    \code filename != NULL \endcode
+ *    \code tags != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if a valid VORBIS_COMMENT block was read from \a filename,
+ *    and \a *tags will be set to the address of the metadata structure.
+ *    Returns \c false if there was a memory allocation error, a file
+ *    decoder error, or the file contained no VORBIS_COMMENT block, and
+ *    \a *tags will be set to \c NULL.
+ */
+FLAC_API FLAC__bool FLAC__metadata_get_tags(const char *filename, FLAC__StreamMetadata **tags);
+
+/** Read the CUESHEET metadata block of the given FLAC file.  This
+ *  function will try to skip any ID3v2 tag at the head of the file.
+ *
+ * \param filename    The path to the FLAC file to read.
+ * \param cuesheet    The address where the returned pointer will be
+ *                    stored.  The \a cuesheet object must be deleted by
+ *                    the caller using FLAC__metadata_object_delete().
+ * \assert
+ *    \code filename != NULL \endcode
+ *    \code cuesheet != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if a valid CUESHEET block was read from \a filename,
+ *    and \a *cuesheet will be set to the address of the metadata
+ *    structure.  Returns \c false if there was a memory allocation
+ *    error, a file decoder error, or the file contained no CUESHEET
+ *    block, and \a *cuesheet will be set to \c NULL.
+ */
+FLAC_API FLAC__bool FLAC__metadata_get_cuesheet(const char *filename, FLAC__StreamMetadata **cuesheet);
+
+/** Read a PICTURE metadata block of the given FLAC file.  This
+ *  function will try to skip any ID3v2 tag at the head of the file.
+ *  Since there can be more than one PICTURE block in a file, this
+ *  function takes a number of parameters that act as constraints to
+ *  the search.  The PICTURE block with the largest area matching all
+ *  the constraints will be returned, or \a *picture will be set to
+ *  \c NULL if there was no such block.
+ *
+ * \param filename    The path to the FLAC file to read.
+ * \param picture     The address where the returned pointer will be
+ *                    stored.  The \a picture object must be deleted by
+ *                    the caller using FLAC__metadata_object_delete().
+ * \param type        The desired picture type.  Use \c -1 to mean
+ *                    "any type".
+ * \param mime_type   The desired MIME type, e.g. "image/jpeg".  The
+ *                    string will be matched exactly.  Use \c NULL to
+ *                    mean "any MIME type".
+ * \param description The desired description.  The string will be
+ *                    matched exactly.  Use \c NULL to mean "any
+ *                    description".
+ * \param max_width   The maximum width in pixels desired.  Use
+ *                    \c (uint32_t)(-1) to mean "any width".
+ * \param max_height  The maximum height in pixels desired.  Use
+ *                    \c (uint32_t)(-1) to mean "any height".
+ * \param max_depth   The maximum color depth in bits-per-pixel desired.
+ *                    Use \c (uint32_t)(-1) to mean "any depth".
+ * \param max_colors  The maximum number of colors desired.  Use
+ *                    \c (uint32_t)(-1) to mean "any number of colors".
+ * \assert
+ *    \code filename != NULL \endcode
+ *    \code picture != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if a valid PICTURE block was read from \a filename,
+ *    and \a *picture will be set to the address of the metadata
+ *    structure.  Returns \c false if there was a memory allocation
+ *    error, a file decoder error, or the file contained no PICTURE
+ *    block, and \a *picture will be set to \c NULL.
+ */
+FLAC_API FLAC__bool FLAC__metadata_get_picture(const char *filename, FLAC__StreamMetadata **picture, FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, uint32_t max_width, uint32_t max_height, uint32_t max_depth, uint32_t max_colors);
+
+/* \} */
+
+
+/** \defgroup flac_metadata_level1 FLAC/metadata.h: metadata level 1 interface
+ *  \ingroup flac_metadata
+ *
+ * \brief
+ * The level 1 interface provides read-write access to FLAC file metadata and
+ * operates directly on the FLAC file.
+ *
+ * The general usage of this interface is:
+ *
+ * - Create an iterator using FLAC__metadata_simple_iterator_new()
+ * - Attach it to a file using FLAC__metadata_simple_iterator_init() and check
+ *   the exit code.  Call FLAC__metadata_simple_iterator_is_writable() to
+ *   see if the file is writable, or only read access is allowed.
+ * - Use FLAC__metadata_simple_iterator_next() and
+ *   FLAC__metadata_simple_iterator_prev() to traverse the blocks.
+ *   This is does not read the actual blocks themselves.
+ *   FLAC__metadata_simple_iterator_next() is relatively fast.
+ *   FLAC__metadata_simple_iterator_prev() is slower since it needs to search
+ *   forward from the front of the file.
+ * - Use FLAC__metadata_simple_iterator_get_block_type() or
+ *   FLAC__metadata_simple_iterator_get_block() to access the actual data at
+ *   the current iterator position.  The returned object is yours to modify
+ *   and free.
+ * - Use FLAC__metadata_simple_iterator_set_block() to write a modified block
+ *   back.  You must have write permission to the original file.  Make sure to
+ *   read the whole comment to FLAC__metadata_simple_iterator_set_block()
+ *   below.
+ * - Use FLAC__metadata_simple_iterator_insert_block_after() to add new blocks.
+ *   Use the object creation functions from
+ *   \link flac_metadata_object here \endlink to generate new objects.
+ * - Use FLAC__metadata_simple_iterator_delete_block() to remove the block
+ *   currently referred to by the iterator, or replace it with padding.
+ * - Destroy the iterator with FLAC__metadata_simple_iterator_delete() when
+ *   finished.
+ *
+ * \note
+ * The FLAC file remains open the whole time between
+ * FLAC__metadata_simple_iterator_init() and
+ * FLAC__metadata_simple_iterator_delete(), so make sure you are not altering
+ * the file during this time.
+ *
+ * \note
+ * Do not modify the \a is_last, \a length, or \a type fields of returned
+ * FLAC__StreamMetadata objects.  These are managed automatically.
+ *
+ * \note
+ * If any of the modification functions
+ * (FLAC__metadata_simple_iterator_set_block(),
+ * FLAC__metadata_simple_iterator_delete_block(),
+ * FLAC__metadata_simple_iterator_insert_block_after(), etc.) return \c false,
+ * you should delete the iterator as it may no longer be valid.
+ *
+ * \{
+ */
+
+struct FLAC__Metadata_SimpleIterator;
+/** The opaque structure definition for the level 1 iterator type.
+ *  See the
+ *  \link flac_metadata_level1 metadata level 1 module \endlink
+ *  for a detailed description.
+ */
+typedef struct FLAC__Metadata_SimpleIterator FLAC__Metadata_SimpleIterator;
+
+/** Status type for FLAC__Metadata_SimpleIterator.
+ *
+ *  The iterator's current status can be obtained by calling FLAC__metadata_simple_iterator_status().
+ */
+typedef enum {
+
+	FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK = 0,
+	/**< The iterator is in the normal OK state */
+
+	FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT,
+	/**< The data passed into a function violated the function's usage criteria */
+
+	FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE,
+	/**< The iterator could not open the target file */
+
+	FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE,
+	/**< The iterator could not find the FLAC signature at the start of the file */
+
+	FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE,
+	/**< The iterator tried to write to a file that was not writable */
+
+	FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA,
+	/**< The iterator encountered input that does not conform to the FLAC metadata specification */
+
+	FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR,
+	/**< The iterator encountered an error while reading the FLAC file */
+
+	FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR,
+	/**< The iterator encountered an error while seeking in the FLAC file */
+
+	FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR,
+	/**< The iterator encountered an error while writing the FLAC file */
+
+	FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR,
+	/**< The iterator encountered an error renaming the FLAC file */
+
+	FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR,
+	/**< The iterator encountered an error removing the temporary file */
+
+	FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR,
+	/**< Memory allocation failed */
+
+	FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR
+	/**< The caller violated an assertion or an unexpected error occurred */
+
+} FLAC__Metadata_SimpleIteratorStatus;
+
+/** Maps a FLAC__Metadata_SimpleIteratorStatus to a C string.
+ *
+ *  Using a FLAC__Metadata_SimpleIteratorStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__Metadata_SimpleIteratorStatusString[];
+
+
+/** Create a new iterator instance.
+ *
+ * \retval FLAC__Metadata_SimpleIterator*
+ *    \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__Metadata_SimpleIterator *FLAC__metadata_simple_iterator_new(void);
+
+/** Free an iterator instance.  Deletes the object pointed to by \a iterator.
+ *
+ * \param iterator  A pointer to an existing iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_simple_iterator_delete(FLAC__Metadata_SimpleIterator *iterator);
+
+/** Get the current status of the iterator.  Call this after a function
+ *  returns \c false to get the reason for the error.  Also resets the status
+ *  to FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK.
+ *
+ * \param iterator  A pointer to an existing iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ * \retval FLAC__Metadata_SimpleIteratorStatus
+ *    The current status of the iterator.
+ */
+FLAC_API FLAC__Metadata_SimpleIteratorStatus FLAC__metadata_simple_iterator_status(FLAC__Metadata_SimpleIterator *iterator);
+
+/** Initialize the iterator to point to the first metadata block in the
+ *  given FLAC file.
+ *
+ * \param iterator             A pointer to an existing iterator.
+ * \param filename             The path to the FLAC file.
+ * \param read_only            If \c true, the FLAC file will be opened
+ *                             in read-only mode; if \c false, the FLAC
+ *                             file will be opened for edit even if no
+ *                             edits are performed.
+ * \param preserve_file_stats  If \c true, the owner and modification
+ *                             time will be preserved even if the FLAC
+ *                             file is written to.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \code filename != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if a memory allocation error occurs, the file can't be
+ *    opened, or another error occurs, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_init(FLAC__Metadata_SimpleIterator *iterator, const char *filename, FLAC__bool read_only, FLAC__bool preserve_file_stats);
+
+/** Returns \c true if the FLAC file is writable.  If \c false, calls to
+ *  FLAC__metadata_simple_iterator_set_block() and
+ *  FLAC__metadata_simple_iterator_insert_block_after() will fail.
+ *
+ * \param iterator             A pointer to an existing iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ * \retval FLAC__bool
+ *    See above.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_writable(const FLAC__Metadata_SimpleIterator *iterator);
+
+/** Moves the iterator forward one metadata block, returning \c false if
+ *  already at the end.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_simple_iterator_init()
+ * \retval FLAC__bool
+ *    \c false if already at the last metadata block of the chain, else
+ *    \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_next(FLAC__Metadata_SimpleIterator *iterator);
+
+/** Moves the iterator backward one metadata block, returning \c false if
+ *  already at the beginning.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_simple_iterator_init()
+ * \retval FLAC__bool
+ *    \c false if already at the first metadata block of the chain, else
+ *    \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_prev(FLAC__Metadata_SimpleIterator *iterator);
+
+/** Returns a flag telling if the current metadata block is the last.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_simple_iterator_init()
+ * \retval FLAC__bool
+ *    \c true if the current metadata block is the last in the file,
+ *    else \c false.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_last(const FLAC__Metadata_SimpleIterator *iterator);
+
+/** Get the offset of the metadata block at the current position.  This
+ *  avoids reading the actual block data which can save time for large
+ *  blocks.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_simple_iterator_init()
+ * \retval off_t
+ *    The offset of the metadata block at the current iterator position.
+ *    This is the byte offset relative to the beginning of the file of
+ *    the current metadata block's header.
+ */
+FLAC_API off_t FLAC__metadata_simple_iterator_get_block_offset(const FLAC__Metadata_SimpleIterator *iterator);
+
+/** Get the type of the metadata block at the current position.  This
+ *  avoids reading the actual block data which can save time for large
+ *  blocks.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_simple_iterator_init()
+ * \retval FLAC__MetadataType
+ *    The type of the metadata block at the current iterator position.
+ */
+FLAC_API FLAC__MetadataType FLAC__metadata_simple_iterator_get_block_type(const FLAC__Metadata_SimpleIterator *iterator);
+
+/** Get the length of the metadata block at the current position.  This
+ *  avoids reading the actual block data which can save time for large
+ *  blocks.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_simple_iterator_init()
+ * \retval uint32_t
+ *    The length of the metadata block at the current iterator position.
+ *    The is same length as that in the
+ *    <a href="http://xiph.org/flac/format.html#metadata_block_header">metadata block header</a>,
+ *    i.e. the length of the metadata body that follows the header.
+ */
+FLAC_API uint32_t FLAC__metadata_simple_iterator_get_block_length(const FLAC__Metadata_SimpleIterator *iterator);
+
+/** Get the application ID of the \c APPLICATION block at the current
+ *  position.  This avoids reading the actual block data which can save
+ *  time for large blocks.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \param id        A pointer to a buffer of at least \c 4 bytes where
+ *                  the ID will be stored.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \code id != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_simple_iterator_init()
+ * \retval FLAC__bool
+ *    \c true if the ID was successfully read, else \c false, in which
+ *    case you should check FLAC__metadata_simple_iterator_status() to
+ *    find out why.  If the status is
+ *    \c FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT, then the
+ *    current metadata block is not an \c APPLICATION block.  Otherwise
+ *    if the status is
+ *    \c FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR or
+ *    \c FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR, an I/O error
+ *    occurred and the iterator can no longer be used.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_get_application_id(FLAC__Metadata_SimpleIterator *iterator, FLAC__byte *id);
+
+/** Get the metadata block at the current position.  You can modify the
+ *  block but must use FLAC__metadata_simple_iterator_set_block() to
+ *  write it back to the FLAC file.
+ *
+ *  You must call FLAC__metadata_object_delete() on the returned object
+ *  when you are finished with it.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_simple_iterator_init()
+ * \retval FLAC__StreamMetadata*
+ *    The current metadata block, or \c NULL if there was a memory
+ *    allocation error.
+ */
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_simple_iterator_get_block(FLAC__Metadata_SimpleIterator *iterator);
+
+/** Write a block back to the FLAC file.  This function tries to be
+ *  as efficient as possible; how the block is actually written is
+ *  shown by the following:
+ *
+ *  Existing block is a STREAMINFO block and the new block is a
+ *  STREAMINFO block: the new block is written in place.  Make sure
+ *  you know what you're doing when changing the values of a
+ *  STREAMINFO block.
+ *
+ *  Existing block is a STREAMINFO block and the new block is a
+ *  not a STREAMINFO block: this is an error since the first block
+ *  must be a STREAMINFO block.  Returns \c false without altering the
+ *  file.
+ *
+ *  Existing block is not a STREAMINFO block and the new block is a
+ *  STREAMINFO block: this is an error since there may be only one
+ *  STREAMINFO block.  Returns \c false without altering the file.
+ *
+ *  Existing block and new block are the same length: the existing
+ *  block will be replaced by the new block, written in place.
+ *
+ *  Existing block is longer than new block: if use_padding is \c true,
+ *  the existing block will be overwritten in place with the new
+ *  block followed by a PADDING block, if possible, to make the total
+ *  size the same as the existing block.  Remember that a padding
+ *  block requires at least four bytes so if the difference in size
+ *  between the new block and existing block is less than that, the
+ *  entire file will have to be rewritten, using the new block's
+ *  exact size.  If use_padding is \c false, the entire file will be
+ *  rewritten, replacing the existing block by the new block.
+ *
+ *  Existing block is shorter than new block: if use_padding is \c true,
+ *  the function will try and expand the new block into the following
+ *  PADDING block, if it exists and doing so won't shrink the PADDING
+ *  block to less than 4 bytes.  If there is no following PADDING
+ *  block, or it will shrink to less than 4 bytes, or use_padding is
+ *  \c false, the entire file is rewritten, replacing the existing block
+ *  with the new block.  Note that in this case any following PADDING
+ *  block is preserved as is.
+ *
+ *  After writing the block, the iterator will remain in the same
+ *  place, i.e. pointing to the new block.
+ *
+ * \param iterator     A pointer to an existing initialized iterator.
+ * \param block        The block to set.
+ * \param use_padding  See above.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_simple_iterator_init()
+ *    \code block != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if successful, else \c false.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_set_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding);
+
+/** This is similar to FLAC__metadata_simple_iterator_set_block()
+ *  except that instead of writing over an existing block, it appends
+ *  a block after the existing block.  \a use_padding is again used to
+ *  tell the function to try an expand into following padding in an
+ *  attempt to avoid rewriting the entire file.
+ *
+ *  This function will fail and return \c false if given a STREAMINFO
+ *  block.
+ *
+ *  After writing the block, the iterator will be pointing to the
+ *  new block.
+ *
+ * \param iterator     A pointer to an existing initialized iterator.
+ * \param block        The block to set.
+ * \param use_padding  See above.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_simple_iterator_init()
+ *    \code block != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if successful, else \c false.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_insert_block_after(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding);
+
+/** Deletes the block at the current position.  This will cause the
+ *  entire FLAC file to be rewritten, unless \a use_padding is \c true,
+ *  in which case the block will be replaced by an equal-sized PADDING
+ *  block.  The iterator will be left pointing to the block before the
+ *  one just deleted.
+ *
+ *  You may not delete the STREAMINFO block.
+ *
+ * \param iterator     A pointer to an existing initialized iterator.
+ * \param use_padding  See above.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_simple_iterator_init()
+ * \retval FLAC__bool
+ *    \c true if successful, else \c false.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_delete_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__bool use_padding);
+
+/* \} */
+
+
+/** \defgroup flac_metadata_level2 FLAC/metadata.h: metadata level 2 interface
+ *  \ingroup flac_metadata
+ *
+ * \brief
+ * The level 2 interface provides read-write access to FLAC file metadata;
+ * all metadata is read into memory, operated on in memory, and then written
+ * to file, which is more efficient than level 1 when editing multiple blocks.
+ *
+ * Currently Ogg FLAC is supported for read only, via
+ * FLAC__metadata_chain_read_ogg() but a subsequent
+ * FLAC__metadata_chain_write() will fail.
+ *
+ * The general usage of this interface is:
+ *
+ * - Create a new chain using FLAC__metadata_chain_new().  A chain is a
+ *   linked list of FLAC metadata blocks.
+ * - Read all metadata into the chain from a FLAC file using
+ *   FLAC__metadata_chain_read() or FLAC__metadata_chain_read_ogg() and
+ *   check the status.
+ * - Optionally, consolidate the padding using
+ *   FLAC__metadata_chain_merge_padding() or
+ *   FLAC__metadata_chain_sort_padding().
+ * - Create a new iterator using FLAC__metadata_iterator_new()
+ * - Initialize the iterator to point to the first element in the chain
+ *   using FLAC__metadata_iterator_init()
+ * - Traverse the chain using FLAC__metadata_iterator_next and
+ *   FLAC__metadata_iterator_prev().
+ * - Get a block for reading or modification using
+ *   FLAC__metadata_iterator_get_block().  The pointer to the object
+ *   inside the chain is returned, so the block is yours to modify.
+ *   Changes will be reflected in the FLAC file when you write the
+ *   chain.  You can also add and delete blocks (see functions below).
+ * - When done, write out the chain using FLAC__metadata_chain_write().
+ *   Make sure to read the whole comment to the function below.
+ * - Delete the chain using FLAC__metadata_chain_delete().
+ *
+ * \note
+ * Even though the FLAC file is not open while the chain is being
+ * manipulated, you must not alter the file externally during
+ * this time.  The chain assumes the FLAC file will not change
+ * between the time of FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg()
+ * and FLAC__metadata_chain_write().
+ *
+ * \note
+ * Do not modify the is_last, length, or type fields of returned
+ * FLAC__StreamMetadata objects.  These are managed automatically.
+ *
+ * \note
+ * The metadata objects returned by FLAC__metadata_iterator_get_block()
+ * are owned by the chain; do not FLAC__metadata_object_delete() them.
+ * In the same way, blocks passed to FLAC__metadata_iterator_set_block()
+ * become owned by the chain and they will be deleted when the chain is
+ * deleted.
+ *
+ * \{
+ */
+
+struct FLAC__Metadata_Chain;
+/** The opaque structure definition for the level 2 chain type.
+ */
+typedef struct FLAC__Metadata_Chain FLAC__Metadata_Chain;
+
+struct FLAC__Metadata_Iterator;
+/** The opaque structure definition for the level 2 iterator type.
+ */
+typedef struct FLAC__Metadata_Iterator FLAC__Metadata_Iterator;
+
+typedef enum {
+	FLAC__METADATA_CHAIN_STATUS_OK = 0,
+	/**< The chain is in the normal OK state */
+
+	FLAC__METADATA_CHAIN_STATUS_ILLEGAL_INPUT,
+	/**< The data passed into a function violated the function's usage criteria */
+
+	FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE,
+	/**< The chain could not open the target file */
+
+	FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE,
+	/**< The chain could not find the FLAC signature at the start of the file */
+
+	FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE,
+	/**< The chain tried to write to a file that was not writable */
+
+	FLAC__METADATA_CHAIN_STATUS_BAD_METADATA,
+	/**< The chain encountered input that does not conform to the FLAC metadata specification */
+
+	FLAC__METADATA_CHAIN_STATUS_READ_ERROR,
+	/**< The chain encountered an error while reading the FLAC file */
+
+	FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR,
+	/**< The chain encountered an error while seeking in the FLAC file */
+
+	FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR,
+	/**< The chain encountered an error while writing the FLAC file */
+
+	FLAC__METADATA_CHAIN_STATUS_RENAME_ERROR,
+	/**< The chain encountered an error renaming the FLAC file */
+
+	FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR,
+	/**< The chain encountered an error removing the temporary file */
+
+	FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR,
+	/**< Memory allocation failed */
+
+	FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR,
+	/**< The caller violated an assertion or an unexpected error occurred */
+
+	FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS,
+	/**< One or more of the required callbacks was NULL */
+
+	FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH,
+	/**< FLAC__metadata_chain_write() was called on a chain read by
+	 *   FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks(),
+	 *   or
+	 *   FLAC__metadata_chain_write_with_callbacks()/FLAC__metadata_chain_write_with_callbacks_and_tempfile()
+	 *   was called on a chain read by
+	 *   FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg().
+	 *   Matching read/write methods must always be used. */
+
+	FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL
+	/**< FLAC__metadata_chain_write_with_callbacks() was called when the
+	 *   chain write requires a tempfile; use
+	 *   FLAC__metadata_chain_write_with_callbacks_and_tempfile() instead.
+	 *   Or, FLAC__metadata_chain_write_with_callbacks_and_tempfile() was
+	 *   called when the chain write does not require a tempfile; use
+	 *   FLAC__metadata_chain_write_with_callbacks() instead.
+	 *   Always check FLAC__metadata_chain_check_if_tempfile_needed()
+	 *   before writing via callbacks. */
+
+} FLAC__Metadata_ChainStatus;
+
+/** Maps a FLAC__Metadata_ChainStatus to a C string.
+ *
+ *  Using a FLAC__Metadata_ChainStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__Metadata_ChainStatusString[];
+
+/*********** FLAC__Metadata_Chain ***********/
+
+/** Create a new chain instance.
+ *
+ * \retval FLAC__Metadata_Chain*
+ *    \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__Metadata_Chain *FLAC__metadata_chain_new(void);
+
+/** Free a chain instance.  Deletes the object pointed to by \a chain.
+ *
+ * \param chain  A pointer to an existing chain.
+ * \assert
+ *    \code chain != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_chain_delete(FLAC__Metadata_Chain *chain);
+
+/** Get the current status of the chain.  Call this after a function
+ *  returns \c false to get the reason for the error.  Also resets the
+ *  status to FLAC__METADATA_CHAIN_STATUS_OK.
+ *
+ * \param chain    A pointer to an existing chain.
+ * \assert
+ *    \code chain != NULL \endcode
+ * \retval FLAC__Metadata_ChainStatus
+ *    The current status of the chain.
+ */
+FLAC_API FLAC__Metadata_ChainStatus FLAC__metadata_chain_status(FLAC__Metadata_Chain *chain);
+
+/** Read all metadata from a FLAC file into the chain.
+ *
+ * \param chain    A pointer to an existing chain.
+ * \param filename The path to the FLAC file to read.
+ * \assert
+ *    \code chain != NULL \endcode
+ *    \code filename != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if a valid list of metadata blocks was read from
+ *    \a filename, else \c false.  On failure, check the status with
+ *    FLAC__metadata_chain_status().
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_read(FLAC__Metadata_Chain *chain, const char *filename);
+
+/** Read all metadata from an Ogg FLAC file into the chain.
+ *
+ * \note Ogg FLAC metadata data writing is not supported yet and
+ * FLAC__metadata_chain_write() will fail.
+ *
+ * \param chain    A pointer to an existing chain.
+ * \param filename The path to the Ogg FLAC file to read.
+ * \assert
+ *    \code chain != NULL \endcode
+ *    \code filename != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if a valid list of metadata blocks was read from
+ *    \a filename, else \c false.  On failure, check the status with
+ *    FLAC__metadata_chain_status().
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_read_ogg(FLAC__Metadata_Chain *chain, const char *filename);
+
+/** Read all metadata from a FLAC stream into the chain via I/O callbacks.
+ *
+ *  The \a handle need only be open for reading, but must be seekable.
+ *  The equivalent minimum stdio fopen() file mode is \c "r" (or \c "rb"
+ *  for Windows).
+ *
+ * \param chain    A pointer to an existing chain.
+ * \param handle   The I/O handle of the FLAC stream to read.  The
+ *                 handle will NOT be closed after the metadata is read;
+ *                 that is the duty of the caller.
+ * \param callbacks
+ *                 A set of callbacks to use for I/O.  The mandatory
+ *                 callbacks are \a read, \a seek, and \a tell.
+ * \assert
+ *    \code chain != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if a valid list of metadata blocks was read from
+ *    \a handle, else \c false.  On failure, check the status with
+ *    FLAC__metadata_chain_status().
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_read_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks);
+
+/** Read all metadata from an Ogg FLAC stream into the chain via I/O callbacks.
+ *
+ *  The \a handle need only be open for reading, but must be seekable.
+ *  The equivalent minimum stdio fopen() file mode is \c "r" (or \c "rb"
+ *  for Windows).
+ *
+ * \note Ogg FLAC metadata data writing is not supported yet and
+ * FLAC__metadata_chain_write() will fail.
+ *
+ * \param chain    A pointer to an existing chain.
+ * \param handle   The I/O handle of the Ogg FLAC stream to read.  The
+ *                 handle will NOT be closed after the metadata is read;
+ *                 that is the duty of the caller.
+ * \param callbacks
+ *                 A set of callbacks to use for I/O.  The mandatory
+ *                 callbacks are \a read, \a seek, and \a tell.
+ * \assert
+ *    \code chain != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if a valid list of metadata blocks was read from
+ *    \a handle, else \c false.  On failure, check the status with
+ *    FLAC__metadata_chain_status().
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_read_ogg_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks);
+
+/** Checks if writing the given chain would require the use of a
+ *  temporary file, or if it could be written in place.
+ *
+ *  Under certain conditions, padding can be utilized so that writing
+ *  edited metadata back to the FLAC file does not require rewriting the
+ *  entire file.  If rewriting is required, then a temporary workfile is
+ *  required.  When writing metadata using callbacks, you must check
+ *  this function to know whether to call
+ *  FLAC__metadata_chain_write_with_callbacks() or
+ *  FLAC__metadata_chain_write_with_callbacks_and_tempfile().  When
+ *  writing with FLAC__metadata_chain_write(), the temporary file is
+ *  handled internally.
+ *
+ * \param chain    A pointer to an existing chain.
+ * \param use_padding
+ *                 Whether or not padding will be allowed to be used
+ *                 during the write.  The value of \a use_padding given
+ *                 here must match the value later passed to
+ *                 FLAC__metadata_chain_write_with_callbacks() or
+ *                 FLAC__metadata_chain_write_with_callbacks_with_tempfile().
+ * \assert
+ *    \code chain != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if writing the current chain would require a tempfile, or
+ *    \c false if metadata can be written in place.
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_check_if_tempfile_needed(FLAC__Metadata_Chain *chain, FLAC__bool use_padding);
+
+/** Write all metadata out to the FLAC file.  This function tries to be as
+ *  efficient as possible; how the metadata is actually written is shown by
+ *  the following:
+ *
+ *  If the current chain is the same size as the existing metadata, the new
+ *  data is written in place.
+ *
+ *  If the current chain is longer than the existing metadata, and
+ *  \a use_padding is \c true, and the last block is a PADDING block of
+ *  sufficient length, the function will truncate the final padding block
+ *  so that the overall size of the metadata is the same as the existing
+ *  metadata, and then just rewrite the metadata.  Otherwise, if not all of
+ *  the above conditions are met, the entire FLAC file must be rewritten.
+ *  If you want to use padding this way it is a good idea to call
+ *  FLAC__metadata_chain_sort_padding() first so that you have the maximum
+ *  amount of padding to work with, unless you need to preserve ordering
+ *  of the PADDING blocks for some reason.
+ *
+ *  If the current chain is shorter than the existing metadata, and
+ *  \a use_padding is \c true, and the final block is a PADDING block, the padding
+ *  is extended to make the overall size the same as the existing data.  If
+ *  \a use_padding is \c true and the last block is not a PADDING block, a new
+ *  PADDING block is added to the end of the new data to make it the same
+ *  size as the existing data (if possible, see the note to
+ *  FLAC__metadata_simple_iterator_set_block() about the four byte limit)
+ *  and the new data is written in place.  If none of the above apply or
+ *  \a use_padding is \c false, the entire FLAC file is rewritten.
+ *
+ *  If \a preserve_file_stats is \c true, the owner and modification time will
+ *  be preserved even if the FLAC file is written.
+ *
+ *  For this write function to be used, the chain must have been read with
+ *  FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg(), not
+ *  FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks().
+ *
+ * \param chain               A pointer to an existing chain.
+ * \param use_padding         See above.
+ * \param preserve_file_stats See above.
+ * \assert
+ *    \code chain != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if the write succeeded, else \c false.  On failure,
+ *    check the status with FLAC__metadata_chain_status().
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_write(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__bool preserve_file_stats);
+
+/** Write all metadata out to a FLAC stream via callbacks.
+ *
+ *  (See FLAC__metadata_chain_write() for the details on how padding is
+ *  used to write metadata in place if possible.)
+ *
+ *  The \a handle must be open for updating and be seekable.  The
+ *  equivalent minimum stdio fopen() file mode is \c "r+" (or \c "r+b"
+ *  for Windows).
+ *
+ *  For this write function to be used, the chain must have been read with
+ *  FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks(),
+ *  not FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg().
+ *  Also, FLAC__metadata_chain_check_if_tempfile_needed() must have returned
+ *  \c false.
+ *
+ * \param chain        A pointer to an existing chain.
+ * \param use_padding  See FLAC__metadata_chain_write()
+ * \param handle       The I/O handle of the FLAC stream to write.  The
+ *                     handle will NOT be closed after the metadata is
+ *                     written; that is the duty of the caller.
+ * \param callbacks    A set of callbacks to use for I/O.  The mandatory
+ *                     callbacks are \a write and \a seek.
+ * \assert
+ *    \code chain != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if the write succeeded, else \c false.  On failure,
+ *    check the status with FLAC__metadata_chain_status().
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks);
+
+/** Write all metadata out to a FLAC stream via callbacks.
+ *
+ *  (See FLAC__metadata_chain_write() for the details on how padding is
+ *  used to write metadata in place if possible.)
+ *
+ *  This version of the write-with-callbacks function must be used when
+ *  FLAC__metadata_chain_check_if_tempfile_needed() returns true.  In
+ *  this function, you must supply an I/O handle corresponding to the
+ *  FLAC file to edit, and a temporary handle to which the new FLAC
+ *  file will be written.  It is the caller's job to move this temporary
+ *  FLAC file on top of the original FLAC file to complete the metadata
+ *  edit.
+ *
+ *  The \a handle must be open for reading and be seekable.  The
+ *  equivalent minimum stdio fopen() file mode is \c "r" (or \c "rb"
+ *  for Windows).
+ *
+ *  The \a temp_handle must be open for writing.  The
+ *  equivalent minimum stdio fopen() file mode is \c "w" (or \c "wb"
+ *  for Windows).  It should be an empty stream, or at least positioned
+ *  at the start-of-file (in which case it is the caller's duty to
+ *  truncate it on return).
+ *
+ *  For this write function to be used, the chain must have been read with
+ *  FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks(),
+ *  not FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg().
+ *  Also, FLAC__metadata_chain_check_if_tempfile_needed() must have returned
+ *  \c true.
+ *
+ * \param chain        A pointer to an existing chain.
+ * \param use_padding  See FLAC__metadata_chain_write()
+ * \param handle       The I/O handle of the original FLAC stream to read.
+ *                     The handle will NOT be closed after the metadata is
+ *                     written; that is the duty of the caller.
+ * \param callbacks    A set of callbacks to use for I/O on \a handle.
+ *                     The mandatory callbacks are \a read, \a seek, and
+ *                     \a eof.
+ * \param temp_handle  The I/O handle of the FLAC stream to write.  The
+ *                     handle will NOT be closed after the metadata is
+ *                     written; that is the duty of the caller.
+ * \param temp_callbacks
+ *                     A set of callbacks to use for I/O on temp_handle.
+ *                     The only mandatory callback is \a write.
+ * \assert
+ *    \code chain != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if the write succeeded, else \c false.  On failure,
+ *    check the status with FLAC__metadata_chain_status().
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks_and_tempfile(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks, FLAC__IOHandle temp_handle, FLAC__IOCallbacks temp_callbacks);
+
+/** Merge adjacent PADDING blocks into a single block.
+ *
+ * \note This function does not write to the FLAC file, it only
+ * modifies the chain.
+ *
+ * \warning Any iterator on the current chain will become invalid after this
+ * call.  You should delete the iterator and get a new one.
+ *
+ * \param chain               A pointer to an existing chain.
+ * \assert
+ *    \code chain != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_chain_merge_padding(FLAC__Metadata_Chain *chain);
+
+/** This function will move all PADDING blocks to the end on the metadata,
+ *  then merge them into a single block.
+ *
+ * \note This function does not write to the FLAC file, it only
+ * modifies the chain.
+ *
+ * \warning Any iterator on the current chain will become invalid after this
+ * call.  You should delete the iterator and get a new one.
+ *
+ * \param chain  A pointer to an existing chain.
+ * \assert
+ *    \code chain != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_chain_sort_padding(FLAC__Metadata_Chain *chain);
+
+
+/*********** FLAC__Metadata_Iterator ***********/
+
+/** Create a new iterator instance.
+ *
+ * \retval FLAC__Metadata_Iterator*
+ *    \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__Metadata_Iterator *FLAC__metadata_iterator_new(void);
+
+/** Free an iterator instance.  Deletes the object pointed to by \a iterator.
+ *
+ * \param iterator  A pointer to an existing iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_iterator_delete(FLAC__Metadata_Iterator *iterator);
+
+/** Initialize the iterator to point to the first metadata block in the
+ *  given chain.
+ *
+ * \param iterator  A pointer to an existing iterator.
+ * \param chain     A pointer to an existing and initialized (read) chain.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \code chain != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_iterator_init(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Chain *chain);
+
+/** Moves the iterator forward one metadata block, returning \c false if
+ *  already at the end.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_iterator_init()
+ * \retval FLAC__bool
+ *    \c false if already at the last metadata block of the chain, else
+ *    \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_iterator_next(FLAC__Metadata_Iterator *iterator);
+
+/** Moves the iterator backward one metadata block, returning \c false if
+ *  already at the beginning.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_iterator_init()
+ * \retval FLAC__bool
+ *    \c false if already at the first metadata block of the chain, else
+ *    \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_iterator_prev(FLAC__Metadata_Iterator *iterator);
+
+/** Get the type of the metadata block at the current position.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_iterator_init()
+ * \retval FLAC__MetadataType
+ *    The type of the metadata block at the current iterator position.
+ */
+FLAC_API FLAC__MetadataType FLAC__metadata_iterator_get_block_type(const FLAC__Metadata_Iterator *iterator);
+
+/** Get the metadata block at the current position.  You can modify
+ *  the block in place but must write the chain before the changes
+ *  are reflected to the FLAC file.  You do not need to call
+ *  FLAC__metadata_iterator_set_block() to reflect the changes;
+ *  the pointer returned by FLAC__metadata_iterator_get_block()
+ *  points directly into the chain.
+ *
+ * \warning
+ * Do not call FLAC__metadata_object_delete() on the returned object;
+ * to delete a block use FLAC__metadata_iterator_delete_block().
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_iterator_init()
+ * \retval FLAC__StreamMetadata*
+ *    The current metadata block.
+ */
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_iterator_get_block(FLAC__Metadata_Iterator *iterator);
+
+/** Set the metadata block at the current position, replacing the existing
+ *  block.  The new block passed in becomes owned by the chain and it will be
+ *  deleted when the chain is deleted.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \param block     A pointer to a metadata block.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_iterator_init()
+ *    \code block != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the conditions in the above description are not met, or
+ *    a memory allocation error occurs, otherwise \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_iterator_set_block(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block);
+
+/** Removes the current block from the chain.  If \a replace_with_padding is
+ *  \c true, the block will instead be replaced with a padding block of equal
+ *  size.  You can not delete the STREAMINFO block.  The iterator will be
+ *  left pointing to the block before the one just "deleted", even if
+ *  \a replace_with_padding is \c true.
+ *
+ * \param iterator              A pointer to an existing initialized iterator.
+ * \param replace_with_padding  See above.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_iterator_init()
+ * \retval FLAC__bool
+ *    \c false if the conditions in the above description are not met,
+ *    otherwise \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_iterator_delete_block(FLAC__Metadata_Iterator *iterator, FLAC__bool replace_with_padding);
+
+/** Insert a new block before the current block.  You cannot insert a block
+ *  before the first STREAMINFO block.  You cannot insert a STREAMINFO block
+ *  as there can be only one, the one that already exists at the head when you
+ *  read in a chain.  The chain takes ownership of the new block and it will be
+ *  deleted when the chain is deleted.  The iterator will be left pointing to
+ *  the new block.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \param block     A pointer to a metadata block to insert.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_iterator_init()
+ * \retval FLAC__bool
+ *    \c false if the conditions in the above description are not met, or
+ *    a memory allocation error occurs, otherwise \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_before(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block);
+
+/** Insert a new block after the current block.  You cannot insert a STREAMINFO
+ *  block as there can be only one, the one that already exists at the head when
+ *  you read in a chain.  The chain takes ownership of the new block and it will
+ *  be deleted when the chain is deleted.  The iterator will be left pointing to
+ *  the new block.
+ *
+ * \param iterator  A pointer to an existing initialized iterator.
+ * \param block     A pointer to a metadata block to insert.
+ * \assert
+ *    \code iterator != NULL \endcode
+ *    \a iterator has been successfully initialized with
+ *    FLAC__metadata_iterator_init()
+ * \retval FLAC__bool
+ *    \c false if the conditions in the above description are not met, or
+ *    a memory allocation error occurs, otherwise \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_after(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block);
+
+/* \} */
+
+
+/** \defgroup flac_metadata_object FLAC/metadata.h: metadata object methods
+ *  \ingroup flac_metadata
+ *
+ * \brief
+ * This module contains methods for manipulating FLAC metadata objects.
+ *
+ * Since many are variable length we have to be careful about the memory
+ * management.  We decree that all pointers to data in the object are
+ * owned by the object and memory-managed by the object.
+ *
+ * Use the FLAC__metadata_object_new() and FLAC__metadata_object_delete()
+ * functions to create all instances.  When using the
+ * FLAC__metadata_object_set_*() functions to set pointers to data, set
+ * \a copy to \c true to have the function make it's own copy of the data, or
+ * to \c false to give the object ownership of your data.  In the latter case
+ * your pointer must be freeable by free() and will be free()d when the object
+ * is FLAC__metadata_object_delete()d.  It is legal to pass a null pointer as
+ * the data pointer to a FLAC__metadata_object_set_*() function as long as
+ * the length argument is 0 and the \a copy argument is \c false.
+ *
+ * The FLAC__metadata_object_new() and FLAC__metadata_object_clone() function
+ * will return \c NULL in the case of a memory allocation error, otherwise a new
+ * object.  The FLAC__metadata_object_set_*() functions return \c false in the
+ * case of a memory allocation error.
+ *
+ * We don't have the convenience of C++ here, so note that the library relies
+ * on you to keep the types straight.  In other words, if you pass, for
+ * example, a FLAC__StreamMetadata* that represents a STREAMINFO block to
+ * FLAC__metadata_object_application_set_data(), you will get an assertion
+ * failure.
+ *
+ * For convenience the FLAC__metadata_object_vorbiscomment_*() functions
+ * maintain a trailing NUL on each Vorbis comment entry.  This is not counted
+ * toward the length or stored in the stream, but it can make working with plain
+ * comments (those that don't contain embedded-NULs in the value) easier.
+ * Entries passed into these functions have trailing NULs added if missing, and
+ * returned entries are guaranteed to have a trailing NUL.
+ *
+ * The FLAC__metadata_object_vorbiscomment_*() functions that take a Vorbis
+ * comment entry/name/value will first validate that it complies with the Vorbis
+ * comment specification and return false if it does not.
+ *
+ * There is no need to recalculate the length field on metadata blocks you
+ * have modified.  They will be calculated automatically before they  are
+ * written back to a file.
+ *
+ * \{
+ */
+
+
+/** Create a new metadata object instance of the given type.
+ *
+ *  The object will be "empty"; i.e. values and data pointers will be \c 0,
+ *  with the exception of FLAC__METADATA_TYPE_VORBIS_COMMENT, which will have
+ *  the vendor string set (but zero comments).
+ *
+ *  Do not pass in a value greater than or equal to
+ *  \a FLAC__METADATA_TYPE_UNDEFINED unless you really know what you're
+ *  doing.
+ *
+ * \param type  Type of object to create
+ * \retval FLAC__StreamMetadata*
+ *    \c NULL if there was an error allocating memory or the type code is
+ *    greater than FLAC__MAX_METADATA_TYPE_CODE, else the new instance.
+ */
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_new(FLAC__MetadataType type);
+
+/** Create a copy of an existing metadata object.
+ *
+ *  The copy is a "deep" copy, i.e. dynamically allocated data within the
+ *  object is also copied.  The caller takes ownership of the new block and
+ *  is responsible for freeing it with FLAC__metadata_object_delete().
+ *
+ * \param object  Pointer to object to copy.
+ * \assert
+ *    \code object != NULL \endcode
+ * \retval FLAC__StreamMetadata*
+ *    \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_clone(const FLAC__StreamMetadata *object);
+
+/** Free a metadata object.  Deletes the object pointed to by \a object.
+ *
+ *  The delete is a "deep" delete, i.e. dynamically allocated data within the
+ *  object is also deleted.
+ *
+ * \param object  A pointer to an existing object.
+ * \assert
+ *    \code object != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_object_delete(FLAC__StreamMetadata *object);
+
+/** Compares two metadata objects.
+ *
+ *  The compare is "deep", i.e. dynamically allocated data within the
+ *  object is also compared.
+ *
+ * \param block1  A pointer to an existing object.
+ * \param block2  A pointer to an existing object.
+ * \assert
+ *    \code block1 != NULL \endcode
+ *    \code block2 != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if objects are identical, else \c false.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_is_equal(const FLAC__StreamMetadata *block1, const FLAC__StreamMetadata *block2);
+
+/** Sets the application data of an APPLICATION block.
+ *
+ *  If \a copy is \c true, a copy of the data is stored; otherwise, the object
+ *  takes ownership of the pointer.  The existing data will be freed if this
+ *  function is successful, otherwise the original data will remain if \a copy
+ *  is \c true and malloc() fails.
+ *
+ * \note It is safe to pass a const pointer to \a data if \a copy is \c true.
+ *
+ * \param object  A pointer to an existing APPLICATION object.
+ * \param data    A pointer to the data to set.
+ * \param length  The length of \a data in bytes.
+ * \param copy    See above.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_APPLICATION \endcode
+ *    \code (data != NULL && length > 0) ||
+ * (data == NULL && length == 0 && copy == false) \endcode
+ * \retval FLAC__bool
+ *    \c false if \a copy is \c true and malloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_application_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, uint32_t length, FLAC__bool copy);
+
+/** Resize the seekpoint array.
+ *
+ *  If the size shrinks, elements will truncated; if it grows, new placeholder
+ *  points will be added to the end.
+ *
+ * \param object          A pointer to an existing SEEKTABLE object.
+ * \param new_num_points  The desired length of the array; may be \c 0.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ *    \code (object->data.seek_table.points == NULL && object->data.seek_table.num_points == 0) ||
+ * (object->data.seek_table.points != NULL && object->data.seek_table.num_points > 0) \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation error, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_resize_points(FLAC__StreamMetadata *object, uint32_t new_num_points);
+
+/** Set a seekpoint in a seektable.
+ *
+ * \param object     A pointer to an existing SEEKTABLE object.
+ * \param point_num  Index into seekpoint array to set.
+ * \param point      The point to set.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ *    \code object->data.seek_table.num_points > point_num \endcode
+ */
+FLAC_API void FLAC__metadata_object_seektable_set_point(FLAC__StreamMetadata *object, uint32_t point_num, FLAC__StreamMetadata_SeekPoint point);
+
+/** Insert a seekpoint into a seektable.
+ *
+ * \param object     A pointer to an existing SEEKTABLE object.
+ * \param point_num  Index into seekpoint array to set.
+ * \param point      The point to set.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ *    \code object->data.seek_table.num_points >= point_num \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation error, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_insert_point(FLAC__StreamMetadata *object, uint32_t point_num, FLAC__StreamMetadata_SeekPoint point);
+
+/** Delete a seekpoint from a seektable.
+ *
+ * \param object     A pointer to an existing SEEKTABLE object.
+ * \param point_num  Index into seekpoint array to set.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ *    \code object->data.seek_table.num_points > point_num \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation error, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_delete_point(FLAC__StreamMetadata *object, uint32_t point_num);
+
+/** Check a seektable to see if it conforms to the FLAC specification.
+ *  See the format specification for limits on the contents of the
+ *  seektable.
+ *
+ * \param object  A pointer to an existing SEEKTABLE object.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \retval FLAC__bool
+ *    \c false if seek table is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_is_legal(const FLAC__StreamMetadata *object);
+
+/** Append a number of placeholder points to the end of a seek table.
+ *
+ * \note
+ * As with the other ..._seektable_template_... functions, you should
+ * call FLAC__metadata_object_seektable_template_sort() when finished
+ * to make the seek table legal.
+ *
+ * \param object  A pointer to an existing SEEKTABLE object.
+ * \param num     The number of placeholder points to append.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_placeholders(FLAC__StreamMetadata *object, uint32_t num);
+
+/** Append a specific seek point template to the end of a seek table.
+ *
+ * \note
+ * As with the other ..._seektable_template_... functions, you should
+ * call FLAC__metadata_object_seektable_template_sort() when finished
+ * to make the seek table legal.
+ *
+ * \param object  A pointer to an existing SEEKTABLE object.
+ * \param sample_number  The sample number of the seek point template.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_point(FLAC__StreamMetadata *object, FLAC__uint64 sample_number);
+
+/** Append specific seek point templates to the end of a seek table.
+ *
+ * \note
+ * As with the other ..._seektable_template_... functions, you should
+ * call FLAC__metadata_object_seektable_template_sort() when finished
+ * to make the seek table legal.
+ *
+ * \param object  A pointer to an existing SEEKTABLE object.
+ * \param sample_numbers  An array of sample numbers for the seek points.
+ * \param num     The number of seek point templates to append.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_points(FLAC__StreamMetadata *object, FLAC__uint64 sample_numbers[], uint32_t num);
+
+/** Append a set of evenly-spaced seek point templates to the end of a
+ *  seek table.
+ *
+ * \note
+ * As with the other ..._seektable_template_... functions, you should
+ * call FLAC__metadata_object_seektable_template_sort() when finished
+ * to make the seek table legal.
+ *
+ * \param object  A pointer to an existing SEEKTABLE object.
+ * \param num     The number of placeholder points to append.
+ * \param total_samples  The total number of samples to be encoded;
+ *                       the seekpoints will be spaced approximately
+ *                       \a total_samples / \a num samples apart.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ *    \code total_samples > 0 \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points(FLAC__StreamMetadata *object, uint32_t num, FLAC__uint64 total_samples);
+
+/** Append a set of evenly-spaced seek point templates to the end of a
+ *  seek table.
+ *
+ * \note
+ * As with the other ..._seektable_template_... functions, you should
+ * call FLAC__metadata_object_seektable_template_sort() when finished
+ * to make the seek table legal.
+ *
+ * \param object  A pointer to an existing SEEKTABLE object.
+ * \param samples The number of samples apart to space the placeholder
+ *                points.  The first point will be at sample \c 0, the
+ *                second at sample \a samples, then 2*\a samples, and
+ *                so on.  As long as \a samples and \a total_samples
+ *                are greater than \c 0, there will always be at least
+ *                one seekpoint at sample \c 0.
+ * \param total_samples  The total number of samples to be encoded;
+ *                       the seekpoints will be spaced
+ *                       \a samples samples apart.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ *    \code samples > 0 \endcode
+ *    \code total_samples > 0 \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(FLAC__StreamMetadata *object, uint32_t samples, FLAC__uint64 total_samples);
+
+/** Sort a seek table's seek points according to the format specification,
+ *  removing duplicates.
+ *
+ * \param object   A pointer to a seek table to be sorted.
+ * \param compact  If \c false, behaves like FLAC__format_seektable_sort().
+ *                 If \c true, duplicates are deleted and the seek table is
+ *                 shrunk appropriately; the number of placeholder points
+ *                 present in the seek table will be the same after the call
+ *                 as before.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \retval FLAC__bool
+ *    \c false if realloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_sort(FLAC__StreamMetadata *object, FLAC__bool compact);
+
+/** Sets the vendor string in a VORBIS_COMMENT block.
+ *
+ *  For convenience, a trailing NUL is added to the entry if it doesn't have
+ *  one already.
+ *
+ *  If \a copy is \c true, a copy of the entry is stored; otherwise, the object
+ *  takes ownership of the \c entry.entry pointer.
+ *
+ *  \note If this function returns \c false, the caller still owns the
+ *  pointer.
+ *
+ * \param object  A pointer to an existing VORBIS_COMMENT object.
+ * \param entry   The entry to set the vendor string to.
+ * \param copy    See above.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ *    \code (entry.entry != NULL && entry.length > 0) ||
+ * (entry.entry == NULL && entry.length == 0) \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation fails or \a entry does not comply with the
+ *    Vorbis comment specification, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_vendor_string(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy);
+
+/** Resize the comment array.
+ *
+ *  If the size shrinks, elements will truncated; if it grows, new empty
+ *  fields will be added to the end.
+ *
+ * \param object            A pointer to an existing VORBIS_COMMENT object.
+ * \param new_num_comments  The desired length of the array; may be \c 0.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ *    \code (object->data.vorbis_comment.comments == NULL && object->data.vorbis_comment.num_comments == 0) ||
+ * (object->data.vorbis_comment.comments != NULL && object->data.vorbis_comment.num_comments > 0) \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_resize_comments(FLAC__StreamMetadata *object, uint32_t new_num_comments);
+
+/** Sets a comment in a VORBIS_COMMENT block.
+ *
+ *  For convenience, a trailing NUL is added to the entry if it doesn't have
+ *  one already.
+ *
+ *  If \a copy is \c true, a copy of the entry is stored; otherwise, the object
+ *  takes ownership of the \c entry.entry pointer.
+ *
+ *  \note If this function returns \c false, the caller still owns the
+ *  pointer.
+ *
+ * \param object       A pointer to an existing VORBIS_COMMENT object.
+ * \param comment_num  Index into comment array to set.
+ * \param entry        The entry to set the comment to.
+ * \param copy         See above.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ *    \code comment_num < object->data.vorbis_comment.num_comments \endcode
+ *    \code (entry.entry != NULL && entry.length > 0) ||
+ * (entry.entry == NULL && entry.length == 0) \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation fails or \a entry does not comply with the
+ *    Vorbis comment specification, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_comment(FLAC__StreamMetadata *object, uint32_t comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy);
+
+/** Insert a comment in a VORBIS_COMMENT block at the given index.
+ *
+ *  For convenience, a trailing NUL is added to the entry if it doesn't have
+ *  one already.
+ *
+ *  If \a copy is \c true, a copy of the entry is stored; otherwise, the object
+ *  takes ownership of the \c entry.entry pointer.
+ *
+ *  \note If this function returns \c false, the caller still owns the
+ *  pointer.
+ *
+ * \param object       A pointer to an existing VORBIS_COMMENT object.
+ * \param comment_num  The index at which to insert the comment.  The comments
+ *                     at and after \a comment_num move right one position.
+ *                     To append a comment to the end, set \a comment_num to
+ *                     \c object->data.vorbis_comment.num_comments .
+ * \param entry        The comment to insert.
+ * \param copy         See above.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ *    \code object->data.vorbis_comment.num_comments >= comment_num \endcode
+ *    \code (entry.entry != NULL && entry.length > 0) ||
+ * (entry.entry == NULL && entry.length == 0 && copy == false) \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation fails or \a entry does not comply with the
+ *    Vorbis comment specification, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_insert_comment(FLAC__StreamMetadata *object, uint32_t comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy);
+
+/** Appends a comment to a VORBIS_COMMENT block.
+ *
+ *  For convenience, a trailing NUL is added to the entry if it doesn't have
+ *  one already.
+ *
+ *  If \a copy is \c true, a copy of the entry is stored; otherwise, the object
+ *  takes ownership of the \c entry.entry pointer.
+ *
+ *  \note If this function returns \c false, the caller still owns the
+ *  pointer.
+ *
+ * \param object       A pointer to an existing VORBIS_COMMENT object.
+ * \param entry        The comment to insert.
+ * \param copy         See above.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ *    \code (entry.entry != NULL && entry.length > 0) ||
+ * (entry.entry == NULL && entry.length == 0 && copy == false) \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation fails or \a entry does not comply with the
+ *    Vorbis comment specification, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_append_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy);
+
+/** Replaces comments in a VORBIS_COMMENT block with a new one.
+ *
+ *  For convenience, a trailing NUL is added to the entry if it doesn't have
+ *  one already.
+ *
+ *  Depending on the value of \a all, either all or just the first comment
+ *  whose field name(s) match the given entry's name will be replaced by the
+ *  given entry.  If no comments match, \a entry will simply be appended.
+ *
+ *  If \a copy is \c true, a copy of the entry is stored; otherwise, the object
+ *  takes ownership of the \c entry.entry pointer.
+ *
+ *  \note If this function returns \c false, the caller still owns the
+ *  pointer.
+ *
+ * \param object       A pointer to an existing VORBIS_COMMENT object.
+ * \param entry        The comment to insert.
+ * \param all          If \c true, all comments whose field name matches
+ *                     \a entry's field name will be removed, and \a entry will
+ *                     be inserted at the position of the first matching
+ *                     comment.  If \c false, only the first comment whose
+ *                     field name matches \a entry's field name will be
+ *                     replaced with \a entry.
+ * \param copy         See above.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ *    \code (entry.entry != NULL && entry.length > 0) ||
+ * (entry.entry == NULL && entry.length == 0 && copy == false) \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation fails or \a entry does not comply with the
+ *    Vorbis comment specification, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_replace_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool all, FLAC__bool copy);
+
+/** Delete a comment in a VORBIS_COMMENT block at the given index.
+ *
+ * \param object       A pointer to an existing VORBIS_COMMENT object.
+ * \param comment_num  The index of the comment to delete.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ *    \code object->data.vorbis_comment.num_comments > comment_num \endcode
+ * \retval FLAC__bool
+ *    \c false if realloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_delete_comment(FLAC__StreamMetadata *object, uint32_t comment_num);
+
+/** Creates a Vorbis comment entry from NUL-terminated name and value strings.
+ *
+ *  On return, the filled-in \a entry->entry pointer will point to malloc()ed
+ *  memory and shall be owned by the caller.  For convenience the entry will
+ *  have a terminating NUL.
+ *
+ * \param entry              A pointer to a Vorbis comment entry.  The entry's
+ *                           \c entry pointer should not point to allocated
+ *                           memory as it will be overwritten.
+ * \param field_name         The field name in ASCII, \c NUL terminated.
+ * \param field_value        The field value in UTF-8, \c NUL terminated.
+ * \assert
+ *    \code entry != NULL \endcode
+ *    \code field_name != NULL \endcode
+ *    \code field_value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if malloc() fails, or if \a field_name or \a field_value does
+ *    not comply with the Vorbis comment specification, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *field_name, const char *field_value);
+
+/** Splits a Vorbis comment entry into NUL-terminated name and value strings.
+ *
+ *  The returned pointers to name and value will be allocated by malloc()
+ *  and shall be owned by the caller.
+ *
+ * \param entry              An existing Vorbis comment entry.
+ * \param field_name         The address of where the returned pointer to the
+ *                           field name will be stored.
+ * \param field_value        The address of where the returned pointer to the
+ *                           field value will be stored.
+ * \assert
+ *    \code (entry.entry != NULL && entry.length > 0) \endcode
+ *    \code memchr(entry.entry, '=', entry.length) != NULL \endcode
+ *    \code field_name != NULL \endcode
+ *    \code field_value != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation fails or \a entry does not comply with the
+ *    Vorbis comment specification, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(const FLAC__StreamMetadata_VorbisComment_Entry entry, char **field_name, char **field_value);
+
+/** Check if the given Vorbis comment entry's field name matches the given
+ *  field name.
+ *
+ * \param entry              An existing Vorbis comment entry.
+ * \param field_name         The field name to check.
+ * \param field_name_length  The length of \a field_name, not including the
+ *                           terminating \c NUL.
+ * \assert
+ *    \code (entry.entry != NULL && entry.length > 0) \endcode
+ * \retval FLAC__bool
+ *    \c true if the field names match, else \c false
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(const FLAC__StreamMetadata_VorbisComment_Entry entry, const char *field_name, uint32_t field_name_length);
+
+/** Find a Vorbis comment with the given field name.
+ *
+ *  The search begins at entry number \a offset; use an offset of 0 to
+ *  search from the beginning of the comment array.
+ *
+ * \param object      A pointer to an existing VORBIS_COMMENT object.
+ * \param offset      The offset into the comment array from where to start
+ *                    the search.
+ * \param field_name  The field name of the comment to find.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ *    \code field_name != NULL \endcode
+ * \retval int
+ *    The offset in the comment array of the first comment whose field
+ *    name matches \a field_name, or \c -1 if no match was found.
+ */
+FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__StreamMetadata *object, uint32_t offset, const char *field_name);
+
+/** Remove first Vorbis comment matching the given field name.
+ *
+ * \param object      A pointer to an existing VORBIS_COMMENT object.
+ * \param field_name  The field name of comment to delete.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ * \retval int
+ *    \c -1 for memory allocation error, \c 0 for no matching entries,
+ *    \c 1 for one matching entry deleted.
+ */
+FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entry_matching(FLAC__StreamMetadata *object, const char *field_name);
+
+/** Remove all Vorbis comments matching the given field name.
+ *
+ * \param object      A pointer to an existing VORBIS_COMMENT object.
+ * \param field_name  The field name of comments to delete.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ * \retval int
+ *    \c -1 for memory allocation error, \c 0 for no matching entries,
+ *    else the number of matching entries deleted.
+ */
+FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entries_matching(FLAC__StreamMetadata *object, const char *field_name);
+
+/** Create a new CUESHEET track instance.
+ *
+ *  The object will be "empty"; i.e. values and data pointers will be \c 0.
+ *
+ * \retval FLAC__StreamMetadata_CueSheet_Track*
+ *    \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_new(void);
+
+/** Create a copy of an existing CUESHEET track object.
+ *
+ *  The copy is a "deep" copy, i.e. dynamically allocated data within the
+ *  object is also copied.  The caller takes ownership of the new object and
+ *  is responsible for freeing it with
+ *  FLAC__metadata_object_cuesheet_track_delete().
+ *
+ * \param object  Pointer to object to copy.
+ * \assert
+ *    \code object != NULL \endcode
+ * \retval FLAC__StreamMetadata_CueSheet_Track*
+ *    \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_clone(const FLAC__StreamMetadata_CueSheet_Track *object);
+
+/** Delete a CUESHEET track object
+ *
+ * \param object       A pointer to an existing CUESHEET track object.
+ * \assert
+ *    \code object != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_object_cuesheet_track_delete(FLAC__StreamMetadata_CueSheet_Track *object);
+
+/** Resize a track's index point array.
+ *
+ *  If the size shrinks, elements will truncated; if it grows, new blank
+ *  indices will be added to the end.
+ *
+ * \param object           A pointer to an existing CUESHEET object.
+ * \param track_num        The index of the track to modify.  NOTE: this is not
+ *                         necessarily the same as the track's \a number field.
+ * \param new_num_indices  The desired length of the array; may be \c 0.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ *    \code object->data.cue_sheet.num_tracks > track_num \endcode
+ *    \code (object->data.cue_sheet.tracks[track_num].indices == NULL && object->data.cue_sheet.tracks[track_num].num_indices == 0) ||
+ * (object->data.cue_sheet.tracks[track_num].indices != NULL && object->data.cue_sheet.tracks[track_num].num_indices > 0) \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation error, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t new_num_indices);
+
+/** Insert an index point in a CUESHEET track at the given index.
+ *
+ * \param object       A pointer to an existing CUESHEET object.
+ * \param track_num    The index of the track to modify.  NOTE: this is not
+ *                     necessarily the same as the track's \a number field.
+ * \param index_num    The index into the track's index array at which to
+ *                     insert the index point.  NOTE: this is not necessarily
+ *                     the same as the index point's \a number field.  The
+ *                     indices at and after \a index_num move right one
+ *                     position.  To append an index point to the end, set
+ *                     \a index_num to
+ *                     \c object->data.cue_sheet.tracks[track_num].num_indices .
+ * \param index        The index point to insert.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ *    \code object->data.cue_sheet.num_tracks > track_num \endcode
+ *    \code object->data.cue_sheet.tracks[track_num].num_indices >= index_num \endcode
+ * \retval FLAC__bool
+ *    \c false if realloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num, FLAC__StreamMetadata_CueSheet_Index index);
+
+/** Insert a blank index point in a CUESHEET track at the given index.
+ *
+ *  A blank index point is one in which all field values are zero.
+ *
+ * \param object       A pointer to an existing CUESHEET object.
+ * \param track_num    The index of the track to modify.  NOTE: this is not
+ *                     necessarily the same as the track's \a number field.
+ * \param index_num    The index into the track's index array at which to
+ *                     insert the index point.  NOTE: this is not necessarily
+ *                     the same as the index point's \a number field.  The
+ *                     indices at and after \a index_num move right one
+ *                     position.  To append an index point to the end, set
+ *                     \a index_num to
+ *                     \c object->data.cue_sheet.tracks[track_num].num_indices .
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ *    \code object->data.cue_sheet.num_tracks > track_num \endcode
+ *    \code object->data.cue_sheet.tracks[track_num].num_indices >= index_num \endcode
+ * \retval FLAC__bool
+ *    \c false if realloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_blank_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num);
+
+/** Delete an index point in a CUESHEET track at the given index.
+ *
+ * \param object       A pointer to an existing CUESHEET object.
+ * \param track_num    The index into the track array of the track to
+ *                     modify.  NOTE: this is not necessarily the same
+ *                     as the track's \a number field.
+ * \param index_num    The index into the track's index array of the index
+ *                     to delete.  NOTE: this is not necessarily the same
+ *                     as the index's \a number field.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ *    \code object->data.cue_sheet.num_tracks > track_num \endcode
+ *    \code object->data.cue_sheet.tracks[track_num].num_indices > index_num \endcode
+ * \retval FLAC__bool
+ *    \c false if realloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_delete_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num);
+
+/** Resize the track array.
+ *
+ *  If the size shrinks, elements will truncated; if it grows, new blank
+ *  tracks will be added to the end.
+ *
+ * \param object            A pointer to an existing CUESHEET object.
+ * \param new_num_tracks    The desired length of the array; may be \c 0.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ *    \code (object->data.cue_sheet.tracks == NULL && object->data.cue_sheet.num_tracks == 0) ||
+ * (object->data.cue_sheet.tracks != NULL && object->data.cue_sheet.num_tracks > 0) \endcode
+ * \retval FLAC__bool
+ *    \c false if memory allocation error, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMetadata *object, uint32_t new_num_tracks);
+
+/** Sets a track in a CUESHEET block.
+ *
+ *  If \a copy is \c true, a copy of the track is stored; otherwise, the object
+ *  takes ownership of the \a track pointer.
+ *
+ * \param object       A pointer to an existing CUESHEET object.
+ * \param track_num    Index into track array to set.  NOTE: this is not
+ *                     necessarily the same as the track's \a number field.
+ * \param track        The track to set the track to.  You may safely pass in
+ *                     a const pointer if \a copy is \c true.
+ * \param copy         See above.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ *    \code track_num < object->data.cue_sheet.num_tracks \endcode
+ *    \code (track->indices != NULL && track->num_indices > 0) ||
+ * (track->indices == NULL && track->num_indices == 0) \endcode
+ * \retval FLAC__bool
+ *    \c false if \a copy is \c true and malloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_set_track(FLAC__StreamMetadata *object, uint32_t track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy);
+
+/** Insert a track in a CUESHEET block at the given index.
+ *
+ *  If \a copy is \c true, a copy of the track is stored; otherwise, the object
+ *  takes ownership of the \a track pointer.
+ *
+ * \param object       A pointer to an existing CUESHEET object.
+ * \param track_num    The index at which to insert the track.  NOTE: this
+ *                     is not necessarily the same as the track's \a number
+ *                     field.  The tracks at and after \a track_num move right
+ *                     one position.  To append a track to the end, set
+ *                     \a track_num to \c object->data.cue_sheet.num_tracks .
+ * \param track        The track to insert.  You may safely pass in a const
+ *                     pointer if \a copy is \c true.
+ * \param copy         See above.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ *    \code object->data.cue_sheet.num_tracks >= track_num \endcode
+ * \retval FLAC__bool
+ *    \c false if \a copy is \c true and malloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_track(FLAC__StreamMetadata *object, uint32_t track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy);
+
+/** Insert a blank track in a CUESHEET block at the given index.
+ *
+ *  A blank track is one in which all field values are zero.
+ *
+ * \param object       A pointer to an existing CUESHEET object.
+ * \param track_num    The index at which to insert the track.  NOTE: this
+ *                     is not necessarily the same as the track's \a number
+ *                     field.  The tracks at and after \a track_num move right
+ *                     one position.  To append a track to the end, set
+ *                     \a track_num to \c object->data.cue_sheet.num_tracks .
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ *    \code object->data.cue_sheet.num_tracks >= track_num \endcode
+ * \retval FLAC__bool
+ *    \c false if \a copy is \c true and malloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_blank_track(FLAC__StreamMetadata *object, uint32_t track_num);
+
+/** Delete a track in a CUESHEET block at the given index.
+ *
+ * \param object       A pointer to an existing CUESHEET object.
+ * \param track_num    The index into the track array of the track to
+ *                     delete.  NOTE: this is not necessarily the same
+ *                     as the track's \a number field.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ *    \code object->data.cue_sheet.num_tracks > track_num \endcode
+ * \retval FLAC__bool
+ *    \c false if realloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_delete_track(FLAC__StreamMetadata *object, uint32_t track_num);
+
+/** Check a cue sheet to see if it conforms to the FLAC specification.
+ *  See the format specification for limits on the contents of the
+ *  cue sheet.
+ *
+ * \param object     A pointer to an existing CUESHEET object.
+ * \param check_cd_da_subset  If \c true, check CUESHEET against more
+ *                   stringent requirements for a CD-DA (audio) disc.
+ * \param violation  Address of a pointer to a string.  If there is a
+ *                   violation, a pointer to a string explanation of the
+ *                   violation will be returned here. \a violation may be
+ *                   \c NULL if you don't need the returned string.  Do not
+ *                   free the returned string; it will always point to static
+ *                   data.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ * \retval FLAC__bool
+ *    \c false if cue sheet is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_is_legal(const FLAC__StreamMetadata *object, FLAC__bool check_cd_da_subset, const char **violation);
+
+/** Calculate and return the CDDB/freedb ID for a cue sheet.  The function
+ *  assumes the cue sheet corresponds to a CD; the result is undefined
+ *  if the cuesheet's is_cd bit is not set.
+ *
+ * \param object     A pointer to an existing CUESHEET object.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ * \retval FLAC__uint32
+ *    The unsigned integer representation of the CDDB/freedb ID
+ */
+FLAC_API FLAC__uint32 FLAC__metadata_object_cuesheet_calculate_cddb_id(const FLAC__StreamMetadata *object);
+
+/** Sets the MIME type of a PICTURE block.
+ *
+ *  If \a copy is \c true, a copy of the string is stored; otherwise, the object
+ *  takes ownership of the pointer.  The existing string will be freed if this
+ *  function is successful, otherwise the original string will remain if \a copy
+ *  is \c true and malloc() fails.
+ *
+ * \note It is safe to pass a const pointer to \a mime_type if \a copy is \c true.
+ *
+ * \param object      A pointer to an existing PICTURE object.
+ * \param mime_type   A pointer to the MIME type string.  The string must be
+ *                    ASCII characters 0x20-0x7e, NUL-terminated.  No validation
+ *                    is done.
+ * \param copy        See above.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode
+ *    \code (mime_type != NULL) \endcode
+ * \retval FLAC__bool
+ *    \c false if \a copy is \c true and malloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_picture_set_mime_type(FLAC__StreamMetadata *object, char *mime_type, FLAC__bool copy);
+
+/** Sets the description of a PICTURE block.
+ *
+ *  If \a copy is \c true, a copy of the string is stored; otherwise, the object
+ *  takes ownership of the pointer.  The existing string will be freed if this
+ *  function is successful, otherwise the original string will remain if \a copy
+ *  is \c true and malloc() fails.
+ *
+ * \note It is safe to pass a const pointer to \a description if \a copy is \c true.
+ *
+ * \param object      A pointer to an existing PICTURE object.
+ * \param description A pointer to the description string.  The string must be
+ *                    valid UTF-8, NUL-terminated.  No validation is done.
+ * \param copy        See above.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode
+ *    \code (description != NULL) \endcode
+ * \retval FLAC__bool
+ *    \c false if \a copy is \c true and malloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_picture_set_description(FLAC__StreamMetadata *object, FLAC__byte *description, FLAC__bool copy);
+
+/** Sets the picture data of a PICTURE block.
+ *
+ *  If \a copy is \c true, a copy of the data is stored; otherwise, the object
+ *  takes ownership of the pointer.  Also sets the \a data_length field of the
+ *  metadata object to what is passed in as the \a length parameter.  The
+ *  existing data will be freed if this function is successful, otherwise the
+ *  original data and data_length will remain if \a copy is \c true and
+ *  malloc() fails.
+ *
+ * \note It is safe to pass a const pointer to \a data if \a copy is \c true.
+ *
+ * \param object  A pointer to an existing PICTURE object.
+ * \param data    A pointer to the data to set.
+ * \param length  The length of \a data in bytes.
+ * \param copy    See above.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode
+ *    \code (data != NULL && length > 0) ||
+ * (data == NULL && length == 0 && copy == false) \endcode
+ * \retval FLAC__bool
+ *    \c false if \a copy is \c true and malloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_picture_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, FLAC__uint32 length, FLAC__bool copy);
+
+/** Check a PICTURE block to see if it conforms to the FLAC specification.
+ *  See the format specification for limits on the contents of the
+ *  PICTURE block.
+ *
+ * \param object     A pointer to existing PICTURE block to be checked.
+ * \param violation  Address of a pointer to a string.  If there is a
+ *                   violation, a pointer to a string explanation of the
+ *                   violation will be returned here. \a violation may be
+ *                   \c NULL if you don't need the returned string.  Do not
+ *                   free the returned string; it will always point to static
+ *                   data.
+ * \assert
+ *    \code object != NULL \endcode
+ *    \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode
+ * \retval FLAC__bool
+ *    \c false if PICTURE block is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_picture_is_legal(const FLAC__StreamMetadata *object, const char **violation);
+
+/* \} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+++ b/src/libflac/FLAC/ordinals.h
@@ -1,0 +1,85 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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.
+ */
+
+#ifndef FLAC__ORDINALS_H
+#define FLAC__ORDINALS_H
+
+#if defined(_MSC_VER) && _MSC_VER < 1600
+
+/* Microsoft Visual Studio earlier than the 2010 version did not provide
+ * the 1999 ISO C Standard header file <stdint.h>.
+ */
+
+typedef signed __int8 FLAC__int8;
+typedef signed __int16 FLAC__int16;
+typedef signed __int32 FLAC__int32;
+typedef signed __int64 FLAC__int64;
+typedef unsigned __int8 FLAC__uint8;
+typedef unsigned __int16 FLAC__uint16;
+typedef unsigned __int32 FLAC__uint32;
+typedef unsigned __int64 FLAC__uint64;
+
+#else
+
+/* For MSVC 2010 and everything else which provides <stdint.h>. */
+
+#include <stdint.h>
+
+typedef int8_t FLAC__int8;
+typedef uint8_t FLAC__uint8;
+
+typedef int16_t FLAC__int16;
+typedef int32_t FLAC__int32;
+typedef int64_t FLAC__int64;
+typedef uint16_t FLAC__uint16;
+typedef uint32_t FLAC__uint32;
+typedef uint64_t FLAC__uint64;
+
+#endif
+
+typedef int FLAC__bool;
+
+typedef FLAC__uint8 FLAC__byte;
+
+
+#ifdef true
+#undef true
+#endif
+#ifdef false
+#undef false
+#endif
+#ifndef __cplusplus
+#define true 1
+#define false 0
+#endif
+
+#endif
--- /dev/null
+++ b/src/libflac/FLAC/stream_decoder.h
@@ -1,0 +1,1559 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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.
+ */
+
+#ifndef FLAC__STREAM_DECODER_H
+#define FLAC__STREAM_DECODER_H
+
+#include <stdio.h> /* for FILE */
+#include "export.h"
+#include "format.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** \file include/FLAC/stream_decoder.h
+ *
+ *  \brief
+ *  This module contains the functions which implement the stream
+ *  decoder.
+ *
+ *  See the detailed documentation in the
+ *  \link flac_stream_decoder stream decoder \endlink module.
+ */
+
+/** \defgroup flac_decoder FLAC/ \*_decoder.h: decoder interfaces
+ *  \ingroup flac
+ *
+ *  \brief
+ *  This module describes the decoder layers provided by libFLAC.
+ *
+ * The stream decoder can be used to decode complete streams either from
+ * the client via callbacks, or directly from a file, depending on how
+ * it is initialized.  When decoding via callbacks, the client provides
+ * callbacks for reading FLAC data and writing decoded samples, and
+ * handling metadata and errors.  If the client also supplies seek-related
+ * callback, the decoder function for sample-accurate seeking within the
+ * FLAC input is also available.  When decoding from a file, the client
+ * needs only supply a filename or open \c FILE* and write/metadata/error
+ * callbacks; the rest of the callbacks are supplied internally.  For more
+ * info see the \link flac_stream_decoder stream decoder \endlink module.
+ */
+
+/** \defgroup flac_stream_decoder FLAC/stream_decoder.h: stream decoder interface
+ *  \ingroup flac_decoder
+ *
+ *  \brief
+ *  This module contains the functions which implement the stream
+ *  decoder.
+ *
+ * The stream decoder can decode native FLAC, and optionally Ogg FLAC
+ * (check FLAC_API_SUPPORTS_OGG_FLAC) streams and files.
+ *
+ * The basic usage of this decoder is as follows:
+ * - The program creates an instance of a decoder using
+ *   FLAC__stream_decoder_new().
+ * - The program overrides the default settings using
+ *   FLAC__stream_decoder_set_*() functions.
+ * - The program initializes the instance to validate the settings and
+ *   prepare for decoding using
+ *   - FLAC__stream_decoder_init_stream() or FLAC__stream_decoder_init_FILE()
+ *     or FLAC__stream_decoder_init_file() for native FLAC,
+ *   - FLAC__stream_decoder_init_ogg_stream() or FLAC__stream_decoder_init_ogg_FILE()
+ *     or FLAC__stream_decoder_init_ogg_file() for Ogg FLAC
+ * - The program calls the FLAC__stream_decoder_process_*() functions
+ *   to decode data, which subsequently calls the callbacks.
+ * - The program finishes the decoding with FLAC__stream_decoder_finish(),
+ *   which flushes the input and output and resets the decoder to the
+ *   uninitialized state.
+ * - The instance may be used again or deleted with
+ *   FLAC__stream_decoder_delete().
+ *
+ * In more detail, the program will create a new instance by calling
+ * FLAC__stream_decoder_new(), then call FLAC__stream_decoder_set_*()
+ * functions to override the default decoder options, and call
+ * one of the FLAC__stream_decoder_init_*() functions.
+ *
+ * There are three initialization functions for native FLAC, one for
+ * setting up the decoder to decode FLAC data from the client via
+ * callbacks, and two for decoding directly from a FLAC file.
+ *
+ * For decoding via callbacks, use FLAC__stream_decoder_init_stream().
+ * You must also supply several callbacks for handling I/O.  Some (like
+ * seeking) are optional, depending on the capabilities of the input.
+ *
+ * For decoding directly from a file, use FLAC__stream_decoder_init_FILE()
+ * or FLAC__stream_decoder_init_file().  Then you must only supply an open
+ * \c FILE* or filename and fewer callbacks; the decoder will handle
+ * the other callbacks internally.
+ *
+ * There are three similarly-named init functions for decoding from Ogg
+ * FLAC streams.  Check \c FLAC_API_SUPPORTS_OGG_FLAC to find out if the
+ * library has been built with Ogg support.
+ *
+ * Once the decoder is initialized, your program will call one of several
+ * functions to start the decoding process:
+ *
+ * - FLAC__stream_decoder_process_single() - Tells the decoder to process at
+ *   most one metadata block or audio frame and return, calling either the
+ *   metadata callback or write callback, respectively, once.  If the decoder
+ *   loses sync it will return with only the error callback being called.
+ * - FLAC__stream_decoder_process_until_end_of_metadata() - Tells the decoder
+ *   to process the stream from the current location and stop upon reaching
+ *   the first audio frame.  The client will get one metadata, write, or error
+ *   callback per metadata block, audio frame, or sync error, respectively.
+ * - FLAC__stream_decoder_process_until_end_of_stream() - Tells the decoder
+ *   to process the stream from the current location until the read callback
+ *   returns FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM or
+ *   FLAC__STREAM_DECODER_READ_STATUS_ABORT.  The client will get one metadata,
+ *   write, or error callback per metadata block, audio frame, or sync error,
+ *   respectively.
+ *
+ * When the decoder has finished decoding (normally or through an abort),
+ * the instance is finished by calling FLAC__stream_decoder_finish(), which
+ * ensures the decoder is in the correct state and frees memory.  Then the
+ * instance may be deleted with FLAC__stream_decoder_delete() or initialized
+ * again to decode another stream.
+ *
+ * Seeking is exposed through the FLAC__stream_decoder_seek_absolute() method.
+ * At any point after the stream decoder has been initialized, the client can
+ * call this function to seek to an exact sample within the stream.
+ * Subsequently, the first time the write callback is called it will be
+ * passed a (possibly partial) block starting at that sample.
+ *
+ * If the client cannot seek via the callback interface provided, but still
+ * has another way of seeking, it can flush the decoder using
+ * FLAC__stream_decoder_flush() and start feeding data from the new position
+ * through the read callback.
+ *
+ * The stream decoder also provides MD5 signature checking.  If this is
+ * turned on before initialization, FLAC__stream_decoder_finish() will
+ * report when the decoded MD5 signature does not match the one stored
+ * in the STREAMINFO block.  MD5 checking is automatically turned off
+ * (until the next FLAC__stream_decoder_reset()) if there is no signature
+ * in the STREAMINFO block or when a seek is attempted.
+ *
+ * The FLAC__stream_decoder_set_metadata_*() functions deserve special
+ * attention.  By default, the decoder only calls the metadata_callback for
+ * the STREAMINFO block.  These functions allow you to tell the decoder
+ * explicitly which blocks to parse and return via the metadata_callback
+ * and/or which to skip.  Use a FLAC__stream_decoder_set_metadata_respond_all(),
+ * FLAC__stream_decoder_set_metadata_ignore() ... or FLAC__stream_decoder_set_metadata_ignore_all(),
+ * FLAC__stream_decoder_set_metadata_respond() ... sequence to exactly specify
+ * which blocks to return.  Remember that metadata blocks can potentially
+ * be big (for example, cover art) so filtering out the ones you don't
+ * use can reduce the memory requirements of the decoder.  Also note the
+ * special forms FLAC__stream_decoder_set_metadata_respond_application(id)
+ * and FLAC__stream_decoder_set_metadata_ignore_application(id) for
+ * filtering APPLICATION blocks based on the application ID.
+ *
+ * STREAMINFO and SEEKTABLE blocks are always parsed and used internally, but
+ * they still can legally be filtered from the metadata_callback.
+ *
+ * \note
+ * The "set" functions may only be called when the decoder is in the
+ * state FLAC__STREAM_DECODER_UNINITIALIZED, i.e. after
+ * FLAC__stream_decoder_new() or FLAC__stream_decoder_finish(), but
+ * before FLAC__stream_decoder_init_*().  If this is the case they will
+ * return \c true, otherwise \c false.
+ *
+ * \note
+ * FLAC__stream_decoder_finish() resets all settings to the constructor
+ * defaults, including the callbacks.
+ *
+ * \{
+ */
+
+
+/** State values for a FLAC__StreamDecoder
+ *
+ * The decoder's state can be obtained by calling FLAC__stream_decoder_get_state().
+ */
+typedef enum {
+
+	FLAC__STREAM_DECODER_SEARCH_FOR_METADATA = 0,
+	/**< The decoder is ready to search for metadata. */
+
+	FLAC__STREAM_DECODER_READ_METADATA,
+	/**< The decoder is ready to or is in the process of reading metadata. */
+
+	FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC,
+	/**< The decoder is ready to or is in the process of searching for the
+	 * frame sync code.
+	 */
+
+	FLAC__STREAM_DECODER_READ_FRAME,
+	/**< The decoder is ready to or is in the process of reading a frame. */
+
+	FLAC__STREAM_DECODER_END_OF_STREAM,
+	/**< The decoder has reached the end of the stream. */
+
+	FLAC__STREAM_DECODER_OGG_ERROR,
+	/**< An error occurred in the underlying Ogg layer.  */
+
+	FLAC__STREAM_DECODER_SEEK_ERROR,
+	/**< An error occurred while seeking.  The decoder must be flushed
+	 * with FLAC__stream_decoder_flush() or reset with
+	 * FLAC__stream_decoder_reset() before decoding can continue.
+	 */
+
+	FLAC__STREAM_DECODER_ABORTED,
+	/**< The decoder was aborted by the read or write callback. */
+
+	FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR,
+	/**< An error occurred allocating memory.  The decoder is in an invalid
+	 * state and can no longer be used.
+	 */
+
+	FLAC__STREAM_DECODER_UNINITIALIZED
+	/**< The decoder is in the uninitialized state; one of the
+	 * FLAC__stream_decoder_init_*() functions must be called before samples
+	 * can be processed.
+	 */
+
+} FLAC__StreamDecoderState;
+
+/** Maps a FLAC__StreamDecoderState to a C string.
+ *
+ *  Using a FLAC__StreamDecoderState as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderStateString[];
+
+
+/** Possible return values for the FLAC__stream_decoder_init_*() functions.
+ */
+typedef enum {
+
+	FLAC__STREAM_DECODER_INIT_STATUS_OK = 0,
+	/**< Initialization was successful. */
+
+	FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER,
+	/**< The library was not compiled with support for the given container
+	 * format.
+	 */
+
+	FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS,
+	/**< A required callback was not supplied. */
+
+	FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR,
+	/**< An error occurred allocating memory. */
+
+	FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE,
+	/**< fopen() failed in FLAC__stream_decoder_init_file() or
+	 * FLAC__stream_decoder_init_ogg_file(). */
+
+	FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED
+	/**< FLAC__stream_decoder_init_*() was called when the decoder was
+	 * already initialized, usually because
+	 * FLAC__stream_decoder_finish() was not called.
+	 */
+
+} FLAC__StreamDecoderInitStatus;
+
+/** Maps a FLAC__StreamDecoderInitStatus to a C string.
+ *
+ *  Using a FLAC__StreamDecoderInitStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderInitStatusString[];
+
+
+/** Return values for the FLAC__StreamDecoder read callback.
+ */
+typedef enum {
+
+	FLAC__STREAM_DECODER_READ_STATUS_CONTINUE,
+	/**< The read was OK and decoding can continue. */
+
+	FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM,
+	/**< The read was attempted while at the end of the stream.  Note that
+	 * the client must only return this value when the read callback was
+	 * called when already at the end of the stream.  Otherwise, if the read
+	 * itself moves to the end of the stream, the client should still return
+	 * the data and \c FLAC__STREAM_DECODER_READ_STATUS_CONTINUE, and then on
+	 * the next read callback it should return
+	 * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM with a byte count
+	 * of \c 0.
+	 */
+
+	FLAC__STREAM_DECODER_READ_STATUS_ABORT
+	/**< An unrecoverable error occurred.  The decoder will return from the process call. */
+
+} FLAC__StreamDecoderReadStatus;
+
+/** Maps a FLAC__StreamDecoderReadStatus to a C string.
+ *
+ *  Using a FLAC__StreamDecoderReadStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderReadStatusString[];
+
+
+/** Return values for the FLAC__StreamDecoder seek callback.
+ */
+typedef enum {
+
+	FLAC__STREAM_DECODER_SEEK_STATUS_OK,
+	/**< The seek was OK and decoding can continue. */
+
+	FLAC__STREAM_DECODER_SEEK_STATUS_ERROR,
+	/**< An unrecoverable error occurred.  The decoder will return from the process call. */
+
+	FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED
+	/**< Client does not support seeking. */
+
+} FLAC__StreamDecoderSeekStatus;
+
+/** Maps a FLAC__StreamDecoderSeekStatus to a C string.
+ *
+ *  Using a FLAC__StreamDecoderSeekStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderSeekStatusString[];
+
+
+/** Return values for the FLAC__StreamDecoder tell callback.
+ */
+typedef enum {
+
+	FLAC__STREAM_DECODER_TELL_STATUS_OK,
+	/**< The tell was OK and decoding can continue. */
+
+	FLAC__STREAM_DECODER_TELL_STATUS_ERROR,
+	/**< An unrecoverable error occurred.  The decoder will return from the process call. */
+
+	FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED
+	/**< Client does not support telling the position. */
+
+} FLAC__StreamDecoderTellStatus;
+
+/** Maps a FLAC__StreamDecoderTellStatus to a C string.
+ *
+ *  Using a FLAC__StreamDecoderTellStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderTellStatusString[];
+
+
+/** Return values for the FLAC__StreamDecoder length callback.
+ */
+typedef enum {
+
+	FLAC__STREAM_DECODER_LENGTH_STATUS_OK,
+	/**< The length call was OK and decoding can continue. */
+
+	FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR,
+	/**< An unrecoverable error occurred.  The decoder will return from the process call. */
+
+	FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED
+	/**< Client does not support reporting the length. */
+
+} FLAC__StreamDecoderLengthStatus;
+
+/** Maps a FLAC__StreamDecoderLengthStatus to a C string.
+ *
+ *  Using a FLAC__StreamDecoderLengthStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderLengthStatusString[];
+
+
+/** Return values for the FLAC__StreamDecoder write callback.
+ */
+typedef enum {
+
+	FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE,
+	/**< The write was OK and decoding can continue. */
+
+	FLAC__STREAM_DECODER_WRITE_STATUS_ABORT
+	/**< An unrecoverable error occurred.  The decoder will return from the process call. */
+
+} FLAC__StreamDecoderWriteStatus;
+
+/** Maps a FLAC__StreamDecoderWriteStatus to a C string.
+ *
+ *  Using a FLAC__StreamDecoderWriteStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderWriteStatusString[];
+
+
+/** Possible values passed back to the FLAC__StreamDecoder error callback.
+ *  \c FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC is the generic catch-
+ *  all.  The rest could be caused by bad sync (false synchronization on
+ *  data that is not the start of a frame) or corrupted data.  The error
+ *  itself is the decoder's best guess at what happened assuming a correct
+ *  sync.  For example \c FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER
+ *  could be caused by a correct sync on the start of a frame, but some
+ *  data in the frame header was corrupted.  Or it could be the result of
+ *  syncing on a point the stream that looked like the starting of a frame
+ *  but was not.  \c FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM
+ *  could be because the decoder encountered a valid frame made by a future
+ *  version of the encoder which it cannot parse, or because of a false
+ *  sync making it appear as though an encountered frame was generated by
+ *  a future encoder.
+ */
+typedef enum {
+
+	FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC,
+	/**< An error in the stream caused the decoder to lose synchronization. */
+
+	FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER,
+	/**< The decoder encountered a corrupted frame header. */
+
+	FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH,
+	/**< The frame's data did not match the CRC in the footer. */
+
+	FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM
+	/**< The decoder encountered reserved fields in use in the stream. */
+
+} FLAC__StreamDecoderErrorStatus;
+
+/** Maps a FLAC__StreamDecoderErrorStatus to a C string.
+ *
+ *  Using a FLAC__StreamDecoderErrorStatus as the index to this array
+ *  will give the string equivalent.  The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderErrorStatusString[];
+
+
+/***********************************************************************
+ *
+ * class FLAC__StreamDecoder
+ *
+ ***********************************************************************/
+
+struct FLAC__StreamDecoderProtected;
+struct FLAC__StreamDecoderPrivate;
+/** The opaque structure definition for the stream decoder type.
+ *  See the \link flac_stream_decoder stream decoder module \endlink
+ *  for a detailed description.
+ */
+typedef struct {
+	struct FLAC__StreamDecoderProtected *protected_; /* avoid the C++ keyword 'protected' */
+	struct FLAC__StreamDecoderPrivate *private_; /* avoid the C++ keyword 'private' */
+} FLAC__StreamDecoder;
+
+/** Signature for the read callback.
+ *
+ *  A function pointer matching this signature must be passed to
+ *  FLAC__stream_decoder_init*_stream(). The supplied function will be
+ *  called when the decoder needs more input data.  The address of the
+ *  buffer to be filled is supplied, along with the number of bytes the
+ *  buffer can hold.  The callback may choose to supply less data and
+ *  modify the byte count but must be careful not to overflow the buffer.
+ *  The callback then returns a status code chosen from
+ *  FLAC__StreamDecoderReadStatus.
+ *
+ * Here is an example of a read callback for stdio streams:
+ * \code
+ * FLAC__StreamDecoderReadStatus read_cb(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+ * {
+ *   FILE *file = ((MyClientData*)client_data)->file;
+ *   if(*bytes > 0) {
+ *     *bytes = fread(buffer, sizeof(FLAC__byte), *bytes, file);
+ *     if(ferror(file))
+ *       return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+ *     else if(*bytes == 0)
+ *       return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+ *     else
+ *       return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+ *   }
+ *   else
+ *     return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+ * }
+ * \endcode
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
+ * \param  decoder  The decoder instance calling the callback.
+ * \param  buffer   A pointer to a location for the callee to store
+ *                  data to be decoded.
+ * \param  bytes    A pointer to the size of the buffer.  On entry
+ *                  to the callback, it contains the maximum number
+ *                  of bytes that may be stored in \a buffer.  The
+ *                  callee must set it to the actual number of bytes
+ *                  stored (0 in case of error or end-of-stream) before
+ *                  returning.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__stream_decoder_init_*().
+ * \retval FLAC__StreamDecoderReadStatus
+ *    The callee's return status.  Note that the callback should return
+ *    \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM if and only if
+ *    zero bytes were read and there is no more data to be read.
+ */
+typedef FLAC__StreamDecoderReadStatus (*FLAC__StreamDecoderReadCallback)(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
+
+/** Signature for the seek callback.
+ *
+ *  A function pointer matching this signature may be passed to
+ *  FLAC__stream_decoder_init*_stream().  The supplied function will be
+ *  called when the decoder needs to seek the input stream.  The decoder
+ *  will pass the absolute byte offset to seek to, 0 meaning the
+ *  beginning of the stream.
+ *
+ * Here is an example of a seek callback for stdio streams:
+ * \code
+ * FLAC__StreamDecoderSeekStatus seek_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+ * {
+ *   FILE *file = ((MyClientData*)client_data)->file;
+ *   if(file == stdin)
+ *     return FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED;
+ *   else if(fseeko(file, (off_t)absolute_byte_offset, SEEK_SET) < 0)
+ *     return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+ *   else
+ *     return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
+ * }
+ * \endcode
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
+ * \param  decoder  The decoder instance calling the callback.
+ * \param  absolute_byte_offset  The offset from the beginning of the stream
+ *                               to seek to.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__stream_decoder_init_*().
+ * \retval FLAC__StreamDecoderSeekStatus
+ *    The callee's return status.
+ */
+typedef FLAC__StreamDecoderSeekStatus (*FLAC__StreamDecoderSeekCallback)(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data);
+
+/** Signature for the tell callback.
+ *
+ *  A function pointer matching this signature may be passed to
+ *  FLAC__stream_decoder_init*_stream().  The supplied function will be
+ *  called when the decoder wants to know the current position of the
+ *  stream.  The callback should return the byte offset from the
+ *  beginning of the stream.
+ *
+ * Here is an example of a tell callback for stdio streams:
+ * \code
+ * FLAC__StreamDecoderTellStatus tell_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+ * {
+ *   FILE *file = ((MyClientData*)client_data)->file;
+ *   off_t pos;
+ *   if(file == stdin)
+ *     return FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED;
+ *   else if((pos = ftello(file)) < 0)
+ *     return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+ *   else {
+ *     *absolute_byte_offset = (FLAC__uint64)pos;
+ *     return FLAC__STREAM_DECODER_TELL_STATUS_OK;
+ *   }
+ * }
+ * \endcode
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
+ * \param  decoder  The decoder instance calling the callback.
+ * \param  absolute_byte_offset  A pointer to storage for the current offset
+ *                               from the beginning of the stream.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__stream_decoder_init_*().
+ * \retval FLAC__StreamDecoderTellStatus
+ *    The callee's return status.
+ */
+typedef FLAC__StreamDecoderTellStatus (*FLAC__StreamDecoderTellCallback)(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
+
+/** Signature for the length callback.
+ *
+ *  A function pointer matching this signature may be passed to
+ *  FLAC__stream_decoder_init*_stream().  The supplied function will be
+ *  called when the decoder wants to know the total length of the stream
+ *  in bytes.
+ *
+ * Here is an example of a length callback for stdio streams:
+ * \code
+ * FLAC__StreamDecoderLengthStatus length_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data)
+ * {
+ *   FILE *file = ((MyClientData*)client_data)->file;
+ *   struct stat filestats;
+ *
+ *   if(file == stdin)
+ *     return FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED;
+ *   else if(fstat(fileno(file), &filestats) != 0)
+ *     return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
+ *   else {
+ *     *stream_length = (FLAC__uint64)filestats.st_size;
+ *     return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
+ *   }
+ * }
+ * \endcode
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
+ * \param  decoder  The decoder instance calling the callback.
+ * \param  stream_length  A pointer to storage for the length of the stream
+ *                        in bytes.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__stream_decoder_init_*().
+ * \retval FLAC__StreamDecoderLengthStatus
+ *    The callee's return status.
+ */
+typedef FLAC__StreamDecoderLengthStatus (*FLAC__StreamDecoderLengthCallback)(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data);
+
+/** Signature for the EOF callback.
+ *
+ *  A function pointer matching this signature may be passed to
+ *  FLAC__stream_decoder_init*_stream().  The supplied function will be
+ *  called when the decoder needs to know if the end of the stream has
+ *  been reached.
+ *
+ * Here is an example of a EOF callback for stdio streams:
+ * FLAC__bool eof_cb(const FLAC__StreamDecoder *decoder, void *client_data)
+ * \code
+ * {
+ *   FILE *file = ((MyClientData*)client_data)->file;
+ *   return feof(file)? true : false;
+ * }
+ * \endcode
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
+ * \param  decoder  The decoder instance calling the callback.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__stream_decoder_init_*().
+ * \retval FLAC__bool
+ *    \c true if the currently at the end of the stream, else \c false.
+ */
+typedef FLAC__bool (*FLAC__StreamDecoderEofCallback)(const FLAC__StreamDecoder *decoder, void *client_data);
+
+/** Signature for the write callback.
+ *
+ *  A function pointer matching this signature must be passed to one of
+ *  the FLAC__stream_decoder_init_*() functions.
+ *  The supplied function will be called when the decoder has decoded a
+ *  single audio frame.  The decoder will pass the frame metadata as well
+ *  as an array of pointers (one for each channel) pointing to the
+ *  decoded audio.
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
+ * \param  decoder  The decoder instance calling the callback.
+ * \param  frame    The description of the decoded frame.  See
+ *                  FLAC__Frame.
+ * \param  buffer   An array of pointers to decoded channels of data.
+ *                  Each pointer will point to an array of signed
+ *                  samples of length \a frame->header.blocksize.
+ *                  Channels will be ordered according to the FLAC
+ *                  specification; see the documentation for the
+ *                  <A HREF="../format.html#frame_header">frame header</A>.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__stream_decoder_init_*().
+ * \retval FLAC__StreamDecoderWriteStatus
+ *    The callee's return status.
+ */
+typedef FLAC__StreamDecoderWriteStatus (*FLAC__StreamDecoderWriteCallback)(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
+
+/** Signature for the metadata callback.
+ *
+ *  A function pointer matching this signature must be passed to one of
+ *  the FLAC__stream_decoder_init_*() functions.
+ *  The supplied function will be called when the decoder has decoded a
+ *  metadata block.  In a valid FLAC file there will always be one
+ *  \c STREAMINFO block, followed by zero or more other metadata blocks.
+ *  These will be supplied by the decoder in the same order as they
+ *  appear in the stream and always before the first audio frame (i.e.
+ *  write callback).  The metadata block that is passed in must not be
+ *  modified, and it doesn't live beyond the callback, so you should make
+ *  a copy of it with FLAC__metadata_object_clone() if you will need it
+ *  elsewhere.  Since metadata blocks can potentially be large, by
+ *  default the decoder only calls the metadata callback for the
+ *  \c STREAMINFO block; you can instruct the decoder to pass or filter
+ *  other blocks with FLAC__stream_decoder_set_metadata_*() calls.
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
+ * \param  decoder  The decoder instance calling the callback.
+ * \param  metadata The decoded metadata block.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__stream_decoder_init_*().
+ */
+typedef void (*FLAC__StreamDecoderMetadataCallback)(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
+
+/** Signature for the error callback.
+ *
+ *  A function pointer matching this signature must be passed to one of
+ *  the FLAC__stream_decoder_init_*() functions.
+ *  The supplied function will be called whenever an error occurs during
+ *  decoding.
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
+ * \param  decoder  The decoder instance calling the callback.
+ * \param  status   The error encountered by the decoder.
+ * \param  client_data  The callee's client data set through
+ *                      FLAC__stream_decoder_init_*().
+ */
+typedef void (*FLAC__StreamDecoderErrorCallback)(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
+
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ ***********************************************************************/
+
+/** Create a new stream decoder instance.  The instance is created with
+ *  default settings; see the individual FLAC__stream_decoder_set_*()
+ *  functions for each setting's default.
+ *
+ * \retval FLAC__StreamDecoder*
+ *    \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__StreamDecoder *FLAC__stream_decoder_new(void);
+
+/** Free a decoder instance.  Deletes the object pointed to by \a decoder.
+ *
+ * \param decoder  A pointer to an existing decoder.
+ * \assert
+ *    \code decoder != NULL \endcode
+ */
+FLAC_API void FLAC__stream_decoder_delete(FLAC__StreamDecoder *decoder);
+
+
+/***********************************************************************
+ *
+ * Public class method prototypes
+ *
+ ***********************************************************************/
+
+/** Set the serial number for the FLAC stream within the Ogg container.
+ *  The default behavior is to use the serial number of the first Ogg
+ *  page.  Setting a serial number here will explicitly specify which
+ *  stream is to be decoded.
+ *
+ * \note
+ * This does not need to be set for native FLAC decoding.
+ *
+ * \default \c use serial number of first page
+ * \param  decoder        A decoder instance to set.
+ * \param  serial_number  See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_ogg_serial_number(FLAC__StreamDecoder *decoder, long serial_number);
+
+/** Set the "MD5 signature checking" flag.  If \c true, the decoder will
+ *  compute the MD5 signature of the unencoded audio data while decoding
+ *  and compare it to the signature from the STREAMINFO block, if it
+ *  exists, during FLAC__stream_decoder_finish().
+ *
+ *  MD5 signature checking will be turned off (until the next
+ *  FLAC__stream_decoder_reset()) if there is no signature in the
+ *  STREAMINFO block or when a seek is attempted.
+ *
+ *  Clients that do not use the MD5 check should leave this off to speed
+ *  up decoding.
+ *
+ * \default \c false
+ * \param  decoder  A decoder instance to set.
+ * \param  value    Flag value (see above).
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_md5_checking(FLAC__StreamDecoder *decoder, FLAC__bool value);
+
+/** Direct the decoder to pass on all metadata blocks of type \a type.
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ *          metadata callback.
+ * \param  decoder  A decoder instance to set.
+ * \param  type     See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \a type is valid
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond(FLAC__StreamDecoder *decoder, FLAC__MetadataType type);
+
+/** Direct the decoder to pass on all APPLICATION metadata blocks of the
+ *  given \a id.
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ *          metadata callback.
+ * \param  decoder  A decoder instance to set.
+ * \param  id       See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \code id != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4]);
+
+/** Direct the decoder to pass on all metadata blocks of any type.
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ *          metadata callback.
+ * \param  decoder  A decoder instance to set.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_all(FLAC__StreamDecoder *decoder);
+
+/** Direct the decoder to filter out all metadata blocks of type \a type.
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ *          metadata callback.
+ * \param  decoder  A decoder instance to set.
+ * \param  type     See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \a type is valid
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore(FLAC__StreamDecoder *decoder, FLAC__MetadataType type);
+
+/** Direct the decoder to filter out all APPLICATION metadata blocks of
+ *  the given \a id.
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ *          metadata callback.
+ * \param  decoder  A decoder instance to set.
+ * \param  id       See above.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \code id != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4]);
+
+/** Direct the decoder to filter out all metadata blocks of any type.
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ *          metadata callback.
+ * \param  decoder  A decoder instance to set.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_all(FLAC__StreamDecoder *decoder);
+
+/** Get the current decoder state.
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__StreamDecoderState
+ *    The current decoder state.
+ */
+FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_get_state(const FLAC__StreamDecoder *decoder);
+
+/** Get the current decoder state as a C string.
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval const char *
+ *    The decoder state as a C string.  Do not modify the contents.
+ */
+FLAC_API const char *FLAC__stream_decoder_get_resolved_state_string(const FLAC__StreamDecoder *decoder);
+
+/** Get the "MD5 signature checking" flag.
+ *  This is the value of the setting, not whether or not the decoder is
+ *  currently checking the MD5 (remember, it can be turned off automatically
+ *  by a seek).  When the decoder is reset the flag will be restored to the
+ *  value returned by this function.
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See above.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_get_md5_checking(const FLAC__StreamDecoder *decoder);
+
+/** Get the total number of samples in the stream being decoded.
+ *  Will only be valid after decoding has started and will contain the
+ *  value from the \c STREAMINFO block.  A value of \c 0 means "unknown".
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval uint32_t
+ *    See above.
+ */
+FLAC_API FLAC__uint64 FLAC__stream_decoder_get_total_samples(const FLAC__StreamDecoder *decoder);
+
+/** Get the current number of channels in the stream being decoded.
+ *  Will only be valid after decoding has started and will contain the
+ *  value from the most recently decoded frame header.
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval uint32_t
+ *    See above.
+ */
+FLAC_API uint32_t FLAC__stream_decoder_get_channels(const FLAC__StreamDecoder *decoder);
+
+/** Get the current channel assignment in the stream being decoded.
+ *  Will only be valid after decoding has started and will contain the
+ *  value from the most recently decoded frame header.
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__ChannelAssignment
+ *    See above.
+ */
+FLAC_API FLAC__ChannelAssignment FLAC__stream_decoder_get_channel_assignment(const FLAC__StreamDecoder *decoder);
+
+/** Get the current sample resolution in the stream being decoded.
+ *  Will only be valid after decoding has started and will contain the
+ *  value from the most recently decoded frame header.
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval uint32_t
+ *    See above.
+ */
+FLAC_API uint32_t FLAC__stream_decoder_get_bits_per_sample(const FLAC__StreamDecoder *decoder);
+
+/** Get the current sample rate in Hz of the stream being decoded.
+ *  Will only be valid after decoding has started and will contain the
+ *  value from the most recently decoded frame header.
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval uint32_t
+ *    See above.
+ */
+FLAC_API uint32_t FLAC__stream_decoder_get_sample_rate(const FLAC__StreamDecoder *decoder);
+
+/** Get the current blocksize of the stream being decoded.
+ *  Will only be valid after decoding has started and will contain the
+ *  value from the most recently decoded frame header.
+ *
+ * \param  decoder  A decoder instance to query.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval uint32_t
+ *    See above.
+ */
+FLAC_API uint32_t FLAC__stream_decoder_get_blocksize(const FLAC__StreamDecoder *decoder);
+
+/** Returns the decoder's current read position within the stream.
+ *  The position is the byte offset from the start of the stream.
+ *  Bytes before this position have been fully decoded.  Note that
+ *  there may still be undecoded bytes in the decoder's read FIFO.
+ *  The returned position is correct even after a seek.
+ *
+ *  \warning This function currently only works for native FLAC,
+ *           not Ogg FLAC streams.
+ *
+ * \param  decoder   A decoder instance to query.
+ * \param  position  Address at which to return the desired position.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \code position != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if successful, \c false if the stream is not native FLAC,
+ *    or there was an error from the 'tell' callback or it returned
+ *    \c FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_get_decode_position(const FLAC__StreamDecoder *decoder, FLAC__uint64 *position);
+
+/** Initialize the decoder instance to decode native FLAC streams.
+ *
+ *  This flavor of initialization sets up the decoder to decode from a
+ *  native FLAC stream. I/O is performed via callbacks to the client.
+ *  For decoding from a plain file via filename or open FILE*,
+ *  FLAC__stream_decoder_init_file() and FLAC__stream_decoder_init_FILE()
+ *  provide a simpler interface.
+ *
+ *  This function should be called after FLAC__stream_decoder_new() and
+ *  FLAC__stream_decoder_set_*() but before any of the
+ *  FLAC__stream_decoder_process_*() functions.  Will set and return the
+ *  decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA
+ *  if initialization succeeded.
+ *
+ * \param  decoder            An uninitialized decoder instance.
+ * \param  read_callback      See FLAC__StreamDecoderReadCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  seek_callback      See FLAC__StreamDecoderSeekCallback.  This
+ *                            pointer may be \c NULL if seeking is not
+ *                            supported.  If \a seek_callback is not \c NULL then a
+ *                            \a tell_callback, \a length_callback, and \a eof_callback must also be supplied.
+ *                            Alternatively, a dummy seek callback that just
+ *                            returns \c FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED
+ *                            may also be supplied, all though this is slightly
+ *                            less efficient for the decoder.
+ * \param  tell_callback      See FLAC__StreamDecoderTellCallback.  This
+ *                            pointer may be \c NULL if not supported by the client.  If
+ *                            \a seek_callback is not \c NULL then a
+ *                            \a tell_callback must also be supplied.
+ *                            Alternatively, a dummy tell callback that just
+ *                            returns \c FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED
+ *                            may also be supplied, all though this is slightly
+ *                            less efficient for the decoder.
+ * \param  length_callback    See FLAC__StreamDecoderLengthCallback.  This
+ *                            pointer may be \c NULL if not supported by the client.  If
+ *                            \a seek_callback is not \c NULL then a
+ *                            \a length_callback must also be supplied.
+ *                            Alternatively, a dummy length callback that just
+ *                            returns \c FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED
+ *                            may also be supplied, all though this is slightly
+ *                            less efficient for the decoder.
+ * \param  eof_callback       See FLAC__StreamDecoderEofCallback.  This
+ *                            pointer may be \c NULL if not supported by the client.  If
+ *                            \a seek_callback is not \c NULL then a
+ *                            \a eof_callback must also be supplied.
+ *                            Alternatively, a dummy length callback that just
+ *                            returns \c false
+ *                            may also be supplied, all though this is slightly
+ *                            less efficient for the decoder.
+ * \param  write_callback     See FLAC__StreamDecoderWriteCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  metadata_callback  See FLAC__StreamDecoderMetadataCallback.  This
+ *                            pointer may be \c NULL if the callback is not
+ *                            desired.
+ * \param  error_callback     See FLAC__StreamDecoderErrorCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  client_data        This value will be supplied to callbacks in their
+ *                            \a client_data argument.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__StreamDecoderInitStatus
+ *    \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful;
+ *    see FLAC__StreamDecoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_stream(
+	FLAC__StreamDecoder *decoder,
+	FLAC__StreamDecoderReadCallback read_callback,
+	FLAC__StreamDecoderSeekCallback seek_callback,
+	FLAC__StreamDecoderTellCallback tell_callback,
+	FLAC__StreamDecoderLengthCallback length_callback,
+	FLAC__StreamDecoderEofCallback eof_callback,
+	FLAC__StreamDecoderWriteCallback write_callback,
+	FLAC__StreamDecoderMetadataCallback metadata_callback,
+	FLAC__StreamDecoderErrorCallback error_callback,
+	void *client_data
+);
+
+/** Initialize the decoder instance to decode Ogg FLAC streams.
+ *
+ *  This flavor of initialization sets up the decoder to decode from a
+ *  FLAC stream in an Ogg container. I/O is performed via callbacks to the
+ *  client.  For decoding from a plain file via filename or open FILE*,
+ *  FLAC__stream_decoder_init_ogg_file() and FLAC__stream_decoder_init_ogg_FILE()
+ *  provide a simpler interface.
+ *
+ *  This function should be called after FLAC__stream_decoder_new() and
+ *  FLAC__stream_decoder_set_*() but before any of the
+ *  FLAC__stream_decoder_process_*() functions.  Will set and return the
+ *  decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA
+ *  if initialization succeeded.
+ *
+ *  \note Support for Ogg FLAC in the library is optional.  If this
+ *  library has been built without support for Ogg FLAC, this function
+ *  will return \c FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER.
+ *
+ * \param  decoder            An uninitialized decoder instance.
+ * \param  read_callback      See FLAC__StreamDecoderReadCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  seek_callback      See FLAC__StreamDecoderSeekCallback.  This
+ *                            pointer may be \c NULL if seeking is not
+ *                            supported.  If \a seek_callback is not \c NULL then a
+ *                            \a tell_callback, \a length_callback, and \a eof_callback must also be supplied.
+ *                            Alternatively, a dummy seek callback that just
+ *                            returns \c FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED
+ *                            may also be supplied, all though this is slightly
+ *                            less efficient for the decoder.
+ * \param  tell_callback      See FLAC__StreamDecoderTellCallback.  This
+ *                            pointer may be \c NULL if not supported by the client.  If
+ *                            \a seek_callback is not \c NULL then a
+ *                            \a tell_callback must also be supplied.
+ *                            Alternatively, a dummy tell callback that just
+ *                            returns \c FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED
+ *                            may also be supplied, all though this is slightly
+ *                            less efficient for the decoder.
+ * \param  length_callback    See FLAC__StreamDecoderLengthCallback.  This
+ *                            pointer may be \c NULL if not supported by the client.  If
+ *                            \a seek_callback is not \c NULL then a
+ *                            \a length_callback must also be supplied.
+ *                            Alternatively, a dummy length callback that just
+ *                            returns \c FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED
+ *                            may also be supplied, all though this is slightly
+ *                            less efficient for the decoder.
+ * \param  eof_callback       See FLAC__StreamDecoderEofCallback.  This
+ *                            pointer may be \c NULL if not supported by the client.  If
+ *                            \a seek_callback is not \c NULL then a
+ *                            \a eof_callback must also be supplied.
+ *                            Alternatively, a dummy length callback that just
+ *                            returns \c false
+ *                            may also be supplied, all though this is slightly
+ *                            less efficient for the decoder.
+ * \param  write_callback     See FLAC__StreamDecoderWriteCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  metadata_callback  See FLAC__StreamDecoderMetadataCallback.  This
+ *                            pointer may be \c NULL if the callback is not
+ *                            desired.
+ * \param  error_callback     See FLAC__StreamDecoderErrorCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  client_data        This value will be supplied to callbacks in their
+ *                            \a client_data argument.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__StreamDecoderInitStatus
+ *    \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful;
+ *    see FLAC__StreamDecoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_stream(
+	FLAC__StreamDecoder *decoder,
+	FLAC__StreamDecoderReadCallback read_callback,
+	FLAC__StreamDecoderSeekCallback seek_callback,
+	FLAC__StreamDecoderTellCallback tell_callback,
+	FLAC__StreamDecoderLengthCallback length_callback,
+	FLAC__StreamDecoderEofCallback eof_callback,
+	FLAC__StreamDecoderWriteCallback write_callback,
+	FLAC__StreamDecoderMetadataCallback metadata_callback,
+	FLAC__StreamDecoderErrorCallback error_callback,
+	void *client_data
+);
+
+/** Initialize the decoder instance to decode native FLAC files.
+ *
+ *  This flavor of initialization sets up the decoder to decode from a
+ *  plain native FLAC file.  For non-stdio streams, you must use
+ *  FLAC__stream_decoder_init_stream() and provide callbacks for the I/O.
+ *
+ *  This function should be called after FLAC__stream_decoder_new() and
+ *  FLAC__stream_decoder_set_*() but before any of the
+ *  FLAC__stream_decoder_process_*() functions.  Will set and return the
+ *  decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA
+ *  if initialization succeeded.
+ *
+ * \param  decoder            An uninitialized decoder instance.
+ * \param  file               An open FLAC file.  The file should have been
+ *                            opened with mode \c "rb" and rewound.  The file
+ *                            becomes owned by the decoder and should not be
+ *                            manipulated by the client while decoding.
+ *                            Unless \a file is \c stdin, it will be closed
+ *                            when FLAC__stream_decoder_finish() is called.
+ *                            Note however that seeking will not work when
+ *                            decoding from \c stdin since it is not seekable.
+ * \param  write_callback     See FLAC__StreamDecoderWriteCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  metadata_callback  See FLAC__StreamDecoderMetadataCallback.  This
+ *                            pointer may be \c NULL if the callback is not
+ *                            desired.
+ * \param  error_callback     See FLAC__StreamDecoderErrorCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  client_data        This value will be supplied to callbacks in their
+ *                            \a client_data argument.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \code file != NULL \endcode
+ * \retval FLAC__StreamDecoderInitStatus
+ *    \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful;
+ *    see FLAC__StreamDecoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_FILE(
+	FLAC__StreamDecoder *decoder,
+	FILE *file,
+	FLAC__StreamDecoderWriteCallback write_callback,
+	FLAC__StreamDecoderMetadataCallback metadata_callback,
+	FLAC__StreamDecoderErrorCallback error_callback,
+	void *client_data
+);
+
+/** Initialize the decoder instance to decode Ogg FLAC files.
+ *
+ *  This flavor of initialization sets up the decoder to decode from a
+ *  plain Ogg FLAC file.  For non-stdio streams, you must use
+ *  FLAC__stream_decoder_init_ogg_stream() and provide callbacks for the I/O.
+ *
+ *  This function should be called after FLAC__stream_decoder_new() and
+ *  FLAC__stream_decoder_set_*() but before any of the
+ *  FLAC__stream_decoder_process_*() functions.  Will set and return the
+ *  decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA
+ *  if initialization succeeded.
+ *
+ *  \note Support for Ogg FLAC in the library is optional.  If this
+ *  library has been built without support for Ogg FLAC, this function
+ *  will return \c FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER.
+ *
+ * \param  decoder            An uninitialized decoder instance.
+ * \param  file               An open FLAC file.  The file should have been
+ *                            opened with mode \c "rb" and rewound.  The file
+ *                            becomes owned by the decoder and should not be
+ *                            manipulated by the client while decoding.
+ *                            Unless \a file is \c stdin, it will be closed
+ *                            when FLAC__stream_decoder_finish() is called.
+ *                            Note however that seeking will not work when
+ *                            decoding from \c stdin since it is not seekable.
+ * \param  write_callback     See FLAC__StreamDecoderWriteCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  metadata_callback  See FLAC__StreamDecoderMetadataCallback.  This
+ *                            pointer may be \c NULL if the callback is not
+ *                            desired.
+ * \param  error_callback     See FLAC__StreamDecoderErrorCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  client_data        This value will be supplied to callbacks in their
+ *                            \a client_data argument.
+ * \assert
+ *    \code decoder != NULL \endcode
+ *    \code file != NULL \endcode
+ * \retval FLAC__StreamDecoderInitStatus
+ *    \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful;
+ *    see FLAC__StreamDecoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_FILE(
+	FLAC__StreamDecoder *decoder,
+	FILE *file,
+	FLAC__StreamDecoderWriteCallback write_callback,
+	FLAC__StreamDecoderMetadataCallback metadata_callback,
+	FLAC__StreamDecoderErrorCallback error_callback,
+	void *client_data
+);
+
+/** Initialize the decoder instance to decode native FLAC files.
+ *
+ *  This flavor of initialization sets up the decoder to decode from a plain
+ *  native FLAC file.  If POSIX fopen() semantics are not sufficient, (for
+ *  example, with Unicode filenames on Windows), you must use
+ *  FLAC__stream_decoder_init_FILE(), or FLAC__stream_decoder_init_stream()
+ *  and provide callbacks for the I/O.
+ *
+ *  This function should be called after FLAC__stream_decoder_new() and
+ *  FLAC__stream_decoder_set_*() but before any of the
+ *  FLAC__stream_decoder_process_*() functions.  Will set and return the
+ *  decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA
+ *  if initialization succeeded.
+ *
+ * \param  decoder            An uninitialized decoder instance.
+ * \param  filename           The name of the file to decode from.  The file will
+ *                            be opened with fopen().  Use \c NULL to decode from
+ *                            \c stdin.  Note that \c stdin is not seekable.
+ * \param  write_callback     See FLAC__StreamDecoderWriteCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  metadata_callback  See FLAC__StreamDecoderMetadataCallback.  This
+ *                            pointer may be \c NULL if the callback is not
+ *                            desired.
+ * \param  error_callback     See FLAC__StreamDecoderErrorCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  client_data        This value will be supplied to callbacks in their
+ *                            \a client_data argument.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__StreamDecoderInitStatus
+ *    \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful;
+ *    see FLAC__StreamDecoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_file(
+	FLAC__StreamDecoder *decoder,
+	const char *filename,
+	FLAC__StreamDecoderWriteCallback write_callback,
+	FLAC__StreamDecoderMetadataCallback metadata_callback,
+	FLAC__StreamDecoderErrorCallback error_callback,
+	void *client_data
+);
+
+/** Initialize the decoder instance to decode Ogg FLAC files.
+ *
+ *  This flavor of initialization sets up the decoder to decode from a plain
+ *  Ogg FLAC file.  If POSIX fopen() semantics are not sufficient, (for
+ *  example, with Unicode filenames on Windows), you must use
+ *  FLAC__stream_decoder_init_ogg_FILE(), or FLAC__stream_decoder_init_ogg_stream()
+ *  and provide callbacks for the I/O.
+ *
+ *  This function should be called after FLAC__stream_decoder_new() and
+ *  FLAC__stream_decoder_set_*() but before any of the
+ *  FLAC__stream_decoder_process_*() functions.  Will set and return the
+ *  decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA
+ *  if initialization succeeded.
+ *
+ *  \note Support for Ogg FLAC in the library is optional.  If this
+ *  library has been built without support for Ogg FLAC, this function
+ *  will return \c FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER.
+ *
+ * \param  decoder            An uninitialized decoder instance.
+ * \param  filename           The name of the file to decode from.  The file will
+ *                            be opened with fopen().  Use \c NULL to decode from
+ *                            \c stdin.  Note that \c stdin is not seekable.
+ * \param  write_callback     See FLAC__StreamDecoderWriteCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  metadata_callback  See FLAC__StreamDecoderMetadataCallback.  This
+ *                            pointer may be \c NULL if the callback is not
+ *                            desired.
+ * \param  error_callback     See FLAC__StreamDecoderErrorCallback.  This
+ *                            pointer must not be \c NULL.
+ * \param  client_data        This value will be supplied to callbacks in their
+ *                            \a client_data argument.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__StreamDecoderInitStatus
+ *    \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful;
+ *    see FLAC__StreamDecoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_file(
+	FLAC__StreamDecoder *decoder,
+	const char *filename,
+	FLAC__StreamDecoderWriteCallback write_callback,
+	FLAC__StreamDecoderMetadataCallback metadata_callback,
+	FLAC__StreamDecoderErrorCallback error_callback,
+	void *client_data
+);
+
+/** Finish the decoding process.
+ *  Flushes the decoding buffer, releases resources, resets the decoder
+ *  settings to their defaults, and returns the decoder state to
+ *  FLAC__STREAM_DECODER_UNINITIALIZED.
+ *
+ *  In the event of a prematurely-terminated decode, it is not strictly
+ *  necessary to call this immediately before FLAC__stream_decoder_delete()
+ *  but it is good practice to match every FLAC__stream_decoder_init_*()
+ *  with a FLAC__stream_decoder_finish().
+ *
+ * \param  decoder  An uninitialized decoder instance.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if MD5 checking is on AND a STREAMINFO block was available
+ *    AND the MD5 signature in the STREAMINFO block was non-zero AND the
+ *    signature does not match the one computed by the decoder; else
+ *    \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_finish(FLAC__StreamDecoder *decoder);
+
+/** Flush the stream input.
+ *  The decoder's input buffer will be cleared and the state set to
+ *  \c FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC.  This will also turn
+ *  off MD5 checking.
+ *
+ * \param  decoder  A decoder instance.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if successful, else \c false if a memory allocation
+ *    error occurs (in which case the state will be set to
+ *    \c FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR).
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_flush(FLAC__StreamDecoder *decoder);
+
+/** Reset the decoding process.
+ *  The decoder's input buffer will be cleared and the state set to
+ *  \c FLAC__STREAM_DECODER_SEARCH_FOR_METADATA.  This is similar to
+ *  FLAC__stream_decoder_finish() except that the settings are
+ *  preserved; there is no need to call FLAC__stream_decoder_init_*()
+ *  before decoding again.  MD5 checking will be restored to its original
+ *  setting.
+ *
+ *  If the decoder is seekable, or was initialized with
+ *  FLAC__stream_decoder_init*_FILE() or FLAC__stream_decoder_init*_file(),
+ *  the decoder will also attempt to seek to the beginning of the file.
+ *  If this rewind fails, this function will return \c false.  It follows
+ *  that FLAC__stream_decoder_reset() cannot be used when decoding from
+ *  \c stdin.
+ *
+ *  If the decoder was initialized with FLAC__stream_encoder_init*_stream()
+ *  and is not seekable (i.e. no seek callback was provided or the seek
+ *  callback returns \c FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED), it
+ *  is the duty of the client to start feeding data from the beginning of
+ *  the stream on the next FLAC__stream_decoder_process_*() call.
+ *
+ * \param  decoder  A decoder instance.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if successful, else \c false if a memory allocation occurs
+ *    (in which case the state will be set to
+ *    \c FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR) or a seek error
+ *    occurs (the state will be unchanged).
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_reset(FLAC__StreamDecoder *decoder);
+
+/** Decode one metadata block or audio frame.
+ *  This version instructs the decoder to decode a either a single metadata
+ *  block or a single frame and stop, unless the callbacks return a fatal
+ *  error or the read callback returns
+ *  \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM.
+ *
+ *  As the decoder needs more input it will call the read callback.
+ *  Depending on what was decoded, the metadata or write callback will be
+ *  called with the decoded metadata block or audio frame.
+ *
+ *  Unless there is a fatal read error or end of stream, this function
+ *  will return once one whole frame is decoded.  In other words, if the
+ *  stream is not synchronized or points to a corrupt frame header, the
+ *  decoder will continue to try and resync until it gets to a valid
+ *  frame, then decode one frame, then return.  If the decoder points to
+ *  a frame whose frame CRC in the frame footer does not match the
+ *  computed frame CRC, this function will issue a
+ *  FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH error to the
+ *  error callback, and return, having decoded one complete, although
+ *  corrupt, frame.  (Such corrupted frames are sent as silence of the
+ *  correct length to the write callback.)
+ *
+ * \param  decoder  An initialized decoder instance.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if any fatal read, write, or memory allocation error
+ *    occurred (meaning decoding must stop), else \c true; for more
+ *    information about the decoder, check the decoder state with
+ *    FLAC__stream_decoder_get_state().
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_process_single(FLAC__StreamDecoder *decoder);
+
+/** Decode until the end of the metadata.
+ *  This version instructs the decoder to decode from the current position
+ *  and continue until all the metadata has been read, or until the
+ *  callbacks return a fatal error or the read callback returns
+ *  \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM.
+ *
+ *  As the decoder needs more input it will call the read callback.
+ *  As each metadata block is decoded, the metadata callback will be called
+ *  with the decoded metadata.
+ *
+ * \param  decoder  An initialized decoder instance.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if any fatal read, write, or memory allocation error
+ *    occurred (meaning decoding must stop), else \c true; for more
+ *    information about the decoder, check the decoder state with
+ *    FLAC__stream_decoder_get_state().
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_metadata(FLAC__StreamDecoder *decoder);
+
+/** Decode until the end of the stream.
+ *  This version instructs the decoder to decode from the current position
+ *  and continue until the end of stream (the read callback returns
+ *  \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM), or until the
+ *  callbacks return a fatal error.
+ *
+ *  As the decoder needs more input it will call the read callback.
+ *  As each metadata block and frame is decoded, the metadata or write
+ *  callback will be called with the decoded metadata or frame.
+ *
+ * \param  decoder  An initialized decoder instance.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if any fatal read, write, or memory allocation error
+ *    occurred (meaning decoding must stop), else \c true; for more
+ *    information about the decoder, check the decoder state with
+ *    FLAC__stream_decoder_get_state().
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_stream(FLAC__StreamDecoder *decoder);
+
+/** Skip one audio frame.
+ *  This version instructs the decoder to 'skip' a single frame and stop,
+ *  unless the callbacks return a fatal error or the read callback returns
+ *  \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM.
+ *
+ *  The decoding flow is the same as what occurs when
+ *  FLAC__stream_decoder_process_single() is called to process an audio
+ *  frame, except that this function does not decode the parsed data into
+ *  PCM or call the write callback.  The integrity of the frame is still
+ *  checked the same way as in the other process functions.
+ *
+ *  This function will return once one whole frame is skipped, in the
+ *  same way that FLAC__stream_decoder_process_single() will return once
+ *  one whole frame is decoded.
+ *
+ *  This function can be used in more quickly determining FLAC frame
+ *  boundaries when decoding of the actual data is not needed, for
+ *  example when an application is separating a FLAC stream into frames
+ *  for editing or storing in a container.  To do this, the application
+ *  can use FLAC__stream_decoder_skip_single_frame() to quickly advance
+ *  to the next frame, then use
+ *  FLAC__stream_decoder_get_decode_position() to find the new frame
+ *  boundary.
+ *
+ *  This function should only be called when the stream has advanced
+ *  past all the metadata, otherwise it will return \c false.
+ *
+ * \param  decoder  An initialized decoder instance not in a metadata
+ *                  state.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if any fatal read, write, or memory allocation error
+ *    occurred (meaning decoding must stop), or if the decoder
+ *    is in the FLAC__STREAM_DECODER_SEARCH_FOR_METADATA or
+ *    FLAC__STREAM_DECODER_READ_METADATA state, else \c true; for more
+ *    information about the decoder, check the decoder state with
+ *    FLAC__stream_decoder_get_state().
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_skip_single_frame(FLAC__StreamDecoder *decoder);
+
+/** Flush the input and seek to an absolute sample.
+ *  Decoding will resume at the given sample.  Note that because of
+ *  this, the next write callback may contain a partial block.  The
+ *  client must support seeking the input or this function will fail
+ *  and return \c false.  Furthermore, if the decoder state is
+ *  \c FLAC__STREAM_DECODER_SEEK_ERROR, then the decoder must be flushed
+ *  with FLAC__stream_decoder_flush() or reset with
+ *  FLAC__stream_decoder_reset() before decoding can continue.
+ *
+ * \param  decoder  A decoder instance.
+ * \param  sample   The target sample number to seek to.
+ * \assert
+ *    \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c true if successful, else \c false.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_seek_absolute(FLAC__StreamDecoder *decoder, FLAC__uint64 sample);
+
+/* \} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+++ b/src/libflac/NOTE.txt
@@ -1,0 +1,4 @@
+8bitbubsy:
+This is a cut down and modified version of libFLAC v1.3.3.
+I have removed stuff I don't want, and only left the decoder in. Please don't
+use this outside of the PT2 clone project!
--- /dev/null
+++ b/src/libflac/bitmath.c
@@ -1,0 +1,69 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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.
+ */
+
+#include "private/bitmath.h"
+
+/* An example of what FLAC__bitmath_silog2() computes:
+ *
+ * silog2(-10) = 5
+ * silog2(- 9) = 5
+ * silog2(- 8) = 4
+ * silog2(- 7) = 4
+ * silog2(- 6) = 4
+ * silog2(- 5) = 4
+ * silog2(- 4) = 3
+ * silog2(- 3) = 3
+ * silog2(- 2) = 2
+ * silog2(- 1) = 2
+ * silog2(  0) = 0
+ * silog2(  1) = 2
+ * silog2(  2) = 3
+ * silog2(  3) = 3
+ * silog2(  4) = 4
+ * silog2(  5) = 4
+ * silog2(  6) = 4
+ * silog2(  7) = 4
+ * silog2(  8) = 5
+ * silog2(  9) = 5
+ * silog2( 10) = 5
+ */
+uint32_t FLAC__bitmath_silog2(FLAC__int64 v)
+{
+	if(v == 0)
+		return 0;
+
+	if(v == -1)
+		return 2;
+
+	v = (v < 0) ? (-(v+1)) : v;
+	return FLAC__bitmath_ilog2_wide(v)+2;
+}
--- /dev/null
+++ b/src/libflac/bitreader.c
@@ -1,0 +1,914 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2018  Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "private/bitmath.h"
+#include "private/bitreader.h"
+#include "private/crc.h"
+#include "private/macros.h"
+#include "share/compat.h"
+#include "share/endswap.h"
+
+/* Things should be fastest when this matches the machine word size */
+/* WATCHOUT: if you change this you must also change the following #defines down to COUNT_ZERO_MSBS2 below to match */
+/* WATCHOUT: there are a few places where the code will not work unless brword is >= 32 bits wide */
+/*           also, some sections currently only have fast versions for 4 or 8 bytes per word */
+
+#if (ENABLE_64_BIT_WORDS == 0)
+
+typedef FLAC__uint32 brword;
+#define FLAC__BYTES_PER_WORD 4		/* sizeof brword */
+#define FLAC__BITS_PER_WORD 32
+#define FLAC__WORD_ALL_ONES ((FLAC__uint32)0xffffffff)
+/* SWAP_BE_WORD_TO_HOST swaps bytes in a brword (which is always big-endian) if necessary to match host byte order */
+#define SWAP_BE_WORD_TO_HOST(x) ENDSWAP_32(x)
+/* counts the # of zero MSBs in a word */
+#define COUNT_ZERO_MSBS(word) FLAC__clz_uint32(word)
+#define COUNT_ZERO_MSBS2(word) FLAC__clz2_uint32(word)
+
+#else
+
+typedef FLAC__uint64 brword;
+#define FLAC__BYTES_PER_WORD 8		/* sizeof brword */
+#define FLAC__BITS_PER_WORD 64
+#define FLAC__WORD_ALL_ONES ((FLAC__uint64)FLAC__U64L(0xffffffffffffffff))
+/* SWAP_BE_WORD_TO_HOST swaps bytes in a brword (which is always big-endian) if necessary to match host byte order */
+#define SWAP_BE_WORD_TO_HOST(x) ENDSWAP_64(x)
+/* counts the # of zero MSBs in a word */
+#define COUNT_ZERO_MSBS(word) FLAC__clz_uint64(word)
+#define COUNT_ZERO_MSBS2(word) FLAC__clz2_uint64(word)
+
+#endif
+
+/*
+ * This should be at least twice as large as the largest number of words
+ * required to represent any 'number' (in any encoding) you are going to
+ * read.  With FLAC this is on the order of maybe a few hundred bits.
+ * If the buffer is smaller than that, the decoder won't be able to read
+ * in a whole number that is in a variable length encoding (e.g. Rice).
+ * But to be practical it should be at least 1K bytes.
+ *
+ * Increase this number to decrease the number of read callbacks, at the
+ * expense of using more memory.  Or decrease for the reverse effect,
+ * keeping in mind the limit from the first paragraph.  The optimal size
+ * also depends on the CPU cache size and other factors; some twiddling
+ * may be necessary to squeeze out the best performance.
+ */
+static const uint32_t FLAC__BITREADER_DEFAULT_CAPACITY = 65536u / FLAC__BITS_PER_WORD; /* in words */
+
+struct FLAC__BitReader {
+	/* any partially-consumed word at the head will stay right-justified as bits are consumed from the left */
+	/* any incomplete word at the tail will be left-justified, and bytes from the read callback are added on the right */
+	brword *buffer;
+	uint32_t capacity; /* in words */
+	uint32_t words; /* # of completed words in buffer */
+	uint32_t bytes; /* # of bytes in incomplete word at buffer[words] */
+	uint32_t consumed_words; /* #words ... */
+	uint32_t consumed_bits; /* ... + (#bits of head word) already consumed from the front of buffer */
+	uint32_t read_crc16; /* the running frame CRC */
+	uint32_t crc16_offset; /* the number of words in the current buffer that should not be CRC'd */
+	uint32_t crc16_align; /* the number of bits in the current consumed word that should not be CRC'd */
+	FLAC__BitReaderReadCallback read_callback;
+	void *client_data;
+};
+
+static inline void crc16_update_word_(FLAC__BitReader *br, brword word)
+{
+	register uint32_t crc = br->read_crc16;
+
+	for( ; br->crc16_align < FLAC__BITS_PER_WORD; br->crc16_align += 8)
+		crc = FLAC__CRC16_UPDATE((uint32_t)((word >> (FLAC__BITS_PER_WORD-8-br->crc16_align)) & 0xff), crc);
+
+	br->read_crc16 = crc;
+	br->crc16_align = 0;
+}
+
+static inline void crc16_update_block_(FLAC__BitReader *br)
+{
+	if(br->consumed_words > br->crc16_offset && br->crc16_align)
+		crc16_update_word_(br, br->buffer[br->crc16_offset++]);
+
+#if FLAC__BYTES_PER_WORD == 4
+	br->read_crc16 = FLAC__crc16_update_words32(br->buffer + br->crc16_offset, br->consumed_words - br->crc16_offset, (FLAC__uint16)br->read_crc16);
+#elif FLAC__BYTES_PER_WORD == 8
+	br->read_crc16 = FLAC__crc16_update_words64(br->buffer + br->crc16_offset, br->consumed_words - br->crc16_offset, br->read_crc16);
+#else
+	unsigned i;
+
+	for(i = br->crc16_offset; i < br->consumed_words; i++)
+		crc16_update_word_(br, br->buffer[i]);
+#endif
+
+	br->crc16_offset = 0;
+}
+
+static FLAC__bool bitreader_read_from_client_(FLAC__BitReader *br)
+{
+	uint32_t start, end;
+	size_t bytes;
+	FLAC__byte *target;
+
+	/* first shift the unconsumed buffer data toward the front as much as possible */
+	if(br->consumed_words > 0) {
+		crc16_update_block_(br); /* CRC consumed words */
+
+		start = br->consumed_words;
+		end = br->words + (br->bytes? 1:0);
+		memmove(br->buffer, br->buffer+start, FLAC__BYTES_PER_WORD * (end - start));
+
+		br->words -= start;
+		br->consumed_words = 0;
+	}
+
+	/*
+	 * set the target for reading, taking into account word alignment and endianness
+	 */
+	bytes = (br->capacity - br->words) * FLAC__BYTES_PER_WORD - br->bytes;
+	if(bytes == 0)
+		return false; /* no space left, buffer is too small; see note for FLAC__BITREADER_DEFAULT_CAPACITY  */
+	target = ((FLAC__byte*)(br->buffer+br->words)) + br->bytes;
+
+	/* before reading, if the existing reader looks like this (say brword is 32 bits wide)
+	 *   bitstream :  11 22 33 44 55            br->words=1 br->bytes=1 (partial tail word is left-justified)
+	 *   buffer[BE]:  11 22 33 44 55 ?? ?? ??   (shown laid out as bytes sequentially in memory)
+	 *   buffer[LE]:  44 33 22 11 ?? ?? ?? 55   (?? being don't-care)
+	 *                               ^^-------target, bytes=3
+	 * on LE machines, have to byteswap the odd tail word so nothing is
+	 * overwritten:
+	 */
+	if(br->bytes)
+		br->buffer[br->words] = SWAP_BE_WORD_TO_HOST(br->buffer[br->words]);
+
+	/* now it looks like:
+	 *   bitstream :  11 22 33 44 55            br->words=1 br->bytes=1
+	 *   buffer[BE]:  11 22 33 44 55 ?? ?? ??
+	 *   buffer[LE]:  44 33 22 11 55 ?? ?? ??
+	 *                               ^^-------target, bytes=3
+	 */
+
+	/* read in the data; note that the callback may return a smaller number of bytes */
+	if(!br->read_callback(target, &bytes, br->client_data))
+		return false;
+
+	/* after reading bytes 66 77 88 99 AA BB CC DD EE FF from the client:
+	 *   bitstream :  11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF
+	 *   buffer[BE]:  11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF ??
+	 *   buffer[LE]:  44 33 22 11 55 66 77 88 99 AA BB CC DD EE FF ??
+	 * now have to byteswap on LE machines:
+	 */
+	end = (br->words*FLAC__BYTES_PER_WORD + br->bytes + (uint32_t)bytes + (FLAC__BYTES_PER_WORD-1)) / FLAC__BYTES_PER_WORD;
+	for(start = br->words; start < end; start++)
+		br->buffer[start] = SWAP_BE_WORD_TO_HOST(br->buffer[start]);
+
+	/* now it looks like:
+	 *   bitstream :  11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF
+	 *   buffer[BE]:  11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF ??
+	 *   buffer[LE]:  44 33 22 11 88 77 66 55 CC BB AA 99 ?? FF EE DD
+	 * finally we'll update the reader values:
+	 */
+	end = br->words*FLAC__BYTES_PER_WORD + br->bytes + (uint32_t)bytes;
+	br->words = end / FLAC__BYTES_PER_WORD;
+	br->bytes = end % FLAC__BYTES_PER_WORD;
+
+	return true;
+}
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ ***********************************************************************/
+
+FLAC__BitReader *FLAC__bitreader_new(void)
+{
+	FLAC__BitReader *br = calloc(1, sizeof(FLAC__BitReader));
+
+	/* calloc() implies:
+		memset(br, 0, sizeof(FLAC__BitReader));
+		br->buffer = 0;
+		br->capacity = 0;
+		br->words = br->bytes = 0;
+		br->consumed_words = br->consumed_bits = 0;
+		br->read_callback = 0;
+		br->client_data = 0;
+	*/
+	return br;
+}
+
+void FLAC__bitreader_delete(FLAC__BitReader *br)
+{
+	FLAC__bitreader_free(br);
+	free(br);
+}
+
+/***********************************************************************
+ *
+ * Public class methods
+ *
+ ***********************************************************************/
+
+FLAC__bool FLAC__bitreader_init(FLAC__BitReader *br, FLAC__BitReaderReadCallback rcb, void *cd)
+{
+	br->words = br->bytes = 0;
+	br->consumed_words = br->consumed_bits = 0;
+	br->capacity = FLAC__BITREADER_DEFAULT_CAPACITY;
+	br->buffer = malloc(sizeof(brword) * br->capacity);
+	if(br->buffer == 0)
+		return false;
+	br->read_callback = rcb;
+	br->client_data = cd;
+
+	return true;
+}
+
+void FLAC__bitreader_free(FLAC__BitReader *br)
+{
+	if(0 != br->buffer)
+		free(br->buffer);
+	br->buffer = 0;
+	br->capacity = 0;
+	br->words = br->bytes = 0;
+	br->consumed_words = br->consumed_bits = 0;
+	br->read_callback = 0;
+	br->client_data = 0;
+}
+
+FLAC__bool FLAC__bitreader_clear(FLAC__BitReader *br)
+{
+	br->words = br->bytes = 0;
+	br->consumed_words = br->consumed_bits = 0;
+	return true;
+}
+
+void FLAC__bitreader_dump(const FLAC__BitReader *br, FILE *out)
+{
+	uint32_t i, j;
+	if(br == 0) {
+		fprintf(out, "bitreader is NULL\n");
+	}
+	else {
+		fprintf(out, "bitreader: capacity=%u words=%u bytes=%u consumed: words=%u, bits=%u\n", br->capacity, br->words, br->bytes, br->consumed_words, br->consumed_bits);
+
+		for(i = 0; i < br->words; i++) {
+			fprintf(out, "%08X: ", i);
+			for(j = 0; j < FLAC__BITS_PER_WORD; j++)
+				if(i < br->consumed_words || (i == br->consumed_words && j < br->consumed_bits))
+					fprintf(out, ".");
+				else
+					fprintf(out, "%01d", br->buffer[i] & ((brword)1 << (FLAC__BITS_PER_WORD-j-1)) ? 1:0);
+			fprintf(out, "\n");
+		}
+		if(br->bytes > 0) {
+			fprintf(out, "%08X: ", i);
+			for(j = 0; j < br->bytes*8; j++)
+				if(i < br->consumed_words || (i == br->consumed_words && j < br->consumed_bits))
+					fprintf(out, ".");
+				else
+					fprintf(out, "%01d", br->buffer[i] & ((brword)1 << (br->bytes*8-j-1)) ? 1:0);
+			fprintf(out, "\n");
+		}
+	}
+}
+
+void FLAC__bitreader_reset_read_crc16(FLAC__BitReader *br, FLAC__uint16 seed)
+{
+	br->read_crc16 = (uint32_t)seed;
+	br->crc16_offset = br->consumed_words;
+	br->crc16_align = br->consumed_bits;
+}
+
+FLAC__uint16 FLAC__bitreader_get_read_crc16(FLAC__BitReader *br)
+{
+	/* CRC consumed words up to here */
+	crc16_update_block_(br);
+
+	/* CRC any tail bytes in a partially-consumed word */
+	if(br->consumed_bits) {
+		const brword tail = br->buffer[br->consumed_words];
+		for( ; br->crc16_align < br->consumed_bits; br->crc16_align += 8)
+			br->read_crc16 = FLAC__CRC16_UPDATE((uint32_t)((tail >> (FLAC__BITS_PER_WORD-8-br->crc16_align)) & 0xff), br->read_crc16);
+	}
+	return (FLAC__uint16)br->read_crc16;
+}
+
+inline FLAC__bool FLAC__bitreader_is_consumed_byte_aligned(const FLAC__BitReader *br)
+{
+	return ((br->consumed_bits & 7) == 0);
+}
+
+inline uint32_t FLAC__bitreader_bits_left_for_byte_alignment(const FLAC__BitReader *br)
+{
+	return 8 - (br->consumed_bits & 7);
+}
+
+inline uint32_t FLAC__bitreader_get_input_bits_unconsumed(const FLAC__BitReader *br)
+{
+	return (br->words-br->consumed_words)*FLAC__BITS_PER_WORD + br->bytes*8 - br->consumed_bits;
+}
+
+FLAC__bool FLAC__bitreader_read_raw_uint32(FLAC__BitReader *br, FLAC__uint32 *val, uint32_t bits)
+{
+	if(bits == 0) { /* OPT: investigate if this can ever happen, maybe change to assertion */
+		*val = 0;
+		return true;
+	}
+
+	while((br->words-br->consumed_words)*FLAC__BITS_PER_WORD + br->bytes*8 - br->consumed_bits < bits) {
+		if(!bitreader_read_from_client_(br))
+			return false;
+	}
+	if(br->consumed_words < br->words) { /* if we've not consumed up to a partial tail word... */
+		/* OPT: taking out the consumed_bits==0 "else" case below might make things faster if less code allows the compiler to inline this function */
+		if(br->consumed_bits) {
+			/* this also works when consumed_bits==0, it's just a little slower than necessary for that case */
+			const uint32_t n = FLAC__BITS_PER_WORD - br->consumed_bits;
+			const brword word = br->buffer[br->consumed_words];
+			if(bits < n) {
+				*val = (FLAC__uint32)((word & (FLAC__WORD_ALL_ONES >> br->consumed_bits)) >> (n-bits)); /* The result has <= 32 non-zero bits */
+				br->consumed_bits += bits;
+				return true;
+			}
+			/* (FLAC__BITS_PER_WORD - br->consumed_bits <= bits) ==> (FLAC__WORD_ALL_ONES >> br->consumed_bits) has no more than 'bits' non-zero bits */
+			*val = (FLAC__uint32)(word & (FLAC__WORD_ALL_ONES >> br->consumed_bits));
+			bits -= n;
+			br->consumed_words++;
+			br->consumed_bits = 0;
+			if(bits) { /* if there are still bits left to read, there have to be less than 32 so they will all be in the next word */
+				*val <<= bits;
+				*val |= (FLAC__uint32)(br->buffer[br->consumed_words] >> (FLAC__BITS_PER_WORD-bits));
+				br->consumed_bits = bits;
+			}
+			return true;
+		}
+		else { /* br->consumed_bits == 0 */
+			const brword word = br->buffer[br->consumed_words];
+			if(bits < FLAC__BITS_PER_WORD) {
+				*val = (FLAC__uint32)(word >> (FLAC__BITS_PER_WORD-bits));
+				br->consumed_bits = bits;
+				return true;
+			}
+			/* at this point bits == FLAC__BITS_PER_WORD == 32; because of previous assertions, it can't be larger */
+			*val = (FLAC__uint32)word;
+			br->consumed_words++;
+			return true;
+		}
+	}
+	else {
+		/* in this case we're starting our read at a partial tail word;
+		 * the reader has guaranteed that we have at least 'bits' bits
+		 * available to read, which makes this case simpler.
+		 */
+		/* OPT: taking out the consumed_bits==0 "else" case below might make things faster if less code allows the compiler to inline this function */
+		if(br->consumed_bits) {
+			/* this also works when consumed_bits==0, it's just a little slower than necessary for that case */
+			*val = (FLAC__uint32)((br->buffer[br->consumed_words] & (FLAC__WORD_ALL_ONES >> br->consumed_bits)) >> (FLAC__BITS_PER_WORD-br->consumed_bits-bits));
+			br->consumed_bits += bits;
+			return true;
+		}
+		else {
+			*val = (FLAC__uint32)(br->buffer[br->consumed_words] >> (FLAC__BITS_PER_WORD-bits));
+			br->consumed_bits += bits;
+			return true;
+		}
+	}
+}
+
+FLAC__bool FLAC__bitreader_read_raw_int32(FLAC__BitReader *br, FLAC__int32 *val, uint32_t bits)
+{
+	FLAC__uint32 uval, mask;
+	/* OPT: inline raw uint32 code here, or make into a macro if possible in the .h file */
+	if(!FLAC__bitreader_read_raw_uint32(br, &uval, bits))
+		return false;
+	/* sign-extend *val assuming it is currently bits wide. */
+	/* From: https://graphics.stanford.edu/~seander/bithacks.html#FixedSignExtend */
+	mask = 1u << (bits - 1);
+	*val = (uval ^ mask) - mask;
+	return true;
+}
+
+FLAC__bool FLAC__bitreader_read_raw_uint64(FLAC__BitReader *br, FLAC__uint64 *val, uint32_t bits)
+{
+	FLAC__uint32 hi, lo;
+
+	if(bits > 32) {
+		if(!FLAC__bitreader_read_raw_uint32(br, &hi, bits-32))
+			return false;
+		if(!FLAC__bitreader_read_raw_uint32(br, &lo, 32))
+			return false;
+		*val = hi;
+		*val <<= 32;
+		*val |= lo;
+	}
+	else {
+		if(!FLAC__bitreader_read_raw_uint32(br, &lo, bits))
+			return false;
+		*val = lo;
+	}
+	return true;
+}
+
+inline FLAC__bool FLAC__bitreader_read_uint32_little_endian(FLAC__BitReader *br, FLAC__uint32 *val)
+{
+	FLAC__uint32 x8, x32 = 0;
+
+	/* this doesn't need to be that fast as currently it is only used for vorbis comments */
+
+	if(!FLAC__bitreader_read_raw_uint32(br, &x32, 8))
+		return false;
+
+	if(!FLAC__bitreader_read_raw_uint32(br, &x8, 8))
+		return false;
+	x32 |= (x8 << 8);
+
+	if(!FLAC__bitreader_read_raw_uint32(br, &x8, 8))
+		return false;
+	x32 |= (x8 << 16);
+
+	if(!FLAC__bitreader_read_raw_uint32(br, &x8, 8))
+		return false;
+	x32 |= (x8 << 24);
+
+	*val = x32;
+	return true;
+}
+
+FLAC__bool FLAC__bitreader_skip_bits_no_crc(FLAC__BitReader *br, uint32_t bits)
+{
+	/*
+	 * OPT: a faster implementation is possible but probably not that useful
+	 * since this is only called a couple of times in the metadata readers.
+	 */
+
+	if(bits > 0) {
+		const uint32_t n = br->consumed_bits & 7;
+		uint32_t m;
+		FLAC__uint32 x;
+
+		if(n != 0) {
+			m = flac_min(8-n, bits);
+			if(!FLAC__bitreader_read_raw_uint32(br, &x, m))
+				return false;
+			bits -= m;
+		}
+		m = bits / 8;
+		if(m > 0) {
+			if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(br, m))
+				return false;
+			bits %= 8;
+		}
+		if(bits > 0) {
+			if(!FLAC__bitreader_read_raw_uint32(br, &x, bits))
+				return false;
+		}
+	}
+
+	return true;
+}
+
+FLAC__bool FLAC__bitreader_skip_byte_block_aligned_no_crc(FLAC__BitReader *br, uint32_t nvals)
+{
+	FLAC__uint32 x;
+
+	/* step 1: skip over partial head word to get word aligned */
+	while(nvals && br->consumed_bits) { /* i.e. run until we read 'nvals' bytes or we hit the end of the head word */
+		if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+			return false;
+		nvals--;
+	}
+	if(0 == nvals)
+		return true;
+	/* step 2: skip whole words in chunks */
+	while(nvals >= FLAC__BYTES_PER_WORD) {
+		if(br->consumed_words < br->words) {
+			br->consumed_words++;
+			nvals -= FLAC__BYTES_PER_WORD;
+		}
+		else if(!bitreader_read_from_client_(br))
+			return false;
+	}
+	/* step 3: skip any remainder from partial tail bytes */
+	while(nvals) {
+		if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+			return false;
+		nvals--;
+	}
+
+	return true;
+}
+
+FLAC__bool FLAC__bitreader_read_byte_block_aligned_no_crc(FLAC__BitReader *br, FLAC__byte *val, uint32_t nvals)
+{
+	FLAC__uint32 x;
+
+	/* step 1: read from partial head word to get word aligned */
+	while(nvals && br->consumed_bits) { /* i.e. run until we read 'nvals' bytes or we hit the end of the head word */
+		if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+			return false;
+		*val++ = (FLAC__byte)x;
+		nvals--;
+	}
+	if(0 == nvals)
+		return true;
+	/* step 2: read whole words in chunks */
+	while(nvals >= FLAC__BYTES_PER_WORD) {
+		if(br->consumed_words < br->words) {
+			const brword word = br->buffer[br->consumed_words++];
+#if FLAC__BYTES_PER_WORD == 4
+			val[0] = (FLAC__byte)(word >> 24);
+			val[1] = (FLAC__byte)(word >> 16);
+			val[2] = (FLAC__byte)(word >> 8);
+			val[3] = (FLAC__byte)word;
+#elif FLAC__BYTES_PER_WORD == 8
+			val[0] = (FLAC__byte)(word >> 56);
+			val[1] = (FLAC__byte)(word >> 48);
+			val[2] = (FLAC__byte)(word >> 40);
+			val[3] = (FLAC__byte)(word >> 32);
+			val[4] = (FLAC__byte)(word >> 24);
+			val[5] = (FLAC__byte)(word >> 16);
+			val[6] = (FLAC__byte)(word >> 8);
+			val[7] = (FLAC__byte)word;
+#else
+			for(x = 0; x < FLAC__BYTES_PER_WORD; x++)
+				val[x] = (FLAC__byte)(word >> (8*(FLAC__BYTES_PER_WORD-x-1)));
+#endif
+			val += FLAC__BYTES_PER_WORD;
+			nvals -= FLAC__BYTES_PER_WORD;
+		}
+		else if(!bitreader_read_from_client_(br))
+			return false;
+	}
+	/* step 3: read any remainder from partial tail bytes */
+	while(nvals) {
+		if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+			return false;
+		*val++ = (FLAC__byte)x;
+		nvals--;
+	}
+
+	return true;
+}
+
+FLAC__bool FLAC__bitreader_read_unary_unsigned(FLAC__BitReader *br, uint32_t *val)
+{
+	uint32_t i;
+
+	*val = 0;
+	while(1) {
+		while(br->consumed_words < br->words) { /* if we've not consumed up to a partial tail word... */
+			brword b = br->buffer[br->consumed_words] << br->consumed_bits;
+			if(b) {
+				i = COUNT_ZERO_MSBS(b);
+				*val += i;
+				i++;
+				br->consumed_bits += i;
+				if(br->consumed_bits >= FLAC__BITS_PER_WORD) { /* faster way of testing if(br->consumed_bits == FLAC__BITS_PER_WORD) */
+					br->consumed_words++;
+					br->consumed_bits = 0;
+				}
+				return true;
+			}
+			else {
+				*val += FLAC__BITS_PER_WORD - br->consumed_bits;
+				br->consumed_words++;
+				br->consumed_bits = 0;
+				/* didn't find stop bit yet, have to keep going... */
+			}
+		}
+		/* at this point we've eaten up all the whole words; have to try
+		 * reading through any tail bytes before calling the read callback.
+		 * this is a repeat of the above logic adjusted for the fact we
+		 * don't have a whole word.  note though if the client is feeding
+		 * us data a byte at a time (unlikely), br->consumed_bits may not
+		 * be zero.
+		 */
+		if(br->bytes*8 > br->consumed_bits) {
+			const uint32_t end = br->bytes * 8;
+			brword b = (br->buffer[br->consumed_words] & (FLAC__WORD_ALL_ONES << (FLAC__BITS_PER_WORD-end))) << br->consumed_bits;
+			if(b) {
+				i = COUNT_ZERO_MSBS(b);
+				*val += i;
+				i++;
+				br->consumed_bits += i;
+				return true;
+			}
+			else {
+				*val += end - br->consumed_bits;
+				br->consumed_bits = end;
+				/* didn't find stop bit yet, have to keep going... */
+			}
+		}
+		if(!bitreader_read_from_client_(br))
+			return false;
+	}
+}
+
+FLAC__bool FLAC__bitreader_read_rice_signed(FLAC__BitReader *br, int *val, uint32_t parameter)
+{
+	FLAC__uint32 lsbs = 0, msbs = 0;
+	uint32_t uval;
+
+	/* read the unary MSBs and end bit */
+	if(!FLAC__bitreader_read_unary_unsigned(br, &msbs))
+		return false;
+
+	/* read the binary LSBs */
+	if(!FLAC__bitreader_read_raw_uint32(br, &lsbs, parameter))
+		return false;
+
+	/* compose the value */
+	uval = (msbs << parameter) | lsbs;
+	if(uval & 1)
+		*val = -((int)(uval >> 1)) - 1;
+	else
+		*val = (int)(uval >> 1);
+
+	return true;
+}
+
+/* this is by far the most heavily used reader call.  it ain't pretty but it's fast */
+FLAC__bool FLAC__bitreader_read_rice_signed_block(FLAC__BitReader *br, int vals[], uint32_t nvals, uint32_t parameter)
+{
+	/* try and get br->consumed_words and br->consumed_bits into register;
+	 * must remember to flush them back to *br before calling other
+	 * bitreader functions that use them, and before returning */
+	uint32_t cwords, words, lsbs, msbs, x, y;
+	uint32_t ucbits; /* keep track of the number of unconsumed bits in word */
+	brword b;
+	int *val, *end;
+
+	val = vals;
+	end = vals + nvals;
+
+	if(parameter == 0) {
+		while(val < end) {
+			/* read the unary MSBs and end bit */
+			if(!FLAC__bitreader_read_unary_unsigned(br, &msbs))
+				return false;
+
+			*val++ = (int)(msbs >> 1) ^ -(int)(msbs & 1);
+		}
+
+		return true;
+	}
+
+	cwords = br->consumed_words;
+	words = br->words;
+
+	/* if we've not consumed up to a partial tail word... */
+	if(cwords >= words) {
+		x = 0;
+		goto process_tail;
+	}
+
+	ucbits = FLAC__BITS_PER_WORD - br->consumed_bits;
+	b = br->buffer[cwords] << br->consumed_bits;  /* keep unconsumed bits aligned to left */
+
+	while(val < end) {
+		/* read the unary MSBs and end bit */
+		x = y = COUNT_ZERO_MSBS2(b);
+		if(x == FLAC__BITS_PER_WORD) {
+			x = ucbits;
+			do {
+				/* didn't find stop bit yet, have to keep going... */
+				cwords++;
+				if (cwords >= words)
+					goto incomplete_msbs;
+				b = br->buffer[cwords];
+				y = COUNT_ZERO_MSBS2(b);
+				x += y;
+			} while(y == FLAC__BITS_PER_WORD);
+		}
+		b <<= y;
+		b <<= 1; /* account for stop bit */
+		ucbits = (ucbits - x - 1) % FLAC__BITS_PER_WORD;
+		msbs = x;
+
+		/* read the binary LSBs */
+		x = (FLAC__uint32)(b >> (FLAC__BITS_PER_WORD - parameter)); /* parameter < 32, so we can cast to 32-bit uint32_t */
+		if(parameter <= ucbits) {
+			ucbits -= parameter;
+			b <<= parameter;
+		} else {
+			/* there are still bits left to read, they will all be in the next word */
+			cwords++;
+			if (cwords >= words)
+				goto incomplete_lsbs;
+			b = br->buffer[cwords];
+			ucbits += FLAC__BITS_PER_WORD - parameter;
+			x |= (FLAC__uint32)(b >> ucbits);
+			b <<= FLAC__BITS_PER_WORD - ucbits;
+		}
+		lsbs = x;
+
+		/* compose the value */
+		x = (msbs << parameter) | lsbs;
+		*val++ = (int)(x >> 1) ^ -(int)(x & 1);
+
+		continue;
+
+		/* at this point we've eaten up all the whole words */
+process_tail:
+		do {
+			if(0) {
+incomplete_msbs:
+				br->consumed_bits = 0;
+				br->consumed_words = cwords;
+			}
+
+			/* read the unary MSBs and end bit */
+			if(!FLAC__bitreader_read_unary_unsigned(br, &msbs))
+				return false;
+			msbs += x;
+			x = ucbits = 0;
+
+			if(0) {
+incomplete_lsbs:
+				br->consumed_bits = 0;
+				br->consumed_words = cwords;
+			}
+
+			/* read the binary LSBs */
+			if(!FLAC__bitreader_read_raw_uint32(br, &lsbs, parameter - ucbits))
+				return false;
+			lsbs = x | lsbs;
+
+			/* compose the value */
+			x = (msbs << parameter) | lsbs;
+			*val++ = (int)(x >> 1) ^ -(int)(x & 1);
+			x = 0;
+
+			cwords = br->consumed_words;
+			words = br->words;
+			ucbits = FLAC__BITS_PER_WORD - br->consumed_bits;
+			b = br->buffer[cwords] << br->consumed_bits;
+		} while(cwords >= words && val < end);
+	}
+
+	if(ucbits == 0 && cwords < words) {
+		/* don't leave the head word with no unconsumed bits */
+		cwords++;
+		ucbits = FLAC__BITS_PER_WORD;
+	}
+
+	br->consumed_bits = FLAC__BITS_PER_WORD - ucbits;
+	br->consumed_words = cwords;
+
+	return true;
+}
+
+/* on return, if *val == 0xffffffff then the utf-8 sequence was invalid, but the return value will be true */
+FLAC__bool FLAC__bitreader_read_utf8_uint32(FLAC__BitReader *br, FLAC__uint32 *val, FLAC__byte *raw, uint32_t *rawlen)
+{
+	FLAC__uint32 v = 0;
+	FLAC__uint32 x;
+	uint32_t i;
+
+	if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+		return false;
+	if(raw)
+		raw[(*rawlen)++] = (FLAC__byte)x;
+	if(!(x & 0x80)) { /* 0xxxxxxx */
+		v = x;
+		i = 0;
+	}
+	else if(x & 0xC0 && !(x & 0x20)) { /* 110xxxxx */
+		v = x & 0x1F;
+		i = 1;
+	}
+	else if(x & 0xE0 && !(x & 0x10)) { /* 1110xxxx */
+		v = x & 0x0F;
+		i = 2;
+	}
+	else if(x & 0xF0 && !(x & 0x08)) { /* 11110xxx */
+		v = x & 0x07;
+		i = 3;
+	}
+	else if(x & 0xF8 && !(x & 0x04)) { /* 111110xx */
+		v = x & 0x03;
+		i = 4;
+	}
+	else if(x & 0xFC && !(x & 0x02)) { /* 1111110x */
+		v = x & 0x01;
+		i = 5;
+	}
+	else {
+		*val = 0xffffffff;
+		return true;
+	}
+	for( ; i; i--) {
+		if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+			return false;
+		if(raw)
+			raw[(*rawlen)++] = (FLAC__byte)x;
+		if(!(x & 0x80) || (x & 0x40)) { /* 10xxxxxx */
+			*val = 0xffffffff;
+			return true;
+		}
+		v <<= 6;
+		v |= (x & 0x3F);
+	}
+	*val = v;
+	return true;
+}
+
+/* on return, if *val == 0xffffffffffffffff then the utf-8 sequence was invalid, but the return value will be true */
+FLAC__bool FLAC__bitreader_read_utf8_uint64(FLAC__BitReader *br, FLAC__uint64 *val, FLAC__byte *raw, uint32_t *rawlen)
+{
+	FLAC__uint64 v = 0;
+	FLAC__uint32 x;
+	uint32_t i;
+
+	if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+		return false;
+	if(raw)
+		raw[(*rawlen)++] = (FLAC__byte)x;
+	if(!(x & 0x80)) { /* 0xxxxxxx */
+		v = x;
+		i = 0;
+	}
+	else if(x & 0xC0 && !(x & 0x20)) { /* 110xxxxx */
+		v = x & 0x1F;
+		i = 1;
+	}
+	else if(x & 0xE0 && !(x & 0x10)) { /* 1110xxxx */
+		v = x & 0x0F;
+		i = 2;
+	}
+	else if(x & 0xF0 && !(x & 0x08)) { /* 11110xxx */
+		v = x & 0x07;
+		i = 3;
+	}
+	else if(x & 0xF8 && !(x & 0x04)) { /* 111110xx */
+		v = x & 0x03;
+		i = 4;
+	}
+	else if(x & 0xFC && !(x & 0x02)) { /* 1111110x */
+		v = x & 0x01;
+		i = 5;
+	}
+	else if(x & 0xFE && !(x & 0x01)) { /* 11111110 */
+		v = 0;
+		i = 6;
+	}
+	else {
+		*val = FLAC__U64L(0xffffffffffffffff);
+		return true;
+	}
+	for( ; i; i--) {
+		if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+			return false;
+		if(raw)
+			raw[(*rawlen)++] = (FLAC__byte)x;
+		if(!(x & 0x80) || (x & 0x40)) { /* 10xxxxxx */
+			*val = FLAC__U64L(0xffffffffffffffff);
+			return true;
+		}
+		v <<= 6;
+		v |= (x & 0x3F);
+	}
+	*val = v;
+	return true;
+}
+
+/* These functions are declared inline in this file but are also callable as
+ * externs from elsewhere.
+ * According to the C99 spec, section 6.7.4, simply providing a function
+ * prototype in a header file without 'inline' and making the function inline
+ * in this file should be sufficient.
+ * Unfortunately, the Microsoft VS compiler doesn't pick them up externally. To
+ * fix that we add extern declarations here.
+ */
+extern FLAC__bool FLAC__bitreader_is_consumed_byte_aligned(const FLAC__BitReader *br);
+extern uint32_t FLAC__bitreader_bits_left_for_byte_alignment(const FLAC__BitReader *br);
+extern uint32_t FLAC__bitreader_get_input_bits_unconsumed(const FLAC__BitReader *br);
+extern FLAC__bool FLAC__bitreader_read_uint32_little_endian(FLAC__BitReader *br, FLAC__uint32 *val);
--- /dev/null
+++ b/src/libflac/crc.c
@@ -1,0 +1,410 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2018  Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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.
+ */
+
+#include "private/crc.h"
+
+/* CRC-8, poly = x^8 + x^2 + x^1 + x^0, init = 0 */
+
+FLAC__uint8 const FLAC__crc8_table[256] = {
+	0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,
+	0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
+	0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
+	0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
+	0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5,
+	0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
+	0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,
+	0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
+	0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,
+	0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
+	0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,
+	0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
+	0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,
+	0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
+	0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,
+	0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
+	0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,
+	0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
+	0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC,
+	0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
+	0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,
+	0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
+	0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,
+	0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
+	0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,
+	0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
+	0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,
+	0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
+	0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,
+	0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
+	0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB,
+	0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
+};
+
+/* CRC-16, poly = x^16 + x^15 + x^2 + x^0, init = 0 */
+
+FLAC__uint16 const FLAC__crc16_table[8][256] = {
+  { 0x0000,  0x8005,  0x800f,  0x000a,  0x801b,  0x001e,  0x0014,  0x8011,
+	0x8033,  0x0036,  0x003c,  0x8039,  0x0028,  0x802d,  0x8027,  0x0022,
+	0x8063,  0x0066,  0x006c,  0x8069,  0x0078,  0x807d,  0x8077,  0x0072,
+	0x0050,  0x8055,  0x805f,  0x005a,  0x804b,  0x004e,  0x0044,  0x8041,
+	0x80c3,  0x00c6,  0x00cc,  0x80c9,  0x00d8,  0x80dd,  0x80d7,  0x00d2,
+	0x00f0,  0x80f5,  0x80ff,  0x00fa,  0x80eb,  0x00ee,  0x00e4,  0x80e1,
+	0x00a0,  0x80a5,  0x80af,  0x00aa,  0x80bb,  0x00be,  0x00b4,  0x80b1,
+	0x8093,  0x0096,  0x009c,  0x8099,  0x0088,  0x808d,  0x8087,  0x0082,
+	0x8183,  0x0186,  0x018c,  0x8189,  0x0198,  0x819d,  0x8197,  0x0192,
+	0x01b0,  0x81b5,  0x81bf,  0x01ba,  0x81ab,  0x01ae,  0x01a4,  0x81a1,
+	0x01e0,  0x81e5,  0x81ef,  0x01ea,  0x81fb,  0x01fe,  0x01f4,  0x81f1,
+	0x81d3,  0x01d6,  0x01dc,  0x81d9,  0x01c8,  0x81cd,  0x81c7,  0x01c2,
+	0x0140,  0x8145,  0x814f,  0x014a,  0x815b,  0x015e,  0x0154,  0x8151,
+	0x8173,  0x0176,  0x017c,  0x8179,  0x0168,  0x816d,  0x8167,  0x0162,
+	0x8123,  0x0126,  0x012c,  0x8129,  0x0138,  0x813d,  0x8137,  0x0132,
+	0x0110,  0x8115,  0x811f,  0x011a,  0x810b,  0x010e,  0x0104,  0x8101,
+	0x8303,  0x0306,  0x030c,  0x8309,  0x0318,  0x831d,  0x8317,  0x0312,
+	0x0330,  0x8335,  0x833f,  0x033a,  0x832b,  0x032e,  0x0324,  0x8321,
+	0x0360,  0x8365,  0x836f,  0x036a,  0x837b,  0x037e,  0x0374,  0x8371,
+	0x8353,  0x0356,  0x035c,  0x8359,  0x0348,  0x834d,  0x8347,  0x0342,
+	0x03c0,  0x83c5,  0x83cf,  0x03ca,  0x83db,  0x03de,  0x03d4,  0x83d1,
+	0x83f3,  0x03f6,  0x03fc,  0x83f9,  0x03e8,  0x83ed,  0x83e7,  0x03e2,
+	0x83a3,  0x03a6,  0x03ac,  0x83a9,  0x03b8,  0x83bd,  0x83b7,  0x03b2,
+	0x0390,  0x8395,  0x839f,  0x039a,  0x838b,  0x038e,  0x0384,  0x8381,
+	0x0280,  0x8285,  0x828f,  0x028a,  0x829b,  0x029e,  0x0294,  0x8291,
+	0x82b3,  0x02b6,  0x02bc,  0x82b9,  0x02a8,  0x82ad,  0x82a7,  0x02a2,
+	0x82e3,  0x02e6,  0x02ec,  0x82e9,  0x02f8,  0x82fd,  0x82f7,  0x02f2,
+	0x02d0,  0x82d5,  0x82df,  0x02da,  0x82cb,  0x02ce,  0x02c4,  0x82c1,
+	0x8243,  0x0246,  0x024c,  0x8249,  0x0258,  0x825d,  0x8257,  0x0252,
+	0x0270,  0x8275,  0x827f,  0x027a,  0x826b,  0x026e,  0x0264,  0x8261,
+	0x0220,  0x8225,  0x822f,  0x022a,  0x823b,  0x023e,  0x0234,  0x8231,
+	0x8213,  0x0216,  0x021c,  0x8219,  0x0208,  0x820d,  0x8207,  0x0202 },
+
+  { 0x0000,  0x8603,  0x8c03,  0x0a00,  0x9803,  0x1e00,  0x1400,  0x9203,
+	0xb003,  0x3600,  0x3c00,  0xba03,  0x2800,  0xae03,  0xa403,  0x2200,
+	0xe003,  0x6600,  0x6c00,  0xea03,  0x7800,  0xfe03,  0xf403,  0x7200,
+	0x5000,  0xd603,  0xdc03,  0x5a00,  0xc803,  0x4e00,  0x4400,  0xc203,
+	0x4003,  0xc600,  0xcc00,  0x4a03,  0xd800,  0x5e03,  0x5403,  0xd200,
+	0xf000,  0x7603,  0x7c03,  0xfa00,  0x6803,  0xee00,  0xe400,  0x6203,
+	0xa000,  0x2603,  0x2c03,  0xaa00,  0x3803,  0xbe00,  0xb400,  0x3203,
+	0x1003,  0x9600,  0x9c00,  0x1a03,  0x8800,  0x0e03,  0x0403,  0x8200,
+	0x8006,  0x0605,  0x0c05,  0x8a06,  0x1805,  0x9e06,  0x9406,  0x1205,
+	0x3005,  0xb606,  0xbc06,  0x3a05,  0xa806,  0x2e05,  0x2405,  0xa206,
+	0x6005,  0xe606,  0xec06,  0x6a05,  0xf806,  0x7e05,  0x7405,  0xf206,
+	0xd006,  0x5605,  0x5c05,  0xda06,  0x4805,  0xce06,  0xc406,  0x4205,
+	0xc005,  0x4606,  0x4c06,  0xca05,  0x5806,  0xde05,  0xd405,  0x5206,
+	0x7006,  0xf605,  0xfc05,  0x7a06,  0xe805,  0x6e06,  0x6406,  0xe205,
+	0x2006,  0xa605,  0xac05,  0x2a06,  0xb805,  0x3e06,  0x3406,  0xb205,
+	0x9005,  0x1606,  0x1c06,  0x9a05,  0x0806,  0x8e05,  0x8405,  0x0206,
+	0x8009,  0x060a,  0x0c0a,  0x8a09,  0x180a,  0x9e09,  0x9409,  0x120a,
+	0x300a,  0xb609,  0xbc09,  0x3a0a,  0xa809,  0x2e0a,  0x240a,  0xa209,
+	0x600a,  0xe609,  0xec09,  0x6a0a,  0xf809,  0x7e0a,  0x740a,  0xf209,
+	0xd009,  0x560a,  0x5c0a,  0xda09,  0x480a,  0xce09,  0xc409,  0x420a,
+	0xc00a,  0x4609,  0x4c09,  0xca0a,  0x5809,  0xde0a,  0xd40a,  0x5209,
+	0x7009,  0xf60a,  0xfc0a,  0x7a09,  0xe80a,  0x6e09,  0x6409,  0xe20a,
+	0x2009,  0xa60a,  0xac0a,  0x2a09,  0xb80a,  0x3e09,  0x3409,  0xb20a,
+	0x900a,  0x1609,  0x1c09,  0x9a0a,  0x0809,  0x8e0a,  0x840a,  0x0209,
+	0x000f,  0x860c,  0x8c0c,  0x0a0f,  0x980c,  0x1e0f,  0x140f,  0x920c,
+	0xb00c,  0x360f,  0x3c0f,  0xba0c,  0x280f,  0xae0c,  0xa40c,  0x220f,
+	0xe00c,  0x660f,  0x6c0f,  0xea0c,  0x780f,  0xfe0c,  0xf40c,  0x720f,
+	0x500f,  0xd60c,  0xdc0c,  0x5a0f,  0xc80c,  0x4e0f,  0x440f,  0xc20c,
+	0x400c,  0xc60f,  0xcc0f,  0x4a0c,  0xd80f,  0x5e0c,  0x540c,  0xd20f,
+	0xf00f,  0x760c,  0x7c0c,  0xfa0f,  0x680c,  0xee0f,  0xe40f,  0x620c,
+	0xa00f,  0x260c,  0x2c0c,  0xaa0f,  0x380c,  0xbe0f,  0xb40f,  0x320c,
+	0x100c,  0x960f,  0x9c0f,  0x1a0c,  0x880f,  0x0e0c,  0x040c,  0x820f },
+
+  { 0x0000,  0x8017,  0x802b,  0x003c,  0x8053,  0x0044,  0x0078,  0x806f,
+	0x80a3,  0x00b4,  0x0088,  0x809f,  0x00f0,  0x80e7,  0x80db,  0x00cc,
+	0x8143,  0x0154,  0x0168,  0x817f,  0x0110,  0x8107,  0x813b,  0x012c,
+	0x01e0,  0x81f7,  0x81cb,  0x01dc,  0x81b3,  0x01a4,  0x0198,  0x818f,
+	0x8283,  0x0294,  0x02a8,  0x82bf,  0x02d0,  0x82c7,  0x82fb,  0x02ec,
+	0x0220,  0x8237,  0x820b,  0x021c,  0x8273,  0x0264,  0x0258,  0x824f,
+	0x03c0,  0x83d7,  0x83eb,  0x03fc,  0x8393,  0x0384,  0x03b8,  0x83af,
+	0x8363,  0x0374,  0x0348,  0x835f,  0x0330,  0x8327,  0x831b,  0x030c,
+	0x8503,  0x0514,  0x0528,  0x853f,  0x0550,  0x8547,  0x857b,  0x056c,
+	0x05a0,  0x85b7,  0x858b,  0x059c,  0x85f3,  0x05e4,  0x05d8,  0x85cf,
+	0x0440,  0x8457,  0x846b,  0x047c,  0x8413,  0x0404,  0x0438,  0x842f,
+	0x84e3,  0x04f4,  0x04c8,  0x84df,  0x04b0,  0x84a7,  0x849b,  0x048c,
+	0x0780,  0x8797,  0x87ab,  0x07bc,  0x87d3,  0x07c4,  0x07f8,  0x87ef,
+	0x8723,  0x0734,  0x0708,  0x871f,  0x0770,  0x8767,  0x875b,  0x074c,
+	0x86c3,  0x06d4,  0x06e8,  0x86ff,  0x0690,  0x8687,  0x86bb,  0x06ac,
+	0x0660,  0x8677,  0x864b,  0x065c,  0x8633,  0x0624,  0x0618,  0x860f,
+	0x8a03,  0x0a14,  0x0a28,  0x8a3f,  0x0a50,  0x8a47,  0x8a7b,  0x0a6c,
+	0x0aa0,  0x8ab7,  0x8a8b,  0x0a9c,  0x8af3,  0x0ae4,  0x0ad8,  0x8acf,
+	0x0b40,  0x8b57,  0x8b6b,  0x0b7c,  0x8b13,  0x0b04,  0x0b38,  0x8b2f,
+	0x8be3,  0x0bf4,  0x0bc8,  0x8bdf,  0x0bb0,  0x8ba7,  0x8b9b,  0x0b8c,
+	0x0880,  0x8897,  0x88ab,  0x08bc,  0x88d3,  0x08c4,  0x08f8,  0x88ef,
+	0x8823,  0x0834,  0x0808,  0x881f,  0x0870,  0x8867,  0x885b,  0x084c,
+	0x89c3,  0x09d4,  0x09e8,  0x89ff,  0x0990,  0x8987,  0x89bb,  0x09ac,
+	0x0960,  0x8977,  0x894b,  0x095c,  0x8933,  0x0924,  0x0918,  0x890f,
+	0x0f00,  0x8f17,  0x8f2b,  0x0f3c,  0x8f53,  0x0f44,  0x0f78,  0x8f6f,
+	0x8fa3,  0x0fb4,  0x0f88,  0x8f9f,  0x0ff0,  0x8fe7,  0x8fdb,  0x0fcc,
+	0x8e43,  0x0e54,  0x0e68,  0x8e7f,  0x0e10,  0x8e07,  0x8e3b,  0x0e2c,
+	0x0ee0,  0x8ef7,  0x8ecb,  0x0edc,  0x8eb3,  0x0ea4,  0x0e98,  0x8e8f,
+	0x8d83,  0x0d94,  0x0da8,  0x8dbf,  0x0dd0,  0x8dc7,  0x8dfb,  0x0dec,
+	0x0d20,  0x8d37,  0x8d0b,  0x0d1c,  0x8d73,  0x0d64,  0x0d58,  0x8d4f,
+	0x0cc0,  0x8cd7,  0x8ceb,  0x0cfc,  0x8c93,  0x0c84,  0x0cb8,  0x8caf,
+	0x8c63,  0x0c74,  0x0c48,  0x8c5f,  0x0c30,  0x8c27,  0x8c1b,  0x0c0c },
+
+  { 0x0000,  0x9403,  0xa803,  0x3c00,  0xd003,  0x4400,  0x7800,  0xec03,
+	0x2003,  0xb400,  0x8800,  0x1c03,  0xf000,  0x6403,  0x5803,  0xcc00,
+	0x4006,  0xd405,  0xe805,  0x7c06,  0x9005,  0x0406,  0x3806,  0xac05,
+	0x6005,  0xf406,  0xc806,  0x5c05,  0xb006,  0x2405,  0x1805,  0x8c06,
+	0x800c,  0x140f,  0x280f,  0xbc0c,  0x500f,  0xc40c,  0xf80c,  0x6c0f,
+	0xa00f,  0x340c,  0x080c,  0x9c0f,  0x700c,  0xe40f,  0xd80f,  0x4c0c,
+	0xc00a,  0x5409,  0x6809,  0xfc0a,  0x1009,  0x840a,  0xb80a,  0x2c09,
+	0xe009,  0x740a,  0x480a,  0xdc09,  0x300a,  0xa409,  0x9809,  0x0c0a,
+	0x801d,  0x141e,  0x281e,  0xbc1d,  0x501e,  0xc41d,  0xf81d,  0x6c1e,
+	0xa01e,  0x341d,  0x081d,  0x9c1e,  0x701d,  0xe41e,  0xd81e,  0x4c1d,
+	0xc01b,  0x5418,  0x6818,  0xfc1b,  0x1018,  0x841b,  0xb81b,  0x2c18,
+	0xe018,  0x741b,  0x481b,  0xdc18,  0x301b,  0xa418,  0x9818,  0x0c1b,
+	0x0011,  0x9412,  0xa812,  0x3c11,  0xd012,  0x4411,  0x7811,  0xec12,
+	0x2012,  0xb411,  0x8811,  0x1c12,  0xf011,  0x6412,  0x5812,  0xcc11,
+	0x4017,  0xd414,  0xe814,  0x7c17,  0x9014,  0x0417,  0x3817,  0xac14,
+	0x6014,  0xf417,  0xc817,  0x5c14,  0xb017,  0x2414,  0x1814,  0x8c17,
+	0x803f,  0x143c,  0x283c,  0xbc3f,  0x503c,  0xc43f,  0xf83f,  0x6c3c,
+	0xa03c,  0x343f,  0x083f,  0x9c3c,  0x703f,  0xe43c,  0xd83c,  0x4c3f,
+	0xc039,  0x543a,  0x683a,  0xfc39,  0x103a,  0x8439,  0xb839,  0x2c3a,
+	0xe03a,  0x7439,  0x4839,  0xdc3a,  0x3039,  0xa43a,  0x983a,  0x0c39,
+	0x0033,  0x9430,  0xa830,  0x3c33,  0xd030,  0x4433,  0x7833,  0xec30,
+	0x2030,  0xb433,  0x8833,  0x1c30,  0xf033,  0x6430,  0x5830,  0xcc33,
+	0x4035,  0xd436,  0xe836,  0x7c35,  0x9036,  0x0435,  0x3835,  0xac36,
+	0x6036,  0xf435,  0xc835,  0x5c36,  0xb035,  0x2436,  0x1836,  0x8c35,
+	0x0022,  0x9421,  0xa821,  0x3c22,  0xd021,  0x4422,  0x7822,  0xec21,
+	0x2021,  0xb422,  0x8822,  0x1c21,  0xf022,  0x6421,  0x5821,  0xcc22,
+	0x4024,  0xd427,  0xe827,  0x7c24,  0x9027,  0x0424,  0x3824,  0xac27,
+	0x6027,  0xf424,  0xc824,  0x5c27,  0xb024,  0x2427,  0x1827,  0x8c24,
+	0x802e,  0x142d,  0x282d,  0xbc2e,  0x502d,  0xc42e,  0xf82e,  0x6c2d,
+	0xa02d,  0x342e,  0x082e,  0x9c2d,  0x702e,  0xe42d,  0xd82d,  0x4c2e,
+	0xc028,  0x542b,  0x682b,  0xfc28,  0x102b,  0x8428,  0xb828,  0x2c2b,
+	0xe02b,  0x7428,  0x4828,  0xdc2b,  0x3028,  0xa42b,  0x982b,  0x0c28 },
+
+  { 0x0000,  0x807b,  0x80f3,  0x0088,  0x81e3,  0x0198,  0x0110,  0x816b,
+	0x83c3,  0x03b8,  0x0330,  0x834b,  0x0220,  0x825b,  0x82d3,  0x02a8,
+	0x8783,  0x07f8,  0x0770,  0x870b,  0x0660,  0x861b,  0x8693,  0x06e8,
+	0x0440,  0x843b,  0x84b3,  0x04c8,  0x85a3,  0x05d8,  0x0550,  0x852b,
+	0x8f03,  0x0f78,  0x0ff0,  0x8f8b,  0x0ee0,  0x8e9b,  0x8e13,  0x0e68,
+	0x0cc0,  0x8cbb,  0x8c33,  0x0c48,  0x8d23,  0x0d58,  0x0dd0,  0x8dab,
+	0x0880,  0x88fb,  0x8873,  0x0808,  0x8963,  0x0918,  0x0990,  0x89eb,
+	0x8b43,  0x0b38,  0x0bb0,  0x8bcb,  0x0aa0,  0x8adb,  0x8a53,  0x0a28,
+	0x9e03,  0x1e78,  0x1ef0,  0x9e8b,  0x1fe0,  0x9f9b,  0x9f13,  0x1f68,
+	0x1dc0,  0x9dbb,  0x9d33,  0x1d48,  0x9c23,  0x1c58,  0x1cd0,  0x9cab,
+	0x1980,  0x99fb,  0x9973,  0x1908,  0x9863,  0x1818,  0x1890,  0x98eb,
+	0x9a43,  0x1a38,  0x1ab0,  0x9acb,  0x1ba0,  0x9bdb,  0x9b53,  0x1b28,
+	0x1100,  0x917b,  0x91f3,  0x1188,  0x90e3,  0x1098,  0x1010,  0x906b,
+	0x92c3,  0x12b8,  0x1230,  0x924b,  0x1320,  0x935b,  0x93d3,  0x13a8,
+	0x9683,  0x16f8,  0x1670,  0x960b,  0x1760,  0x971b,  0x9793,  0x17e8,
+	0x1540,  0x953b,  0x95b3,  0x15c8,  0x94a3,  0x14d8,  0x1450,  0x942b,
+	0xbc03,  0x3c78,  0x3cf0,  0xbc8b,  0x3de0,  0xbd9b,  0xbd13,  0x3d68,
+	0x3fc0,  0xbfbb,  0xbf33,  0x3f48,  0xbe23,  0x3e58,  0x3ed0,  0xbeab,
+	0x3b80,  0xbbfb,  0xbb73,  0x3b08,  0xba63,  0x3a18,  0x3a90,  0xbaeb,
+	0xb843,  0x3838,  0x38b0,  0xb8cb,  0x39a0,  0xb9db,  0xb953,  0x3928,
+	0x3300,  0xb37b,  0xb3f3,  0x3388,  0xb2e3,  0x3298,  0x3210,  0xb26b,
+	0xb0c3,  0x30b8,  0x3030,  0xb04b,  0x3120,  0xb15b,  0xb1d3,  0x31a8,
+	0xb483,  0x34f8,  0x3470,  0xb40b,  0x3560,  0xb51b,  0xb593,  0x35e8,
+	0x3740,  0xb73b,  0xb7b3,  0x37c8,  0xb6a3,  0x36d8,  0x3650,  0xb62b,
+	0x2200,  0xa27b,  0xa2f3,  0x2288,  0xa3e3,  0x2398,  0x2310,  0xa36b,
+	0xa1c3,  0x21b8,  0x2130,  0xa14b,  0x2020,  0xa05b,  0xa0d3,  0x20a8,
+	0xa583,  0x25f8,  0x2570,  0xa50b,  0x2460,  0xa41b,  0xa493,  0x24e8,
+	0x2640,  0xa63b,  0xa6b3,  0x26c8,  0xa7a3,  0x27d8,  0x2750,  0xa72b,
+	0xad03,  0x2d78,  0x2df0,  0xad8b,  0x2ce0,  0xac9b,  0xac13,  0x2c68,
+	0x2ec0,  0xaebb,  0xae33,  0x2e48,  0xaf23,  0x2f58,  0x2fd0,  0xafab,
+	0x2a80,  0xaafb,  0xaa73,  0x2a08,  0xab63,  0x2b18,  0x2b90,  0xabeb,
+	0xa943,  0x2938,  0x29b0,  0xa9cb,  0x28a0,  0xa8db,  0xa853,  0x2828 },
+
+  { 0x0000,  0xf803,  0x7003,  0x8800,  0xe006,  0x1805,  0x9005,  0x6806,
+	0x4009,  0xb80a,  0x300a,  0xc809,  0xa00f,  0x580c,  0xd00c,  0x280f,
+	0x8012,  0x7811,  0xf011,  0x0812,  0x6014,  0x9817,  0x1017,  0xe814,
+	0xc01b,  0x3818,  0xb018,  0x481b,  0x201d,  0xd81e,  0x501e,  0xa81d,
+	0x8021,  0x7822,  0xf022,  0x0821,  0x6027,  0x9824,  0x1024,  0xe827,
+	0xc028,  0x382b,  0xb02b,  0x4828,  0x202e,  0xd82d,  0x502d,  0xa82e,
+	0x0033,  0xf830,  0x7030,  0x8833,  0xe035,  0x1836,  0x9036,  0x6835,
+	0x403a,  0xb839,  0x3039,  0xc83a,  0xa03c,  0x583f,  0xd03f,  0x283c,
+	0x8047,  0x7844,  0xf044,  0x0847,  0x6041,  0x9842,  0x1042,  0xe841,
+	0xc04e,  0x384d,  0xb04d,  0x484e,  0x2048,  0xd84b,  0x504b,  0xa848,
+	0x0055,  0xf856,  0x7056,  0x8855,  0xe053,  0x1850,  0x9050,  0x6853,
+	0x405c,  0xb85f,  0x305f,  0xc85c,  0xa05a,  0x5859,  0xd059,  0x285a,
+	0x0066,  0xf865,  0x7065,  0x8866,  0xe060,  0x1863,  0x9063,  0x6860,
+	0x406f,  0xb86c,  0x306c,  0xc86f,  0xa069,  0x586a,  0xd06a,  0x2869,
+	0x8074,  0x7877,  0xf077,  0x0874,  0x6072,  0x9871,  0x1071,  0xe872,
+	0xc07d,  0x387e,  0xb07e,  0x487d,  0x207b,  0xd878,  0x5078,  0xa87b,
+	0x808b,  0x7888,  0xf088,  0x088b,  0x608d,  0x988e,  0x108e,  0xe88d,
+	0xc082,  0x3881,  0xb081,  0x4882,  0x2084,  0xd887,  0x5087,  0xa884,
+	0x0099,  0xf89a,  0x709a,  0x8899,  0xe09f,  0x189c,  0x909c,  0x689f,
+	0x4090,  0xb893,  0x3093,  0xc890,  0xa096,  0x5895,  0xd095,  0x2896,
+	0x00aa,  0xf8a9,  0x70a9,  0x88aa,  0xe0ac,  0x18af,  0x90af,  0x68ac,
+	0x40a3,  0xb8a0,  0x30a0,  0xc8a3,  0xa0a5,  0x58a6,  0xd0a6,  0x28a5,
+	0x80b8,  0x78bb,  0xf0bb,  0x08b8,  0x60be,  0x98bd,  0x10bd,  0xe8be,
+	0xc0b1,  0x38b2,  0xb0b2,  0x48b1,  0x20b7,  0xd8b4,  0x50b4,  0xa8b7,
+	0x00cc,  0xf8cf,  0x70cf,  0x88cc,  0xe0ca,  0x18c9,  0x90c9,  0x68ca,
+	0x40c5,  0xb8c6,  0x30c6,  0xc8c5,  0xa0c3,  0x58c0,  0xd0c0,  0x28c3,
+	0x80de,  0x78dd,  0xf0dd,  0x08de,  0x60d8,  0x98db,  0x10db,  0xe8d8,
+	0xc0d7,  0x38d4,  0xb0d4,  0x48d7,  0x20d1,  0xd8d2,  0x50d2,  0xa8d1,
+	0x80ed,  0x78ee,  0xf0ee,  0x08ed,  0x60eb,  0x98e8,  0x10e8,  0xe8eb,
+	0xc0e4,  0x38e7,  0xb0e7,  0x48e4,  0x20e2,  0xd8e1,  0x50e1,  0xa8e2,
+	0x00ff,  0xf8fc,  0x70fc,  0x88ff,  0xe0f9,  0x18fa,  0x90fa,  0x68f9,
+	0x40f6,  0xb8f5,  0x30f5,  0xc8f6,  0xa0f0,  0x58f3,  0xd0f3,  0x28f0 },
+
+  { 0x0000,  0x8113,  0x8223,  0x0330,  0x8443,  0x0550,  0x0660,  0x8773,
+	0x8883,  0x0990,  0x0aa0,  0x8bb3,  0x0cc0,  0x8dd3,  0x8ee3,  0x0ff0,
+	0x9103,  0x1010,  0x1320,  0x9233,  0x1540,  0x9453,  0x9763,  0x1670,
+	0x1980,  0x9893,  0x9ba3,  0x1ab0,  0x9dc3,  0x1cd0,  0x1fe0,  0x9ef3,
+	0xa203,  0x2310,  0x2020,  0xa133,  0x2640,  0xa753,  0xa463,  0x2570,
+	0x2a80,  0xab93,  0xa8a3,  0x29b0,  0xaec3,  0x2fd0,  0x2ce0,  0xadf3,
+	0x3300,  0xb213,  0xb123,  0x3030,  0xb743,  0x3650,  0x3560,  0xb473,
+	0xbb83,  0x3a90,  0x39a0,  0xb8b3,  0x3fc0,  0xbed3,  0xbde3,  0x3cf0,
+	0xc403,  0x4510,  0x4620,  0xc733,  0x4040,  0xc153,  0xc263,  0x4370,
+	0x4c80,  0xcd93,  0xcea3,  0x4fb0,  0xc8c3,  0x49d0,  0x4ae0,  0xcbf3,
+	0x5500,  0xd413,  0xd723,  0x5630,  0xd143,  0x5050,  0x5360,  0xd273,
+	0xdd83,  0x5c90,  0x5fa0,  0xdeb3,  0x59c0,  0xd8d3,  0xdbe3,  0x5af0,
+	0x6600,  0xe713,  0xe423,  0x6530,  0xe243,  0x6350,  0x6060,  0xe173,
+	0xee83,  0x6f90,  0x6ca0,  0xedb3,  0x6ac0,  0xebd3,  0xe8e3,  0x69f0,
+	0xf703,  0x7610,  0x7520,  0xf433,  0x7340,  0xf253,  0xf163,  0x7070,
+	0x7f80,  0xfe93,  0xfda3,  0x7cb0,  0xfbc3,  0x7ad0,  0x79e0,  0xf8f3,
+	0x0803,  0x8910,  0x8a20,  0x0b33,  0x8c40,  0x0d53,  0x0e63,  0x8f70,
+	0x8080,  0x0193,  0x02a3,  0x83b0,  0x04c3,  0x85d0,  0x86e0,  0x07f3,
+	0x9900,  0x1813,  0x1b23,  0x9a30,  0x1d43,  0x9c50,  0x9f60,  0x1e73,
+	0x1183,  0x9090,  0x93a0,  0x12b3,  0x95c0,  0x14d3,  0x17e3,  0x96f0,
+	0xaa00,  0x2b13,  0x2823,  0xa930,  0x2e43,  0xaf50,  0xac60,  0x2d73,
+	0x2283,  0xa390,  0xa0a0,  0x21b3,  0xa6c0,  0x27d3,  0x24e3,  0xa5f0,
+	0x3b03,  0xba10,  0xb920,  0x3833,  0xbf40,  0x3e53,  0x3d63,  0xbc70,
+	0xb380,  0x3293,  0x31a3,  0xb0b0,  0x37c3,  0xb6d0,  0xb5e0,  0x34f3,
+	0xcc00,  0x4d13,  0x4e23,  0xcf30,  0x4843,  0xc950,  0xca60,  0x4b73,
+	0x4483,  0xc590,  0xc6a0,  0x47b3,  0xc0c0,  0x41d3,  0x42e3,  0xc3f0,
+	0x5d03,  0xdc10,  0xdf20,  0x5e33,  0xd940,  0x5853,  0x5b63,  0xda70,
+	0xd580,  0x5493,  0x57a3,  0xd6b0,  0x51c3,  0xd0d0,  0xd3e0,  0x52f3,
+	0x6e03,  0xef10,  0xec20,  0x6d33,  0xea40,  0x6b53,  0x6863,  0xe970,
+	0xe680,  0x6793,  0x64a3,  0xe5b0,  0x62c3,  0xe3d0,  0xe0e0,  0x61f3,
+	0xff00,  0x7e13,  0x7d23,  0xfc30,  0x7b43,  0xfa50,  0xf960,  0x7873,
+	0x7783,  0xf690,  0xf5a0,  0x74b3,  0xf3c0,  0x72d3,  0x71e3,  0xf0f0 },
+
+  { 0x0000,  0x1006,  0x200c,  0x300a,  0x4018,  0x501e,  0x6014,  0x7012,
+	0x8030,  0x9036,  0xa03c,  0xb03a,  0xc028,  0xd02e,  0xe024,  0xf022,
+	0x8065,  0x9063,  0xa069,  0xb06f,  0xc07d,  0xd07b,  0xe071,  0xf077,
+	0x0055,  0x1053,  0x2059,  0x305f,  0x404d,  0x504b,  0x6041,  0x7047,
+	0x80cf,  0x90c9,  0xa0c3,  0xb0c5,  0xc0d7,  0xd0d1,  0xe0db,  0xf0dd,
+	0x00ff,  0x10f9,  0x20f3,  0x30f5,  0x40e7,  0x50e1,  0x60eb,  0x70ed,
+	0x00aa,  0x10ac,  0x20a6,  0x30a0,  0x40b2,  0x50b4,  0x60be,  0x70b8,
+	0x809a,  0x909c,  0xa096,  0xb090,  0xc082,  0xd084,  0xe08e,  0xf088,
+	0x819b,  0x919d,  0xa197,  0xb191,  0xc183,  0xd185,  0xe18f,  0xf189,
+	0x01ab,  0x11ad,  0x21a7,  0x31a1,  0x41b3,  0x51b5,  0x61bf,  0x71b9,
+	0x01fe,  0x11f8,  0x21f2,  0x31f4,  0x41e6,  0x51e0,  0x61ea,  0x71ec,
+	0x81ce,  0x91c8,  0xa1c2,  0xb1c4,  0xc1d6,  0xd1d0,  0xe1da,  0xf1dc,
+	0x0154,  0x1152,  0x2158,  0x315e,  0x414c,  0x514a,  0x6140,  0x7146,
+	0x8164,  0x9162,  0xa168,  0xb16e,  0xc17c,  0xd17a,  0xe170,  0xf176,
+	0x8131,  0x9137,  0xa13d,  0xb13b,  0xc129,  0xd12f,  0xe125,  0xf123,
+	0x0101,  0x1107,  0x210d,  0x310b,  0x4119,  0x511f,  0x6115,  0x7113,
+	0x8333,  0x9335,  0xa33f,  0xb339,  0xc32b,  0xd32d,  0xe327,  0xf321,
+	0x0303,  0x1305,  0x230f,  0x3309,  0x431b,  0x531d,  0x6317,  0x7311,
+	0x0356,  0x1350,  0x235a,  0x335c,  0x434e,  0x5348,  0x6342,  0x7344,
+	0x8366,  0x9360,  0xa36a,  0xb36c,  0xc37e,  0xd378,  0xe372,  0xf374,
+	0x03fc,  0x13fa,  0x23f0,  0x33f6,  0x43e4,  0x53e2,  0x63e8,  0x73ee,
+	0x83cc,  0x93ca,  0xa3c0,  0xb3c6,  0xc3d4,  0xd3d2,  0xe3d8,  0xf3de,
+	0x8399,  0x939f,  0xa395,  0xb393,  0xc381,  0xd387,  0xe38d,  0xf38b,
+	0x03a9,  0x13af,  0x23a5,  0x33a3,  0x43b1,  0x53b7,  0x63bd,  0x73bb,
+	0x02a8,  0x12ae,  0x22a4,  0x32a2,  0x42b0,  0x52b6,  0x62bc,  0x72ba,
+	0x8298,  0x929e,  0xa294,  0xb292,  0xc280,  0xd286,  0xe28c,  0xf28a,
+	0x82cd,  0x92cb,  0xa2c1,  0xb2c7,  0xc2d5,  0xd2d3,  0xe2d9,  0xf2df,
+	0x02fd,  0x12fb,  0x22f1,  0x32f7,  0x42e5,  0x52e3,  0x62e9,  0x72ef,
+	0x8267,  0x9261,  0xa26b,  0xb26d,  0xc27f,  0xd279,  0xe273,  0xf275,
+	0x0257,  0x1251,  0x225b,  0x325d,  0x424f,  0x5249,  0x6243,  0x7245,
+	0x0202,  0x1204,  0x220e,  0x3208,  0x421a,  0x521c,  0x6216,  0x7210,
+	0x8232,  0x9234,  0xa23e,  0xb238,  0xc22a,  0xd22c,  0xe226,  0xf220 }
+};
+
+FLAC__uint8 FLAC__crc8(const FLAC__byte *data, uint32_t len)
+{
+	FLAC__uint8 crc = 0;
+
+	while(len--)
+		crc = FLAC__crc8_table[crc ^ *data++];
+
+	return crc;
+}
+
+FLAC__uint16 FLAC__crc16(const FLAC__byte *data, uint32_t len)
+{
+	FLAC__uint16 crc = 0;
+
+	while(len >= 8){
+		crc ^= data[0] << 8 | data[1];
+
+		crc = FLAC__crc16_table[7][crc >> 8] ^ FLAC__crc16_table[6][crc & 0xFF] ^
+		      FLAC__crc16_table[5][data[2] ] ^ FLAC__crc16_table[4][data[3]   ] ^
+		      FLAC__crc16_table[3][data[4] ] ^ FLAC__crc16_table[2][data[5]   ] ^
+		      FLAC__crc16_table[1][data[6] ] ^ FLAC__crc16_table[0][data[7]   ];
+
+		data += 8;
+		len -= 8;
+	}
+
+	while(len--)
+		crc = (crc<<8) ^ FLAC__crc16_table[0][(crc>>8) ^ *data++];
+
+	return crc;
+}
+
+FLAC__uint16 FLAC__crc16_update_words32(const FLAC__uint32 *words, uint32_t len, FLAC__uint16 crc)
+{
+	while (len >= 2) {
+		crc ^= words[0] >> 16;
+
+		crc = FLAC__crc16_table[7][crc >> 8               ] ^ FLAC__crc16_table[6][crc & 0xFF             ] ^
+		      FLAC__crc16_table[5][(words[0] >>  8) & 0xFF] ^ FLAC__crc16_table[4][ words[0]        & 0xFF] ^
+		      FLAC__crc16_table[3][ words[1] >> 24        ] ^ FLAC__crc16_table[2][(words[1] >> 16) & 0xFF] ^
+		      FLAC__crc16_table[1][(words[1] >>  8) & 0xFF] ^ FLAC__crc16_table[0][ words[1]        & 0xFF];
+
+		words += 2;
+		len -= 2;
+	}
+
+	if (len) {
+		crc ^= words[0] >> 16;
+
+		crc = FLAC__crc16_table[3][crc >> 8               ] ^ FLAC__crc16_table[2][crc & 0xFF             ] ^
+		      FLAC__crc16_table[1][(words[0] >>  8) & 0xFF] ^ FLAC__crc16_table[0][words[0]         & 0xFF];
+	}
+
+	return crc;
+}
+
+FLAC__uint16 FLAC__crc16_update_words64(const FLAC__uint64 *words, uint32_t len, FLAC__uint16 crc)
+{
+	while (len--) {
+		crc ^= words[0] >> 48;
+
+		crc = FLAC__crc16_table[7][crc >> 8               ] ^ FLAC__crc16_table[6][crc & 0xFF             ] ^
+		      FLAC__crc16_table[5][(words[0] >> 40) & 0xFF] ^ FLAC__crc16_table[4][(words[0] >> 32) & 0xFF] ^
+		      FLAC__crc16_table[3][(words[0] >> 24) & 0xFF] ^ FLAC__crc16_table[2][(words[0] >> 16) & 0xFF] ^
+		      FLAC__crc16_table[1][(words[0] >>  8) & 0xFF] ^ FLAC__crc16_table[0][ words[0]        & 0xFF];
+
+		words++;
+	}
+
+	return crc;
+}
--- /dev/null
+++ b/src/libflac/fixed.c
@@ -1,0 +1,100 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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.
+ */
+
+#include <math.h>
+#include <string.h>
+#include "share/compat.h"
+#include "private/bitmath.h"
+#include "private/fixed.h"
+#include "private/macros.h"
+
+#ifdef local_abs
+#undef local_abs
+#endif
+#define local_abs(x) ((uint32_t)((x)<0? -(x) : (x)))
+
+void FLAC__fixed_compute_residual(const FLAC__int32 data[], uint32_t data_len, uint32_t order, FLAC__int32 residual[])
+{
+	const int idata_len = (int)data_len;
+	int i;
+
+	switch(order) {
+		case 0:
+			memcpy(residual, data, sizeof(residual[0])*data_len);
+			break;
+		case 1:
+			for(i = 0; i < idata_len; i++)
+				residual[i] = data[i] - data[i-1];
+			break;
+		case 2:
+			for(i = 0; i < idata_len; i++)
+				residual[i] = data[i] - 2*data[i-1] + data[i-2];
+			break;
+		case 3:
+			for(i = 0; i < idata_len; i++)
+				residual[i] = data[i] - 3*data[i-1] + 3*data[i-2] - data[i-3];
+			break;
+		case 4:
+			for(i = 0; i < idata_len; i++)
+				residual[i] = data[i] - 4*data[i-1] + 6*data[i-2] - 4*data[i-3] + data[i-4];
+			break;
+		default: break;
+	}
+}
+
+void FLAC__fixed_restore_signal(const FLAC__int32 residual[], uint32_t data_len, uint32_t order, FLAC__int32 data[])
+{
+	int i, idata_len = (int)data_len;
+
+	switch(order) {
+		case 0:
+			memcpy(data, residual, sizeof(residual[0])*data_len);
+			break;
+		case 1:
+			for(i = 0; i < idata_len; i++)
+				data[i] = residual[i] + data[i-1];
+			break;
+		case 2:
+			for(i = 0; i < idata_len; i++)
+				data[i] = residual[i] + 2*data[i-1] - data[i-2];
+			break;
+		case 3:
+			for(i = 0; i < idata_len; i++)
+				data[i] = residual[i] + 3*data[i-1] - 3*data[i-2] + data[i-3];
+			break;
+		case 4:
+			for(i = 0; i < idata_len; i++)
+				data[i] = residual[i] + 4*data[i-1] - 6*data[i-2] + 4*data[i-3] - data[i-4];
+			break;
+		default: break;
+	}
+}
--- /dev/null
+++ b/src/libflac/format.c
@@ -1,0 +1,566 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h> /* for qsort() */
+#include <string.h> /* for memset() */
+#include "FLAC/format.h"
+#include "share/alloc.h"
+#include "share/compat.h"
+#include "private/format.h"
+#include "private/macros.h"
+
+/* PACKAGE_VERSION should come from configure */
+FLAC_API const char *FLAC__VERSION_STRING = "1.3.3";
+
+FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC " "1.3.3" " 20190804";
+
+FLAC_API const FLAC__byte FLAC__STREAM_SYNC_STRING[4] = { 'f','L','a','C' };
+FLAC_API const uint32_t FLAC__STREAM_SYNC = 0x664C6143;
+FLAC_API const uint32_t FLAC__STREAM_SYNC_LEN = 32; /* bits */
+
+FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN = 16; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN = 16; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN = 24; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN = 24; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN = 20; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN = 3; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN = 5; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN = 36; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN = 128; /* bits */
+
+FLAC_API const uint32_t FLAC__STREAM_METADATA_APPLICATION_ID_LEN = 32; /* bits */
+
+FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN = 64; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN = 64; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN = 16; /* bits */
+
+FLAC_API const FLAC__uint64 FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER = FLAC__U64L(0xffffffffffffffff);
+
+FLAC_API const uint32_t FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN = 32; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN = 32; /* bits */
+
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN = 64; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN = 8; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN = 3*8; /* bits */
+
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN = 64; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN = 8; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN = 12*8; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN = 1; /* bit */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN = 1; /* bit */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN = 6+13*8; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN = 8; /* bits */
+
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN = 128*8; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN = 64; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN = 1; /* bit */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN = 7+258*8; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN = 8; /* bits */
+
+FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_TYPE_LEN = 32; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN = 32; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN = 32; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN = 32; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN = 32; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN = 32; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_COLORS_LEN = 32; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN = 32; /* bits */
+
+FLAC_API const uint32_t FLAC__STREAM_METADATA_IS_LAST_LEN = 1; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_TYPE_LEN = 7; /* bits */
+FLAC_API const uint32_t FLAC__STREAM_METADATA_LENGTH_LEN = 24; /* bits */
+
+FLAC_API const uint32_t FLAC__FRAME_HEADER_SYNC = 0x3ffe;
+FLAC_API const uint32_t FLAC__FRAME_HEADER_SYNC_LEN = 14; /* bits */
+FLAC_API const uint32_t FLAC__FRAME_HEADER_RESERVED_LEN = 1; /* bits */
+FLAC_API const uint32_t FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN = 1; /* bits */
+FLAC_API const uint32_t FLAC__FRAME_HEADER_BLOCK_SIZE_LEN = 4; /* bits */
+FLAC_API const uint32_t FLAC__FRAME_HEADER_SAMPLE_RATE_LEN = 4; /* bits */
+FLAC_API const uint32_t FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN = 4; /* bits */
+FLAC_API const uint32_t FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN = 3; /* bits */
+FLAC_API const uint32_t FLAC__FRAME_HEADER_ZERO_PAD_LEN = 1; /* bits */
+FLAC_API const uint32_t FLAC__FRAME_HEADER_CRC_LEN = 8; /* bits */
+
+FLAC_API const uint32_t FLAC__FRAME_FOOTER_CRC_LEN = 16; /* bits */
+
+FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_TYPE_LEN = 2; /* bits */
+FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN = 4; /* bits */
+FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN = 4; /* bits */
+FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN = 5; /* bits */
+FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN = 5; /* bits */
+
+FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER = 15; /* == (1<<FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN)-1 */
+FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER = 31; /* == (1<<FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN)-1 */
+
+FLAC_API const char * const FLAC__EntropyCodingMethodTypeString[] = {
+	"PARTITIONED_RICE",
+	"PARTITIONED_RICE2"
+};
+
+FLAC_API const uint32_t FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN = 4; /* bits */
+FLAC_API const uint32_t FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN = 5; /* bits */
+
+FLAC_API const uint32_t FLAC__SUBFRAME_ZERO_PAD_LEN = 1; /* bits */
+FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_LEN = 6; /* bits */
+FLAC_API const uint32_t FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN = 1; /* bits */
+
+FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK = 0x00;
+FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK = 0x02;
+FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK = 0x10;
+FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK = 0x40;
+
+FLAC_API const char * const FLAC__SubframeTypeString[] = {
+	"CONSTANT",
+	"VERBATIM",
+	"FIXED",
+	"LPC"
+};
+
+FLAC_API const char * const FLAC__ChannelAssignmentString[] = {
+	"INDEPENDENT",
+	"LEFT_SIDE",
+	"RIGHT_SIDE",
+	"MID_SIDE"
+};
+
+FLAC_API const char * const FLAC__FrameNumberTypeString[] = {
+	"FRAME_NUMBER_TYPE_FRAME_NUMBER",
+	"FRAME_NUMBER_TYPE_SAMPLE_NUMBER"
+};
+
+FLAC_API const char * const FLAC__MetadataTypeString[] = {
+	"STREAMINFO",
+	"PADDING",
+	"APPLICATION",
+	"SEEKTABLE",
+	"VORBIS_COMMENT",
+	"CUESHEET",
+	"PICTURE"
+};
+
+FLAC_API const char * const FLAC__StreamMetadata_Picture_TypeString[] = {
+	"Other",
+	"32x32 pixels 'file icon' (PNG only)",
+	"Other file icon",
+	"Cover (front)",
+	"Cover (back)",
+	"Leaflet page",
+	"Media (e.g. label side of CD)",
+	"Lead artist/lead performer/soloist",
+	"Artist/performer",
+	"Conductor",
+	"Band/Orchestra",
+	"Composer",
+	"Lyricist/text writer",
+	"Recording Location",
+	"During recording",
+	"During performance",
+	"Movie/video screen capture",
+	"A bright coloured fish",
+	"Illustration",
+	"Band/artist logotype",
+	"Publisher/Studio logotype"
+};
+
+FLAC_API FLAC__bool FLAC__format_sample_rate_is_valid(uint32_t sample_rate)
+{
+	if(sample_rate == 0 || sample_rate > FLAC__MAX_SAMPLE_RATE) {
+		return false;
+	}
+	else
+		return true;
+}
+
+FLAC_API FLAC__bool FLAC__format_blocksize_is_subset(uint32_t blocksize, uint32_t sample_rate)
+{
+	if(blocksize > 16384)
+		return false;
+	else if(sample_rate <= 48000 && blocksize > 4608)
+		return false;
+	else
+		return true;
+}
+
+FLAC_API FLAC__bool FLAC__format_sample_rate_is_subset(uint32_t sample_rate)
+{
+	if(
+		!FLAC__format_sample_rate_is_valid(sample_rate) ||
+		(
+			sample_rate >= (1u << 16) &&
+			!(sample_rate % 1000 == 0 || sample_rate % 10 == 0)
+		)
+	) {
+		return false;
+	}
+	else
+		return true;
+}
+
+/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */
+FLAC_API FLAC__bool FLAC__format_seektable_is_legal(const FLAC__StreamMetadata_SeekTable *seek_table)
+{
+	uint32_t i;
+	FLAC__uint64 prev_sample_number = 0;
+	FLAC__bool got_prev = false;
+
+	for(i = 0; i < seek_table->num_points; i++) {
+		if(got_prev) {
+			if(
+				seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER &&
+				seek_table->points[i].sample_number <= prev_sample_number
+			)
+				return false;
+		}
+		prev_sample_number = seek_table->points[i].sample_number;
+		got_prev = true;
+	}
+
+	return true;
+}
+
+/* used as the sort predicate for qsort() */
+static int seekpoint_compare_(const FLAC__StreamMetadata_SeekPoint *l, const FLAC__StreamMetadata_SeekPoint *r)
+{
+	/* we don't just 'return l->sample_number - r->sample_number' since the result (FLAC__int64) might overflow an 'int' */
+	if(l->sample_number == r->sample_number)
+		return 0;
+	else if(l->sample_number < r->sample_number)
+		return -1;
+	else
+		return 1;
+}
+
+/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */
+FLAC_API uint32_t FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *seek_table)
+{
+	uint32_t i, j;
+	FLAC__bool first;
+
+	if (seek_table->num_points == 0)
+		return 0;
+
+	/* sort the seekpoints */
+	qsort(seek_table->points, seek_table->num_points, sizeof(FLAC__StreamMetadata_SeekPoint), (int (*)(const void *, const void *))seekpoint_compare_);
+
+	/* uniquify the seekpoints */
+	first = true;
+	for(i = j = 0; i < seek_table->num_points; i++) {
+		if(seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER) {
+			if(!first) {
+				if(seek_table->points[i].sample_number == seek_table->points[j-1].sample_number)
+					continue;
+			}
+		}
+		first = false;
+		seek_table->points[j++] = seek_table->points[i];
+	}
+
+	for(i = j; i < seek_table->num_points; i++) {
+		seek_table->points[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+		seek_table->points[i].stream_offset = 0;
+		seek_table->points[i].frame_samples = 0;
+	}
+
+	return j;
+}
+
+/*
+ * also disallows non-shortest-form encodings, c.f.
+ *   http://www.unicode.org/versions/corrigendum1.html
+ * and a more clear explanation at the end of this section:
+ *   http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ */
+static uint32_t utf8len_(const FLAC__byte *utf8)
+{
+	if ((utf8[0] & 0x80) == 0) {
+		return 1;
+	}
+	else if ((utf8[0] & 0xE0) == 0xC0 && (utf8[1] & 0xC0) == 0x80) {
+		if ((utf8[0] & 0xFE) == 0xC0) /* overlong sequence check */
+			return 0;
+		return 2;
+	}
+	else if ((utf8[0] & 0xF0) == 0xE0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80) {
+		if (utf8[0] == 0xE0 && (utf8[1] & 0xE0) == 0x80) /* overlong sequence check */
+			return 0;
+		/* illegal surrogates check (U+D800...U+DFFF and U+FFFE...U+FFFF) */
+		if (utf8[0] == 0xED && (utf8[1] & 0xE0) == 0xA0) /* D800-DFFF */
+			return 0;
+		if (utf8[0] == 0xEF && utf8[1] == 0xBF && (utf8[2] & 0xFE) == 0xBE) /* FFFE-FFFF */
+			return 0;
+		return 3;
+	}
+	else if ((utf8[0] & 0xF8) == 0xF0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80) {
+		if (utf8[0] == 0xF0 && (utf8[1] & 0xF0) == 0x80) /* overlong sequence check */
+			return 0;
+		return 4;
+	}
+	else if ((utf8[0] & 0xFC) == 0xF8 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80 && (utf8[4] & 0xC0) == 0x80) {
+		if (utf8[0] == 0xF8 && (utf8[1] & 0xF8) == 0x80) /* overlong sequence check */
+			return 0;
+		return 5;
+	}
+	else if ((utf8[0] & 0xFE) == 0xFC && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80 && (utf8[4] & 0xC0) == 0x80 && (utf8[5] & 0xC0) == 0x80) {
+		if (utf8[0] == 0xFC && (utf8[1] & 0xFC) == 0x80) /* overlong sequence check */
+			return 0;
+		return 6;
+	}
+	else {
+		return 0;
+	}
+}
+
+FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_name_is_legal(const char *name)
+{
+	char c;
+	for(c = *name; c; c = *(++name))
+		if(c < 0x20 || c == 0x3d || c > 0x7d)
+			return false;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_value_is_legal(const FLAC__byte *value, uint32_t length)
+{
+	if(length == (uint32_t)(-1)) {
+		while(*value) {
+			uint32_t n = utf8len_(value);
+			if(n == 0)
+				return false;
+			value += n;
+		}
+	}
+	else {
+		const FLAC__byte *end = value + length;
+		while(value < end) {
+			uint32_t n = utf8len_(value);
+			if(n == 0)
+				return false;
+			value += n;
+		}
+		if(value != end)
+			return false;
+	}
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_is_legal(const FLAC__byte *entry, uint32_t length)
+{
+	const FLAC__byte *s, *end;
+
+	for(s = entry, end = s + length; s < end && *s != '='; s++) {
+		if(*s < 0x20 || *s > 0x7D)
+			return false;
+	}
+	if(s == end)
+		return false;
+
+	s++; /* skip '=' */
+
+	while(s < end) {
+		uint32_t n = utf8len_(s);
+		if(n == 0)
+			return false;
+		s += n;
+	}
+	if(s != end)
+		return false;
+
+	return true;
+}
+
+/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */
+FLAC_API FLAC__bool FLAC__format_cuesheet_is_legal(const FLAC__StreamMetadata_CueSheet *cue_sheet, FLAC__bool check_cd_da_subset, const char **violation)
+{
+	uint32_t i, j;
+
+	if(check_cd_da_subset) {
+		if(cue_sheet->lead_in < 2 * 44100) {
+			if(violation) *violation = "CD-DA cue sheet must have a lead-in length of at least 2 seconds";
+			return false;
+		}
+		if(cue_sheet->lead_in % 588 != 0) {
+			if(violation) *violation = "CD-DA cue sheet lead-in length must be evenly divisible by 588 samples";
+			return false;
+		}
+	}
+
+	if(cue_sheet->num_tracks == 0) {
+		if(violation) *violation = "cue sheet must have at least one track (the lead-out)";
+		return false;
+	}
+
+	if(check_cd_da_subset && cue_sheet->tracks[cue_sheet->num_tracks-1].number != 170) {
+		if(violation) *violation = "CD-DA cue sheet must have a lead-out track number 170 (0xAA)";
+		return false;
+	}
+
+	for(i = 0; i < cue_sheet->num_tracks; i++) {
+		if(cue_sheet->tracks[i].number == 0) {
+			if(violation) *violation = "cue sheet may not have a track number 0";
+			return false;
+		}
+
+		if(check_cd_da_subset) {
+			if(!((cue_sheet->tracks[i].number >= 1 && cue_sheet->tracks[i].number <= 99) || cue_sheet->tracks[i].number == 170)) {
+				if(violation) *violation = "CD-DA cue sheet track number must be 1-99 or 170";
+				return false;
+			}
+		}
+
+		if(check_cd_da_subset && cue_sheet->tracks[i].offset % 588 != 0) {
+			if(violation) {
+				if(i == cue_sheet->num_tracks-1) /* the lead-out track... */
+					*violation = "CD-DA cue sheet lead-out offset must be evenly divisible by 588 samples";
+				else
+					*violation = "CD-DA cue sheet track offset must be evenly divisible by 588 samples";
+			}
+			return false;
+		}
+
+		if(i < cue_sheet->num_tracks - 1) {
+			if(cue_sheet->tracks[i].num_indices == 0) {
+				if(violation) *violation = "cue sheet track must have at least one index point";
+				return false;
+			}
+
+			if(cue_sheet->tracks[i].indices[0].number > 1) {
+				if(violation) *violation = "cue sheet track's first index number must be 0 or 1";
+				return false;
+			}
+		}
+
+		for(j = 0; j < cue_sheet->tracks[i].num_indices; j++) {
+			if(check_cd_da_subset && cue_sheet->tracks[i].indices[j].offset % 588 != 0) {
+				if(violation) *violation = "CD-DA cue sheet track index offset must be evenly divisible by 588 samples";
+				return false;
+			}
+
+			if(j > 0) {
+				if(cue_sheet->tracks[i].indices[j].number != cue_sheet->tracks[i].indices[j-1].number + 1) {
+					if(violation) *violation = "cue sheet track index numbers must increase by 1";
+					return false;
+				}
+			}
+		}
+	}
+
+	return true;
+}
+
+/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */
+FLAC_API FLAC__bool FLAC__format_picture_is_legal(const FLAC__StreamMetadata_Picture *picture, const char **violation)
+{
+	char *p;
+	FLAC__byte *b;
+
+	for(p = picture->mime_type; *p; p++) {
+		if(*p < 0x20 || *p > 0x7e) {
+			if(violation) *violation = "MIME type string must contain only printable ASCII characters (0x20-0x7e)";
+			return false;
+		}
+	}
+
+	for(b = picture->description; *b; ) {
+		uint32_t n = utf8len_(b);
+		if(n == 0) {
+			if(violation) *violation = "description string must be valid UTF-8";
+			return false;
+		}
+		b += n;
+	}
+
+	return true;
+}
+
+/*
+ * These routines are private to libFLAC
+ */
+uint32_t FLAC__format_get_max_rice_partition_order(uint32_t blocksize, uint32_t predictor_order)
+{
+	return
+		FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(
+			FLAC__format_get_max_rice_partition_order_from_blocksize(blocksize),
+			blocksize,
+			predictor_order
+		);
+}
+
+uint32_t FLAC__format_get_max_rice_partition_order_from_blocksize(uint32_t blocksize)
+{
+	uint32_t max_rice_partition_order = 0;
+	while(!(blocksize & 1)) {
+		max_rice_partition_order++;
+		blocksize >>= 1;
+	}
+	return flac_min(FLAC__MAX_RICE_PARTITION_ORDER, max_rice_partition_order);
+}
+
+uint32_t FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(uint32_t limit, uint32_t blocksize, uint32_t predictor_order)
+{
+	uint32_t max_rice_partition_order = limit;
+
+	while(max_rice_partition_order > 0 && (blocksize >> max_rice_partition_order) <= predictor_order)
+		max_rice_partition_order--;
+
+	return max_rice_partition_order;
+}
+
+void FLAC__format_entropy_coding_method_partitioned_rice_contents_init(FLAC__EntropyCodingMethod_PartitionedRiceContents *object)
+{
+	object->parameters = 0;
+	object->raw_bits = 0;
+	object->capacity_by_order = 0;
+}
+
+void FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(FLAC__EntropyCodingMethod_PartitionedRiceContents *object)
+{
+	if(0 != object->parameters)
+		free(object->parameters);
+	if(0 != object->raw_bits)
+		free(object->raw_bits);
+	FLAC__format_entropy_coding_method_partitioned_rice_contents_init(object);
+}
+
+FLAC__bool FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(FLAC__EntropyCodingMethod_PartitionedRiceContents *object, uint32_t max_partition_order)
+{
+	if(object->capacity_by_order < max_partition_order) {
+		if(0 == (object->parameters = safe_realloc_(object->parameters, sizeof(uint32_t)*(1ULL << max_partition_order))))
+			return false;
+		if(0 == (object->raw_bits = safe_realloc_(object->raw_bits, sizeof(uint32_t)*(1ULL << max_partition_order))))
+			return false;
+		memset(object->raw_bits, 0, sizeof(uint32_t)*(1ULL << max_partition_order));
+		object->capacity_by_order = max_partition_order;
+	}
+
+	return true;
+}
--- /dev/null
+++ b/src/libflac/lpc.c
@@ -1,0 +1,1233 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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.
+ */
+
+#include <math.h>
+#include "FLAC/format.h"
+#include "share/compat.h"
+#include "private/bitmath.h"
+#include "private/lpc.h"
+#include "private/macros.h"
+
+/* OPT: #undef'ing this may improve the speed on some architectures */
+#define FLAC__LPC_UNROLLED_FILTER_LOOPS
+
+#if defined(_MSC_VER) && (_MSC_VER < 1800)
+#include <float.h>
+static inline long int lround(double x) {
+	return (long)(x + _copysign(0.5, x));
+}
+#endif
+
+void FLAC__lpc_window_data(const FLAC__int32 in[], const FLAC__real window[], FLAC__real out[], uint32_t data_len)
+{
+	uint32_t i;
+	for(i = 0; i < data_len; i++)
+		out[i] = in[i] * window[i];
+}
+
+void FLAC__lpc_compute_autocorrelation(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[])
+{
+	/*
+	 * this version tends to run faster because of better data locality
+	 * ('data_len' is usually much larger than 'lag')
+	 */
+	FLAC__real d;
+	uint32_t sample, coeff;
+	const uint32_t limit = data_len - lag;
+
+	for(coeff = 0; coeff < lag; coeff++)
+		autoc[coeff] = 0.0;
+	for(sample = 0; sample <= limit; sample++) {
+		d = data[sample];
+		for(coeff = 0; coeff < lag; coeff++)
+			autoc[coeff] += d * data[sample+coeff];
+	}
+	for(; sample < data_len; sample++) {
+		d = data[sample];
+		for(coeff = 0; coeff < data_len - sample; coeff++)
+			autoc[coeff] += d * data[sample+coeff];
+	}
+}
+
+void FLAC__lpc_compute_lp_coefficients(const FLAC__real autoc[], uint32_t *max_order, FLAC__real lp_coeff[][FLAC__MAX_LPC_ORDER], double error[])
+{
+	uint32_t i, j;
+	double r, err, lpc[FLAC__MAX_LPC_ORDER];
+
+	err = autoc[0];
+
+	for(i = 0; i < *max_order; i++) {
+		/* Sum up this iteration's reflection coefficient. */
+		r = -autoc[i+1];
+		for(j = 0; j < i; j++)
+			r -= lpc[j] * autoc[i-j];
+		r /= err;
+
+		/* Update LPC coefficients and total error. */
+		lpc[i]=r;
+		for(j = 0; j < (i>>1); j++) {
+			double tmp = lpc[j];
+			lpc[j] += r * lpc[i-1-j];
+			lpc[i-1-j] += r * tmp;
+		}
+		if(i & 1)
+			lpc[j] += lpc[j] * r;
+
+		err *= (1.0 - r * r);
+
+		/* save this order */
+		for(j = 0; j <= i; j++)
+			lp_coeff[i][j] = (FLAC__real)(-lpc[j]); /* negate FIR filter coeff to get predictor coeff */
+		error[i] = err;
+
+		/* see SF bug https://sourceforge.net/p/flac/bugs/234/ */
+		if(err == 0.0) {
+			*max_order = i+1;
+			return;
+		}
+	}
+}
+
+int FLAC__lpc_quantize_coefficients(const FLAC__real lp_coeff[], uint32_t order, uint32_t precision, FLAC__int32 qlp_coeff[], int *shift)
+{
+	uint32_t i;
+	double cmax;
+	FLAC__int32 qmax, qmin;
+
+	/* drop one bit for the sign; from here on out we consider only |lp_coeff[i]| */
+	precision--;
+	qmax = 1 << precision;
+	qmin = -qmax;
+	qmax--;
+
+	/* calc cmax = max( |lp_coeff[i]| ) */
+	cmax = 0.0;
+	for(i = 0; i < order; i++) {
+		const double d = fabs(lp_coeff[i]);
+		if(d > cmax)
+			cmax = d;
+	}
+
+	if(cmax <= 0.0) {
+		/* => coefficients are all 0, which means our constant-detect didn't work */
+		return 2;
+	}
+	else {
+		const int max_shiftlimit = (1 << (FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN-1)) - 1;
+		const int min_shiftlimit = -max_shiftlimit - 1;
+		int log2cmax;
+
+		(void)frexp(cmax, &log2cmax);
+		log2cmax--;
+		*shift = (int)precision - log2cmax - 1;
+
+		if(*shift > max_shiftlimit)
+			*shift = max_shiftlimit;
+		else if(*shift < min_shiftlimit)
+			return 1;
+	}
+
+	if(*shift >= 0) {
+		double error = 0.0;
+		FLAC__int32 q;
+		for(i = 0; i < order; i++) {
+			error += lp_coeff[i] * (1 << *shift);
+			q = lround(error);
+
+			if(q > qmax)
+				q = qmax;
+			else if(q < qmin)
+				q = qmin;
+			error -= q;
+			qlp_coeff[i] = q;
+		}
+	}
+	/* negative shift is very rare but due to design flaw, negative shift is
+	 * not allowed in the decoder, so it must be handled specially by scaling
+	 * down coeffs
+	 */
+	else {
+		const int nshift = -(*shift);
+		double error = 0.0;
+		FLAC__int32 q;
+
+		for(i = 0; i < order; i++) {
+			error += lp_coeff[i] / (1 << nshift);
+			q = lround(error);
+			if(q > qmax)
+				q = qmax;
+			else if(q < qmin)
+				q = qmin;
+			error -= q;
+			qlp_coeff[i] = q;
+		}
+		*shift = 0;
+	}
+
+	return 0;
+}
+
+#if defined(_MSC_VER)
+// silence MSVC warnings about __restrict modifier
+#pragma warning ( disable : 4028 )
+#endif
+
+void FLAC__lpc_compute_residual_from_qlp_coefficients(const FLAC__int32 * flac_restrict data, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int32 * flac_restrict residual)
+#if !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS)
+{
+	FLAC__int64 sumo;
+	uint32_t i, j;
+	FLAC__int32 sum;
+	const FLAC__int32 *history;
+
+	FLAC__ASSERT(order > 0);
+
+	for(i = 0; i < data_len; i++) {
+		sumo = 0;
+		sum = 0;
+		history = data;
+		for(j = 0; j < order; j++) {
+			sum += qlp_coeff[j] * (*(--history));
+			sumo += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*history);
+			if(sumo > 2147483647ll || sumo < -2147483648ll)
+				fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%" PRId64 "\n",i,j,qlp_coeff[j],*history,sumo);
+		}
+		*(residual++) = *(data++) - (sum >> lp_quantization);
+	}
+}
+#else /* fully unrolled version for normal use */
+{
+	int i;
+	FLAC__int32 sum;
+
+	/*
+	 * We do unique versions up to 12th order since that's the subset limit.
+	 * Also they are roughly ordered to match frequency of occurrence to
+	 * minimize branching.
+	 */
+	if(order <= 12) {
+		if(order > 8) {
+			if(order > 10) {
+				if(order == 12) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[11] * data[i-12];
+						sum += qlp_coeff[10] * data[i-11];
+						sum += qlp_coeff[9] * data[i-10];
+						sum += qlp_coeff[8] * data[i-9];
+						sum += qlp_coeff[7] * data[i-8];
+						sum += qlp_coeff[6] * data[i-7];
+						sum += qlp_coeff[5] * data[i-6];
+						sum += qlp_coeff[4] * data[i-5];
+						sum += qlp_coeff[3] * data[i-4];
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						residual[i] = data[i] - (sum >> lp_quantization);
+					}
+				}
+				else { /* order == 11 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[10] * data[i-11];
+						sum += qlp_coeff[9] * data[i-10];
+						sum += qlp_coeff[8] * data[i-9];
+						sum += qlp_coeff[7] * data[i-8];
+						sum += qlp_coeff[6] * data[i-7];
+						sum += qlp_coeff[5] * data[i-6];
+						sum += qlp_coeff[4] * data[i-5];
+						sum += qlp_coeff[3] * data[i-4];
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						residual[i] = data[i] - (sum >> lp_quantization);
+					}
+				}
+			}
+			else {
+				if(order == 10) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[9] * data[i-10];
+						sum += qlp_coeff[8] * data[i-9];
+						sum += qlp_coeff[7] * data[i-8];
+						sum += qlp_coeff[6] * data[i-7];
+						sum += qlp_coeff[5] * data[i-6];
+						sum += qlp_coeff[4] * data[i-5];
+						sum += qlp_coeff[3] * data[i-4];
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						residual[i] = data[i] - (sum >> lp_quantization);
+					}
+				}
+				else { /* order == 9 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[8] * data[i-9];
+						sum += qlp_coeff[7] * data[i-8];
+						sum += qlp_coeff[6] * data[i-7];
+						sum += qlp_coeff[5] * data[i-6];
+						sum += qlp_coeff[4] * data[i-5];
+						sum += qlp_coeff[3] * data[i-4];
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						residual[i] = data[i] - (sum >> lp_quantization);
+					}
+				}
+			}
+		}
+		else if(order > 4) {
+			if(order > 6) {
+				if(order == 8) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[7] * data[i-8];
+						sum += qlp_coeff[6] * data[i-7];
+						sum += qlp_coeff[5] * data[i-6];
+						sum += qlp_coeff[4] * data[i-5];
+						sum += qlp_coeff[3] * data[i-4];
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						residual[i] = data[i] - (sum >> lp_quantization);
+					}
+				}
+				else { /* order == 7 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[6] * data[i-7];
+						sum += qlp_coeff[5] * data[i-6];
+						sum += qlp_coeff[4] * data[i-5];
+						sum += qlp_coeff[3] * data[i-4];
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						residual[i] = data[i] - (sum >> lp_quantization);
+					}
+				}
+			}
+			else {
+				if(order == 6) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[5] * data[i-6];
+						sum += qlp_coeff[4] * data[i-5];
+						sum += qlp_coeff[3] * data[i-4];
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						residual[i] = data[i] - (sum >> lp_quantization);
+					}
+				}
+				else { /* order == 5 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[4] * data[i-5];
+						sum += qlp_coeff[3] * data[i-4];
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						residual[i] = data[i] - (sum >> lp_quantization);
+					}
+				}
+			}
+		}
+		else {
+			if(order > 2) {
+				if(order == 4) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[3] * data[i-4];
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						residual[i] = data[i] - (sum >> lp_quantization);
+					}
+				}
+				else { /* order == 3 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						residual[i] = data[i] - (sum >> lp_quantization);
+					}
+				}
+			}
+			else {
+				if(order == 2) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						residual[i] = data[i] - (sum >> lp_quantization);
+					}
+				}
+				else { /* order == 1 */
+					for(i = 0; i < (int)data_len; i++)
+						residual[i] = data[i] - ((qlp_coeff[0] * data[i-1]) >> lp_quantization);
+				}
+			}
+		}
+	}
+	else { /* order > 12 */
+		for(i = 0; i < (int)data_len; i++) {
+			sum = 0;
+			switch(order) {
+				default:
+				case 32: sum += qlp_coeff[31] * data[i-32]; /* Falls through. */
+				case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */
+				case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */
+				case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */
+				case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */
+				case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */
+				case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */
+				case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */
+				case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */
+				case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */
+				case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */
+				case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */
+				case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */
+				case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */
+				case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */
+				case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */
+				case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */
+				case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */
+				case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */
+				case 13: sum += qlp_coeff[12] * data[i-13];
+				         sum += qlp_coeff[11] * data[i-12];
+				         sum += qlp_coeff[10] * data[i-11];
+				         sum += qlp_coeff[ 9] * data[i-10];
+				         sum += qlp_coeff[ 8] * data[i- 9];
+				         sum += qlp_coeff[ 7] * data[i- 8];
+				         sum += qlp_coeff[ 6] * data[i- 7];
+				         sum += qlp_coeff[ 5] * data[i- 6];
+				         sum += qlp_coeff[ 4] * data[i- 5];
+				         sum += qlp_coeff[ 3] * data[i- 4];
+				         sum += qlp_coeff[ 2] * data[i- 3];
+				         sum += qlp_coeff[ 1] * data[i- 2];
+				         sum += qlp_coeff[ 0] * data[i- 1];
+			}
+			residual[i] = data[i] - (sum >> lp_quantization);
+		}
+	}
+}
+#endif
+
+void FLAC__lpc_compute_residual_from_qlp_coefficients_wide(const FLAC__int32 * flac_restrict data, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int32 * flac_restrict residual)
+#if !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS)
+{
+	uint32_t i, j;
+	FLAC__int64 sum;
+	const FLAC__int32 *history;
+
+	FLAC__ASSERT(order > 0);
+
+	for(i = 0; i < data_len; i++) {
+		sum = 0;
+		history = data;
+		for(j = 0; j < order; j++)
+			sum += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*(--history));
+		if(FLAC__bitmath_silog2(sum >> lp_quantization) > 32) {
+			fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: OVERFLOW, i=%u, sum=%" PRId64 "\n", i, (sum >> lp_quantization));
+			break;
+		}
+		if(FLAC__bitmath_silog2((FLAC__int64)(*data) - (sum >> lp_quantization)) > 32) {
+			fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: OVERFLOW, i=%u, data=%d, sum=%" PRId64 ", residual=%" PRId64 "\n", i, *data, (int64_t)(sum >> lp_quantization), ((FLAC__int64)(*data) - (sum >> lp_quantization)));
+			break;
+		}
+		*(residual++) = *(data++) - (FLAC__int32)(sum >> lp_quantization);
+	}
+}
+#else /* fully unrolled version for normal use */
+{
+	int i;
+	FLAC__int64 sum;
+
+	/*
+	 * We do unique versions up to 12th order since that's the subset limit.
+	 * Also they are roughly ordered to match frequency of occurrence to
+	 * minimize branching.
+	 */
+	if(order <= 12) {
+		if(order > 8) {
+			if(order > 10) {
+				if(order == 12) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[11] * (FLAC__int64)data[i-12];
+						sum += qlp_coeff[10] * (FLAC__int64)data[i-11];
+						sum += qlp_coeff[9] * (FLAC__int64)data[i-10];
+						sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+						sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+						sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+						sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+						sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+				else { /* order == 11 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[10] * (FLAC__int64)data[i-11];
+						sum += qlp_coeff[9] * (FLAC__int64)data[i-10];
+						sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+						sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+						sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+						sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+						sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+			}
+			else {
+				if(order == 10) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[9] * (FLAC__int64)data[i-10];
+						sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+						sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+						sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+						sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+						sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+				else { /* order == 9 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+						sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+						sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+						sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+						sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+			}
+		}
+		else if(order > 4) {
+			if(order > 6) {
+				if(order == 8) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+						sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+						sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+						sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+				else { /* order == 7 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+						sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+						sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+			}
+			else {
+				if(order == 6) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+						sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+				else { /* order == 5 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+			}
+		}
+		else {
+			if(order > 2) {
+				if(order == 4) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+				else { /* order == 3 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+			}
+			else {
+				if(order == 2) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+				else { /* order == 1 */
+					for(i = 0; i < (int)data_len; i++)
+						residual[i] = data[i] - (FLAC__int32)((qlp_coeff[0] * (FLAC__int64)data[i-1]) >> lp_quantization);
+				}
+			}
+		}
+	}
+	else { /* order > 12 */
+		for(i = 0; i < (int)data_len; i++) {
+			sum = 0;
+			switch(order) {
+				default:
+				case 32: sum += qlp_coeff[31] * (FLAC__int64)data[i-32]; /* Falls through. */
+				case 31: sum += qlp_coeff[30] * (FLAC__int64)data[i-31]; /* Falls through. */
+				case 30: sum += qlp_coeff[29] * (FLAC__int64)data[i-30]; /* Falls through. */
+				case 29: sum += qlp_coeff[28] * (FLAC__int64)data[i-29]; /* Falls through. */
+				case 28: sum += qlp_coeff[27] * (FLAC__int64)data[i-28]; /* Falls through. */
+				case 27: sum += qlp_coeff[26] * (FLAC__int64)data[i-27]; /* Falls through. */
+				case 26: sum += qlp_coeff[25] * (FLAC__int64)data[i-26]; /* Falls through. */
+				case 25: sum += qlp_coeff[24] * (FLAC__int64)data[i-25]; /* Falls through. */
+				case 24: sum += qlp_coeff[23] * (FLAC__int64)data[i-24]; /* Falls through. */
+				case 23: sum += qlp_coeff[22] * (FLAC__int64)data[i-23]; /* Falls through. */
+				case 22: sum += qlp_coeff[21] * (FLAC__int64)data[i-22]; /* Falls through. */
+				case 21: sum += qlp_coeff[20] * (FLAC__int64)data[i-21]; /* Falls through. */
+				case 20: sum += qlp_coeff[19] * (FLAC__int64)data[i-20]; /* Falls through. */
+				case 19: sum += qlp_coeff[18] * (FLAC__int64)data[i-19]; /* Falls through. */
+				case 18: sum += qlp_coeff[17] * (FLAC__int64)data[i-18]; /* Falls through. */
+				case 17: sum += qlp_coeff[16] * (FLAC__int64)data[i-17]; /* Falls through. */
+				case 16: sum += qlp_coeff[15] * (FLAC__int64)data[i-16]; /* Falls through. */
+				case 15: sum += qlp_coeff[14] * (FLAC__int64)data[i-15]; /* Falls through. */
+				case 14: sum += qlp_coeff[13] * (FLAC__int64)data[i-14]; /* Falls through. */
+				case 13: sum += qlp_coeff[12] * (FLAC__int64)data[i-13];
+				         sum += qlp_coeff[11] * (FLAC__int64)data[i-12];
+				         sum += qlp_coeff[10] * (FLAC__int64)data[i-11];
+				         sum += qlp_coeff[ 9] * (FLAC__int64)data[i-10];
+				         sum += qlp_coeff[ 8] * (FLAC__int64)data[i- 9];
+				         sum += qlp_coeff[ 7] * (FLAC__int64)data[i- 8];
+				         sum += qlp_coeff[ 6] * (FLAC__int64)data[i- 7];
+				         sum += qlp_coeff[ 5] * (FLAC__int64)data[i- 6];
+				         sum += qlp_coeff[ 4] * (FLAC__int64)data[i- 5];
+				         sum += qlp_coeff[ 3] * (FLAC__int64)data[i- 4];
+				         sum += qlp_coeff[ 2] * (FLAC__int64)data[i- 3];
+				         sum += qlp_coeff[ 1] * (FLAC__int64)data[i- 2];
+				         sum += qlp_coeff[ 0] * (FLAC__int64)data[i- 1];
+			}
+			residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+		}
+	}
+}
+#endif
+
+void FLAC__lpc_restore_signal(const FLAC__int32 * flac_restrict residual, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int32 * flac_restrict data)
+#if !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS)
+{
+	FLAC__int64 sumo;
+	uint32_t i, j;
+	FLAC__int32 sum;
+	const FLAC__int32 *r = residual, *history;
+
+	FLAC__ASSERT(order > 0);
+
+	for(i = 0; i < data_len; i++) {
+		sumo = 0;
+		sum = 0;
+		history = data;
+		for(j = 0; j < order; j++) {
+			sum += qlp_coeff[j] * (*(--history));
+			sumo += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*history);
+			if(sumo > 2147483647ll || sumo < -2147483648ll)
+				fprintf(stderr,"FLAC__lpc_restore_signal: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%" PRId64 "\n",i,j,qlp_coeff[j],*history,sumo);
+		}
+		*(data++) = *(r++) + (sum >> lp_quantization);
+	}
+}
+#else /* fully unrolled version for normal use */
+{
+	int i;
+	FLAC__int32 sum;
+
+	/*
+	 * We do unique versions up to 12th order since that's the subset limit.
+	 * Also they are roughly ordered to match frequency of occurrence to
+	 * minimize branching.
+	 */
+	if(order <= 12) {
+		if(order > 8) {
+			if(order > 10) {
+				if(order == 12) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[11] * data[i-12];
+						sum += qlp_coeff[10] * data[i-11];
+						sum += qlp_coeff[9] * data[i-10];
+						sum += qlp_coeff[8] * data[i-9];
+						sum += qlp_coeff[7] * data[i-8];
+						sum += qlp_coeff[6] * data[i-7];
+						sum += qlp_coeff[5] * data[i-6];
+						sum += qlp_coeff[4] * data[i-5];
+						sum += qlp_coeff[3] * data[i-4];
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						data[i] = residual[i] + (sum >> lp_quantization);
+					}
+				}
+				else { /* order == 11 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[10] * data[i-11];
+						sum += qlp_coeff[9] * data[i-10];
+						sum += qlp_coeff[8] * data[i-9];
+						sum += qlp_coeff[7] * data[i-8];
+						sum += qlp_coeff[6] * data[i-7];
+						sum += qlp_coeff[5] * data[i-6];
+						sum += qlp_coeff[4] * data[i-5];
+						sum += qlp_coeff[3] * data[i-4];
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						data[i] = residual[i] + (sum >> lp_quantization);
+					}
+				}
+			}
+			else {
+				if(order == 10) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[9] * data[i-10];
+						sum += qlp_coeff[8] * data[i-9];
+						sum += qlp_coeff[7] * data[i-8];
+						sum += qlp_coeff[6] * data[i-7];
+						sum += qlp_coeff[5] * data[i-6];
+						sum += qlp_coeff[4] * data[i-5];
+						sum += qlp_coeff[3] * data[i-4];
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						data[i] = residual[i] + (sum >> lp_quantization);
+					}
+				}
+				else { /* order == 9 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[8] * data[i-9];
+						sum += qlp_coeff[7] * data[i-8];
+						sum += qlp_coeff[6] * data[i-7];
+						sum += qlp_coeff[5] * data[i-6];
+						sum += qlp_coeff[4] * data[i-5];
+						sum += qlp_coeff[3] * data[i-4];
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						data[i] = residual[i] + (sum >> lp_quantization);
+					}
+				}
+			}
+		}
+		else if(order > 4) {
+			if(order > 6) {
+				if(order == 8) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[7] * data[i-8];
+						sum += qlp_coeff[6] * data[i-7];
+						sum += qlp_coeff[5] * data[i-6];
+						sum += qlp_coeff[4] * data[i-5];
+						sum += qlp_coeff[3] * data[i-4];
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						data[i] = residual[i] + (sum >> lp_quantization);
+					}
+				}
+				else { /* order == 7 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[6] * data[i-7];
+						sum += qlp_coeff[5] * data[i-6];
+						sum += qlp_coeff[4] * data[i-5];
+						sum += qlp_coeff[3] * data[i-4];
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						data[i] = residual[i] + (sum >> lp_quantization);
+					}
+				}
+			}
+			else {
+				if(order == 6) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[5] * data[i-6];
+						sum += qlp_coeff[4] * data[i-5];
+						sum += qlp_coeff[3] * data[i-4];
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						data[i] = residual[i] + (sum >> lp_quantization);
+					}
+				}
+				else { /* order == 5 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[4] * data[i-5];
+						sum += qlp_coeff[3] * data[i-4];
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						data[i] = residual[i] + (sum >> lp_quantization);
+					}
+				}
+			}
+		}
+		else {
+			if(order > 2) {
+				if(order == 4) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[3] * data[i-4];
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						data[i] = residual[i] + (sum >> lp_quantization);
+					}
+				}
+				else { /* order == 3 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[2] * data[i-3];
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						data[i] = residual[i] + (sum >> lp_quantization);
+					}
+				}
+			}
+			else {
+				if(order == 2) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[1] * data[i-2];
+						sum += qlp_coeff[0] * data[i-1];
+						data[i] = residual[i] + (sum >> lp_quantization);
+					}
+				}
+				else { /* order == 1 */
+					for(i = 0; i < (int)data_len; i++)
+						data[i] = residual[i] + ((qlp_coeff[0] * data[i-1]) >> lp_quantization);
+				}
+			}
+		}
+	}
+	else { /* order > 12 */
+		for(i = 0; i < (int)data_len; i++) {
+			sum = 0;
+			switch(order) {
+				default:
+				case 32: sum += qlp_coeff[31] * data[i-32]; /* Falls through. */
+				case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */
+				case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */
+				case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */
+				case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */
+				case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */
+				case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */
+				case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */
+				case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */
+				case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */
+				case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */
+				case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */
+				case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */
+				case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */
+				case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */
+				case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */
+				case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */
+				case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */
+				case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */
+				case 13: sum += qlp_coeff[12] * data[i-13];
+				         sum += qlp_coeff[11] * data[i-12];
+				         sum += qlp_coeff[10] * data[i-11];
+				         sum += qlp_coeff[ 9] * data[i-10];
+				         sum += qlp_coeff[ 8] * data[i- 9];
+				         sum += qlp_coeff[ 7] * data[i- 8];
+				         sum += qlp_coeff[ 6] * data[i- 7];
+				         sum += qlp_coeff[ 5] * data[i- 6];
+				         sum += qlp_coeff[ 4] * data[i- 5];
+				         sum += qlp_coeff[ 3] * data[i- 4];
+				         sum += qlp_coeff[ 2] * data[i- 3];
+				         sum += qlp_coeff[ 1] * data[i- 2];
+				         sum += qlp_coeff[ 0] * data[i- 1];
+			}
+			data[i] = residual[i] + (sum >> lp_quantization);
+		}
+	}
+}
+#endif
+
+void FLAC__lpc_restore_signal_wide(const FLAC__int32 * flac_restrict residual, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int32 * flac_restrict data)
+#if !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS)
+{
+	uint32_t i, j;
+	FLAC__int64 sum;
+	const FLAC__int32 *r = residual, *history;
+
+	FLAC__ASSERT(order > 0);
+
+	for(i = 0; i < data_len; i++) {
+		sum = 0;
+		history = data;
+		for(j = 0; j < order; j++)
+			sum += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*(--history));
+		if(FLAC__bitmath_silog2(sum >> lp_quantization) > 32) {
+			fprintf(stderr,"FLAC__lpc_restore_signal_wide: OVERFLOW, i=%u, sum=%" PRId64 "\n", i, (sum >> lp_quantization));
+			break;
+		}
+		if(FLAC__bitmath_silog2((FLAC__int64)(*r) + (sum >> lp_quantization)) > 32) {
+			fprintf(stderr,"FLAC__lpc_restore_signal_wide: OVERFLOW, i=%u, residual=%d, sum=%" PRId64 ", data=%" PRId64 "\n", i, *r, (sum >> lp_quantization), ((FLAC__int64)(*r) + (sum >> lp_quantization)));
+			break;
+		}
+		*(data++) = *(r++) + (FLAC__int32)(sum >> lp_quantization);
+	}
+}
+#else /* fully unrolled version for normal use */
+{
+	int i;
+	FLAC__int64 sum;
+
+	/*
+	 * We do unique versions up to 12th order since that's the subset limit.
+	 * Also they are roughly ordered to match frequency of occurrence to
+	 * minimize branching.
+	 */
+	if(order <= 12) {
+		if(order > 8) {
+			if(order > 10) {
+				if(order == 12) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[11] * (FLAC__int64)data[i-12];
+						sum += qlp_coeff[10] * (FLAC__int64)data[i-11];
+						sum += qlp_coeff[9] * (FLAC__int64)data[i-10];
+						sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+						sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+						sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+						sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+						sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+				else { /* order == 11 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[10] * (FLAC__int64)data[i-11];
+						sum += qlp_coeff[9] * (FLAC__int64)data[i-10];
+						sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+						sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+						sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+						sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+						sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+			}
+			else {
+				if(order == 10) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[9] * (FLAC__int64)data[i-10];
+						sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+						sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+						sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+						sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+						sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+				else { /* order == 9 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+						sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+						sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+						sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+						sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+			}
+		}
+		else if(order > 4) {
+			if(order > 6) {
+				if(order == 8) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+						sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+						sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+						sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+				else { /* order == 7 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+						sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+						sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+			}
+			else {
+				if(order == 6) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+						sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+				else { /* order == 5 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+						sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+			}
+		}
+		else {
+			if(order > 2) {
+				if(order == 4) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+				else { /* order == 3 */
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+			}
+			else {
+				if(order == 2) {
+					for(i = 0; i < (int)data_len; i++) {
+						sum = 0;
+						sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+						sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+						data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+					}
+				}
+				else { /* order == 1 */
+					for(i = 0; i < (int)data_len; i++)
+						data[i] = residual[i] + (FLAC__int32)((qlp_coeff[0] * (FLAC__int64)data[i-1]) >> lp_quantization);
+				}
+			}
+		}
+	}
+	else { /* order > 12 */
+		for(i = 0; i < (int)data_len; i++) {
+			sum = 0;
+			switch(order) {
+				default:
+				case 32: sum += qlp_coeff[31] * (FLAC__int64)data[i-32]; /* Falls through. */
+				case 31: sum += qlp_coeff[30] * (FLAC__int64)data[i-31]; /* Falls through. */
+				case 30: sum += qlp_coeff[29] * (FLAC__int64)data[i-30]; /* Falls through. */
+				case 29: sum += qlp_coeff[28] * (FLAC__int64)data[i-29]; /* Falls through. */
+				case 28: sum += qlp_coeff[27] * (FLAC__int64)data[i-28]; /* Falls through. */
+				case 27: sum += qlp_coeff[26] * (FLAC__int64)data[i-27]; /* Falls through. */
+				case 26: sum += qlp_coeff[25] * (FLAC__int64)data[i-26]; /* Falls through. */
+				case 25: sum += qlp_coeff[24] * (FLAC__int64)data[i-25]; /* Falls through. */
+				case 24: sum += qlp_coeff[23] * (FLAC__int64)data[i-24]; /* Falls through. */
+				case 23: sum += qlp_coeff[22] * (FLAC__int64)data[i-23]; /* Falls through. */
+				case 22: sum += qlp_coeff[21] * (FLAC__int64)data[i-22]; /* Falls through. */
+				case 21: sum += qlp_coeff[20] * (FLAC__int64)data[i-21]; /* Falls through. */
+				case 20: sum += qlp_coeff[19] * (FLAC__int64)data[i-20]; /* Falls through. */
+				case 19: sum += qlp_coeff[18] * (FLAC__int64)data[i-19]; /* Falls through. */
+				case 18: sum += qlp_coeff[17] * (FLAC__int64)data[i-18]; /* Falls through. */
+				case 17: sum += qlp_coeff[16] * (FLAC__int64)data[i-17]; /* Falls through. */
+				case 16: sum += qlp_coeff[15] * (FLAC__int64)data[i-16]; /* Falls through. */
+				case 15: sum += qlp_coeff[14] * (FLAC__int64)data[i-15]; /* Falls through. */
+				case 14: sum += qlp_coeff[13] * (FLAC__int64)data[i-14]; /* Falls through. */
+				case 13: sum += qlp_coeff[12] * (FLAC__int64)data[i-13];
+				         sum += qlp_coeff[11] * (FLAC__int64)data[i-12];
+				         sum += qlp_coeff[10] * (FLAC__int64)data[i-11];
+				         sum += qlp_coeff[ 9] * (FLAC__int64)data[i-10];
+				         sum += qlp_coeff[ 8] * (FLAC__int64)data[i- 9];
+				         sum += qlp_coeff[ 7] * (FLAC__int64)data[i- 8];
+				         sum += qlp_coeff[ 6] * (FLAC__int64)data[i- 7];
+				         sum += qlp_coeff[ 5] * (FLAC__int64)data[i- 6];
+				         sum += qlp_coeff[ 4] * (FLAC__int64)data[i- 5];
+				         sum += qlp_coeff[ 3] * (FLAC__int64)data[i- 4];
+				         sum += qlp_coeff[ 2] * (FLAC__int64)data[i- 3];
+				         sum += qlp_coeff[ 1] * (FLAC__int64)data[i- 2];
+				         sum += qlp_coeff[ 0] * (FLAC__int64)data[i- 1];
+			}
+			data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+		}
+	}
+}
+#endif
+
+#if defined(_MSC_VER)
+#pragma warning ( default : 4028 )
+#endif
+
+double FLAC__lpc_compute_expected_bits_per_residual_sample(double lpc_error, uint32_t total_samples)
+{
+	double error_scale;
+
+	error_scale = 0.5 / (double)total_samples;
+
+	return FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(lpc_error, error_scale);
+}
+
+double FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(double lpc_error, double error_scale)
+{
+	if(lpc_error > 0.0) {
+		double bps = (double)0.5 * log(error_scale * lpc_error) / M_LN2;
+		if(bps >= 0.0)
+			return bps;
+		else
+			return 0.0;
+	}
+	else if(lpc_error < 0.0) { /* error should not be negative but can happen due to inadequate floating-point resolution */
+		return 1e32;
+	}
+	else {
+		return 0.0;
+	}
+}
+
+uint32_t FLAC__lpc_compute_best_order(const double lpc_error[], uint32_t max_order, uint32_t total_samples, uint32_t overhead_bits_per_order)
+{
+	uint32_t order, indx, best_index; /* 'index' the index into lpc_error; index==order-1 since lpc_error[0] is for order==1, lpc_error[1] is for order==2, etc */
+	double bits, best_bits, error_scale;
+
+	error_scale = 0.5 / (double)total_samples;
+
+	best_index = 0;
+	best_bits = (uint32_t)(-1);
+
+	for(indx = 0, order = 1; indx < max_order; indx++, order++) {
+		bits = FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(lpc_error[indx], error_scale) * (double)(total_samples - order) + (double)(order * overhead_bits_per_order);
+		if(bits < best_bits) {
+			best_index = indx;
+			best_bits = bits;
+		}
+	}
+
+	return best_index+1; /* +1 since indx of lpc_error[] is order-1 */
+}
--- /dev/null
+++ b/src/libflac/md5.c
@@ -1,0 +1,479 @@
+#include <stdlib.h>		/* for malloc() */
+#include <string.h>		/* for memcpy() */
+
+#include "private/md5.h"
+#include "share/alloc.h"
+#include "share/compat.h"
+#include "share/endswap.h"
+
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ *
+ * Changed so as no longer to depend on Colin Plumb's `usual.h' header
+ * definitions; now uses stuff from dpkg's config.h.
+ *  - Ian Jackson <ijackson@nyx.cs.du.edu>.
+ * Still in the public domain.
+ *
+ * Josh Coalson: made some changes to integrate with libFLAC.
+ * Still in the public domain.
+ */
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f,w,x,y,z,in,s) \
+	 (w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x)
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void FLAC__MD5Transform(FLAC__uint32 buf[4], FLAC__uint32 const in[16])
+{
+	register FLAC__uint32 a, b, c, d;
+
+	a = buf[0];
+	b = buf[1];
+	c = buf[2];
+	d = buf[3];
+
+	MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+	MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+	MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+	MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+	MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+	MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+	MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+	MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+	MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+	MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+	MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+	MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+	MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+	MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+	MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+	MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+	MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+	MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+	MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+	MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+	MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+	MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+	MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+	MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+	MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+	MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+	MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+	MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+	MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+	MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+	MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+	MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+	MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+	MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+	MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+	MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+	MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+	MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+	MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+	MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+	MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+	MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+	MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+	MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+	MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+	MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+	MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+	MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+	MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+	MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+	MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+	MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+	MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+	MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+	MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+	MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+	MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+	MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+	MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+	MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+	MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+	MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+	MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+	MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+	buf[0] += a;
+	buf[1] += b;
+	buf[2] += c;
+	buf[3] += d;
+}
+
+#define byteSwap(buf, words)
+#define byteSwapX16(buf)
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+static void FLAC__MD5Update(FLAC__MD5Context *ctx, FLAC__byte const *buf, uint32_t len)
+{
+	FLAC__uint32 t;
+
+	/* Update byte count */
+
+	t = ctx->bytes[0];
+	if ((ctx->bytes[0] = t + len) < t)
+		ctx->bytes[1]++;	/* Carry from low to high */
+
+	t = 64 - (t & 0x3f);	/* Space available in ctx->in (at least 1) */
+	if (t > len) {
+		memcpy((FLAC__byte *)ctx->in + 64 - t, buf, len);
+		return;
+	}
+	/* First chunk is an odd size */
+	memcpy((FLAC__byte *)ctx->in + 64 - t, buf, t);
+	byteSwapX16(ctx->in);
+	FLAC__MD5Transform(ctx->buf, ctx->in);
+	buf += t;
+	len -= t;
+
+	/* Process data in 64-byte chunks */
+	while (len >= 64) {
+		memcpy(ctx->in, buf, 64);
+		byteSwapX16(ctx->in);
+		FLAC__MD5Transform(ctx->buf, ctx->in);
+		buf += 64;
+		len -= 64;
+	}
+
+	/* Handle any remaining bytes of data. */
+	memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void FLAC__MD5Init(FLAC__MD5Context *ctx)
+{
+	ctx->buf[0] = 0x67452301;
+	ctx->buf[1] = 0xefcdab89;
+	ctx->buf[2] = 0x98badcfe;
+	ctx->buf[3] = 0x10325476;
+
+	ctx->bytes[0] = 0;
+	ctx->bytes[1] = 0;
+
+	ctx->internal_buf.p8 = 0;
+	ctx->capacity = 0;
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void FLAC__MD5Final(FLAC__byte digest[16], FLAC__MD5Context *ctx)
+{
+	int count = ctx->bytes[0] & 0x3f;	/* Number of bytes in ctx->in */
+	FLAC__byte *p = (FLAC__byte *)ctx->in + count;
+
+	/* Set the first char of padding to 0x80.  There is always room. */
+	*p++ = 0x80;
+
+	/* Bytes of padding needed to make 56 bytes (-8..55) */
+	count = 56 - 1 - count;
+
+	if (count < 0) {	/* Padding forces an extra block */
+		memset(p, 0, count + 8);
+		byteSwapX16(ctx->in);
+		FLAC__MD5Transform(ctx->buf, ctx->in);
+		p = (FLAC__byte *)ctx->in;
+		count = 56;
+	}
+	memset(p, 0, count);
+	byteSwap(ctx->in, 14);
+
+	/* Append length in bits and transform */
+	ctx->in[14] = ctx->bytes[0] << 3;
+	ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29;
+	FLAC__MD5Transform(ctx->buf, ctx->in);
+
+	byteSwap(ctx->buf, 4);
+	memcpy(digest, ctx->buf, 16);
+	if (0 != ctx->internal_buf.p8) {
+		free(ctx->internal_buf.p8);
+		ctx->internal_buf.p8 = 0;
+		ctx->capacity = 0;
+	}
+	memset(ctx, 0, sizeof(*ctx));	/* In case it's sensitive */
+}
+
+/*
+ * Convert the incoming audio signal to a byte stream
+ */
+static void format_input_(FLAC__multibyte *mbuf, const FLAC__int32 * const signal[], uint32_t channels, uint32_t samples, uint32_t bytes_per_sample)
+{
+	FLAC__byte *buf_ = mbuf->p8;
+	FLAC__int16 *buf16 = mbuf->p16;
+	FLAC__int32 *buf32 = mbuf->p32;
+	FLAC__int32 a_word;
+	uint32_t channel, sample;
+
+	/* Storage in the output buffer, buf, is little endian. */
+
+#define BYTES_CHANNEL_SELECTOR(bytes, channels)   (bytes * 100 + channels)
+
+	/* First do the most commonly used combinations. */
+	switch (BYTES_CHANNEL_SELECTOR (bytes_per_sample, channels)) {
+		/* One byte per sample. */
+		case (BYTES_CHANNEL_SELECTOR (1, 1)):
+			for (sample = 0; sample < samples; sample++)
+				*buf_++ = (FLAC__byte)signal[0][sample];
+			return;
+
+		case (BYTES_CHANNEL_SELECTOR (1, 2)):
+			for (sample = 0; sample < samples; sample++) {
+				*buf_++ = (FLAC__byte)signal[0][sample];
+				*buf_++ = (FLAC__byte)signal[1][sample];
+			}
+			return;
+
+		case (BYTES_CHANNEL_SELECTOR (1, 4)):
+			for (sample = 0; sample < samples; sample++) {
+				*buf_++ = (FLAC__byte)signal[0][sample];
+				*buf_++ = (FLAC__byte)signal[1][sample];
+				*buf_++ = (FLAC__byte)signal[2][sample];
+				*buf_++ = (FLAC__byte)signal[3][sample];
+			}
+			return;
+
+		case (BYTES_CHANNEL_SELECTOR (1, 6)):
+			for (sample = 0; sample < samples; sample++) {
+				*buf_++ = (FLAC__byte)signal[0][sample];
+				*buf_++ = (FLAC__byte)signal[1][sample];
+				*buf_++ = (FLAC__byte)signal[2][sample];
+				*buf_++ = (FLAC__byte)signal[3][sample];
+				*buf_++ = (FLAC__byte)signal[4][sample];
+				*buf_++ = (FLAC__byte)signal[5][sample];
+			}
+			return;
+
+		case (BYTES_CHANNEL_SELECTOR (1, 8)):
+			for (sample = 0; sample < samples; sample++) {
+				*buf_++ = (FLAC__byte)signal[0][sample];
+				*buf_++ = (FLAC__byte)signal[1][sample];
+				*buf_++ = (FLAC__byte)signal[2][sample];
+				*buf_++ = (FLAC__byte)signal[3][sample];
+				*buf_++ = (FLAC__byte)signal[4][sample];
+				*buf_++ = (FLAC__byte)signal[5][sample];
+				*buf_++ = (FLAC__byte)signal[6][sample];
+				*buf_++ = (FLAC__byte)signal[7][sample];
+			}
+			return;
+
+		/* Two bytes per sample. */
+		case (BYTES_CHANNEL_SELECTOR (2, 1)):
+			for (sample = 0; sample < samples; sample++)
+				*buf16++ = (FLAC__int16)H2LE_16(signal[0][sample]);
+			return;
+
+		case (BYTES_CHANNEL_SELECTOR (2, 2)):
+			for (sample = 0; sample < samples; sample++) {
+				*buf16++ = (FLAC__int16)H2LE_16(signal[0][sample]);
+				*buf16++ = (FLAC__int16)H2LE_16(signal[1][sample]);
+			}
+			return;
+
+		case (BYTES_CHANNEL_SELECTOR (2, 4)):
+			for (sample = 0; sample < samples; sample++) {
+				*buf16++ = (FLAC__int16)H2LE_16(signal[0][sample]);
+				*buf16++ = (FLAC__int16)H2LE_16(signal[1][sample]);
+				*buf16++ = (FLAC__int16)H2LE_16(signal[2][sample]);
+				*buf16++ = (FLAC__int16)H2LE_16(signal[3][sample]);
+			}
+			return;
+
+		case (BYTES_CHANNEL_SELECTOR (2, 6)):
+			for (sample = 0; sample < samples; sample++) {
+				*buf16++ = (FLAC__int16)H2LE_16(signal[0][sample]);
+				*buf16++ = (FLAC__int16)H2LE_16(signal[1][sample]);
+				*buf16++ = (FLAC__int16)H2LE_16(signal[2][sample]);
+				*buf16++ = (FLAC__int16)H2LE_16(signal[3][sample]);
+				*buf16++ = (FLAC__int16)H2LE_16(signal[4][sample]);
+				*buf16++ = (FLAC__int16)H2LE_16(signal[5][sample]);
+			}
+			return;
+
+		case (BYTES_CHANNEL_SELECTOR (2, 8)):
+			for (sample = 0; sample < samples; sample++) {
+				*buf16++ = (FLAC__int16)H2LE_16(signal[0][sample]);
+				*buf16++ = (FLAC__int16)H2LE_16(signal[1][sample]);
+				*buf16++ = (FLAC__int16)H2LE_16(signal[2][sample]);
+				*buf16++ = (FLAC__int16)H2LE_16(signal[3][sample]);
+				*buf16++ = (FLAC__int16)H2LE_16(signal[4][sample]);
+				*buf16++ = (FLAC__int16)H2LE_16(signal[5][sample]);
+				*buf16++ = (FLAC__int16)H2LE_16(signal[6][sample]);
+				*buf16++ = (FLAC__int16)H2LE_16(signal[7][sample]);
+			}
+			return;
+
+		/* Three bytes per sample. */
+		case (BYTES_CHANNEL_SELECTOR (3, 1)):
+			for (sample = 0; sample < samples; sample++) {
+				a_word = signal[0][sample];
+				*buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+				*buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+				*buf_++ = (FLAC__byte)a_word;
+			}
+			return;
+
+		case (BYTES_CHANNEL_SELECTOR (3, 2)):
+			for (sample = 0; sample < samples; sample++) {
+				a_word = signal[0][sample];
+				*buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+				*buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+				*buf_++ = (FLAC__byte)a_word;
+				a_word = signal[1][sample];
+				*buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+				*buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+				*buf_++ = (FLAC__byte)a_word;
+			}
+			return;
+
+		/* Four bytes per sample. */
+		case (BYTES_CHANNEL_SELECTOR (4, 1)):
+			for (sample = 0; sample < samples; sample++)
+				*buf32++ = H2LE_32(signal[0][sample]);
+			return;
+
+		case (BYTES_CHANNEL_SELECTOR (4, 2)):
+			for (sample = 0; sample < samples; sample++) {
+				*buf32++ = H2LE_32(signal[0][sample]);
+				*buf32++ = H2LE_32(signal[1][sample]);
+			}
+			return;
+
+		case (BYTES_CHANNEL_SELECTOR (4, 4)):
+			for (sample = 0; sample < samples; sample++) {
+				*buf32++ = H2LE_32(signal[0][sample]);
+				*buf32++ = H2LE_32(signal[1][sample]);
+				*buf32++ = H2LE_32(signal[2][sample]);
+				*buf32++ = H2LE_32(signal[3][sample]);
+			}
+			return;
+
+		case (BYTES_CHANNEL_SELECTOR (4, 6)):
+			for (sample = 0; sample < samples; sample++) {
+				*buf32++ = H2LE_32(signal[0][sample]);
+				*buf32++ = H2LE_32(signal[1][sample]);
+				*buf32++ = H2LE_32(signal[2][sample]);
+				*buf32++ = H2LE_32(signal[3][sample]);
+				*buf32++ = H2LE_32(signal[4][sample]);
+				*buf32++ = H2LE_32(signal[5][sample]);
+			}
+			return;
+
+		case (BYTES_CHANNEL_SELECTOR (4, 8)):
+			for (sample = 0; sample < samples; sample++) {
+				*buf32++ = H2LE_32(signal[0][sample]);
+				*buf32++ = H2LE_32(signal[1][sample]);
+				*buf32++ = H2LE_32(signal[2][sample]);
+				*buf32++ = H2LE_32(signal[3][sample]);
+				*buf32++ = H2LE_32(signal[4][sample]);
+				*buf32++ = H2LE_32(signal[5][sample]);
+				*buf32++ = H2LE_32(signal[6][sample]);
+				*buf32++ = H2LE_32(signal[7][sample]);
+			}
+			return;
+
+		default:
+			break;
+	}
+
+	/* General version. */
+	switch (bytes_per_sample) {
+		case 1:
+			for (sample = 0; sample < samples; sample++)
+				for (channel = 0; channel < channels; channel++)
+					*buf_++ = (FLAC__byte)signal[channel][sample];
+			return;
+
+		case 2:
+			for (sample = 0; sample < samples; sample++)
+				for (channel = 0; channel < channels; channel++)
+					*buf16++ = (FLAC__int16)H2LE_16(signal[channel][sample]);
+			return;
+
+		case 3:
+			for (sample = 0; sample < samples; sample++)
+				for (channel = 0; channel < channels; channel++) {
+					a_word = signal[channel][sample];
+					*buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+					*buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+					*buf_++ = (FLAC__byte)a_word;
+				}
+			return;
+
+		case 4:
+			for (sample = 0; sample < samples; sample++)
+				for (channel = 0; channel < channels; channel++)
+					*buf32++ = H2LE_32(signal[channel][sample]);
+			return;
+
+		default:
+			break;
+	}
+}
+
+/*
+ * Convert the incoming audio signal to a byte stream and FLAC__MD5Update it.
+ */
+FLAC__bool FLAC__MD5Accumulate(FLAC__MD5Context *ctx, const FLAC__int32 * const signal[], uint32_t channels, uint32_t samples, uint32_t bytes_per_sample)
+{
+	const size_t bytes_needed = (size_t)channels * (size_t)samples * (size_t)bytes_per_sample;
+
+	/* overflow check */
+	if ((size_t)channels > SIZE_MAX / (size_t)bytes_per_sample)
+		return false;
+	if ((size_t)channels * (size_t)bytes_per_sample > SIZE_MAX / (size_t)samples)
+		return false;
+
+	if (ctx->capacity < bytes_needed) {
+		if (0 == (ctx->internal_buf.p8 = safe_realloc_(ctx->internal_buf.p8, bytes_needed))) {
+			if (0 == (ctx->internal_buf.p8 = safe_malloc_(bytes_needed))) {
+				ctx->capacity = 0;
+				return false;
+			}
+		}
+		ctx->capacity = bytes_needed;
+	}
+
+	format_input_(&ctx->internal_buf, signal, channels, samples, bytes_per_sample);
+
+	FLAC__MD5Update(ctx, ctx->internal_buf.p8, (uint32_t)bytes_needed);
+
+	return true;
+}
--- /dev/null
+++ b/src/libflac/memory.c
@@ -1,0 +1,175 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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.
+ */
+
+#include <stdint.h>
+#include "private/memory.h"
+#include "share/compat.h"
+#include "share/alloc.h"
+
+void *FLAC__memory_alloc_aligned(size_t bytes, void **aligned_address)
+{
+	void *x;
+
+	x = safe_malloc_(bytes);
+	*aligned_address = x;
+
+	return x;
+}
+
+FLAC__bool FLAC__memory_alloc_aligned_int32_array(size_t elements, FLAC__int32 **unaligned_pointer, FLAC__int32 **aligned_pointer)
+{
+	FLAC__int32 *pu; /* unaligned pointer */
+	union { /* union needed to comply with C99 pointer aliasing rules */
+		FLAC__int32 *pa; /* aligned pointer */
+		void        *pv; /* aligned pointer alias */
+	} u;
+
+	if(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */
+		return false;
+
+	pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv);
+	if(0 == pu) {
+		return false;
+	}
+	else {
+		if(*unaligned_pointer != 0)
+			free(*unaligned_pointer);
+		*unaligned_pointer = pu;
+		*aligned_pointer = u.pa;
+		return true;
+	}
+}
+
+FLAC__bool FLAC__memory_alloc_aligned_uint32_array(size_t elements, FLAC__uint32 **unaligned_pointer, FLAC__uint32 **aligned_pointer)
+{
+	FLAC__uint32 *pu; /* unaligned pointer */
+	union { /* union needed to comply with C99 pointer aliasing rules */
+		FLAC__uint32 *pa; /* aligned pointer */
+		void         *pv; /* aligned pointer alias */
+	} u;
+
+	if(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */
+		return false;
+
+	pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv);
+	if(0 == pu) {
+		return false;
+	}
+	else {
+		if(*unaligned_pointer != 0)
+			free(*unaligned_pointer);
+		*unaligned_pointer = pu;
+		*aligned_pointer = u.pa;
+		return true;
+	}
+}
+
+FLAC__bool FLAC__memory_alloc_aligned_uint64_array(size_t elements, FLAC__uint64 **unaligned_pointer, FLAC__uint64 **aligned_pointer)
+{
+	FLAC__uint64 *pu; /* unaligned pointer */
+	union { /* union needed to comply with C99 pointer aliasing rules */
+		FLAC__uint64 *pa; /* aligned pointer */
+		void         *pv; /* aligned pointer alias */
+	} u;
+
+	if(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */
+		return false;
+
+	pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv);
+	if(0 == pu) {
+		return false;
+	}
+	else {
+		if(*unaligned_pointer != 0)
+			free(*unaligned_pointer);
+		*unaligned_pointer = pu;
+		*aligned_pointer = u.pa;
+		return true;
+	}
+}
+
+FLAC__bool FLAC__memory_alloc_aligned_unsigned_array(size_t elements, uint32_t **unaligned_pointer, uint32_t **aligned_pointer)
+{
+	uint32_t *pu; /* unaligned pointer */
+	union { /* union needed to comply with C99 pointer aliasing rules */
+		uint32_t *pa; /* aligned pointer */
+		void     *pv; /* aligned pointer alias */
+	} u;
+
+	if(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */
+		return false;
+
+	pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv);
+	if(0 == pu) {
+		return false;
+	}
+	else {
+		if(*unaligned_pointer != 0)
+			free(*unaligned_pointer);
+		*unaligned_pointer = pu;
+		*aligned_pointer = u.pa;
+		return true;
+	}
+}
+
+FLAC__bool FLAC__memory_alloc_aligned_real_array(size_t elements, FLAC__real **unaligned_pointer, FLAC__real **aligned_pointer)
+{
+	FLAC__real *pu; /* unaligned pointer */
+	union { /* union needed to comply with C99 pointer aliasing rules */
+		FLAC__real *pa; /* aligned pointer */
+		void       *pv; /* aligned pointer alias */
+	} u;
+
+	if(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */
+		return false;
+
+	pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv);
+	if(0 == pu) {
+		return false;
+	}
+	else {
+		if(*unaligned_pointer != 0)
+			free(*unaligned_pointer);
+		*unaligned_pointer = pu;
+		*aligned_pointer = u.pa;
+		return true;
+	}
+}
+
+void *safe_malloc_mul_2op_p(size_t size1, size_t size2)
+{
+	if(!size1 || !size2)
+		return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */
+	if(size1 > SIZE_MAX / size2)
+		return 0;
+	return malloc(size1*size2);
+}
--- /dev/null
+++ b/src/libflac/metadata_iterators.c
@@ -1,0 +1,3147 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <sys/stat.h> /* for stat(), maybe chmod() */
+
+#include "private/metadata.h"
+
+#include "FLAC/stream_decoder.h"
+#include "share/alloc.h"
+#include "share/compat.h"
+#include "share/macros.h"
+#include "share/safe_str.h"
+#include "private/macros.h"
+#include "private/memory.h"
+
+// 8bb: hide POSIX warnings
+#ifdef _MSC_VER
+#pragma warning(disable: 4996)
+#endif
+
+/* Alias the first (in share/alloc.h) to the second (in src/libFLAC/memory.c). */
+#define safe_malloc_mul_2op_ safe_malloc_mul_2op_p
+
+/****************************************************************************
+ *
+ * Local function declarations
+ *
+ ***************************************************************************/
+
+static void pack_uint32_(FLAC__uint32 val, FLAC__byte *b, uint32_t bytes);
+static void pack_uint32_little_endian_(FLAC__uint32 val, FLAC__byte *b, uint32_t bytes);
+static void pack_uint64_(FLAC__uint64 val, FLAC__byte *b, uint32_t bytes);
+static FLAC__uint32 unpack_uint32_(FLAC__byte *b, uint32_t bytes);
+static FLAC__uint32 unpack_uint32_little_endian_(FLAC__byte *b, uint32_t bytes);
+static FLAC__uint64 unpack_uint64_(FLAC__byte *b, uint32_t bytes);
+
+static FLAC__bool read_metadata_block_header_(FLAC__Metadata_SimpleIterator *iterator);
+static FLAC__bool read_metadata_block_data_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block);
+static FLAC__bool read_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__bool *is_last, FLAC__MetadataType *type, uint32_t *length);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata *block);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_StreamInfo *block);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_Padding *block, uint32_t block_length);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Application *block, uint32_t block_length);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_SeekTable *block, uint32_t block_length);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_entry_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment_Entry *entry, uint32_t max_length);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_VorbisComment *block, uint32_t block_length);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_track_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet_Track *track);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet *block);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Picture *block);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Unknown *block, uint32_t block_length);
+
+static FLAC__bool write_metadata_block_header_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block);
+static FLAC__bool write_metadata_block_data_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block);
+static FLAC__bool write_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block);
+static FLAC__bool write_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block);
+static FLAC__bool write_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_StreamInfo *block);
+static FLAC__bool write_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Padding *block, uint32_t block_length);
+static FLAC__bool write_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Application *block, uint32_t block_length);
+static FLAC__bool write_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_SeekTable *block);
+static FLAC__bool write_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_VorbisComment *block);
+static FLAC__bool write_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_CueSheet *block);
+static FLAC__bool write_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Picture *block);
+static FLAC__bool write_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Unknown *block, uint32_t block_length);
+
+static FLAC__bool write_metadata_block_stationary_(FLAC__Metadata_SimpleIterator *iterator, const FLAC__StreamMetadata *block);
+static FLAC__bool write_metadata_block_stationary_with_padding_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, uint32_t padding_length, FLAC__bool padding_is_last);
+static FLAC__bool rewrite_whole_file_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool append);
+
+static void simple_iterator_push_(FLAC__Metadata_SimpleIterator *iterator);
+static FLAC__bool simple_iterator_pop_(FLAC__Metadata_SimpleIterator *iterator);
+
+static uint32_t seek_to_first_metadata_block_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb);
+static uint32_t seek_to_first_metadata_block_(FILE *f);
+
+static FLAC__bool simple_iterator_copy_file_prefix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, FLAC__bool append);
+static FLAC__bool simple_iterator_copy_file_postfix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, int fixup_is_last_code, FLAC__off_t fixup_is_last_flag_offset, FLAC__bool backup);
+
+static FLAC__bool copy_n_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status);
+static FLAC__bool copy_n_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, FLAC__off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status);
+static FLAC__bool copy_remaining_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__Metadata_SimpleIteratorStatus *status);
+static FLAC__bool copy_remaining_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Eof eof_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, FLAC__Metadata_SimpleIteratorStatus *status);
+
+static FLAC__bool open_tempfile_(const char *filename, const char *tempfile_path_prefix, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status);
+static FLAC__bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status);
+static void cleanup_tempfile_(FILE **tempfile, char **tempfilename);
+
+static FLAC__bool get_file_stats_(const char *filename, struct flac_stat_s *stats);
+static void set_file_stats_(const char *filename, struct flac_stat_s *stats);
+
+static int fseek_wrapper_(FLAC__IOHandle handle, FLAC__int64 offset, int whence);
+static FLAC__int64 ftell_wrapper_(FLAC__IOHandle handle);
+
+static FLAC__Metadata_ChainStatus get_equivalent_status_(FLAC__Metadata_SimpleIteratorStatus status);
+
+
+#ifdef FLAC__VALGRIND_TESTING
+static size_t local__fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
+{
+	size_t ret = fwrite(ptr, size, nmemb, stream);
+	if(!ferror(stream))
+		fflush(stream);
+	return ret;
+}
+#else
+#define local__fwrite fwrite
+#endif
+
+/****************************************************************************
+ *
+ * Level 0 implementation
+ *
+ ***************************************************************************/
+
+static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
+static void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
+static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
+
+typedef struct {
+	FLAC__bool got_error;
+	FLAC__StreamMetadata *object;
+} level0_client_data;
+
+static FLAC__StreamMetadata *get_one_metadata_block_(const char *filename, FLAC__MetadataType type)
+{
+	level0_client_data cd;
+	FLAC__StreamDecoder *decoder;
+
+	cd.got_error = false;
+	cd.object = 0;
+
+	decoder = FLAC__stream_decoder_new();
+
+	if(0 == decoder)
+		return 0;
+
+	FLAC__stream_decoder_set_md5_checking(decoder, false);
+	FLAC__stream_decoder_set_metadata_ignore_all(decoder);
+	FLAC__stream_decoder_set_metadata_respond(decoder, type);
+
+	if(FLAC__stream_decoder_init_file(decoder, filename, write_callback_, metadata_callback_, error_callback_, &cd) != FLAC__STREAM_DECODER_INIT_STATUS_OK || cd.got_error) {
+		(void)FLAC__stream_decoder_finish(decoder);
+		FLAC__stream_decoder_delete(decoder);
+		return 0;
+	}
+
+	if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder) || cd.got_error) {
+		(void)FLAC__stream_decoder_finish(decoder);
+		FLAC__stream_decoder_delete(decoder);
+		if(0 != cd.object)
+			FLAC__metadata_object_delete(cd.object);
+		return 0;
+	}
+
+	(void)FLAC__stream_decoder_finish(decoder);
+	FLAC__stream_decoder_delete(decoder);
+
+	return cd.object;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__StreamMetadata *streaminfo)
+{
+	FLAC__StreamMetadata *object;
+
+	object = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_STREAMINFO);
+
+	if (object) {
+		/* can just copy the contents since STREAMINFO has no internal structure */
+		*streaminfo = *object;
+		FLAC__metadata_object_delete(object);
+		return true;
+	}
+	else {
+		return false;
+	}
+}
+
+FLAC_API FLAC__bool FLAC__metadata_get_tags(const char *filename, FLAC__StreamMetadata **tags)
+{
+	*tags = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+	return 0 != *tags;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_get_cuesheet(const char *filename, FLAC__StreamMetadata **cuesheet)
+{
+	*cuesheet = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_CUESHEET);
+
+	return 0 != *cuesheet;
+}
+
+FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+	(void)decoder, (void)frame, (void)buffer, (void)client_data;
+
+	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+	level0_client_data *cd = (level0_client_data *)client_data;
+	(void)decoder;
+
+	/*
+	 * we assume we only get here when the one metadata block we were
+	 * looking for was passed to us
+	 */
+	if(!cd->got_error && 0 == cd->object) {
+		if(0 == (cd->object = FLAC__metadata_object_clone(metadata)))
+			cd->got_error = true;
+	}
+}
+
+void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+	level0_client_data *cd = (level0_client_data *)client_data;
+	(void)decoder;
+
+	if(status != FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC)
+		cd->got_error = true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_get_picture(const char *filename, FLAC__StreamMetadata **picture, FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, uint32_t max_width, uint32_t max_height, uint32_t max_depth, uint32_t max_colors)
+{
+	FLAC__Metadata_SimpleIterator *it;
+	FLAC__uint64 max_area_seen = 0;
+	FLAC__uint64 max_depth_seen = 0;
+
+	*picture = 0;
+
+	it = FLAC__metadata_simple_iterator_new();
+	if(0 == it)
+		return false;
+	if(!FLAC__metadata_simple_iterator_init(it, filename, /*read_only=*/true, /*preserve_file_stats=*/true)) {
+		FLAC__metadata_simple_iterator_delete(it);
+		return false;
+	}
+	do {
+		if(FLAC__metadata_simple_iterator_get_block_type(it) == FLAC__METADATA_TYPE_PICTURE) {
+			FLAC__StreamMetadata *obj = FLAC__metadata_simple_iterator_get_block(it);
+			FLAC__uint64 area = (FLAC__uint64)obj->data.picture.width * (FLAC__uint64)obj->data.picture.height;
+			/* check constraints */
+			if(
+				(type == (FLAC__StreamMetadata_Picture_Type)(-1) || type == obj->data.picture.type) &&
+				(mime_type == 0 || !strcmp(mime_type, obj->data.picture.mime_type)) &&
+				(description == 0 || !strcmp((const char *)description, (const char *)obj->data.picture.description)) &&
+				obj->data.picture.width <= max_width &&
+				obj->data.picture.height <= max_height &&
+				obj->data.picture.depth <= max_depth &&
+				obj->data.picture.colors <= max_colors &&
+				(area > max_area_seen || (area == max_area_seen && obj->data.picture.depth > max_depth_seen))
+			) {
+				if(*picture)
+					FLAC__metadata_object_delete(*picture);
+				*picture = obj;
+				max_area_seen = area;
+				max_depth_seen = obj->data.picture.depth;
+			}
+			else {
+				FLAC__metadata_object_delete(obj);
+			}
+		}
+	} while(FLAC__metadata_simple_iterator_next(it));
+
+	FLAC__metadata_simple_iterator_delete(it);
+
+	return (0 != *picture);
+}
+
+
+/****************************************************************************
+ *
+ * Level 1 implementation
+ *
+ ***************************************************************************/
+
+#define SIMPLE_ITERATOR_MAX_PUSH_DEPTH (1+4)
+/* 1 for initial offset, +4 for our own personal use */
+
+struct FLAC__Metadata_SimpleIterator {
+	FILE *file;
+	char *filename, *tempfile_path_prefix;
+	struct flac_stat_s stats;
+	FLAC__bool has_stats;
+	FLAC__bool is_writable;
+	FLAC__Metadata_SimpleIteratorStatus status;
+	FLAC__off_t offset[SIMPLE_ITERATOR_MAX_PUSH_DEPTH];
+	FLAC__off_t first_offset; /* this is the offset to the STREAMINFO block */
+	uint32_t depth;
+	/* this is the metadata block header of the current block we are pointing to: */
+	FLAC__bool is_last;
+	FLAC__MetadataType type;
+	uint32_t length;
+};
+
+FLAC_API const char * const FLAC__Metadata_SimpleIteratorStatusString[] = {
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK",
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT",
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE",
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE",
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE",
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA",
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR",
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR",
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR",
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR",
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR",
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR",
+	"FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR"
+};
+
+
+FLAC_API FLAC__Metadata_SimpleIterator *FLAC__metadata_simple_iterator_new(void)
+{
+	FLAC__Metadata_SimpleIterator *iterator = calloc(1, sizeof(FLAC__Metadata_SimpleIterator));
+
+	if(0 != iterator) {
+		iterator->file = 0;
+		iterator->filename = 0;
+		iterator->tempfile_path_prefix = 0;
+		iterator->has_stats = false;
+		iterator->is_writable = false;
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+		iterator->first_offset = iterator->offset[0] = -1;
+		iterator->depth = 0;
+	}
+
+	return iterator;
+}
+
+static void simple_iterator_free_guts_(FLAC__Metadata_SimpleIterator *iterator)
+{
+	if(0 != iterator->file) {
+		fclose(iterator->file);
+		iterator->file = 0;
+		if(iterator->has_stats)
+			set_file_stats_(iterator->filename, &iterator->stats);
+	}
+	if(0 != iterator->filename) {
+		free(iterator->filename);
+		iterator->filename = 0;
+	}
+	if(0 != iterator->tempfile_path_prefix) {
+		free(iterator->tempfile_path_prefix);
+		iterator->tempfile_path_prefix = 0;
+	}
+}
+
+FLAC_API void FLAC__metadata_simple_iterator_delete(FLAC__Metadata_SimpleIterator *iterator)
+{
+	simple_iterator_free_guts_(iterator);
+	free(iterator);
+}
+
+FLAC_API FLAC__Metadata_SimpleIteratorStatus FLAC__metadata_simple_iterator_status(FLAC__Metadata_SimpleIterator *iterator)
+{
+	FLAC__Metadata_SimpleIteratorStatus status;
+
+	status = iterator->status;
+	iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+	return status;
+}
+
+static FLAC__bool simple_iterator_prime_input_(FLAC__Metadata_SimpleIterator *iterator, FLAC__bool read_only)
+{
+	uint32_t ret;
+
+	if(read_only || 0 == (iterator->file = flac_fopen(iterator->filename, "r+b"))) {
+		iterator->is_writable = false;
+		if(read_only || errno == EACCES) {
+			if(0 == (iterator->file = flac_fopen(iterator->filename, "rb"))) {
+				iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE;
+				return false;
+			}
+		}
+		else {
+			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE;
+			return false;
+		}
+	}
+	else {
+		iterator->is_writable = true;
+	}
+
+	ret = seek_to_first_metadata_block_(iterator->file);
+	switch(ret) {
+		case 0:
+			iterator->depth = 0;
+			iterator->first_offset = iterator->offset[iterator->depth] = ftello(iterator->file);
+			return read_metadata_block_header_(iterator);
+		case 1:
+			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+			return false;
+		case 2:
+			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+			return false;
+		case 3:
+			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE;
+			return false;
+		default:
+			return false;
+	}
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_init(FLAC__Metadata_SimpleIterator *iterator, const char *filename, FLAC__bool read_only, FLAC__bool preserve_file_stats)
+{
+	const char *tempfile_path_prefix = 0; /*@@@ search for comments near 'flac_rename(...)' for what it will take to finish implementing this */
+
+	simple_iterator_free_guts_(iterator);
+
+	if(!read_only && preserve_file_stats)
+		iterator->has_stats = get_file_stats_(filename, &iterator->stats);
+
+	if(0 == (iterator->filename = strdup(filename))) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+		return false;
+	}
+	if(0 != tempfile_path_prefix && 0 == (iterator->tempfile_path_prefix = strdup(tempfile_path_prefix))) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+		return false;
+	}
+
+	return simple_iterator_prime_input_(iterator, read_only);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_writable(const FLAC__Metadata_SimpleIterator *iterator)
+{
+	return iterator->is_writable;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_next(FLAC__Metadata_SimpleIterator *iterator)
+{
+	if(iterator->is_last)
+		return false;
+
+	if(0 != fseeko(iterator->file, iterator->length, SEEK_CUR)) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+		return false;
+	}
+
+	iterator->offset[iterator->depth] = ftello(iterator->file);
+
+	return read_metadata_block_header_(iterator);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_prev(FLAC__Metadata_SimpleIterator *iterator)
+{
+	FLAC__off_t this_offset;
+
+	if(iterator->offset[iterator->depth] == iterator->first_offset)
+		return false;
+
+	if(0 != fseeko(iterator->file, iterator->first_offset, SEEK_SET)) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+		return false;
+	}
+	this_offset = iterator->first_offset;
+	if(!read_metadata_block_header_(iterator))
+		return false;
+
+	/* we ignore any error from ftello() and catch it in fseeko() */
+	while(ftello(iterator->file) + (FLAC__off_t)iterator->length < iterator->offset[iterator->depth]) {
+		if(0 != fseeko(iterator->file, iterator->length, SEEK_CUR)) {
+			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+			return false;
+		}
+		this_offset = ftello(iterator->file);
+		if(!read_metadata_block_header_(iterator))
+			return false;
+	}
+
+	iterator->offset[iterator->depth] = this_offset;
+
+	return true;
+}
+
+/*@@@@add to tests*/
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_last(const FLAC__Metadata_SimpleIterator *iterator)
+{
+	return iterator->is_last;
+}
+
+/*@@@@add to tests*/
+FLAC_API off_t FLAC__metadata_simple_iterator_get_block_offset(const FLAC__Metadata_SimpleIterator *iterator)
+{
+	return (off_t)iterator->offset[iterator->depth];
+}
+
+FLAC_API FLAC__MetadataType FLAC__metadata_simple_iterator_get_block_type(const FLAC__Metadata_SimpleIterator *iterator)
+{
+	return iterator->type;
+}
+
+/*@@@@add to tests*/
+FLAC_API uint32_t FLAC__metadata_simple_iterator_get_block_length(const FLAC__Metadata_SimpleIterator *iterator)
+{
+	return iterator->length;
+}
+
+/*@@@@add to tests*/
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_get_application_id(FLAC__Metadata_SimpleIterator *iterator, FLAC__byte *id)
+{
+	const uint32_t id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
+
+	if(iterator->type != FLAC__METADATA_TYPE_APPLICATION) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT;
+		return false;
+	}
+
+	if(fread(id, 1, id_bytes, iterator->file) != id_bytes) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+		return false;
+	}
+
+	/* back up */
+	if(0 != fseeko(iterator->file, -((int)id_bytes), SEEK_CUR)) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+		return false;
+	}
+
+	return true;
+}
+
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_simple_iterator_get_block(FLAC__Metadata_SimpleIterator *iterator)
+{
+	FLAC__StreamMetadata *block = FLAC__metadata_object_new(iterator->type);
+
+	if(0 != block) {
+		block->is_last = iterator->is_last;
+		block->length = iterator->length;
+
+		if(!read_metadata_block_data_(iterator, block)) {
+			FLAC__metadata_object_delete(block);
+			return 0;
+		}
+
+		/* back up to the beginning of the block data to stay consistent */
+		if(0 != fseeko(iterator->file, iterator->offset[iterator->depth] + FLAC__STREAM_METADATA_HEADER_LENGTH, SEEK_SET)) {
+			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+			FLAC__metadata_object_delete(block);
+			return 0;
+		}
+	}
+	else
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+	return block;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_set_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding)
+{
+	FLAC__bool ret;
+
+	if(!iterator->is_writable) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE;
+		return false;
+	}
+
+	if(iterator->type == FLAC__METADATA_TYPE_STREAMINFO || block->type == FLAC__METADATA_TYPE_STREAMINFO) {
+		if(iterator->type != block->type) {
+			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT;
+			return false;
+		}
+	}
+
+	block->is_last = iterator->is_last;
+
+	if(iterator->length == block->length)
+		return write_metadata_block_stationary_(iterator, block);
+	else if(iterator->length > block->length) {
+		if(use_padding && iterator->length >= FLAC__STREAM_METADATA_HEADER_LENGTH + block->length) {
+			ret = write_metadata_block_stationary_with_padding_(iterator, block, iterator->length - FLAC__STREAM_METADATA_HEADER_LENGTH - block->length, block->is_last);
+			return ret;
+		}
+		else {
+			ret = rewrite_whole_file_(iterator, block, /*append=*/false);
+			return ret;
+		}
+	}
+	else /* iterator->length < block->length */ {
+		uint32_t padding_leftover = 0;
+		FLAC__bool padding_is_last = false;
+		if(use_padding) {
+			/* first see if we can even use padding */
+			if(iterator->is_last) {
+				use_padding = false;
+			}
+			else {
+				const uint32_t extra_padding_bytes_required = block->length - iterator->length;
+				simple_iterator_push_(iterator);
+				if(!FLAC__metadata_simple_iterator_next(iterator)) {
+					(void)simple_iterator_pop_(iterator);
+					return false;
+				}
+				if(iterator->type != FLAC__METADATA_TYPE_PADDING) {
+					use_padding = false;
+				}
+				else {
+					if(FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length == extra_padding_bytes_required) {
+						padding_leftover = 0;
+						block->is_last = iterator->is_last;
+					}
+					else if(iterator->length < extra_padding_bytes_required)
+						use_padding = false;
+					else {
+						padding_leftover = FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length - extra_padding_bytes_required;
+						padding_is_last = iterator->is_last;
+						block->is_last = false;
+					}
+				}
+				if(!simple_iterator_pop_(iterator))
+					return false;
+			}
+		}
+		if(use_padding) {
+			if(padding_leftover == 0) {
+				ret = write_metadata_block_stationary_(iterator, block);
+				return ret;
+			}
+			else {
+				ret = write_metadata_block_stationary_with_padding_(iterator, block, padding_leftover - FLAC__STREAM_METADATA_HEADER_LENGTH, padding_is_last);
+				return ret;
+			}
+		}
+		else {
+			ret = rewrite_whole_file_(iterator, block, /*append=*/false);
+			return ret;
+		}
+	}
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_insert_block_after(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding)
+{
+	uint32_t padding_leftover = 0;
+	FLAC__bool padding_is_last = false;
+
+	FLAC__bool ret;
+
+	if(!iterator->is_writable) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE;
+		return false;
+	}
+
+	if(block->type == FLAC__METADATA_TYPE_STREAMINFO) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT;
+		return false;
+	}
+
+	block->is_last = iterator->is_last;
+
+	if(use_padding) {
+		/* first see if we can even use padding */
+		if(iterator->is_last) {
+			use_padding = false;
+		}
+		else {
+			simple_iterator_push_(iterator);
+			if(!FLAC__metadata_simple_iterator_next(iterator)) {
+				(void)simple_iterator_pop_(iterator);
+				return false;
+			}
+			if(iterator->type != FLAC__METADATA_TYPE_PADDING) {
+				use_padding = false;
+			}
+			else {
+				if(iterator->length == block->length) {
+					padding_leftover = 0;
+					block->is_last = iterator->is_last;
+				}
+				else if(iterator->length < FLAC__STREAM_METADATA_HEADER_LENGTH + block->length)
+					use_padding = false;
+				else {
+					padding_leftover = iterator->length - block->length;
+					padding_is_last = iterator->is_last;
+					block->is_last = false;
+				}
+			}
+			if(!simple_iterator_pop_(iterator))
+				return false;
+		}
+	}
+	if(use_padding) {
+		/* move to the next block, which is suitable padding */
+		if(!FLAC__metadata_simple_iterator_next(iterator))
+			return false;
+		if(padding_leftover == 0) {
+			ret = write_metadata_block_stationary_(iterator, block);
+			return ret;
+		}
+		else {
+			ret = write_metadata_block_stationary_with_padding_(iterator, block, padding_leftover - FLAC__STREAM_METADATA_HEADER_LENGTH, padding_is_last);
+			return ret;
+		}
+	}
+	else {
+		ret = rewrite_whole_file_(iterator, block, /*append=*/true);
+		return ret;
+	}
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_delete_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__bool use_padding)
+{
+	FLAC__bool ret;
+
+	if(!iterator->is_writable) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE;
+		return false;
+	}
+
+	if(iterator->type == FLAC__METADATA_TYPE_STREAMINFO) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT;
+		return false;
+	}
+
+	if(use_padding) {
+		FLAC__StreamMetadata *padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING);
+		if(0 == padding) {
+			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+			return false;
+		}
+		padding->length = iterator->length;
+		if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, false)) {
+			FLAC__metadata_object_delete(padding);
+			return false;
+		}
+		FLAC__metadata_object_delete(padding);
+		if(!FLAC__metadata_simple_iterator_prev(iterator))
+			return false;
+		return true;
+	}
+	else {
+		ret = rewrite_whole_file_(iterator, 0, /*append=*/false);
+		return ret;
+	}
+}
+
+
+
+/****************************************************************************
+ *
+ * Level 2 implementation
+ *
+ ***************************************************************************/
+
+
+typedef struct FLAC__Metadata_Node {
+	FLAC__StreamMetadata *data;
+	struct FLAC__Metadata_Node *prev, *next;
+} FLAC__Metadata_Node;
+
+struct FLAC__Metadata_Chain {
+	char *filename; /* will be NULL if using callbacks */
+	FLAC__bool is_ogg;
+	FLAC__Metadata_Node *head;
+	FLAC__Metadata_Node *tail;
+	uint32_t nodes;
+	FLAC__Metadata_ChainStatus status;
+	FLAC__off_t first_offset, last_offset;
+	/*
+	 * This is the length of the chain initially read from the FLAC file.
+	 * it is used to compare against the current length to decide whether
+	 * or not the whole file has to be rewritten.
+	 */
+	FLAC__off_t initial_length;
+	/* @@@ hacky, these are currently only needed by ogg reader */
+	FLAC__IOHandle handle;
+	FLAC__IOCallback_Read read_cb;
+};
+
+struct FLAC__Metadata_Iterator {
+	FLAC__Metadata_Chain *chain;
+	FLAC__Metadata_Node *current;
+};
+
+FLAC_API const char * const FLAC__Metadata_ChainStatusString[] = {
+	"FLAC__METADATA_CHAIN_STATUS_OK",
+	"FLAC__METADATA_CHAIN_STATUS_ILLEGAL_INPUT",
+	"FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE",
+	"FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE",
+	"FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE",
+	"FLAC__METADATA_CHAIN_STATUS_BAD_METADATA",
+	"FLAC__METADATA_CHAIN_STATUS_READ_ERROR",
+	"FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR",
+	"FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR",
+	"FLAC__METADATA_CHAIN_STATUS_RENAME_ERROR",
+	"FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR",
+	"FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR",
+	"FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR",
+	"FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS",
+	"FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH",
+	"FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL"
+};
+
+
+static FLAC__Metadata_Node *node_new_(void)
+{
+	return calloc(1, sizeof(FLAC__Metadata_Node));
+}
+
+static void node_delete_(FLAC__Metadata_Node *node)
+{
+	if(0 != node->data)
+		FLAC__metadata_object_delete(node->data);
+	free(node);
+}
+
+static void chain_init_(FLAC__Metadata_Chain *chain)
+{
+	chain->filename = 0;
+	chain->is_ogg = false;
+	chain->head = chain->tail = 0;
+	chain->nodes = 0;
+	chain->status = FLAC__METADATA_CHAIN_STATUS_OK;
+	chain->initial_length = 0;
+	chain->read_cb = 0;
+}
+
+static void chain_clear_(FLAC__Metadata_Chain *chain)
+{
+	FLAC__Metadata_Node *node, *next;
+
+	for(node = chain->head; node; ) {
+		next = node->next;
+		node_delete_(node);
+		node = next;
+	}
+
+	if(0 != chain->filename)
+		free(chain->filename);
+
+	chain_init_(chain);
+}
+
+static void chain_append_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
+{
+	node->next = node->prev = 0;
+	node->data->is_last = true;
+	if(0 != chain->tail)
+		chain->tail->data->is_last = false;
+
+	if(0 == chain->head)
+		chain->head = node;
+	else {
+		chain->tail->next = node;
+		node->prev = chain->tail;
+	}
+	chain->tail = node;
+	chain->nodes++;
+}
+
+static void chain_remove_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
+{
+	if(node == chain->head)
+		chain->head = node->next;
+	else
+		node->prev->next = node->next;
+
+	if(node == chain->tail)
+		chain->tail = node->prev;
+	else
+		node->next->prev = node->prev;
+
+	if(0 != chain->tail)
+		chain->tail->data->is_last = true;
+
+	chain->nodes--;
+}
+
+static void chain_delete_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
+{
+	chain_remove_node_(chain, node);
+	node_delete_(node);
+}
+
+static FLAC__off_t chain_calculate_length_(FLAC__Metadata_Chain *chain)
+{
+	const FLAC__Metadata_Node *node;
+	FLAC__off_t length = 0;
+	for(node = chain->head; node; node = node->next)
+		length += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length);
+	return length;
+}
+
+static void iterator_insert_node_(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Node *node)
+{
+	node->data->is_last = false;
+
+	node->prev = iterator->current->prev;
+	node->next = iterator->current;
+
+	if(0 == node->prev)
+		iterator->chain->head = node;
+	else
+		node->prev->next = node;
+
+	iterator->current->prev = node;
+
+	iterator->chain->nodes++;
+}
+
+static void iterator_insert_node_after_(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Node *node)
+{
+	iterator->current->data->is_last = false;
+
+	node->prev = iterator->current;
+	node->next = iterator->current->next;
+
+	if(0 == node->next)
+		iterator->chain->tail = node;
+	else
+		node->next->prev = node;
+
+	node->prev->next = node;
+
+	iterator->chain->tail->data->is_last = true;
+
+	iterator->chain->nodes++;
+}
+
+/* return true iff node and node->next are both padding */
+static FLAC__bool chain_merge_adjacent_padding_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
+{
+	if(node->data->type == FLAC__METADATA_TYPE_PADDING && 0 != node->next && node->next->data->type == FLAC__METADATA_TYPE_PADDING) {
+		const uint32_t growth = FLAC__STREAM_METADATA_HEADER_LENGTH + node->next->data->length;
+		node->data->length += growth; /* new block size can be greater than max metadata block size, but it'll be fixed later in chain_prepare_for_write_() */
+
+		chain_delete_node_(chain, node->next);
+		return true;
+	}
+	else
+		return false;
+}
+
+/* Returns the new length of the chain, or 0 if there was an error. */
+/* WATCHOUT: This can get called multiple times before a write, so
+ * it should still work when this happens.
+ */
+/* WATCHOUT: Make sure to also update the logic in
+ * FLAC__metadata_chain_check_if_tempfile_needed() if the logic here changes.
+ */
+static FLAC__off_t chain_prepare_for_write_(FLAC__Metadata_Chain *chain, FLAC__bool use_padding)
+{
+	FLAC__off_t current_length = chain_calculate_length_(chain);
+
+	if(use_padding) {
+		/* if the metadata shrank and the last block is padding, we just extend the last padding block */
+		if(current_length < chain->initial_length && chain->tail->data->type == FLAC__METADATA_TYPE_PADDING) {
+			const FLAC__off_t delta = chain->initial_length - current_length;
+			chain->tail->data->length += (uint32_t)delta;
+			current_length += delta;
+		}
+		/* if the metadata shrank more than 4 bytes then there's room to add another padding block */
+		else if(current_length + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH <= chain->initial_length) {
+			FLAC__StreamMetadata *padding;
+			FLAC__Metadata_Node *node;
+			if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING))) {
+				chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+				return 0;
+			}
+			padding->length = (uint32_t)(chain->initial_length - (FLAC__STREAM_METADATA_HEADER_LENGTH + current_length));
+			if(0 == (node = node_new_())) {
+				FLAC__metadata_object_delete(padding);
+				chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+				return 0;
+			}
+			node->data = padding;
+			chain_append_node_(chain, node);
+			current_length = chain_calculate_length_(chain);
+		}
+		/* if the metadata grew but the last block is padding, try cutting the padding to restore the original length so we don't have to rewrite the whole file */
+		else if(current_length > chain->initial_length) {
+			const FLAC__off_t delta = current_length - chain->initial_length;
+			if(chain->tail->data->type == FLAC__METADATA_TYPE_PADDING) {
+				/* if the delta is exactly the size of the last padding block, remove the padding block */
+				if((FLAC__off_t)chain->tail->data->length + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH == delta) {
+					chain_delete_node_(chain, chain->tail);
+					current_length = chain_calculate_length_(chain);
+				}
+				/* if there is at least 'delta' bytes of padding, trim the padding down */
+				else if((FLAC__off_t)chain->tail->data->length >= delta) {
+					chain->tail->data->length -= (uint32_t)delta;
+					current_length -= delta;
+				}
+			}
+		}
+	}
+
+	/* check sizes of all metadata blocks; reduce padding size if necessary */
+	{
+		FLAC__Metadata_Node *node;
+		for (node = chain->head; node; node = node->next) {
+			if(node->data->length >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN)) {
+				if(node->data->type == FLAC__METADATA_TYPE_PADDING) {
+					node->data->length = (1u << FLAC__STREAM_METADATA_LENGTH_LEN) - 1;
+					current_length = chain_calculate_length_(chain);
+				} else {
+					chain->status = FLAC__METADATA_CHAIN_STATUS_BAD_METADATA;
+					return 0;
+				}
+			}
+		}
+	}
+
+	return current_length;
+}
+
+static FLAC__bool chain_read_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__IOCallback_Tell tell_cb)
+{
+	FLAC__Metadata_Node *node;
+
+	/* we assume we're already at the beginning of the file */
+
+	switch(seek_to_first_metadata_block_cb_(handle, read_cb, seek_cb)) {
+		case 0:
+			break;
+		case 1:
+			chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
+			return false;
+		case 2:
+			chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+			return false;
+		case 3:
+			chain->status = FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE;
+			return false;
+		default:
+			return false;
+	}
+
+	{
+		FLAC__int64 pos = tell_cb(handle);
+		if(pos < 0) {
+			chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
+			return false;
+		}
+		chain->first_offset = (FLAC__off_t)pos;
+	}
+
+	{
+		FLAC__bool is_last;
+		FLAC__MetadataType type;
+		uint32_t length;
+
+		do {
+			node = node_new_();
+			if(0 == node) {
+				chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+				return false;
+			}
+
+			if(!read_metadata_block_header_cb_(handle, read_cb, &is_last, &type, &length)) {
+				node_delete_(node);
+				chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
+				return false;
+			}
+
+			node->data = FLAC__metadata_object_new(type);
+			if(0 == node->data) {
+				node_delete_(node);
+				chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+				return false;
+			}
+
+			node->data->is_last = is_last;
+			node->data->length = length;
+
+			chain->status = get_equivalent_status_(read_metadata_block_data_cb_(handle, read_cb, seek_cb, node->data));
+			if(chain->status != FLAC__METADATA_CHAIN_STATUS_OK) {
+				node_delete_(node);
+				return false;
+			}
+			chain_append_node_(chain, node);
+		} while(!is_last);
+	}
+
+	{
+		FLAC__int64 pos = tell_cb(handle);
+		if(pos < 0) {
+			chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
+			return false;
+		}
+		chain->last_offset = (FLAC__off_t)pos;
+	}
+
+	chain->initial_length = chain_calculate_length_(chain);
+
+	return true;
+}
+
+static FLAC__StreamDecoderReadStatus chain_read_ogg_read_cb_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+	FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)client_data;
+	(void)decoder;
+	if(*bytes > 0 && chain->status == FLAC__METADATA_CHAIN_STATUS_OK) {
+		*bytes = chain->read_cb(buffer, sizeof(FLAC__byte), *bytes, chain->handle);
+		if(*bytes == 0)
+			return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+		else
+			return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+	}
+	else
+		return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+}
+
+static FLAC__StreamDecoderWriteStatus chain_read_ogg_write_cb_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+	(void)decoder, (void)frame, (void)buffer, (void)client_data;
+	return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+}
+
+static void chain_read_ogg_metadata_cb_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+	FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)client_data;
+	FLAC__Metadata_Node *node;
+
+	(void)decoder;
+
+	node = node_new_();
+	if(0 == node) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+		return;
+	}
+
+	node->data = FLAC__metadata_object_clone(metadata);
+	if(0 == node->data) {
+		node_delete_(node);
+		chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+		return;
+	}
+
+	chain_append_node_(chain, node);
+}
+
+static void chain_read_ogg_error_cb_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+	FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)client_data;
+	(void)decoder, (void)status;
+	chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; /*@@@ maybe needs better error code */
+}
+
+static FLAC__bool chain_read_ogg_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb)
+{
+	FLAC__StreamDecoder *decoder;
+
+	/* we assume we're already at the beginning of the file */
+
+	chain->handle = handle;
+	chain->read_cb = read_cb;
+	if(0 == (decoder = FLAC__stream_decoder_new())) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+		return false;
+	}
+	FLAC__stream_decoder_set_metadata_respond_all(decoder);
+	if(FLAC__stream_decoder_init_ogg_stream(decoder, chain_read_ogg_read_cb_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, chain_read_ogg_write_cb_, chain_read_ogg_metadata_cb_, chain_read_ogg_error_cb_, chain) != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+		FLAC__stream_decoder_delete(decoder);
+		chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; /*@@@ maybe needs better error code */
+		return false;
+	}
+
+	chain->first_offset = 0; /*@@@ wrong; will need to be set correctly to implement metadata writing for Ogg FLAC */
+
+	if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder))
+		chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; /*@@@ maybe needs better error code */
+	if(chain->status != FLAC__METADATA_CHAIN_STATUS_OK) {
+		FLAC__stream_decoder_delete(decoder);
+		return false;
+	}
+
+	FLAC__stream_decoder_delete(decoder);
+
+	chain->last_offset = 0; /*@@@ wrong; will need to be set correctly to implement metadata writing for Ogg FLAC */
+
+	chain->initial_length = chain_calculate_length_(chain);
+
+	return true;
+}
+
+static FLAC__bool chain_rewrite_metadata_in_place_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, FLAC__IOCallback_Seek seek_cb)
+{
+	FLAC__Metadata_Node *node;
+
+	if(0 != seek_cb(handle, chain->first_offset, SEEK_SET)) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+		return false;
+	}
+
+	for(node = chain->head; node; node = node->next) {
+		if(!write_metadata_block_header_cb_(handle, write_cb, node->data)) {
+			chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
+			return false;
+		}
+		if(!write_metadata_block_data_cb_(handle, write_cb, node->data)) {
+			chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
+			return false;
+		}
+	}
+
+	chain->status = FLAC__METADATA_CHAIN_STATUS_OK;
+	return true;
+}
+
+static FLAC__bool chain_rewrite_metadata_in_place_(FLAC__Metadata_Chain *chain)
+{
+	FILE *file;
+	FLAC__bool ret;
+
+	if(0 == (file = flac_fopen(chain->filename, "r+b"))) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
+		return false;
+	}
+
+	/* chain_rewrite_metadata_in_place_cb_() sets chain->status for us */
+	ret = chain_rewrite_metadata_in_place_cb_(chain, (FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, fseek_wrapper_);
+
+	fclose(file);
+
+	return ret;
+}
+
+static FLAC__bool chain_rewrite_file_(FLAC__Metadata_Chain *chain, const char *tempfile_path_prefix)
+{
+	FILE *f, *tempfile = NULL;
+	char *tempfilename;
+	FLAC__Metadata_SimpleIteratorStatus status;
+	const FLAC__Metadata_Node *node;
+
+	/* copy the file prefix (data up to first metadata block */
+	if(0 == (f = flac_fopen(chain->filename, "rb"))) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
+		return false;
+	}
+	if(!open_tempfile_(chain->filename, tempfile_path_prefix, &tempfile, &tempfilename, &status)) {
+		chain->status = get_equivalent_status_(status);
+		goto err;
+	}
+	if(!copy_n_bytes_from_file_(f, tempfile, chain->first_offset, &status)) {
+		chain->status = get_equivalent_status_(status);
+		goto err;
+	}
+
+	/* write the metadata */
+	for(node = chain->head; node; node = node->next) {
+		if(!write_metadata_block_header_(tempfile, &status, node->data)) {
+			chain->status = get_equivalent_status_(status);
+			goto err;
+		}
+		if(!write_metadata_block_data_(tempfile, &status, node->data)) {
+			chain->status = get_equivalent_status_(status);
+			goto err;
+		}
+	}
+	/*FLAC__ASSERT(fflush(), ftello() == chain->last_offset);*/
+
+	/* copy the file postfix (everything after the metadata) */
+	if(0 != fseeko(f, chain->last_offset, SEEK_SET)) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+		goto err;
+	}
+	if(!copy_remaining_bytes_from_file_(f, tempfile, &status)) {
+		chain->status = get_equivalent_status_(status);
+		goto err;
+	}
+
+	/* move the tempfile on top of the original */
+	(void)fclose(f);
+	if(!transport_tempfile_(chain->filename, &tempfile, &tempfilename, &status))
+		return false;
+
+	return true;
+
+err:
+	(void)fclose(f);
+	cleanup_tempfile_(&tempfile, &tempfilename);
+	return false;
+}
+
+/* assumes 'handle' is already at beginning of file */
+static FLAC__bool chain_rewrite_file_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__IOCallback_Eof eof_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb)
+{
+	FLAC__Metadata_SimpleIteratorStatus status;
+	const FLAC__Metadata_Node *node;
+
+	/* copy the file prefix (data up to first metadata block */
+	if(!copy_n_bytes_from_file_cb_(handle, read_cb, temp_handle, temp_write_cb, chain->first_offset, &status)) {
+		chain->status = get_equivalent_status_(status);
+		return false;
+	}
+
+	/* write the metadata */
+	for(node = chain->head; node; node = node->next) {
+		if(!write_metadata_block_header_cb_(temp_handle, temp_write_cb, node->data)) {
+			chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
+			return false;
+		}
+		if(!write_metadata_block_data_cb_(temp_handle, temp_write_cb, node->data)) {
+			chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
+			return false;
+		}
+	}
+
+	/* copy the file postfix (everything after the metadata) */
+	if(0 != seek_cb(handle, chain->last_offset, SEEK_SET)) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+		return false;
+	}
+	if(!copy_remaining_bytes_from_file_cb_(handle, read_cb, eof_cb, temp_handle, temp_write_cb, &status)) {
+		chain->status = get_equivalent_status_(status);
+		return false;
+	}
+
+	return true;
+}
+
+FLAC_API FLAC__Metadata_Chain *FLAC__metadata_chain_new(void)
+{
+	FLAC__Metadata_Chain *chain = calloc(1, sizeof(FLAC__Metadata_Chain));
+
+	if(0 != chain)
+		chain_init_(chain);
+
+	return chain;
+}
+
+FLAC_API void FLAC__metadata_chain_delete(FLAC__Metadata_Chain *chain)
+{
+	chain_clear_(chain);
+
+	free(chain);
+}
+
+FLAC_API FLAC__Metadata_ChainStatus FLAC__metadata_chain_status(FLAC__Metadata_Chain *chain)
+{
+	FLAC__Metadata_ChainStatus status;
+
+	status = chain->status;
+	chain->status = FLAC__METADATA_CHAIN_STATUS_OK;
+	return status;
+}
+
+static FLAC__bool chain_read_(FLAC__Metadata_Chain *chain, const char *filename, FLAC__bool is_ogg)
+{
+	FILE *file;
+	FLAC__bool ret;
+
+	chain_clear_(chain);
+
+	if(0 == (chain->filename = strdup(filename))) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+		return false;
+	}
+
+	chain->is_ogg = is_ogg;
+
+	if(0 == (file = flac_fopen(filename, "rb"))) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
+		return false;
+	}
+
+	/* the function also sets chain->status for us */
+	ret = is_ogg?
+		chain_read_ogg_cb_(chain, file, (FLAC__IOCallback_Read)fread) :
+		chain_read_cb_(chain, file, (FLAC__IOCallback_Read)fread, fseek_wrapper_, ftell_wrapper_)
+	;
+
+	fclose(file);
+
+	return ret;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_chain_read(FLAC__Metadata_Chain *chain, const char *filename)
+{
+	return chain_read_(chain, filename, /*is_ogg=*/false);
+}
+
+/*@@@@add to tests*/
+FLAC_API FLAC__bool FLAC__metadata_chain_read_ogg(FLAC__Metadata_Chain *chain, const char *filename)
+{
+	return chain_read_(chain, filename, /*is_ogg=*/true);
+}
+
+static FLAC__bool chain_read_with_callbacks_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks, FLAC__bool is_ogg)
+{
+	FLAC__bool ret;
+
+	chain_clear_(chain);
+
+	if (0 == callbacks.read || 0 == callbacks.seek || 0 == callbacks.tell) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
+		return false;
+	}
+
+	chain->is_ogg = is_ogg;
+
+	/* rewind */
+	if(0 != callbacks.seek(handle, 0, SEEK_SET)) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+		return false;
+	}
+
+	/* the function also sets chain->status for us */
+	ret = is_ogg?
+		chain_read_ogg_cb_(chain, handle, callbacks.read) :
+		chain_read_cb_(chain, handle, callbacks.read, callbacks.seek, callbacks.tell)
+	;
+
+	return ret;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_chain_read_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks)
+{
+	return chain_read_with_callbacks_(chain, handle, callbacks, /*is_ogg=*/false);
+}
+
+/*@@@@add to tests*/
+FLAC_API FLAC__bool FLAC__metadata_chain_read_ogg_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks)
+{
+	return chain_read_with_callbacks_(chain, handle, callbacks, /*is_ogg=*/true);
+}
+
+typedef enum {
+	LBS_NONE = 0,
+	LBS_SIZE_CHANGED,
+	LBS_BLOCK_ADDED,
+	LBS_BLOCK_REMOVED
+} LastBlockState;
+
+FLAC_API FLAC__bool FLAC__metadata_chain_check_if_tempfile_needed(FLAC__Metadata_Chain *chain, FLAC__bool use_padding)
+{
+	/* This does all the same checks that are in chain_prepare_for_write_()
+	 * but doesn't actually alter the chain.  Make sure to update the logic
+	 * here if chain_prepare_for_write_() changes.
+	 */
+	FLAC__off_t current_length;
+	LastBlockState lbs_state = LBS_NONE;
+	uint32_t lbs_size = 0;
+
+	current_length = chain_calculate_length_(chain);
+
+	if(use_padding) {
+		const FLAC__Metadata_Node * const node = chain->tail;
+		/* if the metadata shrank and the last block is padding, we just extend the last padding block */
+		if(current_length < chain->initial_length && node->data->type == FLAC__METADATA_TYPE_PADDING) {
+			lbs_state = LBS_SIZE_CHANGED;
+			lbs_size = (uint32_t)(node->data->length + (chain->initial_length - current_length));
+		}
+		/* if the metadata shrank more than 4 bytes then there's room to add another padding block */
+		else if(current_length + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH <= chain->initial_length) {
+			lbs_state = LBS_BLOCK_ADDED;
+			lbs_size = (uint32_t)(chain->initial_length - (current_length + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH));
+		}
+		/* if the metadata grew but the last block is padding, try cutting the padding to restore the original length so we don't have to rewrite the whole file */
+		else if(current_length > chain->initial_length) {
+			const FLAC__off_t delta = current_length - chain->initial_length;
+			if(node->data->type == FLAC__METADATA_TYPE_PADDING) {
+				/* if the delta is exactly the size of the last padding block, remove the padding block */
+				if((FLAC__off_t)node->data->length + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH == delta) {
+					lbs_state = LBS_BLOCK_REMOVED;
+					lbs_size = 0;
+				}
+				/* if there is at least 'delta' bytes of padding, trim the padding down */
+				else if((FLAC__off_t)node->data->length >= delta) {
+					lbs_state = LBS_SIZE_CHANGED;
+					lbs_size = (uint32_t)(node->data->length - delta);
+				}
+			}
+		}
+	}
+
+	current_length = 0;
+	/* check sizes of all metadata blocks; reduce padding size if necessary */
+	{
+		const FLAC__Metadata_Node *node;
+		for(node = chain->head; node; node = node->next) {
+			uint32_t block_len = node->data->length;
+			if(node == chain->tail) {
+				if(lbs_state == LBS_BLOCK_REMOVED)
+					continue;
+				else if(lbs_state == LBS_SIZE_CHANGED)
+					block_len = lbs_size;
+			}
+			if(block_len >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN)) {
+				if(node->data->type == FLAC__METADATA_TYPE_PADDING)
+					block_len = (1u << FLAC__STREAM_METADATA_LENGTH_LEN) - 1;
+				else
+					return false /* the return value doesn't matter */;
+			}
+			current_length += (FLAC__STREAM_METADATA_HEADER_LENGTH + block_len);
+		}
+
+		if(lbs_state == LBS_BLOCK_ADDED) {
+			/* test added padding block */
+			uint32_t block_len = lbs_size;
+			if(block_len >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN))
+				block_len = (1u << FLAC__STREAM_METADATA_LENGTH_LEN) - 1;
+			current_length += (FLAC__STREAM_METADATA_HEADER_LENGTH + block_len);
+		}
+	}
+
+	return (current_length != chain->initial_length);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_chain_write(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__bool preserve_file_stats)
+{
+	struct flac_stat_s stats;
+	const char *tempfile_path_prefix = 0;
+	FLAC__off_t current_length;
+
+	if (chain->is_ogg) { /* cannot write back to Ogg FLAC yet */
+		chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR;
+		return false;
+	}
+
+	if (0 == chain->filename) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH;
+		return false;
+	}
+
+	current_length = chain_prepare_for_write_(chain, use_padding);
+
+	/* a return value of 0 means there was an error; chain->status is already set */
+	if (0 == current_length)
+		return false;
+
+	if(preserve_file_stats)
+		get_file_stats_(chain->filename, &stats);
+
+	if(current_length == chain->initial_length) {
+		if(!chain_rewrite_metadata_in_place_(chain))
+			return false;
+	}
+	else {
+		if(!chain_rewrite_file_(chain, tempfile_path_prefix))
+			return false;
+
+		/* recompute lengths and offsets */
+		{
+			const FLAC__Metadata_Node *node;
+			chain->initial_length = current_length;
+			chain->last_offset = chain->first_offset;
+			for(node = chain->head; node; node = node->next)
+				chain->last_offset += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length);
+		}
+	}
+
+	if(preserve_file_stats)
+		set_file_stats_(chain->filename, &stats);
+
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks)
+{
+	FLAC__off_t current_length;
+
+	if (chain->is_ogg) { /* cannot write back to Ogg FLAC yet */
+		chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR;
+		return false;
+	}
+
+	if (0 != chain->filename) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH;
+		return false;
+	}
+
+	if (0 == callbacks.write || 0 == callbacks.seek) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
+		return false;
+	}
+
+	if (FLAC__metadata_chain_check_if_tempfile_needed(chain, use_padding)) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL;
+		return false;
+	}
+
+	current_length = chain_prepare_for_write_(chain, use_padding);
+
+	/* a return value of 0 means there was an error; chain->status is already set */
+	if (0 == current_length)
+		return false;
+
+	return chain_rewrite_metadata_in_place_cb_(chain, handle, callbacks.write, callbacks.seek);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks_and_tempfile(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks, FLAC__IOHandle temp_handle, FLAC__IOCallbacks temp_callbacks)
+{
+	FLAC__off_t current_length;
+
+	if (chain->is_ogg) { /* cannot write back to Ogg FLAC yet */
+		chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR;
+		return false;
+	}
+
+	if (0 != chain->filename) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH;
+		return false;
+	}
+
+	if (0 == callbacks.read || 0 == callbacks.seek || 0 == callbacks.eof) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
+		return false;
+	}
+	if (0 == temp_callbacks.write) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
+		return false;
+	}
+
+	if (!FLAC__metadata_chain_check_if_tempfile_needed(chain, use_padding)) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL;
+		return false;
+	}
+
+	current_length = chain_prepare_for_write_(chain, use_padding);
+
+	/* a return value of 0 means there was an error; chain->status is already set */
+	if (0 == current_length)
+		return false;
+
+	/* rewind */
+	if(0 != callbacks.seek(handle, 0, SEEK_SET)) {
+		chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+		return false;
+	}
+
+	if(!chain_rewrite_file_cb_(chain, handle, callbacks.read, callbacks.seek, callbacks.eof, temp_handle, temp_callbacks.write))
+		return false;
+
+	/* recompute lengths and offsets */
+	{
+		const FLAC__Metadata_Node *node;
+		chain->initial_length = current_length;
+		chain->last_offset = chain->first_offset;
+		for(node = chain->head; node; node = node->next)
+			chain->last_offset += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length);
+	}
+
+	return true;
+}
+
+FLAC_API void FLAC__metadata_chain_merge_padding(FLAC__Metadata_Chain *chain)
+{
+	FLAC__Metadata_Node *node;
+
+	for(node = chain->head; node; ) {
+		if(!chain_merge_adjacent_padding_(chain, node))
+			node = node->next;
+	}
+}
+
+FLAC_API void FLAC__metadata_chain_sort_padding(FLAC__Metadata_Chain *chain)
+{
+	FLAC__Metadata_Node *node, *save;
+	uint32_t i;
+
+	/*
+	 * Don't try and be too smart... this simple algo is good enough for
+	 * the small number of nodes that we deal with.
+	 */
+	for(i = 0, node = chain->head; i < chain->nodes; i++) {
+		if(node->data->type == FLAC__METADATA_TYPE_PADDING) {
+			save = node->next;
+			chain_remove_node_(chain, node);
+			chain_append_node_(chain, node);
+			node = save;
+		}
+		else {
+			node = node->next;
+		}
+	}
+
+	FLAC__metadata_chain_merge_padding(chain);
+}
+
+
+FLAC_API FLAC__Metadata_Iterator *FLAC__metadata_iterator_new(void)
+{
+	FLAC__Metadata_Iterator *iterator = calloc(1, sizeof(FLAC__Metadata_Iterator));
+
+	/* calloc() implies:
+		iterator->current = 0;
+		iterator->chain = 0;
+	*/
+
+	return iterator;
+}
+
+FLAC_API void FLAC__metadata_iterator_delete(FLAC__Metadata_Iterator *iterator)
+{
+	free(iterator);
+}
+
+FLAC_API void FLAC__metadata_iterator_init(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Chain *chain)
+{
+	iterator->chain = chain;
+	iterator->current = chain->head;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_iterator_next(FLAC__Metadata_Iterator *iterator)
+{
+	if(0 == iterator->current || 0 == iterator->current->next)
+		return false;
+
+	iterator->current = iterator->current->next;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_iterator_prev(FLAC__Metadata_Iterator *iterator)
+{
+	if(0 == iterator->current || 0 == iterator->current->prev)
+		return false;
+
+	iterator->current = iterator->current->prev;
+	return true;
+}
+
+FLAC_API FLAC__MetadataType FLAC__metadata_iterator_get_block_type(const FLAC__Metadata_Iterator *iterator)
+{
+	return iterator->current->data->type;
+}
+
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_iterator_get_block(FLAC__Metadata_Iterator *iterator)
+{
+	return iterator->current->data;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_iterator_set_block(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block)
+{
+	return FLAC__metadata_iterator_delete_block(iterator, false) && FLAC__metadata_iterator_insert_block_after(iterator, block);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_iterator_delete_block(FLAC__Metadata_Iterator *iterator, FLAC__bool replace_with_padding)
+{
+	FLAC__Metadata_Node *save;
+
+	if(0 == iterator->current->prev) {
+		return false;
+	}
+
+	save = iterator->current->prev;
+
+	if(replace_with_padding) {
+		FLAC__metadata_object_delete_data(iterator->current->data);
+		iterator->current->data->type = FLAC__METADATA_TYPE_PADDING;
+	}
+	else {
+		chain_delete_node_(iterator->chain, iterator->current);
+	}
+
+	iterator->current = save;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_before(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block)
+{
+	FLAC__Metadata_Node *node;
+
+	if(block->type == FLAC__METADATA_TYPE_STREAMINFO)
+		return false;
+
+	if(0 == iterator->current->prev) {
+		return false;
+	}
+
+	if(0 == (node = node_new_()))
+		return false;
+
+	node->data = block;
+	iterator_insert_node_(iterator, node);
+	iterator->current = node;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_after(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block)
+{
+	FLAC__Metadata_Node *node;
+
+	if(block->type == FLAC__METADATA_TYPE_STREAMINFO)
+		return false;
+
+	if(0 == (node = node_new_()))
+		return false;
+
+	node->data = block;
+	iterator_insert_node_after_(iterator, node);
+	iterator->current = node;
+	return true;
+}
+
+
+/****************************************************************************
+ *
+ * Local function definitions
+ *
+ ***************************************************************************/
+
+void pack_uint32_(FLAC__uint32 val, FLAC__byte *b, uint32_t bytes)
+{
+	uint32_t i;
+
+	b += bytes;
+
+	for(i = 0; i < bytes; i++) {
+		*(--b) = (FLAC__byte)(val & 0xff);
+		val >>= 8;
+	}
+}
+
+void pack_uint32_little_endian_(FLAC__uint32 val, FLAC__byte *b, uint32_t bytes)
+{
+	uint32_t i;
+
+	for(i = 0; i < bytes; i++) {
+		*(b++) = (FLAC__byte)(val & 0xff);
+		val >>= 8;
+	}
+}
+
+void pack_uint64_(FLAC__uint64 val, FLAC__byte *b, uint32_t bytes)
+{
+	uint32_t i;
+
+	b += bytes;
+
+	for(i = 0; i < bytes; i++) {
+		*(--b) = (FLAC__byte)(val & 0xff);
+		val >>= 8;
+	}
+}
+
+FLAC__uint32 unpack_uint32_(FLAC__byte *b, uint32_t bytes)
+{
+	FLAC__uint32 ret = 0;
+	uint32_t i;
+
+	for(i = 0; i < bytes; i++)
+		ret = (ret << 8) | (FLAC__uint32)(*b++);
+
+	return ret;
+}
+
+FLAC__uint32 unpack_uint32_little_endian_(FLAC__byte *b, uint32_t bytes)
+{
+	FLAC__uint32 ret = 0;
+	uint32_t i;
+
+	b += bytes;
+
+	for(i = 0; i < bytes; i++)
+		ret = (ret << 8) | (FLAC__uint32)(*--b);
+
+	return ret;
+}
+
+FLAC__uint64 unpack_uint64_(FLAC__byte *b, uint32_t bytes)
+{
+	FLAC__uint64 ret = 0;
+	uint32_t i;
+
+	for(i = 0; i < bytes; i++)
+		ret = (ret << 8) | (FLAC__uint64)(*b++);
+
+	return ret;
+}
+
+FLAC__bool read_metadata_block_header_(FLAC__Metadata_SimpleIterator *iterator)
+{
+	if(!read_metadata_block_header_cb_((FLAC__IOHandle)iterator->file, (FLAC__IOCallback_Read)fread, &iterator->is_last, &iterator->type, &iterator->length)) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+		return false;
+	}
+
+	return true;
+}
+
+FLAC__bool read_metadata_block_data_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block)
+{
+	iterator->status = read_metadata_block_data_cb_((FLAC__IOHandle)iterator->file, (FLAC__IOCallback_Read)fread, fseek_wrapper_, block);
+
+	return (iterator->status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK);
+}
+
+FLAC__bool read_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__bool *is_last, FLAC__MetadataType *type, uint32_t *length)
+{
+	FLAC__byte raw_header[FLAC__STREAM_METADATA_HEADER_LENGTH];
+
+	if(read_cb(raw_header, 1, FLAC__STREAM_METADATA_HEADER_LENGTH, handle) != FLAC__STREAM_METADATA_HEADER_LENGTH)
+		return false;
+
+	*is_last = raw_header[0] & 0x80? true : false;
+	*type = (FLAC__MetadataType)(raw_header[0] & 0x7f);
+	*length = unpack_uint32_(raw_header + 1, 3);
+
+	/* Note that we don't check:
+	 *    if(iterator->type >= FLAC__METADATA_TYPE_UNDEFINED)
+	 * we just will read in an opaque block
+	 */
+
+	return true;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata *block)
+{
+	switch(block->type) {
+		case FLAC__METADATA_TYPE_STREAMINFO:
+			return read_metadata_block_data_streaminfo_cb_(handle, read_cb, &block->data.stream_info);
+		case FLAC__METADATA_TYPE_PADDING:
+			return read_metadata_block_data_padding_cb_(handle, seek_cb, &block->data.padding, block->length);
+		case FLAC__METADATA_TYPE_APPLICATION:
+			return read_metadata_block_data_application_cb_(handle, read_cb, &block->data.application, block->length);
+		case FLAC__METADATA_TYPE_SEEKTABLE:
+			return read_metadata_block_data_seektable_cb_(handle, read_cb, &block->data.seek_table, block->length);
+		case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+			return read_metadata_block_data_vorbis_comment_cb_(handle, read_cb, seek_cb, &block->data.vorbis_comment, block->length);
+		case FLAC__METADATA_TYPE_CUESHEET:
+			return read_metadata_block_data_cuesheet_cb_(handle, read_cb, &block->data.cue_sheet);
+		case FLAC__METADATA_TYPE_PICTURE:
+			return read_metadata_block_data_picture_cb_(handle, read_cb, &block->data.picture);
+		default:
+			return read_metadata_block_data_unknown_cb_(handle, read_cb, &block->data.unknown, block->length);
+	}
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_StreamInfo *block)
+{
+	FLAC__byte buffer[FLAC__STREAM_METADATA_STREAMINFO_LENGTH], *b;
+
+	if(read_cb(buffer, 1, FLAC__STREAM_METADATA_STREAMINFO_LENGTH, handle) != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+
+	b = buffer;
+
+	/* we are using hardcoded numbers for simplicity but we should
+	 * probably eventually write a bit-level unpacker and use the
+	 * _STREAMINFO_ constants.
+	 */
+	block->min_blocksize = unpack_uint32_(b, 2); b += 2;
+	block->max_blocksize = unpack_uint32_(b, 2); b += 2;
+	block->min_framesize = unpack_uint32_(b, 3); b += 3;
+	block->max_framesize = unpack_uint32_(b, 3); b += 3;
+	block->sample_rate = (unpack_uint32_(b, 2) << 4) | ((uint32_t)(b[2] & 0xf0) >> 4);
+	block->channels = (uint32_t)((b[2] & 0x0e) >> 1) + 1;
+	block->bits_per_sample = ((((uint32_t)(b[2] & 0x01)) << 4) | (((uint32_t)(b[3] & 0xf0)) >> 4)) + 1;
+	block->total_samples = (((FLAC__uint64)(b[3] & 0x0f)) << 32) | unpack_uint64_(b+4, 4);
+	memcpy(block->md5sum, b+8, 16);
+
+	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_Padding *block, uint32_t block_length)
+{
+	(void)block; /* nothing to do; we don't care about reading the padding bytes */
+
+	if(0 != seek_cb(handle, block_length, SEEK_CUR))
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+
+	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Application *block, uint32_t block_length)
+{
+	const uint32_t id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
+
+	if(read_cb(block->id, 1, id_bytes, handle) != id_bytes)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+
+	if(block_length < id_bytes)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+
+	block_length -= id_bytes;
+
+	if(block_length == 0) {
+		block->data = 0;
+	}
+	else {
+		if(0 == (block->data = malloc(block_length)))
+			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+		if(read_cb(block->data, 1, block_length, handle) != block_length)
+			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	}
+
+	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_SeekTable *block, uint32_t block_length)
+{
+	uint32_t i;
+	FLAC__byte buffer[FLAC__STREAM_METADATA_SEEKPOINT_LENGTH];
+
+	block->num_points = block_length / FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
+
+	if(block->num_points == 0)
+		block->points = 0;
+	else if(0 == (block->points = safe_malloc_mul_2op_p(block->num_points, /*times*/sizeof(FLAC__StreamMetadata_SeekPoint))))
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+	for(i = 0; i < block->num_points; i++) {
+		if(read_cb(buffer, 1, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH, handle) != FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)
+			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+		/* some MAGIC NUMBERs here */
+		block->points[i].sample_number = unpack_uint64_(buffer, 8);
+		block->points[i].stream_offset = unpack_uint64_(buffer+8, 8);
+		block->points[i].frame_samples = unpack_uint32_(buffer+16, 2);
+	}
+
+	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_entry_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment_Entry *entry, uint32_t max_length)
+{
+	const uint32_t entry_length_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8;
+	FLAC__byte buffer[4]; /* magic number is asserted below */
+
+	if(max_length < entry_length_len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA;
+
+	max_length -= entry_length_len;
+	if(read_cb(buffer, 1, entry_length_len, handle) != entry_length_len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	entry->length = unpack_uint32_little_endian_(buffer, entry_length_len);
+	if(max_length < entry->length) {
+		entry->length = 0;
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA;
+	} else max_length -= entry->length;
+
+	if(0 != entry->entry)
+		free(entry->entry);
+
+	if(entry->length == 0) {
+		entry->entry = 0;
+	}
+	else {
+		if(0 == (entry->entry = safe_malloc_add_2op_(entry->length, /*+*/1)))
+			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+		if(read_cb(entry->entry, 1, entry->length, handle) != entry->length)
+			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+
+		entry->entry[entry->length] = '\0';
+	}
+
+	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_VorbisComment *block, uint32_t block_length)
+{
+	uint32_t i;
+	FLAC__Metadata_SimpleIteratorStatus status;
+	const uint32_t num_comments_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8;
+	FLAC__byte buffer[4]; /* magic number is asserted below */
+
+	status = read_metadata_block_data_vorbis_comment_entry_cb_(handle, read_cb, &(block->vendor_string), block_length);
+	if(block_length >= 4)
+		block_length -= 4;
+	if(status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA)
+		goto skip;
+	else if(status != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK)
+		return status;
+	block_length -= block->vendor_string.length;
+
+	if(block_length < num_comments_len) goto skip; else block_length -= num_comments_len;
+	if(read_cb(buffer, 1, num_comments_len, handle) != num_comments_len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	block->num_comments = unpack_uint32_little_endian_(buffer, num_comments_len);
+
+	if(block->num_comments == 0) {
+		block->comments = 0;
+	}
+	else if(0 == (block->comments = calloc(block->num_comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry)))) {
+		block->num_comments = 0;
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+	}
+
+	for(i = 0; i < block->num_comments; i++) {
+		status = read_metadata_block_data_vorbis_comment_entry_cb_(handle, read_cb, block->comments + i, block_length);
+		if(block_length >= 4) block_length -= 4;
+		if(status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA) {
+			block->num_comments = i;
+			goto skip;
+		}
+		else if(status != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK) return status;
+		block_length -= block->comments[i].length;
+	}
+
+  skip:
+	if(block_length > 0) {
+		/* bad metadata */
+		if(0 != seek_cb(handle, block_length, SEEK_CUR))
+			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+	}
+
+	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_track_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet_Track *track)
+{
+	uint32_t i, len;
+	FLAC__byte buffer[32]; /* asserted below that this is big enough */
+
+	len = FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN / 8;
+	if(read_cb(buffer, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	track->offset = unpack_uint64_(buffer, len);
+
+	len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN / 8;
+	if(read_cb(buffer, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	track->number = (FLAC__byte)unpack_uint32_(buffer, len);
+
+	len = FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN / 8;
+	if(read_cb(track->isrc, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+
+	len = (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) / 8;
+	if(read_cb(buffer, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	track->type = buffer[0] >> 7;
+	track->pre_emphasis = (buffer[0] >> 6) & 1;
+
+	len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN / 8;
+	if(read_cb(buffer, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	track->num_indices = (FLAC__byte)unpack_uint32_(buffer, len);
+
+	if(track->num_indices == 0) {
+		track->indices = 0;
+	}
+	else if(0 == (track->indices = calloc(track->num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index))))
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+	for(i = 0; i < track->num_indices; i++) {
+		len = FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN / 8;
+		if(read_cb(buffer, 1, len, handle) != len)
+			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+		track->indices[i].offset = unpack_uint64_(buffer, len);
+
+		len = FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN / 8;
+		if(read_cb(buffer, 1, len, handle) != len)
+			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+		track->indices[i].number = (FLAC__byte)unpack_uint32_(buffer, len);
+
+		len = FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN / 8;
+		if(read_cb(buffer, 1, len, handle) != len)
+			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	}
+
+	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet *block)
+{
+	uint32_t i, len;
+	FLAC__Metadata_SimpleIteratorStatus status;
+	FLAC__byte buffer[1024]; /* MSVC needs a constant expression so we put a magic number and assert */
+
+	len = FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN / 8;
+	if(read_cb(block->media_catalog_number, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+
+	len = FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN / 8;
+	if(read_cb(buffer, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	block->lead_in = unpack_uint64_(buffer, len);
+
+	len = (FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) / 8;
+	if(read_cb(buffer, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	block->is_cd = buffer[0]&0x80? true : false;
+
+	len = FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN / 8;
+	if(read_cb(buffer, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	block->num_tracks = unpack_uint32_(buffer, len);
+
+	if(block->num_tracks == 0) {
+		block->tracks = 0;
+	}
+	else if(0 == (block->tracks = calloc(block->num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track))))
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+	for(i = 0; i < block->num_tracks; i++) {
+		if(FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK != (status = read_metadata_block_data_cuesheet_track_cb_(handle, read_cb, block->tracks + i)))
+			return status;
+	}
+
+	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_picture_cstring_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__byte **data, FLAC__uint32 *length, FLAC__uint32 length_len)
+{
+	FLAC__byte buffer[sizeof(FLAC__uint32)];
+
+	length_len /= 8; /* convert to bytes */
+
+	if(read_cb(buffer, 1, length_len, handle) != length_len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	*length = unpack_uint32_(buffer, length_len);
+
+	if(0 != *data)
+		free(*data);
+
+	if(0 == (*data = safe_malloc_add_2op_(*length, /*+*/1)))
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+	if(*length > 0) {
+		if(read_cb(*data, 1, *length, handle) != *length)
+			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	}
+
+	(*data)[*length] = '\0';
+
+	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Picture *block)
+{
+	FLAC__Metadata_SimpleIteratorStatus status;
+	FLAC__byte buffer[4]; /* asserted below that this is big enough */
+	FLAC__uint32 len;
+
+	len = FLAC__STREAM_METADATA_PICTURE_TYPE_LEN / 8;
+	if(read_cb(buffer, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	block->type = (FLAC__StreamMetadata_Picture_Type)unpack_uint32_(buffer, len);
+
+	if((status = read_metadata_block_data_picture_cstring_cb_(handle, read_cb, (FLAC__byte**)(&(block->mime_type)), &len, FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN)) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK)
+		return status;
+
+	if((status = read_metadata_block_data_picture_cstring_cb_(handle, read_cb, &(block->description), &len, FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN)) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK)
+		return status;
+
+	len = FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN / 8;
+	if(read_cb(buffer, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	block->width = unpack_uint32_(buffer, len);
+
+	len = FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN / 8;
+	if(read_cb(buffer, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	block->height = unpack_uint32_(buffer, len);
+
+	len = FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN / 8;
+	if(read_cb(buffer, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	block->depth = unpack_uint32_(buffer, len);
+
+	len = FLAC__STREAM_METADATA_PICTURE_COLORS_LEN / 8;
+	if(read_cb(buffer, 1, len, handle) != len)
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	block->colors = unpack_uint32_(buffer, len);
+
+	/* for convenience we use read_metadata_block_data_picture_cstring_cb_() even though it adds an extra terminating NUL we don't use */
+	if((status = read_metadata_block_data_picture_cstring_cb_(handle, read_cb, &(block->data), &(block->data_length), FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN)) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK)
+		return status;
+
+	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Unknown *block, uint32_t block_length)
+{
+	if(block_length == 0) {
+		block->data = 0;
+	}
+	else {
+		if(0 == (block->data = malloc(block_length)))
+			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+		if(read_cb(block->data, 1, block_length, handle) != block_length)
+			return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+	}
+
+	return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__bool write_metadata_block_header_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block)
+{
+	if(!write_metadata_block_header_cb_((FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, block)) {
+		*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+		return false;
+	}
+
+	return true;
+}
+
+FLAC__bool write_metadata_block_data_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block)
+{
+	if (write_metadata_block_data_cb_((FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, block)) {
+		*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+		return true;
+	}
+	else {
+		*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+		return false;
+	}
+}
+
+FLAC__bool write_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block)
+{
+	FLAC__byte buffer[FLAC__STREAM_METADATA_HEADER_LENGTH];
+
+	/* double protection */
+	if(block->length >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN))
+		return false;
+
+	buffer[0] = (block->is_last? 0x80 : 0) | (FLAC__byte)block->type;
+	pack_uint32_(block->length, buffer + 1, 3);
+
+	if(write_cb(buffer, 1, FLAC__STREAM_METADATA_HEADER_LENGTH, handle) != FLAC__STREAM_METADATA_HEADER_LENGTH)
+		return false;
+
+	return true;
+}
+
+FLAC__bool write_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block)
+{
+	switch(block->type) {
+		case FLAC__METADATA_TYPE_STREAMINFO:
+			return write_metadata_block_data_streaminfo_cb_(handle, write_cb, &block->data.stream_info);
+		case FLAC__METADATA_TYPE_PADDING:
+			return write_metadata_block_data_padding_cb_(handle, write_cb, &block->data.padding, block->length);
+		case FLAC__METADATA_TYPE_APPLICATION:
+			return write_metadata_block_data_application_cb_(handle, write_cb, &block->data.application, block->length);
+		case FLAC__METADATA_TYPE_SEEKTABLE:
+			return write_metadata_block_data_seektable_cb_(handle, write_cb, &block->data.seek_table);
+		case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+			return write_metadata_block_data_vorbis_comment_cb_(handle, write_cb, &block->data.vorbis_comment);
+		case FLAC__METADATA_TYPE_CUESHEET:
+			return write_metadata_block_data_cuesheet_cb_(handle, write_cb, &block->data.cue_sheet);
+		case FLAC__METADATA_TYPE_PICTURE:
+			return write_metadata_block_data_picture_cb_(handle, write_cb, &block->data.picture);
+		default:
+			return write_metadata_block_data_unknown_cb_(handle, write_cb, &block->data.unknown, block->length);
+	}
+}
+
+FLAC__bool write_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_StreamInfo *block)
+{
+	FLAC__byte buffer[FLAC__STREAM_METADATA_STREAMINFO_LENGTH];
+	const uint32_t channels1 = block->channels - 1;
+	const uint32_t bps1 = block->bits_per_sample - 1;
+
+	/* we are using hardcoded numbers for simplicity but we should
+	 * probably eventually write a bit-level packer and use the
+	 * _STREAMINFO_ constants.
+	 */
+	pack_uint32_(block->min_blocksize, buffer, 2);
+	pack_uint32_(block->max_blocksize, buffer+2, 2);
+	pack_uint32_(block->min_framesize, buffer+4, 3);
+	pack_uint32_(block->max_framesize, buffer+7, 3);
+	buffer[10] = (block->sample_rate >> 12) & 0xff;
+	buffer[11] = (block->sample_rate >> 4) & 0xff;
+	buffer[12] = (FLAC__byte)(((block->sample_rate & 0x0f) << 4) | (channels1 << 1) | (bps1 >> 4));
+	buffer[13] = (FLAC__byte)(((bps1 & 0x0f) << 4) | ((block->total_samples >> 32) & 0x0f));
+	pack_uint32_((FLAC__uint32)block->total_samples, buffer+14, 4);
+	memcpy(buffer+18, block->md5sum, 16);
+
+	if(write_cb(buffer, 1, FLAC__STREAM_METADATA_STREAMINFO_LENGTH, handle) != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
+		return false;
+
+	return true;
+}
+
+FLAC__bool write_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Padding *block, uint32_t block_length)
+{
+	uint32_t i, n = block_length;
+	FLAC__byte buffer[1024];
+
+	(void)block;
+
+	memset(buffer, 0, 1024);
+
+	for(i = 0; i < n/1024; i++)
+		if(write_cb(buffer, 1, 1024, handle) != 1024)
+			return false;
+
+	n %= 1024;
+
+	if(write_cb(buffer, 1, n, handle) != n)
+		return false;
+
+	return true;
+}
+
+FLAC__bool write_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Application *block, uint32_t block_length)
+{
+	const uint32_t id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
+
+	if(write_cb(block->id, 1, id_bytes, handle) != id_bytes)
+		return false;
+
+	block_length -= id_bytes;
+
+	if(write_cb(block->data, 1, block_length, handle) != block_length)
+		return false;
+
+	return true;
+}
+
+FLAC__bool write_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_SeekTable *block)
+{
+	uint32_t i;
+	FLAC__byte buffer[FLAC__STREAM_METADATA_SEEKPOINT_LENGTH];
+
+	for(i = 0; i < block->num_points; i++) {
+		/* some MAGIC NUMBERs here */
+		pack_uint64_(block->points[i].sample_number, buffer, 8);
+		pack_uint64_(block->points[i].stream_offset, buffer+8, 8);
+		pack_uint32_(block->points[i].frame_samples, buffer+16, 2);
+		if(write_cb(buffer, 1, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH, handle) != FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)
+			return false;
+	}
+
+	return true;
+}
+
+FLAC__bool write_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_VorbisComment *block)
+{
+	uint32_t i;
+	const uint32_t entry_length_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8;
+	const uint32_t num_comments_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8;
+	FLAC__byte buffer[4]; /* magic number is asserted below */
+
+	pack_uint32_little_endian_(block->vendor_string.length, buffer, entry_length_len);
+	if(write_cb(buffer, 1, entry_length_len, handle) != entry_length_len)
+		return false;
+	if(write_cb(block->vendor_string.entry, 1, block->vendor_string.length, handle) != block->vendor_string.length)
+		return false;
+
+	pack_uint32_little_endian_(block->num_comments, buffer, num_comments_len);
+	if(write_cb(buffer, 1, num_comments_len, handle) != num_comments_len)
+		return false;
+
+	for(i = 0; i < block->num_comments; i++) {
+		pack_uint32_little_endian_(block->comments[i].length, buffer, entry_length_len);
+		if(write_cb(buffer, 1, entry_length_len, handle) != entry_length_len)
+			return false;
+		if(write_cb(block->comments[i].entry, 1, block->comments[i].length, handle) != block->comments[i].length)
+			return false;
+	}
+
+	return true;
+}
+
+FLAC__bool write_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_CueSheet *block)
+{
+	uint32_t i, j, len;
+	FLAC__byte buffer[1024]; /* asserted below that this is big enough */
+
+	len = FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN / 8;
+	if(write_cb(block->media_catalog_number, 1, len, handle) != len)
+		return false;
+
+	len = FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN / 8;
+	pack_uint64_(block->lead_in, buffer, len);
+	if(write_cb(buffer, 1, len, handle) != len)
+		return false;
+
+	len = (FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) / 8;
+	memset(buffer, 0, len);
+	if(block->is_cd)
+		buffer[0] |= 0x80;
+	if(write_cb(buffer, 1, len, handle) != len)
+		return false;
+
+	len = FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN / 8;
+	pack_uint32_(block->num_tracks, buffer, len);
+	if(write_cb(buffer, 1, len, handle) != len)
+		return false;
+
+	for(i = 0; i < block->num_tracks; i++) {
+		FLAC__StreamMetadata_CueSheet_Track *track = block->tracks + i;
+
+		len = FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN / 8;
+		pack_uint64_(track->offset, buffer, len);
+		if(write_cb(buffer, 1, len, handle) != len)
+			return false;
+
+		len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN / 8;
+		pack_uint32_(track->number, buffer, len);
+		if(write_cb(buffer, 1, len, handle) != len)
+			return false;
+
+		len = FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN / 8;
+		if(write_cb(track->isrc, 1, len, handle) != len)
+			return false;
+
+		len = (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) / 8;
+		memset(buffer, 0, len);
+		buffer[0] = (FLAC__byte)((track->type << 7) | (track->pre_emphasis << 6));
+		if(write_cb(buffer, 1, len, handle) != len)
+			return false;
+
+		len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN / 8;
+		pack_uint32_(track->num_indices, buffer, len);
+		if(write_cb(buffer, 1, len, handle) != len)
+			return false;
+
+		for(j = 0; j < track->num_indices; j++) {
+			FLAC__StreamMetadata_CueSheet_Index *indx = track->indices + j;
+
+			len = FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN / 8;
+			pack_uint64_(indx->offset, buffer, len);
+			if(write_cb(buffer, 1, len, handle) != len)
+				return false;
+
+			len = FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN / 8;
+			pack_uint32_(indx->number, buffer, len);
+			if(write_cb(buffer, 1, len, handle) != len)
+				return false;
+
+			len = FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN / 8;
+			memset(buffer, 0, len);
+			if(write_cb(buffer, 1, len, handle) != len)
+				return false;
+		}
+	}
+
+	return true;
+}
+
+FLAC__bool write_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Picture *block)
+{
+	uint32_t len;
+	size_t slen;
+	FLAC__byte buffer[4]; /* magic number is asserted below */
+
+	len = FLAC__STREAM_METADATA_PICTURE_TYPE_LEN/8;
+	pack_uint32_(block->type, buffer, len);
+	if(write_cb(buffer, 1, len, handle) != len)
+		return false;
+
+	len = FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN/8;
+	slen = strlen(block->mime_type);
+	pack_uint32_((FLAC__uint32)slen, buffer, len);
+	if(write_cb(buffer, 1, len, handle) != len)
+		return false;
+	if(write_cb(block->mime_type, 1, slen, handle) != slen)
+		return false;
+
+	len = FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN/8;
+	slen = strlen((const char *)block->description);
+	pack_uint32_((FLAC__uint32)slen, buffer, len);
+	if(write_cb(buffer, 1, len, handle) != len)
+		return false;
+	if(write_cb(block->description, 1, slen, handle) != slen)
+		return false;
+
+	len = FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN/8;
+	pack_uint32_(block->width, buffer, len);
+	if(write_cb(buffer, 1, len, handle) != len)
+		return false;
+
+	len = FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN/8;
+	pack_uint32_(block->height, buffer, len);
+	if(write_cb(buffer, 1, len, handle) != len)
+		return false;
+
+	len = FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN/8;
+	pack_uint32_(block->depth, buffer, len);
+	if(write_cb(buffer, 1, len, handle) != len)
+		return false;
+
+	len = FLAC__STREAM_METADATA_PICTURE_COLORS_LEN/8;
+	pack_uint32_(block->colors, buffer, len);
+	if(write_cb(buffer, 1, len, handle) != len)
+		return false;
+
+	len = FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN/8;
+	pack_uint32_(block->data_length, buffer, len);
+	if(write_cb(buffer, 1, len, handle) != len)
+		return false;
+	if(write_cb(block->data, 1, block->data_length, handle) != block->data_length)
+		return false;
+
+	return true;
+}
+
+FLAC__bool write_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Unknown *block, uint32_t block_length)
+{
+	if(write_cb(block->data, 1, block_length, handle) != block_length)
+		return false;
+
+	return true;
+}
+
+FLAC__bool write_metadata_block_stationary_(FLAC__Metadata_SimpleIterator *iterator, const FLAC__StreamMetadata *block)
+{
+	if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+		return false;
+	}
+
+	if(!write_metadata_block_header_(iterator->file, &iterator->status, block))
+		return false;
+
+	if(!write_metadata_block_data_(iterator->file, &iterator->status, block))
+		return false;
+
+	if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+		return false;
+	}
+
+	return read_metadata_block_header_(iterator);
+}
+
+FLAC__bool write_metadata_block_stationary_with_padding_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, uint32_t padding_length, FLAC__bool padding_is_last)
+{
+	FLAC__StreamMetadata *padding;
+
+	if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+		return false;
+	}
+
+	block->is_last = false;
+
+	if(!write_metadata_block_header_(iterator->file, &iterator->status, block))
+		return false;
+
+	if(!write_metadata_block_data_(iterator->file, &iterator->status, block))
+		return false;
+
+	if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
+		return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+	padding->is_last = padding_is_last;
+	padding->length = padding_length;
+
+	if(!write_metadata_block_header_(iterator->file, &iterator->status, padding)) {
+		FLAC__metadata_object_delete(padding);
+		return false;
+	}
+
+	if(!write_metadata_block_data_(iterator->file, &iterator->status, padding)) {
+		FLAC__metadata_object_delete(padding);
+		return false;
+	}
+
+	FLAC__metadata_object_delete(padding);
+
+	if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+		return false;
+	}
+
+	return read_metadata_block_header_(iterator);
+}
+
+FLAC__bool rewrite_whole_file_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool append)
+{
+	FILE *tempfile = NULL;
+	char *tempfilename = NULL;
+	int fixup_is_last_code = 0; /* 0 => no need to change any is_last flags */
+	FLAC__off_t fixup_is_last_flag_offset = -1;
+
+	if(iterator->is_last) {
+		if(append) {
+			fixup_is_last_code = 1; /* 1 => clear the is_last flag at the following offset */
+			fixup_is_last_flag_offset = iterator->offset[iterator->depth];
+		}
+		else if(0 == block) {
+			simple_iterator_push_(iterator);
+			if(!FLAC__metadata_simple_iterator_prev(iterator)) {
+				(void)simple_iterator_pop_(iterator);
+				return false;
+			}
+			fixup_is_last_code = -1; /* -1 => set the is_last the flag at the following offset */
+			fixup_is_last_flag_offset = iterator->offset[iterator->depth];
+			if(!simple_iterator_pop_(iterator))
+				return false;
+		}
+	}
+
+	if(!simple_iterator_copy_file_prefix_(iterator, &tempfile, &tempfilename, append))
+		return false;
+
+	if(0 != block) {
+		if(!write_metadata_block_header_(tempfile, &iterator->status, block)) {
+			cleanup_tempfile_(&tempfile, &tempfilename);
+			return false;
+		}
+
+		if(!write_metadata_block_data_(tempfile, &iterator->status, block)) {
+			cleanup_tempfile_(&tempfile, &tempfilename);
+			return false;
+		}
+	}
+
+	if(!simple_iterator_copy_file_postfix_(iterator, &tempfile, &tempfilename, fixup_is_last_code, fixup_is_last_flag_offset, block==0))
+		return false;
+
+	if(append)
+		return FLAC__metadata_simple_iterator_next(iterator);
+
+	return true;
+}
+
+void simple_iterator_push_(FLAC__Metadata_SimpleIterator *iterator)
+{
+	iterator->offset[iterator->depth+1] = iterator->offset[iterator->depth];
+	iterator->depth++;
+}
+
+FLAC__bool simple_iterator_pop_(FLAC__Metadata_SimpleIterator *iterator)
+{
+	iterator->depth--;
+	if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+		return false;
+	}
+
+	return read_metadata_block_header_(iterator);
+}
+
+/* return meanings:
+ * 0: ok
+ * 1: read error
+ * 2: seek error
+ * 3: not a FLAC file
+ */
+uint32_t seek_to_first_metadata_block_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb)
+{
+	FLAC__byte buffer[4];
+	size_t n;
+	uint32_t i;
+
+	/* skip any id3v2 tag */
+	errno = 0;
+	n = read_cb(buffer, 1, 4, handle);
+	if(errno)
+		return 1;
+	else if(n != 4)
+		return 3;
+	else if(0 == memcmp(buffer, "ID3", 3)) {
+		uint32_t tag_length = 0;
+
+		/* skip to the tag length */
+		if(seek_cb(handle, 2, SEEK_CUR) < 0)
+			return 2;
+
+		/* read the length */
+		for(i = 0; i < 4; i++) {
+			if(read_cb(buffer, 1, 1, handle) < 1 || buffer[0] & 0x80)
+				return 1;
+			tag_length <<= 7;
+			tag_length |= (buffer[0] & 0x7f);
+		}
+
+		/* skip the rest of the tag */
+		if(seek_cb(handle, tag_length, SEEK_CUR) < 0)
+			return 2;
+
+		/* read the stream sync code */
+		errno = 0;
+		n = read_cb(buffer, 1, 4, handle);
+		if(errno)
+			return 1;
+		else if(n != 4)
+			return 3;
+	}
+
+	/* check for the fLaC signature */
+	if(0 == memcmp(FLAC__STREAM_SYNC_STRING, buffer, FLAC__STREAM_SYNC_LENGTH))
+		return 0;
+	else
+		return 3;
+}
+
+uint32_t seek_to_first_metadata_block_(FILE *f)
+{
+	return seek_to_first_metadata_block_cb_((FLAC__IOHandle)f, (FLAC__IOCallback_Read)fread, fseek_wrapper_);
+}
+
+FLAC__bool simple_iterator_copy_file_prefix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, FLAC__bool append)
+{
+	const FLAC__off_t offset_end = append? iterator->offset[iterator->depth] + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (FLAC__off_t)iterator->length : iterator->offset[iterator->depth];
+
+	if(0 != fseeko(iterator->file, 0, SEEK_SET)) {
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+		return false;
+	}
+	if(!open_tempfile_(iterator->filename, iterator->tempfile_path_prefix, tempfile, tempfilename, &iterator->status)) {
+		cleanup_tempfile_(tempfile, tempfilename);
+		return false;
+	}
+	if(!copy_n_bytes_from_file_(iterator->file, *tempfile, offset_end, &iterator->status)) {
+		cleanup_tempfile_(tempfile, tempfilename);
+		return false;
+	}
+
+	return true;
+}
+
+FLAC__bool simple_iterator_copy_file_postfix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, int fixup_is_last_code, FLAC__off_t fixup_is_last_flag_offset, FLAC__bool backup)
+{
+	FLAC__off_t save_offset = iterator->offset[iterator->depth];
+
+	if(0 != fseeko(iterator->file, save_offset + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (FLAC__off_t)iterator->length, SEEK_SET)) {
+		cleanup_tempfile_(tempfile, tempfilename);
+		iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+		return false;
+	}
+	if(!copy_remaining_bytes_from_file_(iterator->file, *tempfile, &iterator->status)) {
+		cleanup_tempfile_(tempfile, tempfilename);
+		return false;
+	}
+
+	if(fixup_is_last_code != 0) {
+		/*
+		 * if code == 1, it means a block was appended to the end so
+		 *   we have to clear the is_last flag of the previous block
+		 * if code == -1, it means the last block was deleted so
+		 *   we have to set the is_last flag of the previous block
+		 */
+		/* MAGIC NUMBERs here; we know the is_last flag is the high bit of the byte at this location */
+		FLAC__byte x;
+		if(0 != fseeko(*tempfile, fixup_is_last_flag_offset, SEEK_SET)) {
+			cleanup_tempfile_(tempfile, tempfilename);
+			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+			return false;
+		}
+		if(fread(&x, 1, 1, *tempfile) != 1) {
+			cleanup_tempfile_(tempfile, tempfilename);
+			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+			return false;
+		}
+		if(fixup_is_last_code > 0) {
+			x &= 0x7f;
+		}
+		else {
+			x |= 0x80;
+		}
+		if(0 != fseeko(*tempfile, fixup_is_last_flag_offset, SEEK_SET)) {
+			cleanup_tempfile_(tempfile, tempfilename);
+			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+			return false;
+		}
+		if(local__fwrite(&x, 1, 1, *tempfile) != 1) {
+			cleanup_tempfile_(tempfile, tempfilename);
+			iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+			return false;
+		}
+	}
+
+	(void)fclose(iterator->file);
+
+	if(!transport_tempfile_(iterator->filename, tempfile, tempfilename, &iterator->status))
+		return false;
+
+	if(iterator->has_stats)
+		set_file_stats_(iterator->filename, &iterator->stats);
+
+	if(!simple_iterator_prime_input_(iterator, !iterator->is_writable))
+		return false;
+	if(backup) {
+		while(iterator->offset[iterator->depth] + (FLAC__off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (FLAC__off_t)iterator->length < save_offset)
+			if(!FLAC__metadata_simple_iterator_next(iterator))
+				return false;
+		return true;
+	}
+	else {
+		/* move the iterator to it's original block faster by faking a push, then doing a pop_ */
+		iterator->offset[0] = save_offset;
+		iterator->depth++;
+		return simple_iterator_pop_(iterator);
+	}
+}
+
+FLAC__bool copy_n_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+	FLAC__byte buffer[8192];
+	size_t n;
+
+	while(bytes > 0) {
+		n = flac_min(sizeof(buffer), (size_t)bytes);
+		if(fread(buffer, 1, n, file) != n) {
+			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+			return false;
+		}
+		if(local__fwrite(buffer, 1, n, tempfile) != n) {
+			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+			return false;
+		}
+		bytes -= n;
+	}
+
+	return true;
+}
+
+FLAC__bool copy_n_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, FLAC__off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+	FLAC__byte buffer[8192];
+	size_t n;
+
+	while(bytes > 0) {
+		n = flac_min(sizeof(buffer), (size_t)bytes);
+		if(read_cb(buffer, 1, n, handle) != n) {
+			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+			return false;
+		}
+		if(temp_write_cb(buffer, 1, n, temp_handle) != n) {
+			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+			return false;
+		}
+		bytes -= n;
+	}
+
+	return true;
+}
+
+FLAC__bool copy_remaining_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+	FLAC__byte buffer[8192];
+	size_t n;
+
+	while(!feof(file)) {
+		n = fread(buffer, 1, sizeof(buffer), file);
+		if(n == 0 && !feof(file)) {
+			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+			return false;
+		}
+		if(n > 0 && local__fwrite(buffer, 1, n, tempfile) != n) {
+			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+			return false;
+		}
+	}
+
+	return true;
+}
+
+FLAC__bool copy_remaining_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Eof eof_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+	FLAC__byte buffer[8192];
+	size_t n;
+
+	while(!eof_cb(handle)) {
+		n = read_cb(buffer, 1, sizeof(buffer), handle);
+		if(n == 0 && !eof_cb(handle)) {
+			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+			return false;
+		}
+		if(n > 0 && temp_write_cb(buffer, 1, n, temp_handle) != n) {
+			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+			return false;
+		}
+	}
+
+	return true;
+}
+
+static int
+local_snprintf(char *str, size_t size, const char *fmt, ...)
+{
+	va_list va;
+	int rc;
+
+#if defined _MSC_VER
+	if (size == 0)
+		return 1024;
+#endif
+
+	va_start (va, fmt);
+
+#if defined _MSC_VER
+	rc = vsnprintf_s (str, size, _TRUNCATE, fmt, va);
+	if (rc < 0)
+		rc = (int)(size - 1);
+#elif defined __MINGW32__
+	rc = __mingw_vsnprintf (str, size, fmt, va);
+#else
+	rc = vsnprintf (str, size, fmt, va);
+#endif
+	va_end (va);
+
+	return rc;
+}
+
+FLAC__bool open_tempfile_(const char *filename, const char *tempfile_path_prefix, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+	static const char *tempfile_suffix = ".metadata_edit";
+	if(0 == tempfile_path_prefix) {
+		size_t dest_len = strlen(filename) + strlen(tempfile_suffix) + 1;
+		if(0 == (*tempfilename = safe_malloc_(dest_len))) {
+			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+			return false;
+		}
+		local_snprintf(*tempfilename, dest_len, "%s%s", filename, tempfile_suffix);
+	}
+	else {
+		const char *p = strrchr(filename, '/');
+		size_t dest_len;
+		if(0 == p)
+			p = filename;
+		else
+			p++;
+
+		dest_len = strlen(tempfile_path_prefix) + strlen(p) + strlen(tempfile_suffix) + 2;
+
+		if(0 == (*tempfilename = safe_malloc_(dest_len))) {
+			*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+			return false;
+		}
+		local_snprintf(*tempfilename, dest_len, "%s/%s%s", tempfile_path_prefix, p, tempfile_suffix);
+	}
+
+	if(0 == (*tempfile = flac_fopen(*tempfilename, "w+b"))) {
+		*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE;
+		return false;
+	}
+
+	return true;
+}
+
+FLAC__bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+	(void)fclose(*tempfile);
+	*tempfile = 0;
+
+#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__ || defined __EMX__
+	/* on some flavors of windows, flac_rename() will fail if the destination already exists */
+	if(flac_unlink(filename) < 0) {
+		cleanup_tempfile_(tempfile, tempfilename);
+		*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR;
+		return false;
+	}
+#endif
+
+	/*@@@ to fully support the tempfile_path_prefix we need to update this piece to actually copy across filesystems instead of just flac_rename(): */
+	if(0 != flac_rename(*tempfilename, filename)) {
+		cleanup_tempfile_(tempfile, tempfilename);
+		*status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR;
+		return false;
+	}
+
+	cleanup_tempfile_(tempfile, tempfilename);
+
+	return true;
+}
+
+void cleanup_tempfile_(FILE **tempfile, char **tempfilename)
+{
+	if(0 != *tempfile) {
+		(void)fclose(*tempfile);
+		*tempfile = 0;
+	}
+
+	if(0 != *tempfilename) {
+		(void)flac_unlink(*tempfilename);
+		free(*tempfilename);
+		*tempfilename = 0;
+	}
+}
+
+FLAC__bool get_file_stats_(const char *filename, struct flac_stat_s *stats)
+{
+	return (0 == flac_stat(filename, stats));
+}
+
+void set_file_stats_(const char *filename, struct flac_stat_s *stats)
+{
+	struct utimbuf srctime;
+
+	srctime.actime = stats->st_atime;
+	srctime.modtime = stats->st_mtime;
+	(void)flac_chmod(filename, stats->st_mode);
+	(void)flac_utime(filename, &srctime);
+#if !defined _MSC_VER && !defined __BORLANDC__ && !defined __MINGW32__
+	FLAC_CHECK_RETURN(chown(filename, stats->st_uid, -1));
+	FLAC_CHECK_RETURN(chown(filename, -1, stats->st_gid));
+#endif
+}
+
+int fseek_wrapper_(FLAC__IOHandle handle, FLAC__int64 offset, int whence)
+{
+	return fseeko((FILE*)handle, (FLAC__off_t)offset, whence);
+}
+
+FLAC__int64 ftell_wrapper_(FLAC__IOHandle handle)
+{
+	return ftello((FILE*)handle);
+}
+
+FLAC__Metadata_ChainStatus get_equivalent_status_(FLAC__Metadata_SimpleIteratorStatus status)
+{
+	switch(status) {
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK:
+			return FLAC__METADATA_CHAIN_STATUS_OK;
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT:
+			return FLAC__METADATA_CHAIN_STATUS_ILLEGAL_INPUT;
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE:
+			return FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE:
+			return FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE;
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE:
+			return FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE;
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA:
+			return FLAC__METADATA_CHAIN_STATUS_BAD_METADATA;
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR:
+			return FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR:
+			return FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR:
+			return FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR:
+			return FLAC__METADATA_CHAIN_STATUS_RENAME_ERROR;
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR:
+			return FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR;
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR:
+			return FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+		case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR:
+		default:
+			return FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR;
+	}
+}
--- /dev/null
+++ b/src/libflac/metadata_object.c
@@ -1,0 +1,1588 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "private/metadata.h"
+#include "private/memory.h"
+
+#include "share/alloc.h"
+#include "share/compat.h"
+
+// 8bb: hide POSIX warnings
+#ifdef _MSC_VER
+#pragma warning(disable: 4996)
+#endif
+
+/* Alias the first (in share/alloc.h) to the second (in src/libFLAC/memory.c). */
+#define safe_malloc_mul_2op_ safe_malloc_mul_2op_p
+
+
+/****************************************************************************
+ *
+ * Local routines
+ *
+ ***************************************************************************/
+
+/* copy bytes:
+ *  from = NULL  && bytes = 0
+ *       to <- NULL
+ *  from != NULL && bytes > 0
+ *       to <- copy of from
+ *  else ASSERT
+ * malloc error leaves 'to' unchanged
+ */
+static FLAC__bool copy_bytes_(FLAC__byte **to, const FLAC__byte *from, uint32_t bytes)
+{
+	if (bytes > 0 && from != NULL) {
+		FLAC__byte *x;
+		if ((x = safe_malloc_(bytes)) == NULL)
+			return false;
+		memcpy(x, from, bytes);
+		*to = x;
+	}
+	else {
+		*to = 0;
+	}
+	return true;
+}
+
+/* reallocate entry to 1 byte larger and add a terminating NUL */
+/* realloc() failure leaves entry unchanged */
+static FLAC__bool ensure_null_terminated_(FLAC__byte **entry, uint32_t length)
+{
+	FLAC__byte *x = safe_realloc_add_2op_(*entry, length, /*+*/1);
+	if (x != NULL) {
+		x[length] = '\0';
+		*entry = x;
+		return true;
+	}
+	else
+		return false;
+}
+
+/* copies the NUL-terminated C-string 'from' to '*to', leaving '*to'
+ * unchanged if malloc fails, free()ing the original '*to' if it
+ * succeeds and the original '*to' was not NULL
+ */
+static FLAC__bool copy_cstring_(char **to, const char *from)
+{
+	char *copy = strdup(from);
+	if (copy) {
+		free(*to);
+		*to = copy;
+		return true;
+	}
+	else
+		return false;
+}
+
+static FLAC__bool copy_vcentry_(FLAC__StreamMetadata_VorbisComment_Entry *to, const FLAC__StreamMetadata_VorbisComment_Entry *from)
+{
+	to->length = from->length;
+	if (from->entry == 0) {
+		to->entry = 0;
+	}
+	else {
+		FLAC__byte *x;
+		if ((x = safe_malloc_add_2op_(from->length, /*+*/1)) == NULL)
+			return false;
+		memcpy(x, from->entry, from->length);
+		x[from->length] = '\0';
+		to->entry = x;
+	}
+	return true;
+}
+
+static FLAC__bool copy_track_(FLAC__StreamMetadata_CueSheet_Track *to, const FLAC__StreamMetadata_CueSheet_Track *from)
+{
+	memcpy(to, from, sizeof(FLAC__StreamMetadata_CueSheet_Track));
+	if (from->indices == 0) {
+	}
+	else {
+		FLAC__StreamMetadata_CueSheet_Index *x;
+		if ((x = safe_malloc_mul_2op_p(from->num_indices, /*times*/sizeof(FLAC__StreamMetadata_CueSheet_Index))) == NULL)
+			return false;
+		memcpy(x, from->indices, from->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index));
+		to->indices = x;
+	}
+	return true;
+}
+
+static void seektable_calculate_length_(FLAC__StreamMetadata *object)
+{
+	object->length = object->data.seek_table.num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
+}
+
+static FLAC__StreamMetadata_SeekPoint *seekpoint_array_new_(uint32_t num_points)
+{
+	FLAC__StreamMetadata_SeekPoint *object_array;
+
+	object_array = safe_malloc_mul_2op_p(num_points, /*times*/sizeof(FLAC__StreamMetadata_SeekPoint));
+
+	if (object_array != NULL) {
+		uint32_t i;
+		for (i = 0; i < num_points; i++) {
+			object_array[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+			object_array[i].stream_offset = 0;
+			object_array[i].frame_samples = 0;
+		}
+	}
+
+	return object_array;
+}
+
+static void vorbiscomment_calculate_length_(FLAC__StreamMetadata *object)
+{
+	uint32_t i;
+
+	object->length = (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN) / 8;
+	object->length += object->data.vorbis_comment.vendor_string.length;
+	object->length += (FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN) / 8;
+	for (i = 0; i < object->data.vorbis_comment.num_comments; i++) {
+		object->length += (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8);
+		object->length += object->data.vorbis_comment.comments[i].length;
+	}
+}
+
+static FLAC__StreamMetadata_VorbisComment_Entry *vorbiscomment_entry_array_new_(uint32_t num_comments)
+{
+	return safe_calloc_(num_comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry));
+}
+
+static void vorbiscomment_entry_array_delete_(FLAC__StreamMetadata_VorbisComment_Entry *object_array, uint32_t num_comments)
+{
+	uint32_t i;
+
+	for (i = 0; i < num_comments; i++)
+		free(object_array[i].entry);
+
+	free(object_array);
+}
+
+static FLAC__StreamMetadata_VorbisComment_Entry *vorbiscomment_entry_array_copy_(const FLAC__StreamMetadata_VorbisComment_Entry *object_array, uint32_t num_comments)
+{
+	FLAC__StreamMetadata_VorbisComment_Entry *return_array;
+
+	return_array = vorbiscomment_entry_array_new_(num_comments);
+
+	if (return_array != NULL) {
+		uint32_t i;
+
+		for (i = 0; i < num_comments; i++) {
+			if (!copy_vcentry_(return_array+i, object_array+i)) {
+				vorbiscomment_entry_array_delete_(return_array, num_comments);
+				return 0;
+			}
+		}
+	}
+
+	return return_array;
+}
+
+static FLAC__bool vorbiscomment_set_entry_(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry *dest, const FLAC__StreamMetadata_VorbisComment_Entry *src, FLAC__bool copy)
+{
+	FLAC__byte *save;
+
+	save = dest->entry;
+
+	if (src->entry != NULL) {
+		if (copy) {
+			/* do the copy first so that if we fail we leave the dest object untouched */
+			if (!copy_vcentry_(dest, src))
+				return false;
+		}
+		else {
+			/* we have to make sure that the string we're taking over is null-terminated */
+
+			/*
+			 * Stripping the const from src->entry is OK since we're taking
+			 * ownership of the pointer.  This is a hack around a deficiency
+			 * in the API where the same function is used for 'copy' and
+			 * 'own', but the source entry is a const pointer.  If we were
+			 * precise, the 'own' flavor would be a separate function with a
+			 * non-const source pointer.  But it's not, so we hack away.
+			 */
+			if (!ensure_null_terminated_((FLAC__byte**)(&src->entry), src->length))
+				return false;
+			*dest = *src;
+		}
+	}
+	else {
+		/* the src is null */
+		*dest = *src;
+	}
+
+	free(save);
+
+	vorbiscomment_calculate_length_(object);
+	return true;
+}
+
+static int vorbiscomment_find_entry_from_(const FLAC__StreamMetadata *object, uint32_t offset, const char *field_name, uint32_t field_name_length)
+{
+	uint32_t i;
+
+	for (i = offset; i < object->data.vorbis_comment.num_comments; i++) {
+		if (FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length))
+			return (int)i;
+	}
+
+	return -1;
+}
+
+static void cuesheet_calculate_length_(FLAC__StreamMetadata *object)
+{
+	uint32_t i;
+
+	object->length = (
+		FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN
+	) / 8;
+
+	object->length += object->data.cue_sheet.num_tracks * (
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN +
+		FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN
+	) / 8;
+
+	for (i = 0; i < object->data.cue_sheet.num_tracks; i++) {
+		object->length += object->data.cue_sheet.tracks[i].num_indices * (
+			FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN +
+			FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN +
+			FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN
+		) / 8;
+	}
+}
+
+static FLAC__StreamMetadata_CueSheet_Index *cuesheet_track_index_array_new_(uint32_t num_indices)
+{
+	return safe_calloc_(num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index));
+}
+
+static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_new_(uint32_t num_tracks)
+{
+	return safe_calloc_(num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track));
+}
+
+static void cuesheet_track_array_delete_(FLAC__StreamMetadata_CueSheet_Track *object_array, uint32_t num_tracks)
+{
+	uint32_t i;
+
+	for (i = 0; i < num_tracks; i++) {
+		if (object_array[i].indices != 0) {
+			free(object_array[i].indices);
+		}
+	}
+
+	free(object_array);
+}
+
+static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_copy_(const FLAC__StreamMetadata_CueSheet_Track *object_array, uint32_t num_tracks)
+{
+	FLAC__StreamMetadata_CueSheet_Track *return_array;
+
+	return_array = cuesheet_track_array_new_(num_tracks);
+
+	if (return_array != NULL) {
+		uint32_t i;
+
+		for (i = 0; i < num_tracks; i++) {
+			if (!copy_track_(return_array+i, object_array+i)) {
+				cuesheet_track_array_delete_(return_array, num_tracks);
+				return 0;
+			}
+		}
+	}
+
+	return return_array;
+}
+
+static FLAC__bool cuesheet_set_track_(FLAC__StreamMetadata *object, FLAC__StreamMetadata_CueSheet_Track *dest, const FLAC__StreamMetadata_CueSheet_Track *src, FLAC__bool copy)
+{
+	FLAC__StreamMetadata_CueSheet_Index *save;
+
+	save = dest->indices;
+
+	/* do the copy first so that if we fail we leave the object untouched */
+	if (copy) {
+		if (!copy_track_(dest, src))
+			return false;
+	}
+	else {
+		*dest = *src;
+	}
+
+	free(save);
+
+	cuesheet_calculate_length_(object);
+	return true;
+}
+
+
+/****************************************************************************
+ *
+ * Metadata object routines
+ *
+ ***************************************************************************/
+
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_new(FLAC__MetadataType type)
+{
+	FLAC__StreamMetadata *object;
+
+	if (type > FLAC__MAX_METADATA_TYPE)
+		return 0;
+
+	object = calloc(1, sizeof(FLAC__StreamMetadata));
+	if (object != NULL) {
+		object->is_last = false;
+		object->type = type;
+		switch(type) {
+			case FLAC__METADATA_TYPE_STREAMINFO:
+				object->length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
+				break;
+			case FLAC__METADATA_TYPE_PADDING:
+				/* calloc() took care of this for us:
+				object->length = 0;
+				*/
+				break;
+			case FLAC__METADATA_TYPE_APPLICATION:
+				object->length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
+				/* calloc() took care of this for us:
+				object->data.application.data = 0;
+				*/
+				break;
+			case FLAC__METADATA_TYPE_SEEKTABLE:
+				/* calloc() took care of this for us:
+				object->length = 0;
+				object->data.seek_table.num_points = 0;
+				object->data.seek_table.points = 0;
+				*/
+				break;
+			case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+				object->data.vorbis_comment.vendor_string.length = (uint32_t)strlen(FLAC__VENDOR_STRING);
+				if (!copy_bytes_(&object->data.vorbis_comment.vendor_string.entry, (const FLAC__byte*)FLAC__VENDOR_STRING, object->data.vorbis_comment.vendor_string.length+1)) {
+					free(object);
+					return 0;
+				}
+				vorbiscomment_calculate_length_(object);
+				break;
+			case FLAC__METADATA_TYPE_CUESHEET:
+				cuesheet_calculate_length_(object);
+				break;
+			case FLAC__METADATA_TYPE_PICTURE:
+				object->length = (
+					FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
+					FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* empty mime_type string */
+					FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* empty description string */
+					FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN +
+					FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN +
+					FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN +
+					FLAC__STREAM_METADATA_PICTURE_COLORS_LEN +
+					FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN +
+					0 /* no data */
+				) / 8;
+				object->data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER;
+				object->data.picture.mime_type = 0;
+				object->data.picture.description = 0;
+				/* calloc() took care of this for us:
+				object->data.picture.width = 0;
+				object->data.picture.height = 0;
+				object->data.picture.depth = 0;
+				object->data.picture.colors = 0;
+				object->data.picture.data_length = 0;
+				object->data.picture.data = 0;
+				*/
+				/* now initialize mime_type and description with empty strings to make things easier on the client */
+				if (!copy_cstring_(&object->data.picture.mime_type, "")) {
+					free(object);
+					return 0;
+				}
+				if (!copy_cstring_((char**)(&object->data.picture.description), "")) {
+					free(object->data.picture.mime_type);
+					free(object);
+					return 0;
+				}
+				break;
+			default:
+				/* calloc() took care of this for us:
+				object->length = 0;
+				object->data.unknown.data = 0;
+				*/
+				break;
+		}
+	}
+
+	return object;
+}
+
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_clone(const FLAC__StreamMetadata *object)
+{
+	FLAC__StreamMetadata *to;
+
+	if ((to = FLAC__metadata_object_new(object->type)) != NULL) {
+		to->is_last = object->is_last;
+		to->type = object->type;
+		to->length = object->length;
+		switch(to->type) {
+			case FLAC__METADATA_TYPE_STREAMINFO:
+				memcpy(&to->data.stream_info, &object->data.stream_info, sizeof(FLAC__StreamMetadata_StreamInfo));
+				break;
+			case FLAC__METADATA_TYPE_PADDING:
+				break;
+			case FLAC__METADATA_TYPE_APPLICATION:
+				if (to->length < FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8) { /* underflow check */
+					FLAC__metadata_object_delete(to);
+					return 0;
+				}
+				memcpy(&to->data.application.id, &object->data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8);
+				if (!copy_bytes_(&to->data.application.data, object->data.application.data, object->length - FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8)) {
+					FLAC__metadata_object_delete(to);
+					return 0;
+				}
+				break;
+			case FLAC__METADATA_TYPE_SEEKTABLE:
+				to->data.seek_table.num_points = object->data.seek_table.num_points;
+				if (to->data.seek_table.num_points > UINT32_MAX / sizeof(FLAC__StreamMetadata_SeekPoint)) { /* overflow check */
+					FLAC__metadata_object_delete(to);
+					return 0;
+				}
+				if (!copy_bytes_((FLAC__byte**)&to->data.seek_table.points, (FLAC__byte*)object->data.seek_table.points, object->data.seek_table.num_points * sizeof(FLAC__StreamMetadata_SeekPoint))) {
+					FLAC__metadata_object_delete(to);
+					return 0;
+				}
+				break;
+			case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+				if (to->data.vorbis_comment.vendor_string.entry != NULL) {
+					free(to->data.vorbis_comment.vendor_string.entry);
+					to->data.vorbis_comment.vendor_string.entry = 0;
+				}
+				if (!copy_vcentry_(&to->data.vorbis_comment.vendor_string, &object->data.vorbis_comment.vendor_string)) {
+					FLAC__metadata_object_delete(to);
+					return 0;
+				}
+				if (object->data.vorbis_comment.num_comments == 0) {
+					to->data.vorbis_comment.comments = 0;
+				}
+				else {
+					to->data.vorbis_comment.comments = vorbiscomment_entry_array_copy_(object->data.vorbis_comment.comments, object->data.vorbis_comment.num_comments);
+					if (to->data.vorbis_comment.comments == NULL) {
+						to->data.vorbis_comment.num_comments = 0;
+						FLAC__metadata_object_delete(to);
+						return 0;
+					}
+				}
+				to->data.vorbis_comment.num_comments = object->data.vorbis_comment.num_comments;
+				break;
+			case FLAC__METADATA_TYPE_CUESHEET:
+				memcpy(&to->data.cue_sheet, &object->data.cue_sheet, sizeof(FLAC__StreamMetadata_CueSheet));
+				if (object->data.cue_sheet.num_tracks == 0) {
+				}
+				else {
+					to->data.cue_sheet.tracks = cuesheet_track_array_copy_(object->data.cue_sheet.tracks, object->data.cue_sheet.num_tracks);
+					if (to->data.cue_sheet.tracks == NULL) {
+						FLAC__metadata_object_delete(to);
+						return 0;
+					}
+				}
+				break;
+			case FLAC__METADATA_TYPE_PICTURE:
+				to->data.picture.type = object->data.picture.type;
+				if (!copy_cstring_(&to->data.picture.mime_type, object->data.picture.mime_type)) {
+					FLAC__metadata_object_delete(to);
+					return 0;
+				}
+				if (!copy_cstring_((char**)(&to->data.picture.description), (const char*)object->data.picture.description)) {
+					FLAC__metadata_object_delete(to);
+					return 0;
+				}
+				to->data.picture.width = object->data.picture.width;
+				to->data.picture.height = object->data.picture.height;
+				to->data.picture.depth = object->data.picture.depth;
+				to->data.picture.colors = object->data.picture.colors;
+				to->data.picture.data_length = object->data.picture.data_length;
+				if (!copy_bytes_((&to->data.picture.data), object->data.picture.data, object->data.picture.data_length)) {
+					FLAC__metadata_object_delete(to);
+					return 0;
+				}
+				break;
+			default:
+				if (!copy_bytes_(&to->data.unknown.data, object->data.unknown.data, object->length)) {
+					FLAC__metadata_object_delete(to);
+					return 0;
+				}
+				break;
+		}
+	}
+
+	return to;
+}
+
+void FLAC__metadata_object_delete_data(FLAC__StreamMetadata *object)
+{
+	switch(object->type) {
+		case FLAC__METADATA_TYPE_STREAMINFO:
+		case FLAC__METADATA_TYPE_PADDING:
+			break;
+		case FLAC__METADATA_TYPE_APPLICATION:
+			if (object->data.application.data != NULL) {
+				free(object->data.application.data);
+				object->data.application.data = NULL;
+			}
+			break;
+		case FLAC__METADATA_TYPE_SEEKTABLE:
+			if (object->data.seek_table.points != NULL) {
+				free(object->data.seek_table.points);
+				object->data.seek_table.points = NULL;
+			}
+			break;
+		case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+			if (object->data.vorbis_comment.vendor_string.entry != NULL) {
+				free(object->data.vorbis_comment.vendor_string.entry);
+				object->data.vorbis_comment.vendor_string.entry = 0;
+			}
+			if (object->data.vorbis_comment.comments != NULL) {
+				vorbiscomment_entry_array_delete_(object->data.vorbis_comment.comments, object->data.vorbis_comment.num_comments);
+				object->data.vorbis_comment.comments = NULL;
+				object->data.vorbis_comment.num_comments = 0;
+			}
+			break;
+		case FLAC__METADATA_TYPE_CUESHEET:
+			if (object->data.cue_sheet.tracks != NULL) {
+				cuesheet_track_array_delete_(object->data.cue_sheet.tracks, object->data.cue_sheet.num_tracks);
+				object->data.cue_sheet.tracks = NULL;
+				object->data.cue_sheet.num_tracks = 0;
+			}
+			break;
+		case FLAC__METADATA_TYPE_PICTURE:
+			if (object->data.picture.mime_type != NULL) {
+				free(object->data.picture.mime_type);
+				object->data.picture.mime_type = NULL;
+			}
+			if (object->data.picture.description != NULL) {
+				free(object->data.picture.description);
+				object->data.picture.description = NULL;
+			}
+			if (object->data.picture.data != NULL) {
+				free(object->data.picture.data);
+				object->data.picture.data = NULL;
+			}
+			break;
+		default:
+			if (object->data.unknown.data != NULL) {
+				free(object->data.unknown.data);
+				object->data.unknown.data = NULL;
+			}
+			break;
+	}
+}
+
+FLAC_API void FLAC__metadata_object_delete(FLAC__StreamMetadata *object)
+{
+	FLAC__metadata_object_delete_data(object);
+	free(object);
+}
+
+static FLAC__bool compare_block_data_streaminfo_(const FLAC__StreamMetadata_StreamInfo *block1, const FLAC__StreamMetadata_StreamInfo *block2)
+{
+	if (block1->min_blocksize != block2->min_blocksize)
+		return false;
+	if (block1->max_blocksize != block2->max_blocksize)
+		return false;
+	if (block1->min_framesize != block2->min_framesize)
+		return false;
+	if (block1->max_framesize != block2->max_framesize)
+		return false;
+	if (block1->sample_rate != block2->sample_rate)
+		return false;
+	if (block1->channels != block2->channels)
+		return false;
+	if (block1->bits_per_sample != block2->bits_per_sample)
+		return false;
+	if (block1->total_samples != block2->total_samples)
+		return false;
+	if (memcmp(block1->md5sum, block2->md5sum, 16) != 0)
+		return false;
+	return true;
+}
+
+static FLAC__bool compare_block_data_application_(const FLAC__StreamMetadata_Application *block1, const FLAC__StreamMetadata_Application *block2, uint32_t block_length)
+{
+	if (memcmp(block1->id, block2->id, sizeof(block1->id)) != 0)
+		return false;
+	if (block1->data != NULL && block2->data != NULL)
+		return memcmp(block1->data, block2->data, block_length - sizeof(block1->id)) == 0;
+	else
+		return block1->data == block2->data;
+}
+
+static FLAC__bool compare_block_data_seektable_(const FLAC__StreamMetadata_SeekTable *block1, const FLAC__StreamMetadata_SeekTable *block2)
+{
+	uint32_t i;
+
+	if (block1->num_points != block2->num_points)
+		return false;
+
+	if (block1->points != NULL && block2->points != NULL) {
+		for (i = 0; i < block1->num_points; i++) {
+			if (block1->points[i].sample_number != block2->points[i].sample_number)
+				return false;
+			if (block1->points[i].stream_offset != block2->points[i].stream_offset)
+				return false;
+			if (block1->points[i].frame_samples != block2->points[i].frame_samples)
+				return false;
+		}
+		return true;
+	}
+	else
+		return block1->points == block2->points;
+}
+
+static FLAC__bool compare_block_data_vorbiscomment_(const FLAC__StreamMetadata_VorbisComment *block1, const FLAC__StreamMetadata_VorbisComment *block2)
+{
+	uint32_t i;
+
+	if (block1->vendor_string.length != block2->vendor_string.length)
+		return false;
+
+	if (block1->vendor_string.entry != NULL && block2->vendor_string.entry != NULL) {
+		if (memcmp(block1->vendor_string.entry, block2->vendor_string.entry, block1->vendor_string.length) != 0)
+			return false;
+	}
+	else if (block1->vendor_string.entry != block2->vendor_string.entry)
+		return false;
+
+	if (block1->num_comments != block2->num_comments)
+		return false;
+
+	for (i = 0; i < block1->num_comments; i++) {
+		if (block1->comments[i].entry != NULL && block2->comments[i].entry != NULL) {
+			if (memcmp(block1->comments[i].entry, block2->comments[i].entry, block1->comments[i].length) != 0)
+				return false;
+		}
+		else if (block1->comments[i].entry != block2->comments[i].entry)
+			return false;
+	}
+	return true;
+}
+
+static FLAC__bool compare_block_data_cuesheet_(const FLAC__StreamMetadata_CueSheet *block1, const FLAC__StreamMetadata_CueSheet *block2)
+{
+	uint32_t i, j;
+
+	if (strcmp(block1->media_catalog_number, block2->media_catalog_number) != 0)
+		return false;
+
+	if (block1->lead_in != block2->lead_in)
+		return false;
+
+	if (block1->is_cd != block2->is_cd)
+		return false;
+
+	if (block1->num_tracks != block2->num_tracks)
+		return false;
+
+	if (block1->tracks != NULL && block2->tracks != NULL) {
+		for (i = 0; i < block1->num_tracks; i++) {
+			if (block1->tracks[i].offset != block2->tracks[i].offset)
+				return false;
+			if (block1->tracks[i].number != block2->tracks[i].number)
+				return false;
+			if (memcmp(block1->tracks[i].isrc, block2->tracks[i].isrc, sizeof(block1->tracks[i].isrc)) != 0)
+				return false;
+			if (block1->tracks[i].type != block2->tracks[i].type)
+				return false;
+			if (block1->tracks[i].pre_emphasis != block2->tracks[i].pre_emphasis)
+				return false;
+			if (block1->tracks[i].num_indices != block2->tracks[i].num_indices)
+				return false;
+			if (block1->tracks[i].indices != NULL && block2->tracks[i].indices != NULL) {
+				for (j = 0; j < block1->tracks[i].num_indices; j++) {
+					if (block1->tracks[i].indices[j].offset != block2->tracks[i].indices[j].offset)
+						return false;
+					if (block1->tracks[i].indices[j].number != block2->tracks[i].indices[j].number)
+						return false;
+				}
+			}
+			else if (block1->tracks[i].indices != block2->tracks[i].indices)
+				return false;
+		}
+	}
+	else if (block1->tracks != block2->tracks)
+		return false;
+	return true;
+}
+
+static FLAC__bool compare_block_data_picture_(const FLAC__StreamMetadata_Picture *block1, const FLAC__StreamMetadata_Picture *block2)
+{
+	if (block1->type != block2->type)
+		return false;
+	if (block1->mime_type != block2->mime_type && (block1->mime_type == 0 || block2->mime_type == 0 || strcmp(block1->mime_type, block2->mime_type)))
+		return false;
+	if (block1->description != block2->description && (block1->description == 0 || block2->description == 0 || strcmp((const char *)block1->description, (const char *)block2->description)))
+		return false;
+	if (block1->width != block2->width)
+		return false;
+	if (block1->height != block2->height)
+		return false;
+	if (block1->depth != block2->depth)
+		return false;
+	if (block1->colors != block2->colors)
+		return false;
+	if (block1->data_length != block2->data_length)
+		return false;
+	if (block1->data != block2->data && (block1->data == NULL || block2->data == NULL || memcmp(block1->data, block2->data, block1->data_length)))
+		return false;
+	return true;
+}
+
+static FLAC__bool compare_block_data_unknown_(const FLAC__StreamMetadata_Unknown *block1, const FLAC__StreamMetadata_Unknown *block2, uint32_t block_length)
+{
+	if (block1->data != NULL && block2->data != NULL)
+		return memcmp(block1->data, block2->data, block_length) == 0;
+	else
+		return block1->data == block2->data;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_is_equal(const FLAC__StreamMetadata *block1, const FLAC__StreamMetadata *block2)
+{
+	if (block1->type != block2->type) {
+		return false;
+	}
+	if (block1->is_last != block2->is_last) {
+		return false;
+	}
+	if (block1->length != block2->length) {
+		return false;
+	}
+	switch(block1->type) {
+		case FLAC__METADATA_TYPE_STREAMINFO:
+			return compare_block_data_streaminfo_(&block1->data.stream_info, &block2->data.stream_info);
+		case FLAC__METADATA_TYPE_PADDING:
+			return true; /* we don't compare the padding guts */
+		case FLAC__METADATA_TYPE_APPLICATION:
+			return compare_block_data_application_(&block1->data.application, &block2->data.application, block1->length);
+		case FLAC__METADATA_TYPE_SEEKTABLE:
+			return compare_block_data_seektable_(&block1->data.seek_table, &block2->data.seek_table);
+		case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+			return compare_block_data_vorbiscomment_(&block1->data.vorbis_comment, &block2->data.vorbis_comment);
+		case FLAC__METADATA_TYPE_CUESHEET:
+			return compare_block_data_cuesheet_(&block1->data.cue_sheet, &block2->data.cue_sheet);
+		case FLAC__METADATA_TYPE_PICTURE:
+			return compare_block_data_picture_(&block1->data.picture, &block2->data.picture);
+		default:
+			return compare_block_data_unknown_(&block1->data.unknown, &block2->data.unknown, block1->length);
+	}
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_application_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, uint32_t length, FLAC__bool copy)
+{
+	FLAC__byte *save;
+
+	save = object->data.application.data;
+
+	/* do the copy first so that if we fail we leave the object untouched */
+	if (copy) {
+		if (!copy_bytes_(&object->data.application.data, data, length))
+			return false;
+	}
+	else {
+		object->data.application.data = data;
+	}
+
+	free(save);
+
+	object->length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8 + length;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_resize_points(FLAC__StreamMetadata *object, uint32_t new_num_points)
+{
+	if (object->data.seek_table.points == 0) {
+		if (new_num_points == 0)
+			return true;
+		else if ((object->data.seek_table.points = seekpoint_array_new_(new_num_points)) == 0)
+			return false;
+	}
+	else {
+		const size_t old_size = object->data.seek_table.num_points * sizeof(FLAC__StreamMetadata_SeekPoint);
+		const size_t new_size = new_num_points * sizeof(FLAC__StreamMetadata_SeekPoint);
+
+		/* overflow check */
+		if (new_num_points > UINT32_MAX / sizeof(FLAC__StreamMetadata_SeekPoint))
+			return false;
+
+		if (new_size == 0) {
+			free(object->data.seek_table.points);
+			object->data.seek_table.points = 0;
+		}
+		else if ((object->data.seek_table.points = safe_realloc_(object->data.seek_table.points, new_size)) == NULL)
+			return false;
+
+		/* if growing, set new elements to placeholders */
+		if (new_size > old_size) {
+			uint32_t i;
+			for (i = object->data.seek_table.num_points; i < new_num_points; i++) {
+				object->data.seek_table.points[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+				object->data.seek_table.points[i].stream_offset = 0;
+				object->data.seek_table.points[i].frame_samples = 0;
+			}
+		}
+	}
+
+	object->data.seek_table.num_points = new_num_points;
+
+	seektable_calculate_length_(object);
+	return true;
+}
+
+FLAC_API void FLAC__metadata_object_seektable_set_point(FLAC__StreamMetadata *object, uint32_t point_num, FLAC__StreamMetadata_SeekPoint point)
+{
+	object->data.seek_table.points[point_num] = point;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_insert_point(FLAC__StreamMetadata *object, uint32_t point_num, FLAC__StreamMetadata_SeekPoint point)
+{
+	int i;
+
+	if (!FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points+1))
+		return false;
+
+	/* move all points >= point_num forward one space */
+	for (i = (int)object->data.seek_table.num_points-1; i > (int)point_num; i--)
+		object->data.seek_table.points[i] = object->data.seek_table.points[i-1];
+
+	FLAC__metadata_object_seektable_set_point(object, point_num, point);
+	seektable_calculate_length_(object);
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_delete_point(FLAC__StreamMetadata *object, uint32_t point_num)
+{
+	uint32_t i;
+
+	/* move all points > point_num backward one space */
+	for (i = point_num; i < object->data.seek_table.num_points-1; i++)
+		object->data.seek_table.points[i] = object->data.seek_table.points[i+1];
+
+	return FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points-1);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_is_legal(const FLAC__StreamMetadata *object)
+{
+	return FLAC__format_seektable_is_legal(&object->data.seek_table);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_placeholders(FLAC__StreamMetadata *object, uint32_t num)
+{
+	if (num > 0)
+		/* WATCHOUT: we rely on the fact that growing the array adds PLACEHOLDERS at the end */
+		return FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points + num);
+	else
+		return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_point(FLAC__StreamMetadata *object, FLAC__uint64 sample_number)
+{
+	FLAC__StreamMetadata_SeekTable *seek_table;
+
+	seek_table = &object->data.seek_table;
+
+	if (!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + 1))
+		return false;
+
+	seek_table->points[seek_table->num_points - 1].sample_number = sample_number;
+	seek_table->points[seek_table->num_points - 1].stream_offset = 0;
+	seek_table->points[seek_table->num_points - 1].frame_samples = 0;
+
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_points(FLAC__StreamMetadata *object, FLAC__uint64 sample_numbers[], uint32_t num)
+{
+	if (num > 0) {
+		FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table;
+		uint32_t i, j;
+
+		i = seek_table->num_points;
+
+		if (!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + num))
+			return false;
+
+		for (j = 0; j < num; i++, j++) {
+			seek_table->points[i].sample_number = sample_numbers[j];
+			seek_table->points[i].stream_offset = 0;
+			seek_table->points[i].frame_samples = 0;
+		}
+	}
+
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points(FLAC__StreamMetadata *object, uint32_t num, FLAC__uint64 total_samples)
+{
+	if (num > 0 && total_samples > 0) {
+		FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table;
+		uint32_t i, j;
+
+		i = seek_table->num_points;
+
+		if (!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + num))
+			return false;
+
+		for (j = 0; j < num; i++, j++) {
+			seek_table->points[i].sample_number = total_samples * (FLAC__uint64)j / (FLAC__uint64)num;
+			seek_table->points[i].stream_offset = 0;
+			seek_table->points[i].frame_samples = 0;
+		}
+	}
+
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(FLAC__StreamMetadata *object, uint32_t samples, FLAC__uint64 total_samples)
+{
+	if (samples > 0 && total_samples > 0) {
+		FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table;
+		uint32_t i, j;
+		FLAC__uint64 num, sample;
+
+		num = 1 + total_samples / samples; /* 1+ for the first sample at 0 */
+		/* now account for the fact that we don't place a seekpoint at "total_samples" since samples are number from 0: */
+		if (total_samples % samples == 0)
+			num--;
+
+		/* Put a strict upper bound on the number of allowed seek points. */
+		if (num > 32768) {
+			/* Set the bound and recalculate samples accordingly. */
+			num = 32768;
+			samples = (uint32_t)(total_samples / num);
+		}
+
+		i = seek_table->num_points;
+
+		if (!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + (uint32_t)num))
+			return false;
+
+		sample = 0;
+		for (j = 0; j < num; i++, j++, sample += samples) {
+			seek_table->points[i].sample_number = sample;
+			seek_table->points[i].stream_offset = 0;
+			seek_table->points[i].frame_samples = 0;
+		}
+	}
+
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_sort(FLAC__StreamMetadata *object, FLAC__bool compact)
+{
+	uint32_t unique;
+
+	unique = FLAC__format_seektable_sort(&object->data.seek_table);
+
+	return !compact || FLAC__metadata_object_seektable_resize_points(object, unique);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_vendor_string(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
+{
+	if (!FLAC__format_vorbiscomment_entry_value_is_legal(entry.entry, entry.length))
+		return false;
+	return vorbiscomment_set_entry_(object, &object->data.vorbis_comment.vendor_string, &entry, copy);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_resize_comments(FLAC__StreamMetadata *object, uint32_t new_num_comments)
+{
+	if (object->data.vorbis_comment.comments == NULL) {
+		if (new_num_comments == 0)
+			return true;
+		else if ((object->data.vorbis_comment.comments = vorbiscomment_entry_array_new_(new_num_comments)) == NULL)
+			return false;
+	}
+	else {
+		const size_t old_size = object->data.vorbis_comment.num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry);
+		const size_t new_size = new_num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry);
+
+		/* overflow check */
+		if (new_num_comments > UINT32_MAX / sizeof(FLAC__StreamMetadata_VorbisComment_Entry))
+			return false;
+
+		/* if shrinking, free the truncated entries */
+		if (new_num_comments < object->data.vorbis_comment.num_comments) {
+			uint32_t i;
+			for (i = new_num_comments; i < object->data.vorbis_comment.num_comments; i++)
+				if (object->data.vorbis_comment.comments[i].entry != NULL)
+					free(object->data.vorbis_comment.comments[i].entry);
+		}
+
+		if (new_size == 0) {
+			free(object->data.vorbis_comment.comments);
+			object->data.vorbis_comment.comments = 0;
+		}
+		else {
+			FLAC__StreamMetadata_VorbisComment_Entry *oldptr = object->data.vorbis_comment.comments;
+			if ((object->data.vorbis_comment.comments = realloc(object->data.vorbis_comment.comments, new_size)) == NULL) {
+				vorbiscomment_entry_array_delete_(oldptr, object->data.vorbis_comment.num_comments);
+				object->data.vorbis_comment.num_comments = 0;
+				return false;
+			}
+		}
+
+		/* if growing, zero all the length/pointers of new elements */
+		if (new_size > old_size)
+			memset(object->data.vorbis_comment.comments + object->data.vorbis_comment.num_comments, 0, new_size - old_size);
+	}
+
+	object->data.vorbis_comment.num_comments = new_num_comments;
+
+	vorbiscomment_calculate_length_(object);
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_comment(FLAC__StreamMetadata *object, uint32_t comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
+{
+	if (!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length))
+		return false;
+	return vorbiscomment_set_entry_(object, &object->data.vorbis_comment.comments[comment_num], &entry, copy);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_insert_comment(FLAC__StreamMetadata *object, uint32_t comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
+{
+	FLAC__StreamMetadata_VorbisComment *vc;
+
+	if (!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length))
+		return false;
+
+	vc = &object->data.vorbis_comment;
+
+	if (!FLAC__metadata_object_vorbiscomment_resize_comments(object, vc->num_comments+1))
+		return false;
+
+	/* move all comments >= comment_num forward one space */
+	memmove(&vc->comments[comment_num+1], &vc->comments[comment_num], sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(vc->num_comments-1-comment_num));
+	vc->comments[comment_num].length = 0;
+	vc->comments[comment_num].entry = 0;
+
+	return FLAC__metadata_object_vorbiscomment_set_comment(object, comment_num, entry, copy);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_append_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
+{
+	return FLAC__metadata_object_vorbiscomment_insert_comment(object, object->data.vorbis_comment.num_comments, entry, copy);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_replace_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool all, FLAC__bool copy)
+{
+	if (!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length))
+		return false;
+
+	{
+		int i;
+		size_t field_name_length;
+		const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length);
+
+		if (eq == NULL)
+			return false; /* double protection */
+
+		field_name_length = eq-entry.entry;
+
+		i = vorbiscomment_find_entry_from_(object, 0, (const char *)entry.entry, (uint32_t)field_name_length);
+		if (i >= 0) {
+			uint32_t indx = (uint32_t)i;
+			if (!FLAC__metadata_object_vorbiscomment_set_comment(object, indx, entry, copy))
+				return false;
+			entry = object->data.vorbis_comment.comments[indx];
+			indx++; /* skip over replaced comment */
+			if (all && indx < object->data.vorbis_comment.num_comments) {
+				i = vorbiscomment_find_entry_from_(object, indx, (const char *)entry.entry, (uint32_t)field_name_length);
+				while (i >= 0) {
+					indx = (uint32_t)i;
+					if (!FLAC__metadata_object_vorbiscomment_delete_comment(object, indx))
+						return false;
+					if (indx < object->data.vorbis_comment.num_comments)
+						i = vorbiscomment_find_entry_from_(object, indx, (const char *)entry.entry, (uint32_t)field_name_length);
+					else
+						i = -1;
+				}
+			}
+			return true;
+		}
+		else
+			return FLAC__metadata_object_vorbiscomment_append_comment(object, entry, copy);
+	}
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_delete_comment(FLAC__StreamMetadata *object, uint32_t comment_num)
+{
+	FLAC__StreamMetadata_VorbisComment *vc;
+
+	vc = &object->data.vorbis_comment;
+
+	/* free the comment at comment_num */
+	free(vc->comments[comment_num].entry);
+
+	/* move all comments > comment_num backward one space */
+	memmove(&vc->comments[comment_num], &vc->comments[comment_num+1], sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(vc->num_comments-comment_num-1));
+	vc->comments[vc->num_comments-1].length = 0;
+	vc->comments[vc->num_comments-1].entry = 0;
+
+	return FLAC__metadata_object_vorbiscomment_resize_comments(object, vc->num_comments-1);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *field_name, const char *field_value)
+{
+	if (!FLAC__format_vorbiscomment_entry_name_is_legal(field_name))
+		return false;
+	if (!FLAC__format_vorbiscomment_entry_value_is_legal((const FLAC__byte *)field_value, (uint32_t)(-1)))
+		return false;
+
+	{
+		const size_t nn = strlen(field_name);
+		const size_t nv = strlen(field_value);
+		entry->length = (FLAC__uint32)(nn + 1 /*=*/ + nv);
+		if ((entry->entry = safe_malloc_add_4op_(nn, /*+*/1, /*+*/nv, /*+*/1)) == NULL)
+			return false;
+		memcpy(entry->entry, field_name, nn);
+		entry->entry[nn] = '=';
+		memcpy(entry->entry+nn+1, field_value, nv);
+		entry->entry[entry->length] = '\0';
+	}
+
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(const FLAC__StreamMetadata_VorbisComment_Entry entry, char **field_name, char **field_value)
+{
+	if (!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length))
+		return false;
+
+	{
+		const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length);
+		const size_t nn = eq-entry.entry;
+		const size_t nv = entry.length-nn-1; /* -1 for the '=' */
+
+		if (eq == NULL)
+			return false; /* double protection */
+		if ((*field_name = safe_malloc_add_2op_(nn, /*+*/1)) == NULL)
+			return false;
+		if ((*field_value = safe_malloc_add_2op_(nv, /*+*/1)) == NULL) {
+			free(*field_name);
+			return false;
+		}
+		memcpy(*field_name, entry.entry, nn);
+		memcpy(*field_value, entry.entry+nn+1, nv);
+		(*field_name)[nn] = '\0';
+		(*field_value)[nv] = '\0';
+	}
+
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(const FLAC__StreamMetadata_VorbisComment_Entry entry, const char *field_name, uint32_t field_name_length)
+{
+	const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length);
+	return (eq != NULL && (uint32_t)(eq-entry.entry) == field_name_length && FLAC__STRNCASECMP(field_name, (const char *)entry.entry, field_name_length) == 0);
+}
+
+FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__StreamMetadata *object, uint32_t offset, const char *field_name)
+{
+	return vorbiscomment_find_entry_from_(object, offset, field_name, (uint32_t)strlen(field_name));
+}
+
+FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entry_matching(FLAC__StreamMetadata *object, const char *field_name)
+{
+	const uint32_t field_name_length = (const uint32_t)strlen(field_name);
+	uint32_t i;
+
+	for (i = 0; i < object->data.vorbis_comment.num_comments; i++) {
+		if (FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length)) {
+			if (!FLAC__metadata_object_vorbiscomment_delete_comment(object, i))
+				return -1;
+			else
+				return 1;
+		}
+	}
+
+	return 0;
+}
+
+FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entries_matching(FLAC__StreamMetadata *object, const char *field_name)
+{
+	FLAC__bool ok = true;
+	uint32_t matching = 0;
+	const uint32_t field_name_length = (const uint32_t)strlen(field_name);
+	int i;
+
+	/* must delete from end to start otherwise it will interfere with our iteration */
+	for (i = (int)object->data.vorbis_comment.num_comments - 1; ok && i >= 0; i--) {
+		if (FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length)) {
+			matching++;
+			ok &= FLAC__metadata_object_vorbiscomment_delete_comment(object, (uint32_t)i);
+		}
+	}
+
+	return ok? (int)matching : -1;
+}
+
+FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_new(void)
+{
+	return calloc(1, sizeof(FLAC__StreamMetadata_CueSheet_Track));
+}
+
+FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_clone(const FLAC__StreamMetadata_CueSheet_Track *object)
+{
+	FLAC__StreamMetadata_CueSheet_Track *to;
+
+	if ((to = FLAC__metadata_object_cuesheet_track_new()) != NULL) {
+		if (!copy_track_(to, object)) {
+			FLAC__metadata_object_cuesheet_track_delete(to);
+			return 0;
+		}
+	}
+
+	return to;
+}
+
+void FLAC__metadata_object_cuesheet_track_delete_data(FLAC__StreamMetadata_CueSheet_Track *object)
+{
+	if (object->indices != NULL) {
+		free(object->indices);
+	}
+}
+
+FLAC_API void FLAC__metadata_object_cuesheet_track_delete(FLAC__StreamMetadata_CueSheet_Track *object)
+{
+	FLAC__metadata_object_cuesheet_track_delete_data(object);
+	free(object);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t new_num_indices)
+{
+	FLAC__StreamMetadata_CueSheet_Track *track;
+
+	track = &object->data.cue_sheet.tracks[track_num];
+
+	if (track->indices == NULL) {
+		if (new_num_indices == 0)
+			return true;
+		else if ((track->indices = cuesheet_track_index_array_new_(new_num_indices)) == NULL)
+			return false;
+	}
+	else {
+		const size_t old_size = track->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index);
+		const size_t new_size = new_num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index);
+
+		/* overflow check */
+		if (new_num_indices > UINT32_MAX / sizeof(FLAC__StreamMetadata_CueSheet_Index))
+			return false;
+
+		if (new_size == 0) {
+			free(track->indices);
+			track->indices = 0;
+		}
+		else if ((track->indices = safe_realloc_(track->indices, new_size)) == NULL)
+			return false;
+
+		/* if growing, zero all the lengths/pointers of new elements */
+		if (new_size > old_size)
+			memset(track->indices + track->num_indices, 0, new_size - old_size);
+	}
+
+	track->num_indices = (FLAC__byte)new_num_indices;
+
+	cuesheet_calculate_length_(object);
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num, FLAC__StreamMetadata_CueSheet_Index indx)
+{
+	FLAC__StreamMetadata_CueSheet_Track *track;
+
+	track = &object->data.cue_sheet.tracks[track_num];
+
+	if (!FLAC__metadata_object_cuesheet_track_resize_indices(object, track_num, track->num_indices+1))
+		return false;
+
+	/* move all indices >= index_num forward one space */
+	memmove(&track->indices[index_num+1], &track->indices[index_num], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(track->num_indices-1-index_num));
+
+	track->indices[index_num] = indx;
+	cuesheet_calculate_length_(object);
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_blank_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num)
+{
+	FLAC__StreamMetadata_CueSheet_Index indx;
+	memset(&indx, 0, sizeof(indx));
+	return FLAC__metadata_object_cuesheet_track_insert_index(object, track_num, index_num, indx);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_delete_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num)
+{
+	FLAC__StreamMetadata_CueSheet_Track *track;
+
+	track = &object->data.cue_sheet.tracks[track_num];
+
+	/* move all indices > index_num backward one space */
+	memmove(&track->indices[index_num], &track->indices[index_num+1], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(track->num_indices-index_num-1));
+
+	FLAC__metadata_object_cuesheet_track_resize_indices(object, track_num, track->num_indices-1);
+	cuesheet_calculate_length_(object);
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMetadata *object, uint32_t new_num_tracks)
+{
+	if (object->data.cue_sheet.tracks == NULL) {
+		if (new_num_tracks == 0)
+			return true;
+		else if ((object->data.cue_sheet.tracks = cuesheet_track_array_new_(new_num_tracks)) == NULL)
+			return false;
+	}
+	else {
+		const size_t old_size = object->data.cue_sheet.num_tracks * sizeof(FLAC__StreamMetadata_CueSheet_Track);
+		const size_t new_size = new_num_tracks * sizeof(FLAC__StreamMetadata_CueSheet_Track);
+
+		/* overflow check */
+		if (new_num_tracks > UINT32_MAX / sizeof(FLAC__StreamMetadata_CueSheet_Track))
+			return false;
+
+		/* if shrinking, free the truncated entries */
+		if (new_num_tracks < object->data.cue_sheet.num_tracks) {
+			uint32_t i;
+			for (i = new_num_tracks; i < object->data.cue_sheet.num_tracks; i++)
+				free(object->data.cue_sheet.tracks[i].indices);
+		}
+
+		if (new_size == 0) {
+			free(object->data.cue_sheet.tracks);
+			object->data.cue_sheet.tracks = 0;
+		}
+		else if ((object->data.cue_sheet.tracks = safe_realloc_(object->data.cue_sheet.tracks, new_size)) == NULL)
+			return false;
+
+		/* if growing, zero all the lengths/pointers of new elements */
+		if (new_size > old_size)
+			memset(object->data.cue_sheet.tracks + object->data.cue_sheet.num_tracks, 0, new_size - old_size);
+	}
+
+	object->data.cue_sheet.num_tracks = new_num_tracks;
+
+	cuesheet_calculate_length_(object);
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_set_track(FLAC__StreamMetadata *object, uint32_t track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy)
+{
+	return cuesheet_set_track_(object, object->data.cue_sheet.tracks + track_num, track, copy);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_track(FLAC__StreamMetadata *object, uint32_t track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy)
+{
+	FLAC__StreamMetadata_CueSheet *cs;
+
+	cs = &object->data.cue_sheet;
+
+	if (!FLAC__metadata_object_cuesheet_resize_tracks(object, cs->num_tracks+1))
+		return false;
+
+	/* move all tracks >= track_num forward one space */
+	memmove(&cs->tracks[track_num+1], &cs->tracks[track_num], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(cs->num_tracks-1-track_num));
+	cs->tracks[track_num].num_indices = 0;
+	cs->tracks[track_num].indices = 0;
+
+	return FLAC__metadata_object_cuesheet_set_track(object, track_num, track, copy);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_blank_track(FLAC__StreamMetadata *object, uint32_t track_num)
+{
+	FLAC__StreamMetadata_CueSheet_Track track;
+	memset(&track, 0, sizeof(track));
+	return FLAC__metadata_object_cuesheet_insert_track(object, track_num, &track, /*copy=*/false);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_delete_track(FLAC__StreamMetadata *object, uint32_t track_num)
+{
+	FLAC__StreamMetadata_CueSheet *cs;
+
+	cs = &object->data.cue_sheet;
+
+	/* free the track at track_num */
+	free(cs->tracks[track_num].indices);
+
+	/* move all tracks > track_num backward one space */
+	memmove(&cs->tracks[track_num], &cs->tracks[track_num+1], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(cs->num_tracks-track_num-1));
+	cs->tracks[cs->num_tracks-1].num_indices = 0;
+	cs->tracks[cs->num_tracks-1].indices = 0;
+
+	return FLAC__metadata_object_cuesheet_resize_tracks(object, cs->num_tracks-1);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_is_legal(const FLAC__StreamMetadata *object, FLAC__bool check_cd_da_subset, const char **violation)
+{
+	return FLAC__format_cuesheet_is_legal(&object->data.cue_sheet, check_cd_da_subset, violation);
+}
+
+static FLAC__uint64 get_index_01_offset_(const FLAC__StreamMetadata_CueSheet *cs, uint32_t track)
+{
+	if (track >= (cs->num_tracks-1) || cs->tracks[track].num_indices < 1)
+		return 0;
+	else if (cs->tracks[track].indices[0].number == 1)
+		return cs->tracks[track].indices[0].offset + cs->tracks[track].offset + cs->lead_in;
+	else if (cs->tracks[track].num_indices < 2)
+		return 0;
+	else if (cs->tracks[track].indices[1].number == 1)
+		return cs->tracks[track].indices[1].offset + cs->tracks[track].offset + cs->lead_in;
+	else
+		return 0;
+}
+
+static FLAC__uint32 cddb_add_digits_(FLAC__uint32 x)
+{
+	FLAC__uint32 n = 0;
+	while (x) {
+		n += (x%10);
+		x /= 10;
+	}
+	return n;
+}
+
+/*@@@@add to tests*/
+FLAC_API FLAC__uint32 FLAC__metadata_object_cuesheet_calculate_cddb_id(const FLAC__StreamMetadata *object)
+{
+	const FLAC__StreamMetadata_CueSheet *cs;
+
+	cs = &object->data.cue_sheet;
+
+	if (cs->num_tracks < 2) /* need at least one real track and the lead-out track */
+		return 0;
+
+	{
+		FLAC__uint32 i, length, sum = 0;
+		for (i = 0; i < (cs->num_tracks-1); i++) /* -1 to avoid counting the lead-out */
+			sum += cddb_add_digits_((FLAC__uint32)(get_index_01_offset_(cs, i) / 44100));
+		length = (FLAC__uint32)((cs->tracks[cs->num_tracks-1].offset+cs->lead_in) / 44100) - (FLAC__uint32)(get_index_01_offset_(cs, 0) / 44100);
+
+		return (sum % 0xFF) << 24 | length << 8 | (FLAC__uint32)(cs->num_tracks-1);
+	}
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_picture_set_mime_type(FLAC__StreamMetadata *object, char *mime_type, FLAC__bool copy)
+{
+	char *old;
+	size_t old_length, new_length;
+
+	old = object->data.picture.mime_type;
+	old_length = old? strlen(old) : 0;
+	new_length = strlen(mime_type);
+
+	/* do the copy first so that if we fail we leave the object untouched */
+	if (copy) {
+		if (new_length >= SIZE_MAX) /* overflow check */
+			return false;
+		if (!copy_bytes_((FLAC__byte**)(&object->data.picture.mime_type), (FLAC__byte*)mime_type, (uint32_t)(new_length+1)))
+			return false;
+	}
+	else {
+		object->data.picture.mime_type = mime_type;
+	}
+
+	free(old);
+
+	object->length -= (uint32_t)old_length;
+	object->length += (uint32_t)new_length;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_picture_set_description(FLAC__StreamMetadata *object, FLAC__byte *description, FLAC__bool copy)
+{
+	FLAC__byte *old;
+	size_t old_length, new_length;
+
+	old = object->data.picture.description;
+	old_length = old? strlen((const char *)old) : 0;
+	new_length = strlen((const char *)description);
+
+	/* do the copy first so that if we fail we leave the object untouched */
+	if (copy) {
+		if (new_length >= SIZE_MAX) /* overflow check */
+			return false;
+		if (!copy_bytes_(&object->data.picture.description, description, (uint32_t)(new_length+1)))
+			return false;
+	}
+	else {
+		object->data.picture.description = description;
+	}
+
+	free(old);
+
+	object->length -= (uint32_t)old_length;
+	object->length += (uint32_t)new_length;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_picture_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, FLAC__uint32 length, FLAC__bool copy)
+{
+	FLAC__byte *old;
+
+	old = object->data.picture.data;
+
+	/* do the copy first so that if we fail we leave the object untouched */
+	if (copy) {
+		if (!copy_bytes_(&object->data.picture.data, data, length))
+			return false;
+	}
+	else {
+		object->data.picture.data = data;
+	}
+
+	free(old);
+
+	object->length -= object->data.picture.data_length;
+	object->data.picture.data_length = length;
+	object->length += length;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_picture_is_legal(const FLAC__StreamMetadata *object, const char **violation)
+{
+	return FLAC__format_picture_is_legal(&object->data.picture, violation);
+}
--- /dev/null
+++ b/src/libflac/private/bitmath.h
@@ -1,0 +1,205 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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.
+ */
+
+#ifndef FLAC__PRIVATE__BITMATH_H
+#define FLAC__PRIVATE__BITMATH_H
+
+#include "../FLAC/ordinals.h"
+
+#include "../share/compat.h"
+
+#if defined(_MSC_VER)
+#include <intrin.h> /* for _BitScanReverse* */
+#endif
+
+/* Will never be emitted for MSVC, GCC, Intel compilers */
+static inline uint32_t FLAC__clz_soft_uint32(FLAC__uint32 word)
+{
+	static const uint8_t byte_to_unary_table[] = {
+	8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
+	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	};
+
+	return word > 0xffffff ? byte_to_unary_table[word >> 24] :
+		word > 0xffff ? byte_to_unary_table[word >> 16] + 8 :
+		word > 0xff ? byte_to_unary_table[word >> 8] + 16 :
+		byte_to_unary_table[word] + 24;
+}
+
+static inline uint32_t FLAC__clz_uint32(FLAC__uint32 v)
+{
+/* Never used with input 0 */
+#if defined(__INTEL_COMPILER)
+	return _bit_scan_reverse(v) ^ 31U;
+#elif defined(__GNUC__) && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
+/* This will translate either to (bsr ^ 31U), clz , ctlz, cntlz, lzcnt depending on
+ * -march= setting or to a software routine in exotic machines. */
+	return __builtin_clz(v);
+#elif defined(_MSC_VER)
+	{
+		DWORD idx;
+		_BitScanReverse(&idx, v);
+		return (uint32_t)(idx ^ 31U);
+	}
+#else
+	return FLAC__clz_soft_uint32(v);
+#endif
+}
+
+/* Used when 64-bit bsr/clz is unavailable; can use 32-bit bsr/clz when possible */
+static inline uint32_t FLAC__clz_soft_uint64(FLAC__uint64 word)
+{
+	return (FLAC__uint32)(word>>32) ? FLAC__clz_uint32((FLAC__uint32)(word>>32)) :
+		FLAC__clz_uint32((FLAC__uint32)word) + 32;
+}
+
+static inline uint32_t FLAC__clz_uint64(FLAC__uint64 v)
+{
+	/* Never used with input 0 */
+#if defined(__GNUC__) && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
+	return __builtin_clzll(v);
+#elif (defined(__INTEL_COMPILER) || defined(_MSC_VER)) && (defined(_M_IA64) || defined(_M_X64))
+	{
+		DWORD idx;
+		_BitScanReverse64(&idx, v);
+		return (uint32_t)(idx ^ 63U);
+	}
+#else
+	return FLAC__clz_soft_uint64(v);
+#endif
+}
+
+/* These two functions work with input 0 */
+static inline uint32_t FLAC__clz2_uint32(FLAC__uint32 v)
+{
+	if (!v)
+		return 32;
+	return FLAC__clz_uint32(v);
+}
+
+static inline uint32_t FLAC__clz2_uint64(FLAC__uint64 v)
+{
+	if (!v)
+		return 64;
+	return FLAC__clz_uint64(v);
+}
+
+/* An example of what FLAC__bitmath_ilog2() computes:
+ *
+ * ilog2( 0) = assertion failure
+ * ilog2( 1) = 0
+ * ilog2( 2) = 1
+ * ilog2( 3) = 1
+ * ilog2( 4) = 2
+ * ilog2( 5) = 2
+ * ilog2( 6) = 2
+ * ilog2( 7) = 2
+ * ilog2( 8) = 3
+ * ilog2( 9) = 3
+ * ilog2(10) = 3
+ * ilog2(11) = 3
+ * ilog2(12) = 3
+ * ilog2(13) = 3
+ * ilog2(14) = 3
+ * ilog2(15) = 3
+ * ilog2(16) = 4
+ * ilog2(17) = 4
+ * ilog2(18) = 4
+ */
+
+static inline uint32_t FLAC__bitmath_ilog2(FLAC__uint32 v)
+{
+#if defined(__INTEL_COMPILER)
+	return _bit_scan_reverse(v);
+#elif defined(_MSC_VER)
+	{
+		DWORD idx;
+		_BitScanReverse(&idx, v);
+		return (uint32_t)idx;
+	}
+#else
+	return FLAC__clz_uint32(v) ^ 31U;
+#endif
+}
+
+static inline uint32_t FLAC__bitmath_ilog2_wide(FLAC__uint64 v)
+{
+#if defined(__GNUC__) && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
+	return __builtin_clzll(v) ^ 63U;
+/* Sorry, only supported in x64/Itanium.. and both have fast FPU which makes integer-only encoder pointless */
+#elif (defined(__INTEL_COMPILER) || defined(_MSC_VER)) && (defined(_M_IA64) || defined(_M_X64))
+	{
+		DWORD idx;
+		_BitScanReverse64(&idx, v);
+		return (uint32_t)idx;
+	}
+#else
+/*  Brain-damaged compilers will use the fastest possible way that is,
+	de Bruijn sequences (http://supertech.csail.mit.edu/papers/debruijn.pdf)
+	(C) Timothy B. Terriberry (tterribe@xiph.org) 2001-2009 CC0 (Public domain).
+*/
+	{
+		static const uint8_t DEBRUIJN_IDX64[64]={
+			0, 1, 2, 7, 3,13, 8,19, 4,25,14,28, 9,34,20,40,
+			5,17,26,38,15,46,29,48,10,31,35,54,21,50,41,57,
+			63, 6,12,18,24,27,33,39,16,37,45,47,30,53,49,56,
+			62,11,23,32,36,44,52,55,61,22,43,51,60,42,59,58
+		};
+		v|= v>>1;
+		v|= v>>2;
+		v|= v>>4;
+		v|= v>>8;
+		v|= v>>16;
+		v|= v>>32;
+		v= (v>>1)+1;
+		return DEBRUIJN_IDX64[v*FLAC__U64L(0x218A392CD3D5DBF)>>58&0x3F];
+	}
+#endif
+}
+
+uint32_t FLAC__bitmath_silog2(FLAC__int64 v);
+
+#endif
--- /dev/null
+++ b/src/libflac/private/bitreader.h
@@ -1,0 +1,90 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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.
+ */
+
+#ifndef FLAC__PRIVATE__BITREADER_H
+#define FLAC__PRIVATE__BITREADER_H
+
+#include <stdio.h> /* for FILE */
+#include "../FLAC/ordinals.h"
+
+/*
+ * opaque structure definition
+ */
+struct FLAC__BitReader;
+typedef struct FLAC__BitReader FLAC__BitReader;
+
+typedef FLAC__bool (*FLAC__BitReaderReadCallback)(FLAC__byte buffer[], size_t *bytes, void *client_data);
+
+/*
+ * construction, deletion, initialization, etc functions
+ */
+FLAC__BitReader *FLAC__bitreader_new(void);
+void FLAC__bitreader_delete(FLAC__BitReader *br);
+FLAC__bool FLAC__bitreader_init(FLAC__BitReader *br, FLAC__BitReaderReadCallback rcb, void *cd);
+void FLAC__bitreader_free(FLAC__BitReader *br); /* does not 'free(br)' */
+FLAC__bool FLAC__bitreader_clear(FLAC__BitReader *br);
+void FLAC__bitreader_dump(const FLAC__BitReader *br, FILE *out);
+
+/*
+ * CRC functions
+ */
+void FLAC__bitreader_reset_read_crc16(FLAC__BitReader *br, FLAC__uint16 seed);
+FLAC__uint16 FLAC__bitreader_get_read_crc16(FLAC__BitReader *br);
+
+/*
+ * info functions
+ */
+FLAC__bool FLAC__bitreader_is_consumed_byte_aligned(const FLAC__BitReader *br);
+uint32_t FLAC__bitreader_bits_left_for_byte_alignment(const FLAC__BitReader *br);
+uint32_t FLAC__bitreader_get_input_bits_unconsumed(const FLAC__BitReader *br);
+
+/*
+ * read functions
+ */
+
+FLAC__bool FLAC__bitreader_read_raw_uint32(FLAC__BitReader *br, FLAC__uint32 *val, uint32_t bits);
+FLAC__bool FLAC__bitreader_read_raw_int32(FLAC__BitReader *br, FLAC__int32 *val, uint32_t bits);
+FLAC__bool FLAC__bitreader_read_raw_uint64(FLAC__BitReader *br, FLAC__uint64 *val, uint32_t bits);
+FLAC__bool FLAC__bitreader_read_uint32_little_endian(FLAC__BitReader *br, FLAC__uint32 *val); /*only for bits=32*/
+FLAC__bool FLAC__bitreader_skip_bits_no_crc(FLAC__BitReader *br, uint32_t bits); /* WATCHOUT: does not CRC the skipped data! */ /*@@@@ add to unit tests */
+FLAC__bool FLAC__bitreader_skip_byte_block_aligned_no_crc(FLAC__BitReader *br, uint32_t nvals); /* WATCHOUT: does not CRC the read data! */
+FLAC__bool FLAC__bitreader_read_byte_block_aligned_no_crc(FLAC__BitReader *br, FLAC__byte *val, uint32_t nvals); /* WATCHOUT: does not CRC the read data! */
+FLAC__bool FLAC__bitreader_read_unary_unsigned(FLAC__BitReader *br, uint32_t *val);
+FLAC__bool FLAC__bitreader_read_rice_signed(FLAC__BitReader *br, int *val, uint32_t parameter);
+FLAC__bool FLAC__bitreader_read_rice_signed_block(FLAC__BitReader *br, int vals[], uint32_t nvals, uint32_t parameter);
+#if 0 /* UNUSED */
+FLAC__bool FLAC__bitreader_read_golomb_signed(FLAC__BitReader *br, int *val, uint32_t parameter);
+FLAC__bool FLAC__bitreader_read_golomb_unsigned(FLAC__BitReader *br, uint32_t *val, uint32_t parameter);
+#endif
+FLAC__bool FLAC__bitreader_read_utf8_uint32(FLAC__BitReader *br, FLAC__uint32 *val, FLAC__byte *raw, uint32_t *rawlen);
+FLAC__bool FLAC__bitreader_read_utf8_uint64(FLAC__BitReader *br, FLAC__uint64 *val, FLAC__byte *raw, uint32_t *rawlen);
+#endif
--- /dev/null
+++ b/src/libflac/private/crc.h
@@ -1,0 +1,60 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2018  Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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.
+ */
+
+#ifndef FLAC__PRIVATE__CRC_H
+#define FLAC__PRIVATE__CRC_H
+
+#include "../FLAC/ordinals.h"
+
+/* 8 bit CRC generator, MSB shifted first
+** polynomial = x^8 + x^2 + x^1 + x^0
+** init = 0
+*/
+FLAC__uint8 FLAC__crc8(const FLAC__byte *data, uint32_t len);
+
+/* 16 bit CRC generator, MSB shifted first
+** polynomial = x^16 + x^15 + x^2 + x^0
+** init = 0
+*/
+extern FLAC__uint16 const FLAC__crc16_table[8][256];
+
+#define FLAC__CRC16_UPDATE(data, crc) ((((crc)<<8) & 0xffff) ^ FLAC__crc16_table[0][((crc)>>8) ^ (data)])
+/* this alternate may be faster on some systems/compilers */
+#if 0
+#define FLAC__CRC16_UPDATE(data, crc) ((((crc)<<8) ^ FLAC__crc16_table[0][((crc)>>8) ^ (data)]) & 0xffff)
+#endif
+
+FLAC__uint16 FLAC__crc16(const FLAC__byte *data, uint32_t len);
+FLAC__uint16 FLAC__crc16_update_words32(const FLAC__uint32 *words, uint32_t len, FLAC__uint16 crc);
+FLAC__uint16 FLAC__crc16_update_words64(const FLAC__uint64 *words, uint32_t len, FLAC__uint16 crc);
+
+#endif
--- /dev/null
+++ b/src/libflac/private/fixed.h
@@ -1,0 +1,82 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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.
+ */
+
+#ifndef FLAC__PRIVATE__FIXED_H
+#define FLAC__PRIVATE__FIXED_H
+
+#include "../private/float.h"
+#include "../FLAC/format.h"
+
+/*
+ *	FLAC__fixed_compute_best_predictor()
+ *	--------------------------------------------------------------------
+ *	Compute the best fixed predictor and the expected bits-per-sample
+ *  of the residual signal for each order.  The _wide() version uses
+ *  64-bit integers which is statistically necessary when bits-per-
+ *  sample + log2(blocksize) > 30
+ *
+ *	IN data[0,data_len-1]
+ *	IN data_len
+ *	OUT residual_bits_per_sample[0,FLAC__MAX_FIXED_ORDER]
+ */
+uint32_t FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+uint32_t FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+
+/*
+ *	FLAC__fixed_compute_residual()
+ *	--------------------------------------------------------------------
+ *	Compute the residual signal obtained from sutracting the predicted
+ *	signal from the original.
+ *
+ *	IN data[-order,data_len-1]        original signal (NOTE THE INDICES!)
+ *	IN data_len                       length of original signal
+ *	IN order <= FLAC__MAX_FIXED_ORDER fixed-predictor order
+ *	OUT residual[0,data_len-1]        residual signal
+ */
+void FLAC__fixed_compute_residual(const FLAC__int32 data[], uint32_t data_len, uint32_t order, FLAC__int32 residual[]);
+
+/*
+ *	FLAC__fixed_restore_signal()
+ *	--------------------------------------------------------------------
+ *	Restore the original signal by summing the residual and the
+ *	predictor.
+ *
+ *	IN residual[0,data_len-1]         residual signal
+ *	IN data_len                       length of original signal
+ *	IN order <= FLAC__MAX_FIXED_ORDER fixed-predictor order
+ *	*** IMPORTANT: the caller must pass in the historical samples:
+ *	IN  data[-order,-1]               previously-reconstructed historical samples
+ *	OUT data[0,data_len-1]            original signal
+ */
+void FLAC__fixed_restore_signal(const FLAC__int32 residual[], uint32_t data_len, uint32_t order, FLAC__int32 data[]);
+
+#endif
--- /dev/null
+++ b/src/libflac/private/float.h
@@ -1,0 +1,46 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2004-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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.
+ */
+
+#ifndef FLAC__PRIVATE__FLOAT_H
+#define FLAC__PRIVATE__FLOAT_H
+
+#include "../FLAC/ordinals.h"
+
+/*
+ * FLAC__real is the basic floating point type used in LPC analysis.
+ *
+ * WATCHOUT: changing FLAC__real will change the signatures of many
+ * functions that have assembly language equivalents and break them.
+ */
+typedef float FLAC__real;
+
+#endif
--- /dev/null
+++ b/src/libflac/private/format.h
@@ -1,0 +1,45 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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.
+ */
+
+#ifndef FLAC__PRIVATE__FORMAT_H
+#define FLAC__PRIVATE__FORMAT_H
+
+#include "../FLAC/format.h"
+
+uint32_t FLAC__format_get_max_rice_partition_order(uint32_t blocksize, uint32_t predictor_order);
+uint32_t FLAC__format_get_max_rice_partition_order_from_blocksize(uint32_t blocksize);
+uint32_t FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(uint32_t limit, uint32_t blocksize, uint32_t predictor_order);
+void FLAC__format_entropy_coding_method_partitioned_rice_contents_init(FLAC__EntropyCodingMethod_PartitionedRiceContents *object);
+void FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(FLAC__EntropyCodingMethod_PartitionedRiceContents *object);
+FLAC__bool FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(FLAC__EntropyCodingMethod_PartitionedRiceContents *object, uint32_t max_partition_order);
+
+#endif
--- /dev/null
+++ b/src/libflac/private/lpc.h
@@ -1,0 +1,258 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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.
+ */
+
+#ifndef FLAC__PRIVATE__LPC_H
+#define FLAC__PRIVATE__LPC_H
+
+#include "../private/float.h"
+#include "../FLAC/format.h"
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+/*
+ *	FLAC__lpc_window_data()
+ *	--------------------------------------------------------------------
+ *	Applies the given window to the data.
+ *  OPT: asm implementation
+ *
+ *	IN in[0,data_len-1]
+ *	IN window[0,data_len-1]
+ *	OUT out[0,lag-1]
+ *	IN data_len
+ */
+void FLAC__lpc_window_data(const FLAC__int32 in[], const FLAC__real window[], FLAC__real out[], uint32_t data_len);
+
+/*
+ *	FLAC__lpc_compute_autocorrelation()
+ *	--------------------------------------------------------------------
+ *	Compute the autocorrelation for lags between 0 and lag-1.
+ *	Assumes data[] outside of [0,data_len-1] == 0.
+ *	Asserts that lag > 0.
+ *
+ *	IN data[0,data_len-1]
+ *	IN data_len
+ *	IN 0 < lag <= data_len
+ *	OUT autoc[0,lag-1]
+ */
+void FLAC__lpc_compute_autocorrelation(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+#ifndef FLAC__NO_ASM
+#  ifdef FLAC__CPU_IA32
+#    ifdef FLAC__HAS_NASM
+void FLAC__lpc_compute_autocorrelation_asm_ia32(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_4_old(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_8_old(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_12_old(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_16_old(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+#    endif
+#  endif
+#  if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
+#    ifdef FLAC__SSE_SUPPORTED
+void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_4_old(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_8_old(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_12_old(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_16_old(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_4_new(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_8_new(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_12_new(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_sse_lag_16_new(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+#    endif
+#  endif
+#if defined(FLAC__CPU_PPC64) && defined(FLAC__USE_VSX)
+#ifdef FLAC__HAS_TARGET_POWER9
+void FLAC__lpc_compute_autocorrelation_intrin_power9_vsx_lag_4(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_power9_vsx_lag_8(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_power9_vsx_lag_12(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_power9_vsx_lag_16(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+#endif
+#ifdef FLAC__HAS_TARGET_POWER8
+void FLAC__lpc_compute_autocorrelation_intrin_power8_vsx_lag_4(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_power8_vsx_lag_8(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_power8_vsx_lag_12(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_intrin_power8_vsx_lag_16(const FLAC__real data[], uint32_t data_len, uint32_t lag, FLAC__real autoc[]);
+#endif
+#endif
+#endif
+
+/*
+ *	FLAC__lpc_compute_lp_coefficients()
+ *	--------------------------------------------------------------------
+ *	Computes LP coefficients for orders 1..max_order.
+ *	Do not call if autoc[0] == 0.0.  This means the signal is zero
+ *	and there is no point in calculating a predictor.
+ *
+ *	IN autoc[0,max_order]                      autocorrelation values
+ *	IN 0 < max_order <= FLAC__MAX_LPC_ORDER    max LP order to compute
+ *	OUT lp_coeff[0,max_order-1][0,max_order-1] LP coefficients for each order
+ *	*** IMPORTANT:
+ *	*** lp_coeff[0,max_order-1][max_order,FLAC__MAX_LPC_ORDER-1] are untouched
+ *	OUT error[0,max_order-1]                   error for each order (more
+ *	                                           specifically, the variance of
+ *	                                           the error signal times # of
+ *	                                           samples in the signal)
+ *
+ *	Example: if max_order is 9, the LP coefficients for order 9 will be
+ *	         in lp_coeff[8][0,8], the LP coefficients for order 8 will be
+ *			 in lp_coeff[7][0,7], etc.
+ */
+void FLAC__lpc_compute_lp_coefficients(const FLAC__real autoc[], uint32_t *max_order, FLAC__real lp_coeff[][FLAC__MAX_LPC_ORDER], double error[]);
+
+/*
+ *	FLAC__lpc_quantize_coefficients()
+ *	--------------------------------------------------------------------
+ *	Quantizes the LP coefficients.  NOTE: precision + bits_per_sample
+ *	must be less than 32 (sizeof(FLAC__int32)*8).
+ *
+ *	IN lp_coeff[0,order-1]    LP coefficients
+ *	IN order                  LP order
+ *	IN FLAC__MIN_QLP_COEFF_PRECISION < precision
+ *	                          desired precision (in bits, including sign
+ *	                          bit) of largest coefficient
+ *	OUT qlp_coeff[0,order-1]  quantized coefficients
+ *	OUT shift                 # of bits to shift right to get approximated
+ *	                          LP coefficients.  NOTE: could be negative.
+ *	RETURN 0 => quantization OK
+ *	       1 => coefficients require too much shifting for *shift to
+ *              fit in the LPC subframe header.  'shift' is unset.
+ *         2 => coefficients are all zero, which is bad.  'shift' is
+ *              unset.
+ */
+int FLAC__lpc_quantize_coefficients(const FLAC__real lp_coeff[], uint32_t order, uint32_t precision, FLAC__int32 qlp_coeff[], int *shift);
+
+/*
+ *	FLAC__lpc_compute_residual_from_qlp_coefficients()
+ *	--------------------------------------------------------------------
+ *	Compute the residual signal obtained from sutracting the predicted
+ *	signal from the original.
+ *
+ *	IN data[-order,data_len-1] original signal (NOTE THE INDICES!)
+ *	IN data_len                length of original signal
+ *	IN qlp_coeff[0,order-1]    quantized LP coefficients
+ *	IN order > 0               LP order
+ *	IN lp_quantization         quantization of LP coefficients in bits
+ *	OUT residual[0,data_len-1] residual signal
+ */
+void FLAC__lpc_compute_residual_from_qlp_coefficients(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+void FLAC__lpc_compute_residual_from_qlp_coefficients_wide(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+#ifndef FLAC__NO_ASM
+#  ifdef FLAC__CPU_IA32
+#    ifdef FLAC__HAS_NASM
+void FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+void FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+void FLAC__lpc_compute_residual_from_qlp_coefficients_wide_asm_ia32(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+#    endif
+#  endif
+#  if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
+#    ifdef FLAC__SSE2_SUPPORTED
+void FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_sse2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+#    endif
+#    ifdef FLAC__SSE4_1_SUPPORTED
+void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse41(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+void FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_sse41(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+#    endif
+#    ifdef FLAC__AVX2_SUPPORTED
+void FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_avx2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_avx2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+void FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_avx2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]);
+#    endif
+#  endif
+#endif
+
+#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
+
+/*
+ *	FLAC__lpc_restore_signal()
+ *	--------------------------------------------------------------------
+ *	Restore the original signal by summing the residual and the
+ *	predictor.
+ *
+ *	IN residual[0,data_len-1]  residual signal
+ *	IN data_len                length of original signal
+ *	IN qlp_coeff[0,order-1]    quantized LP coefficients
+ *	IN order > 0               LP order
+ *	IN lp_quantization         quantization of LP coefficients in bits
+ *	*** IMPORTANT: the caller must pass in the historical samples:
+ *	IN  data[-order,-1]        previously-reconstructed historical samples
+ *	OUT data[0,data_len-1]     original signal
+ */
+void FLAC__lpc_restore_signal(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]);
+void FLAC__lpc_restore_signal_wide(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]);
+#ifndef FLAC__NO_ASM
+#  ifdef FLAC__CPU_IA32
+#    ifdef FLAC__HAS_NASM
+void FLAC__lpc_restore_signal_asm_ia32(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]);
+void FLAC__lpc_restore_signal_asm_ia32_mmx(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]);
+void FLAC__lpc_restore_signal_wide_asm_ia32(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]);
+#    endif /* FLAC__HAS_NASM */
+#  endif /* FLAC__CPU_IA32 */
+#  if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN
+#    ifdef FLAC__SSE4_1_SUPPORTED
+void FLAC__lpc_restore_signal_intrin_sse41(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]);
+void FLAC__lpc_restore_signal_16_intrin_sse41(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]);
+void FLAC__lpc_restore_signal_wide_intrin_sse41(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]);
+#    endif
+#  endif
+#endif /* FLAC__NO_ASM */
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+/*
+ *	FLAC__lpc_compute_expected_bits_per_residual_sample()
+ *	--------------------------------------------------------------------
+ *	Compute the expected number of bits per residual signal sample
+ *	based on the LP error (which is related to the residual variance).
+ *
+ *	IN lpc_error >= 0.0   error returned from calculating LP coefficients
+ *	IN total_samples > 0  # of samples in residual signal
+ *	RETURN                expected bits per sample
+ */
+double FLAC__lpc_compute_expected_bits_per_residual_sample(double lpc_error, uint32_t total_samples);
+double FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(double lpc_error, double error_scale);
+
+/*
+ *	FLAC__lpc_compute_best_order()
+ *	--------------------------------------------------------------------
+ *	Compute the best order from the array of signal errors returned
+ *	during coefficient computation.
+ *
+ *	IN lpc_error[0,max_order-1] >= 0.0  error returned from calculating LP coefficients
+ *	IN max_order > 0                    max LP order
+ *	IN total_samples > 0                # of samples in residual signal
+ *	IN overhead_bits_per_order          # of bits overhead for each increased LP order
+ *	                                    (includes warmup sample size and quantized LP coefficient)
+ *	RETURN [1,max_order]                best order
+ */
+uint32_t FLAC__lpc_compute_best_order(const double lpc_error[], uint32_t max_order, uint32_t total_samples, uint32_t overhead_bits_per_order);
+
+#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
+
+#endif
--- /dev/null
+++ b/src/libflac/private/macros.h
@@ -1,0 +1,72 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2012-2016  Xiph.org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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.
+ */
+
+#ifndef FLAC__PRIVATE__MACROS_H
+#define FLAC__PRIVATE__MACROS_H
+
+#if defined(__GNUC__) && (__GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 3))
+
+#define flac_max(a,b) \
+	({ __typeof__ (a) _a = (a); \
+	__typeof__ (b) _b = (b); \
+	_a > _b ? _a : _b; })
+
+#define MIN_PASTE(A,B) A##B
+#define MIN_IMPL(A,B,L) ({ \
+	__typeof__(A) MIN_PASTE(__a,L) = (A); \
+	__typeof__(B) MIN_PASTE(__b,L) = (B); \
+	MIN_PASTE(__a,L) < MIN_PASTE(__b,L) ? MIN_PASTE(__a,L) : MIN_PASTE(__b,L); \
+	})
+
+#define flac_min(A,B) MIN_IMPL(A,B,__COUNTER__)
+
+/* Whatever other unix that has sys/param.h */
+#elif defined(HAVE_SYS_PARAM_H)
+#include <sys/param.h>
+#define flac_max(a,b) MAX(a,b)
+#define flac_min(a,b) MIN(a,b)
+
+/* Windows VS has them in stdlib.h.. XXX:Untested */
+#elif defined(_MSC_VER)
+#include <stdlib.h>
+#define flac_max(a,b) __max(a,b)
+#define flac_min(a,b) __min(a,b)
+#endif
+
+#ifndef flac_min
+#define flac_min(x,y)	((x) <= (y) ? (x) : (y))
+#endif
+
+#ifndef flac_max
+#define flac_max(x,y)	((x) >= (y) ? (x) : (y))
+#endif
+
+#endif
--- /dev/null
+++ b/src/libflac/private/md5.h
@@ -1,0 +1,50 @@
+#ifndef FLAC__PRIVATE__MD5_H
+#define FLAC__PRIVATE__MD5_H
+
+/*
+ * This is the header file for the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ *
+ * Changed so as no longer to depend on Colin Plumb's `usual.h'
+ * header definitions; now uses stuff from dpkg's config.h
+ *  - Ian Jackson <ijackson@nyx.cs.du.edu>.
+ * Still in the public domain.
+ *
+ * Josh Coalson: made some changes to integrate with libFLAC.
+ * Still in the public domain, with no warranty.
+ */
+
+#include "../FLAC/ordinals.h"
+
+typedef union {
+	FLAC__byte *p8;
+	FLAC__int16 *p16;
+	FLAC__int32 *p32;
+} FLAC__multibyte;
+
+typedef struct {
+	FLAC__uint32 in[16];
+	FLAC__uint32 buf[4];
+	FLAC__uint32 bytes[2];
+	FLAC__multibyte internal_buf;
+	size_t capacity;
+} FLAC__MD5Context;
+
+void FLAC__MD5Init(FLAC__MD5Context *context);
+void FLAC__MD5Final(FLAC__byte digest[16], FLAC__MD5Context *context);
+
+FLAC__bool FLAC__MD5Accumulate(FLAC__MD5Context *ctx, const FLAC__int32 * const signal[], uint32_t channels, uint32_t samples, uint32_t bytes_per_sample);
+
+#endif
--- /dev/null
+++ b/src/libflac/private/memory.h
@@ -1,0 +1,55 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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.
+ */
+
+#ifndef FLAC__PRIVATE__MEMORY_H
+#define FLAC__PRIVATE__MEMORY_H
+
+
+#include <stdlib.h> /* for size_t */
+
+#include "../private/float.h"
+#include "../FLAC/ordinals.h" /* for FLAC__bool */
+
+/* Returns the unaligned address returned by malloc.
+ * Use free() on this address to deallocate.
+ */
+void *FLAC__memory_alloc_aligned(size_t bytes, void **aligned_address);
+FLAC__bool FLAC__memory_alloc_aligned_int32_array(size_t elements, FLAC__int32 **unaligned_pointer, FLAC__int32 **aligned_pointer);
+FLAC__bool FLAC__memory_alloc_aligned_uint32_array(size_t elements, FLAC__uint32 **unaligned_pointer, FLAC__uint32 **aligned_pointer);
+FLAC__bool FLAC__memory_alloc_aligned_uint64_array(size_t elements, FLAC__uint64 **unaligned_pointer, FLAC__uint64 **aligned_pointer);
+FLAC__bool FLAC__memory_alloc_aligned_unsigned_array(size_t elements, uint32_t **unaligned_pointer, uint32_t **aligned_pointer);
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+FLAC__bool FLAC__memory_alloc_aligned_real_array(size_t elements, FLAC__real **unaligned_pointer, FLAC__real **aligned_pointer);
+#endif
+void *safe_malloc_mul_2op_p(size_t size1, size_t size2);
+
+#endif
--- /dev/null
+++ b/src/libflac/private/metadata.h
@@ -1,0 +1,46 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2002-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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.
+ */
+
+#ifndef FLAC__PRIVATE__METADATA_H
+#define FLAC__PRIVATE__METADATA_H
+
+#include "../FLAC/metadata.h"
+
+/* WATCHOUT: all malloc()ed data in the block is free()ed; this may not
+ * be a consistent state (e.g. PICTURE) or equivalent to the initial
+ * state after FLAC__metadata_object_new()
+ */
+void FLAC__metadata_object_delete_data(FLAC__StreamMetadata *object);
+
+void FLAC__metadata_object_cuesheet_track_delete_data(FLAC__StreamMetadata_CueSheet_Track *object);
+
+#endif
--- /dev/null
+++ b/src/libflac/private/window.h
@@ -1,0 +1,70 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2006-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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.
+ */
+
+#ifndef FLAC__PRIVATE__WINDOW_H
+#define FLAC__PRIVATE__WINDOW_H
+
+#include "../private/float.h"
+#include "../FLAC/format.h"
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+/*
+ *	FLAC__window_*()
+ *	--------------------------------------------------------------------
+ *	Calculates window coefficients according to different apodization
+ *	functions.
+ *
+ *	OUT window[0,L-1]
+ *	IN L (number of points in window)
+ */
+void FLAC__window_bartlett(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_bartlett_hann(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_blackman(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_blackman_harris_4term_92db_sidelobe(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_connes(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_flattop(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_gauss(FLAC__real *window, const FLAC__int32 L, const FLAC__real stddev); /* 0.0 < stddev <= 0.5 */
+void FLAC__window_hamming(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_hann(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_kaiser_bessel(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_nuttall(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_rectangle(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_triangle(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p);
+void FLAC__window_partial_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end);
+void FLAC__window_punchout_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end);
+void FLAC__window_welch(FLAC__real *window, const FLAC__int32 L);
+
+#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
+
+#endif
--- /dev/null
+++ b/src/libflac/protected/stream_decoder.h
@@ -1,0 +1,60 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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.
+ */
+
+#ifndef FLAC__PROTECTED__STREAM_DECODER_H
+#define FLAC__PROTECTED__STREAM_DECODER_H
+
+#include "../FLAC/stream_decoder.h"
+
+typedef struct FLAC__StreamDecoderProtected {
+	FLAC__StreamDecoderState state;
+	FLAC__StreamDecoderInitStatus initstate;
+	uint32_t channels;
+	FLAC__ChannelAssignment channel_assignment;
+	uint32_t bits_per_sample;
+	uint32_t sample_rate; /* in Hz */
+	uint32_t blocksize; /* in samples (per channel) */
+	FLAC__bool md5_checking; /* if true, generate MD5 signature of decoded data and compare against signature in the STREAMINFO metadata block */
+
+} FLAC__StreamDecoderProtected;
+
+/*
+ * return the number of input bytes consumed
+ */
+uint32_t FLAC__stream_decoder_get_input_bytes_unconsumed(const FLAC__StreamDecoder *decoder);
+
+/*
+ * return client_data from decoder
+ */
+FLAC_API void *get_client_data_from_decoder(FLAC__StreamDecoder *decoder);
+
+#endif
--- /dev/null
+++ b/src/libflac/share/alloc.h
@@ -1,0 +1,213 @@
+/* alloc - Convenience routines for safely allocating memory
+ * Copyright (C) 2007-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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.
+ */
+
+#ifndef FLAC__SHARE__ALLOC_H
+#define FLAC__SHARE__ALLOC_H
+
+/* WATCHOUT: for c++ you may have to #define __STDC_LIMIT_MACROS 1 real early
+ * before #including this file,  otherwise SIZE_MAX might not be defined
+ */
+
+#include <limits.h> /* for SIZE_MAX */
+#include <stdint.h> /* for SIZE_MAX in case limits.h didn't get it */
+#include <stdlib.h> /* for size_t, malloc(), etc */
+#include "../share/compat.h"
+
+#ifndef SIZE_MAX
+# ifndef SIZE_T_MAX
+#  ifdef _MSC_VER
+#   ifdef _WIN64
+#    define SIZE_T_MAX FLAC__U64L(0xffffffffffffffff)
+#   else
+#    define SIZE_T_MAX 0xffffffff
+#   endif
+#  else
+#   error
+#  endif
+# endif
+# define SIZE_MAX SIZE_T_MAX
+#endif
+
+/* avoid malloc()ing 0 bytes, see:
+ * https://www.securecoding.cert.org/confluence/display/seccode/MEM04-A.+Do+not+make+assumptions+about+the+result+of+allocating+0+bytes?focusedCommentId=5407003
+*/
+static inline void *safe_malloc_(size_t size)
+{
+	/* malloc(0) is undefined; FLAC src convention is to always allocate */
+	if(!size)
+		size++;
+	return malloc(size);
+}
+
+static inline void *safe_calloc_(size_t nmemb, size_t size)
+{
+	if(!nmemb || !size)
+		return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */
+	return calloc(nmemb, size);
+}
+
+/*@@@@ there's probably a better way to prevent overflows when allocating untrusted sums but this works for now */
+
+static inline void *safe_malloc_add_2op_(size_t size1, size_t size2)
+{
+	size2 += size1;
+	if(size2 < size1)
+		return 0;
+	return safe_malloc_(size2);
+}
+
+static inline void *safe_malloc_add_3op_(size_t size1, size_t size2, size_t size3)
+{
+	size2 += size1;
+	if(size2 < size1)
+		return 0;
+	size3 += size2;
+	if(size3 < size2)
+		return 0;
+	return safe_malloc_(size3);
+}
+
+static inline void *safe_malloc_add_4op_(size_t size1, size_t size2, size_t size3, size_t size4)
+{
+	size2 += size1;
+	if(size2 < size1)
+		return 0;
+	size3 += size2;
+	if(size3 < size2)
+		return 0;
+	size4 += size3;
+	if(size4 < size3)
+		return 0;
+	return safe_malloc_(size4);
+}
+
+void *safe_malloc_mul_2op_(size_t size1, size_t size2) ;
+
+static inline void *safe_malloc_mul_3op_(size_t size1, size_t size2, size_t size3)
+{
+	if(!size1 || !size2 || !size3)
+		return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */
+	if(size1 > SIZE_MAX / size2)
+		return 0;
+	size1 *= size2;
+	if(size1 > SIZE_MAX / size3)
+		return 0;
+	return malloc(size1*size3);
+}
+
+/* size1*size2 + size3 */
+static inline void *safe_malloc_mul2add_(size_t size1, size_t size2, size_t size3)
+{
+	if(!size1 || !size2)
+		return safe_malloc_(size3);
+	if(size1 > SIZE_MAX / size2)
+		return 0;
+	return safe_malloc_add_2op_(size1*size2, size3);
+}
+
+/* size1 * (size2 + size3) */
+static inline void *safe_malloc_muladd2_(size_t size1, size_t size2, size_t size3)
+{
+	if(!size1 || (!size2 && !size3))
+		return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */
+	size2 += size3;
+	if(size2 < size3)
+		return 0;
+	if(size1 > SIZE_MAX / size2)
+		return 0;
+	return malloc(size1*size2);
+}
+
+static inline void *safe_realloc_(void *ptr, size_t size)
+{
+	void *oldptr = ptr;
+	void *newptr = realloc(ptr, size);
+	if(size > 0 && newptr == 0)
+		free(oldptr);
+	return newptr;
+}
+static inline void *safe_realloc_add_2op_(void *ptr, size_t size1, size_t size2)
+{
+	size2 += size1;
+	if(size2 < size1) {
+		free(ptr);
+		return 0;
+	}
+	return realloc(ptr, size2);
+}
+
+static inline void *safe_realloc_add_3op_(void *ptr, size_t size1, size_t size2, size_t size3)
+{
+	size2 += size1;
+	if(size2 < size1)
+		return 0;
+	size3 += size2;
+	if(size3 < size2)
+		return 0;
+	return realloc(ptr, size3);
+}
+
+static inline void *safe_realloc_add_4op_(void *ptr, size_t size1, size_t size2, size_t size3, size_t size4)
+{
+	size2 += size1;
+	if(size2 < size1)
+		return 0;
+	size3 += size2;
+	if(size3 < size2)
+		return 0;
+	size4 += size3;
+	if(size4 < size3)
+		return 0;
+	return realloc(ptr, size4);
+}
+
+static inline void *safe_realloc_mul_2op_(void *ptr, size_t size1, size_t size2)
+{
+	if(!size1 || !size2)
+		return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */
+	if(size1 > SIZE_MAX / size2)
+		return 0;
+	return safe_realloc_(ptr, size1*size2);
+}
+
+/* size1 * (size2 + size3) */
+static inline void *safe_realloc_muladd2_(void *ptr, size_t size1, size_t size2, size_t size3)
+{
+	if(!size1 || (!size2 && !size3))
+		return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */
+	size2 += size3;
+	if(size2 < size3)
+		return 0;
+	return safe_realloc_mul_2op_(ptr, size1, size2);
+}
+
+#endif
--- /dev/null
+++ b/src/libflac/share/compat.h
@@ -1,0 +1,205 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2012-2016  Xiph.org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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.
+ */
+
+/* This is the preferred location of all CPP hackery to make $random_compiler
+ * work like something approaching a C99 (or maybe more accurately GNU99)
+ * compiler.
+ *
+ * It is assumed that this header will be included after "config.h".
+ */
+
+#ifndef FLAC__SHARE__COMPAT_H
+#define FLAC__SHARE__COMPAT_H
+
+#if defined _WIN32 && !defined __CYGWIN__
+/* where MSVC puts unlink() */
+# include <io.h>
+#else
+# include <unistd.h>
+#endif
+
+#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__
+#include <sys/types.h> /* for off_t */
+#define FLAC__off_t __int64 /* use this instead of off_t to fix the 2 GB limit */
+#if !defined __MINGW32__
+#define fseeko _fseeki64
+#define ftello _ftelli64
+#else /* MinGW */
+#if !defined(HAVE_FSEEKO)
+#define fseeko fseeko64
+#define ftello ftello64
+#endif
+#endif
+#else
+#define FLAC__off_t off_t
+#endif
+
+#if HAVE_INTTYPES_H
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+#endif
+
+#if defined(_MSC_VER)
+#define strtoll _strtoi64
+#define strtoull _strtoui64
+#endif
+
+#if defined(_MSC_VER) && !defined(__cplusplus)
+#define inline __inline
+#endif
+
+#if defined __INTEL_COMPILER || (defined _MSC_VER && defined _WIN64)
+/* MSVS generates VERY slow 32-bit code with __restrict */
+#define flac_restrict __restrict
+#elif defined __GNUC__
+#define flac_restrict __restrict__
+#else
+#define flac_restrict
+#endif
+
+#define FLAC__U64L(x) x##ULL
+
+#if defined _MSC_VER || defined __MINGW32__
+#define FLAC__STRCASECMP _stricmp
+#define FLAC__STRNCASECMP _strnicmp
+#elif defined __BORLANDC__
+#define FLAC__STRCASECMP stricmp
+#define FLAC__STRNCASECMP strnicmp
+#else
+#define FLAC__STRCASECMP strcasecmp
+#define FLAC__STRNCASECMP strncasecmp
+#endif
+
+#if defined _MSC_VER || defined __MINGW32__ || defined __EMX__
+#include <io.h> /* for _setmode(), chmod() */
+#include <fcntl.h> /* for _O_BINARY */
+#else
+#include <unistd.h> /* for chown(), unlink() */
+#endif
+
+#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__
+#if defined __BORLANDC__
+#include <utime.h> /* for utime() */
+#else
+#include <sys/utime.h> /* for utime() */
+#endif
+#else
+#include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
+#include <utime.h> /* for utime() */
+#endif
+
+#if defined _MSC_VER
+#  if _MSC_VER >= 1800
+#    include <inttypes.h>
+#  elif _MSC_VER >= 1600
+/* Visual Studio 2010 has decent C99 support */
+#    include <stdint.h>
+#    define PRIu64 "llu"
+#    define PRId64 "lld"
+#    define PRIx64 "llx"
+#  else
+#    include <limits.h>
+#    ifndef UINT32_MAX
+#      define UINT32_MAX _UI32_MAX
+#    endif
+#    define PRIu64 "I64u"
+#    define PRId64 "I64d"
+#    define PRIx64 "I64x"
+#  endif
+#endif /* defined _MSC_VER */
+
+#ifdef _WIN32
+/* All char* strings are in UTF-8 format. Added to support Unicode files on Windows */
+
+#include "../share/win_utf8_io.h"
+#define flac_printf printf_utf8
+#define flac_fprintf fprintf_utf8
+#define flac_vfprintf vfprintf_utf8
+
+#include "../share/windows_unicode_filenames.h"
+#define flac_fopen flac_internal_fopen_utf8
+#define flac_chmod flac_internal_chmod_utf8
+#define flac_utime flac_internal_utime_utf8
+#define flac_unlink flac_internal_unlink_utf8
+#define flac_rename flac_internal_rename_utf8
+#define flac_stat flac_internal_stat64_utf8
+
+#else
+
+#define flac_printf printf
+#define flac_fprintf fprintf
+#define flac_vfprintf vfprintf
+
+#define flac_fopen fopen
+#define flac_chmod chmod
+#define flac_utime utime
+#define flac_unlink unlink
+#define flac_rename rename
+#define flac_stat stat
+
+#endif
+
+#ifdef _WIN32
+#define flac_stat_s __stat64 /* stat struct */
+#define flac_fstat _fstat64
+#else
+#define flac_stat_s stat /* stat struct */
+#define flac_fstat fstat
+#endif
+
+#ifdef ANDROID
+#include <limits.h>
+#endif
+
+#ifndef M_LN2
+#define M_LN2 0.69314718055994530942
+#endif
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+/* FLAC needs to compile and work correctly on systems with a normal ISO C99
+ * snprintf as well as Microsoft Visual Studio which has an non-standards
+ * conformant snprint_s function.
+ *
+ * This function wraps the MS version to behave more like the ISO version.
+ */
+#include <stdarg.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+int flac_snprintf(char *str, size_t size, const char *fmt, ...);
+int flac_vsnprintf(char *str, size_t size, const char *fmt, va_list va);
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* FLAC__SHARE__COMPAT_H */
--- /dev/null
+++ b/src/libflac/share/endswap.h
@@ -1,0 +1,84 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2012-2016  Xiph.org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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.
+ */
+
+/* It is assumed that this header will be included after "config.h". */
+
+#if HAVE_BSWAP32			/* GCC and Clang */
+
+/* GCC prior to 4.8 didn't provide bswap16 on x86_64 */
+#if ! HAVE_BSWAP16
+static inline unsigned short __builtin_bswap16(unsigned short a)
+{
+	return (a<<8)|(a>>8);
+}
+#endif
+
+#define	ENDSWAP_16(x)		(__builtin_bswap16 (x))
+#define	ENDSWAP_32(x)		(__builtin_bswap32 (x))
+#define	ENDSWAP_64(x)		(__builtin_bswap64 (x))
+
+#elif defined _MSC_VER		/* Windows */
+
+#include <stdlib.h>
+
+#define	ENDSWAP_16(x)		(_byteswap_ushort (x))
+#define	ENDSWAP_32(x)		(_byteswap_ulong (x))
+#define	ENDSWAP_64(x)		(_byteswap_uint64 (x))
+
+#elif defined HAVE_BYTESWAP_H		/* Linux */
+
+#include <byteswap.h>
+
+#define	ENDSWAP_16(x)		(bswap_16 (x))
+#define	ENDSWAP_32(x)		(bswap_32 (x))
+#define	ENDSWAP_64(x)		(bswap_64 (x))
+
+#else
+
+#define	ENDSWAP_16(x)		((((x) >> 8) & 0xFF) | (((x) & 0xFF) << 8))
+#define	ENDSWAP_32(x)		((((x) >> 24) & 0xFF) | (((x) >> 8) & 0xFF00) | (((x) & 0xFF00) << 8) | (((x) & 0xFF) << 24))
+#define	ENDSWAP_64(x)		((ENDSWAP_32(((x) >> 32) & 0xFFFFFFFF)) | (ENDSWAP_32((x) & 0xFFFFFFFF) << 32))
+
+#endif
+
+
+/* Host to little-endian byte swapping (for MD5 calculation) */
+#if CPU_IS_BIG_ENDIAN
+
+#define H2LE_16(x)		ENDSWAP_16 (x)
+#define H2LE_32(x)		ENDSWAP_32 (x)
+
+#else
+
+#define H2LE_16(x)		(x)
+#define H2LE_32(x)		(x)
+
+#endif
--- /dev/null
+++ b/src/libflac/share/macros.h
@@ -1,0 +1,45 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2013-2016  Xiph.org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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.
+ */
+
+#include <errno.h>
+
+/* FLAC_CHECK_RETURN : Check the return value of the provided function and
+ * print an error message if it fails (ie returns a value < 0).
+ *
+ * Ideally, a library should not print anything, but this macro is only used
+ * for things that extremely unlikely to fail, like `chown` to a previoulsy
+ * saved `uid`.
+ */
+
+#define FLAC_CHECK_RETURN(x) \
+			{	if ((x) < 0) \
+					fprintf (stderr, "%s : %s\n", #x, strerror (errno)) ; \
+			}
--- /dev/null
+++ b/src/libflac/share/safe_str.h
@@ -1,0 +1,69 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2013-2016  Xiph.org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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.
+ */
+
+/* Safe string handling functions to replace things like strcpy, strncpy,
+ * strcat, strncat etc.
+ * All of these functions guarantee a correctly NUL terminated string but
+ * the string may be truncated if the destination buffer was too short.
+ */
+
+#ifndef FLAC__SHARE_SAFE_STR_H
+#define FLAC__SHARE_SAFE_STR_H
+
+static inline char *
+safe_strncat(char *dest, const char *src, size_t dest_size)
+{
+	char * ret;
+
+	if (dest_size < 1)
+		return dest;
+
+	ret = strncat(dest, src, dest_size - strlen (dest));
+	dest [dest_size - 1] = 0;
+
+	return ret;
+}
+
+static inline char *
+safe_strncpy(char *dest, const char *src, size_t dest_size)
+{
+	char * ret;
+
+	if (dest_size < 1)
+		return dest;
+
+	ret = strncpy(dest, src, dest_size);
+	dest [dest_size - 1] = 0;
+
+	return ret;
+}
+
+#endif /* FLAC__SHARE_SAFE_STR_H */
--- /dev/null
+++ b/src/libflac/share/utf8.h
@@ -1,0 +1,25 @@
+#ifndef SHARE__UTF8_H
+#define SHARE__UTF8_H
+
+/*
+ * Convert a string between UTF-8 and the locale's charset.
+ * Invalid bytes are replaced by '#', and characters that are
+ * not available in the target encoding are replaced by '?'.
+ *
+ * If the locale's charset is not set explicitly then it is
+ * obtained using nl_langinfo(CODESET), where available, the
+ * environment variable CHARSET, or assumed to be US-ASCII.
+ *
+ * Return value of conversion functions:
+ *
+ *  -1 : memory allocation failed
+ *   0 : data was converted exactly
+ *   1 : valid data was converted approximately (using '?')
+ *   2 : input was invalid (but still converted, using '#')
+ *   3 : unknown encoding (but still converted, using '?')
+ */
+
+int utf8_encode(const char *from, char **to);
+int utf8_decode(const char *from, char **to);
+
+#endif
--- /dev/null
+++ b/src/libflac/share/win_utf8_io.h
@@ -1,0 +1,62 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2013-2016  Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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
+
+#ifndef flac__win_utf8_io_h
+#define flac__win_utf8_io_h
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+size_t strlen_utf8(const char *str);
+int win_get_console_width(void);
+
+int get_utf8_argv(int *argc, char ***argv);
+
+int printf_utf8(const char *format, ...);
+int fprintf_utf8(FILE *stream, const char *format, ...);
+int vfprintf_utf8(FILE *stream, const char *format, va_list argptr);
+
+#define WIN32_MEAN_AND_LEAN
+#include <windows.h>
+HANDLE WINAPI CreateFile_utf8(const char *lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
+#endif
--- /dev/null
+++ b/src/libflac/share/windows_unicode_filenames.h
@@ -1,0 +1,63 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2013-2016  Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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
+
+#ifndef flac__windows_unicode_filenames_h
+#define flac__windows_unicode_filenames_h
+
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/utime.h>
+#include "../FLAC/ordinals.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void flac_internal_set_utf8_filenames(FLAC__bool flag);
+FLAC__bool flac_internal_get_utf8_filenames(void);
+#define flac_set_utf8_filenames flac_internal_set_utf8_filenames
+#define flac_get_utf8_filenames flac_internal_get_utf8_filenames
+
+FILE* flac_internal_fopen_utf8(const char *filename, const char *mode);
+int flac_internal_stat64_utf8(const char *path, struct __stat64 *buffer);
+int flac_internal_chmod_utf8(const char *filename, int pmode);
+int flac_internal_utime_utf8(const char *filename, struct utimbuf *times);
+int flac_internal_unlink_utf8(const char *filename);
+int flac_internal_rename_utf8(const char *oldname, const char *newname);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
+#endif
--- /dev/null
+++ b/src/libflac/stream_decoder.c
@@ -1,0 +1,2951 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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.
+ */
+
+// 8bb: hide POSIX warnings
+#ifdef _MSC_VER
+#pragma warning(disable: 4996)
+#endif
+
+#include <stdio.h>
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memset/memcpy() */
+#include <sys/stat.h> /* for stat() */
+#include <sys/types.h> /* for off_t */
+#include "share/compat.h"
+#include "share/alloc.h"
+#include "protected/stream_decoder.h"
+#include "private/bitreader.h"
+#include "private/bitmath.h"
+#include "private/crc.h"
+#include "private/fixed.h"
+#include "private/format.h"
+#include "private/lpc.h"
+#include "private/md5.h"
+#include "private/memory.h"
+#include "private/macros.h"
+
+/***********************************************************************
+ *
+ * Private static data
+ *
+ ***********************************************************************/
+
+static const FLAC__byte ID3V2_TAG_[3] = { 'I', 'D', '3' };
+
+/***********************************************************************
+ *
+ * Private class method prototypes
+ *
+ ***********************************************************************/
+
+static void set_defaults_(FLAC__StreamDecoder *decoder);
+static FILE *get_binary_stdin_(void);
+static FLAC__bool allocate_output_(FLAC__StreamDecoder *decoder, uint32_t size, uint32_t channels);
+static FLAC__bool has_id_filtered_(FLAC__StreamDecoder *decoder, FLAC__byte *id);
+static FLAC__bool find_metadata_(FLAC__StreamDecoder *decoder);
+static FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder);
+static FLAC__bool read_metadata_streaminfo_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, uint32_t length);
+static FLAC__bool read_metadata_seektable_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, uint32_t length);
+static FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_VorbisComment *obj, uint32_t length);
+static FLAC__bool read_metadata_cuesheet_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_CueSheet *obj);
+static FLAC__bool read_metadata_picture_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_Picture *obj);
+static FLAC__bool skip_id3v2_tag_(FLAC__StreamDecoder *decoder);
+static FLAC__bool frame_sync_(FLAC__StreamDecoder *decoder);
+static FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame, FLAC__bool do_full_decode);
+static FLAC__bool read_frame_header_(FLAC__StreamDecoder *decoder);
+static FLAC__bool read_subframe_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode);
+static FLAC__bool read_subframe_constant_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode);
+static FLAC__bool read_subframe_fixed_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, const uint32_t order, FLAC__bool do_full_decode);
+static FLAC__bool read_subframe_lpc_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, const uint32_t order, FLAC__bool do_full_decode);
+static FLAC__bool read_subframe_verbatim_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode);
+static FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, uint32_t predictor_order, uint32_t partition_order, FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, FLAC__int32 *residual, FLAC__bool is_extended);
+static FLAC__bool read_zero_padding_(FLAC__StreamDecoder *decoder);
+static FLAC__bool read_callback_(FLAC__byte buffer[], size_t *bytes, void *client_data);
+static FLAC__StreamDecoderWriteStatus write_audio_frame_to_client_(FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
+static void send_error_to_client_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status);
+static FLAC__bool seek_to_absolute_sample_(FLAC__StreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample);
+static FLAC__StreamDecoderReadStatus file_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
+static FLAC__StreamDecoderSeekStatus file_seek_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data);
+static FLAC__StreamDecoderTellStatus file_tell_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
+static FLAC__StreamDecoderLengthStatus file_length_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data);
+static FLAC__bool file_eof_callback_(const FLAC__StreamDecoder *decoder, void *client_data);
+
+/***********************************************************************
+ *
+ * Private class data
+ *
+ ***********************************************************************/
+
+typedef struct FLAC__StreamDecoderPrivate {
+	FLAC__bool is_ogg;
+	FLAC__StreamDecoderReadCallback read_callback;
+	FLAC__StreamDecoderSeekCallback seek_callback;
+	FLAC__StreamDecoderTellCallback tell_callback;
+	FLAC__StreamDecoderLengthCallback length_callback;
+	FLAC__StreamDecoderEofCallback eof_callback;
+	FLAC__StreamDecoderWriteCallback write_callback;
+	FLAC__StreamDecoderMetadataCallback metadata_callback;
+	FLAC__StreamDecoderErrorCallback error_callback;
+	/* generic 32-bit datapath: */
+	void (*local_lpc_restore_signal)(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]);
+	/* generic 64-bit datapath: */
+	void (*local_lpc_restore_signal_64bit)(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]);
+	/* for use when the signal is <= 16 bits-per-sample, or <= 15 bits-per-sample on a side channel (which requires 1 extra bit): */
+	void (*local_lpc_restore_signal_16bit)(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]);
+	void *client_data;
+	FILE *file; /* only used if FLAC__stream_decoder_init_file()/FLAC__stream_decoder_init_file() called, else NULL */
+	FLAC__BitReader *input;
+	FLAC__int32 *output[FLAC__MAX_CHANNELS];
+	FLAC__int32 *residual[FLAC__MAX_CHANNELS]; /* WATCHOUT: these are the aligned pointers; the real pointers that should be free()'d are residual_unaligned[] below */
+	FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents[FLAC__MAX_CHANNELS];
+	uint32_t output_capacity, output_channels;
+	FLAC__uint32 fixed_block_size, next_fixed_block_size;
+	FLAC__uint64 samples_decoded;
+	FLAC__bool has_stream_info, has_seek_table;
+	FLAC__StreamMetadata stream_info;
+	FLAC__StreamMetadata seek_table;
+	FLAC__bool metadata_filter[128]; /* MAGIC number 128 == total number of metadata block types == 1 << 7 */
+	FLAC__byte *metadata_filter_ids;
+	size_t metadata_filter_ids_count, metadata_filter_ids_capacity; /* units for both are IDs, not bytes */
+	FLAC__Frame frame;
+	FLAC__bool cached; /* true if there is a byte in lookahead */
+	FLAC__byte header_warmup[2]; /* contains the sync code and reserved bits */
+	FLAC__byte lookahead; /* temp storage when we need to look ahead one byte in the stream */
+	/* unaligned (original) pointers to allocated data */
+	FLAC__int32 *residual_unaligned[FLAC__MAX_CHANNELS];
+	FLAC__bool do_md5_checking; /* initially gets protected_->md5_checking but is turned off after a seek or if the metadata has a zero MD5 */
+	FLAC__bool internal_reset_hack; /* used only during init() so we can call reset to set up the decoder without rewinding the input */
+	FLAC__bool is_seeking;
+	FLAC__MD5Context md5context;
+	FLAC__byte computed_md5sum[16]; /* this is the sum we computed from the decoded data */
+	/* (the rest of these are only used for seeking) */
+	FLAC__Frame last_frame; /* holds the info of the last frame we seeked to */
+	FLAC__uint64 first_frame_offset; /* hint to the seek routine of where in the stream the first audio frame starts */
+	FLAC__uint64 target_sample;
+	uint32_t unparseable_frame_count; /* used to tell whether we're decoding a future version of FLAC or just got a bad sync */
+	FLAC__bool got_a_frame; /* hack needed in Ogg FLAC seek routine to check when process_single() actually writes a frame */
+} FLAC__StreamDecoderPrivate;
+
+/***********************************************************************
+ *
+ * Public static class data
+ *
+ ***********************************************************************/
+
+FLAC_API const char * const FLAC__StreamDecoderStateString[] = {
+	"FLAC__STREAM_DECODER_SEARCH_FOR_METADATA",
+	"FLAC__STREAM_DECODER_READ_METADATA",
+	"FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC",
+	"FLAC__STREAM_DECODER_READ_FRAME",
+	"FLAC__STREAM_DECODER_END_OF_STREAM",
+	"FLAC__STREAM_DECODER_OGG_ERROR",
+	"FLAC__STREAM_DECODER_SEEK_ERROR",
+	"FLAC__STREAM_DECODER_ABORTED",
+	"FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR",
+	"FLAC__STREAM_DECODER_UNINITIALIZED"
+};
+
+FLAC_API const char * const FLAC__StreamDecoderInitStatusString[] = {
+	"FLAC__STREAM_DECODER_INIT_STATUS_OK",
+	"FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER",
+	"FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS",
+	"FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR",
+	"FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE",
+	"FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED"
+};
+
+FLAC_API const char * const FLAC__StreamDecoderReadStatusString[] = {
+	"FLAC__STREAM_DECODER_READ_STATUS_CONTINUE",
+	"FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM",
+	"FLAC__STREAM_DECODER_READ_STATUS_ABORT"
+};
+
+FLAC_API const char * const FLAC__StreamDecoderSeekStatusString[] = {
+	"FLAC__STREAM_DECODER_SEEK_STATUS_OK",
+	"FLAC__STREAM_DECODER_SEEK_STATUS_ERROR",
+	"FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED"
+};
+
+FLAC_API const char * const FLAC__StreamDecoderTellStatusString[] = {
+	"FLAC__STREAM_DECODER_TELL_STATUS_OK",
+	"FLAC__STREAM_DECODER_TELL_STATUS_ERROR",
+	"FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED"
+};
+
+FLAC_API const char * const FLAC__StreamDecoderLengthStatusString[] = {
+	"FLAC__STREAM_DECODER_LENGTH_STATUS_OK",
+	"FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR",
+	"FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED"
+};
+
+FLAC_API const char * const FLAC__StreamDecoderWriteStatusString[] = {
+	"FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE",
+	"FLAC__STREAM_DECODER_WRITE_STATUS_ABORT"
+};
+
+FLAC_API const char * const FLAC__StreamDecoderErrorStatusString[] = {
+	"FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC",
+	"FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER",
+	"FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH",
+	"FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM"
+};
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ ***********************************************************************/
+FLAC_API FLAC__StreamDecoder *FLAC__stream_decoder_new(void)
+{
+	FLAC__StreamDecoder *decoder;
+	uint32_t i;
+
+	decoder = calloc(1, sizeof(FLAC__StreamDecoder));
+	if(decoder == 0) {
+		return 0;
+	}
+
+	decoder->protected_ = calloc(1, sizeof(FLAC__StreamDecoderProtected));
+	if(decoder->protected_ == 0) {
+		free(decoder);
+		return 0;
+	}
+
+	decoder->private_ = calloc(1, sizeof(FLAC__StreamDecoderPrivate));
+	if(decoder->private_ == 0) {
+		free(decoder->protected_);
+		free(decoder);
+		return 0;
+	}
+
+	decoder->private_->input = FLAC__bitreader_new();
+	if(decoder->private_->input == 0) {
+		free(decoder->private_);
+		free(decoder->protected_);
+		free(decoder);
+		return 0;
+	}
+
+	decoder->private_->metadata_filter_ids_capacity = 16;
+	if(0 == (decoder->private_->metadata_filter_ids = malloc((FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) * decoder->private_->metadata_filter_ids_capacity))) {
+		FLAC__bitreader_delete(decoder->private_->input);
+		free(decoder->private_);
+		free(decoder->protected_);
+		free(decoder);
+		return 0;
+	}
+
+	for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
+		decoder->private_->output[i] = 0;
+		decoder->private_->residual_unaligned[i] = decoder->private_->residual[i] = 0;
+	}
+
+	decoder->private_->output_capacity = 0;
+	decoder->private_->output_channels = 0;
+	decoder->private_->has_seek_table = false;
+
+	for(i = 0; i < FLAC__MAX_CHANNELS; i++)
+		FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&decoder->private_->partitioned_rice_contents[i]);
+
+	decoder->private_->file = 0;
+
+	set_defaults_(decoder);
+
+	decoder->protected_->state = FLAC__STREAM_DECODER_UNINITIALIZED;
+
+	return decoder;
+}
+
+FLAC_API void FLAC__stream_decoder_delete(FLAC__StreamDecoder *decoder)
+{
+	uint32_t i;
+
+	if (decoder == NULL)
+		return ;
+
+	(void)FLAC__stream_decoder_finish(decoder);
+
+	if(0 != decoder->private_->metadata_filter_ids)
+		free(decoder->private_->metadata_filter_ids);
+
+	FLAC__bitreader_delete(decoder->private_->input);
+
+	for(i = 0; i < FLAC__MAX_CHANNELS; i++)
+		FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&decoder->private_->partitioned_rice_contents[i]);
+
+	free(decoder->private_);
+	free(decoder->protected_);
+	free(decoder);
+}
+
+/***********************************************************************
+ *
+ * Public class methods
+ *
+ ***********************************************************************/
+
+static FLAC__StreamDecoderInitStatus init_stream_internal_(
+	FLAC__StreamDecoder *decoder,
+	FLAC__StreamDecoderReadCallback read_callback,
+	FLAC__StreamDecoderSeekCallback seek_callback,
+	FLAC__StreamDecoderTellCallback tell_callback,
+	FLAC__StreamDecoderLengthCallback length_callback,
+	FLAC__StreamDecoderEofCallback eof_callback,
+	FLAC__StreamDecoderWriteCallback write_callback,
+	FLAC__StreamDecoderMetadataCallback metadata_callback,
+	FLAC__StreamDecoderErrorCallback error_callback,
+	void *client_data,
+	FLAC__bool is_ogg
+)
+{
+	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+		return FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED;
+
+	if(is_ogg)
+		return FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER;
+
+	if(
+		0 == read_callback ||
+		0 == write_callback ||
+		0 == error_callback ||
+		(seek_callback && (0 == tell_callback || 0 == length_callback || 0 == eof_callback))
+	)
+		return FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS;
+
+	decoder->private_->local_lpc_restore_signal = FLAC__lpc_restore_signal;
+	decoder->private_->local_lpc_restore_signal_64bit = FLAC__lpc_restore_signal_wide;
+	decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal;
+
+	/* from here on, errors are fatal */
+
+	if(!FLAC__bitreader_init(decoder->private_->input, read_callback_, decoder)) {
+		decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+		return FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR;
+	}
+
+	decoder->private_->read_callback = read_callback;
+	decoder->private_->seek_callback = seek_callback;
+	decoder->private_->tell_callback = tell_callback;
+	decoder->private_->length_callback = length_callback;
+	decoder->private_->eof_callback = eof_callback;
+	decoder->private_->write_callback = write_callback;
+	decoder->private_->metadata_callback = metadata_callback;
+	decoder->private_->error_callback = error_callback;
+	decoder->private_->client_data = client_data;
+	decoder->private_->fixed_block_size = decoder->private_->next_fixed_block_size = 0;
+	decoder->private_->samples_decoded = 0;
+	decoder->private_->has_stream_info = false;
+	decoder->private_->cached = false;
+
+	decoder->private_->do_md5_checking = decoder->protected_->md5_checking;
+	decoder->private_->is_seeking = false;
+
+	decoder->private_->internal_reset_hack = true; /* so the following reset does not try to rewind the input */
+	if(!FLAC__stream_decoder_reset(decoder)) {
+		/* above call sets the state for us */
+		return FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR;
+	}
+
+	return FLAC__STREAM_DECODER_INIT_STATUS_OK;
+}
+
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_stream(
+	FLAC__StreamDecoder *decoder,
+	FLAC__StreamDecoderReadCallback read_callback,
+	FLAC__StreamDecoderSeekCallback seek_callback,
+	FLAC__StreamDecoderTellCallback tell_callback,
+	FLAC__StreamDecoderLengthCallback length_callback,
+	FLAC__StreamDecoderEofCallback eof_callback,
+	FLAC__StreamDecoderWriteCallback write_callback,
+	FLAC__StreamDecoderMetadataCallback metadata_callback,
+	FLAC__StreamDecoderErrorCallback error_callback,
+	void *client_data
+)
+{
+	return init_stream_internal_(
+		decoder,
+		read_callback,
+		seek_callback,
+		tell_callback,
+		length_callback,
+		eof_callback,
+		write_callback,
+		metadata_callback,
+		error_callback,
+		client_data,
+		/*is_ogg=*/false
+	);
+}
+
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_stream(
+	FLAC__StreamDecoder *decoder,
+	FLAC__StreamDecoderReadCallback read_callback,
+	FLAC__StreamDecoderSeekCallback seek_callback,
+	FLAC__StreamDecoderTellCallback tell_callback,
+	FLAC__StreamDecoderLengthCallback length_callback,
+	FLAC__StreamDecoderEofCallback eof_callback,
+	FLAC__StreamDecoderWriteCallback write_callback,
+	FLAC__StreamDecoderMetadataCallback metadata_callback,
+	FLAC__StreamDecoderErrorCallback error_callback,
+	void *client_data
+)
+{
+	return init_stream_internal_(
+		decoder,
+		read_callback,
+		seek_callback,
+		tell_callback,
+		length_callback,
+		eof_callback,
+		write_callback,
+		metadata_callback,
+		error_callback,
+		client_data,
+		/*is_ogg=*/true
+	);
+}
+
+static FLAC__StreamDecoderInitStatus init_FILE_internal_(
+	FLAC__StreamDecoder *decoder,
+	FILE *file,
+	FLAC__StreamDecoderWriteCallback write_callback,
+	FLAC__StreamDecoderMetadataCallback metadata_callback,
+	FLAC__StreamDecoderErrorCallback error_callback,
+	void *client_data,
+	FLAC__bool is_ogg
+)
+{
+	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+		return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED;
+
+	if(0 == write_callback || 0 == error_callback)
+		return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS;
+
+	/*
+	 * To make sure that our file does not go unclosed after an error, we
+	 * must assign the FILE pointer before any further error can occur in
+	 * this routine.
+	 */
+	if(file == stdin)
+		file = get_binary_stdin_(); /* just to be safe */
+
+	decoder->private_->file = file;
+
+	return init_stream_internal_(
+		decoder,
+		file_read_callback_,
+		decoder->private_->file == stdin? 0: file_seek_callback_,
+		decoder->private_->file == stdin? 0: file_tell_callback_,
+		decoder->private_->file == stdin? 0: file_length_callback_,
+		file_eof_callback_,
+		write_callback,
+		metadata_callback,
+		error_callback,
+		client_data,
+		is_ogg
+	);
+}
+
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_FILE(
+	FLAC__StreamDecoder *decoder,
+	FILE *file,
+	FLAC__StreamDecoderWriteCallback write_callback,
+	FLAC__StreamDecoderMetadataCallback metadata_callback,
+	FLAC__StreamDecoderErrorCallback error_callback,
+	void *client_data
+)
+{
+	return init_FILE_internal_(decoder, file, write_callback, metadata_callback, error_callback, client_data, /*is_ogg=*/false);
+}
+
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_FILE(
+	FLAC__StreamDecoder *decoder,
+	FILE *file,
+	FLAC__StreamDecoderWriteCallback write_callback,
+	FLAC__StreamDecoderMetadataCallback metadata_callback,
+	FLAC__StreamDecoderErrorCallback error_callback,
+	void *client_data
+)
+{
+	return init_FILE_internal_(decoder, file, write_callback, metadata_callback, error_callback, client_data, /*is_ogg=*/true);
+}
+
+static FLAC__StreamDecoderInitStatus init_file_internal_(
+	FLAC__StreamDecoder *decoder,
+	const char *filename,
+	FLAC__StreamDecoderWriteCallback write_callback,
+	FLAC__StreamDecoderMetadataCallback metadata_callback,
+	FLAC__StreamDecoderErrorCallback error_callback,
+	void *client_data,
+	FLAC__bool is_ogg
+)
+{
+	FILE *file;
+
+	/*
+	 * To make sure that our file does not go unclosed after an error, we
+	 * have to do the same entrance checks here that are later performed
+	 * in FLAC__stream_decoder_init_FILE() before the FILE* is assigned.
+	 */
+	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+		return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED;
+
+	if(0 == write_callback || 0 == error_callback)
+		return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS;
+
+	file = filename? flac_fopen(filename, "rb") : stdin;
+
+	if(0 == file)
+		return FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE;
+
+	return init_FILE_internal_(decoder, file, write_callback, metadata_callback, error_callback, client_data, is_ogg);
+}
+
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_file(
+	FLAC__StreamDecoder *decoder,
+	const char *filename,
+	FLAC__StreamDecoderWriteCallback write_callback,
+	FLAC__StreamDecoderMetadataCallback metadata_callback,
+	FLAC__StreamDecoderErrorCallback error_callback,
+	void *client_data
+)
+{
+	return init_file_internal_(decoder, filename, write_callback, metadata_callback, error_callback, client_data, /*is_ogg=*/false);
+}
+
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_file(
+	FLAC__StreamDecoder *decoder,
+	const char *filename,
+	FLAC__StreamDecoderWriteCallback write_callback,
+	FLAC__StreamDecoderMetadataCallback metadata_callback,
+	FLAC__StreamDecoderErrorCallback error_callback,
+	void *client_data
+)
+{
+	return init_file_internal_(decoder, filename, write_callback, metadata_callback, error_callback, client_data, /*is_ogg=*/true);
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_finish(FLAC__StreamDecoder *decoder)
+{
+	FLAC__bool md5_failed = false;
+	uint32_t i;
+
+	if(decoder->protected_->state == FLAC__STREAM_DECODER_UNINITIALIZED)
+		return true;
+
+	/* see the comment in FLAC__stream_decoder_reset() as to why we
+	 * always call FLAC__MD5Final()
+	 */
+	FLAC__MD5Final(decoder->private_->computed_md5sum, &decoder->private_->md5context);
+
+	free(decoder->private_->seek_table.data.seek_table.points);
+	decoder->private_->seek_table.data.seek_table.points = 0;
+	decoder->private_->has_seek_table = false;
+
+	FLAC__bitreader_free(decoder->private_->input);
+	for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
+		/* WATCHOUT:
+		 * FLAC__lpc_restore_signal_asm_ia32_mmx() and ..._intrin_sseN()
+		 * require that the output arrays have a buffer of up to 3 zeroes
+		 * in front (at negative indices) for alignment purposes;
+		 * we use 4 to keep the data well-aligned.
+		 */
+		if(0 != decoder->private_->output[i]) {
+			free(decoder->private_->output[i]-4);
+			decoder->private_->output[i] = 0;
+		}
+		if(0 != decoder->private_->residual_unaligned[i]) {
+			free(decoder->private_->residual_unaligned[i]);
+			decoder->private_->residual_unaligned[i] = decoder->private_->residual[i] = 0;
+		}
+	}
+	decoder->private_->output_capacity = 0;
+	decoder->private_->output_channels = 0;
+
+	if(0 != decoder->private_->file) {
+		if(decoder->private_->file != stdin)
+			fclose(decoder->private_->file);
+		decoder->private_->file = 0;
+	}
+
+	if(decoder->private_->do_md5_checking) {
+		if(memcmp(decoder->private_->stream_info.data.stream_info.md5sum, decoder->private_->computed_md5sum, 16))
+			md5_failed = true;
+	}
+	decoder->private_->is_seeking = false;
+
+	set_defaults_(decoder);
+
+	decoder->protected_->state = FLAC__STREAM_DECODER_UNINITIALIZED;
+
+	return !md5_failed;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_ogg_serial_number(FLAC__StreamDecoder *decoder, long value)
+{
+	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+		return false;
+
+	(void)value;
+	return false;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_md5_checking(FLAC__StreamDecoder *decoder, FLAC__bool value)
+{
+	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+		return false;
+	decoder->protected_->md5_checking = value;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond(FLAC__StreamDecoder *decoder, FLAC__MetadataType type)
+{
+	/* double protection */
+	if((uint32_t)type > FLAC__MAX_METADATA_TYPE_CODE)
+		return false;
+	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+		return false;
+	decoder->private_->metadata_filter[type] = true;
+	if(type == FLAC__METADATA_TYPE_APPLICATION)
+		decoder->private_->metadata_filter_ids_count = 0;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4])
+{
+	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+		return false;
+
+	if(decoder->private_->metadata_filter[FLAC__METADATA_TYPE_APPLICATION])
+		return true;
+
+	if(decoder->private_->metadata_filter_ids_count == decoder->private_->metadata_filter_ids_capacity) {
+		if(0 == (decoder->private_->metadata_filter_ids = safe_realloc_mul_2op_(decoder->private_->metadata_filter_ids, decoder->private_->metadata_filter_ids_capacity, /*times*/2))) {
+			decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+			return false;
+		}
+		decoder->private_->metadata_filter_ids_capacity *= 2;
+	}
+
+	memcpy(decoder->private_->metadata_filter_ids + decoder->private_->metadata_filter_ids_count * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8));
+	decoder->private_->metadata_filter_ids_count++;
+
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_all(FLAC__StreamDecoder *decoder)
+{
+	uint32_t i;
+	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+		return false;
+	for(i = 0; i < sizeof(decoder->private_->metadata_filter) / sizeof(decoder->private_->metadata_filter[0]); i++)
+		decoder->private_->metadata_filter[i] = true;
+	decoder->private_->metadata_filter_ids_count = 0;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore(FLAC__StreamDecoder *decoder, FLAC__MetadataType type)
+{
+	/* double protection */
+	if((uint32_t)type > FLAC__MAX_METADATA_TYPE_CODE)
+		return false;
+	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+		return false;
+	decoder->private_->metadata_filter[type] = false;
+	if(type == FLAC__METADATA_TYPE_APPLICATION)
+		decoder->private_->metadata_filter_ids_count = 0;
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4])
+{
+	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+		return false;
+
+	if(!decoder->private_->metadata_filter[FLAC__METADATA_TYPE_APPLICATION])
+		return true;
+
+	if(decoder->private_->metadata_filter_ids_count == decoder->private_->metadata_filter_ids_capacity) {
+		if(0 == (decoder->private_->metadata_filter_ids = safe_realloc_mul_2op_(decoder->private_->metadata_filter_ids, decoder->private_->metadata_filter_ids_capacity, /*times*/2))) {
+			decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+			return false;
+		}
+		decoder->private_->metadata_filter_ids_capacity *= 2;
+	}
+
+	memcpy(decoder->private_->metadata_filter_ids + decoder->private_->metadata_filter_ids_count * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8));
+	decoder->private_->metadata_filter_ids_count++;
+
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_all(FLAC__StreamDecoder *decoder)
+{
+	if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+		return false;
+	memset(decoder->private_->metadata_filter, 0, sizeof(decoder->private_->metadata_filter));
+	decoder->private_->metadata_filter_ids_count = 0;
+	return true;
+}
+
+FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_get_state(const FLAC__StreamDecoder *decoder)
+{
+	return decoder->protected_->state;
+}
+
+FLAC_API const char *FLAC__stream_decoder_get_resolved_state_string(const FLAC__StreamDecoder *decoder)
+{
+	return FLAC__StreamDecoderStateString[decoder->protected_->state];
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_get_md5_checking(const FLAC__StreamDecoder *decoder)
+{
+	return decoder->protected_->md5_checking;
+}
+
+FLAC_API FLAC__uint64 FLAC__stream_decoder_get_total_samples(const FLAC__StreamDecoder *decoder)
+{
+	return decoder->private_->has_stream_info? decoder->private_->stream_info.data.stream_info.total_samples : 0;
+}
+
+FLAC_API uint32_t FLAC__stream_decoder_get_channels(const FLAC__StreamDecoder *decoder)
+{
+	return decoder->protected_->channels;
+}
+
+FLAC_API FLAC__ChannelAssignment FLAC__stream_decoder_get_channel_assignment(const FLAC__StreamDecoder *decoder)
+{
+	return decoder->protected_->channel_assignment;
+}
+
+FLAC_API uint32_t FLAC__stream_decoder_get_bits_per_sample(const FLAC__StreamDecoder *decoder)
+{
+	return decoder->protected_->bits_per_sample;
+}
+
+FLAC_API uint32_t FLAC__stream_decoder_get_sample_rate(const FLAC__StreamDecoder *decoder)
+{
+	return decoder->protected_->sample_rate;
+}
+
+FLAC_API uint32_t FLAC__stream_decoder_get_blocksize(const FLAC__StreamDecoder *decoder)
+{
+	return decoder->protected_->blocksize;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_get_decode_position(const FLAC__StreamDecoder *decoder, FLAC__uint64 *position)
+{
+	if(0 == decoder->private_->tell_callback)
+		return false;
+	if(decoder->private_->tell_callback(decoder, position, decoder->private_->client_data) != FLAC__STREAM_DECODER_TELL_STATUS_OK)
+		return false;
+	/* should never happen since all FLAC frames and metadata blocks are byte aligned, but check just in case */
+	if(!FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input))
+		return false;
+	*position -= FLAC__stream_decoder_get_input_bytes_unconsumed(decoder);
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_flush(FLAC__StreamDecoder *decoder)
+{
+	if(!decoder->private_->internal_reset_hack && decoder->protected_->state == FLAC__STREAM_DECODER_UNINITIALIZED)
+		return false;
+
+	decoder->private_->samples_decoded = 0;
+	decoder->private_->do_md5_checking = false;
+
+	if(!FLAC__bitreader_clear(decoder->private_->input)) {
+		decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+		return false;
+	}
+	decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_reset(FLAC__StreamDecoder *decoder)
+{
+	if(!FLAC__stream_decoder_flush(decoder)) {
+		/* above call sets the state for us */
+		return false;
+	}
+
+	/* Rewind if necessary.  If FLAC__stream_decoder_init() is calling us,
+	 * (internal_reset_hack) don't try to rewind since we are already at
+	 * the beginning of the stream and don't want to fail if the input is
+	 * not seekable.
+	 */
+	if(!decoder->private_->internal_reset_hack) {
+		if(decoder->private_->file == stdin)
+			return false; /* can't rewind stdin, reset fails */
+		if(decoder->private_->seek_callback && decoder->private_->seek_callback(decoder, 0, decoder->private_->client_data) == FLAC__STREAM_DECODER_SEEK_STATUS_ERROR)
+			return false; /* seekable and seek fails, reset fails */
+	}
+	else
+		decoder->private_->internal_reset_hack = false;
+
+	decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_METADATA;
+
+	decoder->private_->has_stream_info = false;
+
+	free(decoder->private_->seek_table.data.seek_table.points);
+	decoder->private_->seek_table.data.seek_table.points = 0;
+	decoder->private_->has_seek_table = false;
+
+	decoder->private_->do_md5_checking = decoder->protected_->md5_checking;
+	/*
+	 * This goes in reset() and not flush() because according to the spec, a
+	 * fixed-blocksize stream must stay that way through the whole stream.
+	 */
+	decoder->private_->fixed_block_size = decoder->private_->next_fixed_block_size = 0;
+
+	/* We initialize the FLAC__MD5Context even though we may never use it.  This
+	 * is because md5 checking may be turned on to start and then turned off if
+	 * a seek occurs.  So we init the context here and finalize it in
+	 * FLAC__stream_decoder_finish() to make sure things are always cleaned up
+	 * properly.
+	 */
+	FLAC__MD5Init(&decoder->private_->md5context);
+
+	decoder->private_->first_frame_offset = 0;
+	decoder->private_->unparseable_frame_count = 0;
+
+	return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_process_single(FLAC__StreamDecoder *decoder)
+{
+	FLAC__bool got_a_frame;
+
+	while(1) {
+		switch(decoder->protected_->state) {
+			case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
+				if(!find_metadata_(decoder))
+					return false; /* above function sets the status for us */
+				break;
+			case FLAC__STREAM_DECODER_READ_METADATA:
+				if(!read_metadata_(decoder))
+					return false; /* above function sets the status for us */
+				else
+					return true;
+			case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
+				if(!frame_sync_(decoder))
+					return true; /* above function sets the status for us */
+				break;
+			case FLAC__STREAM_DECODER_READ_FRAME:
+				if(!read_frame_(decoder, &got_a_frame, /*do_full_decode=*/true))
+					return false; /* above function sets the status for us */
+				if(got_a_frame)
+					return true; /* above function sets the status for us */
+				break;
+			case FLAC__STREAM_DECODER_END_OF_STREAM:
+			case FLAC__STREAM_DECODER_ABORTED:
+				return true;
+			default:
+				return false;
+		}
+	}
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_metadata(FLAC__StreamDecoder *decoder)
+{
+	while(1) {
+		switch(decoder->protected_->state) {
+			case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
+				if(!find_metadata_(decoder))
+					return false; /* above function sets the status for us */
+				break;
+			case FLAC__STREAM_DECODER_READ_METADATA:
+				if(!read_metadata_(decoder))
+					return false; /* above function sets the status for us */
+				break;
+			case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
+			case FLAC__STREAM_DECODER_READ_FRAME:
+			case FLAC__STREAM_DECODER_END_OF_STREAM:
+			case FLAC__STREAM_DECODER_ABORTED:
+				return true;
+			default:
+				return false;
+		}
+	}
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_stream(FLAC__StreamDecoder *decoder)
+{
+	FLAC__bool dummy;
+
+	while(1) {
+		switch(decoder->protected_->state) {
+			case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
+				if(!find_metadata_(decoder))
+					return false; /* above function sets the status for us */
+				break;
+			case FLAC__STREAM_DECODER_READ_METADATA:
+				if(!read_metadata_(decoder))
+					return false; /* above function sets the status for us */
+				break;
+			case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
+				if(!frame_sync_(decoder))
+					return true; /* above function sets the status for us */
+				break;
+			case FLAC__STREAM_DECODER_READ_FRAME:
+				if(!read_frame_(decoder, &dummy, /*do_full_decode=*/true))
+					return false; /* above function sets the status for us */
+				break;
+			case FLAC__STREAM_DECODER_END_OF_STREAM:
+			case FLAC__STREAM_DECODER_ABORTED:
+				return true;
+			default:
+				return false;
+		}
+	}
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_skip_single_frame(FLAC__StreamDecoder *decoder)
+{
+	FLAC__bool got_a_frame;
+
+	while(1) {
+		switch(decoder->protected_->state) {
+			case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
+			case FLAC__STREAM_DECODER_READ_METADATA:
+				return false; /* above function sets the status for us */
+			case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
+				if(!frame_sync_(decoder))
+					return true; /* above function sets the status for us */
+				break;
+			case FLAC__STREAM_DECODER_READ_FRAME:
+				if(!read_frame_(decoder, &got_a_frame, /*do_full_decode=*/false))
+					return false; /* above function sets the status for us */
+				if(got_a_frame)
+					return true; /* above function sets the status for us */
+				break;
+			case FLAC__STREAM_DECODER_END_OF_STREAM:
+			case FLAC__STREAM_DECODER_ABORTED:
+				return true;
+			default:
+				return false;
+		}
+	}
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_seek_absolute(FLAC__StreamDecoder *decoder, FLAC__uint64 sample)
+{
+	FLAC__uint64 length;
+
+	if(
+		decoder->protected_->state != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA &&
+		decoder->protected_->state != FLAC__STREAM_DECODER_READ_METADATA &&
+		decoder->protected_->state != FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC &&
+		decoder->protected_->state != FLAC__STREAM_DECODER_READ_FRAME &&
+		decoder->protected_->state != FLAC__STREAM_DECODER_END_OF_STREAM
+	)
+		return false;
+
+	if(0 == decoder->private_->seek_callback)
+		return false;
+
+	if(FLAC__stream_decoder_get_total_samples(decoder) > 0 && sample >= FLAC__stream_decoder_get_total_samples(decoder))
+		return false;
+
+	decoder->private_->is_seeking = true;
+
+	/* turn off md5 checking if a seek is attempted */
+	decoder->private_->do_md5_checking = false;
+
+	/* get the file length (currently our algorithm needs to know the length so it's also an error to get FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED) */
+	if(decoder->private_->length_callback(decoder, &length, decoder->private_->client_data) != FLAC__STREAM_DECODER_LENGTH_STATUS_OK) {
+		decoder->private_->is_seeking = false;
+		return false;
+	}
+
+	/* if we haven't finished processing the metadata yet, do that so we have the STREAMINFO, SEEK_TABLE, and first_frame_offset */
+	if(
+		decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_METADATA ||
+		decoder->protected_->state == FLAC__STREAM_DECODER_READ_METADATA
+	) {
+		if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder)) {
+			/* above call sets the state for us */
+			decoder->private_->is_seeking = false;
+			return false;
+		}
+		/* check this again in case we didn't know total_samples the first time */
+		if(FLAC__stream_decoder_get_total_samples(decoder) > 0 && sample >= FLAC__stream_decoder_get_total_samples(decoder)) {
+			decoder->private_->is_seeking = false;
+			return false;
+		}
+	}
+
+	{
+		const FLAC__bool ok = seek_to_absolute_sample_(decoder, length, sample);
+		decoder->private_->is_seeking = false;
+		return ok;
+	}
+}
+
+/***********************************************************************
+ *
+ * Protected class methods
+ *
+ ***********************************************************************/
+
+uint32_t FLAC__stream_decoder_get_input_bytes_unconsumed(const FLAC__StreamDecoder *decoder)
+{
+	return FLAC__bitreader_get_input_bits_unconsumed(decoder->private_->input) / 8;
+}
+
+/***********************************************************************
+ *
+ * Private class methods
+ *
+ ***********************************************************************/
+
+void set_defaults_(FLAC__StreamDecoder *decoder)
+{
+	decoder->private_->is_ogg = false;
+	decoder->private_->read_callback = 0;
+	decoder->private_->seek_callback = 0;
+	decoder->private_->tell_callback = 0;
+	decoder->private_->length_callback = 0;
+	decoder->private_->eof_callback = 0;
+	decoder->private_->write_callback = 0;
+	decoder->private_->metadata_callback = 0;
+	decoder->private_->error_callback = 0;
+	decoder->private_->client_data = 0;
+
+	memset(decoder->private_->metadata_filter, 0, sizeof(decoder->private_->metadata_filter));
+	decoder->private_->metadata_filter[FLAC__METADATA_TYPE_STREAMINFO] = true;
+	decoder->private_->metadata_filter_ids_count = 0;
+
+	decoder->protected_->md5_checking = false;
+}
+
+/*
+ * This will forcibly set stdin to binary mode (for OSes that require it)
+ */
+FILE *get_binary_stdin_(void)
+{
+	/* if something breaks here it is probably due to the presence or
+	 * absence of an underscore before the identifiers 'setmode',
+	 * 'fileno', and/or 'O_BINARY'; check your system header files.
+	 */
+#if defined _MSC_VER || defined __MINGW32__
+	_setmode(_fileno(stdin), _O_BINARY);
+#elif defined __EMX__
+	setmode(fileno(stdin), O_BINARY);
+#endif
+
+	return stdin;
+}
+
+FLAC__bool allocate_output_(FLAC__StreamDecoder *decoder, uint32_t size, uint32_t channels)
+{
+	uint32_t i;
+	FLAC__int32 *tmp;
+
+	if(size <= decoder->private_->output_capacity && channels <= decoder->private_->output_channels)
+		return true;
+
+	/* simply using realloc() is not practical because the number of channels may change mid-stream */
+
+	for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
+		if(0 != decoder->private_->output[i]) {
+			free(decoder->private_->output[i]-4);
+			decoder->private_->output[i] = 0;
+		}
+		if(0 != decoder->private_->residual_unaligned[i]) {
+			free(decoder->private_->residual_unaligned[i]);
+			decoder->private_->residual_unaligned[i] = decoder->private_->residual[i] = 0;
+		}
+	}
+
+	for(i = 0; i < channels; i++) {
+		/* WATCHOUT:
+		 * FLAC__lpc_restore_signal_asm_ia32_mmx() and ..._intrin_sseN()
+		 * require that the output arrays have a buffer of up to 3 zeroes
+		 * in front (at negative indices) for alignment purposes;
+		 * we use 4 to keep the data well-aligned.
+		 */
+		tmp = safe_malloc_muladd2_(sizeof(FLAC__int32), /*times (*/size, /*+*/4/*)*/);
+		if(tmp == 0) {
+			decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+			return false;
+		}
+		memset(tmp, 0, sizeof(FLAC__int32)*4);
+		decoder->private_->output[i] = tmp + 4;
+
+		if(!FLAC__memory_alloc_aligned_int32_array(size, &decoder->private_->residual_unaligned[i], &decoder->private_->residual[i])) {
+			decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+			return false;
+		}
+	}
+
+	decoder->private_->output_capacity = size;
+	decoder->private_->output_channels = channels;
+
+	return true;
+}
+
+FLAC__bool has_id_filtered_(FLAC__StreamDecoder *decoder, FLAC__byte *id)
+{
+	size_t i;
+
+	for(i = 0; i < decoder->private_->metadata_filter_ids_count; i++)
+		if(0 == memcmp(decoder->private_->metadata_filter_ids + i * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8)))
+			return true;
+
+	return false;
+}
+
+FLAC__bool find_metadata_(FLAC__StreamDecoder *decoder)
+{
+	FLAC__uint32 x;
+	uint32_t i, id;
+	FLAC__bool first = true;
+
+	for(i = id = 0; i < 4; ) {
+		if(decoder->private_->cached) {
+			x = (FLAC__uint32)decoder->private_->lookahead;
+			decoder->private_->cached = false;
+		}
+		else {
+			if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+				return false; /* read_callback_ sets the state for us */
+		}
+		if(x == FLAC__STREAM_SYNC_STRING[i]) {
+			first = true;
+			i++;
+			id = 0;
+			continue;
+		}
+
+		if(id >= 3)
+			return false;
+
+		if(x == ID3V2_TAG_[id]) {
+			id++;
+			i = 0;
+			if(id == 3) {
+				if(!skip_id3v2_tag_(decoder))
+					return false; /* skip_id3v2_tag_ sets the state for us */
+			}
+			continue;
+		}
+		id = 0;
+		if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */
+			decoder->private_->header_warmup[0] = (FLAC__byte)x;
+			if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+				return false; /* read_callback_ sets the state for us */
+
+			/* we have to check if we just read two 0xff's in a row; the second may actually be the beginning of the sync code */
+			/* else we have to check if the second byte is the end of a sync code */
+			if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */
+				decoder->private_->lookahead = (FLAC__byte)x;
+				decoder->private_->cached = true;
+			}
+			else if(x >> 1 == 0x7c) { /* MAGIC NUMBER for the last 6 sync bits and reserved 7th bit */
+				decoder->private_->header_warmup[1] = (FLAC__byte)x;
+				decoder->protected_->state = FLAC__STREAM_DECODER_READ_FRAME;
+				return true;
+			}
+		}
+		i = 0;
+		if(first) {
+			send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+			first = false;
+		}
+	}
+
+	decoder->protected_->state = FLAC__STREAM_DECODER_READ_METADATA;
+	return true;
+}
+
+FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder)
+{
+	FLAC__bool is_last;
+	FLAC__uint32 i, x, type, length;
+
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_IS_LAST_LEN))
+		return false; /* read_callback_ sets the state for us */
+	is_last = x? true : false;
+
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &type, FLAC__STREAM_METADATA_TYPE_LEN))
+		return false; /* read_callback_ sets the state for us */
+
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &length, FLAC__STREAM_METADATA_LENGTH_LEN))
+		return false; /* read_callback_ sets the state for us */
+
+	if(type == FLAC__METADATA_TYPE_STREAMINFO) {
+		if(!read_metadata_streaminfo_(decoder, is_last, length))
+			return false;
+
+		decoder->private_->has_stream_info = true;
+		if(0 == memcmp(decoder->private_->stream_info.data.stream_info.md5sum, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16))
+			decoder->private_->do_md5_checking = false;
+		if(!decoder->private_->is_seeking && decoder->private_->metadata_filter[FLAC__METADATA_TYPE_STREAMINFO] && decoder->private_->metadata_callback)
+			decoder->private_->metadata_callback(decoder, &decoder->private_->stream_info, decoder->private_->client_data);
+	}
+	else if(type == FLAC__METADATA_TYPE_SEEKTABLE) {
+		/* just in case we already have a seek table, and reading the next one fails: */
+		decoder->private_->has_seek_table = false;
+
+		if(!read_metadata_seektable_(decoder, is_last, length))
+			return false;
+
+		decoder->private_->has_seek_table = true;
+		if(!decoder->private_->is_seeking && decoder->private_->metadata_filter[FLAC__METADATA_TYPE_SEEKTABLE] && decoder->private_->metadata_callback)
+			decoder->private_->metadata_callback(decoder, &decoder->private_->seek_table, decoder->private_->client_data);
+	}
+	else {
+		FLAC__bool skip_it = !decoder->private_->metadata_filter[type];
+		uint32_t real_length = length;
+		FLAC__StreamMetadata block;
+
+		memset(&block, 0, sizeof(block));
+		block.is_last = is_last;
+		block.type = (FLAC__MetadataType)type;
+		block.length = length;
+
+		if(type == FLAC__METADATA_TYPE_APPLICATION) {
+			if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8))
+				return false; /* read_callback_ sets the state for us */
+
+			if(real_length < FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) { /* underflow check */
+				decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;/*@@@@@@ maybe wrong error? need to resync?*/
+				return false;
+			}
+
+			real_length -= FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8;
+
+			if(decoder->private_->metadata_filter_ids_count > 0 && has_id_filtered_(decoder, block.data.application.id))
+				skip_it = !skip_it;
+		}
+
+		if(skip_it) {
+			if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, real_length))
+				return false; /* read_callback_ sets the state for us */
+		}
+		else {
+			FLAC__bool ok = true;
+			switch(type) {
+				case FLAC__METADATA_TYPE_PADDING:
+					/* skip the padding bytes */
+					if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, real_length))
+						ok = false; /* read_callback_ sets the state for us */
+					break;
+				case FLAC__METADATA_TYPE_APPLICATION:
+					/* remember, we read the ID already */
+					if(real_length > 0) {
+						if(0 == (block.data.application.data = malloc(real_length))) {
+							decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+							ok = false;
+						}
+						else if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.application.data, real_length))
+							ok = false; /* read_callback_ sets the state for us */
+					}
+					else
+						block.data.application.data = 0;
+					break;
+				case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+					if(!read_metadata_vorbiscomment_(decoder, &block.data.vorbis_comment, real_length))
+						ok = false;
+					break;
+				case FLAC__METADATA_TYPE_CUESHEET:
+					if(!read_metadata_cuesheet_(decoder, &block.data.cue_sheet))
+						ok = false;
+					break;
+				case FLAC__METADATA_TYPE_PICTURE:
+					if(!read_metadata_picture_(decoder, &block.data.picture))
+						ok = false;
+					break;
+				case FLAC__METADATA_TYPE_STREAMINFO:
+				case FLAC__METADATA_TYPE_SEEKTABLE:
+					break;
+				default:
+					if(real_length > 0) {
+						if(0 == (block.data.unknown.data = malloc(real_length))) {
+							decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+							ok = false;
+						}
+						else if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.unknown.data, real_length))
+							ok = false; /* read_callback_ sets the state for us */
+					}
+					else
+						block.data.unknown.data = 0;
+					break;
+			}
+			if(ok && !decoder->private_->is_seeking && decoder->private_->metadata_callback)
+				decoder->private_->metadata_callback(decoder, &block, decoder->private_->client_data);
+
+			/* now we have to free any malloc()ed data in the block */
+			switch(type) {
+				case FLAC__METADATA_TYPE_PADDING:
+					break;
+				case FLAC__METADATA_TYPE_APPLICATION:
+					if(0 != block.data.application.data)
+						free(block.data.application.data);
+					break;
+				case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+					if(0 != block.data.vorbis_comment.vendor_string.entry)
+						free(block.data.vorbis_comment.vendor_string.entry);
+					if(block.data.vorbis_comment.num_comments > 0)
+						for(i = 0; i < block.data.vorbis_comment.num_comments; i++)
+							if(0 != block.data.vorbis_comment.comments[i].entry)
+								free(block.data.vorbis_comment.comments[i].entry);
+					if(0 != block.data.vorbis_comment.comments)
+						free(block.data.vorbis_comment.comments);
+					break;
+				case FLAC__METADATA_TYPE_CUESHEET:
+					if(block.data.cue_sheet.num_tracks > 0)
+						for(i = 0; i < block.data.cue_sheet.num_tracks; i++)
+							if(0 != block.data.cue_sheet.tracks[i].indices)
+								free(block.data.cue_sheet.tracks[i].indices);
+					if(0 != block.data.cue_sheet.tracks)
+						free(block.data.cue_sheet.tracks);
+					break;
+				case FLAC__METADATA_TYPE_PICTURE:
+					if(0 != block.data.picture.mime_type)
+						free(block.data.picture.mime_type);
+					if(0 != block.data.picture.description)
+						free(block.data.picture.description);
+					if(0 != block.data.picture.data)
+						free(block.data.picture.data);
+					break;
+				case FLAC__METADATA_TYPE_STREAMINFO:
+				case FLAC__METADATA_TYPE_SEEKTABLE:
+				default:
+					if(0 != block.data.unknown.data)
+						free(block.data.unknown.data);
+					break;
+			}
+
+			if(!ok) /* anything that unsets "ok" should also make sure decoder->protected_->state is updated */
+				return false;
+		}
+	}
+
+	if(is_last) {
+		/* if this fails, it's OK, it's just a hint for the seek routine */
+		if(!FLAC__stream_decoder_get_decode_position(decoder, &decoder->private_->first_frame_offset))
+			decoder->private_->first_frame_offset = 0;
+		decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+	}
+
+	return true;
+}
+
+FLAC__bool read_metadata_streaminfo_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, uint32_t length)
+{
+	FLAC__uint32 x;
+	uint32_t bits, used_bits = 0;
+
+	decoder->private_->stream_info.type = FLAC__METADATA_TYPE_STREAMINFO;
+	decoder->private_->stream_info.is_last = is_last;
+	decoder->private_->stream_info.length = length;
+
+	bits = FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN;
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, bits))
+		return false; /* read_callback_ sets the state for us */
+	decoder->private_->stream_info.data.stream_info.min_blocksize = x;
+	used_bits += bits;
+
+	bits = FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN;
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN))
+		return false; /* read_callback_ sets the state for us */
+	decoder->private_->stream_info.data.stream_info.max_blocksize = x;
+	used_bits += bits;
+
+	bits = FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN;
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN))
+		return false; /* read_callback_ sets the state for us */
+	decoder->private_->stream_info.data.stream_info.min_framesize = x;
+	used_bits += bits;
+
+	bits = FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN;
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN))
+		return false; /* read_callback_ sets the state for us */
+	decoder->private_->stream_info.data.stream_info.max_framesize = x;
+	used_bits += bits;
+
+	bits = FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN;
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN))
+		return false; /* read_callback_ sets the state for us */
+	decoder->private_->stream_info.data.stream_info.sample_rate = x;
+	used_bits += bits;
+
+	bits = FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN;
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN))
+		return false; /* read_callback_ sets the state for us */
+	decoder->private_->stream_info.data.stream_info.channels = x+1;
+	used_bits += bits;
+
+	bits = FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN;
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN))
+		return false; /* read_callback_ sets the state for us */
+	decoder->private_->stream_info.data.stream_info.bits_per_sample = x+1;
+	used_bits += bits;
+
+	bits = FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN;
+	if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &decoder->private_->stream_info.data.stream_info.total_samples, FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN))
+		return false; /* read_callback_ sets the state for us */
+	used_bits += bits;
+
+	if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, decoder->private_->stream_info.data.stream_info.md5sum, 16))
+		return false; /* read_callback_ sets the state for us */
+	used_bits += 16*8;
+
+	/* skip the rest of the block */
+	length -= (used_bits / 8);
+	if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, length))
+		return false; /* read_callback_ sets the state for us */
+
+	return true;
+}
+
+FLAC__bool read_metadata_seektable_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, uint32_t length)
+{
+	FLAC__uint32 i, x;
+	FLAC__uint64 xx;
+
+	decoder->private_->seek_table.type = FLAC__METADATA_TYPE_SEEKTABLE;
+	decoder->private_->seek_table.is_last = is_last;
+	decoder->private_->seek_table.length = length;
+
+	decoder->private_->seek_table.data.seek_table.num_points = length / FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
+
+	/* use realloc since we may pass through here several times (e.g. after seeking) */
+	if(0 == (decoder->private_->seek_table.data.seek_table.points = safe_realloc_mul_2op_(decoder->private_->seek_table.data.seek_table.points, decoder->private_->seek_table.data.seek_table.num_points, /*times*/sizeof(FLAC__StreamMetadata_SeekPoint)))) {
+		decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+		return false;
+	}
+	for(i = 0; i < decoder->private_->seek_table.data.seek_table.num_points; i++) {
+		if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &xx, FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN))
+			return false; /* read_callback_ sets the state for us */
+		decoder->private_->seek_table.data.seek_table.points[i].sample_number = xx;
+
+		if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &xx, FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN))
+			return false; /* read_callback_ sets the state for us */
+		decoder->private_->seek_table.data.seek_table.points[i].stream_offset = xx;
+
+		if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN))
+			return false; /* read_callback_ sets the state for us */
+		decoder->private_->seek_table.data.seek_table.points[i].frame_samples = x;
+	}
+	length -= (decoder->private_->seek_table.data.seek_table.num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH);
+	/* if there is a partial point left, skip over it */
+	if(length > 0) {
+		/*@@@ do a send_error_to_client_() here?  there's an argument for either way */
+		if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, length))
+			return false; /* read_callback_ sets the state for us */
+	}
+
+	return true;
+}
+
+FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_VorbisComment *obj, uint32_t length)
+{
+	FLAC__uint32 i;
+
+	/* read vendor string */
+	if (length >= 8) {
+		length -= 8; /* vendor string length + num comments entries alone take 8 bytes */
+		if (!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->vendor_string.length))
+			return false; /* read_callback_ sets the state for us */
+		if (obj->vendor_string.length > 0) {
+			if (length < obj->vendor_string.length) {
+				obj->vendor_string.length = 0;
+				obj->vendor_string.entry = 0;
+				goto skip;
+			}
+			else
+				length -= obj->vendor_string.length;
+			if (0 == (obj->vendor_string.entry = safe_malloc_add_2op_(obj->vendor_string.length, /*+*/1))) {
+				decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+				return false;
+			}
+			if (!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->vendor_string.entry, obj->vendor_string.length))
+				return false; /* read_callback_ sets the state for us */
+			obj->vendor_string.entry[obj->vendor_string.length] = '\0';
+		}
+		else
+			obj->vendor_string.entry = 0;
+
+		/* read num comments */
+		if (!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->num_comments))
+			return false; /* read_callback_ sets the state for us */
+
+		/* read comments */
+		if (obj->num_comments > 100000) {
+			/* Possibly malicious file. */
+			obj->num_comments = 0;
+			return false;
+		}
+		if (obj->num_comments > 0) {
+			if (0 == (obj->comments = safe_malloc_mul_2op_p(obj->num_comments, /*times*/sizeof(FLAC__StreamMetadata_VorbisComment_Entry)))) {
+				obj->num_comments = 0;
+				decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+				return false;
+			}
+			for (i = 0; i < obj->num_comments; i++) {
+				/* Initialize here just to make sure. */
+				obj->comments[i].length = 0;
+				obj->comments[i].entry = 0;
+
+				if (length < 4) {
+					obj->num_comments = i;
+					goto skip;
+				}
+				else
+					length -= 4;
+				if (!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->comments[i].length)) {
+					obj->num_comments = i;
+					return false; /* read_callback_ sets the state for us */
+				}
+				if (obj->comments[i].length > 0) {
+					if (length < obj->comments[i].length) {
+						obj->num_comments = i;
+						goto skip;
+					}
+					else
+						length -= obj->comments[i].length;
+					if (0 == (obj->comments[i].entry = safe_malloc_add_2op_(obj->comments[i].length, /*+*/1))) {
+						decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+						obj->num_comments = i;
+						return false;
+					}
+					memset (obj->comments[i].entry, 0, obj->comments[i].length) ;
+					if (!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->comments[i].entry, obj->comments[i].length)) {
+						/* Current i-th entry is bad, so we delete it. */
+						free (obj->comments[i].entry) ;
+						obj->comments[i].entry = NULL ;
+						obj->num_comments = i;
+						goto skip;
+					}
+					obj->comments[i].entry[obj->comments[i].length] = '\0';
+				}
+				else
+					obj->comments[i].entry = 0;
+			}
+		}
+	}
+
+  skip:
+	if (length > 0) {
+		/* length > 0 can only happen on files with invalid data in comments */
+		if(obj->num_comments < 1) {
+			free(obj->comments);
+			obj->comments = NULL;
+		}
+		if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, length))
+			return false; /* read_callback_ sets the state for us */
+	}
+
+	return true;
+}
+
+FLAC__bool read_metadata_cuesheet_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_CueSheet *obj)
+{
+	FLAC__uint32 i, j, x;
+
+	memset(obj, 0, sizeof(FLAC__StreamMetadata_CueSheet));
+
+	if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, (FLAC__byte*)obj->media_catalog_number, FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN/8))
+		return false; /* read_callback_ sets the state for us */
+
+	if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &obj->lead_in, FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN))
+		return false; /* read_callback_ sets the state for us */
+
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN))
+		return false; /* read_callback_ sets the state for us */
+	obj->is_cd = x? true : false;
+
+	if(!FLAC__bitreader_skip_bits_no_crc(decoder->private_->input, FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN))
+		return false; /* read_callback_ sets the state for us */
+
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN))
+		return false; /* read_callback_ sets the state for us */
+	obj->num_tracks = x;
+
+	if(obj->num_tracks > 0) {
+		if(0 == (obj->tracks = safe_calloc_(obj->num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track)))) {
+			decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+			return false;
+		}
+		for(i = 0; i < obj->num_tracks; i++) {
+			FLAC__StreamMetadata_CueSheet_Track *track = &obj->tracks[i];
+			if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &track->offset, FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN))
+				return false; /* read_callback_ sets the state for us */
+
+			if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN))
+				return false; /* read_callback_ sets the state for us */
+			track->number = (FLAC__byte)x;
+
+			if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, (FLAC__byte*)track->isrc, FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN/8))
+				return false; /* read_callback_ sets the state for us */
+
+			if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN))
+				return false; /* read_callback_ sets the state for us */
+			track->type = x;
+
+			if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN))
+				return false; /* read_callback_ sets the state for us */
+			track->pre_emphasis = x;
+
+			if(!FLAC__bitreader_skip_bits_no_crc(decoder->private_->input, FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN))
+				return false; /* read_callback_ sets the state for us */
+
+			if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN))
+				return false; /* read_callback_ sets the state for us */
+			track->num_indices = (FLAC__byte)x;
+
+			if(track->num_indices > 0) {
+				if(0 == (track->indices = safe_calloc_(track->num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index)))) {
+					decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+					return false;
+				}
+				for(j = 0; j < track->num_indices; j++) {
+					FLAC__StreamMetadata_CueSheet_Index *indx = &track->indices[j];
+					if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &indx->offset, FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN))
+						return false; /* read_callback_ sets the state for us */
+
+					if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN))
+						return false; /* read_callback_ sets the state for us */
+					indx->number = (FLAC__byte)x;
+
+					if(!FLAC__bitreader_skip_bits_no_crc(decoder->private_->input, FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN))
+						return false; /* read_callback_ sets the state for us */
+				}
+			}
+		}
+	}
+
+	return true;
+}
+
+FLAC__bool read_metadata_picture_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_Picture *obj)
+{
+	FLAC__uint32 x;
+
+	/* read type */
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_PICTURE_TYPE_LEN))
+		return false; /* read_callback_ sets the state for us */
+	obj->type = x;
+
+	/* read MIME type */
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN))
+		return false; /* read_callback_ sets the state for us */
+	if(0 == (obj->mime_type = safe_malloc_add_2op_(x, /*+*/1))) {
+		decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+		return false;
+	}
+	if(x > 0) {
+		if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, (FLAC__byte*)obj->mime_type, x))
+			return false; /* read_callback_ sets the state for us */
+	}
+	obj->mime_type[x] = '\0';
+
+	/* read description */
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN))
+		return false; /* read_callback_ sets the state for us */
+	if(0 == (obj->description = safe_malloc_add_2op_(x, /*+*/1))) {
+		decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+		return false;
+	}
+	if(x > 0) {
+		if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->description, x))
+			return false; /* read_callback_ sets the state for us */
+	}
+	obj->description[x] = '\0';
+
+	/* read width */
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &obj->width, FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN))
+		return false; /* read_callback_ sets the state for us */
+
+	/* read height */
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &obj->height, FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN))
+		return false; /* read_callback_ sets the state for us */
+
+	/* read depth */
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &obj->depth, FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN))
+		return false; /* read_callback_ sets the state for us */
+
+	/* read colors */
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &obj->colors, FLAC__STREAM_METADATA_PICTURE_COLORS_LEN))
+		return false; /* read_callback_ sets the state for us */
+
+	/* read data */
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &(obj->data_length), FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN))
+		return false; /* read_callback_ sets the state for us */
+	if(0 == (obj->data = safe_malloc_(obj->data_length))) {
+		decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+		return false;
+	}
+	if(obj->data_length > 0) {
+		if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->data, obj->data_length))
+			return false; /* read_callback_ sets the state for us */
+	}
+
+	return true;
+}
+
+FLAC__bool skip_id3v2_tag_(FLAC__StreamDecoder *decoder)
+{
+	FLAC__uint32 x;
+	uint32_t i, skip;
+
+	/* skip the version and flags bytes */
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 24))
+		return false; /* read_callback_ sets the state for us */
+	/* get the size (in bytes) to skip */
+	skip = 0;
+	for(i = 0; i < 4; i++) {
+		if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+			return false; /* read_callback_ sets the state for us */
+		skip <<= 7;
+		skip |= (x & 0x7f);
+	}
+	/* skip the rest of the tag */
+	if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, skip))
+		return false; /* read_callback_ sets the state for us */
+	return true;
+}
+
+FLAC__bool frame_sync_(FLAC__StreamDecoder *decoder)
+{
+	FLAC__uint32 x;
+	FLAC__bool first = true;
+
+	/* If we know the total number of samples in the stream, stop if we've read that many. */
+	/* This will stop us, for example, from wasting time trying to sync on an ID3V1 tag. */
+	if(FLAC__stream_decoder_get_total_samples(decoder) > 0) {
+		if(decoder->private_->samples_decoded >= FLAC__stream_decoder_get_total_samples(decoder)) {
+			decoder->protected_->state = FLAC__STREAM_DECODER_END_OF_STREAM;
+			return true;
+		}
+	}
+
+	/* make sure we're byte aligned */
+	if(!FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)) {
+		if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__bitreader_bits_left_for_byte_alignment(decoder->private_->input)))
+			return false; /* read_callback_ sets the state for us */
+	}
+
+	while(1) {
+		if(decoder->private_->cached) {
+			x = (FLAC__uint32)decoder->private_->lookahead;
+			decoder->private_->cached = false;
+		}
+		else {
+			if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+				return false; /* read_callback_ sets the state for us */
+		}
+		if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */
+			decoder->private_->header_warmup[0] = (FLAC__byte)x;
+			if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+				return false; /* read_callback_ sets the state for us */
+
+			/* we have to check if we just read two 0xff's in a row; the second may actually be the beginning of the sync code */
+			/* else we have to check if the second byte is the end of a sync code */
+			if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */
+				decoder->private_->lookahead = (FLAC__byte)x;
+				decoder->private_->cached = true;
+			}
+			else if(x >> 1 == 0x7c) { /* MAGIC NUMBER for the last 6 sync bits and reserved 7th bit */
+				decoder->private_->header_warmup[1] = (FLAC__byte)x;
+				decoder->protected_->state = FLAC__STREAM_DECODER_READ_FRAME;
+				return true;
+			}
+		}
+		if(first) {
+			send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+			first = false;
+		}
+	}
+
+	return true;
+}
+
+FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame, FLAC__bool do_full_decode)
+{
+	uint32_t channel;
+	uint32_t i;
+	FLAC__int32 mid, side;
+	uint32_t frame_crc; /* the one we calculate from the input stream */
+	FLAC__uint32 x;
+
+	*got_a_frame = false;
+
+	/* init the CRC */
+	frame_crc = 0;
+	frame_crc = FLAC__CRC16_UPDATE(decoder->private_->header_warmup[0], frame_crc);
+	frame_crc = FLAC__CRC16_UPDATE(decoder->private_->header_warmup[1], frame_crc);
+	FLAC__bitreader_reset_read_crc16(decoder->private_->input, (FLAC__uint16)frame_crc);
+
+	if(!read_frame_header_(decoder))
+		return false;
+	if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means we didn't sync on a valid header */
+		return true;
+	if(!allocate_output_(decoder, decoder->private_->frame.header.blocksize, decoder->private_->frame.header.channels))
+		return false;
+	for(channel = 0; channel < decoder->private_->frame.header.channels; channel++) {
+		/*
+		 * first figure the correct bits-per-sample of the subframe
+		 */
+		uint32_t bps = decoder->private_->frame.header.bits_per_sample;
+		switch(decoder->private_->frame.header.channel_assignment) {
+			case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
+				/* no adjustment needed */
+				break;
+			case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE:
+				if(channel == 1)
+					bps++;
+				break;
+			case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE:
+				if(channel == 0)
+					bps++;
+				break;
+			case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
+				if(channel == 1)
+					bps++;
+				break;
+			default: break;
+		}
+		/*
+		 * now read it
+		 */
+		if(!read_subframe_(decoder, channel, bps, do_full_decode))
+			return false;
+		if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means bad sync or got corruption */
+			return true;
+	}
+	if(!read_zero_padding_(decoder))
+		return false;
+	if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means bad sync or got corruption (i.e. "zero bits" were not all zeroes) */
+		return true;
+
+	/*
+	 * Read the frame CRC-16 from the footer and check
+	 */
+	frame_crc = FLAC__bitreader_get_read_crc16(decoder->private_->input);
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__FRAME_FOOTER_CRC_LEN))
+		return false; /* read_callback_ sets the state for us */
+	if(frame_crc == x) {
+		if(do_full_decode) {
+			/* Undo any special channel coding */
+			switch(decoder->private_->frame.header.channel_assignment) {
+				case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
+					/* do nothing */
+					break;
+				case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE:
+					for(i = 0; i < decoder->private_->frame.header.blocksize; i++)
+						decoder->private_->output[1][i] = decoder->private_->output[0][i] - decoder->private_->output[1][i];
+					break;
+				case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE:
+					for(i = 0; i < decoder->private_->frame.header.blocksize; i++)
+						decoder->private_->output[0][i] += decoder->private_->output[1][i];
+					break;
+				case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
+					for(i = 0; i < decoder->private_->frame.header.blocksize; i++) {
+						mid = decoder->private_->output[0][i];
+						side = decoder->private_->output[1][i];
+						mid = ((uint32_t) mid) << 1;
+						mid |= (side & 1); /* i.e. if 'side' is odd... */
+						decoder->private_->output[0][i] = (mid + side) >> 1;
+						decoder->private_->output[1][i] = (mid - side) >> 1;
+					}
+					break;
+				default: break;
+			}
+		}
+	}
+	else {
+		/* Bad frame, emit error and zero the output signal */
+		send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH);
+		if(do_full_decode) {
+			for(channel = 0; channel < decoder->private_->frame.header.channels; channel++) {
+				memset(decoder->private_->output[channel], 0, sizeof(FLAC__int32) * decoder->private_->frame.header.blocksize);
+			}
+		}
+	}
+
+	*got_a_frame = true;
+
+	/* we wait to update fixed_block_size until here, when we're sure we've got a proper frame and hence a correct blocksize */
+	if(decoder->private_->next_fixed_block_size)
+		decoder->private_->fixed_block_size = decoder->private_->next_fixed_block_size;
+
+	/* put the latest values into the public section of the decoder instance */
+	decoder->protected_->channels = decoder->private_->frame.header.channels;
+	decoder->protected_->channel_assignment = decoder->private_->frame.header.channel_assignment;
+	decoder->protected_->bits_per_sample = decoder->private_->frame.header.bits_per_sample;
+	decoder->protected_->sample_rate = decoder->private_->frame.header.sample_rate;
+	decoder->protected_->blocksize = decoder->private_->frame.header.blocksize;
+	decoder->private_->samples_decoded = decoder->private_->frame.header.number.sample_number + decoder->private_->frame.header.blocksize;
+
+	/* write it */
+	if(do_full_decode) {
+		if(write_audio_frame_to_client_(decoder, &decoder->private_->frame, (const FLAC__int32 * const *)decoder->private_->output) != FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE) {
+			decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED;
+			return false;
+		}
+	}
+
+	decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+	return true;
+}
+
+FLAC__bool read_frame_header_(FLAC__StreamDecoder *decoder)
+{
+	FLAC__uint32 x;
+	FLAC__uint64 xx;
+	uint32_t i, blocksize_hint = 0, sample_rate_hint = 0;
+	FLAC__byte crc8, raw_header[16]; /* MAGIC NUMBER based on the maximum frame header size, including CRC */
+	uint32_t raw_header_len;
+	FLAC__bool is_unparseable = false;
+
+	/* init the raw header with the saved bits from synchronization */
+	raw_header[0] = decoder->private_->header_warmup[0];
+	raw_header[1] = decoder->private_->header_warmup[1];
+	raw_header_len = 2;
+
+	/* check to make sure that reserved bit is 0 */
+	if(raw_header[1] & 0x02) /* MAGIC NUMBER */
+		is_unparseable = true;
+
+	/*
+	 * Note that along the way as we read the header, we look for a sync
+	 * code inside.  If we find one it would indicate that our original
+	 * sync was bad since there cannot be a sync code in a valid header.
+	 *
+	 * Three kinds of things can go wrong when reading the frame header:
+	 *  1) We may have sync'ed incorrectly and not landed on a frame header.
+	 *     If we don't find a sync code, it can end up looking like we read
+	 *     a valid but unparseable header, until getting to the frame header
+	 *     CRC.  Even then we could get a false positive on the CRC.
+	 *  2) We may have sync'ed correctly but on an unparseable frame (from a
+	 *     future encoder).
+	 *  3) We may be on a damaged frame which appears valid but unparseable.
+	 *
+	 * For all these reasons, we try and read a complete frame header as
+	 * long as it seems valid, even if unparseable, up until the frame
+	 * header CRC.
+	 */
+
+	/*
+	 * read in the raw header as bytes so we can CRC it, and parse it on the way
+	 */
+	for(i = 0; i < 2; i++) {
+		if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+			return false; /* read_callback_ sets the state for us */
+		if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */
+			/* if we get here it means our original sync was erroneous since the sync code cannot appear in the header */
+			decoder->private_->lookahead = (FLAC__byte)x;
+			decoder->private_->cached = true;
+			send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER);
+			decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+			return true;
+		}
+		raw_header[raw_header_len++] = (FLAC__byte)x;
+	}
+
+	switch(x = raw_header[2] >> 4) {
+		case 0:
+			is_unparseable = true;
+			break;
+		case 1:
+			decoder->private_->frame.header.blocksize = 192;
+			break;
+		case 2:
+		case 3:
+		case 4:
+		case 5:
+			decoder->private_->frame.header.blocksize = 576 << (x-2);
+			break;
+		case 6:
+		case 7:
+			blocksize_hint = x;
+			break;
+		case 8:
+		case 9:
+		case 10:
+		case 11:
+		case 12:
+		case 13:
+		case 14:
+		case 15:
+			decoder->private_->frame.header.blocksize = 256 << (x-8);
+			break;
+		default:
+			break;
+	}
+
+	switch(x = raw_header[2] & 0x0f) {
+		case 0:
+			if(decoder->private_->has_stream_info)
+				decoder->private_->frame.header.sample_rate = decoder->private_->stream_info.data.stream_info.sample_rate;
+			else
+				is_unparseable = true;
+			break;
+		case 1:
+			decoder->private_->frame.header.sample_rate = 88200;
+			break;
+		case 2:
+			decoder->private_->frame.header.sample_rate = 176400;
+			break;
+		case 3:
+			decoder->private_->frame.header.sample_rate = 192000;
+			break;
+		case 4:
+			decoder->private_->frame.header.sample_rate = 8000;
+			break;
+		case 5:
+			decoder->private_->frame.header.sample_rate = 16000;
+			break;
+		case 6:
+			decoder->private_->frame.header.sample_rate = 22050;
+			break;
+		case 7:
+			decoder->private_->frame.header.sample_rate = 24000;
+			break;
+		case 8:
+			decoder->private_->frame.header.sample_rate = 32000;
+			break;
+		case 9:
+			decoder->private_->frame.header.sample_rate = 44100;
+			break;
+		case 10:
+			decoder->private_->frame.header.sample_rate = 48000;
+			break;
+		case 11:
+			decoder->private_->frame.header.sample_rate = 96000;
+			break;
+		case 12:
+		case 13:
+		case 14:
+			sample_rate_hint = x;
+			break;
+		case 15:
+			send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER);
+			decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+			return true;
+		default:
+			break;
+	}
+
+	x = (uint32_t)(raw_header[3] >> 4);
+	if(x & 8) {
+		decoder->private_->frame.header.channels = 2;
+		switch(x & 7) {
+			case 0:
+				decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE;
+				break;
+			case 1:
+				decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE;
+				break;
+			case 2:
+				decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_MID_SIDE;
+				break;
+			default:
+				is_unparseable = true;
+				break;
+		}
+	}
+	else {
+		decoder->private_->frame.header.channels = (uint32_t)x + 1;
+		decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT;
+	}
+
+	switch(x = (uint32_t)(raw_header[3] & 0x0e) >> 1) {
+		case 0:
+			if(decoder->private_->has_stream_info)
+				decoder->private_->frame.header.bits_per_sample = decoder->private_->stream_info.data.stream_info.bits_per_sample;
+			else
+				is_unparseable = true;
+			break;
+		case 1:
+			decoder->private_->frame.header.bits_per_sample = 8;
+			break;
+		case 2:
+			decoder->private_->frame.header.bits_per_sample = 12;
+			break;
+		case 4:
+			decoder->private_->frame.header.bits_per_sample = 16;
+			break;
+		case 5:
+			decoder->private_->frame.header.bits_per_sample = 20;
+			break;
+		case 6:
+			decoder->private_->frame.header.bits_per_sample = 24;
+			break;
+		case 3:
+		case 7:
+			is_unparseable = true;
+			break;
+		default:
+			break;
+	}
+
+	/* check to make sure that reserved bit is 0 */
+	if(raw_header[3] & 0x01) /* MAGIC NUMBER */
+		is_unparseable = true;
+
+	/* read the frame's starting sample number (or frame number as the case may be) */
+	if(
+		raw_header[1] & 0x01 ||
+		/*@@@ this clause is a concession to the old way of doing variable blocksize; the only known implementation is flake and can probably be removed without inconveniencing anyone */
+		(decoder->private_->has_stream_info && decoder->private_->stream_info.data.stream_info.min_blocksize != decoder->private_->stream_info.data.stream_info.max_blocksize)
+	) { /* variable blocksize */
+		if(!FLAC__bitreader_read_utf8_uint64(decoder->private_->input, &xx, raw_header, &raw_header_len))
+			return false; /* read_callback_ sets the state for us */
+		if(xx == FLAC__U64L(0xffffffffffffffff)) { /* i.e. non-UTF8 code... */
+			decoder->private_->lookahead = raw_header[raw_header_len-1]; /* back up as much as we can */
+			decoder->private_->cached = true;
+			send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER);
+			decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+			return true;
+		}
+		decoder->private_->frame.header.number_type = FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER;
+		decoder->private_->frame.header.number.sample_number = xx;
+	}
+	else { /* fixed blocksize */
+		if(!FLAC__bitreader_read_utf8_uint32(decoder->private_->input, &x, raw_header, &raw_header_len))
+			return false; /* read_callback_ sets the state for us */
+		if(x == 0xffffffff) { /* i.e. non-UTF8 code... */
+			decoder->private_->lookahead = raw_header[raw_header_len-1]; /* back up as much as we can */
+			decoder->private_->cached = true;
+			send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER);
+			decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+			return true;
+		}
+		decoder->private_->frame.header.number_type = FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER;
+		decoder->private_->frame.header.number.frame_number = x;
+	}
+
+	if(blocksize_hint) {
+		if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+			return false; /* read_callback_ sets the state for us */
+		raw_header[raw_header_len++] = (FLAC__byte)x;
+		if(blocksize_hint == 7) {
+			FLAC__uint32 _x;
+			if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &_x, 8))
+				return false; /* read_callback_ sets the state for us */
+			raw_header[raw_header_len++] = (FLAC__byte)_x;
+			x = (x << 8) | _x;
+		}
+		decoder->private_->frame.header.blocksize = x+1;
+	}
+
+	if(sample_rate_hint) {
+		if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+			return false; /* read_callback_ sets the state for us */
+		raw_header[raw_header_len++] = (FLAC__byte)x;
+		if(sample_rate_hint != 12) {
+			FLAC__uint32 _x;
+			if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &_x, 8))
+				return false; /* read_callback_ sets the state for us */
+			raw_header[raw_header_len++] = (FLAC__byte)_x;
+			x = (x << 8) | _x;
+		}
+		if(sample_rate_hint == 12)
+			decoder->private_->frame.header.sample_rate = x*1000;
+		else if(sample_rate_hint == 13)
+			decoder->private_->frame.header.sample_rate = x;
+		else
+			decoder->private_->frame.header.sample_rate = x*10;
+	}
+
+	/* read the CRC-8 byte */
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+		return false; /* read_callback_ sets the state for us */
+	crc8 = (FLAC__byte)x;
+
+	if(FLAC__crc8(raw_header, raw_header_len) != crc8) {
+		send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER);
+		decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+		return true;
+	}
+
+	/* calculate the sample number from the frame number if needed */
+	decoder->private_->next_fixed_block_size = 0;
+	if(decoder->private_->frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER) {
+		x = decoder->private_->frame.header.number.frame_number;
+		decoder->private_->frame.header.number_type = FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER;
+		if(decoder->private_->fixed_block_size)
+			decoder->private_->frame.header.number.sample_number = (FLAC__uint64)decoder->private_->fixed_block_size * (FLAC__uint64)x;
+		else if(decoder->private_->has_stream_info) {
+			if(decoder->private_->stream_info.data.stream_info.min_blocksize == decoder->private_->stream_info.data.stream_info.max_blocksize) {
+				decoder->private_->frame.header.number.sample_number = (FLAC__uint64)decoder->private_->stream_info.data.stream_info.min_blocksize * (FLAC__uint64)x;
+				decoder->private_->next_fixed_block_size = decoder->private_->stream_info.data.stream_info.max_blocksize;
+			}
+			else
+				is_unparseable = true;
+		}
+		else if(x == 0) {
+			decoder->private_->frame.header.number.sample_number = 0;
+			decoder->private_->next_fixed_block_size = decoder->private_->frame.header.blocksize;
+		}
+		else {
+			/* can only get here if the stream has invalid frame numbering and no STREAMINFO, so assume it's not the last (possibly short) frame */
+			decoder->private_->frame.header.number.sample_number = (FLAC__uint64)decoder->private_->frame.header.blocksize * (FLAC__uint64)x;
+		}
+	}
+
+	if(is_unparseable) {
+		send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM);
+		decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+		return true;
+	}
+
+	return true;
+}
+
+FLAC__bool read_subframe_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode)
+{
+	FLAC__uint32 x;
+	FLAC__bool wasted_bits;
+	uint32_t i;
+
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) /* MAGIC NUMBER */
+		return false; /* read_callback_ sets the state for us */
+
+	wasted_bits = (x & 1);
+	x &= 0xfe;
+
+	if(wasted_bits) {
+		uint32_t u;
+		if(!FLAC__bitreader_read_unary_unsigned(decoder->private_->input, &u))
+			return false; /* read_callback_ sets the state for us */
+		decoder->private_->frame.subframes[channel].wasted_bits = u+1;
+		if (decoder->private_->frame.subframes[channel].wasted_bits >= bps)
+			return false;
+		bps -= decoder->private_->frame.subframes[channel].wasted_bits;
+	}
+	else
+		decoder->private_->frame.subframes[channel].wasted_bits = 0;
+
+	/*
+	 * Lots of magic numbers here
+	 */
+	if(x & 0x80) {
+		send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+		decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+		return true;
+	}
+	else if(x == 0) {
+		if(!read_subframe_constant_(decoder, channel, bps, do_full_decode))
+			return false;
+	}
+	else if(x == 2) {
+		if(!read_subframe_verbatim_(decoder, channel, bps, do_full_decode))
+			return false;
+	}
+	else if(x < 16) {
+		send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM);
+		decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+		return true;
+	}
+	else if(x <= 24) {
+		if(!read_subframe_fixed_(decoder, channel, bps, (x>>1)&7, do_full_decode))
+			return false;
+		if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means bad sync or got corruption */
+			return true;
+	}
+	else if(x < 64) {
+		send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM);
+		decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+		return true;
+	}
+	else {
+		if(!read_subframe_lpc_(decoder, channel, bps, ((x>>1)&31)+1, do_full_decode))
+			return false;
+		if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means bad sync or got corruption */
+			return true;
+	}
+
+	if(wasted_bits && do_full_decode) {
+		x = decoder->private_->frame.subframes[channel].wasted_bits;
+		for(i = 0; i < decoder->private_->frame.header.blocksize; i++) {
+			uint32_t val = decoder->private_->output[channel][i];
+			decoder->private_->output[channel][i] = (val << x);
+		}
+	}
+
+	return true;
+}
+
+FLAC__bool read_subframe_constant_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode)
+{
+	FLAC__Subframe_Constant *subframe = &decoder->private_->frame.subframes[channel].data.constant;
+	FLAC__int32 x;
+	uint32_t i;
+	FLAC__int32 *output = decoder->private_->output[channel];
+
+	decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_CONSTANT;
+
+	if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &x, bps))
+		return false; /* read_callback_ sets the state for us */
+
+	subframe->value = x;
+
+	/* decode the subframe */
+	if(do_full_decode) {
+		for(i = 0; i < decoder->private_->frame.header.blocksize; i++)
+			output[i] = x;
+	}
+
+	return true;
+}
+
+FLAC__bool read_subframe_fixed_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, const uint32_t order, FLAC__bool do_full_decode)
+{
+	FLAC__Subframe_Fixed *subframe = &decoder->private_->frame.subframes[channel].data.fixed;
+	FLAC__int32 i32;
+	FLAC__uint32 u32;
+	uint32_t u;
+
+	decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_FIXED;
+
+	subframe->residual = decoder->private_->residual[channel];
+	subframe->order = order;
+
+	/* read warm-up samples */
+	for(u = 0; u < order; u++) {
+		if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i32, bps))
+			return false; /* read_callback_ sets the state for us */
+		subframe->warmup[u] = i32;
+	}
+
+	/* read entropy coding method info */
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN))
+		return false; /* read_callback_ sets the state for us */
+	subframe->entropy_coding_method.type = (FLAC__EntropyCodingMethodType)u32;
+	switch(subframe->entropy_coding_method.type) {
+		case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
+		case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2:
+			if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN))
+				return false; /* read_callback_ sets the state for us */
+			if(decoder->private_->frame.header.blocksize >> u32 < order) {
+				send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+				decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+				return true;
+			}
+			subframe->entropy_coding_method.data.partitioned_rice.order = u32;
+			subframe->entropy_coding_method.data.partitioned_rice.contents = &decoder->private_->partitioned_rice_contents[channel];
+			break;
+		default:
+			send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM);
+			decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+			return true;
+	}
+
+	/* read residual */
+	switch(subframe->entropy_coding_method.type) {
+		case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
+		case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2:
+			if(!read_residual_partitioned_rice_(decoder, order, subframe->entropy_coding_method.data.partitioned_rice.order, &decoder->private_->partitioned_rice_contents[channel], decoder->private_->residual[channel], /*is_extended=*/subframe->entropy_coding_method.type == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2))
+				return false;
+			break;
+		default:
+			break;
+	}
+
+	/* decode the subframe */
+	if(do_full_decode) {
+		memcpy(decoder->private_->output[channel], subframe->warmup, sizeof(FLAC__int32) * order);
+		FLAC__fixed_restore_signal(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, order, decoder->private_->output[channel]+order);
+	}
+
+	return true;
+}
+
+FLAC__bool read_subframe_lpc_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, const uint32_t order, FLAC__bool do_full_decode)
+{
+	FLAC__Subframe_LPC *subframe = &decoder->private_->frame.subframes[channel].data.lpc;
+	FLAC__int32 i32;
+	FLAC__uint32 u32;
+	uint32_t u;
+
+	decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_LPC;
+
+	subframe->residual = decoder->private_->residual[channel];
+	subframe->order = order;
+
+	/* read warm-up samples */
+	for(u = 0; u < order; u++) {
+		if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i32, bps))
+			return false; /* read_callback_ sets the state for us */
+		subframe->warmup[u] = i32;
+	}
+
+	/* read qlp coeff precision */
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN))
+		return false; /* read_callback_ sets the state for us */
+	if(u32 == (1u << FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN) - 1) {
+		send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+		decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+		return true;
+	}
+	subframe->qlp_coeff_precision = u32+1;
+
+	/* read qlp shift */
+	if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i32, FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN))
+		return false; /* read_callback_ sets the state for us */
+	if(i32 < 0) {
+		send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+		decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+		return true;
+	}
+	subframe->quantization_level = i32;
+
+	/* read quantized lp coefficiencts */
+	for(u = 0; u < order; u++) {
+		if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i32, subframe->qlp_coeff_precision))
+			return false; /* read_callback_ sets the state for us */
+		subframe->qlp_coeff[u] = i32;
+	}
+
+	/* read entropy coding method info */
+	if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN))
+		return false; /* read_callback_ sets the state for us */
+	subframe->entropy_coding_method.type = (FLAC__EntropyCodingMethodType)u32;
+	switch(subframe->entropy_coding_method.type) {
+		case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
+		case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2:
+			if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN))
+				return false; /* read_callback_ sets the state for us */
+			if(decoder->private_->frame.header.blocksize >> u32 < order) {
+				send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+				decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+				return true;
+			}
+			subframe->entropy_coding_method.data.partitioned_rice.order = u32;
+			subframe->entropy_coding_method.data.partitioned_rice.contents = &decoder->private_->partitioned_rice_contents[channel];
+			break;
+		default:
+			send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM);
+			decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+			return true;
+	}
+
+	/* read residual */
+	switch(subframe->entropy_coding_method.type) {
+		case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
+		case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2:
+			if(!read_residual_partitioned_rice_(decoder, order, subframe->entropy_coding_method.data.partitioned_rice.order, &decoder->private_->partitioned_rice_contents[channel], decoder->private_->residual[channel], /*is_extended=*/subframe->entropy_coding_method.type == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2))
+				return false;
+			break;
+		default:
+			break;
+	}
+
+	/* decode the subframe */
+	if(do_full_decode) {
+		memcpy(decoder->private_->output[channel], subframe->warmup, sizeof(FLAC__int32) * order);
+		if(bps + subframe->qlp_coeff_precision + FLAC__bitmath_ilog2(order) <= 32)
+			if(bps <= 16 && subframe->qlp_coeff_precision <= 16)
+				decoder->private_->local_lpc_restore_signal_16bit(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order);
+			else
+				decoder->private_->local_lpc_restore_signal(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order);
+		else
+			decoder->private_->local_lpc_restore_signal_64bit(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order);
+	}
+
+	return true;
+}
+
+FLAC__bool read_subframe_verbatim_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode)
+{
+	FLAC__Subframe_Verbatim *subframe = &decoder->private_->frame.subframes[channel].data.verbatim;
+	FLAC__int32 x, *residual = decoder->private_->residual[channel];
+	uint32_t i;
+
+	decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_VERBATIM;
+
+	subframe->data = residual;
+
+	for(i = 0; i < decoder->private_->frame.header.blocksize; i++) {
+		if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &x, bps))
+			return false; /* read_callback_ sets the state for us */
+		residual[i] = x;
+	}
+
+	/* decode the subframe */
+	if(do_full_decode)
+		memcpy(decoder->private_->output[channel], subframe->data, sizeof(FLAC__int32) * decoder->private_->frame.header.blocksize);
+
+	return true;
+}
+
+FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, uint32_t predictor_order, uint32_t partition_order, FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, FLAC__int32 *residual, FLAC__bool is_extended)
+{
+	FLAC__uint32 rice_parameter;
+	int i;
+	uint32_t partition, sample, u;
+	const uint32_t partitions = 1u << partition_order;
+	const uint32_t partition_samples = partition_order > 0? decoder->private_->frame.header.blocksize >> partition_order : decoder->private_->frame.header.blocksize - predictor_order;
+	const uint32_t plen = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN;
+	const uint32_t pesc = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER;
+
+	if(!FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(partitioned_rice_contents, flac_max(6u, partition_order))) {
+		decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+		return false;
+	}
+
+	sample = 0;
+	for(partition = 0; partition < partitions; partition++) {
+		if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &rice_parameter, plen))
+			return false; /* read_callback_ sets the state for us */
+		partitioned_rice_contents->parameters[partition] = rice_parameter;
+		if(rice_parameter < pesc) {
+			partitioned_rice_contents->raw_bits[partition] = 0;
+			u = (partition_order == 0 || partition > 0)? partition_samples : partition_samples - predictor_order;
+			if(!FLAC__bitreader_read_rice_signed_block(decoder->private_->input, residual + sample, u, rice_parameter))
+				return false; /* read_callback_ sets the state for us */
+			sample += u;
+		}
+		else {
+			if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN))
+				return false; /* read_callback_ sets the state for us */
+			partitioned_rice_contents->raw_bits[partition] = rice_parameter;
+			for(u = (partition_order == 0 || partition > 0)? 0 : predictor_order; u < partition_samples; u++, sample++) {
+				if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i, rice_parameter))
+					return false; /* read_callback_ sets the state for us */
+				residual[sample] = i;
+			}
+		}
+	}
+
+	return true;
+}
+
+FLAC__bool read_zero_padding_(FLAC__StreamDecoder *decoder)
+{
+	if(!FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)) {
+		FLAC__uint32 zero = 0;
+		if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &zero, FLAC__bitreader_bits_left_for_byte_alignment(decoder->private_->input)))
+			return false; /* read_callback_ sets the state for us */
+		if(zero != 0) {
+			send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+			decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+		}
+	}
+	return true;
+}
+
+FLAC__bool read_callback_(FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+	FLAC__StreamDecoder *decoder = (FLAC__StreamDecoder *)client_data;
+
+	if(
+		decoder->private_->eof_callback && decoder->private_->eof_callback(decoder, decoder->private_->client_data)
+	) {
+		*bytes = 0;
+		decoder->protected_->state = FLAC__STREAM_DECODER_END_OF_STREAM;
+		return false;
+	}
+	else if(*bytes > 0) {
+		/* While seeking, it is possible for our seek to land in the
+		 * middle of audio data that looks exactly like a frame header
+		 * from a future version of an encoder.  When that happens, our
+		 * error callback will get an
+		 * FLAC__STREAM_DECODER_UNPARSEABLE_STREAM and increment its
+		 * unparseable_frame_count.  But there is a remote possibility
+		 * that it is properly synced at such a "future-codec frame",
+		 * so to make sure, we wait to see many "unparseable" errors in
+		 * a row before bailing out.
+		 */
+		if(decoder->private_->is_seeking && decoder->private_->unparseable_frame_count > 20) {
+			decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED;
+			return false;
+		}
+		else {
+			const FLAC__StreamDecoderReadStatus status =
+				decoder->private_->read_callback(decoder, buffer, bytes, decoder->private_->client_data)
+			;
+			if(status == FLAC__STREAM_DECODER_READ_STATUS_ABORT) {
+				decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED;
+				return false;
+			}
+			else if(*bytes == 0) {
+				if(
+					status == FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM ||
+					(
+						decoder->private_->eof_callback && decoder->private_->eof_callback(decoder, decoder->private_->client_data)
+					)
+				) {
+					decoder->protected_->state = FLAC__STREAM_DECODER_END_OF_STREAM;
+					return false;
+				}
+				else
+					return true;
+			}
+			else
+				return true;
+		}
+	}
+	else {
+		/* abort to avoid a deadlock */
+		decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED;
+		return false;
+	}
+	/* [1] @@@ HACK NOTE: The end-of-stream checking has to be hacked around
+	 * for Ogg FLAC.  This is because the ogg decoder aspect can lose sync
+	 * and at the same time hit the end of the stream (for example, seeking
+	 * to a point that is after the beginning of the last Ogg page).  There
+	 * is no way to report an Ogg sync loss through the callbacks (see note
+	 * in read_callback_ogg_aspect_()) so it returns CONTINUE with *bytes==0.
+	 * So to keep the decoder from stopping at this point we gate the call
+	 * to the eof_callback and let the Ogg decoder aspect set the
+	 * end-of-stream state when it is needed.
+	 */
+}
+
+FLAC__StreamDecoderWriteStatus write_audio_frame_to_client_(FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[])
+{
+	if(decoder->private_->is_seeking) {
+		FLAC__uint64 this_frame_sample = frame->header.number.sample_number;
+		FLAC__uint64 next_frame_sample = this_frame_sample + (FLAC__uint64)frame->header.blocksize;
+		FLAC__uint64 target_sample = decoder->private_->target_sample;
+
+		decoder->private_->last_frame = *frame; /* save the frame */
+		if(this_frame_sample <= target_sample && target_sample < next_frame_sample) { /* we hit our target frame */
+			uint32_t delta = (uint32_t)(target_sample - this_frame_sample);
+			/* kick out of seek mode */
+			decoder->private_->is_seeking = false;
+			/* shift out the samples before target_sample */
+			if(delta > 0) {
+				uint32_t channel;
+				const FLAC__int32 *newbuffer[FLAC__MAX_CHANNELS];
+				for(channel = 0; channel < frame->header.channels; channel++)
+					newbuffer[channel] = buffer[channel] + delta;
+				decoder->private_->last_frame.header.blocksize -= delta;
+				decoder->private_->last_frame.header.number.sample_number += (FLAC__uint64)delta;
+				/* write the relevant samples */
+				return decoder->private_->write_callback(decoder, &decoder->private_->last_frame, newbuffer, decoder->private_->client_data);
+			}
+			else {
+				/* write the relevant samples */
+				return decoder->private_->write_callback(decoder, frame, buffer, decoder->private_->client_data);
+			}
+		}
+		else {
+			return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+		}
+	}
+	else {
+		/*
+		 * If we never got STREAMINFO, turn off MD5 checking to save
+		 * cycles since we don't have a sum to compare to anyway
+		 */
+		if(!decoder->private_->has_stream_info)
+			decoder->private_->do_md5_checking = false;
+		if(decoder->private_->do_md5_checking) {
+			if(!FLAC__MD5Accumulate(&decoder->private_->md5context, buffer, frame->header.channels, frame->header.blocksize, (frame->header.bits_per_sample+7) / 8))
+				return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+		}
+		return decoder->private_->write_callback(decoder, frame, buffer, decoder->private_->client_data);
+	}
+}
+
+void send_error_to_client_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status)
+{
+	if(!decoder->private_->is_seeking)
+		decoder->private_->error_callback(decoder, status, decoder->private_->client_data);
+	else if(status == FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM)
+		decoder->private_->unparseable_frame_count++;
+}
+
+FLAC__bool seek_to_absolute_sample_(FLAC__StreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample)
+{
+	FLAC__uint64 first_frame_offset = decoder->private_->first_frame_offset, lower_bound, upper_bound, lower_bound_sample, upper_bound_sample, this_frame_sample;
+	FLAC__int64 pos = -1;
+	int i;
+	uint32_t approx_bytes_per_frame;
+	FLAC__bool first_seek = true;
+	const FLAC__uint64 total_samples = FLAC__stream_decoder_get_total_samples(decoder);
+	const uint32_t min_blocksize = decoder->private_->stream_info.data.stream_info.min_blocksize;
+	const uint32_t max_blocksize = decoder->private_->stream_info.data.stream_info.max_blocksize;
+	const uint32_t max_framesize = decoder->private_->stream_info.data.stream_info.max_framesize;
+	const uint32_t min_framesize = decoder->private_->stream_info.data.stream_info.min_framesize;
+	/* take these from the current frame in case they've changed mid-stream */
+	uint32_t channels = FLAC__stream_decoder_get_channels(decoder);
+	uint32_t bps = FLAC__stream_decoder_get_bits_per_sample(decoder);
+	const FLAC__StreamMetadata_SeekTable *seek_table = decoder->private_->has_seek_table? &decoder->private_->seek_table.data.seek_table : 0;
+
+	/* use values from stream info if we didn't decode a frame */
+	if(channels == 0)
+		channels = decoder->private_->stream_info.data.stream_info.channels;
+	if(bps == 0)
+		bps = decoder->private_->stream_info.data.stream_info.bits_per_sample;
+
+	/* we are just guessing here */
+	if(max_framesize > 0)
+		approx_bytes_per_frame = (max_framesize + min_framesize) / 2 + 1;
+	/*
+	 * Check if it's a known fixed-blocksize stream.  Note that though
+	 * the spec doesn't allow zeroes in the STREAMINFO block, we may
+	 * never get a STREAMINFO block when decoding so the value of
+	 * min_blocksize might be zero.
+	 */
+	else if(min_blocksize == max_blocksize && min_blocksize > 0) {
+		/* note there are no () around 'bps/8' to keep precision up since it's an integer calculation */
+		approx_bytes_per_frame = min_blocksize * channels * bps/8 + 64;
+	}
+	else
+		approx_bytes_per_frame = 4096 * channels * bps/8 + 64;
+
+	/*
+	 * First, we set an upper and lower bound on where in the
+	 * stream we will search.  For now we assume the worst case
+	 * scenario, which is our best guess at the beginning of
+	 * the first frame and end of the stream.
+	 */
+	lower_bound = first_frame_offset;
+	lower_bound_sample = 0;
+	upper_bound = stream_length;
+	upper_bound_sample = total_samples > 0 ? total_samples : target_sample /*estimate it*/;
+
+	/*
+	 * Now we refine the bounds if we have a seektable with
+	 * suitable points.  Note that according to the spec they
+	 * must be ordered by ascending sample number.
+	 *
+	 * Note: to protect against invalid seek tables we will ignore points
+	 * that have frame_samples==0 or sample_number>=total_samples
+	 */
+	if(seek_table) {
+		FLAC__uint64 new_lower_bound = lower_bound;
+		FLAC__uint64 new_upper_bound = upper_bound;
+		FLAC__uint64 new_lower_bound_sample = lower_bound_sample;
+		FLAC__uint64 new_upper_bound_sample = upper_bound_sample;
+
+		/* find the closest seek point <= target_sample, if it exists */
+		for(i = (int)seek_table->num_points - 1; i >= 0; i--) {
+			if(
+				seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER &&
+				seek_table->points[i].frame_samples > 0 && /* defense against bad seekpoints */
+				(total_samples <= 0 || seek_table->points[i].sample_number < total_samples) && /* defense against bad seekpoints */
+				seek_table->points[i].sample_number <= target_sample
+			)
+				break;
+		}
+		if(i >= 0) { /* i.e. we found a suitable seek point... */
+			new_lower_bound = first_frame_offset + seek_table->points[i].stream_offset;
+			new_lower_bound_sample = seek_table->points[i].sample_number;
+		}
+
+		/* find the closest seek point > target_sample, if it exists */
+		for(i = 0; i < (int)seek_table->num_points; i++) {
+			if(
+				seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER &&
+				seek_table->points[i].frame_samples > 0 && /* defense against bad seekpoints */
+				(total_samples <= 0 || seek_table->points[i].sample_number < total_samples) && /* defense against bad seekpoints */
+				seek_table->points[i].sample_number > target_sample
+			)
+				break;
+		}
+		if(i < (int)seek_table->num_points) { /* i.e. we found a suitable seek point... */
+			new_upper_bound = first_frame_offset + seek_table->points[i].stream_offset;
+			new_upper_bound_sample = seek_table->points[i].sample_number;
+		}
+		/* final protection against unsorted seek tables; keep original values if bogus */
+		if(new_upper_bound >= new_lower_bound) {
+			lower_bound = new_lower_bound;
+			upper_bound = new_upper_bound;
+			lower_bound_sample = new_lower_bound_sample;
+			upper_bound_sample = new_upper_bound_sample;
+		}
+	}
+
+	/* there are 2 insidious ways that the following equality occurs, which
+	 * we need to fix:
+	 *  1) total_samples is 0 (unknown) and target_sample is 0
+	 *  2) total_samples is 0 (unknown) and target_sample happens to be
+	 *     exactly equal to the last seek point in the seek table; this
+	 *     means there is no seek point above it, and upper_bound_samples
+	 *     remains equal to the estimate (of target_samples) we made above
+	 * in either case it does not hurt to move upper_bound_sample up by 1
+	 */
+	if(upper_bound_sample == lower_bound_sample)
+		upper_bound_sample++;
+
+	decoder->private_->target_sample = target_sample;
+	while(1) {
+		/* check if the bounds are still ok */
+		if (lower_bound_sample >= upper_bound_sample || lower_bound > upper_bound) {
+			decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+			return false;
+		}
+		pos = (FLAC__int64)lower_bound + (FLAC__int64)((double)(target_sample - lower_bound_sample) / (double)(upper_bound_sample - lower_bound_sample) * (double)(upper_bound - lower_bound)) - approx_bytes_per_frame;
+		if(pos >= (FLAC__int64)upper_bound)
+			pos = (FLAC__int64)upper_bound - 1;
+		if(pos < (FLAC__int64)lower_bound)
+			pos = (FLAC__int64)lower_bound;
+		if(decoder->private_->seek_callback(decoder, (FLAC__uint64)pos, decoder->private_->client_data) != FLAC__STREAM_DECODER_SEEK_STATUS_OK) {
+			decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+			return false;
+		}
+		if(!FLAC__stream_decoder_flush(decoder)) {
+			/* above call sets the state for us */
+			return false;
+		}
+		/* Now we need to get a frame.  First we need to reset our
+		 * unparseable_frame_count; if we get too many unparseable
+		 * frames in a row, the read callback will return
+		 * FLAC__STREAM_DECODER_READ_STATUS_ABORT, causing
+		 * FLAC__stream_decoder_process_single() to return false.
+		 */
+		decoder->private_->unparseable_frame_count = 0;
+		if(!FLAC__stream_decoder_process_single(decoder) ||
+		   decoder->protected_->state == FLAC__STREAM_DECODER_ABORTED) {
+			decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+			return false;
+		}
+		/* our write callback will change the state when it gets to the target frame */
+		/* actually, we could have got_a_frame if our decoder is at FLAC__STREAM_DECODER_END_OF_STREAM so we need to check for that also */
+		if(!decoder->private_->is_seeking)
+			break;
+
+		this_frame_sample = decoder->private_->last_frame.header.number.sample_number;
+
+		if (0 == decoder->private_->samples_decoded || (this_frame_sample + decoder->private_->last_frame.header.blocksize >= upper_bound_sample && !first_seek)) {
+			if (pos == (FLAC__int64)lower_bound) {
+				/* can't move back any more than the first frame, something is fatally wrong */
+				decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+				return false;
+			}
+			/* our last move backwards wasn't big enough, try again */
+			approx_bytes_per_frame = approx_bytes_per_frame? approx_bytes_per_frame * 2 : 16;
+			continue;
+		}
+		/* allow one seek over upper bound, so we can get a correct upper_bound_sample for streams with unknown total_samples */
+		first_seek = false;
+
+		/* make sure we are not seeking in corrupted stream */
+		if (this_frame_sample < lower_bound_sample) {
+			decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+			return false;
+		}
+
+		/* we need to narrow the search */
+		if(target_sample < this_frame_sample) {
+			upper_bound_sample = this_frame_sample + decoder->private_->last_frame.header.blocksize;
+/*@@@@@@ what will decode position be if at end of stream? */
+			if(!FLAC__stream_decoder_get_decode_position(decoder, &upper_bound)) {
+				decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+				return false;
+			}
+			approx_bytes_per_frame = (uint32_t)(2 * (upper_bound - pos) / 3 + 16);
+		}
+		else { /* target_sample >= this_frame_sample + this frame's blocksize */
+			lower_bound_sample = this_frame_sample + decoder->private_->last_frame.header.blocksize;
+			if(!FLAC__stream_decoder_get_decode_position(decoder, &lower_bound)) {
+				decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+				return false;
+			}
+			approx_bytes_per_frame = (uint32_t)(2 * (lower_bound - pos) / 3 + 16);
+		}
+	}
+
+	return true;
+}
+
+FLAC__StreamDecoderReadStatus file_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+	(void)client_data;
+
+	if(*bytes > 0) {
+		*bytes = fread(buffer, sizeof(FLAC__byte), *bytes, decoder->private_->file);
+		if(ferror(decoder->private_->file))
+			return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+		else if(*bytes == 0)
+			return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+		else
+			return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+	}
+	else
+		return FLAC__STREAM_DECODER_READ_STATUS_ABORT; /* abort to avoid a deadlock */
+}
+
+FLAC__StreamDecoderSeekStatus file_seek_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+{
+	(void)client_data;
+
+	if(decoder->private_->file == stdin)
+		return FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED;
+	else if(fseeko(decoder->private_->file, (FLAC__off_t)absolute_byte_offset, SEEK_SET) < 0)
+		return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+	else
+		return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
+}
+
+FLAC__StreamDecoderTellStatus file_tell_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+{
+	FLAC__off_t pos;
+	(void)client_data;
+
+	if(decoder->private_->file == stdin)
+		return FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED;
+	else if((pos = ftello(decoder->private_->file)) < 0)
+		return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+	else {
+		*absolute_byte_offset = (FLAC__uint64)pos;
+		return FLAC__STREAM_DECODER_TELL_STATUS_OK;
+	}
+}
+
+FLAC__StreamDecoderLengthStatus file_length_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data)
+{
+	struct flac_stat_s filestats;
+	(void)client_data;
+
+	if(decoder->private_->file == stdin)
+		return FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED;
+	else if(flac_fstat(fileno(decoder->private_->file), &filestats) != 0)
+		return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
+	else {
+		*stream_length = (FLAC__uint64)filestats.st_size;
+		return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
+	}
+}
+
+FLAC__bool file_eof_callback_(const FLAC__StreamDecoder *decoder, void *client_data)
+{
+	(void)client_data;
+
+	return feof(decoder->private_->file)? true : false;
+}
+
+void *get_client_data_from_decoder(FLAC__StreamDecoder *decoder)
+{
+	return decoder->private_->client_data;
+}
--- /dev/null
+++ b/src/libflac/window.c
@@ -1,0 +1,272 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2006-2009  Josh Coalson
+ * Copyright (C) 2011-2016  Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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.
+ */
+
+#include <math.h>
+#include "share/compat.h"
+#include "FLAC/format.h"
+#include "private/window.h"
+
+void FLAC__window_bartlett(FLAC__real *window, const FLAC__int32 L)
+{
+	const FLAC__int32 N = L - 1;
+	FLAC__int32 n;
+
+	if (L & 1) {
+		for (n = 0; n <= N/2; n++)
+			window[n] = 2.0f * n / (float)N;
+		for (; n <= N; n++)
+			window[n] = 2.0f - 2.0f * n / (float)N;
+	}
+	else {
+		for (n = 0; n <= L/2-1; n++)
+			window[n] = 2.0f * n / (float)N;
+		for (; n <= N; n++)
+			window[n] = 2.0f - 2.0f * n / (float)N;
+	}
+}
+
+void FLAC__window_bartlett_hann(FLAC__real *window, const FLAC__int32 L)
+{
+	const FLAC__int32 N = L - 1;
+	FLAC__int32 n;
+
+	for (n = 0; n < L; n++)
+		window[n] = (FLAC__real)(0.62f - 0.48f * fabs((float)n/(float)N-0.5f) - 0.38f * cos(2.0f * M_PI * ((float)n/(float)N)));
+}
+
+void FLAC__window_blackman(FLAC__real *window, const FLAC__int32 L)
+{
+	const FLAC__int32 N = L - 1;
+	FLAC__int32 n;
+
+	for (n = 0; n < L; n++)
+		window[n] = (FLAC__real)(0.42f - 0.5f * cos(2.0f * M_PI * n / N) + 0.08f * cos(4.0f * M_PI * n / N));
+}
+
+/* 4-term -92dB side-lobe */
+void FLAC__window_blackman_harris_4term_92db_sidelobe(FLAC__real *window, const FLAC__int32 L)
+{
+	const FLAC__int32 N = L - 1;
+	FLAC__int32 n;
+
+	for (n = 0; n <= N; n++)
+		window[n] = (FLAC__real)(0.35875f - 0.48829f * cos(2.0f * M_PI * n / N) + 0.14128f * cos(4.0f * M_PI * n / N) - 0.01168f * cos(6.0f * M_PI * n / N));
+}
+
+void FLAC__window_connes(FLAC__real *window, const FLAC__int32 L)
+{
+	const FLAC__int32 N = L - 1;
+	const double N2 = (double)N / 2.;
+	FLAC__int32 n;
+
+	for (n = 0; n <= N; n++) {
+		double k = ((double)n - N2) / N2;
+		k = 1.0f - k * k;
+		window[n] = (FLAC__real)(k * k);
+	}
+}
+
+void FLAC__window_flattop(FLAC__real *window, const FLAC__int32 L)
+{
+	const FLAC__int32 N = L - 1;
+	FLAC__int32 n;
+
+	for (n = 0; n < L; n++)
+		window[n] = (FLAC__real)(0.21557895f - 0.41663158f * cos(2.0f * M_PI * n / N) + 0.277263158f * cos(4.0f * M_PI * n / N) - 0.083578947f * cos(6.0f * M_PI * n / N) + 0.006947368f * cos(8.0f * M_PI * n / N));
+}
+
+void FLAC__window_gauss(FLAC__real *window, const FLAC__int32 L, const FLAC__real stddev)
+{
+	const FLAC__int32 N = L - 1;
+	const double N2 = (double)N / 2.;
+	FLAC__int32 n;
+
+	for (n = 0; n <= N; n++) {
+		const double k = ((double)n - N2) / (stddev * N2);
+		window[n] = (FLAC__real)exp(-0.5f * k * k);
+	}
+}
+
+void FLAC__window_hamming(FLAC__real *window, const FLAC__int32 L)
+{
+	const FLAC__int32 N = L - 1;
+	FLAC__int32 n;
+
+	for (n = 0; n < L; n++)
+		window[n] = (FLAC__real)(0.54f - 0.46f * cos(2.0f * M_PI * n / N));
+}
+
+void FLAC__window_hann(FLAC__real *window, const FLAC__int32 L)
+{
+	const FLAC__int32 N = L - 1;
+	FLAC__int32 n;
+
+	for (n = 0; n < L; n++)
+		window[n] = (FLAC__real)(0.5f - 0.5f * cos(2.0f * M_PI * n / N));
+}
+
+void FLAC__window_kaiser_bessel(FLAC__real *window, const FLAC__int32 L)
+{
+	const FLAC__int32 N = L - 1;
+	FLAC__int32 n;
+
+	for (n = 0; n < L; n++)
+		window[n] = (FLAC__real)(0.402f - 0.498f * cos(2.0f * M_PI * n / N) + 0.098f * cos(4.0f * M_PI * n / N) - 0.001f * cos(6.0f * M_PI * n / N));
+}
+
+void FLAC__window_nuttall(FLAC__real *window, const FLAC__int32 L)
+{
+	const FLAC__int32 N = L - 1;
+	FLAC__int32 n;
+
+	for (n = 0; n < L; n++)
+		window[n] = (FLAC__real)(0.3635819f - 0.4891775f*cos(2.0f*M_PI*n/N) + 0.1365995f*cos(4.0f*M_PI*n/N) - 0.0106411f*cos(6.0f*M_PI*n/N));
+}
+
+void FLAC__window_rectangle(FLAC__real *window, const FLAC__int32 L)
+{
+	FLAC__int32 n;
+
+	for (n = 0; n < L; n++)
+		window[n] = 1.0f;
+}
+
+void FLAC__window_triangle(FLAC__real *window, const FLAC__int32 L)
+{
+	FLAC__int32 n;
+
+	if (L & 1) {
+		for (n = 1; n <= (L+1)/2; n++)
+			window[n-1] = 2.0f * n / ((float)L + 1.0f);
+		for (; n <= L; n++)
+			window[n-1] = (float)(2 * (L - n + 1)) / ((float)L + 1.0f);
+	}
+	else {
+		for (n = 1; n <= L/2; n++)
+			window[n-1] = 2.0f * n / ((float)L + 1.0f);
+		for (; n <= L; n++)
+			window[n-1] = (float)(2 * (L - n + 1)) / ((float)L + 1.0f);
+	}
+}
+
+void FLAC__window_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p)
+{
+	if (p <= 0.0)
+		FLAC__window_rectangle(window, L);
+	else if (p >= 1.0)
+		FLAC__window_hann(window, L);
+	else {
+		const FLAC__int32 Np = (FLAC__int32)(p / 2.0f * L) - 1;
+		FLAC__int32 n;
+		/* start with rectangle... */
+		FLAC__window_rectangle(window, L);
+		/* ...replace ends with hann */
+		if (Np > 0) {
+			for (n = 0; n <= Np; n++) {
+				window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * n / Np));
+				window[L-Np-1+n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * (n+Np) / Np));
+			}
+		}
+	}
+}
+
+void FLAC__window_partial_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end)
+{
+	const FLAC__int32 start_n = (FLAC__int32)(start * L);
+	const FLAC__int32 end_n = (FLAC__int32)(end * L);
+	const FLAC__int32 N = end_n - start_n;
+	FLAC__int32 Np, n, i;
+
+	if (p <= 0.0f)
+		FLAC__window_partial_tukey(window, L, 0.05f, start, end);
+	else if (p >= 1.0f)
+		FLAC__window_partial_tukey(window, L, 0.95f, start, end);
+	else {
+
+		Np = (FLAC__int32)(p / 2.0f * N);
+
+		for (n = 0; n < start_n && n < L; n++)
+			window[n] = 0.0f;
+		for (i = 1; n < (start_n+Np) && n < L; n++, i++)
+			window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Np));
+		for (; n < (end_n-Np) && n < L; n++)
+			window[n] = 1.0f;
+		for (i = Np; n < end_n && n < L; n++, i--)
+			window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Np));
+		for (; n < L; n++)
+			window[n] = 0.0f;
+	}
+}
+
+void FLAC__window_punchout_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end)
+{
+	const FLAC__int32 start_n = (FLAC__int32)(start * L);
+	const FLAC__int32 end_n = (FLAC__int32)(end * L);
+	FLAC__int32 Ns, Ne, n, i;
+
+	if (p <= 0.0f)
+		FLAC__window_punchout_tukey(window, L, 0.05f, start, end);
+	else if (p >= 1.0f)
+		FLAC__window_punchout_tukey(window, L, 0.95f, start, end);
+	else {
+
+		Ns = (FLAC__int32)(p / 2.0f * start_n);
+		Ne = (FLAC__int32)(p / 2.0f * (L - end_n));
+
+		for (n = 0, i = 1; n < Ns && n < L; n++, i++)
+			window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Ns));
+		for (; n < start_n-Ns && n < L; n++)
+			window[n] = 1.0f;
+		for (i = Ns; n < start_n && n < L; n++, i--)
+			window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Ns));
+		for (; n < end_n && n < L; n++)
+			window[n] = 0.0f;
+		for (i = 1; n < end_n+Ne && n < L; n++, i++)
+			window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Ne));
+		for (; n < L - (Ne) && n < L; n++)
+			window[n] = 1.0f;
+		for (i = Ne; n < L; n++, i--)
+			window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Ne));
+	}
+}
+
+void FLAC__window_welch(FLAC__real *window, const FLAC__int32 L)
+{
+	const FLAC__int32 N = L - 1;
+	const double N2 = (double)N / 2.;
+	FLAC__int32 n;
+
+	for (n = 0; n <= N; n++) {
+		const double k = ((double)n - N2) / N2;
+		window[n] = (FLAC__real)(1.0f - k * k);
+	}
+}
--- /dev/null
+++ b/src/libflac/windows_unicode_filenames.c
@@ -1,0 +1,194 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2013-2016  Xiph.Org Foundation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - 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.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``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 FOUNDATION OR
+ * CONTRIBUTORS 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_MEAN_AND_LEAN
+#include <io.h>
+#include <windows.h>
+#include "share/windows_unicode_filenames.h"
+
+/* convert UTF-8 back to WCHAR. Caller is responsible for freeing memory */
+static wchar_t *wchar_from_utf8(const char *str)
+{
+	wchar_t *widestr;
+	int len;
+
+	if (!str)
+		return NULL;
+	if ((len = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0)) == 0)
+		return NULL;
+	if ((widestr = (wchar_t *)malloc(len*sizeof(wchar_t))) == NULL)
+		return NULL;
+	if (MultiByteToWideChar(CP_UTF8, 0, str, -1, widestr, len) == 0) {
+		free(widestr);
+		widestr = NULL;
+	}
+
+	return widestr;
+}
+
+
+static FLAC__bool utf8_filenames = false;
+
+
+void flac_internal_set_utf8_filenames(FLAC__bool flag)
+{
+	utf8_filenames = flag ? true : false;
+}
+
+FLAC__bool flac_internal_get_utf8_filenames(void)
+{
+	return utf8_filenames;
+}
+
+/* file functions */
+
+FILE* flac_internal_fopen_utf8(const char *filename, const char *mode)
+{
+	if (!utf8_filenames) {
+		return fopen(filename, mode);
+	} else {
+		wchar_t *wname = NULL;
+		wchar_t *wmode = NULL;
+		FILE *f = NULL;
+
+		do {
+			wname = wchar_from_utf8(filename);
+			if (!wname) break;
+			wmode = wchar_from_utf8(mode);
+			if (!wmode) break;
+			f = _wfopen(wname, wmode);
+		} while(0);
+
+		free(wname);
+		free(wmode);
+
+		return f;
+	}
+}
+
+int flac_internal_stat64_utf8(const char *path, struct __stat64 *buffer)
+{
+	if (!utf8_filenames) {
+		return _stat64(path, buffer);
+	} else {
+		wchar_t *wpath;
+		int ret;
+
+		wpath = wchar_from_utf8(path);
+		if (!wpath) return -1;
+		ret = _wstat64(wpath, buffer);
+		free(wpath);
+
+		return ret;
+	}
+}
+
+int flac_internal_chmod_utf8(const char *filename, int pmode)
+{
+	if (!utf8_filenames) {
+		return _chmod(filename, pmode);
+	} else {
+		wchar_t *wname;
+		int ret;
+
+		wname = wchar_from_utf8(filename);
+		if (!wname) return -1;
+		ret = _wchmod(wname, pmode);
+		free(wname);
+
+		return ret;
+	}
+}
+
+int flac_internal_utime_utf8(const char *filename, struct utimbuf *times)
+{
+	if (!utf8_filenames) {
+		return utime(filename, times);
+	} else {
+		wchar_t *wname;
+		struct __utimbuf64 ut;
+		int ret;
+
+		wname = wchar_from_utf8(filename);
+		if (!wname) return -1;
+		ut.actime = times->actime;
+		ut.modtime = times->modtime;
+		ret = _wutime64(wname, &ut);
+		free(wname);
+
+		return ret;
+	}
+}
+
+int flac_internal_unlink_utf8(const char *filename)
+{
+	if (!utf8_filenames) {
+		return _unlink(filename);
+	} else {
+		wchar_t *wname;
+		int ret;
+
+		wname = wchar_from_utf8(filename);
+		if (!wname) return -1;
+		ret = _wunlink(wname);
+		free(wname);
+
+		return ret;
+	}
+}
+
+int flac_internal_rename_utf8(const char *oldname, const char *newname)
+{
+	if (!utf8_filenames) {
+		return rename(oldname, newname);
+	} else {
+		wchar_t *wold = NULL;
+		wchar_t *wnew = NULL;
+		int ret = -1;
+
+		do {
+			wold = wchar_from_utf8(oldname);
+			if (!wold) break;
+			wnew = wchar_from_utf8(newname);
+			if (!wnew) break;
+			ret = _wrename(wold, wnew);
+		} while(0);
+
+		free(wold);
+		free(wnew);
+
+		return ret;
+	}
+}
+
+#endif
--- /dev/null
+++ b/src/modloaders/pt2_load_mod15.c
@@ -1,0 +1,270 @@
+/* 15-sample Amiga MOD loader (The Ultimate Soundtracker, etc.)
+**
+** Note: Data sanitation is done in the last stage
+** of module loading, so you don't need to do that here.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include "../pt2_header.h"
+#include "../pt2_config.h"
+#include "../pt2_structs.h"
+#include "../pt2_replayer.h"
+#include "../pt2_textout.h"
+#include "../pt2_visuals.h"
+
+static int32_t realSampleLengths[15];
+
+module_t *loadMod15(uint8_t *buffer, uint32_t filesize)
+{
+	(void)filesize;
+
+	module_t *m = createEmptyMod();
+	if (m == NULL)
+	{
+		statusOutOfMemory();
+		goto loadError;
+	}
+
+	bool veryLateSTKVerFlag = false; // "DFJ SoundTracker III" and later
+	bool lateSTKVerFlag = false; // "TJC SoundTracker II" and later
+
+	const uint8_t *p = buffer;
+	memcpy(m->header.name, p, 20); p += 20;
+
+	// read sample headers
+	moduleSample_t *s = m->samples;
+	for (int32_t i = 0; i < 15; i++, s++)
+	{
+		memcpy(s->text, p, 22); p += 22;
+
+		realSampleLengths[i] = ((p[0] << 8) | p[1]) * 2; p += 2;
+		s->length = (realSampleLengths[i] > config.maxSampleLength) ? config.maxSampleLength : realSampleLengths[i];
+
+		/* Only late versions of Ultimate SoundTracker can have samples larger than 9999 bytes.
+		** If detected, we know for sure that this is a late STK module.
+		*/
+		if (s->length > 9999)
+			lateSTKVerFlag = true;
+
+		p++; // Hi-byte of volume, no finetune in STK/UST modules. Skip it.
+		s->volume = *p++;
+
+		// in The Ultimate SoundTracker, sample loop start is in bytes, not words
+		s->loopStart = (p[0] << 8) | p[1]; p += 2;
+		s->loopLength = ((p[0] << 8) | p[1]) * 2; p += 2;
+	}
+
+	m->header.numOrders = *p++;
+
+	if (m->header.numOrders == 0 || m->header.numOrders > 128)
+	{
+		displayErrorMsg("NOT A MOD FILE !");
+		goto loadError;
+	}
+
+	uint8_t initTempo = *p++;
+	if (initTempo > 220)
+	{
+		displayErrorMsg("NOT A MOD FILE !");
+		goto loadError;
+	}
+
+	// 120 is a special case and means 50Hz (125BPM)
+	if (initTempo == 0)
+		initTempo = 120;
+
+	// jjk55.mod by Jesper Kyd has a bogus STK tempo value that should be ignored (XXX: hackish...)
+	if (!strcmp("jjk55", m->header.name))
+		initTempo = 120;
+
+	m->header.initialTempo = 125;
+	if (initTempo != 120)
+	{
+		if (initTempo > 220)
+			initTempo = 220;
+
+		// convert UST tempo to BPM
+		uint16_t ciaPeriod = (240 - initTempo) * 122;
+
+		double dHz = (double)CIA_PAL_CLK / (ciaPeriod+1); // +1, CIA triggers on underflow
+		int32_t BPM = (int32_t)((dHz * (125.0 / 50.0)) + 0.5);
+
+		m->header.initialTempo = (uint16_t)BPM;
+	}
+
+	// read orders and count number of patterns
+	int32_t numPatterns = 0;
+	for (int32_t i = 0; i < MOD_ORDERS; i++)
+	{
+		m->header.order[i] = *p++;
+		if (m->header.order[i] > numPatterns)
+			numPatterns = m->header.order[i];
+	}
+	numPatterns++;
+
+	if (numPatterns > MAX_PATTERNS)
+	{
+		displayErrorMsg("UNSUPPORTED MOD !");
+		goto loadError;
+	}
+
+	// load pattern data
+	for (int32_t i = 0; i < numPatterns; i++)
+	{
+		note_t *note = m->patterns[i];
+		for (int32_t j = 0; j < MOD_ROWS; j++)
+		{
+			for (int32_t k = 0; k < 4; k++, note++, p += 4)
+			{
+				note->period = ((p[0] & 0x0F) << 8) | p[1];
+				note->sample = (p[0] & 0xF0) | (p[2] >> 4);
+				note->command = p[2] & 0x0F;
+				note->param = p[3];
+
+				// added sanitation not present in original PT
+				if (note->sample > 31)
+					note->sample = 0;
+
+				if (note->command == 0xC || note->command == 0xD || note->command == 0xE)
+				{
+					// "TJC SoundTracker II" and later
+					lateSTKVerFlag = true;
+				}
+
+				if (note->command == 0xF)
+				{
+					// "DFJ SoundTracker III" and later
+					lateSTKVerFlag = true;
+					veryLateSTKVerFlag = true;
+				}
+			}
+		}
+	}
+
+	// pattern command conversion
+	for (int32_t i = 0; i < numPatterns; i++)
+	{
+		note_t *note = m->patterns[i];
+		for (int32_t j = 0; j < MOD_ROWS*4; j++, note++)
+		{
+			// convert STK effects to PT effects
+
+			if (!lateSTKVerFlag)
+			{
+				// old SoundTracker 1.x commands
+
+				if (note->command == 1)
+				{
+					// arpeggio
+					note->command = 0;
+				}
+				else if (note->command == 2)
+				{
+					// pitch slide
+					if (note->param & 0xF0)
+					{
+						// pitch slide down
+						note->command = 2;
+						note->param >>= 4;
+					}
+					else if (note->param & 0x0F)
+					{
+						// pitch slide up
+						note->command = 1;
+					}
+				}
+			}
+			else
+			{
+				// "DFJ SoundTracker II" or later
+
+				// TODO: This needs more detection and is NOT correct!
+				if (note->command == 0xD)
+				{
+					if (veryLateSTKVerFlag) // "DFJ SoundTracker III" or later
+					{
+						// pattern break w/ no param (param must be cleared to fix some songs)
+						note->param = 0;
+					}
+					else
+					{
+						// volume slide
+						note->command = 0xA;
+					}
+				}
+			}
+
+			// effect F with param 0x00 does nothing in UST/STK (I think?)
+			if (note->command == 0xF && note->param == 0)
+				note->command = 0;
+
+			// remove E8x (Karplus-Strong is only supported for ProTracker .MODs)
+			if (note->command == 0xE && (note->param >> 4) == 0x8)
+			{
+				note->command = 0;
+				note->param = 0;
+			}
+
+			// remove EFx (Invert Loop is only supported for ProTracker .MODs)
+			if (note->command == 0xE && (note->param >> 4) == 0xF)
+			{
+				note->command = 0;
+				note->param = 0;
+			}
+		}
+	}
+
+	// load sample data
+	s = m->samples;
+	for (int32_t i = 0; i < 15; i++, s++)
+	{
+		// For Ultimate SoundTracker modules, only the loop area of a looped sample is played.
+		if (s->loopStart > 0 && s->loopLength < s->length)
+		{
+			s->length -= s->loopStart;
+			p += s->loopStart;
+			s->loopStart = 0;
+		}
+
+		/* We don't support loading samples bigger than 65534 bytes in our PT2 clone,
+		** so skip overflown data in .MOD file if present.
+		*/
+		int32_t bytesToSkip = 0;
+		if (realSampleLengths[i] > config.maxSampleLength)
+			bytesToSkip = realSampleLengths[i] - config.maxSampleLength;
+
+		// For Ultimate SoundTracker modules, don't load sample data after loop end
+		int32_t loopEnd = s->loopStart + s->loopLength;
+		if (loopEnd > 2 && s->length > loopEnd)
+		{
+			bytesToSkip += s->length-loopEnd;
+			s->length = loopEnd;
+		}
+
+		memcpy(&m->sampleData[s->offset], p, s->length); p += s->length;
+		if (bytesToSkip > 0)
+			p += bytesToSkip;
+	}
+
+	return m;
+
+loadError:
+	if (m != NULL)
+	{
+		for (int32_t i = 0; i < MAX_PATTERNS; i++)
+		{
+			if (m->patterns[i] != NULL)
+				free(m->patterns[i]);
+		}
+
+		if (m->sampleData != NULL)
+			free(m->sampleData);
+
+		free(m);
+	}
+
+	return NULL;
+}
--- /dev/null
+++ b/src/modloaders/pt2_load_mod15.h
@@ -1,0 +1,7 @@
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "../pt2_structs.h"
+
+module_t *loadMod15(uint8_t *buffer, uint32_t filesize);
--- /dev/null
+++ b/src/modloaders/pt2_load_mod31.c
@@ -1,0 +1,262 @@
+/* 31-sample MOD loader (Amiga, PC, etc.)
+**
+** Note: Data sanitation is done in the last stage
+** of module loading, so you don't need to do that here.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h> // isdigit()
+#include <stdint.h>
+#include <stdbool.h>
+#include "../pt2_header.h"
+#include "../pt2_paula.h" // PAULA_VOICES
+#include "../pt2_config.h"
+#include "../pt2_structs.h"
+#include "../pt2_replayer.h"
+#include "../pt2_textout.h"
+#include "../pt2_visuals.h"
+
+enum // 31-sample .MOD types
+{
+	FORMAT_UNKNOWN,
+
+	FORMAT_PT,  // ProTracker or compatible
+	FORMAT_FLT, // Startrekker (4 channels)
+	FORMAT_FT2, // FT2 (or other trackers, multichannel)
+	FORMAT_NT,  // NoiseTracker
+	FORMAT_HMNT // His Master's NoiseTracker (special one)
+};
+
+static int32_t realSampleLengths[MOD_SAMPLES];
+
+static uint8_t getMod31Type(uint8_t *buffer, uint32_t filesize, uint8_t *numChannels); // 0 = not detected
+bool detectMod31(uint8_t *buffer, uint32_t filesize);
+
+module_t *loadMod31(uint8_t *buffer, uint32_t filesize)
+{
+	module_t *m = createEmptyMod();
+	if (m == NULL)
+	{
+		statusOutOfMemory();
+		goto loadError;
+	}
+
+	uint8_t numChannels;
+	uint8_t modFormat = getMod31Type(buffer, filesize, &numChannels);
+	if (modFormat == FORMAT_UNKNOWN || numChannels > PAULA_VOICES)
+	{
+		displayErrorMsg("UNSUPPORTED MOD !");
+		goto loadError;
+	}
+
+	uint8_t *p = buffer;
+
+	memcpy(m->header.name, p, 20); p += 20;
+
+	// read sample headers
+	moduleSample_t *s = m->samples;
+	for (int32_t i = 0; i < MOD_SAMPLES; i++, s++)
+	{
+		memcpy(s->text, p, 22); p += 22;
+
+		realSampleLengths[i] = ((p[0] << 8) | p[1]) * 2; p += 2;
+		s->length = (realSampleLengths[i] > config.maxSampleLength) ? config.maxSampleLength : realSampleLengths[i];
+
+		s->fineTune = *p++ & 0xF;
+		s->volume = *p++;
+
+		s->loopStart = ((p[0] << 8) | p[1]) * 2; p += 2;
+		s->loopLength = ((p[0] << 8) | p[1]) * 2; p += 2;
+
+		// fix for poorly converted STK (< v2.5) -> PT/NT modules
+		if (s->loopLength > 2 && s->loopStart+s->loopLength > s->length)
+		{
+			if ((s->loopStart/2) + s->loopLength <= s->length)
+				s->loopStart /= 2;
+		}
+	}
+
+	m->header.numOrders = *p++;
+	p++; // skip uninteresting field (127 in PT MOds, "restart pos" in PC MODs)
+
+	if (modFormat == FORMAT_PT && m->header.numOrders == 129)
+		m->header.numOrders = 127; // fixes a specific copy of beatwave.mod (XXX: hackish...)
+
+	if (m->header.numOrders == 0 || m->header.numOrders > 129)
+	{
+		displayErrorMsg("NOT A MOD FILE !");
+		goto loadError;
+	}
+
+	// read orders and count number of patterns
+	int32_t numPatterns = 0;
+	for (int32_t i = 0; i < MOD_ORDERS; i++)
+	{
+		m->header.order[i] = *p++;
+		if (m->header.order[i] > numPatterns)
+			numPatterns = m->header.order[i];
+	}
+	numPatterns++;
+
+	if (numPatterns > MAX_PATTERNS)
+	{
+		displayErrorMsg("UNSUPPORTED MOD !");
+		goto loadError;
+	}
+
+	p += 4; // skip magic ID (already handled)
+
+	// load pattern data
+	for (int32_t i = 0; i < numPatterns; i++)
+	{
+		note_t *note = m->patterns[i];
+		for (int32_t j = 0; j < MOD_ROWS; j++)
+		{
+			for (int32_t k = 0; k < numChannels; k++, note++, p += 4)
+			{
+				note->period = ((p[0] & 0x0F) << 8) | p[1];
+				note->sample = ((p[0] & 0xF0) | (p[2] >> 4)) & 31;
+				note->command = p[2] & 0x0F;
+				note->param = p[3];
+			}
+
+			if (numChannels < PAULA_VOICES)
+				note += PAULA_VOICES-numChannels;
+		}
+	}
+
+	if (modFormat != FORMAT_PT) // pattern command conversion for non-PT formats
+	{
+		for (int32_t i = 0; i < numPatterns; i++)
+		{
+			note_t *note = m->patterns[i];
+			for (int32_t j = 0; j < MOD_ROWS*4; j++, note++)
+			{
+				if (modFormat == FORMAT_NT || modFormat == FORMAT_HMNT)
+				{
+					// any Dxx == D00 in NT/HMNT
+					if (note->command == 0xD)
+						note->param = 0;
+
+					// effect F with param 0x00 does nothing in NT/HMNT
+					if (note->command == 0xF && note->param == 0)
+						note->command = 0;
+				}
+				else if (modFormat == FORMAT_FLT) // Startrekker (4 channels)
+				{
+					if (note->command == 0xE) // remove unsupported "assembly macros" command
+					{
+						note->command = 0;
+						note->param = 0;
+					}
+
+					// Startrekker is always in vblank mode, and limits speed to 0x1F
+					if (note->command == 0xF && note->param > 0x1F)
+						note->param = 0x1F;
+				}
+
+				// remove E8x (Karplus-Strong is only supported for ProTracker .MODs)
+				if (note->command == 0xE && (note->param >> 4) == 0x8)
+				{
+					note->command = 0;
+					note->param = 0;
+				}
+
+				// remove EFx (Invert Loop is only supported for ProTracker .MODs)
+				if (note->command == 0xE && (note->param >> 4) == 0xF)
+				{
+					note->command = 0;
+					note->param = 0;
+				}
+			}
+		}
+	}
+
+	// load sample data
+	s = m->samples;
+	for (int32_t i = 0; i < MOD_SAMPLES; i++, s++)
+	{
+		/* We don't support loading samples bigger than 65534 bytes in our PT2 clone,
+		** so skip overflown data in .MOD file if present.
+		*/
+		int32_t bytesToSkip = 0;
+		if (realSampleLengths[i] > config.maxSampleLength)
+			bytesToSkip = realSampleLengths[i] - config.maxSampleLength;
+
+		memcpy(&m->sampleData[s->offset], p, s->length); p += s->length;
+		if (bytesToSkip > 0)
+			p += bytesToSkip;
+	}
+
+	m->header.initialTempo = 125;
+	return m;
+
+loadError:
+	if (m != NULL)
+	{
+		for (int32_t i = 0; i < MAX_PATTERNS; i++)
+		{
+			if (m->patterns[i] != NULL)
+				free(m->patterns[i]);
+		}
+
+		if (m->sampleData != NULL)
+			free(m->sampleData);
+
+		free(m);
+	}
+
+	return NULL;
+}
+
+static uint8_t getMod31Type(uint8_t *buffer, uint32_t filesize, uint8_t *numChannels) // 0 = not detected
+{
+	const uint8_t *id = &buffer[1080];
+#define ID(s) !memcmp(s, id, 4)
+
+	*numChannels = 0;
+	if (buffer == NULL || filesize < 1084+1024)
+		return FORMAT_UNKNOWN;
+
+	*numChannels = 4;
+	if (ID("M.K.") || ID("M!K!") || ID("NSMS") || ID("LARD") || ID("PATT"))
+	{
+		return FORMAT_PT; // ProTracker (or compatible)
+	}
+	else if (ID("FLT4"))
+	{
+		return FORMAT_FLT; // Startrekker (4 channels)
+	}
+	else if (ID("N.T."))
+	{
+		return FORMAT_NT; // NoiseTracker
+	}
+	else if (ID("M&K!") || ID("FEST"))
+	{
+		return FORMAT_HMNT; // His Master's NoiseTracker
+	}
+	else if (isdigit(id[0]) && (id[1] == 'C' && id[2] == 'H' && id[3] == 'N'))
+	{
+		*numChannels = id[0] - '0';
+		return FORMAT_FT2; // Fasttracker II 1..9 channels (or other trackers)
+	}
+	else if (isdigit(id[0]) && isdigit(id[1]) && id[1] == 'C' && id[2] == 'H')
+	{
+		*numChannels = ((id[0] - '0') * 10) + (id[1] - '0');
+		return FORMAT_FT2; // Fasttracker II 10+ channels (or other trackers)
+	}
+
+	return FORMAT_UNKNOWN;
+}
+
+bool detectMod31(uint8_t *buffer, uint32_t filesize)
+{
+	uint8_t junk;
+
+	if (buffer == NULL || filesize < 1084+1024)
+		return FORMAT_UNKNOWN;
+
+	return getMod31Type(buffer, filesize, &junk) != FORMAT_UNKNOWN;
+}
--- /dev/null
+++ b/src/modloaders/pt2_load_mod31.h
@@ -1,0 +1,8 @@
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "../pt2_structs.h"
+
+bool detectMod31(uint8_t *buffer, uint32_t filesize);
+module_t *loadMod31(uint8_t *buffer, uint32_t filesize);
--- /dev/null
+++ b/src/modloaders/pt2_pp_unpack.c
@@ -1,0 +1,152 @@
+/* PowerPacker unpack code taken from Heikki Orsila's amigadepack. Seems to have no license,
+** so I'll assume it fits into BSD 3-Clause. If not, feel free to contact me at my email
+** address found at the bottom of 16-bits.org.
+**
+** Edited by me (8bitbubsy).
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#define READ_BITS(nbits, var) \
+	bitCnt = (nbits); \
+	while (bitsLeft < bitCnt) \
+	{ \
+		if (bufSrc < src) \
+			return false; \
+		bitBuffer |= ((*--bufSrc) << bitsLeft); \
+		bitsLeft += 8; \
+	} \
+	(var) = 0; \
+	bitsLeft -= bitCnt; \
+	while (bitCnt--) \
+	{ \
+		(var) = ((var) << 1) | (bitBuffer & 1); \
+		bitBuffer >>= 1; \
+	}
+
+static bool decrunch(uint8_t *src, uint8_t *dst, uint8_t *offsetLens, uint32_t srcLen, uint32_t dstLen, uint8_t skipBits)
+{
+	uint8_t bitCnt;
+	uint32_t x, todo, offset;
+
+	if (src == NULL || dst == NULL || offsetLens == NULL)
+		return false;
+
+	uint8_t bitsLeft = 0;
+	uint32_t bitBuffer = 0;
+	uint32_t written = 0;
+	uint8_t *bufSrc = src + srcLen;
+	uint8_t *out = dst + dstLen;
+	uint8_t *dstEnd = out;
+
+	READ_BITS(skipBits, x);
+	while (written < dstLen)
+	{
+		READ_BITS(1, x);
+		if (x == 0)
+		{
+			todo = 1;
+
+			do
+			{
+				READ_BITS(2, x);
+				todo += x;
+			}
+			while (x == 3);
+
+			while (todo--)
+			{
+				READ_BITS(8, x);
+				if (out <= dst)
+					return false;
+
+				*--out = (uint8_t)x;
+				written++;
+			}
+
+			if (written == dstLen)
+				break;
+		}
+
+		READ_BITS(2, x);
+		uint32_t offBits = offsetLens[x];
+		todo = x + 2;
+
+		if (x == 3)
+		{
+			READ_BITS(1, x);
+			if (x == 0) offBits = 7;
+
+			READ_BITS((uint8_t)offBits, offset);
+			do
+			{
+				READ_BITS(3, x);
+				todo += x;
+			}
+			while (x == 7);
+		}
+		else
+		{
+			READ_BITS((uint8_t)offBits, offset);
+		}
+
+		if (out+offset >= dstEnd)
+			return false;
+
+		while (todo--)
+		{
+			x = out[offset];
+			if (out <= dst)
+				return false;
+
+			*--out = (uint8_t)x;
+			written++;
+		}
+	}
+
+	return true;
+}
+
+uint8_t *unpackPP(FILE *f, uint32_t *filesize)
+{
+	uint8_t *outBuffer, ppCrunchData[4], *ppBuffer;
+	uint32_t ppPackLen, ppUnpackLen;
+
+	ppPackLen = *filesize;
+	if ((ppPackLen & 3) != 0 || ppPackLen <= 12)
+		return NULL;
+
+	ppBuffer = (uint8_t *)malloc(ppPackLen);
+	if (ppBuffer == NULL)
+		return NULL;
+
+	fseek(f, ppPackLen-4, SEEK_SET);
+	fread(ppCrunchData, 1, 4, f);
+
+	ppUnpackLen = (ppCrunchData[0] << 16) | (ppCrunchData[1] << 8) | ppCrunchData[2];
+
+	outBuffer = (uint8_t *)malloc(ppUnpackLen);
+	if (outBuffer == NULL)
+	{
+		free(ppBuffer);
+		return NULL;
+	}
+
+	rewind(f);
+	fread(ppBuffer, 1, ppPackLen, f);
+	fclose(f);
+
+	if (!decrunch(ppBuffer+8, outBuffer, ppBuffer+4, ppPackLen-12, ppUnpackLen, ppCrunchData[3]))
+	{
+		free(ppBuffer);
+		return NULL;
+	}
+
+	free(ppBuffer);
+	*filesize = ppUnpackLen;
+
+	return outBuffer;
+}
\ No newline at end of file
--- /dev/null
+++ b/src/modloaders/pt2_pp_unpack.h
@@ -1,0 +1,5 @@
+#pragma once
+
+#include <stdint.h>
+
+uint8_t *unpackPP(FILE *f, uint32_t *filesize);
--- /dev/null
+++ b/src/modloaders/pt2_xpk_unpack.c
@@ -1,0 +1,426 @@
+/* Taken from the OpenMPT project and converted to C.
+** OpenMPT shares the same license as the PT2 clone (BSD 3-clause),
+** so the licensing is compatible.
+**
+** This is probably not 100% safe code, but it works.
+*/
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include "../pt2_helpers.h"
+
+typedef struct XPKFILEHEADER
+{
+	char XPKF[4];
+	uint32_t SrcLen;
+	char SQSH[4];
+	uint32_t DstLen;
+	char Name[16];
+	uint32_t Reserved;
+} XPKFILEHEADER;
+
+typedef struct XPK_BufferBounds
+{
+	const uint8_t *pSrcBeg;
+	size_t SrcSize;
+} XPK_BufferBounds;
+
+static const uint8_t xpk_table[56] =
+{
+	2,3,4,5,6,7,8,0,3,2,4,5,6,7,8,0,4,3,5,
+	2,6,7,8,0,5,4,6,2,3,7,8,0,6,5,7,2,3,4,
+	8,0,7,6,8,2,3,4,5,0,8,7,6,2,3,4,5,0
+};
+
+static inline uint8_t SrcRead(size_t index, XPK_BufferBounds *bufs)
+{
+	assert(index < bufs->SrcSize);
+	if (index >= bufs->SrcSize)
+		return 0; // this is actually not how to do it, ugh...
+
+	return bufs->pSrcBeg[index];
+}
+
+static inline int32_t bfextu(size_t p, int32_t bo, int32_t bc, XPK_BufferBounds *bufs)
+{
+	p += (uint32_t)bo >> 3;
+
+	uint32_t r = SrcRead(p, bufs); p++;
+	r <<= 8;
+	r |= SrcRead(p, bufs); p++;
+	r <<= 8;
+	r |= SrcRead(p, bufs);
+	r <<= bo & 7;
+	r &= 0x00FFFFFF;
+	r >>= 24 - bc;
+
+	return r;
+}
+
+static inline int32_t bfexts(size_t p, int32_t bo, int32_t bc, XPK_BufferBounds *bufs)
+{
+	p += (uint32_t)bo >> 3;
+
+	uint32_t r = SrcRead(p, bufs); p++;
+	r <<= 8;
+	r |= SrcRead(p, bufs); p++;
+	r <<= 8;
+	r |= SrcRead(p, bufs);
+	r <<= (bo & 7) + 8;
+	r = (int32_t)r >> (32-bc);
+
+	return r;
+}
+
+static inline uint8_t XPK_ReadTable(int32_t index)
+{
+	if (index < 0 || index >= (int32_t)sizeof (xpk_table))
+		return 0; // this is actually not how to do it, ugh...
+
+	return xpk_table[index];
+}
+
+static bool XPK_DoUnpack(const uint8_t *src_, uint32_t srcLen, int32_t len, uint8_t **out)
+{
+	*out = NULL;
+	if (len <= 0)
+		return false;
+
+	int32_t d0, d1, d2, d3, d4, d5, d6, a2, a5, cup1;
+	const uint32_t unpackedLen = MIN((uint32_t)len, MIN(srcLen, UINT32_MAX / 20) * 20);
+
+	uint8_t *unpackedData = (uint8_t *)malloc(unpackedLen);
+	if (unpackedData == NULL)
+		return false;
+
+	uint8_t *PtrEnd = unpackedData + unpackedLen;
+	uint8_t *PtrOut = unpackedData;
+
+	XPK_BufferBounds bufs;
+	bufs.pSrcBeg = src_;
+	bufs.SrcSize = srcLen;
+
+	size_t src = 0;
+	size_t c = src;
+	while (len > 0)
+	{
+		int32_t type = SrcRead(c+0, &bufs);
+		int32_t cp = (SrcRead(c+4, &bufs)<<8) | (SrcRead(c+5, &bufs)); // packed
+		cup1 = (SrcRead(c+6, &bufs)<<8) | (SrcRead(c+7, &bufs)); // unpacked
+
+		c += 8;
+		src = c + 2;
+
+		if (type == 0) // RAW chunk
+		{
+			if (cp < 0 || cp > len)
+			{
+				free(unpackedData);
+				return false;
+			}
+
+			for (int32_t i = 0; i < cp; i++)
+				*PtrOut++ = SrcRead(c + i, &bufs);
+
+			c += cp;
+			len -= cp;
+			continue;
+		}
+
+		if (type != 1)
+			break;
+
+		if (cup1 > len)
+			cup1 = len;
+
+		len -= cup1;
+		cp = (cp + 3) & 0xFFFC;
+		c += cp;
+
+		d0 = d1 = d2 = a2 = 0;
+		d3 = SrcRead(src, &bufs); src++;
+		*PtrOut++ = (uint8_t)d3;
+		cup1--;
+
+		while (cup1 > 0)
+		{
+			if (d1 >= 8) goto l6dc;
+			if (bfextu(src, d0, 1, &bufs)) goto l75a;
+			d0++;
+			d5 = 0;
+			d6 = 8;
+			goto l734;
+
+l6dc:
+			if (bfextu(src, d0, 1, &bufs)) goto l726;
+			d0++;
+			if (!bfextu(src, d0, 1, &bufs)) goto l75a;
+			d0++;
+			if (bfextu(src, d0, 1, &bufs)) goto l6f6;
+			d6 = 2;
+			goto l708;
+
+l6f6:
+			d0++;
+			if (!bfextu(src, d0, 1, &bufs)) goto l706;
+			d6 = bfextu(src, d0, 3, &bufs);
+			d0 += 3;
+			goto l70a;
+
+l706:
+			d6 = 3;
+l708:
+			d0++;
+l70a:
+			d6 = XPK_ReadTable((a2*8) + d6 - 17);
+			if (d6 != 8) goto l730;
+l718:
+			if (d2 >= 20)
+			{
+				d5 = 1;
+				goto l732;
+			}
+			d5 = 0;
+			goto l734;
+
+l726:
+			d0++;
+			d6 = 8;
+			if (d6 == a2) goto l718;
+			d6 = a2;
+l730:
+			d5 = 4;
+l732:
+			d2 += 8;
+l734:
+			while (d5 >= 0 && cup1 > 0)
+			{
+				d4 = bfexts(src, d0, d6, &bufs);
+				d0 += d6;
+				d3 -= d4;
+				*PtrOut++ = (uint8_t)d3;
+				cup1--;
+				d5--;
+			}
+
+			if (d1 != 31)
+				d1++;
+
+			a2 = d6;
+l74c:
+			d6 = d2;
+			d6 >>= 3;
+			d2 -= d6;
+		}
+	}
+
+	if (PtrOut > PtrEnd)
+	{
+		free(unpackedData);
+		return false;
+	}
+
+	*out = unpackedData;
+	return true;
+
+l75a:
+	d0++;
+	if (bfextu(src, d0, 1, &bufs)) goto l766;
+	d4 = 2;
+	goto l79e;
+
+l766:
+	d0++;
+	if (bfextu(src, d0, 1, &bufs)) goto l772;
+	d4 = 4;
+	goto l79e;
+
+l772:
+	d0++;
+	if (bfextu(src, d0, 1, &bufs)) goto l77e;
+	d4 = 6;
+	goto l79e;
+
+l77e:
+	d0++;
+	if (bfextu(src, d0, 1, &bufs)) goto l792;
+	d0++;
+	d6 = bfextu(src, d0, 3, &bufs);
+	d0 += 3;
+	d6 += 8;
+	goto l7a8;
+
+l792:
+	d0++;
+	d6 = bfextu(src, d0, 5, &bufs);
+	d0 += 5;
+	d4 = 16;
+	goto l7a6;
+
+l79e:
+	d0++;
+	d6 = bfextu(src, d0, 1, &bufs);
+	d0++;
+l7a6:
+	d6 += d4;
+l7a8:
+	if (bfextu(src, d0, 1, &bufs))
+	{
+		d5 = 12;
+		a5 = -0x100;
+	}
+	else
+	{
+		d0++;
+		if (bfextu(src, d0, 1, &bufs))
+		{
+			d5 = 14;
+			a5 = -0x1100;
+		}
+		else
+		{
+			d5 = 8;
+			a5 = 0;
+		}
+	}
+
+	d0++;
+	d4 = bfextu(src, d0, d5, &bufs);
+	d0 += d5;
+	d6 -= 3;
+	if (d6 >= 0)
+	{
+		if (d6 > 0)
+			d1--;
+
+		d1--;
+		if (d1 < 0)
+			d1 = 0;
+	}
+	d6 += 2;
+
+	size_t phist = (size_t)(PtrOut-unpackedData) + a5 - d4 - 1;
+	if (phist >= (size_t)(PtrOut-unpackedData))
+	{
+		free(unpackedData);
+		return false;
+	}
+
+	while (d6 >= 0 && cup1 > 0)
+	{
+		d3 = unpackedData[phist];
+		phist++;
+		*PtrOut++ = (uint8_t)d3;
+		cup1--;
+		d6--;
+	}
+
+	goto l74c;
+}
+
+static bool ValidateHeader(XPKFILEHEADER *header)
+{
+	if (memcmp(header->XPKF, "XPKF", 4) != 0)
+		return false;
+
+	if (memcmp(header->SQSH, "SQSH", 4) != 0)
+		return false;
+
+	if (header->SrcLen == 0 || header->DstLen == 0)
+		return false;
+
+	if (header->SrcLen < sizeof (XPKFILEHEADER)-8)
+		return false;
+
+	return true;
+}
+
+bool ReadHeader(FILE *f, XPKFILEHEADER *header)
+{
+	if (f == NULL || fread(header, sizeof (XPKFILEHEADER), 1, f) != 1)
+		return false;
+
+	header->SrcLen = SWAP32(header->SrcLen);
+	header->DstLen = SWAP32(header->DstLen);
+	
+	return true;
+}
+
+bool detectXPK(FILE *f)
+{
+	XPKFILEHEADER header;
+
+	uint32_t OldPos = ftell(f);
+	rewind(f);
+	bool result = ReadHeader(f, &header);
+	fseek(f, OldPos, SEEK_SET);
+
+	if (result == false)
+		return false;
+
+	return ValidateHeader(&header);
+}
+
+bool unpackXPK(FILE *f, uint32_t *filesize, uint8_t **out)
+{
+	XPKFILEHEADER header;
+
+	*filesize = 0;
+	*out = NULL;
+
+	if (f == NULL)
+		return false;
+
+	uint32_t oldPos = ftell(f);
+
+	rewind(f);
+
+	if (!ReadHeader(f, &header))
+	{
+		fseek(f, oldPos, SEEK_SET);
+		return false;
+	}
+
+	if (!ValidateHeader(&header))
+	{
+		fseek(f, oldPos, SEEK_SET);
+		return false;
+	}
+
+	fseek(f, 0, SEEK_END);
+	uint32_t inputfilesize = ftell(f) - sizeof (XPKFILEHEADER);
+	fseek(f, sizeof (XPKFILEHEADER), SEEK_SET);
+
+	uint8_t *packedData = (uint8_t *)malloc(inputfilesize);
+	if (packedData == NULL)
+	{
+		fseek(f, oldPos, SEEK_SET);
+		return false;
+	}
+
+	if (fread(packedData, 1, inputfilesize, f) != inputfilesize)
+	{
+		free(packedData);
+		fseek(f, oldPos, SEEK_SET);
+		return false;
+	}
+
+	uint8_t *unpackedData = NULL;
+	bool result = XPK_DoUnpack(packedData, header.SrcLen - (sizeof (XPKFILEHEADER) - 8), header.DstLen, &unpackedData);
+	free(packedData);
+
+	if (result == true)
+	{
+		*filesize = header.DstLen;
+		*out = unpackedData;
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
--- /dev/null
+++ b/src/modloaders/pt2_xpk_unpack.h
@@ -1,0 +1,7 @@
+#pragma once
+
+#include <stdint.h>
+#include <stdbool.h>
+
+bool detectXPK(FILE *f);
+bool unpackXPK(FILE *f, uint32_t *filesize, uint8_t **out);
--- a/src/pt2_audio.c
+++ b/src/pt2_audio.c
@@ -89,7 +89,7 @@
 		lockAudio();
 
 	audio.ledFilterEnabled = state;
-	paulaWriteByte(0xBFE001, audio.ledFilterEnabled << 1);
+	paulaWriteByte(0xBFE001, (uint8_t)audio.ledFilterEnabled << 1);
 
 	if (audioWasntLocked)
 		unlockAudio();
@@ -102,7 +102,7 @@
 		lockAudio();
 
 	audio.ledFilterEnabled ^= 1;
-	paulaWriteByte(0xBFE001, audio.ledFilterEnabled << 1);
+	paulaWriteByte(0xBFE001, (uint8_t)audio.ledFilterEnabled << 1);
 
 	if (audioWasntLocked)
 		unlockAudio();
@@ -351,33 +351,36 @@
 
 	int16_t *streamOut = (int16_t *)stream;
 
-	uint32_t samplesLeft = (uint32_t)len >> 2;
+	uint32_t samplesLeft = (uint32_t)len / 4;
 	while (samplesLeft > 0)
 	{
-		if (audio.tickSampleCounter64 <= 0)
+		if (audio.tickSampleCounter == 0) // new replayer tick
 		{
-			// new replayer tick
-
 			if (editor.songPlaying)
 			{
-				intMusic(); // PT replayer ticker
+				intMusic(); // PT replayer ticker (also sets audio.samplesPerTickInt and audio.samplesPerTickFrac)
 				fillVisualsSyncBuffer();
 			}
 
-			audio.tickSampleCounter64 += audio.samplesPerTick64;
+			audio.tickSampleCounter = audio.samplesPerTickInt;
+
+			audio.tickSampleCounterFrac += audio.samplesPerTickFrac;
+			if (audio.tickSampleCounterFrac >= BPM_FRAC_SCALE)
+			{
+				audio.tickSampleCounterFrac &= BPM_FRAC_MASK;
+				audio.tickSampleCounter++;
+			}
 		}
 
-		const uint32_t remainingTickSamples = ((uint64_t)audio.tickSampleCounter64 + UINT32_MAX) >> 32; // ceil rounding (upwards)
+		uint32_t samplesToMix = samplesLeft;
+		if (samplesToMix > audio.tickSampleCounter)
+			samplesToMix = audio.tickSampleCounter;
 
-		uint32_t samplesTodo = samplesLeft;
-		if (samplesTodo > remainingTickSamples)
-			samplesTodo = remainingTickSamples;
+		outputAudio(streamOut, samplesToMix);
+		streamOut += samplesToMix * 2; // *2 for stereo
 
-		outputAudio(streamOut, samplesTodo);
-		streamOut += samplesTodo << 1;
-
-		samplesLeft -= samplesTodo;
-		audio.tickSampleCounter64 -= (int64_t)samplesTodo << 32;
+		audio.tickSampleCounter -= samplesToMix;
+		samplesLeft -= samplesToMix;
 	}
 
 	(void)userdata;
@@ -397,10 +400,11 @@
 	if (audioWasntLocked)
 		lockAudio();
 
-	for (int32_t bpm = 32; bpm <= 255; bpm++)
+	for (int32_t bpm = MIN_BPM; bpm <= MAX_BPM; bpm++)
 	{
+		const int32_t i = bpm - MIN_BPM; // index for tables
+
 		double dBpmHz;
-		
 		if (vblankTimingFlag)
 			dBpmHz = AMIGA_PAL_VBLANK_HZ;
 		else
@@ -408,12 +412,15 @@
 
 		const double dSamplesPerTick = dAudioFreq / dBpmHz;
 
-		// convert to rounded 32.32 fixed-point
-		const int32_t i = bpm - 32;
-		audio.samplesPerTickTable[i] = (int64_t)((dSamplesPerTick * (UINT32_MAX+1.0)) + 0.5);
+		double dSamplesPerTickInt;
+		double dSamplesPerTickFrac = modf(dSamplesPerTick, &dSamplesPerTickInt);
+
+		audio.samplesPerTickIntTab[i] = (uint32_t)dSamplesPerTickInt;
+		audio.samplesPerTickFracTab[i] = (uint64_t)((dSamplesPerTickFrac * BPM_FRAC_SCALE) + 0.5); // rounded
 	}
 
-	audio.tickSampleCounter64 = 0;
+	audio.tickSampleCounter = 0;
+	audio.tickSampleCounterFrac = 0;
 
 	if (audioWasntLocked)
 		unlockAudio();
@@ -421,10 +428,11 @@
 
 static void generateTickLengthTable(bool vblankTimingFlag)
 {
-	for (int32_t bpm = 32; bpm <= 255; bpm++)
+	for (int32_t bpm = MIN_BPM; bpm <= MAX_BPM; bpm++)
 	{
-		double dHz;
+		const int32_t i = bpm - MIN_BPM; // index for tables
 
+		double dHz;
 		if (vblankTimingFlag)
 			dHz = AMIGA_PAL_VBLANK_HZ;
 		else
@@ -431,13 +439,13 @@
 			dHz = ciaBpm2Hz(bpm);
 
 		// BPM -> Hz -> tick length for performance counter (syncing visuals to audio)
+		const double dTickTime = (double)hpcFreq.freq64 / dHz;
+
 		double dTimeInt;
-		double dTimeFrac = modf((double)hpcFreq.freq64 / dHz, &dTimeInt);
-		const int32_t timeInt = (int32_t)dTimeInt;
-	
-		dTimeFrac = floor((dTimeFrac * (UINT32_MAX+1.0)) + 0.5); // fractional part (scaled to 0..2^32-1)
+		double dTimeFrac = modf(dTickTime, &dTimeInt);
 
-		audio.tickLengthTable[bpm-32] = ((uint64_t)timeInt << 32) | (uint32_t)dTimeFrac;
+		audio.tickTimeIntTab[i] = (uint32_t)dTimeInt;
+		audio.tickTimeFracTab[i] = (uint64_t)((dTimeFrac * TICK_TIME_FRAC_SCALE) + 0.5); // rounded
 	}
 }
 
@@ -493,15 +501,14 @@
 	audio.amigaModel = config.amigaModel;
 
 	const int32_t paulaMixFrequency = audio.oversamplingFlag ? audio.outputRate*2 : audio.outputRate;
-	const uint32_t maxSamplesToMix = (int32_t)ceil(paulaMixFrequency / (REPLAYER_MIN_BPM / 2.5));
+	int32_t maxSamplesPerTick = (int32_t)ceil(paulaMixFrequency / (MIN_BPM / 2.5)) + 1;
 
-	dMixBufferL = (double *)malloc((maxSamplesToMix + 1) * sizeof (double));
-	dMixBufferR = (double *)malloc((maxSamplesToMix + 1) * sizeof (double));
+	dMixBufferL = (double *)malloc(maxSamplesPerTick * sizeof (double));
+	dMixBufferR = (double *)malloc(maxSamplesPerTick * sizeof (double));
 
 	if (dMixBufferL == NULL || dMixBufferR == NULL)
 	{
 		// these two are free'd later
-
 		showErrorMsgBox("Out of memory!");
 		return false;
 	}
@@ -508,7 +515,7 @@
 
 	paulaSetup(paulaMixFrequency, audio.amigaModel);
 	audioSetStereoSeparation(config.stereoSeparation);
-	updateReplayerTimingMode(); // also generates the BPM table (audio.bpmTable)
+	updateReplayerTimingMode(); // also generates the BPM table (audio.samplesPerTickIntTab & audio.samplesPerTickFracTab)
 	setLEDFilter(false);
 	calcAudioLatencyVars(audio.audioBufferSize, audio.outputRate);
 
@@ -515,8 +522,11 @@
 	clearMixerDownsamplerStates();
 	audio.resetSyncTickTimeFlag = true;
 
-	audio.samplesPerTick64 = audio.samplesPerTickTable[125-32]; // BPM 125
-	audio.tickSampleCounter64 = 0; // zero tick sample counter so that it will instantly initiate a tick
+	audio.samplesPerTickInt = audio.samplesPerTickIntTab[125-MIN_BPM]; // BPM 125
+	audio.samplesPerTickFrac = audio.samplesPerTickFracTab[125-MIN_BPM]; // BPM 125
+
+	audio.tickSampleCounter = 0; // zero tick sample counter so that it will instantly initiate a tick
+	audio.tickSampleCounterFrac = 0;
 
 	SDL_PauseAudioDevice(dev, false);
 	return true;
--- a/src/pt2_audio.h
+++ b/src/pt2_audio.h
@@ -2,10 +2,21 @@
 
 #include <stdint.h>
 #include <stdbool.h>
+#include "pt2_replayer.h"
 
 // for the low-pass/high-pass filters in the SAMPLER screen
 #define FILTERS_BASE_FREQ (PAULA_PAL_CLK / 214.0)
 
+// too many bits makes little sense here
+
+#define BPM_FRAC_BITS 52
+#define BPM_FRAC_SCALE (1ULL << BPM_FRAC_BITS)
+#define BPM_FRAC_MASK (BPM_FRAC_SCALE-1)
+
+#define TICK_TIME_FRAC_BITS 52
+#define TICK_TIME_FRAC_SCALE (1ULL << TICK_TIME_FRAC_BITS)
+#define TICK_TIME_FRAC_MASK (TICK_TIME_FRAC_SCALE-1)
+
 typedef struct audio_t
 {
 	volatile bool locked, isSampling;
@@ -13,15 +24,17 @@
 	bool ledFilterEnabled, oversamplingFlag;
 	
 	uint32_t amigaModel, outputRate, audioBufferSize;
-	int64_t tickSampleCounter64, samplesPerTick64;
-	int64_t samplesPerTickTable[256-32]; // 32.32 fixed-point
 
+	uint32_t tickSampleCounter, samplesPerTickInt, samplesPerTickIntTab[(MAX_BPM-MIN_BPM)+1];
+	uint64_t tickSampleCounterFrac, samplesPerTickFrac, samplesPerTickFracTab[(MAX_BPM-MIN_BPM)+1];
+
 	// for audio sampling
 	bool rescanAudioDevicesSupported;
 
 	// for audio/video syncing
 	bool resetSyncTickTimeFlag;
-	uint64_t tickLengthTable[224];
+	uint32_t tickTimeIntTab[(MAX_BPM-MIN_BPM)+1];
+	uint64_t tickTimeFracTab[(MAX_BPM-MIN_BPM)+1];
 } audio_t;
 
 void setAmigaFilterModel(uint8_t model);
--- a/src/pt2_blep.c
+++ b/src/pt2_blep.c
@@ -4,12 +4,7 @@
 #include <assert.h>
 #include "pt2_blep.h"
 
-/* 18th of April 2022, 8bitbubsy:
-** Table entries were changed to readable numbers instead of "IEEE 754" 64-bit hex data, for better cross-platform support.
-** These numbers have enough digits to keep the same accuracy as the old table (verified).
-** If some compilers were to make a small rounding error here, it wouldn't matter. We have good enough accuracy anyway.
-*/
-static const double dMinblepData[256 + 1] =
+static const double dMinblepData[256+1] =
 {
 	 1.000047730261351741631870027, 1.000070326525919428561905988, 1.000026295486963423542192686, 0.999910424773336803383472216,
 	 0.999715744379055859525351480, 0.999433014919733908598686867, 0.999050085771328588712947294, 0.998551121919525108694415394,
--- a/src/pt2_downsample2x.h
+++ b/src/pt2_downsample2x.h
@@ -13,7 +13,7 @@
 void downsample2xDouble(double *buffer, uint32_t originalLength);
 
 // Warning: These are slow and use normalization to prevent clipping from undershoot/overshoot!
-void downsample2x8Bit(int8_t *buffer, uint32_t originalLength);
-void downsample2x8BitU(uint8_t *buffer, uint32_t originalLength);
-void downsample2x16Bit(int16_t *buffer, uint32_t originalLength);
-void downsample2x32Bit(int32_t *buffer, uint32_t originalLength);
+bool downsample2x8Bit(int8_t *buffer, uint32_t originalLength);
+bool downsample2x8BitU(uint8_t *buffer, uint32_t originalLength);
+bool downsample2x16Bit(int16_t *buffer, uint32_t originalLength);
+bool downsample2x32Bit(int32_t *buffer, uint32_t originalLength);
--- a/src/pt2_edit.c
+++ b/src/pt2_edit.c
@@ -679,7 +679,7 @@
 		{
 			if (song->tick > song->speed>>1)
 			{
-				row = (row + 1) & 0x3F;
+				row = (row + 1) & 63;
 				editor.didQuantize = true;
 			}
 		}
--- a/src/pt2_header.h
+++ b/src/pt2_header.h
@@ -14,7 +14,7 @@
 #include "pt2_unicode.h"
 #include "pt2_palette.h"
 
-#define PROG_VER_STR "1.57"
+#define PROG_VER_STR "1.58"
 
 #ifdef _WIN32
 #define DIR_DELIMITER '\\'
@@ -68,19 +68,6 @@
 
 // Amount of video frames. 14 (PT on Amiga) -> 17 (converted from 49.92Hz to 60Hz)
 #define KEYB_REPEAT_DELAY 17
-
-// .MOD types
-enum
-{
-	FORMAT_MK, // ProTracker or compatible
-	FORMAT_FLT, // Startrekker (4 channels)
-	FORMAT_FT2, // FT2 (or other trackers, multichannel)
-	FORMAT_STK, // The Ultimate SoundTracker (15 samples)
-	FORMAT_NT, // NoiseTracker
-	FORMAT_HMNT, // His Master's NoiseTracker (special one)
-
-	FORMAT_UNKNOWN // may be The Ultimate Soundtracker (set to FORMAT_STK later)
-};
 
 enum
 {
--- a/src/pt2_helpers.h
+++ b/src/pt2_helpers.h
@@ -23,6 +23,18 @@
 	(((uint32_t)((value) & 0xFF000000)) >> 24)   \
 )
 
+#define SWAP64(x) \
+( \
+	(((x) << 56) & 0xFF00000000000000ULL) | \
+	(((x) << 40) & 0x00FF000000000000ULL) | \
+	(((x) << 24) & 0x0000FF0000000000ULL) | \
+	(((x) <<  8) & 0x000000FF00000000ULL) | \
+	(((x) >>  8) & 0x00000000FF000000ULL) | \
+	(((x) >> 24) & 0x0000000000FF0000ULL) | \
+	(((x) >> 40) & 0x000000000000FF00ULL) | \
+	(((x) >> 56) & 0x00000000000000FFULL)  \
+)
+
 #define SGN(x) (((x) >= 0) ? 1 : -1)
 #define ABS(a) (((a) < 0) ? -(a) : (a))
 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
--- a/src/pt2_hpc.c
+++ b/src/pt2_hpc.c
@@ -98,8 +98,7 @@
 	hpc->durationInt = hpcFreq.freq64 / hz;
 	hpc->durationFrac = getFrac64FromU64DivU32(hpcFreq.freq64, hz) >> 1;
 
-	hpc->resetFrame = hz * 3600; // reset counters every hour
-
+	hpc->resetFrame = hz * (60 * 30); // reset counters every half an hour
 }
 
 void hpc_ResetCounters(hpc_t *hpc)
@@ -152,8 +151,8 @@
 
 	/* The counter ("endTimeInt") can accumulate major errors after a couple of hours,
 	** since each frame is not happening at perfect intervals.
-	** To fix this, reset the counter's int & frac once every hour. We should only get
-	** up to one frame of stutter while they are resetting, then it's back to normal.
+	** To fix this, reset the counter's int & frac once every half an hour. We should only
+	** get up to one frame of stutter while they are resetting, then it's back to normal.
 	*/
 	hpc->frameCounter++;
 	if (hpc->frameCounter >= hpc->resetFrame)
--- a/src/pt2_main.c
+++ b/src/pt2_main.c
@@ -286,6 +286,13 @@
 		return 1;
 	}
 
+	// setup GUI text pointers (for recently allocated song structure)
+	editor.currEditPatternDisp = &song->currPattern;
+	editor.currPosDisp = &song->currOrder;
+	editor.currPatternDisp = &song->header.order[0];
+	editor.currPosEdPattDisp = &song->header.order[0];
+	editor.currLengthDisp = &song->header.numOrders;
+
 	if (!initScopes())
 	{
 		cleanUp();
--- a/src/pt2_mod2wav.c
+++ b/src/pt2_mod2wav.c
@@ -195,9 +195,7 @@
 	fseek(f, sizeof (wavHeader_t), SEEK_SET);
 
 	uint32_t sampleCounter = 0;
-	uint8_t tickCounter = 8;
-	int64_t tickSampleCounter64 = 0;
-
+	uint64_t samplesToMixFrac = 0;
 	int8_t numLoops = editor.mod2WavNumLoops;
 
 	bool renderDone = false;
@@ -205,7 +203,7 @@
 	{
 		uint32_t samplesInChunk = 0;
 
-		// render several ticks at once to prevent frequent disk I/O (can speed up the process)
+		// render several ticks at once to prevent frequent disk I/O (speeds up the process)
 		int16_t *ptr16 = mod2WavBuffer;
 		for (uint32_t i = 0; i < TICKS_PER_RENDER_CHUNK; i++)
 		{
@@ -215,39 +213,38 @@
 				break;
 			}
 
-			if (tickSampleCounter64 <= 0) // new replayer tick
+			/* PT replayer ticker (also sets audio.samplesPerTickInt and audio.samplesPerTickFrac).
+			** Returns false on end of song.
+			*/
+			if (!intMusic())
 			{
-				if (!intMusic())
+				if (--numLoops < 0)
 				{
-					if (--numLoops < 0)
-					{
-						renderDone = true; // this tick is the last tick
-					}
-					else
-					{
-						// clear the "last visisted rows" table and let the song continue playing (loop)
-						memset(editor.rowVisitTable, 0, MOD_ORDERS * MOD_ROWS);
-					}
+					renderDone = true; // this tick is the last tick
 				}
-
-				tickSampleCounter64 += audio.samplesPerTick64;
+				else
+				{
+					// clear the "last visisted rows" table and let the song continue playing (loop)
+					memset(editor.rowVisitTable, 0, MOD_ORDERS * MOD_ROWS);
+				}
 			}
 
-			int32_t remainingTick = (tickSampleCounter64 + UINT32_MAX) >> 32; // ceil (rounded upwards)
+			uint32_t samplesToMix = audio.samplesPerTickInt;
 
-			outputAudio(ptr16, remainingTick);
-			tickSampleCounter64 -= (int64_t)remainingTick << 32;
+			samplesToMixFrac += audio.samplesPerTickFrac;
+			if (samplesToMixFrac >= BPM_FRAC_SCALE)
+			{
+				samplesToMixFrac &= BPM_FRAC_MASK;
+				samplesToMix++;
+			}
 
-			samplesInChunk += remainingTick;
-			sampleCounter += remainingTick;
+			outputAudio(ptr16, samplesToMix);
+			ptr16 += samplesToMix * 2; // *2 for stereo
 
-			ptr16 += remainingTick * 2;
+			samplesInChunk += samplesToMix;
+			sampleCounter += samplesToMix;
 
-			if (++tickCounter >= 4)
-			{
-				tickCounter = 0;
-				ui.updateMod2WavDialog = true;
-			}
+			ui.updateMod2WavDialog = true;
 		}
 
 		// write buffer to disk
@@ -255,6 +252,8 @@
 			fwrite(mod2WavBuffer, sizeof (int16_t), samplesInChunk * 2, f);
 	}
 
+	ui.updateMod2WavDialog = true;
+
 	uint32_t endOfDataOffset = ftell(f);
 
 	free(mod2WavBuffer);
@@ -353,9 +352,9 @@
 	strncpy(lastFilename, filename, PATH_MAX-1);
 
 	const int32_t paulaMixFrequency = config.mod2WavOutputFreq * 2; // *2 for oversampling (we always do oversampling in MOD2WAV)
-	const uint32_t maxSamplesToMix = (int32_t)ceil(paulaMixFrequency / (REPLAYER_MIN_BPM / 2.5));
+	int32_t maxSamplesPerTick = (int32_t)ceil(paulaMixFrequency / (MIN_BPM / 2.5)) + 1;
 
-	mod2WavBuffer = (int16_t *)malloc(((TICKS_PER_RENDER_CHUNK * maxSamplesToMix) + 1) * sizeof (int16_t) * 2);
+	mod2WavBuffer = (int16_t *)malloc((TICKS_PER_RENDER_CHUNK * maxSamplesPerTick) * sizeof (int16_t) * 2);
 	if (mod2WavBuffer == NULL)
 	{
 		fclose(fOut);
--- a/src/pt2_module_loader.c
+++ b/src/pt2_module_loader.c
@@ -24,157 +24,26 @@
 #include "pt2_visuals.h"
 #include "pt2_sample_loader.h"
 #include "pt2_config.h"
-#include "pt2_xpk.h"
+#include "modloaders/pt2_load_mod15.h"
+#include "modloaders/pt2_load_mod31.h"
+#include "modloaders/pt2_xpk_unpack.h"
+#include "modloaders/pt2_pp_unpack.h"
 #include "pt2_askbox.h"
 
-typedef struct mem_t
-{
-	bool _eof;
-	uint8_t *_ptr, *_base;
-	uint32_t _cnt, _bufsiz;
-} MEMFILE;
+static void fixZeroesInString(char *str, uint32_t maxLength); // converts zeroes to spaces in a string, up until the last zero found
 
-static int32_t realSampleLengths[MOD_SAMPLES];
-
-static MEMFILE *mopen(const uint8_t *src, uint32_t length);
-static void mclose(MEMFILE **buf);
-static int32_t mgetc(MEMFILE *buf);
-static size_t mread(void *buffer, size_t size, size_t count, MEMFILE *buf);
-static void mseek(MEMFILE *buf, int32_t offset, int32_t whence);
-static void mrewind(MEMFILE *buf);
-static uint8_t ppdecrunch(uint8_t *src, uint8_t *dst, uint8_t *offsetLens, uint32_t srcLen, uint32_t dstLen, uint8_t skipBits);
-
-#define IS_ID(s, b) !strncmp(s, b, 4)
-
-static uint8_t getModType(uint8_t *numChannels, const char *id)
-{
-	*numChannels = 4;
-
-	if (IS_ID("M.K.", id) || IS_ID("M!K!", id) || IS_ID("NSMS", id) || IS_ID("LARD", id) || IS_ID("PATT", id))
-	{
-		return FORMAT_MK; // ProTracker (or compatible)
-	}
-	else if (IS_ID("FLT4", id))
-	{
-		return FORMAT_FLT; // Startrekker (4 channels)
-	}
-	else if (IS_ID("N.T.", id))
-	{
-		return FORMAT_NT; // NoiseTracker
-	}
-	else if (IS_ID("M&K!", id) || IS_ID("FEST", id))
-	{
-		return FORMAT_HMNT; // His Master's NoiseTracker
-	}
-	else if (id[1] == 'C' && id[2] == 'H' && id[3] == 'N')
-	{
-		*numChannels = id[0] - '0';
-		return FORMAT_FT2; // Fasttracker II 1..9 channels (or other trackers)
-	}
-
-	return FORMAT_UNKNOWN; // may be The Ultimate Soundtracker (set to FORMAT_STK later)
-}
-
-// converts zeroes to spaces in a string, up until the last zero found
-static void fixZeroesInString(char *str, uint32_t maxLength)
-{
-	int32_t i;
-
-	for (i = maxLength-1; i >= 0; i--)
-	{
-		if (str[i] != '\0')
-			break;
-	}
-
-	// convert zeroes to spaces
-	if (i > 0)
-	{
-		for (int32_t j = 0; j < i; j++)
-		{
-			if (str[j] == '\0')
-				str[j] = ' ';
-		}
-	}
-}
-
-static uint8_t *unpackPPModule(FILE *f, uint32_t *filesize)
-{
-	uint8_t *modBuffer, ppCrunchData[4], *ppBuffer;
-	uint32_t ppPackLen, ppUnpackLen;
-
-	ppPackLen = *filesize;
-	if ((ppPackLen & 3) || ppPackLen <= 12)
-	{
-		displayErrorMsg("POWERPACKER ERROR");
-		return NULL;
-	}
-
-	ppBuffer = (uint8_t *)malloc(ppPackLen);
-	if (ppBuffer == NULL)
-	{
-		statusOutOfMemory();
-		return NULL;
-	}
-
-	fseek(f, ppPackLen-4, SEEK_SET);
-
-	ppCrunchData[0] = (uint8_t)fgetc(f);
-	ppCrunchData[1] = (uint8_t)fgetc(f);
-	ppCrunchData[2] = (uint8_t)fgetc(f);
-	ppCrunchData[3] = (uint8_t)fgetc(f);
-
-	ppUnpackLen = (ppCrunchData[0] << 16) | (ppCrunchData[1] << 8) | ppCrunchData[2];
-
-	modBuffer = (uint8_t *)malloc(ppUnpackLen);
-	if (modBuffer == NULL)
-	{
-		free(ppBuffer);
-		statusOutOfMemory();
-		return NULL;
-	}
-
-	rewind(f);
-	fread(ppBuffer, 1, ppPackLen, f);
-	fclose(f);
-
-	if (!ppdecrunch(ppBuffer+8, modBuffer, ppBuffer+4, ppPackLen-12, ppUnpackLen, ppCrunchData[3]))
-	{
-		free(ppBuffer);
-		displayErrorMsg("POWERPACKER ERROR");
-		return NULL;
-	}
-
-	free(ppBuffer);
-	*filesize = ppUnpackLen;
-	return modBuffer;
-}
-
 module_t *modLoad(UNICHAR *fileName)
 {
-	char modID[4];
-	uint8_t numChannels;
 	uint32_t powerPackerID;
 
-	bool veryLateSTKVerFlag = false; // "DFJ SoundTracker III" and later
-	bool lateSTKVerFlag = false; // "TJC SoundTracker II" and later
-	bool mightBeSTK = false;
-
-	MEMFILE *m = NULL;
-	FILE *f = NULL;
 	uint8_t *modBuffer = NULL;
+	module_t *newMod = NULL;
 
-	module_t *newMod = (module_t *)calloc(1, sizeof (module_t));
-	if (newMod == NULL)
-	{
-		statusOutOfMemory();
-		goto modLoadError;
-	}
-
-	f = UNICHAR_FOPEN(fileName, "rb");
+	FILE *f = UNICHAR_FOPEN(fileName, "rb");
 	if (f == NULL)
 	{
 		displayErrorMsg("FILE I/O ERROR !");
-		goto modLoadError;
+		goto loadError;
 	}
 
 	fseek(f, 0, SEEK_END);
@@ -186,28 +55,31 @@
 	if (powerPackerID == 0x30325850) // "PX20"
 	{
 		displayErrorMsg("ENCRYPTED MOD !");
-		goto modLoadError;
+		goto loadError;
 	}
 	else if (powerPackerID == 0x30325050) // "PP20"
 	{
-		modBuffer = unpackPPModule(f, &filesize);
+		modBuffer = unpackPP(f, &filesize);
 		if (modBuffer == NULL)
-			goto modLoadError; // error msg is set in unpackPPModule()
+		{
+			displayErrorMsg("PP UNPACK ERROR !");
+			goto loadError; // error msg is set in unpackPPModule()
+		}
 	}
 	else
 	{
-		if (DetectXPK(f))
+		if (detectXPK(f))
 		{
-			if (!UnpackXPK(f, &filesize, &modBuffer))
+			if (!unpackXPK(f, &filesize, &modBuffer))
 			{
-				displayErrorMsg("XPK UNPACK ERROR !");
-				goto modLoadError;
+				displayErrorMsg("XPK UNPACK ERROR");
+				goto loadError;
 			}
 
 			if (modBuffer == NULL)
 			{
 				statusOutOfMemory();
-				goto modLoadError;
+				goto loadError;
 			}
 
 			fclose(f);
@@ -218,48 +90,34 @@
 			if (modBuffer == NULL)
 			{
 				statusOutOfMemory();
-				goto modLoadError;
+				goto loadError;
 			}
 
-			fseek(f, 0, SEEK_SET);
+			rewind(f);
 			fread(modBuffer, 1, filesize, f);
 			fclose(f);
 		}
 	}
 
-	// smallest and biggest possible PT .MOD
-	if (filesize < 2108 || filesize > 4195326)
-	{
-		displayErrorMsg("NOT A MOD FILE !");
-		goto modLoadError;
-	}
+	// read module is in now in modBuffer, time to load...
 
-	// Use MEMFILE functions on module buffer (similar to FILE functions)
+	bool isMod31 = detectMod31(modBuffer, filesize);
+	if (isMod31)
+		newMod = loadMod31(modBuffer, filesize);
+	else
+		newMod = loadMod15(modBuffer, filesize);
 
-	m = mopen(modBuffer, filesize);
-	if (m == NULL)
-	{
-		displayErrorMsg("FILE I/O ERROR !");
-		goto modLoadError;
-	}
+	free(modBuffer);
+	modBuffer = NULL;
 
-	// check magic ID
-	memset(modID, 0, 4); // in case mread fails
-	mseek(m, 1080, SEEK_SET);
-	mread(modID, 1, 4, m);
-
-	uint8_t modFormat = getModType(&numChannels, modID);
-	if (numChannels == 0 || numChannels > PAULA_VOICES)
+	if (newMod == NULL)
 	{
-		displayErrorMsg("UNSUPPORTED MOD !");
-		goto modLoadError;
+		// error message is shown in the mod loader
+		goto loadError;
 	}
 
-	if (modFormat == FORMAT_UNKNOWN)
-		mightBeSTK = true;
+	// module is loaded, do some sanitation...
 
-	mrewind(m);
-	mread(newMod->header.name, 1, 20, m);
 	newMod->header.name[20] = '\0';
 
 	// convert illegal song name characters to space
@@ -274,372 +132,39 @@
 
 	fixZeroesInString(newMod->header.name, 20);
 
-	// read sample headers
 	moduleSample_t *s = newMod->samples;
 	for (int32_t i = 0; i < MOD_SAMPLES; i++, s++)
 	{
-		if (mightBeSTK && i >= 15) // skip reading sample headers past sample slot 15 in STK/UST modules
-		{
-			s->loopLength = 2; // this be set though
-			continue;
-		}
-
-		mread(s->text, 1, 22, m);
 		s->text[22] = '\0';
 
-		if (modFormat == FORMAT_HMNT)
+		// convert illegal sample name characters to space
+		for (int32_t j = 0; j < 22; j++)
 		{
-			// most of "His Master's Noisetracker" songs have junk sample names, so let's wipe it.
-			memset(s->text, 0, 22);
-		}
-		else
-		{
-			// convert illegal sample name characters to space
-			for (int32_t j = 0; j < 22; j++)
-			{
-				char tmpChar = s->text[j];
-				if ((tmpChar < ' ' || tmpChar > '~') && tmpChar != '\0')
-					tmpChar = ' ';
+			char tmpChar = s->text[j];
+			if ((tmpChar < ' ' || tmpChar > '~') && tmpChar != '\0')
+				tmpChar = ' ';
 
-				s->text[j] = tmpChar;
-			}
-
-			fixZeroesInString(s->text, 22);
+			s->text[j] = tmpChar;
 		}
 
-		realSampleLengths[i] = ((mgetc(m) << 8) | mgetc(m)) * 2;
-		s->length = (realSampleLengths[i] > config.maxSampleLength) ? config.maxSampleLength : realSampleLengths[i];
+		fixZeroesInString(s->text, 22);
 
-		/* Only late versions of Ultimate SoundTracker could have samples larger than 9999 bytes.
-		** If found, we know for sure that this is a late STK module.
-		*/
-		if (mightBeSTK && s->length > 9999)
-			lateSTKVerFlag = true;
+		if (s->length > config.maxSampleLength)
+			s->length = config.maxSampleLength;
 
-		if (modFormat == FORMAT_HMNT) // finetune in "His Master's NoiseTracker" is different
-			s->fineTune = (uint8_t)((-mgetc(m) & 0x1F) / 2); // one more bit of precision, + inverted
-		else
-			s->fineTune = (uint8_t)mgetc(m) & 0xF;
-
-		if (mightBeSTK)
-			s->fineTune = 0; // this is high byte of volume in STK/UST (has no finetune), set to zero
-
-		s->volume = (int8_t)mgetc(m);
 		if ((uint8_t)s->volume > 64)
 			s->volume = 64;
 
-		int32_t loopStart = ((mgetc(m) << 8) | mgetc(m)) * 2;
-		int32_t loopLength = ((mgetc(m) << 8) | mgetc(m)) * 2;
+		if (s->loopLength < 2)
+			s->loopLength = 2;
 
-		if (loopLength < 2)
-			loopLength = 2; // fixes empty samples in .MODs saved from FT2
-
 		// we don't support samples bigger than 65534 (or 128kB) bytes, disable uncompatible loops
-		if (loopStart > config.maxSampleLength || loopStart+loopLength > config.maxSampleLength)
+		if (s->loopStart > config.maxSampleLength || s->loopStart+s->loopLength > config.maxSampleLength)
 		{
 			s->loopStart = 0;
 			s->loopLength = 2;
 		}
-		else
-		{
-			s->loopStart = loopStart;
-			s->loopLength = loopLength;
-		}
 
-		// in The Ultimate SoundTracker, sample loop start is in bytes, not words
-		if (mightBeSTK)
-			s->loopStart /= 2;
-
-		// fix for poorly converted STK (< v2.5) -> PT/NT modules
-		if (!mightBeSTK && s->loopLength > 2 && s->loopStart+s->loopLength > s->length)
-		{
-			if ((s->loopStart/2) + s->loopLength <= s->length)
-				s->loopStart /= 2;
-		}
-	}
-
-	newMod->header.numOrders = (uint8_t)mgetc(m);
-
-	if (modFormat == FORMAT_MK && newMod->header.numOrders == 129)
-		newMod->header.numOrders = 127; // fixes a specific copy of beatwave.mod
-
-	if (newMod->header.numOrders > 129)
-	{
-		displayErrorMsg("NOT A MOD FILE !");
-		goto modLoadError;
-	}
-
-	if (newMod->header.numOrders == 0)
-	{
-		displayErrorMsg("NOT A MOD FILE !");
-		goto modLoadError;
-	}
-
-	uint8_t restartPos = (uint8_t)mgetc(m);
-	if (mightBeSTK && restartPos > 220)
-	{
-		displayErrorMsg("NOT A MOD FILE !");
-		goto modLoadError;
-	}
-
-	newMod->header.initialTempo = 125;
-	if (mightBeSTK)
-	{
-		/* If we're still here at this point and the mightBeSTK flag is set,
-		** then it's most likely a proper The Ultimate SoundTracker (STK/UST) module.
-		*/
-		modFormat = FORMAT_STK;
-
-		if (restartPos == 0)
-			restartPos = 120;
-
-		// jjk55.mod by Jesper Kyd has a bogus STK tempo value that should be ignored
-		if (!strcmp("jjk55", newMod->header.name))
-			restartPos = 120;
-
-		// the "restart pos" field in STK is the inital tempo (must be converted to BPM first)
-		if (restartPos != 120) // 120 is a special case and means 50Hz (125BPM)
-		{
-			if (restartPos > 220)
-				restartPos = 220;
-
-			// convert UST tempo to BPM
-			uint16_t ciaPeriod = (240 - restartPos) * 122;
-			double dHz = (double)CIA_PAL_CLK / ciaPeriod;
-			int32_t BPM = (int32_t)((dHz * (125.0 / 50.0)) + 0.5);
-
-			newMod->header.initialTempo = (uint16_t)BPM;
-		}
-	}
-
-	// read orders and count number of patterns
-	int32_t numPatterns = 0;
-	for (int32_t i = 0; i < MOD_ORDERS; i++)
-	{
-		newMod->header.order[i] = (int16_t)mgetc(m);
-		if (newMod->header.order[i] > numPatterns)
-			numPatterns = newMod->header.order[i];
-	}
-	numPatterns++;
-
-	if (numPatterns > MAX_PATTERNS)
-	{
-		displayErrorMsg("UNSUPPORTED MOD !");
-		goto modLoadError;
-	}
-
-	// skip magic ID (The Ultimate SoundTracker MODs doesn't have it)
-	if (modFormat != FORMAT_STK)
-		mseek(m, 4, SEEK_CUR);
-
-	// allocate 100 patterns
-	for (int32_t i = 0; i < MAX_PATTERNS; i++)
-	{
-		newMod->patterns[i] = (note_t *)calloc(MOD_ROWS * PAULA_VOICES, sizeof (note_t));
-		if (newMod->patterns[i] == NULL)
-		{
-			statusOutOfMemory();
-			goto modLoadError;
-		}
-	}
-
-	// load pattern data
-	for (int32_t i = 0; i < numPatterns; i++)
-	{
-		note_t *note = newMod->patterns[i];
-		for (int32_t j = 0; j < MOD_ROWS; j++)
-		{
-			for (int32_t k = 0; k < numChannels; k++, note++)
-			{
-				uint8_t bytes[4] = { 0 };
-				mread(bytes, 1, 4, m);
-
-				note->period = ((bytes[0] & 0x0F) << 8) | bytes[1];
-				note->sample = (bytes[0] & 0xF0) | (bytes[2] >> 4);
-				note->command = bytes[2] & 0x0F;
-				note->param = bytes[3];
-
-				// added sanitation not present in original PT
-				if (note->sample > 31)
-					note->sample = 0;
-
-				if (modFormat == FORMAT_STK)
-				{
-					if (note->command == 0xC || note->command == 0xD || note->command == 0xE)
-					{
-						// "TJC SoundTracker II" and later
-						lateSTKVerFlag = true;
-					}
-
-					if (note->command == 0xF)
-					{
-						// "DFJ SoundTracker III" and later
-						lateSTKVerFlag = true;
-						veryLateSTKVerFlag = true;
-					}
-				}
-			}
-
-			if (numChannels < PAULA_VOICES)
-				note += PAULA_VOICES-numChannels;
-		}
-	}
-
-	// pattern command conversion for non-PT formats
-	if (modFormat == FORMAT_STK || modFormat == FORMAT_FT2 || modFormat == FORMAT_NT || modFormat == FORMAT_HMNT || modFormat == FORMAT_FLT)
-	{
-		for (int32_t i = 0; i < numPatterns; i++)
-		{
-			note_t *note = newMod->patterns[i];
-			for (int32_t j = 0; j < MOD_ROWS*4; j++, note++)
-			{
-				if (modFormat == FORMAT_NT || modFormat == FORMAT_HMNT)
-				{
-					// any Dxx == D00 in NT/HMNT
-					if (note->command == 0xD)
-						note->param = 0;
-
-					// effect F with param 0x00 does nothing in NT/HMNT
-					if (note->command == 0xF && note->param == 0)
-						note->command = 0;
-				}
-				else if (modFormat == FORMAT_FLT) // Startrekker (4 channels)
-				{
-					if (note->command == 0xE) // remove unsupported "assembly macros" command
-					{
-						note->command = 0;
-						note->param = 0;
-					}
-
-					// Startrekker is always in vblank mode, and limits speed to 0x1F
-					if (note->command == 0xF && note->param > 0x1F)
-						note->param = 0x1F;
-				}
-				else if (modFormat == FORMAT_STK)
-				{
-					// convert STK effects to PT effects
-
-					if (!lateSTKVerFlag)
-					{
-						// old SoundTracker 1.x commands
-
-						if (note->command == 1)
-						{
-							// arpeggio
-							note->command = 0;
-						}
-						else if (note->command == 2)
-						{
-							// pitch slide
-							if (note->param & 0xF0)
-							{
-								// pitch slide down
-								note->command = 2;
-								note->param >>= 4;
-							}
-							else if (note->param & 0x0F)
-							{
-								// pitch slide up
-								note->command = 1;
-							}
-						}
-					}
-					else
-					{
-						// "DFJ SoundTracker II" or later
-
-						// TODO: This needs more detection and is NOT correct!
-						if (note->command == 0xD)
-						{
-							if (veryLateSTKVerFlag) // "DFJ SoundTracker III" or later
-							{
-								// pattern break w/ no param (param must be cleared to fix some songs)
-								note->param = 0;
-							}
-							else
-							{
-								// volume slide
-								note->command = 0xA;
-							}
-						}
-					}
-
-					// effect F with param 0x00 does nothing in UST/STK (I think?)
-					if (note->command == 0xF && note->param == 0)
-						note->command = 0;
-				}
-
-				// remove sample-trashing effects that were only present in ProTracker
-
-				// remove E8x (Karplus-Strong in ProTracker)
-				if (note->command == 0xE && (note->param >> 4) == 0x8)
-				{
-					note->command = 0;
-					note->param = 0;
-				}
-
-				// remove EFx (Invert Loop in ProTracker)
-				if (note->command == 0xE && (note->param >> 4) == 0xF)
-				{
-					note->command = 0;
-					note->param = 0;
-				}
-			}
-		}
-	}
-
-	newMod->sampleData = allocMemForAllSamples();
-	if (newMod->sampleData == NULL)
-	{
-		statusOutOfMemory();
-		goto modLoadError;
-	}
-
-	// set sample data offsets (sample data = one huge buffer to rule them all)
-	for (int32_t i = 0; i < MOD_SAMPLES; i++)
-		newMod->samples[i].offset = config.maxSampleLength * i;
-
-	// load sample data
-	int32_t numSamples = (modFormat == FORMAT_STK) ? 15 : 31;
-	s = newMod->samples;
-	for (int32_t i = 0; i < numSamples; i++, s++)
-	{
-		/* For Ultimate SoundTracker modules, only the loop area of a looped sample is played.
-		** Skip loading of eventual data present before loop start.
-		*/
-		if (modFormat == FORMAT_STK && s->loopStart > 0 && s->loopLength < s->length)
-		{
-			s->length -= s->loopStart;
-			mseek(m, s->loopStart, SEEK_CUR);
-			s->loopStart = 0;
-		}
-
-		/* We don't support loading samples bigger than 65534 bytes in our PT2 clone,
-		** so skip overflown data in .MOD file if present.
-		*/
-		int32_t bytesToSkip = 0;
-		if (realSampleLengths[i] > config.maxSampleLength)
-			bytesToSkip = realSampleLengths[i] - config.maxSampleLength;
-
-		// For Ultimate SoundTracker modules, don't load sample data after loop end
-		int32_t loopEnd = s->loopStart + s->loopLength;
-		if (modFormat == FORMAT_STK && loopEnd > 2 && s->length > loopEnd)
-		{
-			bytesToSkip += s->length-loopEnd;
-			s->length = loopEnd;
-		}
-
-		mread(&newMod->sampleData[s->offset], 1, s->length, m);
-		if (bytesToSkip > 0)
-			mseek(m, bytesToSkip, SEEK_CUR);
-
-		// clear first two bytes of non-looping samples to prevent beep after sample has been played
-		if (s->length >= 2 && loopEnd <= 2)
-		{
-			newMod->sampleData[s->offset+0] = 0;
-			newMod->sampleData[s->offset+1] = 0;
-		}
-
 		// some modules are broken like this, adjust sample length if possible (this is ok if we have room)
 		if (s->length > 0 && s->loopLength > 2 && s->loopStart+s->loopLength > s->length)
 		{
@@ -654,262 +179,56 @@
 				s->loopLength = 2;
 			}
 		}
-	}
 
-	mclose(&m);
-	free(modBuffer);
-
+		// clear first two bytes of non-looping samples to prevent beep after sample has been played
+		if (s->length >= 2 && s->loopStart+s->loopLength <= 2)
+		{
+			newMod->sampleData[s->offset+0] = 0;
+			newMod->sampleData[s->offset+1] = 0;
+		}
+	}
+	
 	initializeModuleChannels(newMod);
-
 	return newMod;
 
-modLoadError:
-	if (m != NULL)
-		mclose(&m);
-
+loadError:
 	if (modBuffer != NULL)
 		free(modBuffer);
 
-	if (newMod != NULL)
-	{
-		for (int32_t i = 0; i < MAX_PATTERNS; i++)
-		{
-			if (newMod->patterns[i] != NULL)
-				free(newMod->patterns[i]);
-		}
-
-		free(newMod);
-	}
-
 	return NULL;
 }
 
-static MEMFILE *mopen(const uint8_t *src, uint32_t length)
+static void fixZeroesInString(char *str, uint32_t maxLength)
 {
-	if (src == NULL || length == 0)
-		return NULL;
+	int32_t i;
 
-	MEMFILE *b = (MEMFILE *)malloc(sizeof (MEMFILE));
-	if (b == NULL)
-		return NULL;
-
-	b->_base = (uint8_t *)src;
-	b->_ptr = (uint8_t *)src;
-	b->_cnt = length;
-	b->_bufsiz = length;
-	b->_eof = false;
-
-	return b;
-}
-
-static void mclose(MEMFILE **buf)
-{
-	if (*buf != NULL)
+	for (i = maxLength-1; i >= 0; i--)
 	{
-		free(*buf);
-		*buf = NULL;
+		if (str[i] != '\0')
+			break;
 	}
-}
 
-static int32_t mgetc(MEMFILE *buf)
-{
-	if (buf == NULL || buf->_ptr == NULL || buf->_cnt <= 0)
-		return 0;
-
-	int32_t b = *buf->_ptr;
-
-	buf->_cnt--;
-	buf->_ptr++;
-
-	if (buf->_cnt <= 0)
+	// convert zeroes to spaces
+	if (i > 0)
 	{
-		buf->_ptr = buf->_base + buf->_bufsiz;
-		buf->_cnt = 0;
-		buf->_eof = true;
-	}
-
-	return (int32_t)b;
-}
-
-static size_t mread(void *buffer, size_t size, size_t count, MEMFILE *buf)
-{
-	if (buf == NULL || buf->_ptr == NULL)
-		return 0;
-
-	size_t wrcnt = size * count;
-	if (size == 0 || buf->_eof)
-		return 0;
-
-	int32_t pcnt = (buf->_cnt > (uint32_t)wrcnt) ? (uint32_t)wrcnt : buf->_cnt;
-	memcpy(buffer, buf->_ptr, pcnt);
-
-	buf->_cnt -= pcnt;
-	buf->_ptr += pcnt;
-
-	if (buf->_cnt <= 0)
-	{
-		buf->_ptr = buf->_base + buf->_bufsiz;
-		buf->_cnt = 0;
-		buf->_eof = true;
-	}
-
-	return pcnt / size;
-}
-
-static void mseek(MEMFILE *buf, int32_t offset, int32_t whence)
-{
-	if (buf == NULL)
-		return;
-
-	if (buf->_base)
-	{
-		switch (whence)
+		for (int32_t j = 0; j < i; j++)
 		{
-			case SEEK_SET: buf->_ptr = buf->_base + offset; break;
-			case SEEK_CUR: buf->_ptr += offset; break;
-			case SEEK_END: buf->_ptr = buf->_base + buf->_bufsiz + offset; break;
-			default: break;
+			if (str[j] == '\0')
+				str[j] = ' ';
 		}
-
-		buf->_eof = false;
-		if (buf->_ptr >= buf->_base+buf->_bufsiz)
-		{
-			buf->_ptr = buf->_base + buf->_bufsiz;
-			buf->_eof = true;
-		}
-
-		buf->_cnt = (uint32_t)((buf->_base + buf->_bufsiz) - buf->_ptr);
 	}
 }
 
-static void mrewind(MEMFILE *buf)
-{
-	mseek(buf, 0, SEEK_SET);
-}
-
-/* PowerPacker unpack code taken from Heikki Orsila's amigadepack. Seems to have no license,
-** so I'll assume it fits into BSD 3-Clause. If not, feel free to contact me at my email
-** address found at the bottom of 16-bits.org.
-**
-** Modified by 8bitbubsy (me).
-*/
-
-#define PP_READ_BITS(nbits, var) \
-	bitCnt = (nbits); \
-	while (bitsLeft < bitCnt) \
-	{ \
-		if (bufSrc < src) \
-			return false; \
-		bitBuffer |= ((*--bufSrc) << bitsLeft); \
-		bitsLeft += 8; \
-	} \
-	(var) = 0; \
-	bitsLeft -= bitCnt; \
-	while (bitCnt--) \
-	{ \
-		(var) = ((var) << 1) | (bitBuffer & 1); \
-		bitBuffer >>= 1; \
-	} \
-
-static uint8_t ppdecrunch(uint8_t *src, uint8_t *dst, uint8_t *offsetLens, uint32_t srcLen, uint32_t dstLen, uint8_t skipBits)
-{
-	uint8_t bitCnt;
-	uint32_t x, todo, offset;
-
-	if (src == NULL || dst == NULL || offsetLens == NULL)
-		return false;
-
-	uint8_t bitsLeft = 0;
-	uint32_t bitBuffer = 0;
-	uint32_t written = 0;
-	uint8_t *bufSrc = src + srcLen;
-	uint8_t *out = dst + dstLen;
-	uint8_t *dstEnd = out;
-
-	PP_READ_BITS(skipBits, x);
-	while (written < dstLen)
-	{
-		PP_READ_BITS(1, x);
-		if (x == 0)
-		{
-			todo = 1;
-
-			do
-			{
-				PP_READ_BITS(2, x);
-				todo += x;
-			}
-			while (x == 3);
-
-			while (todo--)
-			{
-				PP_READ_BITS(8, x);
-				if (out <= dst)
-					return false;
-
-				*--out = (uint8_t)x;
-				written++;
-			}
-
-			if (written == dstLen)
-				break;
-		}
-
-		PP_READ_BITS(2, x);
-		uint32_t offBits = offsetLens[x];
-		todo = x + 2;
-
-		if (x == 3)
-		{
-			PP_READ_BITS(1, x);
-			if (x == 0) offBits = 7;
-
-			PP_READ_BITS((uint8_t)offBits, offset);
-			do
-			{
-				PP_READ_BITS(3, x);
-				todo += x;
-			}
-			while (x == 7);
-		}
-		else
-		{
-			PP_READ_BITS((uint8_t)offBits, offset);
-		}
-
-		if (out+offset >= dstEnd)
-			return false;
-
-		while (todo--)
-		{
-			x = out[offset];
-			if (out <= dst)
-				return false;
-
-			*--out = (uint8_t)x;
-			written++;
-		}
-	}
-
-	return true;
-}
-
 void setupLoadedMod(void)
 {
-	// setup GUI text pointers
-	for (int32_t i = 0; i < MOD_SAMPLES; i++)
-	{
-		song->samples[i].volumeDisp = &song->samples[i].volume;
-		song->samples[i].lengthDisp = &song->samples[i].length;
-		song->samples[i].loopStartDisp = &song->samples[i].loopStart;
-		song->samples[i].loopLengthDisp = &song->samples[i].loopLength;
-
+	moduleSample_t *s = song->samples;
+	for (int32_t i = 0; i < MOD_SAMPLES; i++, s++)
 		fillSampleRedoBuffer((uint8_t)i);
-	}
 
 	modSetPos(0, 0);
 	modSetPattern(0); // set pattern to 00 instead of first order's pattern
 
+	// setup GUI text pointers
 	editor.currEditPatternDisp = &song->currPattern;
 	editor.currPosDisp = &song->currOrder;
 	editor.currPatternDisp = &song->header.order[0];
@@ -926,7 +245,10 @@
 
 	editor.editMoveAdd = 1;
 	editor.currSample = 0;
-	editor.musicTime64 = 0;
+
+	editor.playbackSeconds = 0;
+	editor.playbackSecondsFrac = 0;
+
 	editor.modLoaded = true;
 	editor.blockMarkFlag = false;
 	editor.sampleZero = false;
@@ -1148,53 +470,4 @@
 DropExit:
 	free(ansiName);
 	free(fullPathU);
-}
-
-module_t *createEmptyMod(void)
-{
-	module_t *newMod = (module_t *)calloc(1, sizeof (module_t));
-	if (newMod == NULL)
-		goto oom;
-
-	for (int32_t i = 0; i < MAX_PATTERNS; i++)
-	{
-		newMod->patterns[i] = (note_t *)calloc(1, MOD_ROWS * sizeof (note_t) * PAULA_VOICES);
-		if (newMod->patterns[i] == NULL)
-			goto oom;
-	}
-
-	newMod->sampleData = allocMemForAllSamples();
-	if (newMod->sampleData == NULL)
-		goto oom;
-
-	newMod->header.numOrders = 1;
-
-	moduleSample_t *s = newMod->samples;
-	for (int32_t i = 0; i < MOD_SAMPLES; i++, s++)
-	{
-		s->offset = config.maxSampleLength * i;
-		s->loopLength = 2;
-
-		// setup GUI text pointers
-		s->volumeDisp = &s->volume;
-		s->lengthDisp = &s->length;
-		s->loopStartDisp = &s->loopStart;
-		s->loopLengthDisp = &s->loopLength;
-	}
-
-	initializeModuleChannels(newMod);
-
-	// setup GUI text pointers
-	editor.currEditPatternDisp = &newMod->currPattern;
-	editor.currPosDisp = &newMod->currOrder;
-	editor.currPatternDisp = &newMod->header.order[0];
-	editor.currPosEdPattDisp = &newMod->header.order[0];
-	editor.currLengthDisp = &newMod->header.numOrders;
-
-	ui.updateSongSize = true;
-	return newMod;
-
-oom:
-	showErrorMsgBox("Out of memory!");
-	return NULL;
 }
--- a/src/pt2_module_loader.h
+++ b/src/pt2_module_loader.h
@@ -8,6 +8,5 @@
 
 void loadModFromArg(char *arg);
 void loadDroppedFile(char *fullPath, uint32_t fullPathLen, bool autoPlay, bool songModifiedCheck);
-module_t *createEmptyMod(void);
 module_t *modLoad(UNICHAR *fileName);
 void setupLoadedMod(void);
--- a/src/pt2_pat2smp.c
+++ b/src/pt2_pat2smp.c
@@ -224,10 +224,10 @@
 	}
 
 	const double dAudioFrequency = dPat2SmpFreq * 2.0; // *2 for oversampling
-	const uint32_t maxSamplesToMix = (int32_t)ceil(dAudioFrequency / (REPLAYER_MIN_BPM / 2.5)); // *2 for oversampling
+	int32_t maxSamplesPerTick = (int32_t)ceil(dAudioFrequency / (MIN_BPM / 2.5)) + 1;
 
-	dMixBufferL = (double *)malloc((maxSamplesToMix + 1) * sizeof (double));
-	dMixBufferR = (double *)malloc((maxSamplesToMix + 1) * sizeof (double));
+	dMixBufferL = (double *)malloc(maxSamplesPerTick * sizeof (double));
+	dMixBufferR = (double *)malloc(maxSamplesPerTick * sizeof (double));
 
 	if (dMixBufferL == NULL || dMixBufferR == NULL)
 	{
@@ -254,33 +254,37 @@
 
 	song->currRow = song->row = 0;
 	pat2SmpPos = 0;
-	int64_t tickSampleCounter64 = 0;
 
+	uint64_t samplesToMixFrac = 0;
+
 	bool lastRow = false;
 
 	pat2SmpEndReached = false;
 	while (!pat2SmpEndReached && editor.songPlaying)
 	{
-		//int8_t prevRow = song->row;
-		if (tickSampleCounter64 <= 0) // new replayer tick
-		{
-			if (!intMusic())
-				lastRow = true;
+		/* PT replayer ticker (also sets audio.samplesPerTickInt and audio.samplesPerTickFrac).
+		** Returns false on end of song.
+		*/
+		if (!intMusic())
+			lastRow = true;
 
-			if (song->row > pat2SmpStartRow+pat2SmpRows)
-				break; // we rendered as many rows as requested (don't write this tick to output)
+		if (song->row > pat2SmpStartRow+pat2SmpRows)
+			break; // we rendered as many rows as requested (don't write this tick to output)
 
-			tickSampleCounter64 += audio.samplesPerTick64;
+		uint32_t samplesToMix = audio.samplesPerTickInt;
+
+		samplesToMixFrac += audio.samplesPerTickFrac;
+		if (samplesToMixFrac >= BPM_FRAC_SCALE)
+		{
+			samplesToMixFrac &= BPM_FRAC_MASK;
+			samplesToMix++;
 		}
 
 		if (lastRow && song->tick == song->speed-1)
 			pat2SmpEndReached = true;
 
-		const uint32_t samplesTodo = ((uint64_t)tickSampleCounter64 + UINT32_MAX) >> 32; // ceil (rounded upwards)
 		if (lastRow || song->row > pat2SmpStartRow)
-			pat2SmpOutputAudio(samplesTodo);
-
-		tickSampleCounter64 -= (uint64_t)samplesTodo << 32;
+			pat2SmpOutputAudio(samplesToMix);
 	}
 	editor.pat2SmpOngoing = false;
 
--- a/src/pt2_paula.c
+++ b/src/pt2_paula.c
@@ -246,7 +246,7 @@
 	paula[ch].DMA_active = false;
 }
 
-void paulaWriteByte(uint32_t address, uint16_t data8)
+void paulaWriteByte(uint32_t address, uint8_t data8)
 {
 	if (address == 0)
 		return;
@@ -264,12 +264,6 @@
 				clearTwoPoleFilterState(&filterLED);
 		}
 		break;
-	
-		// AUDxVOL ( byte-write to AUDxVOL works on most Amigas (not 68040/68060) )
-		case 0xDFF0A9: audxvol(0, data8); break;
-		case 0xDFF0B9: audxvol(1, data8); break;
-		case 0xDFF0C9: audxvol(2, data8); break;
-		case 0xDFF0D9: audxvol(3, data8); break;
 
 		default: return;
 	}
@@ -391,8 +385,13 @@
 // output is -4.00 .. 3.97 (can be louder because of high-pass filter)
 void paulaGenerateSamples(double *dOutL, double *dOutR, int32_t numSamples)
 {
-	double *dMixBufSelect[PAULA_VOICES] = { dOutL, dOutR, dOutR, dOutL };
+	double *dMixBufSelect[PAULA_VOICES];
 
+	dMixBufSelect[0] = dOutL;
+	dMixBufSelect[1] = dOutR;
+	dMixBufSelect[2] = dOutR;
+	dMixBufSelect[3] = dOutL;
+
 	if (numSamples <= 0)
 		return;
 
@@ -437,7 +436,10 @@
 	// apply Amiga filters
 	for (int32_t i = 0; i < numSamples; i++)
 	{
-		double dOut[2] = { dOutL[i], dOutR[i] };
+		double dOut[2];
+
+		dOut[0] = dOutL[i];
+		dOut[1] = dOutR[i];
 
 		if (useLowpassFilter)
 			onePoleLPFilterStereo(&filterLo, dOut, dOut);
--- a/src/pt2_paula.h
+++ b/src/pt2_paula.h
@@ -22,7 +22,7 @@
 
 int8_t *paulaGetNullSamplePtr(void);
 
-void paulaWriteByte(uint32_t address, uint16_t data8);
+void paulaWriteByte(uint32_t address, uint8_t data8);
 void paulaWriteWord(uint32_t address, uint16_t data16);
 void paulaWritePtr(uint32_t address, const int8_t *ptr);
 
--- a/src/pt2_replayer.c
+++ b/src/pt2_replayer.c
@@ -92,13 +92,13 @@
 	editor.tuningToneFlag = false;
 }
 
-void initializeModuleChannels(module_t *s)
+void initializeModuleChannels(module_t *m)
 {
-	assert(s != NULL);
+	assert(m != NULL);
 
-	memset(s->channels, 0, sizeof (s->channels));
+	memset(m->channels, 0, sizeof (m->channels));
 
-	moduleChannel_t *ch = s->channels;
+	moduleChannel_t *ch = m->channels;
 	for (uint8_t i = 0; i < PAULA_VOICES; i++, ch++)
 	{
 		ch->n_chanindex = i;
@@ -117,11 +117,63 @@
 	song->tick = 0;
 }
 
-int8_t *allocMemForAllSamples(void)
+module_t *createEmptyMod(void)
 {
+	module_t *m = (module_t *)calloc(1, sizeof (module_t));
+	if (m == NULL)
+		goto error;
+
 	// allocate memory for all sample data blocks (+ 2 extra, for quirk + safety)
 	const size_t allocLen = (MOD_SAMPLES + 2) * config.maxSampleLength;
-	return (int8_t *)calloc(allocLen, 1);
+
+	m->sampleData = (int8_t *)calloc(allocLen, 1);
+	if (m->sampleData == NULL)
+		goto error;
+
+	for (int32_t i = 0; i < MAX_PATTERNS; i++)
+	{
+		m->patterns[i] = (note_t *)calloc(1, MOD_ROWS * sizeof (note_t) * PAULA_VOICES);
+		if (m->patterns[i] == NULL)
+			goto error;
+	}
+
+	m->header.numOrders = 1;
+
+	moduleSample_t *s = m->samples;
+	for (int32_t i = 0; i < MOD_SAMPLES; i++, s++)
+	{
+		// setup GUI text pointers
+		s->volumeDisp = &s->volume;
+		s->lengthDisp = &s->length;
+		s->loopStartDisp = &s->loopStart;
+		s->loopLengthDisp = &s->loopLength;
+
+		s->loopLength = 2;
+
+		// sample data offsets (sample data = one huge buffer to rule them all)
+		s->offset = config.maxSampleLength * i;
+	}
+
+	initializeModuleChannels(m);
+
+	return m;
+
+error:
+	if (m != NULL)
+	{
+		for (int32_t i = 0; i < MAX_PATTERNS; i++)
+		{
+			if (m->patterns[i] != NULL)
+				free(m->patterns[i]);
+		}
+
+		if (m->sampleData != NULL)
+			free(m->sampleData);
+
+		free(m);
+	}
+
+	return NULL;
 }
 
 void modSetSpeed(int32_t speed)
@@ -1130,13 +1182,19 @@
 
 static void increasePlaybackTimer(void)
 {
-	// the timer is not counting in "play pattern" mode
-	if (editor.playMode != PLAY_MODE_PATTERN && modBPM >= 32 && modBPM <= 255)
+	// (the timer is not counting in "play pattern" mode)
+	if (editor.playMode != PLAY_MODE_PATTERN && modBPM >= MIN_BPM && modBPM <= MAX_BPM)
 	{
 		if (editor.timingMode == TEMPO_MODE_CIA)
-			editor.musicTime64 += musicTimeTab64[modBPM-32];
+			editor.playbackSecondsFrac += musicTimeTab52[modBPM-MIN_BPM];
 		else
-			editor.musicTime64 += musicTimeTab64[(255-32)+1]; // vblank tempo mode
+			editor.playbackSecondsFrac += musicTimeTab52[(MAX_BPM-MIN_BPM)+1]; // vblank tempo mode
+
+		if (editor.playbackSecondsFrac >= 1ULL << 52)
+		{
+			editor.playbackSecondsFrac &= (1ULL << 52)-1;
+			editor.playbackSeconds++;
+		}
 	}
 }
 
@@ -1188,7 +1246,7 @@
 	moduleChannel_t *ch = song->channels;
 	for (int32_t i = 0; i < PAULA_VOICES; i++, ch++)
 	{
-		if (DMACONtemp & ch->n_dmabit) // sample trigger
+		if (DMACONtemp & ch->n_dmabit) // handle visuals on sample trigger
 		{
 			ch->syncAnalyzerVolume = ch->n_volume;
 			ch->syncAnalyzerPeriod = ch->n_period;
@@ -1209,7 +1267,7 @@
 
 void modSetTempo(int32_t bpm, bool doLockAudio)
 {
-	if (bpm < 32 || bpm > 255)
+	if (bpm < MIN_BPM || bpm > MAX_BPM)
 		return;
 
 	const bool audioWasntLocked = !audio.locked;
@@ -1223,19 +1281,15 @@
 		ui.updateSongBPM = true;
 	}
 
-	bpm -= 32; // 32..255 -> 0..223
-	audio.samplesPerTick64 = audio.samplesPerTickTable[bpm];
+	const int32_t i = bpm - MIN_BPM; // 32..255 -> 0..223
 
+	audio.samplesPerTickInt = audio.samplesPerTickIntTab[i];
+	audio.samplesPerTickFrac = audio.samplesPerTickFracTab[i];
+
 	// calculate tick time length for audio/video sync timestamp (visualizers)
 	if (!editor.pat2SmpOngoing && !editor.mod2WavOngoing)
-	{
-		const uint64_t tickTimeLen64 = audio.tickLengthTable[bpm];
-		const uint32_t tickTimeLen = tickTimeLen64 >> 32;
-		const uint32_t tickTimeLenFrac = (uint32_t)tickTimeLen64;
+		setSyncTickTimeLen(audio.tickTimeIntTab[i], audio.tickTimeFracTab[i]);
 
-		setSyncTickTimeLen(tickTimeLen, tickTimeLenFrac);
-	}
-
 	if (doLockAudio && audioWasntLocked)
 		unlockAudio();
 }
@@ -1341,13 +1395,13 @@
 
 			if (editor.stepPlayLastMode == MODE_EDIT || editor.stepPlayLastMode == MODE_IDLE)
 			{
-				song->row &= 0x3F;
+				song->row &= 63;
 				song->currRow = song->row;
 			}
 			else
 			{
 				// if we were playing, set replayer row to tracker row (stay in sync)
-				song->currRow &= 0x3F;
+				song->currRow &= 63;
 				song->row = song->currRow;
 			}
 
@@ -1485,9 +1539,11 @@
 	if (!editor.stepPlayEnabled)
 		pointerSetMode(POINTER_MODE_PLAY, DO_CARRY);
 
-	audio.tickSampleCounter64 = 0; // zero tick sample counter so that it will instantly initiate a tick
-	song->currRow = song->row = startRow & 0x3F;
+	audio.tickSampleCounter = 0; // zero tick sample counter so that it will instantly initiate a tick
+	audio.tickSampleCounterFrac = 0;
 
+	song->currRow = song->row = startRow & 63;
+
 	if (!editor.stepPlayEnabled)
 		song->tick = song->speed-1;
 	else
@@ -1584,10 +1640,15 @@
 	editor.songPlaying = true;
 	editor.didQuantize = false;
 
+	// don't reset playback counter in "play/rec pattern" mode
 	if (editor.playMode != PLAY_MODE_PATTERN)
-		editor.musicTime64 = 0; // don't reset playback counter in "play/rec pattern" mode
+	{
+		editor.playbackSeconds = 0;
+		editor.playbackSecondsFrac = 0;
+	}
 
-	audio.tickSampleCounter64 = 0; // zero tick sample counter so that it will instantly initiate a tick
+	audio.tickSampleCounter = 0; // zero tick sample counter so that it will instantly initiate a tick
+	audio.tickSampleCounterFrac = 0;
 
 	if (audioWasntLocked)
 		unlockAudio();
@@ -1621,7 +1682,8 @@
 	editor.f9Pos = 48;
 	editor.f10Pos = 63;
 
-	editor.musicTime64 = 0;
+	editor.playbackSeconds = 0;
+	editor.playbackSecondsFrac = 0;
 
 	editor.metroFlag = false;
 	editor.currSample = 0;
--- a/src/pt2_replayer.h
+++ b/src/pt2_replayer.h
@@ -4,13 +4,14 @@
 #include <stdbool.h>
 #include "pt2_structs.h"
 
-#define REPLAYER_MIN_BPM 32
+#define MIN_BPM 32
+#define MAX_BPM 255
 
 double ciaBpm2Hz(int32_t bpm);
-void updatePaulaLoops(void); // used after manipulating sample loop points while Paula is live
+void updatePaulaLoops(void); // used after manipulating Paula sample loop points while playing
 void turnOffVoices(void);
 void initializeModuleChannels(module_t *s);
-int8_t *allocMemForAllSamples(void);
+module_t *createEmptyMod(void);
 void setReplayerPosToTrackerPos(void);
 void setPattern(int16_t pattern);
 bool intMusic(void);
--- a/src/pt2_sample_loader.c
+++ b/src/pt2_sample_loader.c
@@ -8,7 +8,7 @@
 #include <stdint.h>
 #include <stdbool.h>
 #include "pt2_textout.h"
-#include "pt2_sampler.h" // fixSampleBeep()
+#include "pt2_sampler.h"
 #include "pt2_audio.h"
 #include "pt2_visuals.h"
 #include "pt2_helpers.h"
@@ -20,1539 +20,36 @@
 
 enum
 {
-	WAV_FORMAT_PCM = 0x0001,
-	WAV_FORMAT_IEEE_FLOAT = 0x0003
+	SAMPLETYPE_RAW,
+	SAMPLETYPE_IFF,
+	SAMPLETYPE_AIFF,
+	SAMPLETYPE_WAV,
+	SAMPLETYPE_FLAC
 };
 
-enum
-{
-	SAMPLE_IFF = 0,
-	SAMPLE_AIFF = 1,
-	SAMPLE_WAV = 2
-};
+bool loadRAWSample(FILE *f, int32_t filesize, moduleSample_t *s);
+bool loadIFFSample(FILE *f, int32_t filesize, moduleSample_t *s);
+bool loadAIFFSample(FILE *f, int32_t filesize, moduleSample_t *s);
+bool loadWAVSample(FILE *f, int32_t filesize, moduleSample_t *s);
+bool loadFLACSample(FILE *f, int32_t filesize, moduleSample_t *s);
 
-static bool loadWAVSample(UNICHAR *fileName, char *entryName)
+static void setSampleTextFromFilename(moduleSample_t *s, char *entryName, const char *ext)
 {
-	uint16_t audioFormat, numChannels, bitsPerSample;
-	uint32_t sampleRate;
+	int32_t extLen = (int32_t)strlen(ext);
+	int32_t nameLen = (int32_t)strlen(entryName);
 
-	// zero out chunk pointers and lengths
-	uint32_t fmtPtr  = 0; uint32_t fmtLen = 0;
-	uint32_t dataPtr = 0; uint32_t dataLen = 0;
-	uint32_t inamPtr = 0;  int32_t inamLen = 0;
-	uint32_t xtraPtr = 0; uint32_t xtraLen = 0;
-	uint32_t smplPtr = 0; uint32_t smplLen = 0;
+	// don't include file extension (if present)
+	if (nameLen >= extLen && !_strnicmp(&entryName[nameLen-extLen], ext, extLen))
+		nameLen -= extLen;
 
-	bool wavSampleNameFound = false;
-
-	moduleSample_t *s = &song->samples[editor.currSample];
-
-	FILE *f = UNICHAR_FOPEN(fileName, "rb");
-	if (f == NULL)
-	{
-		displayErrorMsg("FILE I/O ERROR !");
-		return false;
-	}
-
-	fseek(f, 0, SEEK_END);
-	uint32_t fileSize = ftell(f);
-	if (fileSize == 0)
-	{
-		fclose(f);
-
-		displayErrorMsg("NOT A WAV !");
-		return false;
-	}
-
-	// look for wanted chunks and set up pointers + lengths
-	fseek(f, 12, SEEK_SET);
-
-	uint32_t bytesRead = 0;
-	while (!feof(f) && bytesRead < fileSize-12)
-	{
-		uint32_t chunkID, chunkSize;
-
-		fread(&chunkID, 4, 1, f); if (feof(f)) break;
-		fread(&chunkSize, 4, 1, f); if (feof(f)) break;
-
-		uint32_t endOfChunk = (ftell(f) + chunkSize) + (chunkSize & 1);
-		switch (chunkID)
-		{
-			case 0x20746D66: // "fmt "
-			{
-				fmtPtr = ftell(f);
-				fmtLen = chunkSize;
-			}
-			break;
-
-			case 0x61746164: // "data"
-			{
-				dataPtr = ftell(f);
-				dataLen = chunkSize;
-			}
-			break;
-
-			case 0x5453494C: // "LIST"
-			{
-				if (chunkSize >= 4)
-				{
-					fread(&chunkID, 4, 1, f);
-					if (chunkID == 0x4F464E49) // "INFO"
-					{
-						bytesRead = 0;
-						while (!feof(f) && (bytesRead < chunkSize))
-						{
-							fread(&chunkID, 4, 1, f);
-							fread(&chunkSize, 4, 1, f);
-
-							switch (chunkID)
-							{
-								case 0x4D414E49: // "INAM"
-								{
-									inamPtr = ftell(f);
-									inamLen = chunkSize;
-								}
-								break;
-
-								default: break;
-							}
-
-							bytesRead += (chunkSize + (chunkSize & 1));
-						}
-					}
-				}
-			}
-			break;
-
-			case 0x61727478: // "xtra"
-			{
-				xtraPtr = ftell(f);
-				xtraLen = chunkSize;
-			}
-			break;
-
-			case 0x6C706D73: // "smpl"
-			{
-				smplPtr = ftell(f);
-				smplLen = chunkSize;
-			}
-			break;
-
-			default: break;
-		}
-
-		bytesRead += chunkSize + (chunkSize & 1);
-		fseek(f, endOfChunk, SEEK_SET);
-	}
-
-	// we need at least "fmt " and "data" - check if we found them sanely
-	if ((fmtPtr == 0 || fmtLen < 16) || (dataPtr == 0 || dataLen == 0))
-	{
-		fclose(f);
-		displayErrorMsg("NOT A WAV !");
-		return false;
-	}
-
-	// ---- READ "fmt " CHUNK ----
-	fseek(f, fmtPtr, SEEK_SET);
-	fread(&audioFormat, 2, 1, f);
-	fread(&numChannels, 2, 1, f);
-	fread(&sampleRate,  4, 1, f);
-	fseek(f, 6, SEEK_CUR);
-	fread(&bitsPerSample, 2, 1, f);
-	int32_t sampleLength = dataLen;
-	// ---------------------------
-
-	if (sampleRate == 0 || sampleLength == 0 || sampleLength >= (int32_t)fileSize*(bitsPerSample/8))
-	{
-		fclose(f);
-		displayErrorMsg("WAV CORRUPT !");
-		return false;
-	}
-
-	if (audioFormat != WAV_FORMAT_PCM && audioFormat != WAV_FORMAT_IEEE_FLOAT)
-	{
-		fclose(f);
-		displayErrorMsg("WAV UNSUPPORTED !");
-		return false;
-	}
-
-	if ((numChannels == 0) || (numChannels > 2))
-	{
-		fclose(f);
-		displayErrorMsg("WAV UNSUPPORTED !");
-		return false;
-	}
-
-	if (audioFormat == WAV_FORMAT_IEEE_FLOAT && bitsPerSample != 32 && bitsPerSample != 64)
-	{
-		fclose(f);
-		displayErrorMsg("WAV UNSUPPORTED !");
-		return false;
-	}
-
-	if (bitsPerSample != 8 && bitsPerSample != 16 && bitsPerSample != 24 && bitsPerSample != 32 && bitsPerSample != 64)
-	{
-		fclose(f);
-		displayErrorMsg("WAV UNSUPPORTED !");
-		return false;
-	}
-
-	bool forceDownSampling = false;
-	if (sampleRate > 22050 && !config.noDownsampleOnSmpLoad)
-	{
-		if (askBox(ASKBOX_DOWNSAMPLE, "DOWNSAMPLE ?"))
-			forceDownSampling = true;
-	}
-
-	// ---- READ SAMPLE DATA ----
-	fseek(f, dataPtr, SEEK_SET);
-
-	int8_t *smpPtr = &song->sampleData[editor.currSample * config.maxSampleLength];
-
-	if (bitsPerSample == 8) // 8-BIT INTEGER SAMPLE
-	{
-		if (sampleLength > config.maxSampleLength*4)
-			sampleLength = config.maxSampleLength*4;
-
-		uint8_t *audioDataU8 = (uint8_t *)malloc(sampleLength * sizeof (uint8_t));
-		if (audioDataU8 == NULL)
-		{
-			fclose(f);
-			statusOutOfMemory();
-			return false;
-		}
-
-		// read sample data
-		if (fread(audioDataU8, 1, sampleLength, f) != (size_t)sampleLength)
-		{
-			fclose(f);
-			free(audioDataU8);
-			displayErrorMsg("I/O ERROR !");
-			return false;
-		}
-
-		// convert from stereo to mono (if needed)
-		if (numChannels == 2)
-		{
-			sampleLength >>= 1;
-			for (int32_t i = 0; i < sampleLength-1; i++) // add right channel to left channel
-			{
-				int32_t smp32 = (audioDataU8[(i << 1) + 0] - 128) + (audioDataU8[(i << 1) + 1] - 128);
-				smp32 = 128 + (smp32 >> 1);
-				audioDataU8[i] = (uint8_t)smp32;
-			}
-		}
-
-		// 2x downsampling
-		if (forceDownSampling)
-		{
-			downsample2x8BitU(audioDataU8, sampleLength);
-			sampleLength >>= 1;
-		}
-
-		if (sampleLength > config.maxSampleLength)
-			sampleLength = config.maxSampleLength;
-
-		turnOffVoices();
-		for (int32_t i = 0; i < sampleLength; i++)
-			smpPtr[i] = audioDataU8[i] - 128;
-
-		free(audioDataU8);
-	}
-	else if (bitsPerSample == 16) // 16-BIT INTEGER SAMPLE
-	{
-		sampleLength >>= 1;
-		if (sampleLength > config.maxSampleLength*4)
-			sampleLength = config.maxSampleLength*4;
-
-		int16_t *audioDataS16 = (int16_t *)malloc(sampleLength * sizeof (int16_t));
-		if (audioDataS16 == NULL)
-		{
-			fclose(f);
-			statusOutOfMemory();
-			return false;
-		}
-
-		// read sample data
-		if (fread(audioDataS16, 2, sampleLength, f) != (size_t)sampleLength)
-		{
-			fclose(f);
-			free(audioDataS16);
-			displayErrorMsg("I/O ERROR !");
-			return false;
-		}
-
-		// convert from stereo to mono (if needed)
-		if (numChannels == 2)
-		{
-			sampleLength >>= 1;
-			for (int32_t i = 0; i < sampleLength-1; i++) // add right channel to left channel
-				audioDataS16[i] = (audioDataS16[(i << 1) + 0] + audioDataS16[(i << 1) + 1]) >> 1;;
-		}
-
-		// 2x downsampling
-		if (forceDownSampling)
-		{
-			downsample2x16Bit(audioDataS16, sampleLength);
-			sampleLength >>= 1;
-		}
-
-		if (sampleLength > config.maxSampleLength)
-			sampleLength = config.maxSampleLength;
-
-		double dAmp = 1.0;
-		if (forceDownSampling) // we already normalized
-		{
-			dAmp = INT8_MAX / (double)INT16_MAX;
-		}
-		else
-		{
-			const double dPeak = get16BitPeak(audioDataS16, sampleLength);
-			if (dPeak > 0.0)
-				dAmp = INT8_MAX / dPeak;
-		}
-
-		turnOffVoices();
-		for (int32_t i = 0; i < sampleLength; i++)
-		{
-			int32_t smp32 = (int32_t)round(audioDataS16[i] * dAmp);
-			assert(smp32 >= -128 && smp32 <= 127); // shouldn't happen according to dAmp (but just in case)
-			smpPtr[i] = (int8_t)smp32;
-		}
-
-		free(audioDataS16);
-	}
-	else if (bitsPerSample == 24) // 24-BIT INTEGER SAMPLE
-	{
-		sampleLength /= 3;
-		if (sampleLength > config.maxSampleLength*4)
-			sampleLength = config.maxSampleLength*4;
-
-		int32_t *audioDataS32 = (int32_t *)malloc(sampleLength * sizeof (int32_t));
-		if (audioDataS32 == NULL)
-		{
-			fclose(f);
-			statusOutOfMemory();
-			return false;
-		}
-
-		// read sample data
-		uint8_t *audioDataU8 = (uint8_t *)audioDataS32;
-		for (int32_t i = 0; i < sampleLength; i++)
-		{
-			audioDataU8[0] = 0;
-			fread(&audioDataU8[1], 3, 1, f);
-			audioDataU8 += sizeof (int32_t);
-		}
-
-		// convert from stereo to mono (if needed)
-		if (numChannels == 2)
-		{
-			sampleLength >>= 1;
-			for (int32_t i = 0; i < sampleLength-1; i++) // add right channel to left channel
-			{
-				int64_t smp = ((int64_t)audioDataS32[(i << 1) + 0] + audioDataS32[(i << 1) + 1]) >> 1;
-				audioDataS32[i] = (int32_t)smp;
-			}
-		}
-
-		// 2x downsampling
-		if (forceDownSampling)
-		{
-			downsample2x32Bit(audioDataS32, sampleLength);
-			sampleLength >>= 1;
-		}
-
-		if (sampleLength > config.maxSampleLength)
-			sampleLength = config.maxSampleLength;
-
-		double dAmp = 1.0;
-		if (forceDownSampling) // we already normalized
-		{
-			dAmp = INT8_MAX / (double)INT32_MAX;
-		}
-		else
-		{
-			const double dPeak = get32BitPeak(audioDataS32, sampleLength);
-			if (dPeak > 0.0)
-				dAmp = INT8_MAX / dPeak;
-		}
-
-		turnOffVoices();
-		for (int32_t i = 0; i < sampleLength; i++)
-		{
-			int32_t smp32 = (int32_t)round(audioDataS32[i] * dAmp);
-			assert(smp32 >= -128 && smp32 <= 127); // shouldn't happen according to dAmp (but just in case)
-			smpPtr[i] = (int8_t)smp32;
-		}
-
-		free(audioDataS32);
-	}
-	else if (audioFormat == WAV_FORMAT_PCM && bitsPerSample == 32) // 32-BIT INTEGER SAMPLE
-	{
-		sampleLength >>= 2;
-		if (sampleLength > config.maxSampleLength*4)
-			sampleLength = config.maxSampleLength*4;
-
-		int32_t *audioDataS32 = (int32_t *)malloc(sampleLength * sizeof (int32_t));
-		if (audioDataS32 == NULL)
-		{
-			fclose(f);
-			statusOutOfMemory();
-			return false;
-		}
-
-		// read sample data
-		if (fread(audioDataS32, 4, sampleLength, f) != (size_t)sampleLength)
-		{
-			fclose(f);
-			free(audioDataS32);
-			displayErrorMsg("I/O ERROR !");
-			return false;
-		}
-
-		// convert from stereo to mono (if needed)
-		if (numChannels == 2)
-		{
-			sampleLength >>= 1;
-			for (int32_t i = 0; i < sampleLength-1; i++) // add right channel to left channel
-			{
-				int64_t smp = ((int64_t)audioDataS32[(i << 1) + 0] + audioDataS32[(i << 1) + 1]) >> 1;
-				audioDataS32[i] = (int32_t)smp;
-			}
-		}
-
-		// 2x downsampling
-		if (forceDownSampling)
-		{
-			downsample2x32Bit(audioDataS32, sampleLength);
-			sampleLength >>= 1;
-		}
-
-		if (sampleLength > config.maxSampleLength)
-			sampleLength = config.maxSampleLength;
-
-		double dAmp = 1.0;
-		if (forceDownSampling) // we already normalized
-		{
-			dAmp = INT8_MAX / (double)INT32_MAX;
-		}
-		else
-		{
-			const double dPeak = get32BitPeak(audioDataS32, sampleLength);
-			if (dPeak > 0.0)
-				dAmp = INT8_MAX / dPeak;
-		}
-
-		turnOffVoices();
-		for (int32_t i = 0; i < sampleLength; i++)
-		{
-			int32_t smp32 = (int32_t)round(audioDataS32[i] * dAmp);
-			assert(smp32 >= -128 && smp32 <= 127); // shouldn't happen according to dAmp (but just in case)
-			smpPtr[i] = (int8_t)smp32;
-		}
-
-		free(audioDataS32);
-	}
-	else if (audioFormat == WAV_FORMAT_IEEE_FLOAT && bitsPerSample == 32) // 32-BIT FLOATING POINT SAMPLE
-	{
-		sampleLength >>= 2;
-		if (sampleLength > config.maxSampleLength*4)
-			sampleLength = config.maxSampleLength*4;
-
-		uint32_t *audioDataU32 = (uint32_t *)malloc(sampleLength * sizeof (uint32_t));
-		if (audioDataU32 == NULL)
-		{
-			fclose(f);
-			statusOutOfMemory();
-			return false;
-		}
-
-		// read sample data
-		if (fread(audioDataU32, 4, sampleLength, f) != (size_t)sampleLength)
-		{
-			fclose(f);
-			free(audioDataU32);
-			displayErrorMsg("I/O ERROR !");
-			return false;
-		}
-
-		float *fAudioDataFloat = (float *)audioDataU32;
-
-		// convert from stereo to mono (if needed)
-		if (numChannels == 2)
-		{
-			sampleLength >>= 1;
-			for (int32_t i = 0; i < sampleLength-1; i++) // add right channel to left channel
-				fAudioDataFloat[i] = (fAudioDataFloat[(i * 2) + 0] + fAudioDataFloat[(i * 2) + 1]) * 0.5f;
-		}
-
-		// 2x downsampling
-		if (forceDownSampling)
-		{
-			downsample2xFloat(fAudioDataFloat, sampleLength);
-			sampleLength >>= 1;
-		}
-
-		if (sampleLength > config.maxSampleLength)
-			sampleLength = config.maxSampleLength;
-
-		float fAmp = 1.0f;
-		const float fPeak = getFloatPeak(fAudioDataFloat, sampleLength);
-		if (fPeak > 0.0f)
-			fAmp = INT8_MAX / fPeak;
-
-		turnOffVoices();
-		for (int32_t i = 0; i < sampleLength; i++)
-		{
-			int32_t smp32 = (int32_t)roundf(fAudioDataFloat[i] * fAmp);
-			assert(smp32 >= -128 && smp32 <= 127); // shouldn't happen according to dAmp (but just in case)
-			smpPtr[i] = (int8_t)smp32;
-		}
-
-		free(audioDataU32);
-	}
-	else if (audioFormat == WAV_FORMAT_IEEE_FLOAT && bitsPerSample == 64) // 64-BIT FLOATING POINT SAMPLE
-	{
-		sampleLength >>= 3;
-		if (sampleLength > config.maxSampleLength*4)
-			sampleLength = config.maxSampleLength*4;
-
-		uint32_t *audioDataU32 = (uint32_t *)malloc(sampleLength * (sizeof (uint32_t) * 2));
-		if (audioDataU32 == NULL)
-		{
-			fclose(f);
-			statusOutOfMemory();
-			return false;
-		}
-
-		// read sample data
-		if (fread(audioDataU32, 8, sampleLength, f) != (size_t)sampleLength)
-		{
-			fclose(f);
-			free(audioDataU32);
-			displayErrorMsg("I/O ERROR !");
-			return false;
-		}
-
-		double *dAudioDataDouble = (double *)audioDataU32;
-
-		// convert from stereo to mono (if needed)
-		if (numChannels == 2)
-		{
-			sampleLength >>= 1;
-			for (int32_t i = 0; i < sampleLength-1; i++) // add right channel to left channel
-				dAudioDataDouble[i] = (dAudioDataDouble[(i * 2) + 0] + dAudioDataDouble[(i * 2) + 1]) * 0.5;
-		}
-
-		// 2x downsampling
-		if (forceDownSampling)
-		{
-			downsample2xDouble(dAudioDataDouble, sampleLength);
-			sampleLength >>= 1;
-		}
-
-		if (sampleLength > config.maxSampleLength)
-			sampleLength = config.maxSampleLength;
-
-		double dAmp = 1.0;
-		const double dPeak = getDoublePeak(dAudioDataDouble, sampleLength);
-		if (dPeak > 0.0)
-			dAmp = INT8_MAX / dPeak;
-
-		turnOffVoices();
-		for (int32_t i = 0; i < sampleLength; i++)
-		{
-			int32_t smp32 = (int32_t)round(dAudioDataDouble[i] * dAmp);
-			assert(smp32 >= -128 && smp32 <= 127); // shouldn't happen according to dAmp (but just in case)
-			smpPtr[i] = (int8_t)smp32;
-		}
-
-		free(audioDataU32);
-	}
-
-	if (sampleLength < config.maxSampleLength) // clear rest of sample data
-		memset(&song->sampleData[s->offset + sampleLength], 0, config.maxSampleLength - sampleLength);
-
-	// set sample length
-	if (sampleLength & 1)
-	{
-		if (++sampleLength > config.maxSampleLength)
-			sampleLength = config.maxSampleLength;
-	}
-
-	s->length = sampleLength;
-	s->fineTune = 0;
-	s->volume = 64;
-	s->loopStart = 0;
-	s->loopLength = 2;
-
-	// ---- READ "smpl" chunk ----
-	if (smplPtr != 0 && smplLen > 52)
-	{
-		int32_t loopStart, loopEnd;
-		uint32_t loopFlags;
-
-		fseek(f, smplPtr + 28, SEEK_SET); // seek to first wanted byte
-
-		fread(&loopFlags, 4, 1, f);
-		fseek(f, 12, SEEK_CUR);
-		fread(&loopStart, 4, 1, f);
-		fread(&loopEnd, 4, 1, f);
-		loopEnd++;
-
-		if (forceDownSampling)
-		{
-			// we already downsampled 2x, so we're half the original length
-			loopStart >>= 1;
-			loopEnd >>= 1;
-		}
-
-		loopStart &= ~1;
-		loopEnd &= ~1;
-
-		if (loopFlags)
-		{
-			if (loopStart+(loopEnd-loopStart) <= s->length)
-			{
-				s->loopStart = loopStart;
-				s->loopLength = loopEnd - loopStart;
-
-				if (s->loopLength < 2)
-				{
-					s->loopStart = 0;
-					s->loopLength = 2;
-				}
-			}
-		}
-	}
-	// ---------------------------
-
-	// ---- READ "xtra" chunk ----
-	if (xtraPtr != 0 && xtraLen >= 8)
-	{
-		int16_t tempVol;
-
-		fseek(f, xtraPtr + 4, SEEK_SET); // seek to first wanted byte
-
-		// volume (0..256)
-		fseek(f, 2, SEEK_CUR);
-		fread(&tempVol, 2, 1, f);
-		if (tempVol > 256)
-			tempVol = 256;
-
-		tempVol >>= 2; // 0..256 -> 0..64
-
-		s->volume = (int8_t)tempVol;
-	}
-	// ---------------------------
-
-	// ---- READ "INAM" chunk ----
-	if (inamPtr != 0 && inamLen > 0)
-	{
-		fseek(f, inamPtr, SEEK_SET); // seek to first wanted byte
-
-		for (int32_t i = 0; i < 21; i++)
-		{
-			if (i < inamLen)
-				s->text[i] = (char)fgetc(f);
-			else
-				s->text[i] = '\0';
-		}
-
-		s->text[21] = '\0';
-		s->text[22] = '\0';
-
-		wavSampleNameFound = true;
-	}
-	// ---------------------------
-
-	fclose(f);
-
-	// copy over sample name
-	if (!wavSampleNameFound)
-	{
-		int32_t nameLen = (int32_t)strlen(entryName);
-		for (int32_t i = 0; i < 21; i++)
-			s->text[i] = (i < nameLen) ? (char)entryName[i] : '\0';
-
-		s->text[21] = '\0';
-		s->text[22] = '\0';
-	}
-
-	// remove .wav from end of sample name (if present)
-	int32_t nameLen = (uint32_t)strlen(s->text);
-	if (nameLen >= 4 && !_strnicmp(&s->text[nameLen-4], ".WAV", 4))
-		 memset(&s->text[nameLen-4], '\0', 4);
-
-	editor.sampleZero = false;
-	editor.samplePos = 0;
-
-	fixSampleBeep(s);
-	fillSampleRedoBuffer(editor.currSample);
-
-	if (ui.samplingBoxShown)
-	{
-		removeSamplingBox();
-		ui.samplingBoxShown = false;
-	}
-
-	updateCurrSample();
-
-	updateWindowTitle(MOD_IS_MODIFIED);
-	return true;
-}
-
-static bool loadIFFSample(UNICHAR *fileName, char *entryName)
-{
-	char tmpCharBuf[23];
-	uint16_t sampleRate;
-	int32_t sampleLoopStart, sampleLoopLength;
-
-	// zero out chunk pointers and lengths
-	uint32_t vhdrPtr = 0; uint32_t vhdrLen = 0;
-	uint32_t bodyPtr = 0; uint32_t bodyLen = 0;
-	uint32_t namePtr = 0;  int32_t nameLen = 0;
-
-	moduleSample_t *s = &song->samples[editor.currSample];
-
-	FILE *f = UNICHAR_FOPEN(fileName, "rb");
-	if (f == NULL)
-	{
-		displayErrorMsg("FILE I/O ERROR !");
-		return false;
-	}
-
-	fseek(f, 0, SEEK_END);
-	int32_t fileSize = ftell(f);
-	if (fileSize == 0)
-	{
-		displayErrorMsg("IFF IS CORRUPT !");
-		return false;
-	}
-
-	fseek(f, 8, SEEK_SET);
-	fread(tmpCharBuf, 1, 4, f);
-	bool is16Bit = !strncmp(tmpCharBuf, "16SV", 4);
-
-	int32_t sampleLength = 0;
-	bool nameFound = false;
-	uint32_t sampleVolume = 65536; // max volume
-
-	fseek(f, 12, SEEK_SET);
-	while (!feof(f) && ftell(f) < fileSize-12)
-	{
-		uint32_t blockName, blockSize;
-
-		fread(&blockName, 4, 1, f); if (feof(f)) break;
-		fread(&blockSize, 4, 1, f); if (feof(f)) break;
-
-		blockName = SWAP32(blockName);
-		blockSize = SWAP32(blockSize);
-
-		switch (blockName)
-		{
-			case 0x56484452: // VHDR
-			{
-				vhdrPtr = ftell(f);
-				vhdrLen = blockSize;
-			}
-			break;
-
-			case 0x4E414D45: // NAME
-			{
-				namePtr = ftell(f);
-				nameLen = blockSize;
-			}
-			break;
-
-			case 0x424F4459: // BODY
-			{
-				bodyPtr = ftell(f);
-				bodyLen = blockSize;
-			}
-			break;
-
-			default: break;
-		}
-
-		fseek(f, blockSize + (blockSize & 1), SEEK_CUR);
-	}
-
-	if (vhdrPtr == 0 || vhdrLen < 20 || bodyPtr == 0)
-	{
-		fclose(f);
-		displayErrorMsg("NOT A VALID IFF !");
-		return false;
-	}
-
-	// kludge for some really strange IFFs
-	if (bodyLen == 0)
-		bodyLen = fileSize - bodyPtr;
-
-	if (bodyPtr+bodyLen > (uint32_t)fileSize)
-		bodyLen = fileSize - bodyPtr;
-
-	fseek(f, vhdrPtr, SEEK_SET);
-	fread(&sampleLoopStart,  4, 1, f); sampleLoopStart  = SWAP32(sampleLoopStart);
-	fread(&sampleLoopLength, 4, 1, f); sampleLoopLength = SWAP32(sampleLoopLength);
-	fseek(f, 4, SEEK_CUR);
-	fread(&sampleRate, 2, 1, f); sampleRate = SWAP16(sampleRate);
-	fseek(f, 1, SEEK_CUR);
-
-	if (fgetc(f) != 0) // sample type
-	{
-		fclose(f);
-		displayErrorMsg("UNSUPPORTED IFF !");
-		return false;
-	}
-
-	fread(&sampleVolume, 4, 1, f); sampleVolume = SWAP32(sampleVolume);
-	if (sampleVolume > 65536)
-		sampleVolume = 65536;
-
-	sampleVolume = (sampleVolume + 512) / 1024; // rounded
-	if (sampleVolume > 64)
-		sampleVolume = 64;
-
-	sampleLength = bodyLen;
-
-	if (sampleLength == 0)
-	{
-		fclose(f);
-		displayErrorMsg("NOT A VALID IFF !");
-		return false;
-	}
-
-	bool forceDownSampling = false;
-	if (sampleRate > 22050 && !config.noDownsampleOnSmpLoad)
-	{
-		if (askBox(ASKBOX_DOWNSAMPLE, "DOWNSAMPLE ?"))
-			forceDownSampling = true;
-	}
-
-	int32_t maxSampleLength = config.maxSampleLength;
-	if (is16Bit)
-		maxSampleLength *= 2;
-
-	if (forceDownSampling)
-		maxSampleLength *= 2;
-
-	if (sampleLength > maxSampleLength)
-		sampleLength = maxSampleLength;
-
-	int8_t *sampleData = (int8_t *)malloc(sampleLength);
-	if (sampleData == NULL)
-	{
-		fclose(f);
-		statusOutOfMemory();
-		return false;
-	}
-
-	if (is16Bit)
-	{
-		sampleLength >>= 1;
-		sampleLoopStart >>= 1;
-		sampleLoopLength >>= 1;
-	}
-
-	if (forceDownSampling)
-	{
-		sampleLoopStart >>= 1;
-		sampleLoopLength >>= 1;
-	}
-
-	turnOffVoices();
-
-	fseek(f, bodyPtr, SEEK_SET);
-	if (is16Bit) // FT2-specific 16SV format (little-endian samples)
-	{
-		fread(sampleData, 1, sampleLength << 1, f);
-		int16_t *ptr16 = (int16_t *)sampleData;
-
-		// 2x downsampling
-		if (forceDownSampling)
-		{
-			downsample2x16Bit(ptr16, sampleLength);
-			sampleLength >>= 1;
-		}
-
-		if (sampleLength > config.maxSampleLength)
-			sampleLength = config.maxSampleLength;
-
-		double dAmp = 1.0;
-		if (forceDownSampling) // we already normalized
-		{
-			dAmp = INT8_MAX / (double)INT16_MAX;
-		}
-		else
-		{
-			const double dPeak = get16BitPeak(ptr16, sampleLength);
-			if (dPeak > 0.0)
-				dAmp = INT8_MAX / dPeak;
-		}
-
-		int8_t *smpPtr = &song->sampleData[s->offset];
-		for (int32_t i = 0; i < sampleLength; i++)
-		{
-			int32_t smp32 = (int32_t)round(ptr16[i] * dAmp);
-			assert(smp32 >= -128 && smp32 <= 127); // shouldn't happen according to dAmp (but just in case)
-			smpPtr[i] = (int8_t)smp32;
-		}
-	}
-	else
-	{
-		fread(sampleData, 1, sampleLength, f);
-
-		// 2x downsampling
-		if (forceDownSampling)
-		{
-			downsample2x8Bit(sampleData, sampleLength);
-			sampleLength >>= 1;
-		}
-
-		if (sampleLength > config.maxSampleLength)
-			sampleLength = config.maxSampleLength;
-
-		memcpy(&song->sampleData[s->offset], sampleData, sampleLength);
-	}
-
-	free(sampleData);
-
-	if (sampleLength < config.maxSampleLength) // clear rest of sample data
-		memset(&song->sampleData[s->offset + sampleLength], 0, config.maxSampleLength - sampleLength);
-
-	// set sample length
-	if (sampleLength & 1)
-	{
-		if (++sampleLength > config.maxSampleLength)
-			sampleLength = config.maxSampleLength;
-	}
-
-	sampleLoopStart &= ~1;
-	sampleLoopLength &= ~1;
-
-	if (sampleLoopLength < 2)
-	{
-		sampleLoopStart = 0;
-		sampleLoopLength = 2;
-	}
-
-	if (sampleLoopStart >= sampleLength || sampleLoopLength > sampleLength)
-	{
-		sampleLoopStart = 0;
-		sampleLoopLength = 2;
-	}
-
-	if (sampleLoopStart+sampleLoopLength > sampleLength)
-	{
-		sampleLoopStart = 0;
-		sampleLoopLength = 2;
-	}
-
-	if (sampleLoopStart > sampleLength-2)
-	{
-		sampleLoopStart = 0;
-		sampleLoopLength = 2;
-	}
-
-	// set sample attributes
-	s->volume = (int8_t)sampleVolume;
-	s->fineTune = 0;
-	s->length = sampleLength;
-	s->loopStart = sampleLoopStart;
-	s->loopLength = sampleLoopLength;
-
-	// read name
-	if (namePtr != 0 && nameLen > 0)
-	{
-		fseek(f, namePtr, SEEK_SET);
-		memset(tmpCharBuf, 0, sizeof (tmpCharBuf));
-
-		if (nameLen > 21)
-		{
-			fread(tmpCharBuf, 1, 21, f);
-			fseek(f, nameLen - 21, SEEK_CUR);
-		}
-		else
-		{
-			fread(tmpCharBuf, 1, nameLen, f);
-		}
-
-		nameFound = true;
-	}
-
-	fclose(f);
-
-	// copy over sample name
-	memset(s->text, '\0', sizeof (s->text));
-
-	if (nameFound)
-	{
-		nameLen = (uint32_t)strlen(tmpCharBuf);
-		if (nameLen > 21)
-			nameLen = 21;
-
-		memcpy(s->text, tmpCharBuf, nameLen);
-	}
-	else
-	{
-		nameLen = (uint32_t)strlen(entryName);
-		if (nameLen > 21)
-			nameLen = 21;
-
-		memcpy(s->text, entryName, nameLen);
-	}
-
-	// remove .iff from end of sample name (if present)
-	nameLen = (uint32_t)strlen(s->text);
-	if (nameLen >= 4 && !strncmp(&s->text[nameLen-4], ".IFF", 4))
-		memset(&s->text[nameLen-4], '\0', 4);
-
-	editor.sampleZero = false;
-	editor.samplePos = 0;
-
-	fixSampleBeep(s);
-	fillSampleRedoBuffer(editor.currSample);
-	updateCurrSample();
-
-	updateWindowTitle(MOD_IS_MODIFIED);
-	return false;
-}
-
-static bool loadRAWSample(UNICHAR *fileName, char *entryName)
-{
-	moduleSample_t *s = &song->samples[editor.currSample];
-
-	FILE *f = UNICHAR_FOPEN(fileName, "rb");
-	if (f == NULL)
-	{
-		displayErrorMsg("FILE I/O ERROR !");
-		return false;
-	}
-
-	fseek(f, 0, SEEK_END);
-	int32_t fileSize = ftell(f);
-	fseek(f, 0, SEEK_SET);
-
-	fileSize &= ~1;
-	if (fileSize > config.maxSampleLength)
-		fileSize = config.maxSampleLength;
-
-	turnOffVoices();
-
-	fread(&song->sampleData[s->offset], 1, fileSize, f);
-	fclose(f);
-
-	if (fileSize < config.maxSampleLength)
-		memset(&song->sampleData[s->offset + fileSize], 0, config.maxSampleLength - fileSize);
-
-	// set sample attributes
-	s->volume = 64;
-	s->fineTune = 0;
-	s->length = fileSize;
-	s->loopStart = 0;
-	s->loopLength = 2;
-
-	// copy over sample name
-	int32_t nameLen = (uint32_t)strlen(entryName);
+	// copy over filename to sample name first
 	for (int32_t i = 0; i < 21; i++)
 		s->text[i] = (i < nameLen) ? (char)entryName[i] : '\0';
 
 	s->text[21] = '\0';
 	s->text[22] = '\0';
-
-	editor.sampleZero = false;
-	editor.samplePos = 0;
-
-	fixSampleBeep(s);
-	fillSampleRedoBuffer(editor.currSample);
-
-	if (ui.samplingBoxShown)
-	{
-		removeSamplingBox();
-		ui.samplingBoxShown = false;
-	}
-
-	updateCurrSample();
-
-	updateWindowTitle(MOD_IS_MODIFIED);
-	return true;
 }
 
-static int32_t getAIFFRate(uint8_t *in)
-{
-	int32_t exp = (int32_t)(((in[0] & 0x7F) << 8) | in[1]);
-	uint32_t lo = (in[2] << 24) | (in[3] << 16) | (in[4] << 8) | in[5];
-	uint32_t hi = (in[6] << 24) | (in[7] << 16) | (in[8] << 8) | in[9];
-
-	if (exp == 0 && lo == 0 && hi == 0)
-		return 0;
-
-	exp -= 16383;
-
-	double dOut = ldexp(lo, -31 + exp) + ldexp(hi, -63 + exp);
-	return (int32_t)(dOut + 0.5);
-}
-
-static bool loadAIFFSample(UNICHAR *fileName, char *entryName)
-{
-	uint8_t sampleRateBytes[10];
-	uint16_t bitDepth, numChannels;
-	uint32_t offset, sampleRate;
-
-	// zero out chunk pointers and lengths
-	uint32_t commPtr = 0; uint32_t commLen = 0;
-	uint32_t ssndPtr = 0; uint32_t ssndLen = 0;
-
-	bool unsigned8bit = false;
-
-	moduleSample_t *s = &song->samples[editor.currSample];
-
-	FILE *f = UNICHAR_FOPEN(fileName, "rb");
-	if (f == NULL)
-	{
-		displayErrorMsg("FILE I/O ERROR !");
-		return false;
-	}
-
-	fseek(f, 0, SEEK_END);
-	int32_t fileSize = ftell(f);
-	if (fileSize == 0)
-	{
-		displayErrorMsg("AIFF IS CORRUPT !");
-		return false;
-	}
-
-	fseek(f, 12, SEEK_SET);
-	while (!feof(f) && ftell(f) < fileSize-12)
-	{
-		uint32_t blockName, blockSize;
-
-		fread(&blockName, 4, 1, f); if (feof(f)) break;
-		fread(&blockSize, 4, 1, f); if (feof(f)) break;
-
-		blockName = SWAP32(blockName);
-		blockSize = SWAP32(blockSize);
-
-		switch (blockName)
-		{
-			case 0x434F4D4D: // "COMM"
-			{
-				commPtr = ftell(f);
-				commLen = blockSize;
-			}
-			break;
-
-			case 0x53534E44: // "SSND"
-			{
-				ssndPtr = ftell(f);
-				ssndLen = blockSize;
-			}
-			break;
-
-			default: break;
-		}
-
-		fseek(f, blockSize + (blockSize & 1), SEEK_CUR);
-	}
-
-	if (commPtr == 0 || commLen < 18 || ssndPtr == 0)
-	{
-		fclose(f);
-		displayErrorMsg("NOT A VALID AIFF!");
-		return false;
-	}
-
-	// kludge for some really strange AIFFs
-	if (ssndLen == 0)
-		ssndLen = fileSize - ssndPtr;
-
-	if (ssndPtr+ssndLen > (uint32_t)fileSize)
-		ssndLen = fileSize - ssndPtr;
-
-	fseek(f, commPtr, SEEK_SET);
-	fread(&numChannels, 2, 1, f); numChannels = SWAP16(numChannels);
-	fseek(f, 4, SEEK_CUR);
-	fread(&bitDepth, 2, 1, f); bitDepth = SWAP16(bitDepth);
-	fread(sampleRateBytes, 1, 10, f);
-
-	fseek(f, 4 + 2 + 1, SEEK_CUR);
-
-	if (numChannels != 1 && numChannels != 2) // sample type
-	{
-		fclose(f);
-		displayErrorMsg("UNSUPPORTED AIFF!");
-		return false;
-	}
-
-	if (bitDepth != 8 && bitDepth != 16 && bitDepth != 24 && bitDepth != 32)
-	{
-		fclose(f);
-		displayErrorMsg("UNSUPPORTED AIFF!");
-		return false;
-	}
-
-	// read compression type (if present)
-	if (commLen > 18)
-	{
-		char compType[4];
-		fread(&compType, 1, 4, f);
-		if (memcmp(compType, "NONE", 4))
-		{
-			fclose(f);
-			displayErrorMsg("UNSUPPORTED AIFF!");
-			return false;
-		}
-	}
-
-	sampleRate = getAIFFRate(sampleRateBytes);
-
-	// sample data chunk
-
-	fseek(f, ssndPtr, SEEK_SET);
-
-	fread(&offset, 4, 1, f);
-	if (offset > 0)
-	{
-		fclose(f);
-		displayErrorMsg("UNSUPPORTED AIFF!");
-		return false;
-	}
-
-	fseek(f, 4, SEEK_CUR);
-
-	ssndLen -= 8; // don't include offset and blockSize datas
-
-	int32_t sampleLength = ssndLen;
-	if (sampleLength == 0)
-	{
-		fclose(f);
-		displayErrorMsg("NOT A VALID AIFF!");
-		return false;
-	}
-
-	bool forceDownSampling = false;
-	if (sampleRate > 22050 && !config.noDownsampleOnSmpLoad)
-	{
-		if (askBox(ASKBOX_DOWNSAMPLE, "DOWNSAMPLE ?"))
-			forceDownSampling = true;
-	}
-
-	int8_t *smpPtr = &song->sampleData[editor.currSample * config.maxSampleLength];
-
-	if (bitDepth == 8) // 8-BIT INTEGER SAMPLE
-	{
-		if (sampleLength > config.maxSampleLength*4)
-			sampleLength = config.maxSampleLength*4;
-
-		int8_t *audioDataS8 = (int8_t *)malloc(sampleLength * sizeof (int8_t));
-		if (audioDataS8 == NULL)
-		{
-			fclose(f);
-			statusOutOfMemory();
-			return false;
-		}
-
-		// read sample data
-		if (fread(audioDataS8, 1, sampleLength, f) != (size_t)sampleLength)
-		{
-			fclose(f);
-			free(audioDataS8);
-			displayErrorMsg("I/O ERROR !");
-			return false;
-		}
-
-		if (unsigned8bit)
-		{
-			for (int32_t i = 0; i < sampleLength; i++)
-				audioDataS8[i] ^= 0x80;
-		}
-
-		// convert from stereo to mono (if needed)
-		if (numChannels == 2)
-		{
-			sampleLength >>= 1;
-			for (int32_t i = 0; i < sampleLength-1; i++) // add right channel to left channel
-				audioDataS8[i] = (audioDataS8[(i * 2) + 0] + audioDataS8[(i * 2) + 1]) >> 1;;
-		}
-
-		// 2x downsampling
-		if (forceDownSampling)
-		{
-			downsample2x8Bit(audioDataS8, sampleLength);
-			sampleLength >>= 1;
-		}
-
-		if (sampleLength > config.maxSampleLength)
-			sampleLength = config.maxSampleLength;
-
-		turnOffVoices();
-		for (int32_t i = 0; i < sampleLength; i++)
-			smpPtr[i] = audioDataS8[i];
-
-		free(audioDataS8);
-	}
-	else if (bitDepth == 16) // 16-BIT INTEGER SAMPLE
-	{
-		sampleLength >>= 1;
-		if (sampleLength > config.maxSampleLength*4)
-			sampleLength = config.maxSampleLength*4;
-
-		int16_t *audioDataS16 = (int16_t *)malloc(sampleLength * sizeof (int16_t));
-		if (audioDataS16 == NULL)
-		{
-			fclose(f);
-			statusOutOfMemory();
-			return false;
-		}
-
-		// read sample data
-		if (fread(audioDataS16, 2, sampleLength, f) != (size_t)sampleLength)
-		{
-			fclose(f);
-			free(audioDataS16);
-			displayErrorMsg("I/O ERROR !");
-			return false;
-		}
-
-		// fix endianness
-		for (int32_t i = 0; i < sampleLength; i++)
-			audioDataS16[i] = SWAP16(audioDataS16[i]);
-
-		// convert from stereo to mono (if needed)
-		if (numChannels == 2)
-		{
-			sampleLength >>= 1;
-			for (int32_t i = 0; i < sampleLength-1; i++) // add right channel to left channel
-				audioDataS16[i] = (audioDataS16[(i << 1) + 0] + audioDataS16[(i << 1) + 1]) >> 1;
-		}
-
-		// 2x downsampling
-		if (forceDownSampling)
-		{
-			downsample2x16Bit(audioDataS16, sampleLength);
-			sampleLength >>= 1;
-		}
-
-		if (sampleLength > config.maxSampleLength)
-			sampleLength = config.maxSampleLength;
-
-		double dAmp = 1.0;
-		if (forceDownSampling) // we already normalized
-		{
-			dAmp = INT8_MAX / (double)INT16_MAX;
-		}
-		else
-		{
-			const double dPeak = get16BitPeak(audioDataS16, sampleLength);
-			if (dPeak > 0.0)
-				dAmp = INT8_MAX / dPeak;
-		}
-
-		turnOffVoices();
-		for (int32_t i = 0; i < sampleLength; i++)
-		{
-			int32_t smp32 = (int32_t)round(audioDataS16[i] * dAmp);
-			assert(smp32 >= -128 && smp32 <= 127); // shouldn't happen according to dAmp (but just in case)
-			smpPtr[i] = (int8_t)smp32;
-		}
-
-		free(audioDataS16);
-	}
-	else if (bitDepth == 24) // 24-BIT INTEGER SAMPLE
-	{
-		sampleLength /= 3;
-		if (sampleLength > config.maxSampleLength*4)
-			sampleLength = config.maxSampleLength*4;
-
-		int32_t *audioDataS32 = (int32_t *)malloc(sampleLength * sizeof (int32_t));
-		if (audioDataS32 == NULL)
-		{
-			fclose(f);
-			statusOutOfMemory();
-			return false;
-		}
-
-		// read sample data
-		if (fread(&audioDataS32[sampleLength >> 2], 3, sampleLength, f) != (size_t)sampleLength)
-		{
-			fclose(f);
-			free(audioDataS32);
-			displayErrorMsg("I/O ERROR !");
-			return false;
-		}
-
-		// convert to 32-bit
-		uint8_t *audioDataU8 = (uint8_t *)audioDataS32 + sampleLength;
-		for (int32_t i = 0; i < sampleLength; i++)
-		{
-			audioDataS32[i] = (audioDataU8[0] << 24) | (audioDataU8[1] << 16) | (audioDataU8[2] << 8);
-			audioDataU8 += 3;
-		}
-
-		// convert from stereo to mono (if needed)
-		if (numChannels == 2)
-		{
-			sampleLength >>= 1;
-			for (int32_t i = 0; i < sampleLength-1; i++) // add right channel to left channel
-			{
-				int64_t smp = ((int64_t)audioDataS32[(i << 1) + 0] + audioDataS32[(i << 1) + 1]) >> 1;
-				audioDataS32[i] = (int32_t)smp;
-			}
-		}
-
-		// 2x downsampling
-		if (forceDownSampling)
-		{
-			downsample2x32Bit(audioDataS32, sampleLength);
-			sampleLength >>= 1;
-		}
-
-		if (sampleLength > config.maxSampleLength)
-			sampleLength = config.maxSampleLength;
-
-		double dAmp = 1.0;
-		if (forceDownSampling) // we already normalized
-		{
-			dAmp = INT8_MAX / (double)INT32_MAX;
-		}
-		else
-		{
-			const double dPeak = get32BitPeak(audioDataS32, sampleLength);
-			if (dPeak > 0.0)
-				dAmp = INT8_MAX / dPeak;
-		}
-
-		turnOffVoices();
-		for (int32_t i = 0; i < sampleLength; i++)
-		{
-			int32_t smp32 = (int32_t)round(audioDataS32[i] * dAmp);
-			smpPtr[i] = (int8_t)smp32;
-		}
-
-		free(audioDataS32);
-	}
-	else if (bitDepth == 32) // 32-BIT INTEGER SAMPLE
-	{
-		sampleLength >>= 2;
-		if (sampleLength > config.maxSampleLength*4)
-			sampleLength = config.maxSampleLength*4;
-
-		int32_t *audioDataS32 = (int32_t *)malloc(sampleLength * sizeof (int32_t));
-		if (audioDataS32 == NULL)
-		{
-			fclose(f);
-			statusOutOfMemory();
-			return false;
-		}
-
-		// read sample data
-		if (fread(audioDataS32, 4, sampleLength, f) != (size_t)sampleLength)
-		{
-			fclose(f);
-			free(audioDataS32);
-			displayErrorMsg("I/O ERROR !");
-			return false;
-		}
-
-		// fix endianness
-		for (int32_t i = 0; i < sampleLength; i++)
-			audioDataS32[i] = SWAP32(audioDataS32[i]);
-
-		// convert from stereo to mono (if needed)
-		if (numChannels == 2)
-		{
-			sampleLength >>= 1;
-			for (int32_t i = 0; i < sampleLength-1; i++) // add right channel to left channel
-			{
-				int64_t smp = ((int64_t)audioDataS32[(i << 1) + 0] + audioDataS32[(i << 1) + 1]) >> 1;
-				audioDataS32[i] = (int32_t)smp;
-			}
-		}
-
-		// 2x downsampling
-		if (forceDownSampling)
-		{
-			downsample2x32Bit(audioDataS32, sampleLength);
-			sampleLength >>= 1;
-		}
-
-		if (sampleLength > config.maxSampleLength)
-			sampleLength = config.maxSampleLength;
-
-		double dAmp = 1.0;
-		if (forceDownSampling) // we already normalized
-		{
-			dAmp = INT8_MAX / (double)INT32_MAX;
-		}
-		else
-		{
-			const double dPeak = get32BitPeak(audioDataS32, sampleLength);
-			if (dPeak > 0.0)
-				dAmp = INT8_MAX / dPeak;
-		}
-
-		turnOffVoices();
-		for (int32_t i = 0; i < sampleLength; i++)
-		{
-			int32_t smp32 = (int32_t)round(audioDataS32[i] * dAmp);
-			smpPtr[i] = (int8_t)smp32;
-		}
-
-		free(audioDataS32);
-	}
-
-	if (sampleLength < config.maxSampleLength) // clear rest of sample data
-		memset(&song->sampleData[s->offset + sampleLength], 0, config.maxSampleLength - sampleLength);
-
-	// set sample length
-	if (sampleLength & 1)
-	{
-		if (++sampleLength > config.maxSampleLength)
-			sampleLength = config.maxSampleLength;
-	}
-
-	s->length = sampleLength;
-	s->fineTune = 0;
-	s->volume = 64;
-	s->loopStart = 0;
-	s->loopLength = 2;
-
-	fclose(f);
-
-	// copy over sample name
-	int32_t nameLen = (int32_t)strlen(entryName);
-	for (int32_t i = 0; i < 21; i++)
-		s->text[i] = (i < nameLen) ? (char)entryName[i] : '\0';
-
-	s->text[21] = '\0';
-	s->text[22] = '\0';
-
-	// remove .aiff from end of sample name (if present)
-	nameLen = (uint32_t)strlen(s->text);
-	if (nameLen >= 5 && !_strnicmp(&s->text[nameLen-5], ".AIFF", 5))
-		memset(&s->text[nameLen-5], '\0', 5);
-
-	editor.sampleZero = false;
-	editor.samplePos = 0;
-
-	fixSampleBeep(s);
-	fillSampleRedoBuffer(editor.currSample);
-
-	if (ui.samplingBoxShown)
-	{
-		removeSamplingBox();
-		ui.samplingBoxShown = false;
-	}
-
-	updateCurrSample();
-
-	updateWindowTitle(MOD_IS_MODIFIED);
-	return true;
-}
-
 bool loadSample(UNICHAR *fileName, char *entryName)
 {
 	if (editor.sampleZero)
@@ -1568,39 +65,33 @@
 		return false;
 	}
 
+	uint32_t filesize;
 	fseek(f, 0, SEEK_END);
-	uint32_t fileSize = ftell(f);
-	fseek(f, 0, SEEK_SET);
+	filesize = (uint32_t)ftell(f);
+	rewind(f);
 
+	// defaults to RAW if no format was identified
+	uint8_t sampleType = SAMPLETYPE_RAW;
+
 	// first, check heades before we eventually load as RAW
-	if (fileSize > 16)
+	if (filesize > 16)
 	{
 		uint32_t ID;
 		fread(&ID, 4, 1, f);
 
-		/* Reject FLAC files, since they are not supported.
-		** This is a dumb test since any sample *could* start
-		** with "fLaC", but in 99.999% of cases it won't happen.
-		*/
-		if (ID == 0x43614C66) // "fLaC"
+		if (ID == 0x43614C66) // "fLaC" (XXX: weak detection)
 		{
-			displayErrorMsg("NOT SUPPORTED !");
-			return false;
+			sampleType = SAMPLETYPE_FLAC;
 		}
-
-		// check if it's actually a WAV sample
-		if (ID == 0x46464952) // "RIFF"
+		else if (ID == 0x46464952) // "RIFF" (WAV)
 		{
 			fseek(f, 4, SEEK_CUR);
 			fread(&ID, 4, 1, f);
 
 			if (ID == 0x45564157) // "WAVE"
-			{
-				fclose(f);
-				return loadWAVSample(fileName, entryName);
-			}
+				sampleType = SAMPLETYPE_WAV;
 		}
-		else if (ID == 0x4D524F46) // "FORM"
+		else if (ID == 0x4D524F46) // "FORM" (IFF/AIFF)
 		{
 			fseek(f, 4, SEEK_CUR);
 			fread(&ID, 4, 1, f);
@@ -1608,15 +99,13 @@
 			// check if it's an Amiga IFF sample
 			if (ID == 0x58565338 || ID == 0x56533631) // "8SVX" (normal) and "16SV" (FT2 sample)
 			{
-				fclose(f);
-				return loadIFFSample(fileName, entryName);
+				sampleType = SAMPLETYPE_IFF;
 			}
 
 			// check if it's an AIFF sample
 			else if (ID == 0x46464941) // "AIFF"
 			{
-				fclose(f);
-				return loadAIFFSample(fileName, entryName);
+				sampleType = SAMPLETYPE_AIFF;
 			}
 
 			else if (ID == 0x43464941) // "AIFC" (compressed AIFF)
@@ -1628,8 +117,76 @@
 		}
 	}
 
-	// nope, continue loading as RAW
+	moduleSample_t *s = &song->samples[editor.currSample];
+
+	// we're not ready to load the sample (error message is shown in the loaders)
+
+	rewind(f);
+
+	bool result = false;
+	switch (sampleType)
+	{
+		case SAMPLETYPE_RAW:
+			result = loadRAWSample(f, filesize, s);
+		break;
+
+		case SAMPLETYPE_IFF:
+			setSampleTextFromFilename(s, entryName, ".iff");
+			result = loadIFFSample(f, filesize, s); 
+		break;
+
+		case SAMPLETYPE_AIFF:
+			setSampleTextFromFilename(s, entryName, ".aiff");
+			result = loadAIFFSample(f, filesize, s);
+		break;
+
+		case SAMPLETYPE_WAV:
+			setSampleTextFromFilename(s, entryName, ".wav");
+			result = loadWAVSample(f, filesize, s);
+		break;
+
+		case SAMPLETYPE_FLAC:
+			setSampleTextFromFilename(s, entryName, ".flac");
+			result = loadFLACSample(f, filesize, s);
+		break;
+
+		default: break;
+	}
+
 	fclose(f);
 
-	return loadRAWSample(fileName, entryName);
+	if (result == true)
+	{
+		// sample load was successful
+
+		if (s->length > config.maxSampleLength)
+			s->length = config.maxSampleLength;
+
+		if (s->loopStart+s->loopLength > s->length)
+		{
+			s->loopStart = 0;
+			s->loopLength = 2;
+		}
+
+		// zero out rest of sample (if not full length)
+		if (s->length < config.maxSampleLength)
+			memset(&song->sampleData[s->offset + s->length], 0, config.maxSampleLength - s->length);
+
+		editor.sampleZero = false;
+		editor.samplePos = 0;
+
+		fixSampleBeep(s);
+		fillSampleRedoBuffer(editor.currSample);
+
+		if (ui.samplingBoxShown)
+		{
+			removeSamplingBox();
+			ui.samplingBoxShown = false;
+		}
+
+		updateCurrSample();
+		updateWindowTitle(MOD_IS_MODIFIED);
+	}
+
+	return result;
 }
--- a/src/pt2_structs.h
+++ b/src/pt2_structs.h
@@ -180,7 +180,11 @@
 	uint16_t effectMacros[10], currPlayNote, vol1, vol2, lpCutOff, hpCutOff;
 	int32_t smpRedoLoopStarts[MOD_SAMPLES], smpRedoLoopLengths[MOD_SAMPLES], smpRedoLengths[MOD_SAMPLES];
 	int32_t oldTempo, modulatePos, modulateOffset, markStartOfs, markEndOfs, samplePos, chordLength;
-	uint64_t musicTime64;
+	uint32_t playbackSeconds;
+	uint64_t playbackSecondsFrac;
+
+	uint32_t framesPassed;
+
 	note_t trackBuffer[MOD_ROWS], cmdsBuffer[MOD_ROWS], blockBuffer[MOD_ROWS];
 	note_t patternBuffer[MOD_ROWS * PAULA_VOICES], undoBuffer[MOD_ROWS * PAULA_VOICES];
 	SDL_Thread *mod2WavThread, *pat2SmpThread;
--- a/src/pt2_tables.c
+++ b/src/pt2_tables.c
@@ -1,5 +1,6 @@
 #include <stdint.h>
 #include "pt2_mouse.h"
+#include "pt2_replayer.h"
 
 const char *ftuneStrTab[16] =
 {
@@ -179,59 +180,75 @@
 };
 
 /*
+** For playback time counter.
+**
 ** Formula:
-** for (int32_t i = 32; i <= 255; i++)
-** {
-**     double dBpmMs1024 = 1024.0 / (i / 2.5); // binary ms (1000->1024)
-**     musicTimeTab64[i-32] = (uint64_t)floor((UINT32_MAX + 1.0) * dBpmMs1024);
-** }
+** for (int32_t i = MIN_BPM; i <= MAX_BPM; i++)
+**     musicTimeTab52[i-MIN_BPM] = (uint64_t)round((1ULL << 52) / ciaBpm2Hz(i));
 **
 ** // vblank mode (~49.92Hz)
-** double dBpmMs1024 = 1024.0 / 49.920409283472; // binary ms (1000->1024)
-** musicTimeTab64[256] =  (uint64_t)floor((UINT32_MAX + 1.0) * dBpmMs1024);
+** musicTimeTab52[(MAX_BPM-MIN_BPM)+1] = (uint64_t)round((1ULL << 52) / AMIGA_PAL_VBLANK_HZ);
 */
-const uint64_t musicTimeTab64[(256-32) + 1] =
+const uint64_t musicTimeTab52[(MAX_BPM-MIN_BPM)+1+1] =
 {
-	0x5000000000,0x4D9364D936,0x4B4B4B4B4B,0x4924924924,0x471C71C71C,0x45306EB3E4,
-	0x435E50D794,0x41A41A41A4,0x4000000000,0x3E7063E706,0x3CF3CF3CF3,0x3B88EE23B8,
-	0x3A2E8BA2E8,0x38E38E38E3,0x37A6F4DE9B,0x3677D46CEF,0x3555555555,0x343EB1A1F5,
-	0x3333333333,0x3232323232,0x313B13B13B,0x304D4873EC,0x2F684BDA12,0x2E8BA2E8BA,
-	0x2DB6DB6DB6,0x2CE98B3A62,0x2C234F72C2,0x2B63CBEEA4,0x2AAAAAAAAA,0x29F79B4758,
-	0x294A5294A5,0x28A28A28A2,0x2800000000,0x2762762762,0x26C9B26C9B,0x26357E16EC,
-	0x25A5A5A5A5,0x2519F89467,0x2492492492,0x240E6C2B44,0x238E38E38E,0x231188C462,
-	0x22983759F2,0x2222222222,0x21AF286BCA,0x213F2B3884,0x20D20D20D2,0x2067B23A54,
-	0x2000000000,0x1F9ADD3C0C,0x1F3831F383,0x1ED7E75346,0x1E79E79E79,0x1E1E1E1E1E,
-	0x1DC47711DC,0x1D6CDFA1D6,0x1D1745D174,0x1CC398730E,0x1C71C71C71,0x1C21C21C21,
-	0x1BD37A6F4D,0x1B86E1B86E,0x1B3BEA3677,0x1AF286BCA1,0x1AAAAAAAAA,0x1A6449E59B,
-	0x1A1F58D0FA,0x19DBCC4867,0x1999999999,0x1958B67EBB,0x1919191919,0x18DAB7EC1D,
-	0x189D89D89D,0x1861861861,0x1826A439F6,0x17ECDC1CB5,0x17B425ED09,0x177C7A20E1,
-	0x1745D1745D,0x171024E6A1,0x16DB6DB6DB,0x16A7A5616A,0x1674C59D31,0x1642C8590B,
-	0x1611A7B961,0x15E15E15E1,0x15B1E5F752,0x15833A1583,0x1555555555,0x152832C6E0,
-	0x14FBCDA3AC,0x14D0214D02,0x14A5294A52,0x147AE147AE,0x1451451451,0x142850A142,
-	0x1400000000,0x13D84F613D,0x13B13B13B1,0x138ABF82EE,0x1364D9364D,0x133F84CFE1,
-	0x131ABF0B76,0x12F684BDA1,0x12D2D2D2D2,0x12AFA64E7B,0x128CFC4A33,0x126AD1F4F3,
-	0x1249249249,0x1227F179A5,0x12073615A2,0x11E6EFE35B,0x11C71C71C7,0x11A7B9611A,
-	0x1188C46231,0x116A3B35FC,0x114C1BACF9,0x112E63A6A8,0x1111111111,0x10F421E843,
-	0x10D79435E5,0x10BB6610BB,0x109F959C42,0x1084210842,0x1069069069,0x104E447BEC,
-	0x1033D91D2A,0x1019C2D14E,0x1000000000,0x0FE68F1B07,0x0FCD6E9E06,0x0FB49D0E22,
-	0x0F9C18F9C1,0x0F83E0F83E,0x0F6BF3A9A3,0x0F544FB66B,0x0F3CF3CF3C,0x0F25DEACAF,
-	0x0F0F0F0F0F,0x0EF883BE20,0x0EE23B88EE,0x0ECC35458C,0x0EB66FD0EB,0x0EA0EA0EA0,
-	0x0E8BA2E8BA,0x0E76994F8C,0x0E61CC3987,0x0E4D3AA30A,0x0E38E38E38,0x0E24C602D4,
-	0x0E10E10E10,0x0DFD33C272,0x0DE9BD37A6,0x0DD67C8A60,0x0DC370DC37,0x0DB0995382,
-	0x0D9DF51B3B,0x0D8B8362E0,0x0D79435E50,0x0D673445B2,0x0D55555555,0x0D43A5CD98,
-	0x0D3224F2CD,0x0D20D20D20,0x0D0FAC687D,0x0CFEB35477,0x0CEDE62433,0x0CDD442E4F,
-	0x0CCCCCCCCC,0x0CBC7F5CF9,0x0CAC5B3F5D,0x0C9C5FD7A5,0x0C8C8C8C8C,0x0C7CE0C7CE,
-	0x0C6D5BF60E,0x0C5DFD86CD,0x0C4EC4EC4E,0x0C3FB19B8F,0x0C30C30C30,0x0C21F8B86A,
-	0x0C13521CFB,0x0C04CEB916,0x0BF66E0E5A,0x0BE82FA0BE,0x0BDA12F684,0x0BCC17982F,
-	0x0BBE3D1070,0x0BB082EC20,0x0BA2E8BA2E,0x0B956E0B95,0x0B88127350,0x0B7AD58650,
-	0x0B6DB6DB6D,0x0B60B60B60,0x0B53D2B0B5,0x0B470C67C0,0x0B3A62CE98,0x0B2DD58507,
-	0x0B21642C85,0x0B150E682C,0x0B08D3DCB0,0x0AFCB43057,0x0AF0AF0AF0,0x0AE4C415C9,
-	0x0AD8F2FBA9,0x0ACD3B68C6,0x0AC19D0AC1,0x0AB617909A,0x0AAAAAAAAA,0x0A9F560A9F,
-	0x0A94196370,0x0A88F46959,0x0A7DE6D1D6,0x0A72F05397,0x0A6810A681,0x0A5D4783A0,
-	0x0A5294A529,0x0A47F7C66C,0x0A3D70A3D7,0x0A32FEFAE6,0x0A28A28A28,0x0A1E5B1133,
-	0x0A142850A1,0x0A0A0A0A0A,
+	0x1400121B82E16,0x1364DD2764D7A,0x12D2E541CEAFF,0x12492642C0D42,
+	0x11C729E981458,0x114C3301B339D,0x10D79BFD857FE,0x10691DE9554BE,
+	0x10001337516C9,0x0F9C1D4D4B7CD,0x0F3CF537A0B0C,0x0EE23C5C22A32,
+	0x0E8BABC72E881,0x0E38E4DE95FA5,0x0DE9CFFBCD60A,0x0D9DF6DE1ABC7,
+	0x0D5559857E0DD,0x0D0FB0FE5488D,0x0CCCCDFB86FAE,0x0C8C98D689CAA,
+	0x0C4ECA9BBA2C4,0x0C13634B181FB,0x0BDA1BF100D90,0x0BA2F48D74585,
+	0x0B6DBDD35B6AE,0x0B3A77C2B610D,0x0B08DB67E17E2,0x0AD90069694C3,
+	0x0AAAB77A36486,0x0A7DE8F3BCD96,0x0A5294D5FCFF3,0x0A28A37A6B208,
+	0x0A0014E1073D5,0x09D8A2162E89D,0x09B27A66F8387,0x098D6E864D16C,
+	0x09697E742D24A,0x0946928A0CC8D,0x09249321606A1,0x0903AF873F3AE,
+	0x08E3A0C8066F7,0x08C466E3B607B,0x08A61980D99CF,0x0888895259FC9,
+	0x086BCDFEC2BFF,0x084FCFDF884DC,0x08348EF4AAA5F,0x0819F3979E2F4,
+	0x0800156EEE82F,0x07E6C52D846E7,0x07CE1A79EB8B1,0x07B5FDAD983F8,
+	0x079E866F16250,0x07879D17D9A26,0x07712A01571E3,0x075B44D21A31E,
+	0x0745D5E397440,0x0730F4DC59EE0,0x071C726F4AFD2,0x07087DE981A42,
+	0x06F4E7FDE6B05,0x06E1C85305BB0,0x06CF0742532AE,0x06BCA4CBCEFFF,
+	0x06AAB89604D39,0x06991353DD731,0x0687E45270111,0x0676FC44A57B0,
+	0x066672D1094A1,0x065630510FE52,0x06464C6B44E55,0x0636AF791CB17,
+	0x0627712122E2C,0x061862164046B,0x0609B1A58C0FD,0x05FB48287AA4E,
+	0x05ED0DF8806C8,0x05DF3262B4996,0x05D18619FFF8D,0x05C420C4EE242,
+	0x05B6EABCF3821,0x05A9FBA89BABF,0x059D3BE15B086,0x0590C30DBD30C,
+	0x05847987368BC,0x05785F4DC7195,0x056C8C07FA72C,0x0560D068B9658,
+	0x05555BBD1B243,0x054A165E94157,0x053F004D24395,0x05341988CB8FD,
+	0x05294A6AFE7F9,0x051EC240D43B4,0x051451BD35904,0x050A282D39B12,
+	0x05001643C96B5,0x04F61C00E4BED,0x04EC510B1744E,0x04E2B56260FD9,
+	0x04D94906C1E8E,0x04CFF451AE6D8,0x04C6B743268B6,0x04BDA981B5DBE,
+	0x04B4CB0D5C5EF,0x04ABEC9902E21,0x04A355184C311,0x049ABD9795801,
+	0x04925563F601B,0x048A04D6E21C9,0x0481E396E56A1,0x0479C256E8B7A,
+	0x0471D0640337B,0x0469F617A9512,0x04623371DB03D,0x045AA01923E92,
+	0x04530CC06CCE7,0x044BA8B4CCE66,0x044444A92CFE5,0x043D0FEAA448D,
+	0x0435F2D2A72CA,0x042EED6135A9C,0x0427E7EFC426E,0x042111CB69D69,
+	0x041A534D9B1FA,0x041394CFCC68A,0x040D059F14E44,0x0406766E5D5FE,
+	0x0400168ABD0E2,0x03F9B6A71CBC5,0x03F36E6A0803E,0x03ED3DD37EE4B,
+	0x03E70D3CF5C59,0x03E10BF383D8F,0x03DB0AAA11EC6,0x03D521072B992,
+	0x03CF4F0AD0DF3,0x03C97D0E76253,0x03C3DA5F329DD,0x03BE37AFEF167,
+	0x03B89500AB8F2,0x03B3219E7F3A5,0x03ADAE3C52E59,0x03A83ADA2690D,
+	0x03A2F6C5116EB,0x039DB2AFFC4C8,0x0398864172C3A,0x039359D2E93AD,
+	0x038E450AEB4B4,0x038947E978F4F,0x03844AC8069EB,0x037F4DA694487,
+	0x037A7FD23924D,0x0375B1FDDE012,0x0370E42982DD8,0x036C2DFBB3532,
+	0x03678F746F621,0x0362F0ED2B711,0x035E5265E7800,0x0359E32BBAC18,
+	0x03555C4B0269C,0x0350ED10D5AB5,0x034C957D34863,0x03483DE993610,
+	0x0343FDFC7DD53,0x033FBE0F68495,0x033B7E2252BD8,0x033755DBC8CAF,
+	0x0333453BCA71B,0x032F349BCC187,0x032B23FBCDBF3,0x03272B025AFF4,
+	0x03233208E83F5,0x031F390F757F6,0x031B57BC8E58C,0x03178E1032CB6,
+	0x0313C463D73E1,0x030FFAB77BB0B,0x030C310B20236,0x03087F05502F5,
+	0x0304E4A60BD49,0x03014A46C779D,0x02FDAFE7831F1,0x02FA15883EC45,
+	0x02F692CF8602E,0x02F31016CD417,0x02EFA504A0195,0x02EC224BE757E,
+	0x02E8CEE045C91,0x02E563CE18A0F,0x02E2106277121,0x02DEBCF6D5834,
+	0x02DB8131BF8DB,0x02D82DC61DFEE,0x02D509A793A2A,0x02D1CDE27DAD1,
+	0x02CEA9C3F350E,0x02CB85A568F4A,0x02C86186DE986,0x02C5550EDFD57,
+	0x02C24896E1128,0x02BF3C1EE24F9,0x02BC2FA6E38CA,0x02B93AD570630,
+	0x02B64603FD396,0x02B351328A0FC,0x02B07407A27F7,0x02AD96DCBAEF1,
+	0x02AAB9B1D35EC,0x02A7DC86EBCE7,0x02A517028FD76,0x02A2517E33E06,
+	0x029F8BF9D7E95,0x029CC6757BF25,0x029A1897AB949,0x029753134F9D8,
+	0x0294A5357F3FD,0x02920EFE3A7B6,0x028F61206A1DA,0x028CCAE925593,
+	0x028A34B1E094C,0x02879E7A9BD06,0x02851FE9E2A53,0x028289B29DE0D,
 
-	0x14833D2EF0 // ~49.92Hz (vblank tempo mode)
+	0x0520CF4BBC202 // ~49.92Hz (vblank tempo mode)
 };
 
 // button tables taken from the ptplay project + modified
--- a/src/pt2_tables.h
+++ b/src/pt2_tables.h
@@ -3,8 +3,10 @@
 #include <stdint.h>
 #include "pt2_palette.h"
 #include "pt2_mouse.h"
+#include "pt2_replayer.h"
 
 // TABLES
+
 extern const char *ftuneStrTab[16];
 extern const int8_t vuMeterHeights[65];
 extern const char hexTable[16];
@@ -16,7 +18,7 @@
 extern const uint8_t vibratoTable[32];
 extern const int16_t periodTable[(37*16)+15];
 extern int8_t pNoteTable[32];
-extern const uint64_t musicTimeTab64[(256-32)+1];
+extern const uint64_t musicTimeTab52[(MAX_BPM-MIN_BPM)+1+1];
 
 // changable by config file
 extern uint16_t analyzerColors[36];
--- a/src/pt2_visuals.c
+++ b/src/pt2_visuals.c
@@ -33,6 +33,7 @@
 #include "pt2_sampling.h"
 #include "pt2_chordmaker.h"
 #include "pt2_mod2wav.h"
+#include "pt2_audio.h"
 
 typedef struct sprite_t
 {
@@ -543,9 +544,7 @@
 
 	// playback timer
 
-	const uint32_t ms1024 = editor.musicTime64 >> 32; // milliseconds (scaled from 1000 to 1024)
-
-	uint32_t seconds = ms1024 >> 10;
+	uint32_t seconds = editor.playbackSeconds;
 	if (seconds <= 5999) // below 100 minutes (99:59 is max for the UI)
 	{
 		const uint32_t MI_TimeM = seconds / 60;
@@ -1721,6 +1720,15 @@
 			hpc_Wait(&video.vblankHpc);
 #endif
 	}
+
+	editor.framesPassed++;
+
+	/* Reset audio/video sync timestamp every half an hour to prevent
+	** possible sync drifting after hours of playing a song without
+	** a single song stop (resets timestamp) in-between.
+	*/
+	if (editor.framesPassed >= VBLANK_HZ*60*30)
+		audio.resetSyncTickTimeFlag = true;
 }
 
 void updateSpectrumAnalyzer(int8_t vol, int16_t period)
--- a/src/pt2_visuals_sync.c
+++ b/src/pt2_visuals_sync.c
@@ -17,9 +17,11 @@
 } syncVoice_t;
 
 static volatile bool chQueueClearing;
-static uint32_t audLatencyPerfValInt, audLatencyPerfValFrac;
+static uint32_t audLatencyPerfValInt;
+static uint64_t audLatencyPerfValFrac;
 static uint64_t tickTime64, tickTime64Frac;
-static uint32_t tickTimeLen, tickTimeLenFrac;
+static uint32_t tickTimeLenInt;
+static uint64_t tickTimeLenFrac;
 static syncVoice_t syncVoice[PAULA_VOICES];
 static chSyncData_t *chSyncEntry;
 static chSync_t chSync;
@@ -139,7 +141,7 @@
 
 void calcAudioLatencyVars(int32_t audioBufferSize, int32_t audioFreq)
 {
-	double dInt, dFrac;
+	double dInt;
 
 	if (audioFreq == 0)
 		return;
@@ -146,18 +148,15 @@
 
 	const double dAudioLatencySecs = audioBufferSize / (double)audioFreq;
 
-	dFrac = modf(dAudioLatencySecs * (double)hpcFreq.freq64, &dInt);
+	double dFrac = modf(dAudioLatencySecs * (double)hpcFreq.freq64, &dInt);
 
-	// integer part
 	audLatencyPerfValInt = (uint32_t)dInt;
-
-	// fractional part (scaled to 0..2^32-1)
-	audLatencyPerfValFrac = (uint32_t)((dFrac * (UINT32_MAX+1.0)) + 0.5); // rounded
+	audLatencyPerfValFrac = (uint64_t)((dFrac * TICK_TIME_FRAC_SCALE) + 0.5); // rounded
 }
 
-void setSyncTickTimeLen(uint32_t timeLen, uint32_t timeLenFrac)
+void setSyncTickTimeLen(uint32_t timeLenInt, uint64_t timeLenFrac)
 {
-	tickTimeLen = timeLen;
+	tickTimeLenInt = timeLenInt;
 	tickTimeLenFrac = timeLenFrac;
 }
 
@@ -294,11 +293,12 @@
 		chQueuePush(chSyncData);
 	}
 
-	tickTime64 += tickTimeLen;
+	tickTime64 += tickTimeLenInt;
+
 	tickTime64Frac += tickTimeLenFrac;
-	if (tickTime64Frac > UINT32_MAX)
+	if (tickTime64Frac >= TICK_TIME_FRAC_SCALE)
 	{
-		tickTime64Frac &= UINT32_MAX;
+		tickTime64Frac &= TICK_TIME_FRAC_MASK;
 		tickTime64++;
 	}
 }
--- a/src/pt2_visuals_sync.h
+++ b/src/pt2_visuals_sync.h
@@ -53,7 +53,7 @@
 } chSync_t;
 
 void calcAudioLatencyVars(int32_t audioBufferSize, int32_t audioFreq);
-void setSyncTickTimeLen(uint32_t timeLen, uint32_t timeLenFrac);
+void setSyncTickTimeLen(uint32_t timeLenInt, uint64_t timeLenFrac);
 void fillVisualsSyncBuffer(void);
 void resetChSyncQueue(void);
 void updateChannelSyncBuffer(void);
--- a/src/pt2_xpk.c
+++ /dev/null
@@ -1,428 +1,0 @@
-/* Taken from the OpenMPT project and converted to C.
-** OpenMPT shares the same license as the PT2 clone (BSD 3-clause),
-** so the licensing is compatible.
-**
-** This is probably not 100% safe code, but it works.
-*/
-
-#include <assert.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "pt2_helpers.h"
-
-typedef struct XPKFILEHEADER
-{
-	char XPKF[4];
-	uint32_t SrcLen;
-	char SQSH[4];
-	uint32_t DstLen;
-	char Name[16];
-	uint32_t Reserved;
-} XPKFILEHEADER;
-
-typedef struct XPK_BufferBounds
-{
-	const uint8_t *pSrcBeg;
-	size_t SrcSize;
-} XPK_BufferBounds;
-
-static const uint8_t xpk_table[56] =
-{
-	2,3,4,5,6,7,8,0,3,2,4,5,6,7,8,0,4,3,5,
-	2,6,7,8,0,5,4,6,2,3,7,8,0,6,5,7,2,3,4,
-	8,0,7,6,8,2,3,4,5,0,8,7,6,2,3,4,5,0
-};
-
-static inline uint8_t SrcRead(size_t index, XPK_BufferBounds *bufs)
-{
-	assert(index < bufs->SrcSize);
-	if (index >= bufs->SrcSize)
-		return 0; // this is actually not how to do it, ugh...
-
-	return bufs->pSrcBeg[index];
-}
-
-static inline int32_t bfextu(size_t p, int32_t bo, int32_t bc, XPK_BufferBounds *bufs)
-{
-	p += (uint32_t)bo >> 3;
-
-	uint32_t r = SrcRead(p, bufs); p++;
-	r <<= 8;
-	r |= SrcRead(p, bufs); p++;
-	r <<= 8;
-	r |= SrcRead(p, bufs);
-	r <<= bo & 7;
-	r &= 0x00FFFFFF;
-	r >>= 24 - bc;
-
-	return r;
-}
-
-static inline int32_t bfexts(size_t p, int32_t bo, int32_t bc, XPK_BufferBounds *bufs)
-{
-	p += (uint32_t)bo >> 3;
-
-	uint32_t r = SrcRead(p, bufs); p++;
-	r <<= 8;
-	r |= SrcRead(p, bufs); p++;
-	r <<= 8;
-	r |= SrcRead(p, bufs);
-	r <<= (bo & 7) + 8;
-	r = (int32_t)r >> (32-bc);
-
-	return r;
-}
-
-static inline uint8_t XPK_ReadTable(int32_t index)
-{
-	if (index < 0 || index >= (int32_t)sizeof (xpk_table))
-		return 0; // this is actually not how to do it, ugh...
-
-	return xpk_table[index];
-}
-
-static bool XPK_DoUnpack(const uint8_t *src_, uint32_t srcLen, int32_t len, uint8_t **out)
-{
-	*out = NULL;
-	if (len <= 0)
-		return false;
-
-	int32_t d0, d1, d2, d3, d4, d5, d6, a2, a5, cup1;
-	size_t phist = 0;
-
-	const uint32_t unpackedLen = MIN((uint32_t)len, MIN(srcLen, UINT32_MAX / 20) * 20);
-
-	uint8_t *unpackedData = (uint8_t *)malloc(unpackedLen);
-	if (unpackedData == NULL)
-		return false;
-
-	uint8_t *PtrEnd = unpackedData + unpackedLen;
-	uint8_t *PtrOut = unpackedData;
-
-	XPK_BufferBounds bufs;
-	bufs.pSrcBeg = src_;
-	bufs.SrcSize = srcLen;
-
-	size_t src = 0;
-	size_t c = src;
-	while (len > 0)
-	{
-		int32_t type = SrcRead(c+0, &bufs);
-		int32_t cp = (SrcRead(c+4, &bufs)<<8) | (SrcRead(c+5, &bufs)); // packed
-		cup1 = (SrcRead(c+6, &bufs)<<8) | (SrcRead(c+7, &bufs)); // unpacked
-
-		c += 8;
-		src = c+2;
-		if (type == 0)
-		{
-			// RAW chunk
-			if (cp < 0 || cp > len)
-			{
-				free(unpackedData);
-				return false;
-			}
-
-			for (int32_t i = 0; i < cp; i++)
-				*PtrOut++ = SrcRead(c + i, &bufs);
-
-			c += cp;
-			len -= cp;
-			continue;
-		}
-
-		if (type != 1)
-			break;
-
-		if (cup1 > len)
-			cup1 = len;
-
-		len -= cup1;
-		cp = (cp + 3) & 0xFFFC;
-		c += cp;
-
-		d0 = d1 = d2 = a2 = 0;
-		d3 = SrcRead(src, &bufs); src++;
-		*PtrOut++ = (uint8_t)d3;
-		cup1--;
-
-		while (cup1 > 0)
-		{
-			if (d1 >= 8) goto l6dc;
-			if (bfextu(src,d0,1,&bufs)) goto l75a;
-			d0 += 1;
-			d5 = 0;
-			d6 = 8;
-			goto l734;
-
-l6dc:
-			if (bfextu(src,d0,1,&bufs)) goto l726;
-			d0 += 1;
-			if (!bfextu(src,d0,1,&bufs)) goto l75a;
-			d0 += 1;
-			if (bfextu(src,d0,1,&bufs)) goto l6f6;
-			d6 = 2;
-			goto l708;
-
-l6f6:
-			d0 += 1;
-			if (!bfextu(src,d0,1,&bufs)) goto l706;
-			d6 = bfextu(src,d0,3,&bufs);
-			d0 += 3;
-			goto l70a;
-
-l706:
-			d6 = 3;
-l708:
-			d0 += 1;
-l70a:
-			d6 = XPK_ReadTable((a2*8) + d6 - 17);
-			if (d6 != 8) goto l730;
-l718:
-			if (d2 >= 20)
-			{
-				d5 = 1;
-				goto l732;
-			}
-			d5 = 0;
-			goto l734;
-
-l726:
-			d0 += 1;
-			d6 = 8;
-			if (d6 == a2) goto l718;
-			d6 = a2;
-l730:
-			d5 = 4;
-l732:
-			d2 += 8;
-l734:
-			while (d5 >= 0 && cup1 > 0)
-			{
-				d4 = bfexts(src,d0,d6,&bufs);
-				d0 += d6;
-				d3 -= d4;
-				*PtrOut++ = (uint8_t)d3;
-				cup1--;
-				d5--;
-			}
-
-			if (d1 != 31)
-				d1++;
-
-			a2 = d6;
-l74c:
-			d6 = d2;
-			d6 >>= 3;
-			d2 -= d6;
-		}
-	}
-
-	if (PtrOut > PtrEnd)
-	{
-		free(unpackedData);
-		return false;
-	}
-
-	*out = unpackedData;
-	return true;
-
-l75a:
-	d0 += 1;
-	if (bfextu(src,d0,1,&bufs)) goto l766;
-	d4 = 2;
-	goto l79e;
-
-l766:
-	d0 += 1;
-	if (bfextu(src,d0,1,&bufs)) goto l772;
-	d4 = 4;
-	goto l79e;
-
-l772:
-	d0 += 1;
-	if (bfextu(src,d0,1,&bufs)) goto l77e;
-	d4 = 6;
-	goto l79e;
-
-l77e:
-	d0 += 1;
-	if (bfextu(src,d0,1,&bufs)) goto l792;
-	d0 += 1;
-	d6 = bfextu(src,d0,3,&bufs);
-	d0 += 3;
-	d6 += 8;
-	goto l7a8;
-
-l792:
-	d0 += 1;
-	d6 = bfextu(src,d0,5,&bufs);
-	d0 += 5;
-	d4 = 16;
-	goto l7a6;
-
-l79e:
-	d0 += 1;
-	d6 = bfextu(src,d0,1,&bufs);
-	d0 += 1;
-l7a6:
-	d6 += d4;
-l7a8:
-	if (bfextu(src, d0, 1, &bufs))
-	{
-		d5 = 12;
-		a5 = -0x100;
-	}
-	else
-	{
-		d0 += 1;
-		if (bfextu(src, d0, 1, &bufs))
-		{
-			d5 = 14;
-			a5 = -0x1100;
-		}
-		else
-		{
-			d5 = 8;
-			a5 = 0;
-		}
-	}
-
-	d0 += 1;
-	d4 = bfextu(src,d0,d5,&bufs);
-	d0 += d5;
-	d6 -= 3;
-	if (d6 >= 0)
-	{
-		if (d6 > 0)
-			d1 -= 1;
-
-		d1 -= 1;
-		if (d1 < 0)
-			d1 = 0;
-	}
-	d6 += 2;
-
-	phist = (size_t)(PtrOut-unpackedData) + a5 - d4 - 1;
-	if (phist >= (size_t)(PtrOut-unpackedData))
-	{
-		free(unpackedData);
-		return false;
-	}
-
-	while (d6 >= 0 && cup1 > 0)
-	{
-		d3 = unpackedData[phist];
-		phist++;
-		*PtrOut++ = (uint8_t)d3;
-		cup1--;
-		d6--;
-	}
-
-	goto l74c;
-}
-
-static bool ValidateHeader(XPKFILEHEADER *header)
-{
-	if (memcmp(header->XPKF, "XPKF", 4) != 0)
-		return false;
-
-	if (memcmp(header->SQSH, "SQSH", 4) != 0)
-		return false;
-
-	if (header->SrcLen == 0 || header->DstLen == 0)
-		return false;
-
-	if (header->SrcLen < sizeof (XPKFILEHEADER)-8)
-		return false;
-
-	return true;
-}
-
-bool ReadHeader(FILE *f, XPKFILEHEADER *header)
-{
-	if (f == NULL || fread(header, sizeof (XPKFILEHEADER), 1, f) != 1)
-		return false;
-
-	header->SrcLen = SWAP32(header->SrcLen);
-	header->DstLen = SWAP32(header->DstLen);
-	
-	return true;
-}
-
-bool DetectXPK(FILE *f)
-{
-	XPKFILEHEADER header;
-
-	uint32_t OldPos = ftell(f);
-	rewind(f);
-	bool result = ReadHeader(f, &header);
-	fseek(f, OldPos, SEEK_SET);
-
-	if (result == false)
-		return false;
-
-	return ValidateHeader(&header);
-}
-
-bool UnpackXPK(FILE *f, uint32_t *filesize, uint8_t **out)
-{
-	XPKFILEHEADER header;
-
-	*filesize = 0;
-	*out = NULL;
-
-	if (f == NULL)
-		return false;
-
-	uint32_t oldPos = ftell(f);
-
-	rewind(f);
-
-	if (!ReadHeader(f, &header))
-	{
-		fseek(f, oldPos, SEEK_SET);
-		return false;
-	}
-
-	if (!ValidateHeader(&header))
-	{
-		fseek(f, oldPos, SEEK_SET);
-		return false;
-	}
-
-	fseek(f, 0, SEEK_END);
-	uint32_t inputfilesize = ftell(f) - sizeof (XPKFILEHEADER);
-	fseek(f, sizeof (XPKFILEHEADER), SEEK_SET);
-
-	uint8_t *packedData = (uint8_t *)malloc(inputfilesize);
-	if (packedData == NULL)
-	{
-		fseek(f, oldPos, SEEK_SET);
-		return false;
-	}
-
-	if (fread(packedData, 1, inputfilesize, f) != inputfilesize)
-	{
-		free(packedData);
-		fseek(f, oldPos, SEEK_SET);
-		return false;
-	}
-
-	uint8_t *unpackedData = NULL;
-	bool result = XPK_DoUnpack(packedData, header.SrcLen - (sizeof (XPKFILEHEADER) - 8), header.DstLen, &unpackedData);
-	free(packedData);
-
-	if (result == true)
-	{
-		*filesize = header.DstLen;
-		*out = unpackedData;
-		return true;
-	}
-	else
-	{
-		return false;
-	}
-}
--- a/src/pt2_xpk.h
+++ /dev/null
@@ -1,7 +1,0 @@
-#pragma once
-
-#include <stdint.h>
-#include <stdbool.h>
-
-bool DetectXPK(FILE *f);
-bool UnpackXPK(FILE *f, uint32_t *filesize, uint8_t **out);
--- /dev/null
+++ b/src/smploaders/pt2_load_aiff.c
@@ -1,0 +1,426 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <math.h>
+#include "../pt2_header.h"
+#include "../pt2_config.h"
+#include "../pt2_structs.h"
+#include "../pt2_textout.h"
+#include "../pt2_visuals.h"
+#include "../pt2_helpers.h"
+#include "../pt2_replayer.h"
+#include "../pt2_askbox.h"
+#include "../pt2_downsample2x.h"
+#include "../pt2_audio.h"
+
+static uint32_t getAIFFSampleRate(uint8_t *in)
+{
+	/* 80-bit IEEE-754 to unsigned 32-bit integer (rounded).
+	** Sign bit is ignored.
+	*/
+
+#define EXP_BIAS 16383
+
+	const uint16_t exp15 = ((in[0] & 0x7F) << 8) | in[1];
+	const uint64_t mantissaBits = *(uint64_t *)&in[2];
+	const uint64_t mantissa63 = SWAP64(mantissaBits) & INT64_MAX;
+
+	double dExp = exp15 - EXP_BIAS;
+	double dMantissa = mantissa63 / (INT64_MAX+1.0);
+
+	double dResult = (1.0 + dMantissa) * exp2(dExp);
+	return (uint32_t)round(dResult);
+}
+
+bool loadAIFFSample(FILE *f, int32_t filesize, moduleSample_t *s)
+{
+	uint8_t sampleRateBytes[10];
+	uint16_t bitDepth, numChannels;
+	uint32_t offset, sampleRate;
+
+	// zero out chunk pointers and lengths
+	uint32_t commPtr = 0; uint32_t commLen = 0;
+	uint32_t ssndPtr = 0; uint32_t ssndLen = 0;
+
+	bool unsigned8bit = false;
+
+	fseek(f, 12, SEEK_SET);
+	while (!feof(f) && ftell(f) < filesize-12)
+	{
+		uint32_t blockName, blockSize;
+
+		fread(&blockName, 4, 1, f); if (feof(f)) break;
+		fread(&blockSize, 4, 1, f); if (feof(f)) break;
+
+		blockName = SWAP32(blockName);
+		blockSize = SWAP32(blockSize);
+
+		switch (blockName)
+		{
+			case 0x434F4D4D: // "COMM"
+			{
+				commPtr = ftell(f);
+				commLen = blockSize;
+			}
+			break;
+
+			case 0x53534E44: // "SSND"
+			{
+				ssndPtr = ftell(f);
+				ssndLen = blockSize;
+			}
+			break;
+
+			default: break;
+		}
+
+		fseek(f, blockSize + (blockSize & 1), SEEK_CUR);
+	}
+
+	if (commPtr == 0 || commLen < 18 || ssndPtr == 0)
+	{
+		displayErrorMsg("NOT A VALID AIFF!");
+		return false;
+	}
+
+	// kludge for some really strange AIFFs
+	if (ssndLen == 0)
+		ssndLen = filesize - ssndPtr;
+
+	if (ssndPtr+ssndLen > (uint32_t)filesize)
+		ssndLen = filesize - ssndPtr;
+
+	fseek(f, commPtr, SEEK_SET);
+	fread(&numChannels, 2, 1, f); numChannels = SWAP16(numChannels);
+	fseek(f, 4, SEEK_CUR);
+	fread(&bitDepth, 2, 1, f); bitDepth = SWAP16(bitDepth);
+	fread(sampleRateBytes, 1, 10, f);
+
+	fseek(f, 4 + 2 + 1, SEEK_CUR);
+
+	if (numChannels != 1 && numChannels != 2) // sample type
+	{
+		displayErrorMsg("UNSUPPORTED AIFF!");
+		return false;
+	}
+
+	if (bitDepth != 8 && bitDepth != 16 && bitDepth != 24 && bitDepth != 32)
+	{
+		displayErrorMsg("UNSUPPORTED AIFF!");
+		return false;
+	}
+
+	// read compression type (if present)
+	if (commLen > 18)
+	{
+		char compType[4];
+		fread(&compType, 1, 4, f);
+		if (memcmp(compType, "NONE", 4))
+		{
+			displayErrorMsg("UNSUPPORTED AIFF!");
+			return false;
+		}
+	}
+
+	sampleRate = getAIFFSampleRate(sampleRateBytes);
+
+	// sample data chunk
+
+	fseek(f, ssndPtr, SEEK_SET);
+
+	fread(&offset, 4, 1, f);
+	if (offset > 0)
+	{
+		displayErrorMsg("UNSUPPORTED AIFF!");
+		return false;
+	}
+
+	fseek(f, 4, SEEK_CUR);
+
+	ssndLen -= 8; // don't include offset and blockSize datas
+
+	int32_t sampleLength = ssndLen;
+	if (sampleLength == 0)
+	{
+		displayErrorMsg("NOT A VALID AIFF!");
+		return false;
+	}
+
+	bool downSample = false;
+	if (sampleRate > 22050 && !config.noDownsampleOnSmpLoad)
+	{
+		if (askBox(ASKBOX_DOWNSAMPLE, "DOWNSAMPLE ?"))
+			downSample = true;
+	}
+
+	int8_t *smpDataPtr = &song->sampleData[s->offset];
+
+	if (bitDepth == 8) // 8-BIT INTEGER SAMPLE
+	{
+		if (sampleLength > config.maxSampleLength*4)
+			sampleLength = config.maxSampleLength*4;
+
+		int8_t *audioDataS8 = (int8_t *)malloc(sampleLength * sizeof (int8_t));
+		if (audioDataS8 == NULL)
+		{
+			statusOutOfMemory();
+			return false;
+		}
+
+		// read sample data
+		if (fread(audioDataS8, 1, sampleLength, f) != (size_t)sampleLength)
+		{
+			free(audioDataS8);
+			displayErrorMsg("I/O ERROR !");
+			return false;
+		}
+
+		if (unsigned8bit)
+		{
+			for (int32_t i = 0; i < sampleLength; i++)
+				audioDataS8[i] ^= 0x80;
+		}
+
+		// convert from stereo to mono (if needed)
+		if (numChannels == 2)
+		{
+			sampleLength >>= 1;
+			for (int32_t i = 0; i < sampleLength-1; i++) // add right channel to left channel
+				audioDataS8[i] = (audioDataS8[(i * 2) + 0] + audioDataS8[(i * 2) + 1]) >> 1;;
+		}
+
+		// 2x downsampling
+		if (downSample)
+		{
+			downsample2x8Bit(audioDataS8, sampleLength);
+			sampleLength >>= 1;
+		}
+
+		if (sampleLength > config.maxSampleLength)
+			sampleLength = config.maxSampleLength;
+
+		turnOffVoices();
+		for (int32_t i = 0; i < sampleLength; i++)
+			smpDataPtr[i] = audioDataS8[i];
+
+		free(audioDataS8);
+	}
+	else if (bitDepth == 16) // 16-BIT INTEGER SAMPLE
+	{
+		sampleLength >>= 1;
+		if (sampleLength > config.maxSampleLength*4)
+			sampleLength = config.maxSampleLength*4;
+
+		int16_t *audioDataS16 = (int16_t *)malloc(sampleLength * sizeof (int16_t));
+		if (audioDataS16 == NULL)
+		{
+			statusOutOfMemory();
+			return false;
+		}
+
+		// read sample data
+		if (fread(audioDataS16, 2, sampleLength, f) != (size_t)sampleLength)
+		{
+			free(audioDataS16);
+			displayErrorMsg("I/O ERROR !");
+			return false;
+		}
+
+		// fix endianness
+		for (int32_t i = 0; i < sampleLength; i++)
+			audioDataS16[i] = SWAP16(audioDataS16[i]);
+
+		// convert from stereo to mono (if needed)
+		if (numChannels == 2)
+		{
+			sampleLength >>= 1;
+			for (int32_t i = 0; i < sampleLength-1; i++) // add right channel to left channel
+				audioDataS16[i] = (audioDataS16[(i << 1) + 0] + audioDataS16[(i << 1) + 1]) >> 1;
+		}
+
+		// 2x downsampling
+		if (downSample)
+		{
+			downsample2x16Bit(audioDataS16, sampleLength);
+			sampleLength >>= 1;
+		}
+
+		if (sampleLength > config.maxSampleLength)
+			sampleLength = config.maxSampleLength;
+
+		double dAmp = 1.0;
+		if (downSample) // we already normalized
+		{
+			dAmp = INT8_MAX / (double)INT16_MAX;
+		}
+		else
+		{
+			const double dPeak = get16BitPeak(audioDataS16, sampleLength);
+			if (dPeak > 0.0)
+				dAmp = INT8_MAX / dPeak;
+		}
+
+		turnOffVoices();
+		for (int32_t i = 0; i < sampleLength; i++)
+		{
+			int32_t smp32 = (int32_t)round(audioDataS16[i] * dAmp);
+			assert(smp32 >= -128 && smp32 <= 127); // shouldn't happen according to dAmp (but just in case)
+			smpDataPtr[i] = (int8_t)smp32;
+		}
+
+		free(audioDataS16);
+	}
+	else if (bitDepth == 24) // 24-BIT INTEGER SAMPLE
+	{
+		sampleLength /= 3;
+		if (sampleLength > config.maxSampleLength*4)
+			sampleLength = config.maxSampleLength*4;
+
+		int32_t *audioDataS32 = (int32_t *)malloc(sampleLength * sizeof (int32_t));
+		if (audioDataS32 == NULL)
+		{
+			statusOutOfMemory();
+			return false;
+		}
+
+		// read sample data
+		if (fread(&audioDataS32[sampleLength >> 2], 3, sampleLength, f) != (size_t)sampleLength)
+		{
+			free(audioDataS32);
+			displayErrorMsg("I/O ERROR !");
+			return false;
+		}
+
+		// convert to 32-bit
+		uint8_t *audioDataU8 = (uint8_t *)audioDataS32 + sampleLength;
+		for (int32_t i = 0; i < sampleLength; i++)
+		{
+			audioDataS32[i] = (audioDataU8[0] << 24) | (audioDataU8[1] << 16) | (audioDataU8[2] << 8);
+			audioDataU8 += 3;
+		}
+
+		// convert from stereo to mono (if needed)
+		if (numChannels == 2)
+		{
+			sampleLength >>= 1;
+			for (int32_t i = 0; i < sampleLength-1; i++) // add right channel to left channel
+			{
+				int64_t smp = ((int64_t)audioDataS32[(i << 1) + 0] + audioDataS32[(i << 1) + 1]) >> 1;
+				audioDataS32[i] = (int32_t)smp;
+			}
+		}
+
+		// 2x downsampling
+		if (downSample)
+		{
+			downsample2x32Bit(audioDataS32, sampleLength);
+			sampleLength >>= 1;
+		}
+
+		if (sampleLength > config.maxSampleLength)
+			sampleLength = config.maxSampleLength;
+
+		double dAmp = 1.0;
+		if (downSample) // we already normalized
+		{
+			dAmp = INT8_MAX / (double)INT32_MAX;
+		}
+		else
+		{
+			const double dPeak = get32BitPeak(audioDataS32, sampleLength);
+			if (dPeak > 0.0)
+				dAmp = INT8_MAX / dPeak;
+		}
+
+		turnOffVoices();
+		for (int32_t i = 0; i < sampleLength; i++)
+		{
+			int32_t smp32 = (int32_t)round(audioDataS32[i] * dAmp);
+			smpDataPtr[i] = (int8_t)smp32;
+		}
+
+		free(audioDataS32);
+	}
+	else if (bitDepth == 32) // 32-BIT INTEGER SAMPLE
+	{
+		sampleLength >>= 2;
+		if (sampleLength > config.maxSampleLength*4)
+			sampleLength = config.maxSampleLength*4;
+
+		int32_t *audioDataS32 = (int32_t *)malloc(sampleLength * sizeof (int32_t));
+		if (audioDataS32 == NULL)
+		{
+			statusOutOfMemory();
+			return false;
+		}
+
+		// read sample data
+		if (fread(audioDataS32, 4, sampleLength, f) != (size_t)sampleLength)
+		{
+			free(audioDataS32);
+			displayErrorMsg("I/O ERROR !");
+			return false;
+		}
+
+		// fix endianness
+		for (int32_t i = 0; i < sampleLength; i++)
+			audioDataS32[i] = SWAP32(audioDataS32[i]);
+
+		// convert from stereo to mono (if needed)
+		if (numChannels == 2)
+		{
+			sampleLength >>= 1;
+			for (int32_t i = 0; i < sampleLength-1; i++) // add right channel to left channel
+			{
+				int64_t smp = ((int64_t)audioDataS32[(i << 1) + 0] + audioDataS32[(i << 1) + 1]) >> 1;
+				audioDataS32[i] = (int32_t)smp;
+			}
+		}
+
+		// 2x downsampling
+		if (downSample)
+		{
+			downsample2x32Bit(audioDataS32, sampleLength);
+			sampleLength >>= 1;
+		}
+
+		if (sampleLength > config.maxSampleLength)
+			sampleLength = config.maxSampleLength;
+
+		double dAmp = 1.0;
+		if (downSample) // we already normalized
+		{
+			dAmp = INT8_MAX / (double)INT32_MAX;
+		}
+		else
+		{
+			const double dPeak = get32BitPeak(audioDataS32, sampleLength);
+			if (dPeak > 0.0)
+				dAmp = INT8_MAX / dPeak;
+		}
+
+		turnOffVoices();
+		for (int32_t i = 0; i < sampleLength; i++)
+		{
+			int32_t smp32 = (int32_t)round(audioDataS32[i] * dAmp);
+			smpDataPtr[i] = (int8_t)smp32;
+		}
+
+		free(audioDataS32);
+	}
+
+	if (sampleLength & 1)
+	{
+		if (++sampleLength > config.maxSampleLength)
+			sampleLength = config.maxSampleLength;
+	}
+
+	s->length = sampleLength;
+	s->fineTune = 0;
+	s->volume = 64;
+	s->loopStart = 0;
+	s->loopLength = 2;
+
+	return true;
+}
\ No newline at end of file
--- /dev/null
+++ b/src/smploaders/pt2_load_flac.c
@@ -1,0 +1,532 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <math.h>
+#ifndef _WIN32
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#endif
+#include "../pt2_header.h"
+#include "../pt2_config.h"
+#include "../pt2_structs.h"
+#include "../pt2_textout.h"
+#include "../pt2_visuals.h"
+#include "../pt2_helpers.h"
+#include "../pt2_replayer.h"
+#include "../pt2_askbox.h"
+#include "../pt2_downsample2x.h"
+#include "../pt2_audio.h"
+
+#ifdef HAS_LIBFLAC
+
+// hide POSIX warning for fileno()
+#ifdef _MSC_VER
+#pragma warning(disable: 4996)
+#endif
+
+#ifdef EXTERNAL_LIBFLAC
+#include <FLAC/stream_decoder.h>
+#else
+#include "../libflac/FLAC/stream_decoder.h"
+#endif
+
+static bool loopEnabled;
+static int8_t *smpBuf8;
+static int16_t *smpBuf16;
+static int32_t *smpBuf24, sampleLength, loopStart, loopLength;
+static uint32_t numChannels, bitDepth, sampleRate, samplesRead;
+static moduleSample_t *smp;
+
+static FLAC__StreamDecoderReadStatus read_callback(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
+static FLAC__StreamDecoderSeekStatus seek_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data);
+static FLAC__StreamDecoderTellStatus tell_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
+static FLAC__StreamDecoderLengthStatus length_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data);
+static FLAC__bool eof_callback(const FLAC__StreamDecoder *decoder, void *client_data);
+static void metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
+static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data);
+static void error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
+
+bool loadFLACSample(FILE *f, int32_t filesize, moduleSample_t *s)
+{
+	FLAC__StreamDecoder *decoder = FLAC__stream_decoder_new();
+	if (decoder == NULL)
+	{
+		displayErrorMsg("FLAC LOAD ERROR !");
+		goto error;
+	}
+
+	FLAC__stream_decoder_set_metadata_respond_all(decoder);
+
+	FLAC__StreamDecoderInitStatus initStatus =
+		FLAC__stream_decoder_init_stream
+		(
+			decoder,
+			read_callback, seek_callback,
+			tell_callback, length_callback,
+			eof_callback, write_callback,
+			metadata_callback, error_callback,
+			f
+		);
+
+	if (initStatus != FLAC__STREAM_DECODER_INIT_STATUS_OK)
+	{
+		displayErrorMsg("FLAC LOAD ERROR !");
+		goto error;
+	}
+
+	smp = s;
+	s->volume = 64;
+	loopStart = 0;
+	loopLength = 2;
+	smpBuf8 = NULL;
+	smpBuf16 = NULL;
+	smpBuf24 = NULL;
+
+	if (!FLAC__stream_decoder_process_until_end_of_stream(decoder))
+	{
+		displayErrorMsg("FLAC LOAD ERROR !");
+		goto error;
+	}
+
+	FLAC__stream_decoder_finish(decoder);
+	FLAC__stream_decoder_delete(decoder);
+
+	// sample has been read to smpBufX now (depending on bitdepth)
+
+	bool downSample = false;
+	if (sampleRate > 22050 && !config.noDownsampleOnSmpLoad)
+	{
+		if (askBox(ASKBOX_DOWNSAMPLE, "DOWNSAMPLE ?"))
+			downSample = true;
+	}
+
+	int8_t *smpDataPtr = &song->sampleData[s->offset];
+
+	if (bitDepth == 8)
+	{
+		if (downSample)
+		{
+			if (!downsample2x8Bit(smpBuf8, sampleLength))
+			{
+				statusOutOfMemory();
+				goto error;
+			}
+
+			sampleLength /= 2;
+		}
+
+		turnOffVoices();
+		memcpy(smpDataPtr, smpBuf8, sampleLength * sizeof (int8_t));
+		free(smpBuf8);
+	}
+	else if (bitDepth == 16)
+	{
+		if (downSample)
+		{
+			if (!downsample2x16Bit(smpBuf16, sampleLength))
+			{
+				statusOutOfMemory();
+				goto error;
+			}
+
+			sampleLength /= 2;
+		}
+
+		double dAmp = 1.0;
+		if (downSample) // we already normalized
+		{
+			dAmp = INT8_MAX / (double)INT16_MAX;
+		}
+		else
+		{
+			const double dPeak = get16BitPeak(smpBuf16, sampleLength);
+			if (dPeak > 0.0)
+				dAmp = INT8_MAX / dPeak;
+		}
+
+		turnOffVoices();
+		for (int32_t i = 0; i < sampleLength; i++)
+		{
+			int32_t smp32 = (int32_t)round(smpBuf16[i] * dAmp);
+			assert(smp32 >= -128 && smp32 <= 127); // shouldn't happen according to dAmp (but just in case)
+			smpDataPtr[i] = (int8_t)smp32;
+		}
+
+		free(smpBuf16);
+	}
+	else if (bitDepth == 24)
+	{
+		if (downSample)
+		{
+			if (!downsample2x32Bit(smpBuf24, sampleLength))
+			{
+				statusOutOfMemory();
+				goto error;
+			}
+
+			sampleLength /= 2;
+		}
+
+		double dAmp = 1.0;
+		if (downSample) // we already normalized
+		{
+			dAmp = INT8_MAX / (double)INT32_MAX;
+		}
+		else
+		{
+			const double dPeak = get32BitPeak(smpBuf24, sampleLength);
+			if (dPeak > 0.0)
+				dAmp = INT8_MAX / dPeak;
+		}
+
+		turnOffVoices();
+		for (int32_t i = 0; i < sampleLength; i++)
+		{
+			int32_t smp32 = (int32_t)round(smpBuf24[i] * dAmp);
+			assert(smp32 >= -128 && smp32 <= 127); // shouldn't happen according to dAmp (but just in case)
+			smpDataPtr[i] = (int8_t)smp32;
+		}
+
+		free(smpBuf24);
+	}
+
+	if (sampleLength & 1)
+	{
+		if (++sampleLength > config.maxSampleLength)
+			sampleLength = config.maxSampleLength;
+	}
+
+	if (downSample)
+	{
+		loopStart /= 2;
+		loopLength /= 2;
+	}
+
+	loopStart &= ~1;
+	loopLength &= ~1;
+
+	if (loopLength < 2 || loopStart+loopLength > sampleLength)
+	{
+		loopStart = 0;
+		loopLength = 2;
+	}
+
+	s->fineTune = 0;
+	s->loopStart = loopStart;
+	s->loopLength = loopLength;
+	s->length = sampleLength;
+
+	return true;
+
+error:
+	if (smpBuf8 != NULL) free(smpBuf8);
+	if (smpBuf16 != NULL) free(smpBuf16);
+	if (smpBuf24 != NULL) free(smpBuf24);
+	if (decoder != NULL) FLAC__stream_decoder_delete(decoder);
+
+	return false;
+
+	(void)filesize;
+}
+
+static FLAC__StreamDecoderReadStatus read_callback(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+	FILE *file = (FILE *)client_data;
+	if (*bytes > 0)
+	{
+		*bytes = fread(buffer, sizeof (FLAC__byte), *bytes, file);
+		if (ferror(file))
+			return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+		else if (*bytes == 0)
+			return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+		else
+			return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+	}
+	else
+	{
+		return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+	}
+
+	(void)decoder;
+}
+
+static FLAC__StreamDecoderSeekStatus seek_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+{
+	FILE *file = (FILE *)client_data;
+
+	if (absolute_byte_offset > INT32_MAX)
+		return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+
+	if (fseek(file, (int32_t)absolute_byte_offset, SEEK_SET) < 0)
+		return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+	else
+		return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
+
+	(void)decoder;
+}
+
+static FLAC__StreamDecoderTellStatus tell_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+{
+	FILE *file = (FILE *)client_data;
+	int32_t pos = ftell(file);
+
+	if (pos < 0)
+	{
+		return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+	}
+	else
+	{
+		*absolute_byte_offset = (FLAC__uint64)pos;
+		return FLAC__STREAM_DECODER_TELL_STATUS_OK;
+	}
+
+	(void)decoder;
+}
+
+static FLAC__StreamDecoderLengthStatus length_callback(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data)
+{
+	FILE *file = (FILE *)client_data;
+	struct stat filestats;
+
+	if (fstat(fileno(file), &filestats) != 0)
+	{
+		return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
+	}
+	else
+	{
+		*stream_length = (FLAC__uint64)filestats.st_size;
+		return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
+	}
+
+	(void)decoder;
+}
+
+static FLAC__bool eof_callback(const FLAC__StreamDecoder *decoder, void *client_data)
+{
+	FILE *file = (FILE *)client_data;
+	return feof(file) ? true : false;
+
+	(void)decoder;
+}
+
+static void metadata_callback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+	if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO && metadata->data.stream_info.total_samples != 0)
+	{
+		bitDepth = metadata->data.stream_info.bits_per_sample;
+		numChannels = metadata->data.stream_info.channels;
+		sampleRate = metadata->data.stream_info.sample_rate;
+
+		int64_t tmp64 = metadata->data.stream_info.total_samples;
+		if (tmp64 > config.maxSampleLength*2)
+			tmp64 = config.maxSampleLength*2;
+
+		sampleLength = (int32_t)tmp64;
+
+		if (bitDepth == 8)
+			smpBuf8 = (int8_t *)calloc(1, config.maxSampleLength * 2 * sizeof (int8_t));
+		else if (bitDepth == 16)
+			smpBuf16 = (int16_t *)calloc(1, config.maxSampleLength * 2 * sizeof (int16_t));
+		else if (bitDepth == 24)
+			smpBuf24 = (int32_t *)calloc(1, config.maxSampleLength * 2 * sizeof (int32_t));
+
+		// alloc result is tasted later
+	}
+
+	// check for RIFF chunks (loop/vol/pan information)
+	else if (metadata->type == FLAC__METADATA_TYPE_APPLICATION && !memcmp(metadata->data.application.id, "riff", 4))
+	{
+		const uint8_t *data = (const uint8_t *)metadata->data.application.data;
+
+		uint32_t chunkID  = *(uint32_t *)data; data += 4;
+		uint32_t chunkLen = *(uint32_t *)data; data += 4;
+
+		if (chunkID == 0x61727478 && chunkLen >= 8) // "xtra"
+		{
+			data += 6;
+
+			// volume (0..256)
+			uint16_t tmpVol = *(uint16_t *)data;
+			if (tmpVol > 256)
+				tmpVol = 256;
+
+			smp->volume = (uint8_t)((tmpVol + 2) / 4); // 0..256 -> 0..64 (rounded)
+		}
+
+		if (chunkID == 0x6C706D73 && chunkLen > 52) // "smpl"
+		{
+			data += 28; // seek to first wanted byte
+
+			uint32_t numLoops = *(uint32_t *)data; data += 4;
+			if (numLoops == 1)
+			{
+				data += 4+4; // skip "samplerData" and "identifier"
+
+				uint32_t loopType  = *(uint32_t *)data; data += 4;
+				         loopStart = *(uint32_t *)data; data += 4;
+				uint32_t loopEnd   = *(uint32_t *)data; data += 4;
+
+				loopLength = (loopEnd+1) - loopStart;
+				loopEnabled = (loopType == 0);
+			}
+		}
+	}
+
+	else if (metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT)
+	{
+		uint32_t tmpSampleRate = 0;
+		for (uint32_t i = 0; i < metadata->data.vorbis_comment.num_comments; i++)
+		{
+			const char *tag = (const char *)metadata->data.vorbis_comment.comments[i].entry;
+			uint32_t length = metadata->data.vorbis_comment.comments[i].length;
+
+			if (length > 6 && !memcmp(tag, "TITLE=", 6))
+			{
+				length -= 6;
+				if (length > 22)
+					length = 22;
+
+				memcpy(smp->text, &tag[6], length);
+				smp->text[22] = '\0';
+			}
+
+			// the following tags haven't been tested!
+			else if (length > 11 && !memcmp(tag, "SAMPLERATE=", 11))
+			{
+				tmpSampleRate = atoi(&tag[11]);
+			}
+			else if (length > 10 && !memcmp(tag, "LOOPSTART=", 10))
+			{
+				loopStart = atoi(&tag[10]);
+			}
+			else if (length > 11 && !memcmp(tag, "LOOPLENGTH=", 11))
+			{
+				loopLength = atoi(&tag[11]);
+			}
+
+			if (tmpSampleRate > 0)
+				sampleRate = tmpSampleRate;
+		}
+	}
+
+	(void)client_data;
+	(void)decoder;
+}
+
+static FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data)
+{
+
+	if (sampleLength == 0 || numChannels == 0)
+	{
+		displayErrorMsg("FLAC LOAD ERROR !");
+		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+	}
+
+	if (numChannels > 2)
+	{
+		displayErrorMsg("UNSUPPORTED FLAC !");
+		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+	}
+
+	if (bitDepth != 8 && bitDepth != 16 && bitDepth != 24)
+	{
+		displayErrorMsg("UNSUPPORTED FLAC !");
+		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+	}
+
+	if ((bitDepth == 8 && smpBuf8 == NULL) || (bitDepth == 16 && smpBuf16 == NULL) || (bitDepth == 24 && smpBuf24 == NULL))
+	{
+		statusOutOfMemory();
+		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+	}
+
+	if (frame->header.number.sample_number == 0)
+		samplesRead = 0;
+
+	uint32_t blockSize = frame->header.blocksize;
+
+	const uint32_t samplesAllocated = config.maxSampleLength * 2;
+	if (samplesRead+blockSize > samplesAllocated)
+		blockSize = samplesAllocated-samplesRead;
+	
+	if (blockSize > 0)
+	{
+		if (numChannels == 2) // mix to mono
+		{
+			const int32_t *src_L = buffer[0];
+			const int32_t *src_R = buffer[1];
+
+			if (bitDepth == 8)
+			{
+				int8_t *dst8 = smpBuf8 + samplesRead;
+				for (uint32_t i = 0; i < blockSize; i++)
+					dst8[i] = (int8_t)((src_L[i] + src_R[i]) >> 1);
+			}
+			else if (bitDepth == 16)
+			{
+				int16_t *dst16 = smpBuf16 + samplesRead;
+				for (uint32_t i = 0; i < blockSize; i++)
+					dst16[i] = (int16_t)((src_L[i] + src_R[i]) >> 1);
+			}
+			else if (bitDepth == 24)
+			{
+				int32_t *dst24 = smpBuf24 + samplesRead;
+				for (uint32_t i = 0; i < blockSize; i++)
+					dst24[i] = (int32_t)((src_L[i] + src_R[i]) >> 1);
+			}
+		}
+		else // mono sample
+		{
+			const int32_t *src = buffer[0];
+
+			if (bitDepth == 8)
+			{
+				int8_t *dst8 = smpBuf8 + samplesRead;
+				for (uint32_t i = 0; i < blockSize; i++)
+					dst8[i] = (int8_t)src[i];
+			}
+			else if (bitDepth == 16)
+			{
+				int16_t *dst16 = smpBuf16 + samplesRead;
+				for (uint32_t i = 0; i < blockSize; i++)
+					dst16[i] = (int16_t)src[i];
+			}
+			else if (bitDepth == 24)
+			{
+				int32_t *dst24 = smpBuf24 + samplesRead;
+				for (uint32_t i = 0; i < blockSize; i++)
+					dst24[i] = (int32_t)src[i];
+			}
+		}
+
+		samplesRead += blockSize;
+	}
+
+	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+
+	(void)client_data;
+	(void)decoder;
+}
+
+static void error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+	(void)status;
+	(void)decoder;
+	(void)client_data;
+}
+
+#else
+
+bool loadFLACSample(FILE *f, int32_t filesize, moduleSample_t *s)
+{
+	displayErrorMsg("NO FLAC SUPPORT !");
+	return false;
+
+	(void)f;
+	(void)filesize;
+	(void)s;
+}
+
+#endif
--- /dev/null
+++ b/src/smploaders/pt2_load_iff.c
@@ -1,0 +1,262 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <math.h>
+#include "../pt2_header.h"
+#include "../pt2_config.h"
+#include "../pt2_structs.h"
+#include "../pt2_textout.h"
+#include "../pt2_visuals.h"
+#include "../pt2_helpers.h"
+#include "../pt2_replayer.h"
+#include "../pt2_askbox.h"
+#include "../pt2_downsample2x.h"
+#include "../pt2_audio.h"
+
+bool loadIFFSample(FILE *f, int32_t filesize, moduleSample_t *s)
+{
+	char tmpCharBuf[23];
+	uint16_t sampleRate;
+	int32_t loopStart, loopLength;
+
+	// zero out chunk pointers and lengths
+	uint32_t vhdrPtr = 0; uint32_t vhdrLen = 0;
+	uint32_t bodyPtr = 0; uint32_t bodyLen = 0;
+	uint32_t namePtr = 0;  int32_t nameLen = 0;
+
+	fseek(f, 8, SEEK_SET);
+	fread(tmpCharBuf, 1, 4, f);
+	bool is16Bit = !strncmp(tmpCharBuf, "16SV", 4);
+
+	int32_t sampleLength = 0;
+	uint32_t sampleVolume = 65536; // max volume
+
+	fseek(f, 12, SEEK_SET);
+	while (!feof(f) && ftell(f) < filesize-12)
+	{
+		uint32_t blockName, blockSize;
+
+		fread(&blockName, 4, 1, f); if (feof(f)) break;
+		fread(&blockSize, 4, 1, f); if (feof(f)) break;
+
+		blockName = SWAP32(blockName);
+		blockSize = SWAP32(blockSize);
+
+		switch (blockName)
+		{
+			case 0x56484452: // VHDR
+			{
+				vhdrPtr = ftell(f);
+				vhdrLen = blockSize;
+			}
+			break;
+
+			case 0x4E414D45: // NAME
+			{
+				namePtr = ftell(f);
+				nameLen = blockSize;
+			}
+			break;
+
+			case 0x424F4459: // BODY
+			{
+				bodyPtr = ftell(f);
+				bodyLen = blockSize;
+			}
+			break;
+
+			default: break;
+		}
+
+		fseek(f, blockSize + (blockSize & 1), SEEK_CUR);
+	}
+
+	if (vhdrPtr == 0 || vhdrLen < 20 || bodyPtr == 0)
+	{
+		displayErrorMsg("NOT A VALID IFF !");
+		return false;
+	}
+
+	// kludge for some really strange IFFs
+	if (bodyLen == 0)
+		bodyLen = filesize - bodyPtr;
+
+	if (bodyPtr+bodyLen > (uint32_t)filesize)
+		bodyLen = filesize - bodyPtr;
+
+	fseek(f, vhdrPtr, SEEK_SET);
+	fread(&loopStart,  4, 1, f); loopStart  = SWAP32(loopStart);
+	fread(&loopLength, 4, 1, f); loopLength = SWAP32(loopLength);
+	fseek(f, 4, SEEK_CUR);
+	fread(&sampleRate, 2, 1, f); sampleRate = SWAP16(sampleRate);
+	fseek(f, 1, SEEK_CUR);
+
+	if (fgetc(f) != 0) // sample type
+	{
+		displayErrorMsg("UNSUPPORTED IFF !");
+		return false;
+	}
+
+	fread(&sampleVolume, 4, 1, f); sampleVolume = SWAP32(sampleVolume);
+	if (sampleVolume > 65536)
+		sampleVolume = 65536;
+
+	sampleVolume = (sampleVolume + 512) / 1024; // rounded
+	if (sampleVolume > 64)
+		sampleVolume = 64;
+
+	sampleLength = bodyLen;
+
+	if (sampleLength == 0)
+	{
+		displayErrorMsg("NOT A VALID IFF !");
+		return false;
+	}
+
+	bool downSample = false;
+	if (sampleRate > 22050 && !config.noDownsampleOnSmpLoad)
+	{
+		if (askBox(ASKBOX_DOWNSAMPLE, "DOWNSAMPLE ?"))
+			downSample = true;
+	}
+
+	int32_t maxSampleLength = config.maxSampleLength;
+	if (is16Bit)
+		maxSampleLength *= 2;
+
+	if (downSample)
+		maxSampleLength *= 2;
+
+	if (sampleLength > maxSampleLength)
+		sampleLength = maxSampleLength;
+
+	int8_t *sampleData = (int8_t *)malloc(sampleLength);
+	if (sampleData == NULL)
+	{
+		statusOutOfMemory();
+		return false;
+	}
+
+	if (is16Bit)
+	{
+		sampleLength >>= 1;
+		loopStart >>= 1;
+		loopLength >>= 1;
+	}
+
+	if (downSample)
+	{
+		loopStart >>= 1;
+		loopLength >>= 1;
+	}
+
+	turnOffVoices();
+
+	int8_t *smpDataPtr = &song->sampleData[s->offset];
+
+	fseek(f, bodyPtr, SEEK_SET);
+	if (is16Bit) // FT2-specific 16SV format (little-endian samples)
+	{
+		fread(sampleData, 1, sampleLength << 1, f);
+		int16_t *ptr16 = (int16_t *)sampleData;
+
+		// 2x downsampling
+		if (downSample)
+		{
+			downsample2x16Bit(ptr16, sampleLength);
+			sampleLength >>= 1;
+		}
+
+		if (sampleLength > config.maxSampleLength)
+			sampleLength = config.maxSampleLength;
+
+		double dAmp = 1.0;
+		if (downSample) // we already normalized
+		{
+			dAmp = INT8_MAX / (double)INT16_MAX;
+		}
+		else
+		{
+			const double dPeak = get16BitPeak(ptr16, sampleLength);
+			if (dPeak > 0.0)
+				dAmp = INT8_MAX / dPeak;
+		}
+
+		for (int32_t i = 0; i < sampleLength; i++)
+		{
+			int32_t smp32 = (int32_t)round(ptr16[i] * dAmp);
+			assert(smp32 >= -128 && smp32 <= 127); // shouldn't happen according to dAmp (but just in case)
+			smpDataPtr[i] = (int8_t)smp32;
+		}
+	}
+	else
+	{
+		fread(sampleData, 1, sampleLength, f);
+
+		// 2x downsampling
+		if (downSample)
+		{
+			downsample2x8Bit(sampleData, sampleLength);
+			sampleLength >>= 1;
+		}
+
+		if (sampleLength > config.maxSampleLength)
+			sampleLength = config.maxSampleLength;
+
+		memcpy(smpDataPtr, sampleData, sampleLength);
+	}
+
+	free(sampleData);
+
+	if (sampleLength & 1)
+	{
+		if (++sampleLength > config.maxSampleLength)
+			sampleLength = config.maxSampleLength;
+	}
+
+	loopStart &= ~1;
+	loopLength &= ~1;
+
+	if (loopLength < 2 || loopStart+loopLength > sampleLength)
+	{
+		loopStart = 0;
+		loopLength = 2;
+	}
+
+	// set sample attributes
+	s->volume = (int8_t)sampleVolume;
+	s->fineTune = 0;
+	s->length = sampleLength;
+	s->loopStart = loopStart;
+	s->loopLength = loopLength;
+
+	if (namePtr != 0 && nameLen > 0)
+	{
+		// read name
+
+		fseek(f, namePtr, SEEK_SET);
+		memset(tmpCharBuf, 0, sizeof (tmpCharBuf));
+
+		if (nameLen > 21)
+		{
+			fread(tmpCharBuf, 1, 21, f);
+			fseek(f, nameLen - 21, SEEK_CUR);
+		}
+		else
+		{
+			fread(tmpCharBuf, 1, nameLen, f);
+		}
+
+		// copy over sample name
+		memset(s->text, '\0', sizeof (s->text));
+
+		nameLen = (uint32_t)strlen(tmpCharBuf);
+		if (nameLen > 21)
+			nameLen = 21;
+
+		memcpy(s->text, tmpCharBuf, nameLen);
+	}
+
+	return true;
+}
\ No newline at end of file
--- /dev/null
+++ b/src/smploaders/pt2_load_raw.c
@@ -1,0 +1,34 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include "../pt2_header.h"
+#include "../pt2_config.h"
+#include "../pt2_structs.h"
+#include "../pt2_replayer.h"
+
+bool loadRAWSample(FILE *f, int32_t filesize, moduleSample_t *s)
+{
+	int32_t sampleLength = filesize;
+	if (sampleLength > config.maxSampleLength)
+		sampleLength = config.maxSampleLength;
+
+	int8_t *smpDataPtr = &song->sampleData[s->offset];
+
+	turnOffVoices();
+	fread(smpDataPtr, 1, sampleLength, f);
+
+	if (sampleLength & 1)
+	{
+		if (++sampleLength > config.maxSampleLength)
+			sampleLength = config.maxSampleLength;
+	}
+
+	s->volume = 64;
+	s->fineTune = 0;
+	s->length = sampleLength;
+	s->loopStart = 0;
+	s->loopLength = 2;
+
+	return true;
+}
\ No newline at end of file
--- /dev/null
+++ b/src/smploaders/pt2_load_wav.c
@@ -1,0 +1,616 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <math.h>
+#include "../pt2_header.h"
+#include "../pt2_config.h"
+#include "../pt2_structs.h"
+#include "../pt2_textout.h"
+#include "../pt2_visuals.h"
+#include "../pt2_helpers.h"
+#include "../pt2_replayer.h"
+#include "../pt2_askbox.h"
+#include "../pt2_downsample2x.h"
+#include "../pt2_audio.h"
+
+enum
+{
+	WAV_FORMAT_PCM = 0x0001,
+	WAV_FORMAT_IEEE_FLOAT = 0x0003
+};
+
+bool loadWAVSample(FILE *f, int32_t filesize, moduleSample_t *s)
+{
+	uint16_t audioFormat, numChannels, bitsPerSample;
+	uint32_t sampleRate;
+
+	// zero out chunk pointers and lengths
+	uint32_t fmtPtr  = 0; uint32_t fmtLen = 0;
+	uint32_t dataPtr = 0; uint32_t dataLen = 0;
+	uint32_t inamPtr = 0;  int32_t inamLen = 0;
+	uint32_t xtraPtr = 0; uint32_t xtraLen = 0;
+	uint32_t smplPtr = 0; uint32_t smplLen = 0;
+
+	// look for wanted chunks and set up pointers + lengths
+	fseek(f, 12, SEEK_SET);
+
+	uint32_t bytesRead = 0;
+	while (!feof(f) && bytesRead < (uint32_t)filesize-12)
+	{
+		uint32_t chunkID, chunkSize;
+
+		fread(&chunkID, 4, 1, f); if (feof(f)) break;
+		fread(&chunkSize, 4, 1, f); if (feof(f)) break;
+
+		uint32_t endOfChunk = (ftell(f) + chunkSize) + (chunkSize & 1);
+		switch (chunkID)
+		{
+			case 0x20746D66: // "fmt "
+			{
+				fmtPtr = ftell(f);
+				fmtLen = chunkSize;
+			}
+			break;
+
+			case 0x61746164: // "data"
+			{
+				dataPtr = ftell(f);
+				dataLen = chunkSize;
+			}
+			break;
+
+			case 0x5453494C: // "LIST"
+			{
+				if (chunkSize >= 4)
+				{
+					fread(&chunkID, 4, 1, f);
+					if (chunkID == 0x4F464E49) // "INFO"
+					{
+						bytesRead = 0;
+						while (!feof(f) && bytesRead < chunkSize)
+						{
+							fread(&chunkID, 4, 1, f);
+							fread(&chunkSize, 4, 1, f);
+
+							switch (chunkID)
+							{
+								case 0x4D414E49: // "INAM"
+								{
+									inamPtr = ftell(f);
+									inamLen = chunkSize;
+								}
+								break;
+
+								default: break;
+							}
+
+							bytesRead += chunkSize + (chunkSize & 1);
+						}
+					}
+				}
+			}
+			break;
+
+			case 0x61727478: // "xtra"
+			{
+				xtraPtr = ftell(f);
+				xtraLen = chunkSize;
+			}
+			break;
+
+			case 0x6C706D73: // "smpl"
+			{
+				smplPtr = ftell(f);
+				smplLen = chunkSize;
+			}
+			break;
+
+			default: break;
+		}
+
+		bytesRead += chunkSize + (chunkSize & 1);
+		fseek(f, endOfChunk, SEEK_SET);
+	}
+
+	// we need at least "fmt " and "data" - check if we found them sanely
+	if (fmtPtr == 0 || fmtLen < 16 || dataPtr == 0 || dataLen == 0)
+	{
+		displayErrorMsg("NOT A WAV !");
+		return false;
+	}
+
+	// ---- READ "fmt " CHUNK ----
+	fseek(f, fmtPtr, SEEK_SET);
+	fread(&audioFormat, 2, 1, f);
+	fread(&numChannels, 2, 1, f);
+	fread(&sampleRate,  4, 1, f);
+	fseek(f, 6, SEEK_CUR);
+	fread(&bitsPerSample, 2, 1, f);
+	int32_t sampleLength = dataLen;
+	// ---------------------------
+
+	if (sampleRate == 0 || sampleLength == 0 || sampleLength >= (int32_t)filesize*(bitsPerSample/8))
+	{
+		displayErrorMsg("WAV CORRUPT !");
+		return false;
+	}
+
+	if (audioFormat != WAV_FORMAT_PCM && audioFormat != WAV_FORMAT_IEEE_FLOAT)
+	{
+		displayErrorMsg("WAV UNSUPPORTED !");
+		return false;
+	}
+
+	if (numChannels == 0 || numChannels > 2)
+	{
+		displayErrorMsg("WAV UNSUPPORTED !");
+		return false;
+	}
+
+	if (audioFormat == WAV_FORMAT_IEEE_FLOAT && bitsPerSample != 32 && bitsPerSample != 64)
+	{
+		displayErrorMsg("WAV UNSUPPORTED !");
+		return false;
+	}
+
+	if (bitsPerSample != 8 && bitsPerSample != 16 && bitsPerSample != 24 && bitsPerSample != 32 && bitsPerSample != 64)
+	{
+		displayErrorMsg("WAV UNSUPPORTED !");
+		return false;
+	}
+
+	bool downSample = false;
+	if (sampleRate > 22050 && !config.noDownsampleOnSmpLoad)
+	{
+		if (askBox(ASKBOX_DOWNSAMPLE, "DOWNSAMPLE ?"))
+			downSample = true;
+	}
+
+	// ---- READ SAMPLE DATA ----
+	fseek(f, dataPtr, SEEK_SET);
+
+	int8_t *smpDataPtr = &song->sampleData[s->offset];
+
+	if (bitsPerSample == 8) // 8-BIT INTEGER SAMPLE
+	{
+		if (sampleLength > config.maxSampleLength*4)
+			sampleLength = config.maxSampleLength*4;
+
+		uint8_t *audioDataU8 = (uint8_t *)malloc(sampleLength * sizeof (uint8_t));
+		if (audioDataU8 == NULL)
+		{
+			statusOutOfMemory();
+			return false;
+		}
+
+		// read sample data
+		if (fread(audioDataU8, 1, sampleLength, f) != (size_t)sampleLength)
+		{
+			free(audioDataU8);
+			displayErrorMsg("I/O ERROR !");
+			return false;
+		}
+
+		// convert from stereo to mono (if needed)
+		if (numChannels == 2)
+		{
+			sampleLength >>= 1;
+			for (int32_t i = 0; i < sampleLength-1; i++) // add right channel to left channel
+			{
+				int32_t smp32 = (audioDataU8[(i << 1) + 0] - 128) + (audioDataU8[(i << 1) + 1] - 128);
+				smp32 = 128 + (smp32 >> 1);
+				audioDataU8[i] = (uint8_t)smp32;
+			}
+		}
+
+		// 2x downsampling
+		if (downSample)
+		{
+			downsample2x8BitU(audioDataU8, sampleLength);
+			sampleLength >>= 1;
+		}
+
+		if (sampleLength > config.maxSampleLength)
+			sampleLength = config.maxSampleLength;
+
+		turnOffVoices();
+		for (int32_t i = 0; i < sampleLength; i++)
+			smpDataPtr[i] = audioDataU8[i] - 128;
+
+		free(audioDataU8);
+	}
+	else if (bitsPerSample == 16) // 16-BIT INTEGER SAMPLE
+	{
+		sampleLength >>= 1;
+		if (sampleLength > config.maxSampleLength*4)
+			sampleLength = config.maxSampleLength*4;
+
+		int16_t *audioDataS16 = (int16_t *)malloc(sampleLength * sizeof (int16_t));
+		if (audioDataS16 == NULL)
+		{
+			statusOutOfMemory();
+			return false;
+		}
+
+		// read sample data
+		if (fread(audioDataS16, 2, sampleLength, f) != (size_t)sampleLength)
+		{
+			free(audioDataS16);
+			displayErrorMsg("I/O ERROR !");
+			return false;
+		}
+
+		// convert from stereo to mono (if needed)
+		if (numChannels == 2)
+		{
+			sampleLength >>= 1;
+			for (int32_t i = 0; i < sampleLength-1; i++) // add right channel to left channel
+				audioDataS16[i] = (audioDataS16[(i << 1) + 0] + audioDataS16[(i << 1) + 1]) >> 1;;
+		}
+
+		// 2x downsampling
+		if (downSample)
+		{
+			downsample2x16Bit(audioDataS16, sampleLength);
+			sampleLength >>= 1;
+		}
+
+		if (sampleLength > config.maxSampleLength)
+			sampleLength = config.maxSampleLength;
+
+		double dAmp = 1.0;
+		if (downSample) // we already normalized
+		{
+			dAmp = INT8_MAX / (double)INT16_MAX;
+		}
+		else
+		{
+			const double dPeak = get16BitPeak(audioDataS16, sampleLength);
+			if (dPeak > 0.0)
+				dAmp = INT8_MAX / dPeak;
+		}
+
+		turnOffVoices();
+		for (int32_t i = 0; i < sampleLength; i++)
+		{
+			int32_t smp32 = (int32_t)round(audioDataS16[i] * dAmp);
+			assert(smp32 >= -128 && smp32 <= 127); // shouldn't happen according to dAmp (but just in case)
+			smpDataPtr[i] = (int8_t)smp32;
+		}
+
+		free(audioDataS16);
+	}
+	else if (bitsPerSample == 24) // 24-BIT INTEGER SAMPLE
+	{
+		sampleLength /= 3;
+		if (sampleLength > config.maxSampleLength*4)
+			sampleLength = config.maxSampleLength*4;
+
+		int32_t *audioDataS32 = (int32_t *)malloc(sampleLength * sizeof (int32_t));
+		if (audioDataS32 == NULL)
+		{
+			statusOutOfMemory();
+			return false;
+		}
+
+		// read sample data
+		uint8_t *audioDataU8 = (uint8_t *)audioDataS32;
+		for (int32_t i = 0; i < sampleLength; i++)
+		{
+			audioDataU8[0] = 0;
+			fread(&audioDataU8[1], 3, 1, f);
+			audioDataU8 += sizeof (int32_t);
+		}
+
+		// convert from stereo to mono (if needed)
+		if (numChannels == 2)
+		{
+			sampleLength >>= 1;
+			for (int32_t i = 0; i < sampleLength-1; i++) // add right channel to left channel
+			{
+				int64_t smp = ((int64_t)audioDataS32[(i << 1) + 0] + audioDataS32[(i << 1) + 1]) >> 1;
+				audioDataS32[i] = (int32_t)smp;
+			}
+		}
+
+		// 2x downsampling
+		if (downSample)
+		{
+			downsample2x32Bit(audioDataS32, sampleLength);
+			sampleLength >>= 1;
+		}
+
+		if (sampleLength > config.maxSampleLength)
+			sampleLength = config.maxSampleLength;
+
+		double dAmp = 1.0;
+		if (downSample) // we already normalized
+		{
+			dAmp = INT8_MAX / (double)INT32_MAX;
+		}
+		else
+		{
+			const double dPeak = get32BitPeak(audioDataS32, sampleLength);
+			if (dPeak > 0.0)
+				dAmp = INT8_MAX / dPeak;
+		}
+
+		turnOffVoices();
+		for (int32_t i = 0; i < sampleLength; i++)
+		{
+			int32_t smp32 = (int32_t)round(audioDataS32[i] * dAmp);
+			assert(smp32 >= -128 && smp32 <= 127); // shouldn't happen according to dAmp (but just in case)
+			smpDataPtr[i] = (int8_t)smp32;
+		}
+
+		free(audioDataS32);
+	}
+	else if (audioFormat == WAV_FORMAT_PCM && bitsPerSample == 32) // 32-BIT INTEGER SAMPLE
+	{
+		sampleLength >>= 2;
+		if (sampleLength > config.maxSampleLength*4)
+			sampleLength = config.maxSampleLength*4;
+
+		int32_t *audioDataS32 = (int32_t *)malloc(sampleLength * sizeof (int32_t));
+		if (audioDataS32 == NULL)
+		{
+			statusOutOfMemory();
+			return false;
+		}
+
+		// read sample data
+		if (fread(audioDataS32, 4, sampleLength, f) != (size_t)sampleLength)
+		{
+			free(audioDataS32);
+			displayErrorMsg("I/O ERROR !");
+			return false;
+		}
+
+		// convert from stereo to mono (if needed)
+		if (numChannels == 2)
+		{
+			sampleLength >>= 1;
+			for (int32_t i = 0; i < sampleLength-1; i++) // add right channel to left channel
+			{
+				int64_t smp = ((int64_t)audioDataS32[(i << 1) + 0] + audioDataS32[(i << 1) + 1]) >> 1;
+				audioDataS32[i] = (int32_t)smp;
+			}
+		}
+
+		// 2x downsampling
+		if (downSample)
+		{
+			downsample2x32Bit(audioDataS32, sampleLength);
+			sampleLength >>= 1;
+		}
+
+		if (sampleLength > config.maxSampleLength)
+			sampleLength = config.maxSampleLength;
+
+		double dAmp = 1.0;
+		if (downSample) // we already normalized
+		{
+			dAmp = INT8_MAX / (double)INT32_MAX;
+		}
+		else
+		{
+			const double dPeak = get32BitPeak(audioDataS32, sampleLength);
+			if (dPeak > 0.0)
+				dAmp = INT8_MAX / dPeak;
+		}
+
+		turnOffVoices();
+		for (int32_t i = 0; i < sampleLength; i++)
+		{
+			int32_t smp32 = (int32_t)round(audioDataS32[i] * dAmp);
+			assert(smp32 >= -128 && smp32 <= 127); // shouldn't happen according to dAmp (but just in case)
+			smpDataPtr[i] = (int8_t)smp32;
+		}
+
+		free(audioDataS32);
+	}
+	else if (audioFormat == WAV_FORMAT_IEEE_FLOAT && bitsPerSample == 32) // 32-BIT FLOATING POINT SAMPLE
+	{
+		sampleLength >>= 2;
+		if (sampleLength > config.maxSampleLength*4)
+			sampleLength = config.maxSampleLength*4;
+
+		uint32_t *audioDataU32 = (uint32_t *)malloc(sampleLength * sizeof (uint32_t));
+		if (audioDataU32 == NULL)
+		{
+			statusOutOfMemory();
+			return false;
+		}
+
+		// read sample data
+		if (fread(audioDataU32, 4, sampleLength, f) != (size_t)sampleLength)
+		{
+			free(audioDataU32);
+			displayErrorMsg("I/O ERROR !");
+			return false;
+		}
+
+		float *fAudioDataFloat = (float *)audioDataU32;
+
+		// convert from stereo to mono (if needed)
+		if (numChannels == 2)
+		{
+			sampleLength >>= 1;
+			for (int32_t i = 0; i < sampleLength-1; i++) // add right channel to left channel
+				fAudioDataFloat[i] = (fAudioDataFloat[(i * 2) + 0] + fAudioDataFloat[(i * 2) + 1]) * 0.5f;
+		}
+
+		// 2x downsampling
+		if (downSample)
+		{
+			downsample2xFloat(fAudioDataFloat, sampleLength);
+			sampleLength >>= 1;
+		}
+
+		if (sampleLength > config.maxSampleLength)
+			sampleLength = config.maxSampleLength;
+
+		float fAmp = 1.0f;
+		const float fPeak = getFloatPeak(fAudioDataFloat, sampleLength);
+		if (fPeak > 0.0f)
+			fAmp = INT8_MAX / fPeak;
+
+		turnOffVoices();
+		for (int32_t i = 0; i < sampleLength; i++)
+		{
+			int32_t smp32 = (int32_t)roundf(fAudioDataFloat[i] * fAmp);
+			assert(smp32 >= -128 && smp32 <= 127); // shouldn't happen according to dAmp (but just in case)
+			smpDataPtr[i] = (int8_t)smp32;
+		}
+
+		free(audioDataU32);
+	}
+	else if (audioFormat == WAV_FORMAT_IEEE_FLOAT && bitsPerSample == 64) // 64-BIT FLOATING POINT SAMPLE
+	{
+		sampleLength >>= 3;
+		if (sampleLength > config.maxSampleLength*4)
+			sampleLength = config.maxSampleLength*4;
+
+		uint32_t *audioDataU32 = (uint32_t *)malloc(sampleLength * (sizeof (uint32_t) * 2));
+		if (audioDataU32 == NULL)
+		{
+			statusOutOfMemory();
+			return false;
+		}
+
+		// read sample data
+		if (fread(audioDataU32, 8, sampleLength, f) != (size_t)sampleLength)
+		{
+			free(audioDataU32);
+			displayErrorMsg("I/O ERROR !");
+			return false;
+		}
+
+		double *dAudioDataDouble = (double *)audioDataU32;
+
+		// convert from stereo to mono (if needed)
+		if (numChannels == 2)
+		{
+			sampleLength >>= 1;
+			for (int32_t i = 0; i < sampleLength-1; i++) // add right channel to left channel
+				dAudioDataDouble[i] = (dAudioDataDouble[(i * 2) + 0] + dAudioDataDouble[(i * 2) + 1]) * 0.5;
+		}
+
+		// 2x downsampling
+		if (downSample)
+		{
+			downsample2xDouble(dAudioDataDouble, sampleLength);
+			sampleLength >>= 1;
+		}
+
+		if (sampleLength > config.maxSampleLength)
+			sampleLength = config.maxSampleLength;
+
+		double dAmp = 1.0;
+		const double dPeak = getDoublePeak(dAudioDataDouble, sampleLength);
+		if (dPeak > 0.0)
+			dAmp = INT8_MAX / dPeak;
+
+		turnOffVoices();
+		for (int32_t i = 0; i < sampleLength; i++)
+		{
+			int32_t smp32 = (int32_t)round(dAudioDataDouble[i] * dAmp);
+			assert(smp32 >= -128 && smp32 <= 127); // shouldn't happen according to dAmp (but just in case)
+			smpDataPtr[i] = (int8_t)smp32;
+		}
+
+		free(audioDataU32);
+	}
+
+	if (sampleLength & 1)
+	{
+		if (++sampleLength > config.maxSampleLength)
+			sampleLength = config.maxSampleLength;
+	}
+
+	s->length = sampleLength;
+	s->fineTune = 0;
+	s->volume = 64;
+	s->loopStart = 0;
+	s->loopLength = 2;
+
+	// ---- READ "smpl" chunk ----
+	if (smplPtr != 0 && smplLen > 52)
+	{
+		int32_t loopStart, loopEnd;
+		uint32_t loopFlags;
+
+		fseek(f, smplPtr + 28, SEEK_SET); // seek to first wanted byte
+
+		fread(&loopFlags, 4, 1, f);
+		fseek(f, 12, SEEK_CUR);
+		fread(&loopStart, 4, 1, f);
+		fread(&loopEnd, 4, 1, f);
+		loopEnd++;
+
+		if (loopFlags) // loop enabled?
+		{
+			int32_t loopLength = loopEnd - loopStart;
+
+			if (downSample)
+			{
+				// we already downsampled 2x, so we're half the original length
+				loopStart >>= 1;
+				loopLength >>= 1;
+			}
+
+			loopStart &= ~1;
+			loopLength &= ~1;
+
+			if (loopLength < 2 || loopStart+loopLength >= s->length)
+			{
+				loopStart = 0;
+				loopLength = 2;
+			}
+
+			s->loopStart = loopStart;
+			s->loopLength = loopLength;
+		}
+	}
+	// ---------------------------
+
+	// ---- READ "xtra" chunk ----
+	if (xtraPtr != 0 && xtraLen >= 8)
+	{
+		uint16_t tempVol;
+
+		fseek(f, xtraPtr + 4, SEEK_SET); // seek to first wanted byte
+
+		// volume (0..256)
+		fseek(f, 2, SEEK_CUR);
+		fread(&tempVol, 2, 1, f);
+		if (tempVol > 256)
+			tempVol = 256;
+
+		tempVol >>= 2; // 0..256 -> 0..64
+
+		s->volume = (int8_t)tempVol;
+	}
+	// ---------------------------
+
+	// ---- READ "INAM" chunk ----
+	if (inamPtr != 0 && inamLen > 0)
+	{
+		fseek(f, inamPtr, SEEK_SET); // seek to first wanted byte
+
+		for (int32_t i = 0; i < 21; i++)
+		{
+			if (i < inamLen)
+				s->text[i] = (char)fgetc(f);
+			else
+				s->text[i] = '\0';
+		}
+
+		s->text[21] = '\0';
+		s->text[22] = '\0';
+	}
+	// ---------------------------
+
+	return true;
+}
binary files a/vs2019_project/pt2-clone/SDL2.dll b/vs2019_project/pt2-clone/SDL2.dll differ
--- a/vs2019_project/pt2-clone/pt2-clone.vcxproj
+++ b/vs2019_project/pt2-clone/pt2-clone.vcxproj
@@ -31,9 +31,9 @@
     <CharacterSet>Unicode</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
-    <PlatformToolset>v142</PlatformToolset>
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <CharacterSet>Unicode</CharacterSet>
+    <PlatformToolset>v142</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
     <PlatformToolset>v140</PlatformToolset>
@@ -88,7 +88,7 @@
     <ClCompile>
       <WarningLevel>Level4</WarningLevel>
       <Optimization>MaxSpeed</Optimization>
-      <PreprocessorDefinitions>NDEBUG;WIN32;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+      <PreprocessorDefinitions>NDEBUG;WIN32;_CRT_SECURE_NO_WARNINGS;HAS_LIBFLAC</PreprocessorDefinitions>
       <EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
       <IntrinsicFunctions>true</IntrinsicFunctions>
@@ -135,7 +135,7 @@
     <ClCompile>
       <WarningLevel>Level4</WarningLevel>
       <Optimization>MaxSpeed</Optimization>
-      <PreprocessorDefinitions>NDEBUG;WIN32;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+      <PreprocessorDefinitions>NDEBUG;WIN32;_CRT_SECURE_NO_WARNINGS;HAS_LIBFLAC</PreprocessorDefinitions>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <StringPooling>true</StringPooling>
@@ -178,7 +178,7 @@
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
     <ClCompile>
       <WarningLevel>Level4</WarningLevel>
-      <PreprocessorDefinitions>_CRTDBG_MAP_ALLOC;DEBUG;_DEBUG;WIN32;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+      <PreprocessorDefinitions>_CRTDBG_MAP_ALLOC;DEBUG;_DEBUG;WIN32;_CRT_SECURE_NO_WARNINGS;HAS_LIBFLAC</PreprocessorDefinitions>
       <EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
       <TreatWChar_tAsBuiltInType>false</TreatWChar_tAsBuiltInType>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
@@ -207,7 +207,7 @@
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
     <ClCompile>
       <WarningLevel>Level4</WarningLevel>
-      <PreprocessorDefinitions>_CRTDBG_MAP_ALLOC;DEBUG;_DEBUG;WIN32;_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
+      <PreprocessorDefinitions>_CRTDBG_MAP_ALLOC;DEBUG;_DEBUG;WIN32;_CRT_SECURE_NO_WARNINGS;HAS_LIBFLAC</PreprocessorDefinitions>
       <OmitFramePointers>false</OmitFramePointers>
       <TreatWChar_tAsBuiltInType>false</TreatWChar_tAsBuiltInType>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
@@ -242,6 +242,10 @@
     <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="..\..\src\modloaders\pt2_load_mod15.h" />
+    <ClInclude Include="..\..\src\modloaders\pt2_load_mod31.h" />
+    <ClInclude Include="..\..\src\modloaders\pt2_pp_unpack.h" />
+    <ClInclude Include="..\..\src\modloaders\pt2_xpk_unpack.h" />
     <ClInclude Include="..\..\src\pt2_askbox.h" />
     <ClInclude Include="..\..\src\pt2_audio.h" />
     <ClInclude Include="..\..\src\pt2_blep.h" />
@@ -277,7 +281,6 @@
     <ClInclude Include="..\..\src\pt2_textout.h" />
     <ClInclude Include="..\..\src\pt2_unicode.h" />
     <ClInclude Include="..\..\src\pt2_visuals.h" />
-    <ClInclude Include="..\..\src\pt2_xpk.h" />
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\..\src\gfx\pt2_gfx_aboutscreen.c" />
@@ -294,6 +297,23 @@
     <ClCompile Include="..\..\src\gfx\pt2_gfx_spectrum.c" />
     <ClCompile Include="..\..\src\gfx\pt2_gfx_tracker.c" />
     <ClCompile Include="..\..\src\gfx\pt2_gfx_vumeter.c" />
+    <ClCompile Include="..\..\src\libflac\bitmath.c" />
+    <ClCompile Include="..\..\src\libflac\bitreader.c" />
+    <ClCompile Include="..\..\src\libflac\crc.c" />
+    <ClCompile Include="..\..\src\libflac\fixed.c" />
+    <ClCompile Include="..\..\src\libflac\format.c" />
+    <ClCompile Include="..\..\src\libflac\lpc.c" />
+    <ClCompile Include="..\..\src\libflac\md5.c" />
+    <ClCompile Include="..\..\src\libflac\memory.c" />
+    <ClCompile Include="..\..\src\libflac\metadata_iterators.c" />
+    <ClCompile Include="..\..\src\libflac\metadata_object.c" />
+    <ClCompile Include="..\..\src\libflac\stream_decoder.c" />
+    <ClCompile Include="..\..\src\libflac\window.c" />
+    <ClCompile Include="..\..\src\libflac\windows_unicode_filenames.c" />
+    <ClCompile Include="..\..\src\modloaders\pt2_load_mod15.c" />
+    <ClCompile Include="..\..\src\modloaders\pt2_load_mod31.c" />
+    <ClCompile Include="..\..\src\modloaders\pt2_pp_unpack.c" />
+    <ClCompile Include="..\..\src\modloaders\pt2_xpk_unpack.c" />
     <ClCompile Include="..\..\src\pt2_askbox.c" />
     <ClCompile Include="..\..\src\pt2_audio.c" />
     <ClCompile Include="..\..\src\pt2_blep.c" />
@@ -329,7 +349,11 @@
     <ClCompile Include="..\..\src\pt2_textout.c" />
     <ClCompile Include="..\..\src\pt2_unicode.c" />
     <ClCompile Include="..\..\src\pt2_visuals.c" />
-    <ClCompile Include="..\..\src\pt2_xpk.c" />
+    <ClCompile Include="..\..\src\smploaders\pt2_load_aiff.c" />
+    <ClCompile Include="..\..\src\smploaders\pt2_load_flac.c" />
+    <ClCompile Include="..\..\src\smploaders\pt2_load_iff.c" />
+    <ClCompile Include="..\..\src\smploaders\pt2_load_raw.c" />
+    <ClCompile Include="..\..\src\smploaders\pt2_load_wav.c" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="..\..\src\pt2-clone.rc">
--- a/vs2019_project/pt2-clone/pt2-clone.vcxproj.filters
+++ b/vs2019_project/pt2-clone/pt2-clone.vcxproj.filters
@@ -7,6 +7,15 @@
     <Filter Include="headers">
       <UniqueIdentifier>{d92546b9-e457-49e3-83c0-5826b29679ee}</UniqueIdentifier>
     </Filter>
+    <Filter Include="modloaders">
+      <UniqueIdentifier>{4edd2c33-3edd-4892-ad94-f40d3fadc82a}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="smploaders">
+      <UniqueIdentifier>{962f7c81-1341-453b-a297-c8364806f7f6}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="libflac">
+      <UniqueIdentifier>{5d2aea95-3dd5-40ab-8051-220433bcd953}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\src\pt2_audio.h">
@@ -105,9 +114,6 @@
     <ClInclude Include="..\..\src\pt2_hpc.h">
       <Filter>headers</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\src\pt2_xpk.h">
-      <Filter>headers</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\src\pt2_askbox.h">
       <Filter>headers</Filter>
     </ClInclude>
@@ -117,6 +123,18 @@
     <ClInclude Include="..\..\src\pt2_paula.h">
       <Filter>headers</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\src\modloaders\pt2_pp_unpack.h">
+      <Filter>modloaders</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\modloaders\pt2_xpk_unpack.h">
+      <Filter>modloaders</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\modloaders\pt2_load_mod31.h">
+      <Filter>modloaders</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\src\modloaders\pt2_load_mod15.h">
+      <Filter>modloaders</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\..\src\pt2_audio.c" />
@@ -194,9 +212,74 @@
     <ClCompile Include="..\..\src\pt2_downsample2x.c" />
     <ClCompile Include="..\..\src\pt2_math.c" />
     <ClCompile Include="..\..\src\pt2_hpc.c" />
-    <ClCompile Include="..\..\src\pt2_xpk.c" />
     <ClCompile Include="..\..\src\pt2_askbox.c" />
     <ClCompile Include="..\..\src\pt2_paula.c" />
+    <ClCompile Include="..\..\src\modloaders\pt2_pp_unpack.c">
+      <Filter>modloaders</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\modloaders\pt2_xpk_unpack.c">
+      <Filter>modloaders</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\modloaders\pt2_load_mod15.c">
+      <Filter>modloaders</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\modloaders\pt2_load_mod31.c">
+      <Filter>modloaders</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\smploaders\pt2_load_iff.c">
+      <Filter>smploaders</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\smploaders\pt2_load_raw.c">
+      <Filter>smploaders</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\smploaders\pt2_load_aiff.c">
+      <Filter>smploaders</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\smploaders\pt2_load_wav.c">
+      <Filter>smploaders</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\smploaders\pt2_load_flac.c">
+      <Filter>smploaders</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\libflac\bitmath.c">
+      <Filter>libflac</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\libflac\bitreader.c">
+      <Filter>libflac</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\libflac\crc.c">
+      <Filter>libflac</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\libflac\fixed.c">
+      <Filter>libflac</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\libflac\format.c">
+      <Filter>libflac</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\libflac\lpc.c">
+      <Filter>libflac</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\libflac\md5.c">
+      <Filter>libflac</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\libflac\memory.c">
+      <Filter>libflac</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\libflac\metadata_iterators.c">
+      <Filter>libflac</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\libflac\metadata_object.c">
+      <Filter>libflac</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\libflac\stream_decoder.c">
+      <Filter>libflac</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\libflac\window.c">
+      <Filter>libflac</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\libflac\windows_unicode_filenames.c">
+      <Filter>libflac</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="..\..\src\pt2-clone.rc" />
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_assert.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_assert.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -125,12 +125,10 @@
     const struct SDL_AssertData *next;
 } SDL_AssertData;
 
-#if (SDL_ASSERT_LEVEL > 0)
-
 /* Never call this directly. Use the SDL_assert* macros. */
 extern DECLSPEC SDL_AssertState SDLCALL SDL_ReportAssertion(SDL_AssertData *,
-                                                             const char *,
-                                                             const char *, int)
+                                                            const char *,
+                                                            const char *, int)
 #if defined(__clang__)
 #if __has_feature(attribute_analyzer_noreturn)
 /* this tells Clang's static analysis that we're a custom assert function,
@@ -151,9 +149,7 @@
 #define SDL_enabled_assert(condition) \
     do { \
         while ( !(condition) ) { \
-            static struct SDL_AssertData sdl_assert_data = { \
-                0, 0, #condition, 0, 0, 0, 0 \
-            }; \
+            static struct SDL_AssertData sdl_assert_data = { 0, 0, #condition, 0, 0, 0, 0 }; \
             const SDL_AssertState sdl_assert_state = SDL_ReportAssertion(&sdl_assert_data, SDL_FUNCTION, SDL_FILE, SDL_LINE); \
             if (sdl_assert_state == SDL_ASSERTION_RETRY) { \
                 continue; /* go again. */ \
@@ -163,8 +159,6 @@
             break; /* not retrying. */ \
         } \
     } while (SDL_NULL_WHILE_LOOP_CONDITION)
-
-#endif  /* enabled assertions support code */
 
 /* Enable various levels of assertions. */
 #if SDL_ASSERT_LEVEL == 0   /* assertions disabled */
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_atomic.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_atomic.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_audio.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_audio.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_bits.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_bits.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_blendmode.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_blendmode.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_clipboard.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_clipboard.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_config.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_config.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_config.h.cmake
+++ /dev/null
@@ -1,445 +1,0 @@
-/*
-  Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef SDL_config_h_
-#define SDL_config_h_
-
-/**
- *  \file SDL_config.h.in
- *
- *  This is a set of defines to configure the SDL features
- */
-
-/* General platform specific identifiers */
-#include "SDL_platform.h"
-
-/* C language features */
-#cmakedefine const @HAVE_CONST@
-#cmakedefine inline @HAVE_INLINE@
-#cmakedefine volatile @HAVE_VOLATILE@
-
-/* C datatypes */
-/* Define SIZEOF_VOIDP for 64/32 architectures */
-#ifdef __LP64__
-#define SIZEOF_VOIDP 8
-#else
-#define SIZEOF_VOIDP 4
-#endif
-
-#cmakedefine HAVE_GCC_ATOMICS @HAVE_GCC_ATOMICS@
-#cmakedefine HAVE_GCC_SYNC_LOCK_TEST_AND_SET @HAVE_GCC_SYNC_LOCK_TEST_AND_SET@
-
-#cmakedefine HAVE_D3D_H @HAVE_D3D_H@
-#cmakedefine HAVE_D3D11_H @HAVE_D3D11_H@
-#cmakedefine HAVE_DDRAW_H @HAVE_DDRAW_H@
-#cmakedefine HAVE_DSOUND_H @HAVE_DSOUND_H@
-#cmakedefine HAVE_DINPUT_H @HAVE_DINPUT_H@
-#cmakedefine HAVE_XAUDIO2_H @HAVE_XAUDIO2_H@
-#cmakedefine HAVE_XINPUT_H @HAVE_XINPUT_H@
-#cmakedefine HAVE_DXGI_H @HAVE_DXGI_H@
-#cmakedefine HAVE_XINPUT_GAMEPAD_EX @HAVE_XINPUT_GAMEPAD_EX@
-#cmakedefine HAVE_XINPUT_STATE_EX @HAVE_XINPUT_STATE_EX@
-
-/* Comment this if you want to build without any C library requirements */
-#cmakedefine HAVE_LIBC 1
-#if HAVE_LIBC
-
-/* Useful headers */
-#cmakedefine HAVE_ALLOCA_H 1
-#cmakedefine HAVE_SYS_TYPES_H 1
-#cmakedefine HAVE_STDIO_H 1
-#cmakedefine STDC_HEADERS 1
-#cmakedefine HAVE_STDLIB_H 1
-#cmakedefine HAVE_STDARG_H 1
-#cmakedefine HAVE_MALLOC_H 1
-#cmakedefine HAVE_MEMORY_H 1
-#cmakedefine HAVE_STRING_H 1
-#cmakedefine HAVE_STRINGS_H 1
-#cmakedefine HAVE_WCHAR_H 1
-#cmakedefine HAVE_INTTYPES_H 1
-#cmakedefine HAVE_STDINT_H 1
-#cmakedefine HAVE_CTYPE_H 1
-#cmakedefine HAVE_MATH_H 1
-#cmakedefine HAVE_ICONV_H 1
-#cmakedefine HAVE_SIGNAL_H 1
-#cmakedefine HAVE_ALTIVEC_H 1
-#cmakedefine HAVE_PTHREAD_NP_H 1
-#cmakedefine HAVE_LIBUDEV_H 1
-#cmakedefine HAVE_DBUS_DBUS_H 1
-#cmakedefine HAVE_IBUS_IBUS_H 1
-#cmakedefine HAVE_FCITX_FRONTEND_H 1
-#cmakedefine HAVE_LIBSAMPLERATE_H 1
-
-/* C library functions */
-#cmakedefine HAVE_MALLOC 1
-#cmakedefine HAVE_CALLOC 1
-#cmakedefine HAVE_REALLOC 1
-#cmakedefine HAVE_FREE 1
-#cmakedefine HAVE_ALLOCA 1
-#ifndef __WIN32__ /* Don't use C runtime versions of these on Windows */
-#cmakedefine HAVE_GETENV 1
-#cmakedefine HAVE_SETENV 1
-#cmakedefine HAVE_PUTENV 1
-#cmakedefine HAVE_UNSETENV 1
-#endif
-#cmakedefine HAVE_QSORT 1
-#cmakedefine HAVE_ABS 1
-#cmakedefine HAVE_BCOPY 1
-#cmakedefine HAVE_MEMSET 1
-#cmakedefine HAVE_MEMCPY 1
-#cmakedefine HAVE_MEMMOVE 1
-#cmakedefine HAVE_MEMCMP 1
-#cmakedefine HAVE_WCSLEN 1
-#cmakedefine HAVE_WCSLCPY 1
-#cmakedefine HAVE_WCSLCAT 1
-#cmakedefine HAVE_WCSCMP 1
-#cmakedefine HAVE_STRLEN 1
-#cmakedefine HAVE_STRLCPY 1
-#cmakedefine HAVE_STRLCAT 1
-#cmakedefine HAVE_STRDUP 1
-#cmakedefine HAVE__STRREV 1
-#cmakedefine HAVE__STRUPR 1
-#cmakedefine HAVE__STRLWR 1
-#cmakedefine HAVE_INDEX 1
-#cmakedefine HAVE_RINDEX 1
-#cmakedefine HAVE_STRCHR 1
-#cmakedefine HAVE_STRRCHR 1
-#cmakedefine HAVE_STRSTR 1
-#cmakedefine HAVE_ITOA 1
-#cmakedefine HAVE__LTOA 1
-#cmakedefine HAVE__UITOA 1
-#cmakedefine HAVE__ULTOA 1
-#cmakedefine HAVE_STRTOL 1
-#cmakedefine HAVE_STRTOUL 1
-#cmakedefine HAVE__I64TOA 1
-#cmakedefine HAVE__UI64TOA 1
-#cmakedefine HAVE_STRTOLL 1
-#cmakedefine HAVE_STRTOULL 1
-#cmakedefine HAVE_STRTOD 1
-#cmakedefine HAVE_ATOI 1
-#cmakedefine HAVE_ATOF 1
-#cmakedefine HAVE_STRCMP 1
-#cmakedefine HAVE_STRNCMP 1
-#cmakedefine HAVE__STRICMP 1
-#cmakedefine HAVE_STRCASECMP 1
-#cmakedefine HAVE__STRNICMP 1
-#cmakedefine HAVE_STRNCASECMP 1
-#cmakedefine HAVE_VSSCANF 1
-#cmakedefine HAVE_VSNPRINTF 1
-#cmakedefine HAVE_M_PI 1
-#cmakedefine HAVE_ATAN 1
-#cmakedefine HAVE_ATAN2 1
-#cmakedefine HAVE_ACOS 1
-#cmakedefine HAVE_ASIN 1
-#cmakedefine HAVE_CEIL 1
-#cmakedefine HAVE_COPYSIGN 1
-#cmakedefine HAVE_COS 1
-#cmakedefine HAVE_COSF 1
-#cmakedefine HAVE_FABS 1
-#cmakedefine HAVE_FLOOR 1
-#cmakedefine HAVE_LOG 1
-#cmakedefine HAVE_POW 1
-#cmakedefine HAVE_SCALBN 1
-#cmakedefine HAVE_SIN 1
-#cmakedefine HAVE_SINF 1
-#cmakedefine HAVE_SQRT 1
-#cmakedefine HAVE_SQRTF 1
-#cmakedefine HAVE_TAN 1
-#cmakedefine HAVE_TANF 1
-#cmakedefine HAVE_FOPEN64 1
-#cmakedefine HAVE_FSEEKO 1
-#cmakedefine HAVE_FSEEKO64 1
-#cmakedefine HAVE_SIGACTION 1
-#cmakedefine HAVE_SA_SIGACTION 1
-#cmakedefine HAVE_SETJMP 1
-#cmakedefine HAVE_NANOSLEEP 1
-#cmakedefine HAVE_SYSCONF 1
-#cmakedefine HAVE_SYSCTLBYNAME 1
-#cmakedefine HAVE_CLOCK_GETTIME 1
-#cmakedefine HAVE_GETPAGESIZE 1
-#cmakedefine HAVE_MPROTECT 1
-#cmakedefine HAVE_ICONV 1
-#cmakedefine HAVE_PTHREAD_SETNAME_NP 1
-#cmakedefine HAVE_PTHREAD_SET_NAME_NP 1
-#cmakedefine HAVE_SEM_TIMEDWAIT 1
-#cmakedefine HAVE_GETAUXVAL 1
-#cmakedefine HAVE_POLL 1
-
-#elif __WIN32__
-#cmakedefine HAVE_STDARG_H 1
-#cmakedefine HAVE_STDDEF_H 1
-#else
-/* We may need some replacement for stdarg.h here */
-#include <stdarg.h>
-#endif /* HAVE_LIBC */
-
-/* SDL internal assertion support */
-#cmakedefine SDL_DEFAULT_ASSERT_LEVEL @SDL_DEFAULT_ASSERT_LEVEL@
-
-/* Allow disabling of core subsystems */
-#cmakedefine SDL_ATOMIC_DISABLED @SDL_ATOMIC_DISABLED@
-#cmakedefine SDL_AUDIO_DISABLED @SDL_AUDIO_DISABLED@
-#cmakedefine SDL_CPUINFO_DISABLED @SDL_CPUINFO_DISABLED@
-#cmakedefine SDL_EVENTS_DISABLED @SDL_EVENTS_DISABLED@
-#cmakedefine SDL_FILE_DISABLED @SDL_FILE_DISABLED@
-#cmakedefine SDL_JOYSTICK_DISABLED @SDL_JOYSTICK_DISABLED@
-#cmakedefine SDL_HAPTIC_DISABLED @SDL_HAPTIC_DISABLED@
-#cmakedefine SDL_LOADSO_DISABLED @SDL_LOADSO_DISABLED@
-#cmakedefine SDL_RENDER_DISABLED @SDL_RENDER_DISABLED@
-#cmakedefine SDL_THREADS_DISABLED @SDL_THREADS_DISABLED@
-#cmakedefine SDL_TIMERS_DISABLED @SDL_TIMERS_DISABLED@
-#cmakedefine SDL_VIDEO_DISABLED @SDL_VIDEO_DISABLED@
-#cmakedefine SDL_POWER_DISABLED @SDL_POWER_DISABLED@
-#cmakedefine SDL_FILESYSTEM_DISABLED @SDL_FILESYSTEM_DISABLED@
-
-/* Enable various audio drivers */
-#cmakedefine SDL_AUDIO_DRIVER_ALSA @SDL_AUDIO_DRIVER_ALSA@
-#cmakedefine SDL_AUDIO_DRIVER_ALSA_DYNAMIC @SDL_AUDIO_DRIVER_ALSA_DYNAMIC@
-#cmakedefine SDL_AUDIO_DRIVER_ANDROID @SDL_AUDIO_DRIVER_ANDROID@
-#cmakedefine SDL_AUDIO_DRIVER_ARTS @SDL_AUDIO_DRIVER_ARTS@
-#cmakedefine SDL_AUDIO_DRIVER_ARTS_DYNAMIC @SDL_AUDIO_DRIVER_ARTS_DYNAMIC@
-#cmakedefine SDL_AUDIO_DRIVER_COREAUDIO @SDL_AUDIO_DRIVER_COREAUDIO@
-#cmakedefine SDL_AUDIO_DRIVER_DISK @SDL_AUDIO_DRIVER_DISK@
-#cmakedefine SDL_AUDIO_DRIVER_DSOUND @SDL_AUDIO_DRIVER_DSOUND@
-#cmakedefine SDL_AUDIO_DRIVER_DUMMY @SDL_AUDIO_DRIVER_DUMMY@
-#cmakedefine SDL_AUDIO_DRIVER_EMSCRIPTEN @SDL_AUDIO_DRIVER_EMSCRIPTEN@
-#cmakedefine SDL_AUDIO_DRIVER_ESD @SDL_AUDIO_DRIVER_ESD@
-#cmakedefine SDL_AUDIO_DRIVER_ESD_DYNAMIC @SDL_AUDIO_DRIVER_ESD_DYNAMIC@
-#cmakedefine SDL_AUDIO_DRIVER_FUSIONSOUND @SDL_AUDIO_DRIVER_FUSIONSOUND@
-#cmakedefine SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC @SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC@
-#cmakedefine SDL_AUDIO_DRIVER_HAIKU @SDL_AUDIO_DRIVER_HAIKU@
-#cmakedefine SDL_AUDIO_DRIVER_JACK @SDL_AUDIO_DRIVER_JACK@
-#cmakedefine SDL_AUDIO_DRIVER_JACK_DYNAMIC @SDL_AUDIO_DRIVER_JACK_DYNAMIC@
-#cmakedefine SDL_AUDIO_DRIVER_NAS @SDL_AUDIO_DRIVER_NAS@
-#cmakedefine SDL_AUDIO_DRIVER_NAS_DYNAMIC @SDL_AUDIO_DRIVER_NAS_DYNAMIC@
-#cmakedefine SDL_AUDIO_DRIVER_NETBSD @SDL_AUDIO_DRIVER_NETBSD@
-#cmakedefine SDL_AUDIO_DRIVER_OSS @SDL_AUDIO_DRIVER_OSS@
-#cmakedefine SDL_AUDIO_DRIVER_OSS_SOUNDCARD_H @SDL_AUDIO_DRIVER_OSS_SOUNDCARD_H@
-#cmakedefine SDL_AUDIO_DRIVER_PAUDIO @SDL_AUDIO_DRIVER_PAUDIO@
-#cmakedefine SDL_AUDIO_DRIVER_PULSEAUDIO @SDL_AUDIO_DRIVER_PULSEAUDIO@
-#cmakedefine SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC @SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC@
-#cmakedefine SDL_AUDIO_DRIVER_QSA @SDL_AUDIO_DRIVER_QSA@
-#cmakedefine SDL_AUDIO_DRIVER_SNDIO @SDL_AUDIO_DRIVER_SNDIO@
-#cmakedefine SDL_AUDIO_DRIVER_SNDIO_DYNAMIC @SDL_AUDIO_DRIVER_SNDIO_DYNAMIC@
-#cmakedefine SDL_AUDIO_DRIVER_SUNAUDIO @SDL_AUDIO_DRIVER_SUNAUDIO@
-#cmakedefine SDL_AUDIO_DRIVER_WASAPI @SDL_AUDIO_DRIVER_WASAPI@
-#cmakedefine SDL_AUDIO_DRIVER_WINMM @SDL_AUDIO_DRIVER_WINMM@
-#cmakedefine SDL_AUDIO_DRIVER_XAUDIO2 @SDL_AUDIO_DRIVER_XAUDIO2@
-
-/* Enable various input drivers */
-#cmakedefine SDL_INPUT_LINUXEV @SDL_INPUT_LINUXEV@
-#cmakedefine SDL_INPUT_LINUXKD @SDL_INPUT_LINUXKD@
-#cmakedefine SDL_INPUT_TSLIB @SDL_INPUT_TSLIB@
-#cmakedefine SDL_JOYSTICK_ANDROID @SDL_JOYSTICK_ANDROID@
-#cmakedefine SDL_JOYSTICK_HAIKU @SDL_JOYSTICK_HAIKU@
-#cmakedefine SDL_JOYSTICK_DINPUT @SDL_JOYSTICK_DINPUT@
-#cmakedefine SDL_JOYSTICK_XINPUT @SDL_JOYSTICK_XINPUT@
-#cmakedefine SDL_JOYSTICK_DUMMY @SDL_JOYSTICK_DUMMY@
-#cmakedefine SDL_JOYSTICK_IOKIT @SDL_JOYSTICK_IOKIT@
-#cmakedefine SDL_JOYSTICK_MFI @SDL_JOYSTICK_MFI@
-#cmakedefine SDL_JOYSTICK_LINUX @SDL_JOYSTICK_LINUX@
-#cmakedefine SDL_JOYSTICK_WINMM @SDL_JOYSTICK_WINMM@
-#cmakedefine SDL_JOYSTICK_USBHID @SDL_JOYSTICK_USBHID@
-#cmakedefine SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H @SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H@
-#cmakedefine SDL_JOYSTICK_EMSCRIPTEN @SDL_JOYSTICK_EMSCRIPTEN@
-#cmakedefine SDL_HAPTIC_DUMMY @SDL_HAPTIC_DUMMY@
-#cmakedefine SDL_HAPTIC_LINUX @SDL_HAPTIC_LINUX@
-#cmakedefine SDL_HAPTIC_IOKIT @SDL_HAPTIC_IOKIT@
-#cmakedefine SDL_HAPTIC_DINPUT @SDL_HAPTIC_DINPUT@
-#cmakedefine SDL_HAPTIC_XINPUT @SDL_HAPTIC_XINPUT@
-#cmakedefine SDL_HAPTIC_ANDROID @SDL_HAPTIC_ANDROID@
-
-/* Enable various shared object loading systems */
-#cmakedefine SDL_LOADSO_DLOPEN @SDL_LOADSO_DLOPEN@
-#cmakedefine SDL_LOADSO_DUMMY @SDL_LOADSO_DUMMY@
-#cmakedefine SDL_LOADSO_LDG @SDL_LOADSO_LDG@
-#cmakedefine SDL_LOADSO_WINDOWS @SDL_LOADSO_WINDOWS@
-
-/* Enable various threading systems */
-#cmakedefine SDL_THREAD_PTHREAD @SDL_THREAD_PTHREAD@
-#cmakedefine SDL_THREAD_PTHREAD_RECURSIVE_MUTEX @SDL_THREAD_PTHREAD_RECURSIVE_MUTEX@
-#cmakedefine SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP @SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP@
-#cmakedefine SDL_THREAD_WINDOWS @SDL_THREAD_WINDOWS@
-
-/* Enable various timer systems */
-#cmakedefine SDL_TIMER_HAIKU @SDL_TIMER_HAIKU@
-#cmakedefine SDL_TIMER_DUMMY @SDL_TIMER_DUMMY@
-#cmakedefine SDL_TIMER_UNIX @SDL_TIMER_UNIX@
-#cmakedefine SDL_TIMER_WINDOWS @SDL_TIMER_WINDOWS@
-#cmakedefine SDL_TIMER_WINCE @SDL_TIMER_WINCE@
-
-/* Enable various video drivers */
-#cmakedefine SDL_VIDEO_DRIVER_ANDROID @SDL_VIDEO_DRIVER_ANDROID@
-#cmakedefine SDL_VIDEO_DRIVER_HAIKU @SDL_VIDEO_DRIVER_HAIKU@
-#cmakedefine SDL_VIDEO_DRIVER_COCOA @SDL_VIDEO_DRIVER_COCOA@
-#cmakedefine SDL_VIDEO_DRIVER_DIRECTFB @SDL_VIDEO_DRIVER_DIRECTFB@
-#cmakedefine SDL_VIDEO_DRIVER_DIRECTFB_DYNAMIC @SDL_VIDEO_DRIVER_DIRECTFB_DYNAMIC@
-#cmakedefine SDL_VIDEO_DRIVER_DUMMY @SDL_VIDEO_DRIVER_DUMMY@
-#cmakedefine SDL_VIDEO_DRIVER_WINDOWS @SDL_VIDEO_DRIVER_WINDOWS@
-#cmakedefine SDL_VIDEO_DRIVER_WAYLAND @SDL_VIDEO_DRIVER_WAYLAND@
-#cmakedefine SDL_VIDEO_DRIVER_RPI @SDL_VIDEO_DRIVER_RPI@
-#cmakedefine SDL_VIDEO_DRIVER_VIVANTE @SDL_VIDEO_DRIVER_VIVANTE@
-#cmakedefine SDL_VIDEO_DRIVER_VIVANTE_VDK @SDL_VIDEO_DRIVER_VIVANTE_VDK@
-
-#cmakedefine SDL_VIDEO_DRIVER_KMSDRM @SDL_VIDEO_DRIVER_KMSDRM@
-#cmakedefine SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC @SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC@
-#cmakedefine SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC_GBM @SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC_GBM@
-
-#cmakedefine SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH @SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH@
-#cmakedefine SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC @SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC@
-#cmakedefine SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL @SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL@
-#cmakedefine SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR @SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR@
-#cmakedefine SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON @SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON@
-
-#cmakedefine SDL_VIDEO_DRIVER_MIR @SDL_VIDEO_DRIVER_MIR@
-#cmakedefine SDL_VIDEO_DRIVER_MIR_DYNAMIC @SDL_VIDEO_DRIVER_MIR_DYNAMIC@
-#cmakedefine SDL_VIDEO_DRIVER_MIR_DYNAMIC_XKBCOMMON @SDL_VIDEO_DRIVER_MIR_DYNAMIC_XKBCOMMON@
-#cmakedefine SDL_VIDEO_DRIVER_EMSCRIPTEN @SDL_VIDEO_DRIVER_EMSCRIPTEN@
-#cmakedefine SDL_VIDEO_DRIVER_X11 @SDL_VIDEO_DRIVER_X11@
-#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC @SDL_VIDEO_DRIVER_X11_DYNAMIC@
-#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT @SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT@
-#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XCURSOR @SDL_VIDEO_DRIVER_X11_DYNAMIC_XCURSOR@
-#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XINERAMA @SDL_VIDEO_DRIVER_X11_DYNAMIC_XINERAMA@
-#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2 @SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2@
-#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR @SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR@
-#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS @SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS@
-#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XVIDMODE @SDL_VIDEO_DRIVER_X11_DYNAMIC_XVIDMODE@
-#cmakedefine SDL_VIDEO_DRIVER_X11_XCURSOR @SDL_VIDEO_DRIVER_X11_XCURSOR@
-#cmakedefine SDL_VIDEO_DRIVER_X11_XDBE @SDL_VIDEO_DRIVER_X11_XDBE@
-#cmakedefine SDL_VIDEO_DRIVER_X11_XINERAMA @SDL_VIDEO_DRIVER_X11_XINERAMA@
-#cmakedefine SDL_VIDEO_DRIVER_X11_XINPUT2 @SDL_VIDEO_DRIVER_X11_XINPUT2@
-#cmakedefine SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH @SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH@
-#cmakedefine SDL_VIDEO_DRIVER_X11_XRANDR @SDL_VIDEO_DRIVER_X11_XRANDR@
-#cmakedefine SDL_VIDEO_DRIVER_X11_XSCRNSAVER @SDL_VIDEO_DRIVER_X11_XSCRNSAVER@
-#cmakedefine SDL_VIDEO_DRIVER_X11_XSHAPE @SDL_VIDEO_DRIVER_X11_XSHAPE@
-#cmakedefine SDL_VIDEO_DRIVER_X11_XVIDMODE @SDL_VIDEO_DRIVER_X11_XVIDMODE@
-#cmakedefine SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS @SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS@
-#cmakedefine SDL_VIDEO_DRIVER_X11_CONST_PARAM_XEXTADDDISPLAY @SDL_VIDEO_DRIVER_X11_CONST_PARAM_XEXTADDDISPLAY@
-#cmakedefine SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM @SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM@
-
-#cmakedefine SDL_VIDEO_RENDER_D3D @SDL_VIDEO_RENDER_D3D@
-#cmakedefine SDL_VIDEO_RENDER_D3D11 @SDL_VIDEO_RENDER_D3D11@
-#cmakedefine SDL_VIDEO_RENDER_OGL @SDL_VIDEO_RENDER_OGL@
-#cmakedefine SDL_VIDEO_RENDER_OGL_ES @SDL_VIDEO_RENDER_OGL_ES@
-#cmakedefine SDL_VIDEO_RENDER_OGL_ES2 @SDL_VIDEO_RENDER_OGL_ES2@
-#cmakedefine SDL_VIDEO_RENDER_DIRECTFB @SDL_VIDEO_RENDER_DIRECTFB@
-
-/* Enable OpenGL support */
-#cmakedefine SDL_VIDEO_OPENGL @SDL_VIDEO_OPENGL@
-#cmakedefine SDL_VIDEO_OPENGL_ES @SDL_VIDEO_OPENGL_ES@
-#cmakedefine SDL_VIDEO_OPENGL_ES2 @SDL_VIDEO_OPENGL_ES2@
-#cmakedefine SDL_VIDEO_OPENGL_BGL @SDL_VIDEO_OPENGL_BGL@
-#cmakedefine SDL_VIDEO_OPENGL_CGL @SDL_VIDEO_OPENGL_CGL@
-#cmakedefine SDL_VIDEO_OPENGL_GLX @SDL_VIDEO_OPENGL_GLX@
-#cmakedefine SDL_VIDEO_OPENGL_WGL @SDL_VIDEO_OPENGL_WGL@
-#cmakedefine SDL_VIDEO_OPENGL_EGL @SDL_VIDEO_OPENGL_EGL@
-#cmakedefine SDL_VIDEO_OPENGL_OSMESA @SDL_VIDEO_OPENGL_OSMESA@
-#cmakedefine SDL_VIDEO_OPENGL_OSMESA_DYNAMIC @SDL_VIDEO_OPENGL_OSMESA_DYNAMIC@
-
-/* Enable Vulkan support */
-#cmakedefine SDL_VIDEO_VULKAN @SDL_VIDEO_VULKAN@
-
-/* Enable system power support */
-#cmakedefine SDL_POWER_ANDROID @SDL_POWER_ANDROID@
-#cmakedefine SDL_POWER_LINUX @SDL_POWER_LINUX@
-#cmakedefine SDL_POWER_WINDOWS @SDL_POWER_WINDOWS@
-#cmakedefine SDL_POWER_MACOSX @SDL_POWER_MACOSX@
-#cmakedefine SDL_POWER_HAIKU @SDL_POWER_HAIKU@
-#cmakedefine SDL_POWER_EMSCRIPTEN @SDL_POWER_EMSCRIPTEN@
-#cmakedefine SDL_POWER_HARDWIRED @SDL_POWER_HARDWIRED@
-
-/* Enable system filesystem support */
-#cmakedefine SDL_FILESYSTEM_ANDROID @SDL_FILESYSTEM_ANDROID@
-#cmakedefine SDL_FILESYSTEM_HAIKU @SDL_FILESYSTEM_HAIKU@
-#cmakedefine SDL_FILESYSTEM_COCOA @SDL_FILESYSTEM_COCOA@
-#cmakedefine SDL_FILESYSTEM_DUMMY @SDL_FILESYSTEM_DUMMY@
-#cmakedefine SDL_FILESYSTEM_UNIX @SDL_FILESYSTEM_UNIX@
-#cmakedefine SDL_FILESYSTEM_WINDOWS @SDL_FILESYSTEM_WINDOWS@
-#cmakedefine SDL_FILESYSTEM_EMSCRIPTEN @SDL_FILESYSTEM_EMSCRIPTEN@
-
-/* Enable assembly routines */
-#cmakedefine SDL_ASSEMBLY_ROUTINES @SDL_ASSEMBLY_ROUTINES@
-#cmakedefine SDL_ALTIVEC_BLITTERS @SDL_ALTIVEC_BLITTERS@
-
-/* Enable dynamic libsamplerate support */
-#cmakedefine SDL_LIBSAMPLERATE_DYNAMIC @SDL_LIBSAMPLERATE_DYNAMIC@
-
-/* Platform specific definitions */
-#if !defined(__WIN32__)
-#  if !defined(_STDINT_H_) && !defined(_STDINT_H) && !defined(HAVE_STDINT_H) && !defined(_HAVE_STDINT_H)
-typedef unsigned int size_t;
-typedef signed char int8_t;
-typedef unsigned char uint8_t;
-typedef signed short int16_t;
-typedef unsigned short uint16_t;
-typedef signed int int32_t;
-typedef unsigned int uint32_t;
-typedef signed long long int64_t;
-typedef unsigned long long uint64_t;
-typedef unsigned long uintptr_t;
-#  endif /* if (stdint.h isn't available) */
-#else /* __WIN32__ */
-#  if !defined(_STDINT_H_) && !defined(HAVE_STDINT_H) && !defined(_HAVE_STDINT_H)
-#    if defined(__GNUC__) || defined(__DMC__) || defined(__WATCOMC__)
-#define HAVE_STDINT_H	1
-#    elif defined(_MSC_VER)
-typedef signed __int8 int8_t;
-typedef unsigned __int8 uint8_t;
-typedef signed __int16 int16_t;
-typedef unsigned __int16 uint16_t;
-typedef signed __int32 int32_t;
-typedef unsigned __int32 uint32_t;
-typedef signed __int64 int64_t;
-typedef unsigned __int64 uint64_t;
-#      ifndef _UINTPTR_T_DEFINED
-#        ifdef  _WIN64
-typedef unsigned __int64 uintptr_t;
-#          else
-typedef unsigned int uintptr_t;
-#        endif
-#define _UINTPTR_T_DEFINED
-#      endif
-/* Older Visual C++ headers don't have the Win64-compatible typedefs... */
-#      if ((_MSC_VER <= 1200) && (!defined(DWORD_PTR)))
-#define DWORD_PTR DWORD
-#      endif
-#      if ((_MSC_VER <= 1200) && (!defined(LONG_PTR)))
-#define LONG_PTR LONG
-#      endif
-#    else /* !__GNUC__ && !_MSC_VER */
-typedef signed char int8_t;
-typedef unsigned char uint8_t;
-typedef signed short int16_t;
-typedef unsigned short uint16_t;
-typedef signed int int32_t;
-typedef unsigned int uint32_t;
-typedef signed long long int64_t;
-typedef unsigned long long uint64_t;
-#      ifndef _SIZE_T_DEFINED_
-#define _SIZE_T_DEFINED_
-typedef unsigned int size_t;
-#      endif
-typedef unsigned int uintptr_t;
-#    endif /* __GNUC__ || _MSC_VER */
-#  endif /* !_STDINT_H_ && !HAVE_STDINT_H */
-#endif /* __WIN32__ */
-
-#endif /* SDL_config_h_ */
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_config.h.in
+++ /dev/null
@@ -1,389 +1,0 @@
-/*
-  Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef SDL_config_h_
-#define SDL_config_h_
-
-/**
- *  \file SDL_config.h.in
- *
- *  This is a set of defines to configure the SDL features
- */
-
-/* General platform specific identifiers */
-#include "SDL_platform.h"
-
-/* Make sure that this isn't included by Visual C++ */
-#ifdef _MSC_VER
-#error You should run hg revert SDL_config.h 
-#endif
-
-/* C language features */
-#undef const
-#undef inline
-#undef volatile
-
-/* C datatypes */
-#ifdef __LP64__
-#define SIZEOF_VOIDP 8
-#else
-#define SIZEOF_VOIDP 4
-#endif
-#undef HAVE_GCC_ATOMICS
-#undef HAVE_GCC_SYNC_LOCK_TEST_AND_SET
-
-#undef HAVE_DDRAW_H
-#undef HAVE_DINPUT_H
-#undef HAVE_DSOUND_H
-#undef HAVE_DXGI_H
-#undef HAVE_XINPUT_H
-#undef HAVE_XINPUT_GAMEPAD_EX
-#undef HAVE_XINPUT_STATE_EX
-
-/* Comment this if you want to build without any C library requirements */
-#undef HAVE_LIBC
-#if HAVE_LIBC
-
-/* Useful headers */
-#undef HAVE_ALLOCA_H
-#undef HAVE_SYS_TYPES_H
-#undef HAVE_STDIO_H
-#undef STDC_HEADERS
-#undef HAVE_STDLIB_H
-#undef HAVE_STDARG_H
-#undef HAVE_MALLOC_H
-#undef HAVE_MEMORY_H
-#undef HAVE_STRING_H
-#undef HAVE_STRINGS_H
-#undef HAVE_WCHAR_H
-#undef HAVE_INTTYPES_H
-#undef HAVE_STDINT_H
-#undef HAVE_CTYPE_H
-#undef HAVE_MATH_H
-#undef HAVE_ICONV_H
-#undef HAVE_SIGNAL_H
-#undef HAVE_ALTIVEC_H
-#undef HAVE_PTHREAD_NP_H
-#undef HAVE_LIBUDEV_H
-#undef HAVE_DBUS_DBUS_H
-#undef HAVE_IBUS_IBUS_H
-#undef HAVE_FCITX_FRONTEND_H
-#undef HAVE_LIBSAMPLERATE_H
-
-/* C library functions */
-#undef HAVE_MALLOC
-#undef HAVE_CALLOC
-#undef HAVE_REALLOC
-#undef HAVE_FREE
-#undef HAVE_ALLOCA
-#ifndef __WIN32__ /* Don't use C runtime versions of these on Windows */
-#undef HAVE_GETENV
-#undef HAVE_SETENV
-#undef HAVE_PUTENV
-#undef HAVE_UNSETENV
-#endif
-#undef HAVE_QSORT
-#undef HAVE_ABS
-#undef HAVE_BCOPY
-#undef HAVE_MEMSET
-#undef HAVE_MEMCPY
-#undef HAVE_MEMMOVE
-#undef HAVE_MEMCMP
-#undef HAVE_WCSLEN
-#undef HAVE_WCSLCPY
-#undef HAVE_WCSLCAT
-#undef HAVE_WCSCMP
-#undef HAVE_STRLEN
-#undef HAVE_STRLCPY
-#undef HAVE_STRLCAT
-#undef HAVE_STRDUP
-#undef HAVE__STRREV
-#undef HAVE__STRUPR
-#undef HAVE__STRLWR
-#undef HAVE_INDEX
-#undef HAVE_RINDEX
-#undef HAVE_STRCHR
-#undef HAVE_STRRCHR
-#undef HAVE_STRSTR
-#undef HAVE_ITOA
-#undef HAVE__LTOA
-#undef HAVE__UITOA
-#undef HAVE__ULTOA
-#undef HAVE_STRTOL
-#undef HAVE_STRTOUL
-#undef HAVE__I64TOA
-#undef HAVE__UI64TOA
-#undef HAVE_STRTOLL
-#undef HAVE_STRTOULL
-#undef HAVE_STRTOD
-#undef HAVE_ATOI
-#undef HAVE_ATOF
-#undef HAVE_STRCMP
-#undef HAVE_STRNCMP
-#undef HAVE__STRICMP
-#undef HAVE_STRCASECMP
-#undef HAVE__STRNICMP
-#undef HAVE_STRNCASECMP
-#undef HAVE_SSCANF
-#undef HAVE_VSSCANF
-#undef HAVE_SNPRINTF
-#undef HAVE_VSNPRINTF
-#undef HAVE_M_PI
-#undef HAVE_ATAN
-#undef HAVE_ATAN2
-#undef HAVE_ACOS
-#undef HAVE_ASIN
-#undef HAVE_CEIL
-#undef HAVE_COPYSIGN
-#undef HAVE_COS
-#undef HAVE_COSF
-#undef HAVE_FABS
-#undef HAVE_FLOOR
-#undef HAVE_LOG
-#undef HAVE_POW
-#undef HAVE_SCALBN
-#undef HAVE_SIN
-#undef HAVE_SINF
-#undef HAVE_SQRT
-#undef HAVE_SQRTF
-#undef HAVE_TAN
-#undef HAVE_TANF
-#undef HAVE_FOPEN64
-#undef HAVE_FSEEKO
-#undef HAVE_FSEEKO64
-#undef HAVE_SIGACTION
-#undef HAVE_SA_SIGACTION
-#undef HAVE_SETJMP
-#undef HAVE_NANOSLEEP
-#undef HAVE_SYSCONF
-#undef HAVE_SYSCTLBYNAME
-#undef HAVE_CLOCK_GETTIME
-#undef HAVE_GETPAGESIZE
-#undef HAVE_MPROTECT
-#undef HAVE_ICONV
-#undef HAVE_PTHREAD_SETNAME_NP
-#undef HAVE_PTHREAD_SET_NAME_NP
-#undef HAVE_SEM_TIMEDWAIT
-#undef HAVE_GETAUXVAL
-#undef HAVE_POLL
-
-#else
-#define HAVE_STDARG_H   1
-#define HAVE_STDDEF_H   1
-#define HAVE_STDINT_H   1
-#endif /* HAVE_LIBC */
-
-/* SDL internal assertion support */
-#undef SDL_DEFAULT_ASSERT_LEVEL
-
-/* Allow disabling of core subsystems */
-#undef SDL_ATOMIC_DISABLED
-#undef SDL_AUDIO_DISABLED
-#undef SDL_CPUINFO_DISABLED
-#undef SDL_EVENTS_DISABLED
-#undef SDL_FILE_DISABLED
-#undef SDL_JOYSTICK_DISABLED
-#undef SDL_HAPTIC_DISABLED
-#undef SDL_LOADSO_DISABLED
-#undef SDL_RENDER_DISABLED
-#undef SDL_THREADS_DISABLED
-#undef SDL_TIMERS_DISABLED
-#undef SDL_VIDEO_DISABLED
-#undef SDL_POWER_DISABLED
-#undef SDL_FILESYSTEM_DISABLED
-
-/* Enable various audio drivers */
-#undef SDL_AUDIO_DRIVER_ALSA
-#undef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
-#undef SDL_AUDIO_DRIVER_ANDROID
-#undef SDL_AUDIO_DRIVER_ARTS
-#undef SDL_AUDIO_DRIVER_ARTS_DYNAMIC
-#undef SDL_AUDIO_DRIVER_COREAUDIO
-#undef SDL_AUDIO_DRIVER_DISK
-#undef SDL_AUDIO_DRIVER_DSOUND
-#undef SDL_AUDIO_DRIVER_DUMMY
-#undef SDL_AUDIO_DRIVER_EMSCRIPTEN
-#undef SDL_AUDIO_DRIVER_ESD
-#undef SDL_AUDIO_DRIVER_ESD_DYNAMIC
-#undef SDL_AUDIO_DRIVER_FUSIONSOUND
-#undef SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC
-#undef SDL_AUDIO_DRIVER_HAIKU
-#undef SDL_AUDIO_DRIVER_JACK
-#undef SDL_AUDIO_DRIVER_JACK_DYNAMIC
-#undef SDL_AUDIO_DRIVER_NACL
-#undef SDL_AUDIO_DRIVER_NAS
-#undef SDL_AUDIO_DRIVER_NAS_DYNAMIC
-#undef SDL_AUDIO_DRIVER_NETBSD
-#undef SDL_AUDIO_DRIVER_OSS
-#undef SDL_AUDIO_DRIVER_OSS_SOUNDCARD_H
-#undef SDL_AUDIO_DRIVER_PAUDIO
-#undef SDL_AUDIO_DRIVER_PULSEAUDIO
-#undef SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC
-#undef SDL_AUDIO_DRIVER_QSA
-#undef SDL_AUDIO_DRIVER_SNDIO
-#undef SDL_AUDIO_DRIVER_SNDIO_DYNAMIC
-#undef SDL_AUDIO_DRIVER_SUNAUDIO
-#undef SDL_AUDIO_DRIVER_WASAPI
-#undef SDL_AUDIO_DRIVER_WINMM
-#undef SDL_AUDIO_DRIVER_XAUDIO2
-
-/* Enable various input drivers */
-#undef SDL_INPUT_LINUXEV
-#undef SDL_INPUT_LINUXKD
-#undef SDL_INPUT_TSLIB
-#undef SDL_JOYSTICK_HAIKU
-#undef SDL_JOYSTICK_DINPUT
-#undef SDL_JOYSTICK_XINPUT
-#undef SDL_JOYSTICK_DUMMY
-#undef SDL_JOYSTICK_IOKIT
-#undef SDL_JOYSTICK_LINUX
-#undef SDL_JOYSTICK_ANDROID
-#undef SDL_JOYSTICK_WINMM
-#undef SDL_JOYSTICK_USBHID
-#undef SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H
-#undef SDL_JOYSTICK_EMSCRIPTEN
-#undef SDL_HAPTIC_DUMMY
-#undef SDL_HAPTIC_LINUX
-#undef SDL_HAPTIC_IOKIT
-#undef SDL_HAPTIC_DINPUT
-#undef SDL_HAPTIC_XINPUT
-
-/* Enable various shared object loading systems */
-#undef SDL_LOADSO_DLOPEN
-#undef SDL_LOADSO_DUMMY
-#undef SDL_LOADSO_LDG
-#undef SDL_LOADSO_WINDOWS
-
-/* Enable various threading systems */
-#undef SDL_THREAD_PTHREAD
-#undef SDL_THREAD_PTHREAD_RECURSIVE_MUTEX
-#undef SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP
-#undef SDL_THREAD_WINDOWS
-
-/* Enable various timer systems */
-#undef SDL_TIMER_HAIKU
-#undef SDL_TIMER_DUMMY
-#undef SDL_TIMER_UNIX
-#undef SDL_TIMER_WINDOWS
-
-/* Enable various video drivers */
-#undef SDL_VIDEO_DRIVER_HAIKU
-#undef SDL_VIDEO_DRIVER_COCOA
-#undef SDL_VIDEO_DRIVER_DIRECTFB
-#undef SDL_VIDEO_DRIVER_DIRECTFB_DYNAMIC
-#undef SDL_VIDEO_DRIVER_DUMMY
-#undef SDL_VIDEO_DRIVER_WINDOWS
-#undef SDL_VIDEO_DRIVER_WAYLAND
-#undef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
-#undef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC
-#undef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL
-#undef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR
-#undef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON
-#undef SDL_VIDEO_DRIVER_MIR
-#undef SDL_VIDEO_DRIVER_MIR_DYNAMIC
-#undef SDL_VIDEO_DRIVER_MIR_DYNAMIC_XKBCOMMON
-#undef SDL_VIDEO_DRIVER_X11
-#undef SDL_VIDEO_DRIVER_RPI
-#undef SDL_VIDEO_DRIVER_KMSDRM
-#undef SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC
-#undef SDL_VIDEO_DRIVER_KMSDRM_DYNAMIC_GBM
-#undef SDL_VIDEO_DRIVER_ANDROID
-#undef SDL_VIDEO_DRIVER_EMSCRIPTEN
-#undef SDL_VIDEO_DRIVER_X11_DYNAMIC
-#undef SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT
-#undef SDL_VIDEO_DRIVER_X11_DYNAMIC_XCURSOR
-#undef SDL_VIDEO_DRIVER_X11_DYNAMIC_XINERAMA
-#undef SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2
-#undef SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR
-#undef SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS
-#undef SDL_VIDEO_DRIVER_X11_DYNAMIC_XVIDMODE
-#undef SDL_VIDEO_DRIVER_X11_XCURSOR
-#undef SDL_VIDEO_DRIVER_X11_XDBE
-#undef SDL_VIDEO_DRIVER_X11_XINERAMA
-#undef SDL_VIDEO_DRIVER_X11_XINPUT2
-#undef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
-#undef SDL_VIDEO_DRIVER_X11_XRANDR
-#undef SDL_VIDEO_DRIVER_X11_XSCRNSAVER
-#undef SDL_VIDEO_DRIVER_X11_XSHAPE
-#undef SDL_VIDEO_DRIVER_X11_XVIDMODE
-#undef SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS
-#undef SDL_VIDEO_DRIVER_X11_CONST_PARAM_XEXTADDDISPLAY
-#undef SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
-#undef SDL_VIDEO_DRIVER_NACL
-#undef SDL_VIDEO_DRIVER_VIVANTE
-#undef SDL_VIDEO_DRIVER_VIVANTE_VDK
-#undef SDL_VIDEO_DRIVER_QNX
-
-#undef SDL_VIDEO_RENDER_D3D
-#undef SDL_VIDEO_RENDER_D3D11
-#undef SDL_VIDEO_RENDER_OGL
-#undef SDL_VIDEO_RENDER_OGL_ES
-#undef SDL_VIDEO_RENDER_OGL_ES2
-#undef SDL_VIDEO_RENDER_DIRECTFB
-
-/* Enable OpenGL support */
-#undef SDL_VIDEO_OPENGL
-#undef SDL_VIDEO_OPENGL_ES
-#undef SDL_VIDEO_OPENGL_ES2
-#undef SDL_VIDEO_OPENGL_BGL
-#undef SDL_VIDEO_OPENGL_CGL
-#undef SDL_VIDEO_OPENGL_EGL
-#undef SDL_VIDEO_OPENGL_GLX
-#undef SDL_VIDEO_OPENGL_WGL
-#undef SDL_VIDEO_OPENGL_OSMESA
-#undef SDL_VIDEO_OPENGL_OSMESA_DYNAMIC
-
-/* Enable Vulkan support */
-#undef SDL_VIDEO_VULKAN
-
-/* Enable system power support */
-#undef SDL_POWER_LINUX
-#undef SDL_POWER_WINDOWS
-#undef SDL_POWER_MACOSX
-#undef SDL_POWER_HAIKU
-#undef SDL_POWER_ANDROID
-#undef SDL_POWER_EMSCRIPTEN
-#undef SDL_POWER_HARDWIRED
-
-/* Enable system filesystem support */
-#undef SDL_FILESYSTEM_HAIKU
-#undef SDL_FILESYSTEM_COCOA
-#undef SDL_FILESYSTEM_DUMMY
-#undef SDL_FILESYSTEM_UNIX
-#undef SDL_FILESYSTEM_WINDOWS
-#undef SDL_FILESYSTEM_NACL
-#undef SDL_FILESYSTEM_ANDROID
-#undef SDL_FILESYSTEM_EMSCRIPTEN
-
-/* Enable assembly routines */
-#undef SDL_ASSEMBLY_ROUTINES
-#undef SDL_ALTIVEC_BLITTERS
-
-/* Enable ime support */
-#undef SDL_USE_IME
-
-/* Enable dynamic udev support */
-#undef SDL_UDEV_DYNAMIC
-
-/* Enable dynamic libsamplerate support */
-#undef SDL_LIBSAMPLERATE_DYNAMIC
-
-#endif /* SDL_config_h_ */
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_config_android.h
+++ /dev/null
@@ -1,157 +1,0 @@
-/*
-  Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef SDL_config_android_h_
-#define SDL_config_android_h_
-#define SDL_config_h_
-
-#include "SDL_platform.h"
-
-/**
- *  \file SDL_config_android.h
- *
- *  This is a configuration that can be used to build SDL for Android
- */
-
-#include <stdarg.h>
-
-#define HAVE_GCC_ATOMICS    1
-
-#define HAVE_ALLOCA_H       1
-#define HAVE_SYS_TYPES_H    1
-#define HAVE_STDIO_H    1
-#define STDC_HEADERS    1
-#define HAVE_STRING_H   1
-#define HAVE_INTTYPES_H 1
-#define HAVE_STDINT_H   1
-#define HAVE_CTYPE_H    1
-#define HAVE_MATH_H 1
-#define HAVE_SIGNAL_H 1
-
-/* C library functions */
-#define HAVE_MALLOC 1
-#define HAVE_CALLOC 1
-#define HAVE_REALLOC    1
-#define HAVE_FREE   1
-#define HAVE_ALLOCA 1
-#define HAVE_GETENV 1
-#define HAVE_SETENV 1
-#define HAVE_PUTENV 1
-#define HAVE_SETENV 1
-#define HAVE_UNSETENV   1
-#define HAVE_QSORT  1
-#define HAVE_ABS    1
-#define HAVE_BCOPY  1
-#define HAVE_MEMSET 1
-#define HAVE_MEMCPY 1
-#define HAVE_MEMMOVE    1
-#define HAVE_MEMCMP 1
-#define HAVE_STRLEN 1
-#define HAVE_STRLCPY    1
-#define HAVE_STRLCAT    1
-#define HAVE_STRDUP 1
-#define HAVE_STRCHR 1
-#define HAVE_STRRCHR    1
-#define HAVE_STRSTR 1
-#define HAVE_STRTOL 1
-#define HAVE_STRTOUL    1
-#define HAVE_STRTOLL    1
-#define HAVE_STRTOULL   1
-#define HAVE_STRTOD 1
-#define HAVE_ATOI   1
-#define HAVE_ATOF 1
-#define HAVE_STRCMP 1
-#define HAVE_STRNCMP    1
-#define HAVE_STRCASECMP 1
-#define HAVE_STRNCASECMP 1
-#define HAVE_VSSCANF 1
-#define HAVE_VSNPRINTF  1
-#define HAVE_M_PI   1
-#define HAVE_ATAN   1
-#define HAVE_ATAN2  1
-#define HAVE_ACOS  1
-#define HAVE_ASIN  1
-#define HAVE_CEIL   1
-#define HAVE_COPYSIGN   1
-#define HAVE_COS    1
-#define HAVE_COSF   1
-#define HAVE_FABS   1
-#define HAVE_FLOOR  1
-#define HAVE_LOG    1
-#define HAVE_POW    1
-#define HAVE_SCALBN 1
-#define HAVE_SIN    1
-#define HAVE_SINF   1
-#define HAVE_SQRT   1
-#define HAVE_SQRTF  1
-#define HAVE_TAN    1
-#define HAVE_TANF   1
-#define HAVE_SIGACTION 1
-#define HAVE_SETJMP 1
-#define HAVE_NANOSLEEP  1
-#define HAVE_SYSCONF    1
-#define HAVE_CLOCK_GETTIME	1
-
-#define SIZEOF_VOIDP 4
-
-/* Enable various audio drivers */
-#define SDL_AUDIO_DRIVER_ANDROID    1
-#define SDL_AUDIO_DRIVER_DUMMY  1
-
-/* Enable various input drivers */
-#define SDL_JOYSTICK_ANDROID    1
-#define SDL_HAPTIC_ANDROID    1
-
-/* Enable various shared object loading systems */
-#define SDL_LOADSO_DLOPEN   1
-
-/* Enable various threading systems */
-#define SDL_THREAD_PTHREAD  1
-#define SDL_THREAD_PTHREAD_RECURSIVE_MUTEX  1
-
-/* Enable various timer systems */
-#define SDL_TIMER_UNIX  1
-
-/* Enable various video drivers */
-#define SDL_VIDEO_DRIVER_ANDROID 1
-
-/* Enable OpenGL ES */
-#define SDL_VIDEO_OPENGL_ES 1
-#define SDL_VIDEO_OPENGL_ES2 1
-#define SDL_VIDEO_OPENGL_EGL 1
-#define SDL_VIDEO_RENDER_OGL_ES 1
-#define SDL_VIDEO_RENDER_OGL_ES2    1
-
-/* Enable Vulkan support */
-/* Android does not support Vulkan in native code using the "armeabi" ABI. */
-#if defined(__ARM_ARCH) && __ARM_ARCH < 7
-#define SDL_VIDEO_VULKAN 0
-#else
-#define SDL_VIDEO_VULKAN 1
-#endif
-
-/* Enable system power support */
-#define SDL_POWER_ANDROID 1
-
-/* Enable the filesystem driver */
-#define SDL_FILESYSTEM_ANDROID   1
-
-#endif /* SDL_config_android_h_ */
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_config_iphoneos.h
+++ /dev/null
@@ -1,166 +1,0 @@
-/*
-  Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef SDL_config_iphoneos_h_
-#define SDL_config_iphoneos_h_
-#define SDL_config_h_
-
-#include "SDL_platform.h"
-
-#ifdef __LP64__
-#define SIZEOF_VOIDP 8
-#else
-#define SIZEOF_VOIDP 4
-#endif
-
-#define HAVE_GCC_ATOMICS    1
-
-#define HAVE_ALLOCA_H       1
-#define HAVE_SYS_TYPES_H    1
-#define HAVE_STDIO_H    1
-#define STDC_HEADERS    1
-#define HAVE_STRING_H   1
-#define HAVE_INTTYPES_H 1
-#define HAVE_STDINT_H   1
-#define HAVE_CTYPE_H    1
-#define HAVE_MATH_H 1
-#define HAVE_SIGNAL_H   1
-
-/* C library functions */
-#define HAVE_MALLOC 1
-#define HAVE_CALLOC 1
-#define HAVE_REALLOC    1
-#define HAVE_FREE   1
-#define HAVE_ALLOCA 1
-#define HAVE_GETENV 1
-#define HAVE_SETENV 1
-#define HAVE_PUTENV 1
-#define HAVE_SETENV 1
-#define HAVE_UNSETENV   1
-#define HAVE_QSORT  1
-#define HAVE_ABS    1
-#define HAVE_BCOPY  1
-#define HAVE_MEMSET 1
-#define HAVE_MEMCPY 1
-#define HAVE_MEMMOVE    1
-#define HAVE_MEMCMP 1
-#define HAVE_STRLEN 1
-#define HAVE_STRLCPY    1
-#define HAVE_STRLCAT    1
-#define HAVE_STRDUP 1
-#define HAVE_STRCHR 1
-#define HAVE_STRRCHR    1
-#define HAVE_STRSTR 1
-#define HAVE_STRTOL 1
-#define HAVE_STRTOUL    1
-#define HAVE_STRTOLL    1
-#define HAVE_STRTOULL   1
-#define HAVE_STRTOD 1
-#define HAVE_ATOI   1
-#define HAVE_ATOF   1
-#define HAVE_STRCMP 1
-#define HAVE_STRNCMP    1
-#define HAVE_STRCASECMP 1
-#define HAVE_STRNCASECMP 1
-#define HAVE_VSSCANF 1
-#define HAVE_VSNPRINTF  1
-#define HAVE_M_PI   1
-#define HAVE_ATAN   1
-#define HAVE_ATAN2  1
-#define HAVE_ACOS  1
-#define HAVE_ASIN  1
-#define HAVE_CEIL   1
-#define HAVE_COPYSIGN   1
-#define HAVE_COS    1
-#define HAVE_COSF   1
-#define HAVE_FABS   1
-#define HAVE_FLOOR  1
-#define HAVE_LOG    1
-#define HAVE_POW    1
-#define HAVE_SCALBN 1
-#define HAVE_SIN    1
-#define HAVE_SINF   1
-#define HAVE_SQRT   1
-#define HAVE_SQRTF  1
-#define HAVE_TAN    1
-#define HAVE_TANF   1
-#define HAVE_SIGACTION  1
-#define HAVE_SETJMP 1
-#define HAVE_NANOSLEEP  1
-#define HAVE_SYSCONF    1
-#define HAVE_SYSCTLBYNAME 1
-
-/* enable iPhone version of Core Audio driver */
-#define SDL_AUDIO_DRIVER_COREAUDIO 1
-/* Enable the dummy audio driver (src/audio/dummy/\*.c) */
-#define SDL_AUDIO_DRIVER_DUMMY  1
-
-/* Enable the stub haptic driver (src/haptic/dummy/\*.c) */
-#define SDL_HAPTIC_DUMMY 1
-
-/* Enable MFi joystick support */
-#define SDL_JOYSTICK_MFI 1
-
-/* Enable Unix style SO loading */
-#define SDL_LOADSO_DLOPEN 1
-
-/* Enable various threading systems */
-#define SDL_THREAD_PTHREAD  1
-#define SDL_THREAD_PTHREAD_RECURSIVE_MUTEX  1
-
-/* Enable various timer systems */
-#define SDL_TIMER_UNIX  1
-
-/* Supported video drivers */
-#define SDL_VIDEO_DRIVER_UIKIT  1
-#define SDL_VIDEO_DRIVER_DUMMY  1
-
-/* enable OpenGL ES */
-#define SDL_VIDEO_OPENGL_ES2 1
-#define SDL_VIDEO_OPENGL_ES 1
-#define SDL_VIDEO_RENDER_OGL_ES 1
-#define SDL_VIDEO_RENDER_OGL_ES2    1
-
-/* Enable Vulkan support */
-#if !TARGET_OS_SIMULATOR && !TARGET_CPU_ARM // Only 64-bit devices have Metal
-#define SDL_VIDEO_VULKAN 1
-#else
-#define SDL_VIDEO_VULKAN 0
-#endif
-
-/* Enable system power support */
-#define SDL_POWER_UIKIT 1
-
-/* enable iPhone keyboard support */
-#define SDL_IPHONE_KEYBOARD 1
-
-/* enable iOS extended launch screen */
-#define SDL_IPHONE_LAUNCHSCREEN 1
-
-/* Set max recognized G-force from accelerometer
-   See src/joystick/uikit/SDL_sysjoystick.m for notes on why this is needed
- */
-#define SDL_IPHONE_MAX_GFORCE 5.0
-
-/* enable filesystem support */
-#define SDL_FILESYSTEM_COCOA   1
-
-#endif /* SDL_config_iphoneos_h_ */
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_config_macosx.h
+++ /dev/null
@@ -1,197 +1,0 @@
-/*
-  Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef SDL_config_macosx_h_
-#define SDL_config_macosx_h_
-#define SDL_config_h_
-
-#include "SDL_platform.h"
-
-/* This gets us MAC_OS_X_VERSION_MIN_REQUIRED... */
-#include <AvailabilityMacros.h>
-
-/* This is a set of defines to configure the SDL features */
-
-#ifdef __LP64__
-    #define SIZEOF_VOIDP 8
-#else
-    #define SIZEOF_VOIDP 4
-#endif
-
-/* Useful headers */
-#define HAVE_ALLOCA_H       1
-#define HAVE_SYS_TYPES_H    1
-#define HAVE_STDIO_H    1
-#define STDC_HEADERS    1
-#define HAVE_STRING_H   1
-#define HAVE_INTTYPES_H 1
-#define HAVE_STDINT_H   1
-#define HAVE_CTYPE_H    1
-#define HAVE_MATH_H 1
-#define HAVE_SIGNAL_H   1
-
-/* C library functions */
-#define HAVE_MALLOC 1
-#define HAVE_CALLOC 1
-#define HAVE_REALLOC    1
-#define HAVE_FREE   1
-#define HAVE_ALLOCA 1
-#define HAVE_GETENV 1
-#define HAVE_SETENV 1
-#define HAVE_PUTENV 1
-#define HAVE_UNSETENV   1
-#define HAVE_QSORT  1
-#define HAVE_ABS    1
-#define HAVE_BCOPY  1
-#define HAVE_MEMSET 1
-#define HAVE_MEMCPY 1
-#define HAVE_MEMMOVE    1
-#define HAVE_MEMCMP 1
-#define HAVE_STRLEN 1
-#define HAVE_STRLCPY    1
-#define HAVE_STRLCAT    1
-#define HAVE_STRDUP 1
-#define HAVE_STRCHR 1
-#define HAVE_STRRCHR    1
-#define HAVE_STRSTR 1
-#define HAVE_STRTOL 1
-#define HAVE_STRTOUL    1
-#define HAVE_STRTOLL    1
-#define HAVE_STRTOULL   1
-#define HAVE_STRTOD 1
-#define HAVE_ATOI   1
-#define HAVE_ATOF   1
-#define HAVE_STRCMP 1
-#define HAVE_STRNCMP    1
-#define HAVE_STRCASECMP 1
-#define HAVE_STRNCASECMP 1
-#define HAVE_VSSCANF 1
-#define HAVE_VSNPRINTF  1
-#define HAVE_CEIL   1
-#define HAVE_COPYSIGN   1
-#define HAVE_COS    1
-#define HAVE_COSF   1
-#define HAVE_FABS   1
-#define HAVE_FLOOR  1
-#define HAVE_LOG    1
-#define HAVE_POW    1
-#define HAVE_SCALBN 1
-#define HAVE_SIN    1
-#define HAVE_SINF   1
-#define HAVE_SQRT   1
-#define HAVE_SQRTF  1
-#define HAVE_TAN    1
-#define HAVE_TANF   1
-#define HAVE_SIGACTION  1
-#define HAVE_SETJMP 1
-#define HAVE_NANOSLEEP  1
-#define HAVE_SYSCONF    1
-#define HAVE_SYSCTLBYNAME 1
-#define HAVE_ATAN 1
-#define HAVE_ATAN2 1
-#define HAVE_ACOS 1
-#define HAVE_ASIN 1
-
-/* Enable various audio drivers */
-#define SDL_AUDIO_DRIVER_COREAUDIO  1
-#define SDL_AUDIO_DRIVER_DISK   1
-#define SDL_AUDIO_DRIVER_DUMMY  1
-
-/* Enable various input drivers */
-#define SDL_JOYSTICK_IOKIT  1
-#define SDL_HAPTIC_IOKIT    1
-
-/* Enable various shared object loading systems */
-#define SDL_LOADSO_DLOPEN   1
-
-/* Enable various threading systems */
-#define SDL_THREAD_PTHREAD  1
-#define SDL_THREAD_PTHREAD_RECURSIVE_MUTEX  1
-
-/* Enable various timer systems */
-#define SDL_TIMER_UNIX  1
-
-/* Enable various video drivers */
-#define SDL_VIDEO_DRIVER_COCOA  1
-#define SDL_VIDEO_DRIVER_DUMMY  1
-#undef SDL_VIDEO_DRIVER_X11
-#define SDL_VIDEO_DRIVER_X11_DYNAMIC "/usr/X11R6/lib/libX11.6.dylib"
-#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT "/usr/X11R6/lib/libXext.6.dylib"
-#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XINERAMA "/usr/X11R6/lib/libXinerama.1.dylib"
-#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2 "/usr/X11R6/lib/libXi.6.dylib"
-#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR "/usr/X11R6/lib/libXrandr.2.dylib"
-#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS "/usr/X11R6/lib/libXss.1.dylib"
-#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XVIDMODE "/usr/X11R6/lib/libXxf86vm.1.dylib"
-#define SDL_VIDEO_DRIVER_X11_XDBE 1
-#define SDL_VIDEO_DRIVER_X11_XINERAMA 1
-#define SDL_VIDEO_DRIVER_X11_XRANDR 1
-#define SDL_VIDEO_DRIVER_X11_XSCRNSAVER 1
-#define SDL_VIDEO_DRIVER_X11_XSHAPE 1
-#define SDL_VIDEO_DRIVER_X11_XVIDMODE 1
-#define SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM 1
-
-#ifdef MAC_OS_X_VERSION_10_8
-/*
- * No matter the versions targeted, this is the 10.8 or later SDK, so you have
- *  to use the external Xquartz, which is a more modern Xlib. Previous SDKs
- *  used an older Xlib.
- */
-#define SDL_VIDEO_DRIVER_X11_XINPUT2 1
-#define SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS 1
-#define SDL_VIDEO_DRIVER_X11_CONST_PARAM_XEXTADDDISPLAY 1
-#endif
-
-#ifndef SDL_VIDEO_RENDER_OGL
-#define SDL_VIDEO_RENDER_OGL    1
-#endif
-
-/* Enable OpenGL support */
-#ifndef SDL_VIDEO_OPENGL
-#define SDL_VIDEO_OPENGL    1
-#endif
-#ifndef SDL_VIDEO_OPENGL_CGL
-#define SDL_VIDEO_OPENGL_CGL    1
-#endif
-#ifndef SDL_VIDEO_OPENGL_GLX
-#define SDL_VIDEO_OPENGL_GLX    1
-#endif
-
-/* Enable Vulkan support */
-/* Metal/MoltenVK/Vulkan only supported on 64-bit architectures with 10.11+ */
-#if TARGET_CPU_X86_64 && (MAC_OS_X_VERSION_MAX_ALLOWED >= 101100)
-#define SDL_VIDEO_VULKAN 1
-#else
-#define  SDL_VIDEO_VULKAN 0
-#endif
-
-/* Enable system power support */
-#define SDL_POWER_MACOSX 1
-
-/* enable filesystem support */
-#define SDL_FILESYSTEM_COCOA   1
-
-/* Enable assembly routines */
-#define SDL_ASSEMBLY_ROUTINES   1
-#ifdef __ppc__
-#define SDL_ALTIVEC_BLITTERS    1
-#endif
-
-#endif /* SDL_config_macosx_h_ */
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_config_macosx.h.orig
+++ /dev/null
@@ -1,197 +1,0 @@
-/*
-  Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef SDL_config_macosx_h_
-#define SDL_config_macosx_h_
-#define SDL_config_h_
-
-#include "SDL_platform.h"
-
-/* This gets us MAC_OS_X_VERSION_MIN_REQUIRED... */
-#include <AvailabilityMacros.h>
-
-/* This is a set of defines to configure the SDL features */
-
-#ifdef __LP64__
-    #define SIZEOF_VOIDP 8
-#else
-    #define SIZEOF_VOIDP 4
-#endif
-
-/* Useful headers */
-#define HAVE_ALLOCA_H       1
-#define HAVE_SYS_TYPES_H    1
-#define HAVE_STDIO_H    1
-#define STDC_HEADERS    1
-#define HAVE_STRING_H   1
-#define HAVE_INTTYPES_H 1
-#define HAVE_STDINT_H   1
-#define HAVE_CTYPE_H    1
-#define HAVE_MATH_H 1
-#define HAVE_SIGNAL_H   1
-
-/* C library functions */
-#define HAVE_MALLOC 1
-#define HAVE_CALLOC 1
-#define HAVE_REALLOC    1
-#define HAVE_FREE   1
-#define HAVE_ALLOCA 1
-#define HAVE_GETENV 1
-#define HAVE_SETENV 1
-#define HAVE_PUTENV 1
-#define HAVE_UNSETENV   1
-#define HAVE_QSORT  1
-#define HAVE_ABS    1
-#define HAVE_BCOPY  1
-#define HAVE_MEMSET 1
-#define HAVE_MEMCPY 1
-#define HAVE_MEMMOVE    1
-#define HAVE_MEMCMP 1
-#define HAVE_STRLEN 1
-#define HAVE_STRLCPY    1
-#define HAVE_STRLCAT    1
-#define HAVE_STRDUP 1
-#define HAVE_STRCHR 1
-#define HAVE_STRRCHR    1
-#define HAVE_STRSTR 1
-#define HAVE_STRTOL 1
-#define HAVE_STRTOUL    1
-#define HAVE_STRTOLL    1
-#define HAVE_STRTOULL   1
-#define HAVE_STRTOD 1
-#define HAVE_ATOI   1
-#define HAVE_ATOF   1
-#define HAVE_STRCMP 1
-#define HAVE_STRNCMP    1
-#define HAVE_STRCASECMP 1
-#define HAVE_STRNCASECMP 1
-#define HAVE_VSSCANF 1
-#define HAVE_VSNPRINTF  1
-#define HAVE_CEIL   1
-#define HAVE_COPYSIGN   1
-#define HAVE_COS    1
-#define HAVE_COSF   1
-#define HAVE_FABS   1
-#define HAVE_FLOOR  1
-#define HAVE_LOG    1
-#define HAVE_POW    1
-#define HAVE_SCALBN 1
-#define HAVE_SIN    1
-#define HAVE_SINF   1
-#define HAVE_SQRT   1
-#define HAVE_SQRTF  1
-#define HAVE_TAN    1
-#define HAVE_TANF   1
-#define HAVE_SIGACTION  1
-#define HAVE_SETJMP 1
-#define HAVE_NANOSLEEP  1
-#define HAVE_SYSCONF    1
-#define HAVE_SYSCTLBYNAME 1
-#define HAVE_ATAN 1
-#define HAVE_ATAN2 1
-#define HAVE_ACOS 1
-#define HAVE_ASIN 1
-
-/* Enable various audio drivers */
-#define SDL_AUDIO_DRIVER_COREAUDIO  1
-#define SDL_AUDIO_DRIVER_DISK   1
-#define SDL_AUDIO_DRIVER_DUMMY  1
-
-/* Enable various input drivers */
-#define SDL_JOYSTICK_IOKIT  1
-#define SDL_HAPTIC_IOKIT    1
-
-/* Enable various shared object loading systems */
-#define SDL_LOADSO_DLOPEN   1
-
-/* Enable various threading systems */
-#define SDL_THREAD_PTHREAD  1
-#define SDL_THREAD_PTHREAD_RECURSIVE_MUTEX  1
-
-/* Enable various timer systems */
-#define SDL_TIMER_UNIX  1
-
-/* Enable various video drivers */
-#define SDL_VIDEO_DRIVER_COCOA  1
-#define SDL_VIDEO_DRIVER_DUMMY  1
-#undef SDL_VIDEO_DRIVER_X11
-#define SDL_VIDEO_DRIVER_X11_DYNAMIC "/usr/X11R6/lib/libX11.6.dylib"
-#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT "/usr/X11R6/lib/libXext.6.dylib"
-#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XINERAMA "/usr/X11R6/lib/libXinerama.1.dylib"
-#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2 "/usr/X11R6/lib/libXi.6.dylib"
-#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR "/usr/X11R6/lib/libXrandr.2.dylib"
-#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS "/usr/X11R6/lib/libXss.1.dylib"
-#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XVIDMODE "/usr/X11R6/lib/libXxf86vm.1.dylib"
-#define SDL_VIDEO_DRIVER_X11_XDBE 1
-#define SDL_VIDEO_DRIVER_X11_XINERAMA 1
-#define SDL_VIDEO_DRIVER_X11_XRANDR 1
-#define SDL_VIDEO_DRIVER_X11_XSCRNSAVER 1
-#define SDL_VIDEO_DRIVER_X11_XSHAPE 1
-#define SDL_VIDEO_DRIVER_X11_XVIDMODE 1
-#define SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM 1
-
-#ifdef MAC_OS_X_VERSION_10_8
-/*
- * No matter the versions targeted, this is the 10.8 or later SDK, so you have
- *  to use the external Xquartz, which is a more modern Xlib. Previous SDKs
- *  used an older Xlib.
- */
-#define SDL_VIDEO_DRIVER_X11_XINPUT2 1
-#define SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS 1
-#define SDL_VIDEO_DRIVER_X11_CONST_PARAM_XEXTADDDISPLAY 1
-#endif
-
-#ifndef SDL_VIDEO_RENDER_OGL
-#define SDL_VIDEO_RENDER_OGL    1
-#endif
-
-/* Enable OpenGL support */
-#ifndef SDL_VIDEO_OPENGL
-#define SDL_VIDEO_OPENGL    1
-#endif
-#ifndef SDL_VIDEO_OPENGL_CGL
-#define SDL_VIDEO_OPENGL_CGL    1
-#endif
-#ifndef SDL_VIDEO_OPENGL_GLX
-#define SDL_VIDEO_OPENGL_GLX    1
-#endif
-
-/* Enable Vulkan support */
-/* Metal/MoltenVK/Vulkan only supported on 64-bit architectures and 10.11+ */
-#if TARGET_CPU_X86_64
-#define SDL_VIDEO_VULKAN 1
-#else
-#define  SDL_VIDEO_VULKAN 0
-#endif
-
-/* Enable system power support */
-#define SDL_POWER_MACOSX 1
-
-/* enable filesystem support */
-#define SDL_FILESYSTEM_COCOA   1
-
-/* Enable assembly routines */
-#define SDL_ASSEMBLY_ROUTINES   1
-#ifdef __ppc__
-#define SDL_ALTIVEC_BLITTERS    1
-#endif
-
-#endif /* SDL_config_macosx_h_ */
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_config_minimal.h
+++ /dev/null
@@ -1,82 +1,0 @@
-/*
-  Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef SDL_config_minimal_h_
-#define SDL_config_minimal_h_
-#define SDL_config_h_
-
-#include "SDL_platform.h"
-
-/**
- *  \file SDL_config_minimal.h
- *
- *  This is the minimal configuration that can be used to build SDL.
- */
-
-#define HAVE_STDARG_H   1
-#define HAVE_STDDEF_H   1
-
-/* Most everything except Visual Studio 2008 and earlier has stdint.h now */
-#if defined(_MSC_VER) && (_MSC_VER < 1600)
-/* Here are some reasonable defaults */
-typedef unsigned int size_t;
-typedef signed char int8_t;
-typedef unsigned char uint8_t;
-typedef signed short int16_t;
-typedef unsigned short uint16_t;
-typedef signed int int32_t;
-typedef unsigned int uint32_t;
-typedef signed long long int64_t;
-typedef unsigned long long uint64_t;
-typedef unsigned long uintptr_t;
-#else
-#define HAVE_STDINT_H 1
-#endif /* Visual Studio 2008 */
-
-#ifdef __GNUC__
-#define HAVE_GCC_SYNC_LOCK_TEST_AND_SET 1
-#endif
-
-/* Enable the dummy audio driver (src/audio/dummy/\*.c) */
-#define SDL_AUDIO_DRIVER_DUMMY  1
-
-/* Enable the stub joystick driver (src/joystick/dummy/\*.c) */
-#define SDL_JOYSTICK_DISABLED   1
-
-/* Enable the stub haptic driver (src/haptic/dummy/\*.c) */
-#define SDL_HAPTIC_DISABLED 1
-
-/* Enable the stub shared object loader (src/loadso/dummy/\*.c) */
-#define SDL_LOADSO_DISABLED 1
-
-/* Enable the stub thread support (src/thread/generic/\*.c) */
-#define SDL_THREADS_DISABLED    1
-
-/* Enable the stub timer support (src/timer/dummy/\*.c) */
-#define SDL_TIMERS_DISABLED 1
-
-/* Enable the dummy video driver (src/video/dummy/\*.c) */
-#define SDL_VIDEO_DRIVER_DUMMY  1
-
-/* Enable the dummy filesystem driver (src/filesystem/dummy/\*.c) */
-#define SDL_FILESYSTEM_DUMMY  1
-
-#endif /* SDL_config_minimal_h_ */
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_config_pandora.h
+++ /dev/null
@@ -1,128 +1,0 @@
-/*
-  Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef SDL_config_pandora_h_
-#define SDL_config_pandora_h_
-#define SDL_config_h_
-
-/* This is a set of defines to configure the SDL features */
-
-/* General platform specific identifiers */
-#include "SDL_platform.h"
-
-#ifdef __LP64__
-#define SIZEOF_VOIDP 8
-#else
-#define SIZEOF_VOIDP 4
-#endif
-
-#define SDL_BYTEORDER 1234
-
-#define HAVE_ALLOCA_H 1
-#define HAVE_SYS_TYPES_H 1
-#define HAVE_STDIO_H 1
-#define STDC_HEADERS 1
-#define HAVE_STDLIB_H 1
-#define HAVE_STDARG_H 1
-#define HAVE_MALLOC_H 1
-#define HAVE_MEMORY_H 1
-#define HAVE_STRING_H 1
-#define HAVE_STRINGS_H 1
-#define HAVE_INTTYPES_H 1
-#define HAVE_STDINT_H 1
-#define HAVE_CTYPE_H 1
-#define HAVE_MATH_H 1
-#define HAVE_ICONV_H 1
-#define HAVE_SIGNAL_H 1
-#define HAVE_MALLOC 1
-#define HAVE_CALLOC 1
-#define HAVE_REALLOC 1
-#define HAVE_FREE 1
-#define HAVE_ALLOCA 1
-#define HAVE_GETENV 1
-#define HAVE_SETENV 1
-#define HAVE_PUTENV 1
-#define HAVE_UNSETENV 1
-#define HAVE_QSORT 1
-#define HAVE_ABS 1
-#define HAVE_BCOPY 1
-#define HAVE_MEMSET 1
-#define HAVE_MEMCPY 1
-#define HAVE_MEMMOVE 1
-#define HAVE_STRLEN 1
-#define HAVE_STRDUP 1
-#define HAVE_STRCHR 1
-#define HAVE_STRRCHR 1
-#define HAVE_STRSTR 1
-#define HAVE_STRTOL 1
-#define HAVE_STRTOUL 1
-#define HAVE_STRTOLL 1
-#define HAVE_STRTOULL 1
-#define HAVE_ATOI 1
-#define HAVE_ATOF 1
-#define HAVE_STRCMP 1
-#define HAVE_STRNCMP 1
-#define HAVE_STRCASECMP 1
-#define HAVE_STRNCASECMP 1
-#define HAVE_VSSCANF 1
-#define HAVE_VSNPRINTF 1
-#define HAVE_M_PI 1
-#define HAVE_CEIL 1
-#define HAVE_COPYSIGN 1
-#define HAVE_COS 1
-#define HAVE_COSF 1
-#define HAVE_FABS 1
-#define HAVE_FLOOR 1
-#define HAVE_LOG 1
-#define HAVE_SCALBN 1
-#define HAVE_SIN 1
-#define HAVE_SINF 1
-#define HAVE_SQRT 1
-#define HAVE_SQRTF 1
-#define HAVE_TAN 1
-#define HAVE_TANF 1
-#define HAVE_SIGACTION 1
-#define HAVE_SETJMP 1
-#define HAVE_NANOSLEEP 1
-
-#define SDL_AUDIO_DRIVER_DUMMY 1
-#define SDL_AUDIO_DRIVER_OSS 1
-
-#define SDL_INPUT_LINUXEV 1
-#define SDL_INPUT_TSLIB 1
-#define SDL_JOYSTICK_LINUX 1
-#define SDL_HAPTIC_LINUX 1
-
-#define SDL_LOADSO_DLOPEN 1
-
-#define SDL_THREAD_PTHREAD 1
-#define SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP 1
-
-#define SDL_TIMER_UNIX 1
-#define SDL_FILESYSTEM_UNIX 1
-
-#define SDL_VIDEO_DRIVER_DUMMY 1
-#define SDL_VIDEO_DRIVER_X11 1
-#define SDL_VIDEO_DRIVER_PANDORA 1
-#define SDL_VIDEO_RENDER_OGL_ES 1
-#define SDL_VIDEO_OPENGL_ES 1
-
-#endif /* SDL_config_pandora_h_ */
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_config_psp.h
+++ /dev/null
@@ -1,144 +1,0 @@
-/*
-  Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef SDL_config_psp_h_
-#define SDL_config_psp_h_
-#define SDL_config_h_
-
-#include "SDL_platform.h"
-
-
-
-#ifdef __GNUC__
-#define HAVE_GCC_SYNC_LOCK_TEST_AND_SET 1
-#endif
-
-#define HAVE_GCC_ATOMICS    1
-
-#define HAVE_ALLOCA_H       1
-#define HAVE_SYS_TYPES_H    1
-#define HAVE_STDIO_H    1
-#define STDC_HEADERS    1
-#define HAVE_STRING_H   1
-#define HAVE_INTTYPES_H 1
-#define HAVE_STDINT_H   1
-#define HAVE_CTYPE_H    1
-#define HAVE_MATH_H 1
-#define HAVE_SIGNAL_H   1
-
-/* C library functions */
-#define HAVE_MALLOC 1
-#define HAVE_CALLOC 1
-#define HAVE_REALLOC    1
-#define HAVE_FREE   1
-#define HAVE_ALLOCA 1
-#define HAVE_GETENV 1
-#define HAVE_SETENV 1
-#define HAVE_PUTENV 1
-#define HAVE_SETENV 1
-#define HAVE_UNSETENV   1
-#define HAVE_QSORT  1
-#define HAVE_ABS    1
-#define HAVE_BCOPY  1
-#define HAVE_MEMSET 1
-#define HAVE_MEMCPY 1
-#define HAVE_MEMMOVE    1
-#define HAVE_MEMCMP 1
-#define HAVE_STRLEN 1
-#define HAVE_STRLCPY    1
-#define HAVE_STRLCAT    1
-#define HAVE_STRDUP 1
-#define HAVE_STRCHR 1
-#define HAVE_STRRCHR    1
-#define HAVE_STRSTR 1
-#define HAVE_STRTOL 1
-#define HAVE_STRTOUL    1
-#define HAVE_STRTOLL    1
-#define HAVE_STRTOULL   1
-#define HAVE_STRTOD 1
-#define HAVE_ATOI   1
-#define HAVE_ATOF   1
-#define HAVE_STRCMP 1
-#define HAVE_STRNCMP    1
-#define HAVE_STRCASECMP 1
-#define HAVE_STRNCASECMP 1
-#define HAVE_VSSCANF 1
-#define HAVE_VSNPRINTF  1
-#define HAVE_M_PI   1
-#define HAVE_ATAN   1
-#define HAVE_ATAN2  1
-#define HAVE_ACOS  1
-#define HAVE_ASIN  1
-#define HAVE_CEIL   1
-#define HAVE_COPYSIGN   1
-#define HAVE_COS    1
-#define HAVE_COSF   1
-#define HAVE_FABS   1
-#define HAVE_FLOOR  1
-#define HAVE_LOG    1
-#define HAVE_POW    1
-#define HAVE_SCALBN 1
-#define HAVE_SIN    1
-#define HAVE_SINF   1
-#define HAVE_SQRT   1
-#define HAVE_SQRTF  1
-#define HAVE_TAN    1
-#define HAVE_TANF   1
-#define HAVE_SETJMP 1
-#define HAVE_NANOSLEEP  1
-/* #define HAVE_SYSCONF  1 */
-/* #define HAVE_SIGACTION    1 */
-
-
-/* PSP isn't that sophisticated */
-#define LACKS_SYS_MMAN_H 1
-
-/* Enable the stub thread support (src/thread/psp/\*.c) */
-#define SDL_THREAD_PSP  1
-
-/* Enable the stub timer support (src/timer/psp/\*.c) */
-#define SDL_TIMERS_PSP  1
-
-/* Enable the stub joystick driver (src/joystick/psp/\*.c) */
-#define SDL_JOYSTICK_PSP        1
-
-/* Enable the stub audio driver (src/audio/psp/\*.c) */
-#define SDL_AUDIO_DRIVER_PSP    1
-
-/* PSP video dirver */
-#define SDL_VIDEO_DRIVER_PSP   1
-
-/* PSP render dirver */
-#define SDL_VIDEO_RENDER_PSP   1
-
-#define SDL_POWER_PSP          1
-
-/* !!! FIXME: what does PSP do for filesystem stuff? */
-#define SDL_FILESYSTEM_DUMMY   1
-
-/* PSP doesn't have haptic device (src/haptic/dummy/\*.c) */
-#define SDL_HAPTIC_DISABLED    1
-
-/* PSP can't load shared object (src/loadso/dummy/\*.c) */
-#define SDL_LOADSO_DISABLED    1
-
-
-#endif /* SDL_config_psp_h_ */
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_config_windows.h
+++ /dev/null
@@ -1,225 +1,0 @@
-/*
-  Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef SDL_config_windows_h_
-#define SDL_config_windows_h_
-#define SDL_config_h_
-
-#include "SDL_platform.h"
-
-/* This is a set of defines to configure the SDL features */
-
-#if !defined(_STDINT_H_) && (!defined(HAVE_STDINT_H) || !_HAVE_STDINT_H)
-#if defined(__GNUC__) || defined(__DMC__) || defined(__WATCOMC__)
-#define HAVE_STDINT_H   1
-#elif defined(_MSC_VER)
-typedef signed __int8 int8_t;
-typedef unsigned __int8 uint8_t;
-typedef signed __int16 int16_t;
-typedef unsigned __int16 uint16_t;
-typedef signed __int32 int32_t;
-typedef unsigned __int32 uint32_t;
-typedef signed __int64 int64_t;
-typedef unsigned __int64 uint64_t;
-#ifndef _UINTPTR_T_DEFINED
-#ifdef  _WIN64
-typedef unsigned __int64 uintptr_t;
-#else
-typedef unsigned int uintptr_t;
-#endif
-#define _UINTPTR_T_DEFINED
-#endif
-/* Older Visual C++ headers don't have the Win64-compatible typedefs... */
-#if ((_MSC_VER <= 1200) && (!defined(DWORD_PTR)))
-#define DWORD_PTR DWORD
-#endif
-#if ((_MSC_VER <= 1200) && (!defined(LONG_PTR)))
-#define LONG_PTR LONG
-#endif
-#else /* !__GNUC__ && !_MSC_VER */
-typedef signed char int8_t;
-typedef unsigned char uint8_t;
-typedef signed short int16_t;
-typedef unsigned short uint16_t;
-typedef signed int int32_t;
-typedef unsigned int uint32_t;
-typedef signed long long int64_t;
-typedef unsigned long long uint64_t;
-#ifndef _SIZE_T_DEFINED_
-#define _SIZE_T_DEFINED_
-typedef unsigned int size_t;
-#endif
-typedef unsigned int uintptr_t;
-#endif /* __GNUC__ || _MSC_VER */
-#endif /* !_STDINT_H_ && !HAVE_STDINT_H */
-
-#ifdef _WIN64
-# define SIZEOF_VOIDP 8
-#else
-# define SIZEOF_VOIDP 4
-#endif
-
-#define HAVE_DDRAW_H 1
-#define HAVE_DINPUT_H 1
-#define HAVE_DSOUND_H 1
-#define HAVE_DXGI_H 1
-#define HAVE_XINPUT_H 1
-
-/* This is disabled by default to avoid C runtime dependencies and manifest requirements */
-#ifdef HAVE_LIBC
-/* Useful headers */
-#define HAVE_STDIO_H 1
-#define STDC_HEADERS 1
-#define HAVE_STRING_H 1
-#define HAVE_CTYPE_H 1
-#define HAVE_MATH_H 1
-#define HAVE_SIGNAL_H 1
-
-/* C library functions */
-#define HAVE_MALLOC 1
-#define HAVE_CALLOC 1
-#define HAVE_REALLOC 1
-#define HAVE_FREE 1
-#define HAVE_ALLOCA 1
-#define HAVE_QSORT 1
-#define HAVE_ABS 1
-#define HAVE_MEMSET 1
-#define HAVE_MEMCPY 1
-#define HAVE_MEMMOVE 1
-#define HAVE_MEMCMP 1
-#define HAVE_STRLEN 1
-#define HAVE__STRREV 1
-#define HAVE__STRUPR 1
-#define HAVE__STRLWR 1
-#define HAVE_STRCHR 1
-#define HAVE_STRRCHR 1
-#define HAVE_STRSTR 1
-#define HAVE__LTOA 1
-#define HAVE__ULTOA 1
-#define HAVE_STRTOL 1
-#define HAVE_STRTOUL 1
-#define HAVE_STRTOD 1
-#define HAVE_ATOI 1
-#define HAVE_ATOF 1
-#define HAVE_STRCMP 1
-#define HAVE_STRNCMP 1
-#define HAVE__STRICMP 1
-#define HAVE__STRNICMP 1
-#define HAVE_ATAN 1
-#define HAVE_ATAN2 1
-#define HAVE_ACOS  1
-#define HAVE_ASIN  1
-#define HAVE_CEIL 1
-#define HAVE_COS 1
-#define HAVE_COSF 1
-#define HAVE_FABS 1
-#define HAVE_FLOOR 1
-#define HAVE_LOG 1
-#define HAVE_POW 1
-#define HAVE_SIN 1
-#define HAVE_SINF 1
-#define HAVE_SQRT 1
-#define HAVE_SQRTF 1
-#define HAVE_TAN 1
-#define HAVE_TANF 1
-#if _MSC_VER >= 1800
-#define HAVE_STRTOLL 1
-#define HAVE_VSSCANF 1
-#define HAVE_COPYSIGN 1
-#define HAVE_SCALBN 1
-#endif
-#if !defined(_MSC_VER) || defined(_USE_MATH_DEFINES)
-#define HAVE_M_PI 1
-#endif
-#else
-#define HAVE_STDARG_H   1
-#define HAVE_STDDEF_H   1
-#endif
-
-/* Enable various audio drivers */
-#define SDL_AUDIO_DRIVER_WASAPI 1
-#define SDL_AUDIO_DRIVER_DSOUND 1
-#define SDL_AUDIO_DRIVER_XAUDIO2    0
-#define SDL_AUDIO_DRIVER_WINMM  1
-#define SDL_AUDIO_DRIVER_DISK   1
-#define SDL_AUDIO_DRIVER_DUMMY  1
-
-/* Enable various input drivers */
-#define SDL_JOYSTICK_DINPUT 1
-#define SDL_JOYSTICK_XINPUT 1
-#define SDL_HAPTIC_DINPUT   1
-#define SDL_HAPTIC_XINPUT   1
-
-/* Enable various shared object loading systems */
-#define SDL_LOADSO_WINDOWS  1
-
-/* Enable various threading systems */
-#define SDL_THREAD_WINDOWS  1
-
-/* Enable various timer systems */
-#define SDL_TIMER_WINDOWS   1
-
-/* Enable various video drivers */
-#define SDL_VIDEO_DRIVER_DUMMY  1
-#define SDL_VIDEO_DRIVER_WINDOWS    1
-
-#ifndef SDL_VIDEO_RENDER_D3D
-#define SDL_VIDEO_RENDER_D3D    1
-#endif
-#ifndef SDL_VIDEO_RENDER_D3D11
-#define SDL_VIDEO_RENDER_D3D11	0
-#endif
-
-/* Enable OpenGL support */
-#ifndef SDL_VIDEO_OPENGL
-#define SDL_VIDEO_OPENGL    1
-#endif
-#ifndef SDL_VIDEO_OPENGL_WGL
-#define SDL_VIDEO_OPENGL_WGL    1
-#endif
-#ifndef SDL_VIDEO_RENDER_OGL
-#define SDL_VIDEO_RENDER_OGL    1
-#endif
-#ifndef SDL_VIDEO_RENDER_OGL_ES2
-#define SDL_VIDEO_RENDER_OGL_ES2    1
-#endif
-#ifndef SDL_VIDEO_OPENGL_ES2
-#define SDL_VIDEO_OPENGL_ES2    1
-#endif
-#ifndef SDL_VIDEO_OPENGL_EGL
-#define SDL_VIDEO_OPENGL_EGL    1
-#endif
-
-/* Enable Vulkan support */
-#define SDL_VIDEO_VULKAN 1
-
-/* Enable system power support */
-#define SDL_POWER_WINDOWS 1
-
-/* Enable filesystem support */
-#define SDL_FILESYSTEM_WINDOWS  1
-
-/* Enable assembly routines (Win64 doesn't have inline asm) */
-#ifndef _WIN64
-#define SDL_ASSEMBLY_ROUTINES   1
-#endif
-
-#endif /* SDL_config_windows_h_ */
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_config_winrt.h
+++ /dev/null
@@ -1,215 +1,0 @@
-/*
-  Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef SDL_config_winrt_h_
-#define SDL_config_winrt_h_
-#define SDL_config_h_
-
-#include "SDL_platform.h"
-
-/* Make sure the Windows SDK's NTDDI_VERSION macro gets defined.  This is used
-   by SDL to determine which version of the Windows SDK is being used.
-*/
-#include <sdkddkver.h>
-
-/* Define possibly-undefined NTDDI values (used when compiling SDL against
-   older versions of the Windows SDK.
-*/
-#ifndef NTDDI_WINBLUE
-#define NTDDI_WINBLUE 0x06030000
-#endif
-#ifndef NTDDI_WIN10
-#define NTDDI_WIN10 0x0A000000
-#endif
-
-/* This is a set of defines to configure the SDL features */
-
-#if !defined(_STDINT_H_) && (!defined(HAVE_STDINT_H) || !_HAVE_STDINT_H)
-#if defined(__GNUC__) || defined(__DMC__) || defined(__WATCOMC__)
-#define HAVE_STDINT_H	1
-#elif defined(_MSC_VER)
-typedef signed __int8 int8_t;
-typedef unsigned __int8 uint8_t;
-typedef signed __int16 int16_t;
-typedef unsigned __int16 uint16_t;
-typedef signed __int32 int32_t;
-typedef unsigned __int32 uint32_t;
-typedef signed __int64 int64_t;
-typedef unsigned __int64 uint64_t;
-#ifndef _UINTPTR_T_DEFINED
-#ifdef  _WIN64
-typedef unsigned __int64 uintptr_t;
-#else
-typedef unsigned int uintptr_t;
-#endif
-#define _UINTPTR_T_DEFINED
-#endif
-/* Older Visual C++ headers don't have the Win64-compatible typedefs... */
-#if ((_MSC_VER <= 1200) && (!defined(DWORD_PTR)))
-#define DWORD_PTR DWORD
-#endif
-#if ((_MSC_VER <= 1200) && (!defined(LONG_PTR)))
-#define LONG_PTR LONG
-#endif
-#else /* !__GNUC__ && !_MSC_VER */
-typedef signed char int8_t;
-typedef unsigned char uint8_t;
-typedef signed short int16_t;
-typedef unsigned short uint16_t;
-typedef signed int int32_t;
-typedef unsigned int uint32_t;
-typedef signed long long int64_t;
-typedef unsigned long long uint64_t;
-#ifndef _SIZE_T_DEFINED_
-#define _SIZE_T_DEFINED_
-typedef unsigned int size_t;
-#endif
-typedef unsigned int uintptr_t;
-#endif /* __GNUC__ || _MSC_VER */
-#endif /* !_STDINT_H_ && !HAVE_STDINT_H */
-
-#ifdef _WIN64
-# define SIZEOF_VOIDP 8
-#else
-# define SIZEOF_VOIDP 4
-#endif
-
-/* Useful headers */
-#define HAVE_DXGI_H 1
-#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
-#define HAVE_XINPUT_H 1
-#endif
-#define HAVE_LIBC 1
-#define HAVE_STDIO_H 1
-#define STDC_HEADERS 1
-#define HAVE_STRING_H 1
-#define HAVE_CTYPE_H 1
-#define HAVE_MATH_H 1
-#define HAVE_FLOAT_H 1
-#define HAVE_SIGNAL_H 1
-
-/* C library functions */
-#define HAVE_MALLOC 1
-#define HAVE_CALLOC 1
-#define HAVE_REALLOC 1
-#define HAVE_FREE 1
-#define HAVE_ALLOCA 1
-#define HAVE_QSORT 1
-#define HAVE_ABS 1
-#define HAVE_MEMSET 1
-#define HAVE_MEMCPY 1
-#define HAVE_MEMMOVE 1
-#define HAVE_MEMCMP 1
-#define HAVE_STRLEN 1
-#define HAVE__STRREV 1
-#define HAVE__STRUPR 1
-//#define HAVE__STRLWR 1	// TODO, WinRT: consider using _strlwr_s instead
-#define HAVE_STRCHR 1
-#define HAVE_STRRCHR 1
-#define HAVE_STRSTR 1
-//#define HAVE_ITOA 1   // TODO, WinRT: consider using _itoa_s instead
-//#define HAVE__LTOA 1	// TODO, WinRT: consider using _ltoa_s instead
-//#define HAVE__ULTOA 1	// TODO, WinRT: consider using _ultoa_s instead
-#define HAVE_STRTOL 1
-#define HAVE_STRTOUL 1
-//#define HAVE_STRTOLL 1
-#define HAVE_STRTOD 1
-#define HAVE_ATOI 1
-#define HAVE_ATOF 1
-#define HAVE_STRCMP 1
-#define HAVE_STRNCMP 1
-#define HAVE__STRICMP 1
-#define HAVE__STRNICMP 1
-#define HAVE_VSNPRINTF 1
-//#define HAVE_SSCANF 1	// TODO, WinRT: consider using sscanf_s instead
-#define HAVE_M_PI 1
-#define HAVE_ATAN 1
-#define HAVE_ATAN2 1
-#define HAVE_CEIL 1
-#define HAVE__COPYSIGN 1
-#define HAVE_COS 1
-#define HAVE_COSF 1
-#define HAVE_FABS 1
-#define HAVE_FLOOR 1
-#define HAVE_LOG 1
-#define HAVE_POW 1
-//#define HAVE_SCALBN 1
-#define HAVE__SCALB 1
-#define HAVE_SIN 1
-#define HAVE_SINF 1
-#define HAVE_SQRT 1
-#define HAVE_SQRTF 1
-#define HAVE_TAN 1
-#define HAVE_TANF 1
-#define HAVE__FSEEKI64 1
-
-/* Enable various audio drivers */
-#define SDL_AUDIO_DRIVER_XAUDIO2	1
-#define SDL_AUDIO_DRIVER_DISK	1
-#define SDL_AUDIO_DRIVER_DUMMY	1
-
-/* Enable various input drivers */
-#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
-#define SDL_JOYSTICK_DISABLED 1
-#define SDL_HAPTIC_DISABLED	1
-#else
-#define SDL_JOYSTICK_XINPUT 1
-#define SDL_HAPTIC_XINPUT   1
-#endif
-
-/* Enable various shared object loading systems */
-#define SDL_LOADSO_WINDOWS	1
-
-/* Enable various threading systems */
-#if (NTDDI_VERSION >= NTDDI_WINBLUE)
-#define SDL_THREAD_WINDOWS  1
-#else
-/* WinRT on Windows 8.0 and Windows Phone 8.0 don't support CreateThread() */
-#define SDL_THREAD_STDCPP   1
-#endif
-
-/* Enable various timer systems */
-#define SDL_TIMER_WINDOWS	1
-
-/* Enable various video drivers */
-#define SDL_VIDEO_DRIVER_WINRT	1
-#define SDL_VIDEO_DRIVER_DUMMY  1
-
-/* Enable OpenGL ES 2.0 (via a modified ANGLE library) */
-#define SDL_VIDEO_OPENGL_ES2 1
-#define SDL_VIDEO_OPENGL_EGL 1
-
-/* Enable appropriate renderer(s) */
-#define SDL_VIDEO_RENDER_D3D11  1
-
-#if SDL_VIDEO_OPENGL_ES2
-#define SDL_VIDEO_RENDER_OGL_ES2 1
-#endif
-
-/* Enable system power support */
-#define SDL_POWER_WINRT 1
-
-/* Enable assembly routines (Win64 doesn't have inline asm) */
-#ifndef _WIN64
-#define SDL_ASSEMBLY_ROUTINES	1
-#endif
-
-#endif /* SDL_config_winrt_h_ */
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_config_wiz.h
+++ /dev/null
@@ -1,121 +1,0 @@
-/*
-  Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef SDL_config_wiz_h_
-#define SDL_config_wiz_h_
-#define SDL_config_h_
-
-/* This is a set of defines to configure the SDL features */
-
-/* General platform specific identifiers */
-#include "SDL_platform.h"
-
-#define SDL_BYTEORDER 1234
-
-#define HAVE_ALLOCA_H 1
-#define HAVE_SYS_TYPES_H 1
-#define HAVE_STDIO_H 1
-#define STDC_HEADERS 1
-#define HAVE_STDLIB_H 1
-#define HAVE_STDARG_H 1
-#define HAVE_MALLOC_H 1
-#define HAVE_MEMORY_H 1
-#define HAVE_STRING_H 1
-#define HAVE_STRINGS_H 1
-#define HAVE_INTTYPES_H 1
-#define HAVE_STDINT_H 1
-#define HAVE_CTYPE_H 1
-#define HAVE_MATH_H 1
-#define HAVE_ICONV_H 1
-#define HAVE_SIGNAL_H 1
-#define HAVE_MALLOC 1
-#define HAVE_CALLOC 1
-#define HAVE_REALLOC 1
-#define HAVE_FREE 1
-#define HAVE_ALLOCA 1
-#define HAVE_GETENV 1
-#define HAVE_SETENV 1
-#define HAVE_PUTENV 1
-#define HAVE_UNSETENV 1
-#define HAVE_QSORT 1
-#define HAVE_ABS 1
-#define HAVE_BCOPY 1
-#define HAVE_MEMSET 1
-#define HAVE_MEMCPY 1
-#define HAVE_MEMMOVE 1
-#define HAVE_STRLEN 1
-#define HAVE_STRDUP 1
-#define HAVE_STRCHR 1
-#define HAVE_STRRCHR 1
-#define HAVE_STRSTR 1
-#define HAVE_STRTOL 1
-#define HAVE_STRTOUL 1
-#define HAVE_STRTOLL 1
-#define HAVE_STRTOULL 1
-#define HAVE_ATOI 1
-#define HAVE_ATOF 1
-#define HAVE_STRCMP 1
-#define HAVE_STRNCMP 1
-#define HAVE_STRCASECMP 1
-#define HAVE_STRNCASECMP 1
-#define HAVE_VSSCANF 1
-#define HAVE_VSNPRINTF 1
-#define HAVE_M_PI 1
-#define HAVE_CEIL 1
-#define HAVE_COPYSIGN 1
-#define HAVE_COS 1
-#define HAVE_COSF 1
-#define HAVE_FABS 1
-#define HAVE_FLOOR 1
-#define HAVE_LOG 1
-#define HAVE_SCALBN 1
-#define HAVE_SIN 1
-#define HAVE_SINF 1
-#define HAVE_SQRT 1
-#define HAVE_SQRTF 1
-#define HAVE_TAN 1
-#define HAVE_TANF 1
-#define HAVE_SIGACTION 1
-#define HAVE_SETJMP 1
-#define HAVE_NANOSLEEP 1
-#define HAVE_POW 1
-
-#define SDL_AUDIO_DRIVER_DUMMY 1
-#define SDL_AUDIO_DRIVER_OSS 1
-
-#define SDL_INPUT_LINUXEV 1
-#define SDL_INPUT_TSLIB 1
-#define SDL_JOYSTICK_LINUX 1
-#define SDL_HAPTIC_LINUX 1
-
-#define SDL_LOADSO_DLOPEN 1
-
-#define SDL_THREAD_PTHREAD 1
-#define SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP 1
-
-#define SDL_TIMER_UNIX 1
-
-#define SDL_VIDEO_DRIVER_DUMMY 1
-#define SDL_VIDEO_DRIVER_PANDORA 1
-#define SDL_VIDEO_RENDER_OGL_ES 1
-#define SDL_VIDEO_OPENGL_ES 1
-
-#endif /* SDL_config_wiz_h_ */
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_copying.h
+++ /dev/null
@@ -1,20 +1,0 @@
-/*
-  Simple DirectMedia Layer
-  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
-
-  This software is provided 'as-is', without any express or implied
-  warranty.  In no event will the authors be held liable for any damages
-  arising from the use of this software.
-
-  Permission is granted to anyone to use this software for any purpose,
-  including commercial applications, and to alter it and redistribute it
-  freely, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-*/
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_cpuinfo.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_cpuinfo.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_egl.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_egl.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_endian.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_endian.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_error.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_error.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_events.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_events.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_filesystem.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_filesystem.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_gamecontroller.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_gamecontroller.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_gesture.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_gesture.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_guid.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_guid.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_haptic.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_haptic.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_hidapi.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_hidapi.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_hints.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_hints.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_joystick.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_joystick.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_keyboard.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_keyboard.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_keycode.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_keycode.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_loadso.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_loadso.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_locale.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_locale.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_log.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_log.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_main.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_main.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_messagebox.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_messagebox.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_metal.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_metal.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_misc.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_misc.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_mouse.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_mouse.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_mutex.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_mutex.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_name.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_name.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_opengl.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_opengl.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_opengles.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_opengles.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_opengles2.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_opengles2.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_pixels.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_pixels.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_platform.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_platform.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_power.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_power.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_quit.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_quit.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_rect.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_rect.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_render.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_render.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_revision.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_revision.h
@@ -1,7 +1,7 @@
 /* Generated by updaterev.sh, do not edit */
 #ifdef SDL_VENDOR_INFO
-#define SDL_REVISION "SDL-release-2.26.2-0-gf070c83a6 (" SDL_VENDOR_INFO ")"
+#define SDL_REVISION "SDL-release-2.26.5-0-gac13ca9ab (" SDL_VENDOR_INFO ")"
 #else
-#define SDL_REVISION "SDL-release-2.26.2-0-gf070c83a6"
+#define SDL_REVISION "SDL-release-2.26.5-0-gac13ca9ab"
 #endif
 #define SDL_REVISION_NUMBER 0
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_rwops.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_rwops.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_scancode.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_scancode.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_sensor.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_sensor.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_shape.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_shape.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_stdinc.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_stdinc.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_surface.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_surface.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_system.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_system.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_syswm.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_syswm.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_test.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_test.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_test_assert.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_test_assert.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_test_common.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_test_common.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_test_compare.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_test_compare.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_test_crc32.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_test_crc32.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_test_font.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_test_font.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_test_fuzzer.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_test_fuzzer.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_test_harness.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_test_harness.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_test_images.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_test_images.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_test_log.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_test_log.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_test_md5.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_test_md5.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_test_memory.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_test_memory.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_test_random.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_test_random.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_thread.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_thread.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_timer.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_timer.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_touch.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_touch.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_types.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_types.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_version.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_version.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -59,7 +59,7 @@
 */
 #define SDL_MAJOR_VERSION   2
 #define SDL_MINOR_VERSION   26
-#define SDL_PATCHLEVEL      2
+#define SDL_PATCHLEVEL      5
 
 /**
  * Macro to determine SDL version program was compiled against.
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_video.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/SDL_video.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/begin_code.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/begin_code.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
--- a/vs2019_project/pt2-clone/sdl/include/SDL2/close_code.h
+++ b/vs2019_project/pt2-clone/sdl/include/SDL2/close_code.h
@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+  Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
binary files a/vs2019_project/x64/Debug/SDL2.dll b/vs2019_project/x64/Debug/SDL2.dll differ