diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..7638b1f
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,19 @@
+# Set the default behavior, in case people don't have core.autocrlf set.
+* text=auto
+
+# Declare files that will always have CRLF line endings on checkout.
+*.ac text eol=lf
+*.am text eol=lf
+*.m4 text eol=lf
+*.pc text eol=lf
+*.spec text eol=lf
+*.sh text eol=lf
+
+# Explicitly declare text files you want to always be normalized and converted
+# to native line endings on checkout.
+*.c text
+*.h text
+
+# exclude repository configurations from 'git archive'
+.git*      	export-ignore
+.travis.yml	export-ignore
diff --git a/.github/workflows/action.yml b/.github/workflows/action.yml
new file mode 100644
index 0000000..65a1a04
--- /dev/null
+++ b/.github/workflows/action.yml
@@ -0,0 +1,238 @@
+name: C/C++ CI
+
+on: [push, pull_request]
+
+jobs:
+  build:
+    strategy:
+      fail-fast: false
+      matrix:
+        name: [
+          ubuntu-gcc-autotools,
+          ubuntu-clang-autotools,
+          ubuntu-gcc-ossfuzz,
+          macos-autotools,
+          ubuntu-gcc-cmake,
+          ubuntu-gcc-cmake-shared,
+          ubuntu-clang-cmake,
+          ubuntu-clang-cmake-shared,
+          macos-cmake,
+          macos-cmake-shared,
+          windows-vs2022-x64,
+          windows-vs2022-x64-shared,
+          windows-vs2022-Win32,
+          windows-vs2022-Win32-shared
+        ]
+        include:
+          - name: ubuntu-gcc-autotools
+            os: ubuntu-latest
+            cc: gcc
+            cxx: g++
+            autotools-options: --enable-werror
+            build-system: autotools
+
+          - name: ubuntu-clang-autotools
+            os: ubuntu-latest
+            cc: clang
+            cxx: clang++
+            autotools-options: --enable-werror
+            build-system: autotools
+
+          - name: ubuntu-gcc-ossfuzz
+            os: ubuntu-latest
+            cc: gcc
+            cxx: g++
+            autotools-options: --enable-werror
+            build-system: ossfuzz
+
+          - name: macos-autotools
+            os: macos-latest
+            cc: clang
+            cxx: clang++
+            autotools-options: --enable-werror
+            build-system: autotools
+
+          - name: ubuntu-gcc-cmake
+            os: ubuntu-latest
+            cc: gcc
+            cxx: g++
+            build-system: cmake
+            cmake-generator: 'Ninja'
+            cmake-options: >-
+              -DCMAKE_BUILD_TYPE=Release
+              -DCMAKE_C_FLAGS="-Wall -Wextra"
+              -DCMAKE_VERBOSE_MAKEFILE=ON
+
+          - name: ubuntu-gcc-cmake-shared
+            os: ubuntu-latest
+            cc: gcc
+            cxx: g++
+            build-system: cmake
+            cmake-generator: 'Ninja'
+            cmake-options: >-
+              -DCMAKE_BUILD_TYPE=Release
+              -DBUILD_SHARED_LIBS=ON
+              -DCMAKE_C_FLAGS="-Wall -Wextra"
+              -DCMAKE_VERBOSE_MAKEFILE=ON
+
+          - name: ubuntu-clang-cmake
+            os: ubuntu-latest
+            cc: clang
+            cxx: clang++
+            build-system: cmake
+            cmake-generator: 'Ninja'
+            cmake-options: >-
+              -DCMAKE_BUILD_TYPE=Release
+              -DCMAKE_C_FLAGS="-Wall -Wextra"
+              -DCMAKE_VERBOSE_MAKEFILE=ON
+
+          - name: ubuntu-clang-cmake-shared
+            os: ubuntu-latest
+            cc: clang
+            cxx: clang++
+            build-system: cmake
+            cmake-generator: 'Ninja'
+            cmake-options: >-
+              -DCMAKE_BUILD_TYPE=Release
+              -DBUILD_SHARED_LIBS=ON
+              -DCMAKE_C_FLAGS="-Wall -Wextra"
+              -DCMAKE_VERBOSE_MAKEFILE=ON
+
+          - name: macos-cmake
+            os: macos-latest
+            cc: clang
+            cxx: clang++
+            build-system: cmake
+            cmake-generator: 'Unix Makefiles'
+            cmake-options: >-
+              -DCMAKE_BUILD_TYPE=Release
+              -DCMAKE_C_FLAGS="-Wall -Wextra"
+              -DCMAKE_VERBOSE_MAKEFILE=ON
+
+          - name: macos-cmake-shared
+            os: macos-latest
+            cc: clang
+            cxx: clang++
+            build-system: cmake
+            cmake-generator: 'Unix Makefiles'
+            cmake-options: >-
+              -DCMAKE_BUILD_TYPE=Release
+              -DBUILD_SHARED_LIBS=ON
+              -DCMAKE_C_FLAGS="-Wall -Wextra"
+              -DCMAKE_VERBOSE_MAKEFILE=ON
+
+          - name: windows-vs2022-x64
+            os: windows-latest
+            triplet: 'x64-windows-static'
+            build-system: cmake
+            cmake-generator: 'Visual Studio 17 2022'
+            cmake-options: >-
+              -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded$<$<CONFIG:Debug>:Debug>
+              -DCMAKE_BUILD_TYPE=Release
+              -DVCPKG_TARGET_TRIPLET=x64-windows-static
+              -DCMAKE_TOOLCHAIN_FILE=c:/vcpkg/scripts/buildsystems/vcpkg.cmake
+
+          - name: windows-vs2022-x64-shared
+            os: windows-latest
+            triplet: 'x64-windows-static'
+            build-system: cmake
+            cmake-generator: 'Visual Studio 17 2022'
+            cmake-options: >-
+              -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded$<$<CONFIG:Debug>:Debug>
+              -DBUILD_SHARED_LIBS=ON
+              -DBUILD_REGTEST=OFF
+              -DBUILD_EXAMPLES=OFF
+              -DINSTALL_PKGCONFIG_MODULE=OFF
+              -DCMAKE_BUILD_TYPE=Release
+              -DVCPKG_TARGET_TRIPLET=x64-windows-static
+              -DCMAKE_TOOLCHAIN_FILE=c:/vcpkg/scripts/buildsystems/vcpkg.cmake
+
+          - name: windows-vs2022-Win32
+            os: windows-latest
+            triplet: 'x86-windows-static'
+            build-system: cmake
+            cmake-generator: 'Visual Studio 17 2022'
+            cmake-options: >-
+              -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded$<$<CONFIG:Debug>:Debug>
+              -DCMAKE_GENERATOR_PLATFORM=Win32
+              -DCMAKE_BUILD_TYPE=Release
+              -DVCPKG_TARGET_TRIPLET=x86-windows-static
+              -DCMAKE_TOOLCHAIN_FILE=c:/vcpkg/scripts/buildsystems/vcpkg.cmake
+
+          - name: windows-vs2022-Win32-shared
+            os: windows-latest
+            triplet: 'x86-windows-static'
+            build-system: cmake
+            cmake-generator: 'Visual Studio 17 2022'
+            cmake-options: >-
+              -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded$<$<CONFIG:Debug>:Debug>
+              -DCMAKE_GENERATOR_PLATFORM=Win32
+              -DBUILD_SHARED_LIBS=ON
+              -DBUILD_REGTEST=OFF
+              -DBUILD_EXAMPLES=OFF
+              -DINSTALL_PKGCONFIG_MODULE=OFF
+              -DCPACK_PACKAGE_NAME=libsndfile
+              -DCMAKE_BUILD_TYPE=Release
+              -DVCPKG_TARGET_TRIPLET=x86-windows-static
+              -DCMAKE_TOOLCHAIN_FILE=c:/vcpkg/scripts/buildsystems/vcpkg.cmake
+
+    runs-on: ${{ matrix.os }}
+    steps:
+      - uses: actions/checkout@v2
+
+      - name: Install MacOS dependencies
+        if: startsWith(matrix.os,'macos')
+        run: |
+          brew install automake autogen speex mpg123
+
+      - name: Install Linux dependencies
+        if: startsWith(matrix.os,'ubuntu')
+        run: sudo apt-get update -y && sudo apt-get install -y autogen ninja-build libogg-dev libvorbis-dev libflac-dev libopus-dev libasound2-dev libsqlite3-dev libspeex-dev libmp3lame-dev libmpg123-dev
+
+      - name: Setup NuGet Credentials
+        env:
+          VCPKG_BINARY_SOURCES: 'clear;nuget,GitHub,readwrite'
+        if: startsWith(matrix.os,'windows')
+        shell: 'bash'
+        run: >
+          `vcpkg fetch nuget | tail -n 1`
+          sources add
+          -source "https://nuget.pkg.github.com/libsndfile/index.json"
+          -storepasswordincleartext
+          -name "GitHub"
+          -username "evpobr"
+          -password "${{ secrets.GITHUB_TOKEN }}"
+
+      - name: Configure, build and test with Autotools
+        env:
+          CC: ${{ matrix.cc }}
+          CXX: ${{ matrix.cxx }}
+        if: startsWith(matrix.build-system,'autotools')
+        run: |
+          ./autogen.sh
+          if [[ "${CC}" == "clang" ]]; then
+            ./configure --enable-werror && make distcheck
+          else
+            Scripts/asan-configure.sh --enable-werror && make distcheck
+          fi
+
+      - name: Configure, build and test with CMake
+        env:
+          CC: ${{ matrix.cc }}
+          CXX: ${{ matrix.cxx }}
+          VCPKG_BINARY_SOURCES: 'clear;nuget,GitHub,readwrite'
+        if: startsWith(matrix.build-system,'cmake')
+        run: |
+          mkdir build
+          cd build
+          cmake .. -G "${{matrix.cmake-generator}}" ${{matrix.cmake-options}}
+          cmake --build . --config Release
+          ctest
+
+      - name: Configure, build and test with OSSFuzz
+        env:
+          CC: ${{ matrix.cc }}
+          CXX: ${{ matrix.cxx }}
+        if: startsWith(matrix.build-system,'ossfuzz')
+        run: |
+          ./ossfuzz/ci_oss.sh
diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml
new file mode 100644
index 0000000..58ef9c4
--- /dev/null
+++ b/.github/workflows/cifuzz.yml
@@ -0,0 +1,26 @@
+name: CIFuzz
+on: [pull_request]
+jobs:
+  Fuzzing:
+    runs-on: ubuntu-latest
+    steps:
+    - name: Build Fuzzers
+      id: build
+      uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
+      with:
+        oss-fuzz-project-name: 'libsndfile'
+        dry-run: false
+        language: c
+    - name: Run Fuzzers
+      uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
+      with:
+        oss-fuzz-project-name: 'libsndfile'
+        fuzz-seconds: 600
+        dry-run: false
+        language: c
+    - name: Upload Crash
+      uses: actions/upload-artifact@v1
+      if: failure() && steps.build.outcome == 'success'
+      with:
+        name: artifacts
+        path: ./out/artifacts
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..05f79a9
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,146 @@
+*.user
+*.8svx
+*.a
+*.aif
+*.aifc
+*.aiff
+*.au
+*.bin
+*.caf
+*.dll
+*.exe
+*.flac
+*.la
+*.lib
+*.lo
+*.loT
+*.o
+*.oct
+*.oga
+*.ogg
+*.paf
+*.raw
+*.rifx
+*.sd2
+*.sds
+*.svx
+/*.so*
+*.w64
+*.wav
+*.wavex
+.DS_Store
+.deps
+.dirstamp
+.libs
+Hack
+Hack/sndfile-fuzzbomb
+INSTALL
+m4/libtool.m4
+m4/ltoptions.m4
+m4/ltsugar.m4
+m4/ltversion.m4
+m4/lt~obsolete.m4
+Makefile
+Makefile.in
+aclocal.m4
+autom4te.cache
+build-test-tarball.mk
+config.log
+config.status
+configure
+configure~
+doc/AUTHORS
+doc/ChangeLog
+doc/NEWS
+doc/README
+doc/libsndfile.css
+echo-install-dirs
+examples/generate
+examples/list_formats
+examples/make_sine
+examples/sfprocess
+examples/sndfile-loopify
+examples/sndfile-to-text
+examples/sndfilehandle
+include/sndfile.h
+libsndfile-*.tar.xz
+libsndfile-testsuite-*
+libsndfile.spec
+libtool
+man/sndfile-deinterleave.1
+man/sndfile-metadata-set.1
+programs/sndfile-cmp
+programs/sndfile-concat
+programs/sndfile-convert
+programs/sndfile-data-trim
+programs/sndfile-deinterleave
+programs/sndfile-info
+programs/sndfile-interleave
+programs/sndfile-jackplay
+programs/sndfile-metadata-get
+programs/sndfile-metadata-set
+programs/sndfile-play
+programs/sndfile-salvage
+regtest/sndfile-regtest
+sndfile.pc
+src/Ext
+src/G72x/g72x_test
+Symbols.darwin
+Symbols.gnu-binutils
+Symbols.os2
+Symbols.static
+src/config.h
+src/config.h.in
+src/config.h.in~
+src/libsndfile.so*
+libsndfile*.def
+src/stamp-h1
+src/test_endswap.c
+src/test_main
+src/version-metadata.rc
+tests/*_test
+tests/benchmark
+tests/benchmark.c
+tests/fix_this
+tests/floating_point_test.c
+tests/header_test.c
+tests/libsndfile-1.dll
+tests/pcm_test.c
+tests/pedantic-header-test.sh
+tests/pipe_test.c
+tests/rdwr_test.c
+tests/scale_clip_test.c
+tests/sfversion
+tests/test_wrapper.sh
+tests/utils.c
+tests/utils.h
+tests/write_read_test.c
+*.log
+*.trs
+.vs/
+packages/
+*.vcxproj.user
+*.VC.db
+*.VC.opendb
+Debug/
+Release/
+bin/
+obj/
+octave-workspace
+
+CMakeCache.txt
+CMakeFiles
+CMakeScripts
+Testing
+Makefile
+cmake_install.cmake
+install_manifest.txt
+compile_commands.json
+CTestTestfile.cmake
+CMakeSettings.json
+
+/*[Bb]uild*/
+
+/.vscode/
+/.vs/
+/out/
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3719e0f..d61761e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ## [Unreleased]
 
+### Fixed
+
+* Searching for LAME dependency with CMake build system (issue #821).
+* CMake build from Autotools tarball (issue #816).
+* Build on UWP platform (issue #824).
+* Fix signed integer overflow (issue #785).
+* Skipping large wav chunks on stdin (PR #819).
+
+### Removed
+
+* Maximum samplerate limit, thanks @drmpeg, @justacec (issue #850).
+  
+  In version 1.1.0, an artificial limit of 655350 Hz was created, but as it
+  turned out, this is not enough for some scenarios.
+
 ## [1.1.0] - 2022-03-27
 
 ### Added
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b1b49e9..ae8ebec 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -174,7 +174,7 @@ set_package_properties (FLAC PROPERTIES
 	DESCRIPTION "Free Lossless Audio Codec Library"
 	PURPOSE "Enables FLAC support"
 	)
-set_package_properties (Lame PROPERTIES
+set_package_properties (mp3lame PROPERTIES
 	TYPE RECOMMENDED
 	URL "https://lame.sourceforge.io/"
 	DESCRIPTION "High quality MPEG Audio Layer III (MP3) encoder"
@@ -237,20 +237,7 @@ if (INSTALL_PKGCONFIG_MODULE)
 	endif ()
 	if (ENABLE_MPEG)
 		set (EXTERNAL_MPEG_REQUIRE "libmpg123")
-		get_filename_component(LAME_WE ${LAME_LIBRARY} NAME_WE)
-		if (LAME_HIP_LIBRARY)
-			get_filename_component(LAME_HIP_WE ${LAME_HIP_LIBRARY} NAME_WE)
-		endif ()
-		if (CMAKE_IMPORT_LIBRARY_PREFIX)
-			string (REGEX REPLACE "^${CMAKE_IMPORT_LIBRARY_PREFIX}" "" LAME_WE_NO_PREFIX ${LAME_WE})
-			if (LAME_HIP_LIBRARY)
-				string (REGEX REPLACE "^${CMAKE_IMPORT_LIBRARY_PREFIX}" "" LAME_HIP_WE_NO_PREFIX ${LAME_HIP_WE})
-			endif ()
-		endif ()
-		set (EXTERNAL_MPEG_LIBS "-l${LAME_WE_NO_PREFIX}")
-		if (LAME_HIP_LIBRARY)
-			set (EXTERNAL_MPEG_LIBS "${MPEG_LIBS} -l${LAME_HIP_WE}")
-		endif ()
+		set (EXTERNAL_MPEG_LIBS "-lmp3lame")
 	endif ()
 
 	configure_file (sndfile.pc.in sndfile.pc @ONLY)
@@ -411,7 +398,7 @@ target_link_libraries (sndfile
 		$<$<AND:$<BOOL:${ENABLE_EXPERIMENTAL}>,$<BOOL:${HAVE_EXTERNAL_XIPH_LIBS}>,$<BOOL:${HAVE_SPEEX}>>:Speex::Speex>
 		$<$<BOOL:${HAVE_EXTERNAL_XIPH_LIBS}>:Opus::opus>
 		$<$<BOOL:${HAVE_MPEG}>:MPG123::libmpg123>
-		$<$<BOOL:${HAVE_MPEG}>:Lame::Lame>
+		$<$<BOOL:${HAVE_MPEG}>:mp3lame::mp3lame>
 	)
 set_target_properties (sndfile PROPERTIES
 	PUBLIC_HEADER "${sndfile_HDRS}"
diff --git a/Makefile.am b/Makefile.am
index d2bbdcb..5efbf9a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -24,6 +24,7 @@ cmake_files = cmake/ClipMode.cmake cmake/FindFLAC.cmake \
 	cmake/TestLargeFiles.cmake cmake/TestInline.c.in \
 	cmake/FindOpus.cmake cmake/SndFileConfig.cmake.in \
 	cmake/CheckCPUArch.cmake cmake/CheckCPUArch.c.in \
+	cmake/Findmp3lame.cmake cmake/FindMpg123.cmake \
 	cmake/SetupABIVersions.cmake
 
 pkgconfig_DATA = sndfile.pc
diff --git a/cmake/FindLame.cmake b/cmake/FindLame.cmake
deleted file mode 100644
index be32475..0000000
--- a/cmake/FindLame.cmake
+++ /dev/null
@@ -1,66 +0,0 @@
-# - Find lame
-# Find the native lame includes and libraries
-#
-#  LAME_INCLUDE_DIRS - where to find lame.h, etc.
-#  LAME_LIBRARIES    - List of libraries when using lame.
-#  LAME_FOUND        - True if Lame found.
-
-if (LAME_INCLUDE_DIR)
-    # Already in cache, be silent
-    set(LAME_FIND_QUIETLY TRUE)
-endif ()
-
-find_path (LAME_INCLUDE_DIR lame/lame.h
-	HINTS
-		${LAME_ROOT}
-	)
-
-# MSVC built lame may be named mp3lame_static.
-# The provided project files name the library with the lib prefix.
-
-find_library (LAME_LIBRARY
-	NAMES
-		mp3lame
-		mp3lame_static
-		libmp3lame
-		libmp3lame_static
-		libmp3lame-static
-	HINTS
-		${LAME_ROOT}
-	)
-
-find_library (LAME_HIP_LIBRARY
-	NAMES
-		mpghip-static
-		libmpghip-static
-	HINTS
-		${LAME_ROOT}
-	)
-
-# Handle the QUIETLY and REQUIRED arguments and set LAME_FOUND
-# to TRUE if all listed variables are TRUE.
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args (Lame
-	REQUIRED_VARS
-		LAME_LIBRARY
-		LAME_INCLUDE_DIR
-	)
-
-if (LAME_FOUND)
-	set (LAME_LIBRARIES ${LAME_LIBRARY} ${LAME_HIP_LIBRARY})
-	set (LAME_INCLUDE_DIRS ${LAME_INCLUDE_DIR})
-
-	if (NOT TARGET Lame::Lame)
-		add_library (Lame::Lame UNKNOWN IMPORTED)
-		set_target_properties (Lame::Lame PROPERTIES
-			INTERFACE_INCLUDE_DIRECTORIES "${LAME_INCLUDE_DIRS}"
-			IMPORTED_LOCATION "${LAME_LIBRARY}"
-		)
-		if (LAME_HIP_LIBRARY)
-			set_property (TARGET Lame::Lame APPEND PROPERTY
-				INTERFACE_LINK_LIBRARIES "${LAME_HIP_LIBRARY}")
-		endif ()
-	endif ()
-endif ()
-
-mark_as_advanced(LAME_INCLUDE_DIR LAME_LIBRARY LAME_HIP_LIBRARY)
diff --git a/cmake/Findmp3lame.cmake b/cmake/Findmp3lame.cmake
new file mode 100644
index 0000000..223dd08
--- /dev/null
+++ b/cmake/Findmp3lame.cmake
@@ -0,0 +1,67 @@
+# - Find lame
+# Find the native lame includes and libraries
+#
+#  MP3LAME_INCLUDE_DIRS - where to find lame.h, etc.
+#  MP3LAME_LIBRARIES    - List of libraries when using lame.
+#  MP3LAME_FOUND        - True if Lame found.
+
+if (MP3LAME_INCLUDE_DIR)
+    # Already in cache, be silent
+    set(MP3LAME_FIND_QUIETLY TRUE)
+endif ()
+
+find_path (MP3LAME_INCLUDE_DIR lame/lame.h
+	HINTS
+		${LAME_ROOT}
+	)
+
+# MSVC built lame may be named mp3lame_static.
+# The provided project files name the library with the lib prefix.
+
+find_library (MP3LAME_LIBRARY
+	NAMES
+		mp3lame
+		mp3lame_static
+		libmp3lame
+		libmp3lame_static
+		libmp3lame-static
+	HINTS
+		${MP3LAME_ROOT}
+	)
+
+find_library (MP3LAME_HIP_LIBRARY
+	NAMES
+		mpghip-static
+		libmpghip-static
+	HINTS
+		${MP3LAME_ROOT}
+	)
+
+# Handle the QUIETLY and REQUIRED arguments and set LAME_FOUND
+# to TRUE if all listed variables are TRUE.
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args (mp3lame
+	REQUIRED_VARS
+		MP3LAME_LIBRARY
+		MP3LAME_INCLUDE_DIR
+	)
+
+if (MP3LAME_FOUND)
+	set (MP3LAME_LIBRARIES ${MP3LAME_LIBRARY} ${MP3LAME_HIP_LIBRARY})
+	set (MP3LAME_INCLUDE_DIRS ${MP3LAME_INCLUDE_DIR})
+
+	if (NOT TARGET mp3lame::mp3lame)
+		add_library (mp3lame::mp3lame UNKNOWN IMPORTED)
+		set_target_properties (mp3lame::mp3lame PROPERTIES
+			INTERFACE_INCLUDE_DIRECTORIES "${MP3LAME_INCLUDE_DIRS}"
+			IMPORTED_LOCATION "${MP3LAME_LIBRARY}"
+		)
+		if (MP3LAME_HIP_LIBRARY AND (NOT TARGET mp3lame::mpghip))
+			add_library (mp3lame::mpghip STATIC IMPORTED)
+			set_property (mp3lame::mpghip PROPERTY IMPORTED_LOCATION "${MP3LAME_HIP_LIBRARY}")
+			set_property (TARGET mp3lame::mp3lame PROPERTY INTERFACE_LINK_LIBRARIES "mp3lame::mpghip")
+		endif ()
+	endif ()
+endif ()
+
+mark_as_advanced(MP3LAME_INCLUDE_DIR MP3LAME_LIBRARY MP3LAME_HIP_LIBRARY)
diff --git a/cmake/SndFileChecks.cmake b/cmake/SndFileChecks.cmake
index f5d5994..2e09ba6 100644
--- a/cmake/SndFileChecks.cmake
+++ b/cmake/SndFileChecks.cmake
@@ -56,9 +56,9 @@ else ()
 	set (HAVE_EXTERNAL_XIPH_LIBS 0)
 endif ()
 
-find_package (Lame)
+find_package (mp3lame)
 find_package (Mpg123 1.25.10)
-if (LAME_FOUND AND (TARGET MPG123::libmpg123))
+if (TARGET mp3lame::mp3lame AND (TARGET MPG123::libmpg123))
 	set (HAVE_MPEG_LIBS 1)
 else ()
 	set (HAVE_MPEG_LIBS 0)
diff --git a/cmake/SndFileConfig.cmake.in b/cmake/SndFileConfig.cmake.in
index 1d5463a..0c98e7e 100644
--- a/cmake/SndFileConfig.cmake.in
+++ b/cmake/SndFileConfig.cmake.in
@@ -18,7 +18,7 @@ if (SndFile_WITH_EXTERNAL_LIBS AND NOT @BUILD_SHARED_LIBS@)
 endif ()
 
 if (SndFile_WITH_MPEG AND NOT @BUILD_SHARED_LIBS@)
-	find_dependency (Lame)
+	find_dependency (mp3lame)
 	find_dependency (MPG123)
 endif ()
 
diff --git a/configure.ac b/configure.ac
index 727b67b..a4c776d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -739,6 +739,7 @@ AC_SUBST(SNDIO_LIBS)
 AC_SUBST(EXTERNAL_XIPH_CFLAGS)
 AC_SUBST(EXTERNAL_XIPH_LIBS)
 AC_SUBST(EXTERNAL_XIPH_REQUIRE)
+AC_SUBST(EXTERNAL_MPEG_LIBS)
 AC_SUBST(EXTERNAL_MPEG_REQUIRE)
 AC_SUBST(MPG123_CFLAGS)
 AC_SUBST(MPG123_LIBS)
diff --git a/debian/changelog b/debian/changelog
index 9751224..01369c4 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
+libsndfile (1.1.0+git20220806.1.36216ba+ds-1) UNRELEASED; urgency=low
+
+  * New upstream snapshot.
+  * Drop patch fix-pkg-config.patch, present upstream.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Tue, 06 Sep 2022 22:07:38 -0000
+
 libsndfile (1.1.0-1) unstable; urgency=medium
 
   * New upstream version 1.1.0
diff --git a/debian/patches/fix-pkg-config.patch b/debian/patches/fix-pkg-config.patch
deleted file mode 100644
index ff1ca3c..0000000
--- a/debian/patches/fix-pkg-config.patch
+++ /dev/null
@@ -1,17 +0,0 @@
-Description: fix substitutions in pkg-config file
-Author: IOhannes m zmölnig
-Origin: Debian
-Forwarded: no
-Last-Update: 2022-08-06
----
-This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
---- libsndfile.orig/configure.ac
-+++ libsndfile/configure.ac
-@@ -739,6 +739,7 @@
- AC_SUBST(EXTERNAL_XIPH_CFLAGS)
- AC_SUBST(EXTERNAL_XIPH_LIBS)
- AC_SUBST(EXTERNAL_XIPH_REQUIRE)
-+AC_SUBST(EXTERNAL_MPEG_LIBS)
- AC_SUBST(EXTERNAL_MPEG_REQUIRE)
- AC_SUBST(MPG123_CFLAGS)
- AC_SUBST(MPG123_LIBS)
diff --git a/debian/patches/fix_typos.patch b/debian/patches/fix_typos.patch
index 2d7aef0..a05d853 100644
--- a/debian/patches/fix_typos.patch
+++ b/debian/patches/fix_typos.patch
@@ -13,9 +13,11 @@ discovered by lintian
  src/wavlike.c              | 2 +-
  4 files changed, 4 insertions(+), 4 deletions(-)
 
+Index: libsndfile/programs/sndfile-convert.c
+===================================================================
 --- libsndfile.orig/programs/sndfile-convert.c
 +++ libsndfile/programs/sndfile-convert.c
-@@ -336,7 +336,7 @@
+@@ -336,7 +336,7 @@ main (int argc, char * argv [])
  	if ((sfinfo.format & SF_FORMAT_SUBMASK) == SF_FORMAT_GSM610 && sfinfo.samplerate != 8000)
  	{	printf (
  			"WARNING: GSM 6.10 data format only supports 8kHz sample rate. The converted\n"
@@ -24,9 +26,11 @@ discovered by lintian
  			"but not re-sampled.\n"
  			) ;
  		} ;
+Index: libsndfile/src/ogg.c
+===================================================================
 --- libsndfile.orig/src/ogg.c
 +++ libsndfile/src/ogg.c
-@@ -807,7 +807,7 @@
+@@ -809,7 +809,7 @@ ogg_stream_classify (SF_PRIVATE *psf, OG
  			break ;
  		} ;
  
@@ -35,9 +39,11 @@ discovered by lintian
  	return SFE_UNIMPLEMENTED ;
  } /* ogg_stream_classify */
  
+Index: libsndfile/src/wavlike.c
+===================================================================
 --- libsndfile.orig/src/wavlike.c
 +++ libsndfile/src/wavlike.c
-@@ -161,7 +161,7 @@
+@@ -161,7 +161,7 @@ wavlike_read_fmt_chunk (SF_PRIVATE *psf,
  	{	psf_log_printf (psf, "  Bit Width     : 24\n") ;
  
  		psf_log_printf (psf, "\n"
@@ -46,9 +52,11 @@ discovered by lintian
  			"    0) Invalid IEEE float file generated by Syntrillium's Cooledit!\n"
  			"    1) File generated by ALSA's arecord containing 24 bit samples in 32 bit containers.\n"
  			"    2) 24 bit file with incorrect Block Align value.\n"
+Index: libsndfile/src/ogg_opus.c
+===================================================================
 --- libsndfile.orig/src/ogg_opus.c
 +++ libsndfile/src/ogg_opus.c
-@@ -1440,7 +1440,7 @@
+@@ -1448,7 +1448,7 @@ ogg_opus_analyze_file (SF_PRIVATE *psf)
  		oopus->pkt_pos = oopus->pg_pos - gp ;
  		}
  	else if (gp < oopus->pg_pos)
@@ -57,9 +65,11 @@ discovered by lintian
  		return SFE_MALFORMED_FILE ;
  		} ;
  	oopus->u.decode.gp_start = oopus->pkt_pos ;
+Index: libsndfile/tests/misc_test.c
+===================================================================
 --- libsndfile.orig/tests/misc_test.c
 +++ libsndfile/tests/misc_test.c
-@@ -293,7 +293,7 @@
+@@ -293,7 +293,7 @@ filesystem_full_test (int format)
  	sfinfo.frames = 0 ;
  
  	if ((file = sf_open (filename, SFM_WRITE, &sfinfo)) != NULL)
@@ -68,9 +78,11 @@ discovered by lintian
  		exit (1) ;
  		} ;
  
+Index: libsndfile/tests/win32_test.c
+===================================================================
 --- libsndfile.orig/tests/win32_test.c
 +++ libsndfile/tests/win32_test.c
-@@ -135,7 +135,7 @@
+@@ -135,7 +135,7 @@ show_fstat_error (void)
  
  	printf ("2) Now use system (\"%s %s\") to show the file length.\n\n", dir_cmd, filename) ;
  
@@ -79,7 +91,7 @@ discovered by lintian
  	memset (data, 0, sizeof (data)) ;
  	strncpy (data, dir_cmd, sizeof (data) - 1) ;
  	strncat (data, " ", sizeof (data) - 1 - strlen (data)) ;
-@@ -155,7 +155,7 @@
+@@ -155,7 +155,7 @@ show_fstat_error (void)
  	close (fd) ;
  
  	if (statbuf.st_size != 2 * sizeof (data))
@@ -88,7 +100,7 @@ discovered by lintian
  	else
  	{	printf ("which is correct.\n\n") ;
  		unlink (filename) ;
-@@ -196,7 +196,7 @@
+@@ -196,7 +196,7 @@ show_lseek_error (void)
  
  	printf ("2) Now use system (\"%s %s\") to show the file length.\n\n", dir_cmd, filename) ;
  
@@ -97,7 +109,7 @@ discovered by lintian
  	memset (data, 0, sizeof (data)) ;
  	strncpy (data, dir_cmd, sizeof (data) - 1) ;
  	strncat (data, " ", sizeof (data) - 1 - strlen (data)) ;
-@@ -213,7 +213,7 @@
+@@ -213,7 +213,7 @@ show_lseek_error (void)
  	close (fd) ;
  
  	if (retval != 2 * sizeof (data))
@@ -106,7 +118,7 @@ discovered by lintian
  	else
  	{	printf ("which is correct.\n\n") ;
  		unlink (filename) ;
-@@ -244,7 +244,7 @@
+@@ -244,7 +244,7 @@ show_stat_fstat_error (void)
  
  	assert (write (fd, data, sizeof (data)) > 0) ;
  
@@ -115,7 +127,7 @@ discovered by lintian
  
  	if (stat (filename, &buf) != 0)
  	{	printf ("\n\nLine %d: stat() failed : %s\n\n", __LINE__, strerror (errno)) ;
-@@ -262,7 +262,7 @@
+@@ -262,7 +262,7 @@ show_stat_fstat_error (void)
  
  
  	if (stat_size == 0 || stat_size != fstat_size)
diff --git a/debian/patches/series b/debian/patches/series
index c60ed95..48dc2d5 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,2 +1 @@
 fix_typos.patch
-fix-pkg-config.patch
diff --git a/docs/api.md b/docs/api.md
index 7025443..047fb4a 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -97,10 +97,9 @@ calling **sf_open**(). The only exception to this is the case of RAW files where
 the caller has to set the **samplerate**, **channels** and **format** fields to
 valid values. All other fields of the structure are filled in by the library.
 
-**Note:** The libsndfile library will reject values ​​for **samplerate** field
-that are greater than `655350` and values ​​for field **channels** that are
-greater than `1024`. These values ​​represent the maximum theoretical limit and
-may be less for specific formats.
+**Note:** The libsndfile library will reject values ​​for field **channels** that
+are greater than `1024`. These value ​​represent the maximum theoretical limit
+and may be less for specific formats.
 
 When opening a file for write, the caller must fill in structure members
 **samplerate**, **channels**, and **format**.
diff --git a/docs/command.md b/docs/command.md
index 6d2133a..b5a76f6 100644
--- a/docs/command.md
+++ b/docs/command.md
@@ -64,6 +64,7 @@ The available commands are as follows:
 | [SFC_WAVEX_SET_AMBISONIC](#sfc_wavex_set_ambisonic)               | Modify a WAVEX header for Ambisonic format.             |
 | [SFC_SET_VBR_ENCODING_QUALITY](#sfc_set_vbr_encoding_quality)     | Set the Variable Bit Rate encoding quality.             |
 | [SFC_SET_OGG_PAGE_LATENCY_MS](#sfc_set_ogg_page_latency_ms)       | Set Ogg page latency for Opus file.                     |
+| [SFC_GET_OGG_STREAM_SERIALNO](#sfc_get_ogg_stream_serialno)       | Get Ogg stream serial number.                           |
 | [SFC_SET_COMPRESSION_LEVEL](#sfc_set_compression_level)           | Set the compression level.                              |
 | [SFC_RAW_DATA_NEEDS_ENDSWAP](#sfc_raw_data_needs_endswap)         | Determine if raw data needs endswapping.                |
 | [SFC_GET_BROADCAST_INFO](#sfc_get_broadcast_info)                 | Get the Broadcast Chunk info.                           |
@@ -81,8 +82,8 @@ The available commands are as follows:
 | [SFC_RF64_AUTO_DOWNGRADE](#sfc_rf64_auto_downgrade)               | Set auto downgrade from RF64 to WAV.                    |
 | [SFC_GET_ORIGINAL_SAMPLERATE](#sfc_get_original_samplerate)       | Get original samplerate metadata.                       |
 | [SFC_SET_ORIGINAL_SAMPLERATE](#sfc_set_original_samplerate)       | Set original samplerate metadata.                       |
-| [SFC_GET_BITRATE_MODE](#sfc_get_bitrate_mode)                     | Get bitrate mode.
-| [SFC_SET_BITRATE_MODE](#sfc_set_bitrate_mode)                     | Set bitrate mode.
+| [SFC_GET_BITRATE_MODE](#sfc_get_bitrate_mode)                     | Get bitrate mode.                                       |
+| [SFC_SET_BITRATE_MODE](#sfc_set_bitrate_mode)                     | Set bitrate mode.                                       |
 
 ---
 
@@ -1273,6 +1274,30 @@ datasize
 
 0 on success and non-zero otherwise.
 
+## SFC_GET_OGG_STREAM_SERIALNO
+
+Get the Ogg stream serial number for files with the Ogg major format. Ogg
+stream serail numbers are a randomly chosen 32-bit value, used for
+differentiating logical Ogg streams.
+
+### Parameters
+
+sndfile
+: A valid SNDFILE* pointer
+
+cmd
+: SFC_SET_OGG_STREAM_SERIALNO
+
+data
+: A pointer to a 32-bit int value
+
+datasize
+: sizeof (int32_t) = 4
+
+### Return value
+
+0 on success and non-zero otherwise.
+
 ## SFC_SET_COMPRESSION_LEVEL
 
 Set the compression level. The compression level should be between 0.0 (minimum
diff --git a/include/sndfile.h.in b/include/sndfile.h.in
index 2bcbdb1..8842fd4 100644
--- a/include/sndfile.h.in
+++ b/include/sndfile.h.in
@@ -220,8 +220,11 @@ enum
 
 	SFC_SET_VBR_ENCODING_QUALITY	= 0x1300,
 	SFC_SET_COMPRESSION_LEVEL		= 0x1301,
+
+	/* Ogg format commands */
 	SFC_SET_OGG_PAGE_LATENCY_MS		= 0x1302,
 	SFC_SET_OGG_PAGE_LATENCY		= 0x1303,
+	SFC_GET_OGG_STREAM_SERIALNO		= 0x1306,
 
 	SFC_GET_BITRATE_MODE			= 0x1304,
 	SFC_SET_BITRATE_MODE			= 0x1305,
diff --git a/ossfuzz/.gitignore b/ossfuzz/.gitignore
new file mode 100644
index 0000000..6e9ed16
--- /dev/null
+++ b/ossfuzz/.gitignore
@@ -0,0 +1 @@
+sndfile_fuzzer
diff --git a/src/aiff.c b/src/aiff.c
index 7ad0312..4c66245 100644
--- a/src/aiff.c
+++ b/src/aiff.c
@@ -404,7 +404,7 @@ aiff_read_header (SF_PRIVATE *psf, COMM_CHUNK *comm_fmt)
 	char		*cptr ;
 	int			instr_found = 0, mark_found = 0 ;
 
-	if (psf->filelength > SF_PLATFORM_S64 (0xffffffff))
+	if (psf->filelength > 0xFFFFFFFFLL)
 		psf_log_printf (psf, "Warning : filelength > 0xffffffff. This is bad!!!!\n") ;
 
 	if ((paiff = psf->container_data) == NULL)
diff --git a/src/common.c b/src/common.c
index c4ef4a6..ddf621b 100644
--- a/src/common.c
+++ b/src/common.c
@@ -925,8 +925,22 @@ header_seek (SF_PRIVATE *psf, sf_count_t position, int whence)
 
 			if (psf->header.indx + position > psf->header.len)
 			{	/* Need to jump this without caching it. */
+				position -= (psf->header.end - psf->header.indx) ;
 				psf->header.indx = psf->header.end ;
-				psf_fseek (psf, position, SEEK_CUR) ;
+				if (psf->is_pipe)
+				{
+					/* seeking is not supported on pipe input, so we read instead */
+					size_t skip = position ;
+					while (skip)
+					{	char junk [16 * 1024] ;
+						size_t to_skip = SF_MIN (skip, sizeof (junk)) ;
+						psf_fread (junk, 1, to_skip, psf) ;
+						skip -= to_skip ;
+						}
+					}
+				else
+				{	psf_fseek (psf, position, SEEK_CUR) ;
+					}
 				break ;
 				} ;
 
diff --git a/src/common.h b/src/common.h
index 6ca0648..c7747c5 100644
--- a/src/common.h
+++ b/src/common.h
@@ -50,20 +50,6 @@
 #error "This code is not designed to be compiled with a C++ compiler."
 #endif
 
-#ifdef INT64_C
-#	define	SF_PLATFORM_S64(x)		INT64_C (x)
-#elif (SIZEOF_LONG == 8)
-#	define	SF_PLATFORM_S64(x)		x##l
-#elif (SIZEOF_LONG_LONG == 8)
-#	define	SF_PLATFORM_S64(x)		x##ll
-#elif COMPILER_IS_GCC
-#	define	SF_PLATFORM_S64(x)		x##ll
-#elif OS_IS_WIN32
-#	define	SF_PLATFORM_S64(x)		x##I64
-#else
-#	error "Don't know how to define a 64 bit integer constant."
-#endif
-
 
 
 /*
@@ -110,9 +96,6 @@
 
 
 #define		SF_MAX_CHANNELS		1024
-/* Max FLAC sample rate : https://xiph.org/flac/format.html */
-#define		SF_MAX_SAMPLERATE	655350
-
 
 /*
 *	Macros for spliting the format file of SF_INFO into container type,
diff --git a/src/file_io.c b/src/file_io.c
index 334ba2a..90c9608 100644
--- a/src/file_io.c
+++ b/src/file_io.c
@@ -827,9 +827,6 @@ psf_open_handle (PSF_FILE * pfile)
 		} ;
 
 #if defined (WINAPI_FAMILY_PARTITION) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
-	if (!pfile->use_wchar)
-		return INVALID_HANDLE_VALUE ;
-
 	CREATEFILE2_EXTENDED_PARAMETERS cfParams = { 0 } ;
 	cfParams.dwSize = sizeof (CREATEFILE2_EXTENDED_PARAMETERS) ;
 	cfParams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL ;
diff --git a/src/flac.c b/src/flac.c
index 8caf4fa..20cbb1b 100644
--- a/src/flac.c
+++ b/src/flac.c
@@ -43,6 +43,15 @@
 
 #define ENC_BUFFER_SIZE 8192
 
+/*
+** READ_LOOP_MAX_LEN is the maximum 'len' that will be passed to
+** flac_read_loop().  This is somewhat arbitrary, but must be less
+** than (UINT_MAX - FLAC__MAX_CHANNELS * FLAC__MAX_BLOCK_SIZE) to
+** avoid overflows, and must also be a multiple of the number of
+** channels (which is between 1 and 8.)
+*/
+#define READ_LOOP_MAX_LEN (0x10000 * 3 * 5 * 7)
+
 typedef enum
 {	PFLAC_PCM_SHORT = 50,
 	PFLAC_PCM_INT = 51,
@@ -977,7 +986,7 @@ flac_read_flac2s (SF_PRIVATE *psf, short *ptr, sf_count_t len)
 
 	while (total < len)
 	{	pflac->ptr = ptr + total ;
-		readlen = (len - total > 0x1000000) ? 0x1000000 : (unsigned) (len - total) ;
+		readlen = (len - total > READ_LOOP_MAX_LEN) ? READ_LOOP_MAX_LEN : (unsigned) (len - total) ;
 		current = flac_read_loop (psf, readlen) ;
 		if (current == 0)
 			break ;
@@ -997,7 +1006,7 @@ flac_read_flac2i (SF_PRIVATE *psf, int *ptr, sf_count_t len)
 
 	while (total < len)
 	{	pflac->ptr = ptr + total ;
-		readlen = (len - total > 0x1000000) ? 0x1000000 : (unsigned) (len - total) ;
+		readlen = (len - total > READ_LOOP_MAX_LEN) ? READ_LOOP_MAX_LEN : (unsigned) (len - total) ;
 		current = flac_read_loop (psf, readlen) ;
 		if (current == 0)
 			break ;
@@ -1017,7 +1026,7 @@ flac_read_flac2f (SF_PRIVATE *psf, float *ptr, sf_count_t len)
 
 	while (total < len)
 	{	pflac->ptr = ptr + total ;
-		readlen = (len - total > 0x1000000) ? 0x1000000 : (unsigned) (len - total) ;
+		readlen = (len - total > READ_LOOP_MAX_LEN) ? READ_LOOP_MAX_LEN : (unsigned) (len - total) ;
 		current = flac_read_loop (psf, readlen) ;
 		if (current == 0)
 			break ;
@@ -1037,7 +1046,7 @@ flac_read_flac2d (SF_PRIVATE *psf, double *ptr, sf_count_t len)
 
 	while (total < len)
 	{	pflac->ptr = ptr + total ;
-		readlen = (len - total > 0x1000000) ? 0x1000000 : (unsigned) (len - total) ;
+		readlen = (len - total > READ_LOOP_MAX_LEN) ? READ_LOOP_MAX_LEN : (unsigned) (len - total) ;
 
 		current = flac_read_loop (psf, readlen) ;
 		if (current == 0)
diff --git a/src/g72x.c b/src/g72x.c
index 8698ebf..62e4005 100644
--- a/src/g72x.c
+++ b/src/g72x.c
@@ -141,7 +141,7 @@ g72x_init (SF_PRIVATE * psf)
 		else
 			pg72x->blocks_total = psf->datalength / pg72x->blocksize ;
 
-		psf->sf.frames = pg72x->blocks_total * pg72x->samplesperblock ;
+		psf->sf.frames = (sf_count_t) pg72x->blocks_total * pg72x->samplesperblock ;
 
 		psf_g72x_decode_block (psf, pg72x) ;
 		}
diff --git a/src/gsm610.c b/src/gsm610.c
index 77d4f1f..933f03f 100644
--- a/src/gsm610.c
+++ b/src/gsm610.c
@@ -150,7 +150,7 @@ Need separate gsm_data structs for encode and decode.
 			pgsm610->blocks = psf->datalength / pgsm610->blocksize + 1 ;
 			} ;
 
-		psf->sf.frames = pgsm610->samplesperblock * pgsm610->blocks ;
+		psf->sf.frames = (sf_count_t) pgsm610->samplesperblock * pgsm610->blocks ;
 
 		psf_fseek (psf, psf->dataoffset, SEEK_SET) ;
 
diff --git a/src/ogg.c b/src/ogg.c
index 7a4a167..f8cb0a4 100644
--- a/src/ogg.c
+++ b/src/ogg.c
@@ -447,7 +447,9 @@ ogg_sync_last_page_before (SF_PRIVATE *psf, OGG_PRIVATE *odata, uint64_t *gp_out
 } /* ogg_sync_last_page_before */
 
 int
-ogg_stream_seek_page_search (SF_PRIVATE *psf, OGG_PRIVATE *odata, uint64_t target_gp, uint64_t pcm_start, uint64_t pcm_end, uint64_t *best_gp, sf_count_t begin, sf_count_t end)
+ogg_stream_seek_page_search (SF_PRIVATE *psf, OGG_PRIVATE *odata,
+	uint64_t target_gp, uint64_t pcm_start, uint64_t pcm_end, uint64_t *best_gp,
+	sf_count_t begin, sf_count_t end, uint64_t gp_rate)
 {	ogg_page page ;
 	uint64_t gp ;
 	sf_count_t d0, d1, d2 ;
@@ -614,7 +616,7 @@ ogg_stream_seek_page_search (SF_PRIVATE *psf, OGG_PRIVATE *odata, uint64_t targe
 				if (buffering)
 					ogg_stream_reset (&odata->ostream) ;
 				/* Check to see if the last packet continues. */
-				if (page.header [27 + page.header [26] - 1] == 255)
+				if (ogg_page_continues (&page))
 				{	ogg_page_search_continued_data (odata, &page) ;
 					/*
 					** If we have a continued packet, remember the offset of
@@ -624,15 +626,15 @@ ogg_stream_seek_page_search (SF_PRIVATE *psf, OGG_PRIVATE *odata, uint64_t targe
 					** remember the end of the page.
 					*/
 					best_start = page_offset ;
-					} ;
-				/*
-				** Then force buffering on, so that if a packet starts (but
-				** does not end) on the next page, we still avoid the extra
-				** seek back.
-				*/
-				buffering = SF_TRUE ;
+					/*
+					** Then force buffering on, so that if a packet starts (but
+					** does not end) on the next page, we still avoid the extra
+					** seek back.
+					*/
+					buffering = SF_TRUE ;
+				} ;
 				*best_gp = pcm_start = gp ;
-				if (target_gp - gp > 48000)
+				if (target_gp - gp > gp_rate)
 				{	/* Out by over a second. Try another bisection. */
 					break ;
 					}
diff --git a/src/ogg.h b/src/ogg.h
index 5c837a8..8b2927a 100644
--- a/src/ogg.h
+++ b/src/ogg.h
@@ -57,7 +57,36 @@ typedef struct
 								((buf [base + 2] <<16) & 0xff0000) | \
 								((buf [base + 1] << 8) & 0xff00) | \
 								(buf [base] & 0xff))
+/*-----------------------------------------------------------------------------------------------
+** Inline functions.
+*/
+
+/*
+** LibOgg documentation is noted as being bad by it's author.
+** Add some useful utility inline functions for introspecting Ogg pages.
+*/
+
+/* ogg_page_segments returns how many segments are in this page. */
+static inline int
+ogg_page_segments (ogg_page *pg)
+{	return (int) (pg->header [26]) ; }
 
+/* ogg_page_continues returns true if this page ends in a continued packet. */
+static inline int
+ogg_page_continues (ogg_page *pg)
+{	return pg->header [27 + pg->header [26] - 1] == 255 ;
+}
+
+/*-----------------------------------------------------------------------------------------------
+** Exported functions.
+*/
+
+/*
+** ogg_read_first_page loads the first Ogg page found in the file, and sets the
+** OGG_PRIVATE serialno to match the logical stream of the page. Data is read
+** without seeking backwards, loading any data present from psf->header into
+** the ogg_sync state first, so that this function works with pipes.
+*/
 int	ogg_read_first_page	(SF_PRIVATE *, OGG_PRIVATE *) ;
 
 /*
@@ -125,10 +154,16 @@ int ogg_stream_unpack_page (SF_PRIVATE *psf, OGG_PRIVATE *odata) ;
 ** Preforms a bisection search. If not found exactly, the best result is
 ** returned in *best_gp. Found page is loaded into the virtual bitstream,
 ** ready for unpacking. Arguments pcm_start and pcm_end are the highest and
-** lowest granule positions of the file. begin and end are the file offsets.
+** lowest granule positions of the file. begin and end are the file offset
+** range to search. gp_rate is an information hint so granule positions can
+** be correlated to playback time, so the search can figure out how close it
+** is, should be granule positions per second.
 */
 int ogg_stream_seek_page_search (SF_PRIVATE *psf, OGG_PRIVATE *odata,
-								uint64_t target_gp, uint64_t pcm_start, uint64_t pcm_end,
-								uint64_t *best_gp, sf_count_t begin, sf_count_t end) ;
+								uint64_t target_gp,
+								uint64_t pcm_start, uint64_t pcm_end,
+								uint64_t *best_gp,
+								sf_count_t begin, sf_count_t end,
+								uint64_t gp_rate) ;
 
 #endif /* SF_SRC_OGG_H */
diff --git a/src/ogg_opus.c b/src/ogg_opus.c
index dfa446e..c938362 100644
--- a/src/ogg_opus.c
+++ b/src/ogg_opus.c
@@ -171,16 +171,26 @@
 #define OGG_OPUS_COMMENT_PAD (512) /* Same as oggenc default */
 
 /*
-** Opus packets can be any multiple of 2.5ms (at 48kHz). We use the recommended
+** When encoding, we can choose the size of the Opus frames.
+** Valid values are 2.5, 5, 10, 20, 40, and 60 milliseconds.
+**
+** Frames smaller than 10ms can't use CELT (MDCT) mode.
+** Frames larger than 20ms "are only interesting at fairly low bitrates."
+**
+** We choose the suggested default of 20ms for high-fidelity audio, however,
+** maybe this could be user-selected, or triggered by bitrate command.
 ** default for non-realtime of 20ms. While longer packets reduce the overhead
 ** data somewhat, it also decreases the quality.
 */
 #define OGG_OPUS_ENCODE_PACKET_LEN(samplerate) ((20 * (samplerate)) / 1000)
 
 /*
-** How long does it take for a decoder to converge (avoiding flush on seek.
+** The pre-roll is how long it takes for the decoder to converge. It converges
+** pretty quickly, to within -40db within 80ms. However, this also depends on
+** the signal. From experimentation, use the conservative pre-roll amount of
+** 660ms after which the output is 32-bit-exact with high probability.
 */
-#define OGG_OPUS_PREROLL (80 * 48) /* 80 milliseconds */
+#define OGG_OPUS_PREROLL (660 * 48) /* 660 milliseconds (33 packets of 20ms) */
 
 typedef struct
 {	uint8_t version ;
@@ -215,10 +225,12 @@ typedef struct
 {	uint32_t serialno ;
 	OpusHeader header ;
 
-	/* Granule position before the current packet */
+	/* Encode: Granule position after the previous packet.
+	 * Decode: Granule position after the current packet */
 	uint64_t pkt_pos ;
 
-	/* Granule position at the end of the current page (encode: last completed) */
+	/* Encode: Granule position at the end of the previous page.
+	 * Decode: Granule position at the end of the current page. */
 	uint64_t pg_pos ;
 
 	/* integer coefficient of (current sample rate) / 48000Hz */
@@ -291,9 +303,9 @@ static sf_count_t	ogg_opus_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_
 static sf_count_t	ogg_opus_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ;
 
 static sf_count_t	ogg_opus_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ;
-static sf_count_t	ogg_opus_seek_null_read (SF_PRIVATE *psf, sf_count_t offset) ;
-static sf_count_t	ogg_opus_seek_manual (SF_PRIVATE *psf, uint64_t target_gp) ;
-static int			ogg_opus_seek_page_search (SF_PRIVATE *psf, uint64_t target_gp) ;
+static sf_count_t	ogg_opus_null_read (SF_PRIVATE *psf, sf_count_t offset) ;
+static sf_count_t	ogg_opus_page_seek_manual (SF_PRIVATE *psf, uint64_t target_gp) ;
+static int			ogg_opus_page_seek_search (SF_PRIVATE *psf, uint64_t target_gp) ;
 
 static int			ogg_opus_analyze_file (SF_PRIVATE *psf) ;
 static int			ogg_opus_command (SF_PRIVATE *psf, int command, void *data, int datasize) ;
@@ -409,27 +421,27 @@ ogg_opus_close (SF_PRIVATE *psf)
 static void
 opus_print_header (SF_PRIVATE *psf, OpusHeader *h)
 {	psf_log_printf (psf, "Opus Header Metadata\n") ;
-	psf_log_printf (psf, "  OggOpus version  : %d\n", h->version) ;
-	psf_log_printf (psf, "  Channels         : %d\n", h->channels) ;
-	psf_log_printf (psf, "  Preskip          : %d samples @48kHz\n", h->preskip) ;
-	psf_log_printf (psf, "  Input Samplerate : %d Hz\n", h->input_samplerate) ;
-	psf_log_printf (psf, "  Gain             : %d.%d\n", arith_shift_right (h->gain & 0xF0, 8), h->gain & 0x0F) ;
+	psf_log_printf (psf, "  OggOpus version  : %d\n", (int) h->version) ;
+	psf_log_printf (psf, "  Channels         : %d\n", (int) h->channels) ;
+	psf_log_printf (psf, "  Preskip          : %d samples @48kHz\n", (int) h->preskip) ;
+	psf_log_printf (psf, "  Input Samplerate : %d Hz\n", (int) h->input_samplerate) ;
+	psf_log_printf (psf, "  Gain             : %d.%d\n", (int) arith_shift_right (h->gain & 0xF0, 8), h->gain & 0x0F) ;
 	psf_log_printf (psf, "  Channel Mapping  : ") ;
 	switch (h->channel_mapping)
 	{	case 0 :	psf_log_printf (psf, "0 (mono or stereo)\n") ; break ;
 		case 1 :	psf_log_printf (psf, "1 (surround, AC3 channel order)\n") ; break ;
 		case 255 :	psf_log_printf (psf, "255 (no channel order)\n") ; break ;
-		default :	psf_log_printf (psf, "%d (unknown or unsupported)\n", h->channel_mapping) ; break ;
+		default :	psf_log_printf (psf, "%d (unknown or unsupported)\n", (int) h->channel_mapping) ; break ;
 		} ;
 
 	if (h->channel_mapping > 0)
 	{	int i ;
-		psf_log_printf (psf, "   streams total   : %d\n", h->nb_streams) ;
-		psf_log_printf (psf, "   streams coupled : %d\n", h->nb_coupled) ;
+		psf_log_printf (psf, "   streams total   : %d\n", (int) h->nb_streams) ;
+		psf_log_printf (psf, "   streams coupled : %d\n", (int) h->nb_coupled) ;
 		psf_log_printf (psf, "   stream mapping : [") ;
 		for (i = 0 ; i < h->channels - 1 ; i++)
-			psf_log_printf (psf, "%d,", h->stream_map [i]) ;
-		psf_log_printf (psf, "%d]\n", h->stream_map [i]) ;
+			psf_log_printf (psf, "%d,", (int) (h->stream_map [i])) ;
+		psf_log_printf (psf, "%d]\n", (int) (h->stream_map [i])) ;
 		} ;
 } /* opus_print_header */
 
@@ -458,7 +470,7 @@ opus_read_header_packet (SF_PRIVATE *psf, OpusHeader *h, ogg_packet *opacket)
 
 	count = psf_binheader_readf (psf, "ep1", 8, &h->version) ;
 	if (! (h->version == 1 || h->version == 0))
-	{	psf_log_printf (psf, "Opus : Unknown / unsupported embedding scheme version: %d.\n", h->version) ;
+	{	psf_log_printf (psf, "Opus : Unknown / unsupported embedding scheme version: %d.\n", (int) h->version) ;
 		return SFE_UNIMPLEMENTED ;
 		} ;
 
@@ -955,8 +967,8 @@ ogg_opus_unpack_next_page (SF_PRIVATE *psf, OGG_PRIVATE *odata, OPUS_PRIVATE *oo
 		oopus->pg_pos = odata->pkt [odata->pkt_len - 1].granulepos ;
 		gp = ogg_opus_calculate_page_duration (odata) ;
 		oopus->pkt_pos = oopus->pg_pos - gp ;
-		psf_log_printf (psf, "Opus : Hole found appears to be of length %d samples.\n",
-				(oopus->pkt_pos - last_page) / oopus->sr_factor) ;
+		psf_log_printf (psf, "Opus : Hole found appears to be of length %D samples.\n",
+				(oopus->pkt_pos - last_page) / (uint64_t) oopus->sr_factor) ;
 		/*
 		** Could save the hole size here, and have ogg_opus_read_refill()
 		** do packet loss concealment until the hole is gone, but libopus does
@@ -1050,7 +1062,7 @@ ogg_opus_read_refill (SF_PRIVATE *psf, OGG_PRIVATE *odata, OPUS_PRIVATE *oopus)
 			**	MAY defer this action until it decodes the last packet
 			**	completed on that page.
 			*/
-			psf_log_printf (psf, "Opus : Mid-strem page's granule position %d is less than total samples of %d\n", oopus->pg_pos, pkt_granulepos) ;
+			psf_log_printf (psf, "Opus : Mid-stream page's granule position %D is less than total samples of %D\n", oopus->pg_pos, pkt_granulepos) ;
 			psf->error = SFE_MALFORMED_FILE ;
 			return -1 ;
 			} ;
@@ -1118,11 +1130,7 @@ ogg_opus_write_out (SF_PRIVATE *psf, OGG_PRIVATE *odata, OPUS_PRIVATE *oopus)
 		else
 			nbytes = ogg_stream_pageout_fill (&odata->ostream, &odata->opage, 255 * 255) ;
 		if (nbytes > 0)
-		{	/*
-			** LibOgg documentation is noted as being bad by it's author. Ogg
-			** page header byte 26 is the segment count.
-			*/
-			oopus->u.encode.last_segments -= odata->opage.header [26] ;
+		{	oopus->u.encode.last_segments -= ogg_page_segments (&odata->opage) ;
 			oopus->pg_pos = oopus->pkt_pos ;
 			ogg_write_page (psf, &odata->opage) ;
 			}
@@ -1467,7 +1475,12 @@ ogg_opus_analyze_file (SF_PRIVATE *psf)
 		{	psf->sf.frames = (oopus->u.decode.gp_end - oopus->u.decode.gp_start
 				- oopus->header.preskip) / oopus->sr_factor ;
 			} ;
-	}
+		} ;
+
+
+	psf_log_printf (psf, "  Granule pos offset  : %D\n", oopus->u.decode.gp_start) ;
+	if (oopus->u.decode.gp_end != (uint64_t) -1)
+		psf_log_printf (psf, "  Last Granule pos : %D\n", oopus->u.decode.gp_end) ;
 
 	/* Go back to where we left off. */
 	ogg_sync_fseek (psf, saved_offset, SEEK_SET) ;
@@ -1475,23 +1488,25 @@ ogg_opus_analyze_file (SF_PRIVATE *psf)
 } /* ogg_opus_analyze_file */
 
 /*
-** ogg_opus_seek_null_read
+** ogg_opus_null_read
 **
 ** Decode samples, doing nothing with them, until the desired granule position
 ** is reached.
 */
 static sf_count_t
-ogg_opus_seek_null_read (SF_PRIVATE *psf, sf_count_t offset)
+ogg_opus_null_read (SF_PRIVATE *psf, sf_count_t offset)
 {	OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ;
 	OPUS_PRIVATE *oopus = (OPUS_PRIVATE *) psf->codec_data ;
 	sf_count_t total ;
-	sf_count_t readlen ;
-
-	total = oopus->pkt_pos / oopus->sr_factor ;
-	total += oopus->loc ;
 
+	total = (oopus->pkt_pos / oopus->sr_factor) - (oopus->len - oopus->loc) ;
 	for ( ; total < offset ; )
-	{	if (oopus->loc == oopus->len)
+	{	sf_count_t readlen = SF_MIN ((int) (offset - total), (oopus->len - oopus->loc)) ;
+		if (readlen > 0)
+		{	total += readlen ;
+			oopus->loc += readlen ;
+			} ;
+		if (oopus->loc == oopus->len)
 		{	if (ogg_opus_read_refill (psf, odata, oopus) <= 0)
 				return total ;
 			/*
@@ -1500,22 +1515,18 @@ ogg_opus_seek_null_read (SF_PRIVATE *psf, sf_count_t offset)
 			*/
 			oopus->loc = 0 ;
 			} ;
-
-		readlen = SF_MIN ((int) (offset - total), (oopus->len - oopus->loc)) ;
-		if (readlen > 0)
-		{	total += readlen ;
-			oopus->loc += readlen ;
-			} ;
 		} ;
 	return total ;
-} /* ogg_opus_seek_null_read */
+} /* ogg_opus_null_read */
 
 /*
+** ogg_opus_page_seek_search
+**
 ** Search within the file for the page with the highest granule position at or
 ** before our target.
 */
 static int
-ogg_opus_seek_page_search (SF_PRIVATE *psf, uint64_t target_gp)
+ogg_opus_page_seek_search (SF_PRIVATE *psf, uint64_t target_gp)
 {	OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ;
 	OPUS_PRIVATE *oopus = (OPUS_PRIVATE *) psf->codec_data ;
 	uint64_t pcm_start ;
@@ -1523,49 +1534,48 @@ ogg_opus_seek_page_search (SF_PRIVATE *psf, uint64_t target_gp)
 	uint64_t best_gp ;
 	sf_count_t begin ;
 	sf_count_t end ;
+	sf_count_t old_pos ;
 	int ret ;
 
 	best_gp = pcm_start = oopus->u.decode.gp_start ;
 	pcm_end = oopus->u.decode.gp_end ;
 	begin = psf->dataoffset ;
+	end = oopus->u.decode.last_offset ;
 
-	/* Adjust the target to give time to converge. */
-	if (target_gp >= OGG_OPUS_PREROLL)
-		target_gp -= OGG_OPUS_PREROLL ;
-	if (target_gp < pcm_start)
-		target_gp = pcm_start ;
-
-	/* Seek to beginning special case */
-	if (target_gp < pcm_start + (uint64_t) oopus->header.preskip)
-		end = begin ;
-	else
-		end = oopus->u.decode.last_offset ;
-
-	ogg_stream_seek_page_search (psf, odata, target_gp, pcm_start, pcm_end, &best_gp, begin, end) ;
+	/* Search the Ogg stream for such a page */
+	old_pos = ogg_sync_ftell (psf) ;
+	ret = ogg_stream_seek_page_search (psf, odata, target_gp, pcm_start, pcm_end, &best_gp, begin, end, 48000) ;
+	if (ret != 0)
+	{	ogg_sync_fseek (psf, old_pos, SEEK_SET) ;
+		return ret ;
+		} ;
 
+	/* Load the page that contains our pre-roll target */
 	oopus->loc = 0 ;
 	oopus->len = 0 ;
 	if ((ret = ogg_opus_unpack_next_page (psf, odata, oopus)) != 1)
 		return ret ;
 	oopus->pkt_pos = best_gp ;
+
+	/* Reset the decoder (gain settings survive the reset) */
 	opus_multistream_decoder_ctl (oopus->u.decode.state, OPUS_RESET_STATE) ;
-	/* Gain decoder settings survive resets. */
 
 	return 0 ;
-} /* ogg_opus_seek_page_search */
+} /* ogg_opus_page_seek_search */
 
+/*
+** ogg_opus_page_seek_manual
+**
+** Seek to the beginning of the Ogg stream and read pages until we find one with
+** a granule position at or before our target.
+*/
 static sf_count_t
-ogg_opus_seek_manual (SF_PRIVATE *psf, uint64_t target_gp)
+ogg_opus_page_seek_manual (SF_PRIVATE *psf, uint64_t target_gp)
 {	OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ;
 	OPUS_PRIVATE *oopus = (OPUS_PRIVATE *) psf->codec_data ;
 	sf_count_t pos ;
 	int nn ;
 
-	if (target_gp > OGG_OPUS_PREROLL)
-		target_gp -= OGG_OPUS_PREROLL ;
-	if (target_gp < oopus->pg_pos)
-		target_gp = oopus->pg_pos ;
-
 	if (oopus->pg_pos > target_gp)
 	{	ogg_stream_reset (&odata->ostream) ;
 		pos = ogg_sync_fseek (psf, psf->dataoffset, SEEK_SET) ;
@@ -1582,13 +1592,13 @@ ogg_opus_seek_manual (SF_PRIVATE *psf, uint64_t target_gp)
 		} ;
 
 	return 1 ;
-} /* ogg_opus_seek_manual */
+} /* ogg_opus_page_seek_manual */
 
 static sf_count_t
 ogg_opus_seek (SF_PRIVATE *psf, int mode, sf_count_t offset)
-{	OPUS_PRIVATE *oopus = (OPUS_PRIVATE *) psf->codec_data ;
-	uint64_t target_gp ;
-	uint64_t current ;
+{	OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ;
+	OPUS_PRIVATE *oopus = (OPUS_PRIVATE *) psf->codec_data ;
+	uint64_t target_gp, current_gp ;
 	int ret ;
 
 	/* Only support seeking in read mode. */
@@ -1597,28 +1607,40 @@ ogg_opus_seek (SF_PRIVATE *psf, int mode, sf_count_t offset)
 		return PSF_SEEK_ERROR ;
 		} ;
 
-	current = oopus->pkt_pos + oopus->loc * oopus->sr_factor ;
-	/*
-	** Remember, there are preskip granulepos worth of samples at the front of
-	** the stream which are bunk. Also, granule positions can be offset.
-	*/
-	target_gp = offset * oopus->sr_factor + oopus->u.decode.gp_start + oopus->header.preskip ;
+	/* Figure out the current position granule pos. Use the start of the
+	 * current buffer, to avoid backwards seeking if the target is on the page
+	 * but before the current locaiton. */
+	oopus->loc = 0 ;
+	current_gp = oopus->pkt_pos - (uint64_t) (oopus->len * oopus->sr_factor) ;
+
+	/* Calculate the target granule pos. This includes the decoder delay and
+	 * the file granule position offset. */
+	target_gp = offset * oopus->sr_factor ;
+	target_gp += oopus->u.decode.gp_start ;
+	target_gp += oopus->header.preskip ;
+
+	/* Check if we need to do a page seek. */
+	if (target_gp < current_gp || target_gp - current_gp > OGG_OPUS_PREROLL)
+	{	uint64_t preroll_gp ;
+
+		/* For a page seek, use an earlier target granule pos, giving the
+		 * decoder samples to converge before the actual target. */
+		if (target_gp >= OGG_OPUS_PREROLL + oopus->u.decode.gp_start + (uint64_t) oopus->header.preskip)
+		{	preroll_gp = target_gp - OGG_OPUS_PREROLL ;
+			}
+		else
+		{	preroll_gp = oopus->u.decode.gp_start + (uint64_t) oopus->header.preskip ;
+			} ;
 
-	if (oopus->u.decode.gp_end == (uint64_t) -1)
-	{	/*
-		** Don't know the end of the file. Could be a chained file we don't yet
-		** support. Oh well, just do it manually.
-		*/
-		ogg_opus_seek_manual (psf, target_gp) ;
-		}
-	else
-	{	/*
-		** Avoid seeking in the file if where we want is just ahead or exactly
-		** were we are. To avoid needing to flush the decoder we choose pre-
-		** roll plus 10ms.
-		*/
-		if (target_gp < current || target_gp - current > OGG_OPUS_PREROLL + 10 * 48)
-		{	ret = ogg_opus_seek_page_search (psf, target_gp) ;
+		if (oopus->u.decode.gp_end == (uint64_t) -1)
+		{	/*
+			** Don't know the end of the file. Could be a chained file we don't yet
+			** support. Oh well, just do it manually.
+			*/
+			ogg_opus_page_seek_manual (psf, preroll_gp) ;
+			}
+		else
+		{	ret = ogg_opus_page_seek_search (psf, preroll_gp) ;
 			if (ret < 0)
 			{	/*
 				** Page seek failed, what to do? Could be bad data. We can
@@ -1626,7 +1648,7 @@ ogg_opus_seek (SF_PRIVATE *psf, int mode, sf_count_t offset)
 				** from the beginning has the advantage of finding where the
 				** file goes bad.
 				*/
-				ret = ogg_opus_seek_manual (psf, target_gp) ;
+				ret = ogg_opus_page_seek_manual (psf, preroll_gp) ;
 				if (ret < 0)
 				{	/*
 					** If were here, and there is no error, we can be pretty
@@ -1638,13 +1660,29 @@ ogg_opus_seek (SF_PRIVATE *psf, int mode, sf_count_t offset)
 					} ;
 				} ;
 			} ;
+
+		/*
+		** Skip over packets on the found page that are before our pre-roll
+		** target to avoid unnecessary decoding, and make decoder convergence
+		** independent of page boundaries for more visible errors.
+		*/
+		for ( ; odata->pkt_indx != odata->pkt_len ; )
+		{	ogg_packet *ppkt = &odata->pkt [odata->pkt_indx] ;
+			int nsamp = opus_packet_get_nb_samples (ppkt->packet, ppkt->bytes, 48000) ;
+			if (oopus->pkt_pos + nsamp < preroll_gp)
+			{	oopus->pkt_pos += nsamp ;
+				odata->pkt_indx++ ;
+				}
+			else
+				break ;
+			} ;
 		} ;
 
 	/*
 	** We've seeked or skipped through pages until just before our target,
 	** now decode until we hit it.
 	*/
-	offset = ogg_opus_seek_null_read (psf, target_gp / oopus->sr_factor) ;
+	offset = ogg_opus_null_read (psf, target_gp / oopus->sr_factor) ;
 	return offset - ((oopus->header.preskip + oopus->u.decode.gp_start) / oopus->sr_factor) ;
 
 } /* ogg_opus_seek */
@@ -1733,6 +1771,13 @@ ogg_opus_command (SF_PRIVATE *psf, int command, void *data, int datasize)
 			*((int *) data) = oopus->header.input_samplerate ;
 			return SF_TRUE ;
 
+		case SFC_GET_OGG_STREAM_SERIALNO :
+			if (data == NULL || datasize != sizeof (int32_t))
+				return SF_FALSE ;
+
+			*((int32_t *) data) = odata->ostream.serialno ;
+			return SF_TRUE ;
+
 		default :
 			break ;
 	}
diff --git a/src/ogg_vorbis.c b/src/ogg_vorbis.c
index 1b00af5..f9428ed 100644
--- a/src/ogg_vorbis.c
+++ b/src/ogg_vorbis.c
@@ -264,9 +264,9 @@ vorbis_read_header (SF_PRIVATE *psf)
 		ogg_sync_fseek (psf, saved_offset, SEEK_SET) ;
 		}
 
-	psf_log_printf (psf, "PCM offset  : %d\n", vdata->pcm_start) ;
+	psf_log_printf (psf, "PCM offset  : %D\n", vdata->pcm_start) ;
 	if (vdata->pcm_end != (uint64_t) -1)
-		psf_log_printf (psf, "PCM end     : %d\n", vdata->pcm_end) ;
+		psf_log_printf (psf, "PCM end     : %D\n", vdata->pcm_end) ;
 	else
 		psf_log_printf (psf, "PCM end     : unknown\n") ;
 
@@ -511,7 +511,8 @@ ogg_vorbis_open (SF_PRIVATE *psf)
 
 static int
 vorbis_command (SF_PRIVATE *psf, int command, void * data, int datasize)
-{	VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ;
+{	OGG_PRIVATE* odata = psf->container_data ;
+	VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ;
 
 	switch (command)
 	{	case SFC_SET_COMPRESSION_LEVEL :
@@ -529,6 +530,13 @@ vorbis_command (SF_PRIVATE *psf, int command, void * data, int datasize)
 			psf_log_printf (psf, "%s : Setting SFC_SET_VBR_ENCODING_QUALITY to %f.\n", __func__, vdata->quality) ;
 			return SF_TRUE ;
 
+		case SFC_GET_OGG_STREAM_SERIALNO :
+			if (data == NULL || datasize != sizeof (int32_t))
+				return SF_FALSE ;
+
+			*((int32_t *) data) = odata->ostream.serialno ;
+			return SF_TRUE ;
+
 		default :
 			return SF_FALSE ;
 		} ;
@@ -891,7 +899,7 @@ vorbis_seek_trysearch (SF_PRIVATE *psf, uint64_t target_gp)
 	search_target_gp = search_target_gp < target_gp ? target_gp - search_target_gp : 0 ;
 
 	ret = ogg_stream_seek_page_search (psf, odata, search_target_gp, vdata->pcm_start,
-			vdata->pcm_end, &best_gp, psf->dataoffset, vdata->last_page) ;
+			vdata->pcm_end, &best_gp, psf->dataoffset, vdata->last_page, vdata->vinfo.rate) ;
 	if (ret < 0)
 		return ret ;
 
diff --git a/src/sndfile.c b/src/sndfile.c
index 2517723..21975f6 100644
--- a/src/sndfile.c
+++ b/src/sndfile.c
@@ -2908,7 +2908,7 @@ retry:
 
 static int
 validate_sfinfo (SF_INFO *sfinfo)
-{	if ((sfinfo->samplerate < 1) || (sfinfo->samplerate > SF_MAX_SAMPLERATE))
+{	if (sfinfo->samplerate < 1)
 		return 0 ;
 	if (sfinfo->frames < 0)
 		return 0 ;
diff --git a/src/svx.c b/src/svx.c
index a6b7232..342b006 100644
--- a/src/svx.c
+++ b/src/svx.c
@@ -134,7 +134,7 @@ svx_read_header	(SF_PRIVATE *psf)
 	int				filetype = 0, parsestage = 0, done = 0 ;
 	int 			bytecount = 0, channels ;
 
-	if (psf->filelength > SF_PLATFORM_S64 (0xffffffff))
+	if (psf->filelength > 0xFFFFFFFFLL)
 		psf_log_printf (psf, "Warning : filelength > 0xffffffff. This is bad!!!!\n") ;
 
 	memset (&vhdr, 0, sizeof (vhdr)) ;
diff --git a/src/test_conversions.c b/src/test_conversions.c
index f6ee36e..f717fa5 100644
--- a/src/test_conversions.c
+++ b/src/test_conversions.c
@@ -44,7 +44,7 @@ conversion_test (char endian)
 {
 	SF_PRIVATE	sf_private, *psf ;
 	const char * filename = "conversion.bin" ;
-	int64_t i64 = SF_PLATFORM_S64 (0x0123456789abcdef), t64 = 0 ;
+	int64_t i64 = 0x0123456789ABCDEFLL, t64 = 0 ;
 	char format_str [16] ;
 	char test_name [64] ;
 	char i8 = 12, t8 = 0 ;
diff --git a/src/wav.c b/src/wav.c
index 0dd6c73..80baf28 100644
--- a/src/wav.c
+++ b/src/wav.c
@@ -310,7 +310,7 @@ wav_read_header	(SF_PRIVATE *psf, int *blockalign, int *framesperblock)
 	uint32_t	marker, chunk_size = 0, RIFFsize = 0, done = 0 ;
 	int			parsestage = 0, error, format = 0 ;
 
-	if (psf->is_pipe == 0 && psf->filelength > SF_PLATFORM_S64 (0xffffffff))
+	if (psf->is_pipe == 0 && psf->filelength > 0xFFFFFFFFLL)
 		psf_log_printf (psf, "Warning : filelength > 0xffffffff. This is bad!!!!\n") ;
 
 	if ((wpriv = psf->container_data) == NULL)