From 061991fe60923f7a6b5cf4ee11692defeca22934 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 2 Apr 2025 15:09:53 -0500 Subject: [PATCH] desubmodulize libsndfile - PLEASE READ it appears a one-character typo in the cmake_minimum_required line prevents it from compiling under CMake 4.0. in order to fix that, I had to take this thing out of submodules... it is recommended to do this after you pull; git submodule deinit extern/libsndfile --- .github/workflows/build.yml | 9 +- .gitmodules | 4 - CMakeLists.txt | 2 +- extern/libsndfile-modified/.editorconfig | 16 + extern/libsndfile-modified/.gitattributes | 19 + .../.github/workflows/action.yml | 238 ++ .../.github/workflows/cifuzz.yml | 26 + extern/libsndfile-modified/.gitignore | 146 + extern/libsndfile-modified/AUTHORS | 235 ++ .../Building-for-Android.md | 46 + extern/libsndfile-modified/CHANGELOG.md | 190 + extern/libsndfile-modified/CMakeLists.txt | 1604 ++++++++ extern/libsndfile-modified/CODEOWNERS | 14 + extern/libsndfile-modified/CONTRIBUTING.md | 49 + extern/libsndfile-modified/COPYING | 503 +++ extern/libsndfile-modified/ChangeLog | 3 + extern/libsndfile-modified/MODIFIED.md | 6 + extern/libsndfile-modified/Makefile.am | 546 +++ extern/libsndfile-modified/NEWS.OLD | 303 ++ extern/libsndfile-modified/Octave/Makefile.am | 79 + extern/libsndfile-modified/Octave/PKG_ADD | 3 + extern/libsndfile-modified/Octave/Readme.txt | 23 + extern/libsndfile-modified/Octave/format.h | 21 + .../libsndfile-modified/Octave/octave_test.m | 52 + .../libsndfile-modified/Octave/octave_test.sh | 81 + extern/libsndfile-modified/Octave/sndfile.cc | 405 ++ .../libsndfile-modified/Octave/sndfile_load.m | 52 + .../libsndfile-modified/Octave/sndfile_play.m | 59 + .../libsndfile-modified/Octave/sndfile_save.m | 53 + extern/libsndfile-modified/README | 78 + extern/libsndfile-modified/README.md | 319 ++ extern/libsndfile-modified/SECURITY.md | 11 + .../Scripts/android-configure.sh | 96 + .../Scripts/asan-configure.sh | 4 + .../Scripts/build-test-tarball.mk.in | 61 + .../Scripts/clang-sanitize.sh | 13 + .../Scripts/cmake-build.sh | 9 + extern/libsndfile-modified/Scripts/cstyle.py | 256 ++ .../Scripts/git-pre-commit-hook | 84 + .../Scripts/linux-to-win-cross-configure.sh | 22 + .../Scripts/static-deps-build.mk | 125 + .../Win32/README-precompiled-dll.txt | 40 + extern/libsndfile-modified/Win32/testprog.c | 16 + .../cmake/CMakeAutoGen.cmake | 46 + .../cmake/CMakeAutoGenScript.cmake | 442 +++ .../cmake/CheckCPUArch.c.in | 7 + .../cmake/CheckCPUArch.cmake | 23 + .../libsndfile-modified/cmake/ClipMode.cmake | 92 + .../libsndfile-modified/cmake/FindFLAC.cmake | 67 + .../libsndfile-modified/cmake/FindOgg.cmake | 61 + .../libsndfile-modified/cmake/FindOpus.cmake | 67 + .../libsndfile-modified/cmake/FindSndio.cmake | 61 + .../libsndfile-modified/cmake/FindSpeex.cmake | 55 + .../cmake/FindVorbis.cmake | 210 + .../cmake/Findmp3lame.cmake | 67 + .../cmake/Findmpg123.cmake | 95 + .../cmake/SetupABIVersions.cmake | 56 + .../cmake/SndFileChecks.cmake | 256 ++ .../cmake/SndFileConfig.cmake.in | 46 + .../libsndfile-modified/cmake/TestInline.c.in | 10 + .../cmake/TestInline.cmake | 54 + .../cmake/TestLargeFiles.cmake | 121 + .../cmake/sqlite/FindSQLite3.cmake | 56 + extern/libsndfile-modified/configure.ac | 761 ++++ extern/libsndfile-modified/docs/FAQ.md | 482 +++ extern/libsndfile-modified/docs/_config.yml | 8 + .../docs/_includes/logo.html | 1 + .../docs/_layouts/default.html | 18 + .../docs/_layouts/home.html | 34 + .../docs/_layouts/page.html | 10 + extern/libsndfile-modified/docs/api.md | 744 ++++ extern/libsndfile-modified/docs/bugs.md | 47 + extern/libsndfile-modified/docs/command.md | 2016 ++++++++++ .../libsndfile-modified/docs/development.md | 18 + extern/libsndfile-modified/docs/donate.md | 60 + .../docs/embedded_files.md | 21 + extern/libsndfile-modified/docs/formats.md | 53 + extern/libsndfile-modified/docs/index.md | 322 ++ .../libsndfile-modified/docs/libsndfile.css | 101 + .../libsndfile-modified/docs/libsndfile.jpg | Bin 0 -> 22043 bytes .../docs/linux_games_programming.txt | 434 +++ extern/libsndfile-modified/docs/lists.md | 27 + .../docs/new_file_type_howto.md | 134 + extern/libsndfile-modified/docs/octave.md | 71 + extern/libsndfile-modified/docs/print.css | 14 + .../libsndfile-modified/docs/sndfile_info.md | 36 + extern/libsndfile-modified/docs/tutorial.md | 10 + extern/libsndfile-modified/docs/win32.md | 18 + .../libsndfile-modified/examples/generate.c | 131 + .../libsndfile-modified/examples/generate.cs | 250 ++ .../examples/list_formats.c | 76 + .../libsndfile-modified/examples/make_sine.c | 100 + .../libsndfile-modified/examples/sfprocess.c | 144 + .../examples/sndfile-loopify.c | 175 + .../examples/sndfile-to-text.c | 168 + .../examples/sndfilehandle.cc | 84 + extern/libsndfile-modified/include/sndfile.hh | 484 +++ .../m4/ax_add_fortify_source.m4 | 80 + .../m4/ax_append_compile_flags.m4 | 67 + .../libsndfile-modified/m4/ax_append_flag.m4 | 71 + .../m4/ax_append_link_flags.m4 | 65 + .../m4/ax_check_compile_flag.m4 | 74 + .../m4/ax_check_link_flag.m4 | 74 + .../m4/ax_compiler_vendor.m4 | 87 + .../m4/ax_compiler_version.m4 | 492 +++ .../m4/ax_recursive_eval.m4 | 56 + .../m4/ax_require_defined.m4 | 37 + extern/libsndfile-modified/m4/clip_mode.m4 | 124 + extern/libsndfile-modified/m4/extra_pkg.m4 | 105 + .../libsndfile-modified/m4/flexible_array.m4 | 32 + .../m4/mkoctfile_version.m4 | 38 + extern/libsndfile-modified/m4/octave.m4 | 143 + extern/libsndfile-modified/make_lite.py | 491 +++ extern/libsndfile-modified/man/sndfile-cmp.1 | 29 + .../libsndfile-modified/man/sndfile-concat.1 | 28 + .../libsndfile-modified/man/sndfile-convert.1 | 160 + extern/libsndfile-modified/man/sndfile-info.1 | 34 + .../man/sndfile-interleave.1 | 62 + .../man/sndfile-metadata-get.1 | 116 + extern/libsndfile-modified/man/sndfile-play.1 | 36 + .../libsndfile-modified/man/sndfile-salvage.1 | 25 + extern/libsndfile-modified/ossfuzz/.gitignore | 1 + extern/libsndfile-modified/ossfuzz/ci_oss.sh | 30 + extern/libsndfile-modified/ossfuzz/ossfuzz.sh | 32 + .../ossfuzz/sndfile_alt_fuzzer.cc | 79 + .../ossfuzz/sndfile_fuzz_header.h | 119 + .../ossfuzz/sndfile_fuzzer.cc | 39 + .../ossfuzz/standaloneengine.cc | 86 + .../libsndfile-modified/ossfuzz/testinput.h | 3 + extern/libsndfile-modified/programs/common.c | 503 +++ extern/libsndfile-modified/programs/common.h | 82 + .../programs/sndfile-cmp.c | 155 + .../programs/sndfile-concat.c | 170 + .../programs/sndfile-convert.c | 410 ++ .../programs/sndfile-deinterleave.c | 222 ++ .../programs/sndfile-info.c | 529 +++ .../programs/sndfile-interleave.c | 217 ++ .../programs/sndfile-metadata-get.c | 197 + .../programs/sndfile-metadata-set.c | 298 ++ .../programs/sndfile-play.c | 860 ++++ .../programs/sndfile-salvage.c | 302 ++ .../programs/test-sndfile-metadata-set.py | 198 + extern/libsndfile-modified/regtest/Readme.txt | 108 + extern/libsndfile-modified/regtest/checksum.c | 117 + extern/libsndfile-modified/regtest/database.c | 542 +++ extern/libsndfile-modified/regtest/regtest.h | 38 + .../regtest/sndfile-regtest.c | 121 + extern/libsndfile-modified/sndfile.pc.in | 13 + .../src/ALAC/ALACAudioTypes.h | 206 + .../src/ALAC/ALACBitUtilities.c | 262 ++ .../src/ALAC/ALACBitUtilities.h | 89 + .../src/ALAC/ALACDecoder.h | 61 + .../src/ALAC/ALACEncoder.h | 92 + .../src/ALAC/EndianPortable.h | 39 + extern/libsndfile-modified/src/ALAC/LICENSE | 170 + extern/libsndfile-modified/src/ALAC/ag_dec.c | 358 ++ extern/libsndfile-modified/src/ALAC/ag_enc.c | 352 ++ extern/libsndfile-modified/src/ALAC/aglib.h | 81 + .../libsndfile-modified/src/ALAC/alac_codec.h | 104 + .../src/ALAC/alac_decoder.c | 652 ++++ .../src/ALAC/alac_decoder.h | 61 + .../src/ALAC/alac_encoder.c | 1333 +++++++ extern/libsndfile-modified/src/ALAC/dp_dec.c | 381 ++ extern/libsndfile-modified/src/ALAC/dp_enc.c | 387 ++ extern/libsndfile-modified/src/ALAC/dplib.h | 61 + .../libsndfile-modified/src/ALAC/matrix_dec.c | 330 ++ .../libsndfile-modified/src/ALAC/matrix_enc.c | 275 ++ .../libsndfile-modified/src/ALAC/matrixlib.h | 81 + extern/libsndfile-modified/src/ALAC/shift.h | 31 + extern/libsndfile-modified/src/G72x/ChangeLog | 50 + extern/libsndfile-modified/src/G72x/README | 0 .../src/G72x/README.original | 94 + extern/libsndfile-modified/src/G72x/g721.c | 155 + extern/libsndfile-modified/src/G72x/g723_16.c | 162 + extern/libsndfile-modified/src/G72x/g723_24.c | 139 + extern/libsndfile-modified/src/G72x/g723_40.c | 153 + extern/libsndfile-modified/src/G72x/g72x.c | 645 +++ extern/libsndfile-modified/src/G72x/g72x.h | 91 + .../libsndfile-modified/src/G72x/g72x_priv.h | 129 + .../libsndfile-modified/src/G72x/g72x_test.c | 220 ++ .../libsndfile-modified/src/GSM610/COPYRIGHT | 16 + .../libsndfile-modified/src/GSM610/ChangeLog | 56 + extern/libsndfile-modified/src/GSM610/README | 36 + extern/libsndfile-modified/src/GSM610/add.c | 243 ++ extern/libsndfile-modified/src/GSM610/code.c | 87 + .../libsndfile-modified/src/GSM610/config.h | 26 + .../libsndfile-modified/src/GSM610/decode.c | 58 + extern/libsndfile-modified/src/GSM610/gsm.h | 52 + .../src/GSM610/gsm610_priv.h | 337 ++ .../src/GSM610/gsm_create.c | 37 + .../src/GSM610/gsm_decode.c | 357 ++ .../src/GSM610/gsm_destroy.c | 25 + .../src/GSM610/gsm_encode.c | 448 +++ .../src/GSM610/gsm_option.c | 66 + .../src/GSM610/long_term.c | 932 +++++ extern/libsndfile-modified/src/GSM610/lpc.c | 333 ++ .../src/GSM610/preprocess.c | 101 + extern/libsndfile-modified/src/GSM610/rpe.c | 460 +++ .../src/GSM610/short_term.c | 412 ++ extern/libsndfile-modified/src/GSM610/table.c | 60 + extern/libsndfile-modified/src/aiff.c | 1851 +++++++++ extern/libsndfile-modified/src/alac.c | 999 +++++ extern/libsndfile-modified/src/alaw.c | 553 +++ extern/libsndfile-modified/src/au.c | 454 +++ extern/libsndfile-modified/src/audio_detect.c | 107 + extern/libsndfile-modified/src/avr.c | 244 ++ .../src/binheader_writef_check.py | 114 + extern/libsndfile-modified/src/broadcast.c | 190 + extern/libsndfile-modified/src/caf.c | 1034 +++++ extern/libsndfile-modified/src/cart.c | 101 + extern/libsndfile-modified/src/chanmap.c | 262 ++ extern/libsndfile-modified/src/chanmap.h | 32 + extern/libsndfile-modified/src/chunk.c | 266 ++ extern/libsndfile-modified/src/command.c | 415 ++ extern/libsndfile-modified/src/common.c | 1845 +++++++++ extern/libsndfile-modified/src/common.h | 1096 ++++++ extern/libsndfile-modified/src/config.h.cmake | 315 ++ .../src/create_symbols_file.py | 181 + extern/libsndfile-modified/src/dither.c | 534 +++ extern/libsndfile-modified/src/double64.c | 1063 +++++ extern/libsndfile-modified/src/dwd.c | 201 + extern/libsndfile-modified/src/dwvw.c | 674 ++++ extern/libsndfile-modified/src/file_io.c | 1206 ++++++ extern/libsndfile-modified/src/flac.c | 1463 +++++++ extern/libsndfile-modified/src/float32.c | 1017 +++++ extern/libsndfile-modified/src/g72x.c | 608 +++ extern/libsndfile-modified/src/gsm610.c | 629 +++ extern/libsndfile-modified/src/htk.c | 226 ++ extern/libsndfile-modified/src/id3.c | 132 + extern/libsndfile-modified/src/id3.h | 29 + extern/libsndfile-modified/src/ima_adpcm.c | 1008 +++++ .../libsndfile-modified/src/ima_oki_adpcm.c | 297 ++ .../libsndfile-modified/src/ima_oki_adpcm.h | 54 + extern/libsndfile-modified/src/interleave.c | 299 ++ extern/libsndfile-modified/src/ircam.c | 323 ++ extern/libsndfile-modified/src/macos.c | 51 + .../src/make-static-lib-hidden-privates.sh | 14 + extern/libsndfile-modified/src/mat4.c | 391 ++ extern/libsndfile-modified/src/mat5.c | 509 +++ extern/libsndfile-modified/src/mpc2k.c | 202 + extern/libsndfile-modified/src/mpeg.c | 165 + extern/libsndfile-modified/src/mpeg.h | 74 + extern/libsndfile-modified/src/mpeg_decode.c | 644 +++ .../libsndfile-modified/src/mpeg_l3_encode.c | 784 ++++ extern/libsndfile-modified/src/ms_adpcm.c | 857 ++++ extern/libsndfile-modified/src/new.c | 116 + extern/libsndfile-modified/src/nist.c | 372 ++ extern/libsndfile-modified/src/nms_adpcm.c | 1156 ++++++ extern/libsndfile-modified/src/ogg.c | 921 +++++ extern/libsndfile-modified/src/ogg.h | 169 + extern/libsndfile-modified/src/ogg_opus.c | 1823 +++++++++ extern/libsndfile-modified/src/ogg_pcm.c | 167 + extern/libsndfile-modified/src/ogg_speex.c | 428 ++ extern/libsndfile-modified/src/ogg_vcomment.c | 277 ++ extern/libsndfile-modified/src/ogg_vcomment.h | 45 + extern/libsndfile-modified/src/ogg_vorbis.c | 1057 +++++ extern/libsndfile-modified/src/paf.c | 818 ++++ extern/libsndfile-modified/src/pcm.c | 2918 ++++++++++++++ extern/libsndfile-modified/src/pvf.c | 188 + extern/libsndfile-modified/src/raw.c | 111 + extern/libsndfile-modified/src/rf64.c | 894 +++++ extern/libsndfile-modified/src/rx2.c | 318 ++ extern/libsndfile-modified/src/sd2.c | 619 +++ extern/libsndfile-modified/src/sds.c | 1022 +++++ extern/libsndfile-modified/src/sf_unistd.h | 112 + extern/libsndfile-modified/src/sfconfig.h | 131 + extern/libsndfile-modified/src/sfendian.h | 360 ++ extern/libsndfile-modified/src/sndfile.c | 3450 +++++++++++++++++ extern/libsndfile-modified/src/strings.c | 190 + extern/libsndfile-modified/src/svx.c | 402 ++ .../src/test_audio_detect.c | 113 + .../src/test_binheader_writef.c | 61 + .../src/test_broadcast_var.c | 123 + .../libsndfile-modified/src/test_cart_var.c | 91 + .../src/test_conversions.c | 112 + .../libsndfile-modified/src/test_endswap.def | 40 + .../libsndfile-modified/src/test_endswap.tpl | 153 + extern/libsndfile-modified/src/test_file_io.c | 492 +++ extern/libsndfile-modified/src/test_float.c | 104 + .../src/test_ima_oki_adpcm.c | 157 + .../libsndfile-modified/src/test_log_printf.c | 125 + extern/libsndfile-modified/src/test_main.c | 70 + extern/libsndfile-modified/src/test_main.h | 44 + .../libsndfile-modified/src/test_nms_adpcm.c | 400 ++ .../src/test_strncpy_crlf.c | 59 + extern/libsndfile-modified/src/txw.c | 377 ++ extern/libsndfile-modified/src/ulaw.c | 1056 +++++ .../src/version-metadata.rc.in | 31 + extern/libsndfile-modified/src/voc.c | 883 +++++ extern/libsndfile-modified/src/vox_adpcm.c | 400 ++ extern/libsndfile-modified/src/w64.c | 640 +++ extern/libsndfile-modified/src/wav.c | 1653 ++++++++ extern/libsndfile-modified/src/wavlike.c | 1371 +++++++ extern/libsndfile-modified/src/wavlike.h | 374 ++ extern/libsndfile-modified/src/windows.c | 70 + extern/libsndfile-modified/src/wve.c | 209 + extern/libsndfile-modified/src/xi.c | 1223 ++++++ .../libsndfile-modified/tests/aiff_rw_test.c | 169 + extern/libsndfile-modified/tests/alaw_test.c | 238 ++ .../tests/benchmark-0.0.28 | 40 + .../libsndfile-modified/tests/benchmark-1.0.0 | 35 + .../tests/benchmark-1.0.0rc2 | 31 + .../tests/benchmark-1.0.18pre16-hendrix | 38 + .../tests/benchmark-1.0.18pre16-mingus | 38 + .../tests/benchmark-1.0.6pre10-coltrane | 39 + .../tests/benchmark-1.0.6pre10-miles | 39 + .../tests/benchmark-latest-coltrane | 75 + .../libsndfile-modified/tests/benchmark.def | 17 + .../libsndfile-modified/tests/benchmark.tpl | 360 ++ .../libsndfile-modified/tests/channel_test.c | 138 + .../libsndfile-modified/tests/checksum_test.c | 129 + extern/libsndfile-modified/tests/chunk_test.c | 446 +++ .../libsndfile-modified/tests/command_test.c | 1806 +++++++++ .../tests/compression_size_test.c | 234 ++ extern/libsndfile-modified/tests/cpp_test.cc | 315 ++ extern/libsndfile-modified/tests/cue_test.c | 135 + extern/libsndfile-modified/tests/dft_cmp.c | 151 + extern/libsndfile-modified/tests/dft_cmp.h | 25 + .../libsndfile-modified/tests/dither_test.c | 184 + extern/libsndfile-modified/tests/dwvw_test.c | 111 + extern/libsndfile-modified/tests/error_test.c | 314 ++ .../tests/external_libs_test.c | 204 + extern/libsndfile-modified/tests/fix_this.c | 334 ++ .../tests/floating_point_test.def | 32 + .../tests/floating_point_test.tpl | 380 ++ .../tests/format_check_test.c | 166 + extern/libsndfile-modified/tests/generate.c | 75 + extern/libsndfile-modified/tests/generate.h | 19 + .../libsndfile-modified/tests/header_test.def | 22 + .../libsndfile-modified/tests/header_test.tpl | 583 +++ .../tests/headerless_test.c | 187 + .../tests/largefile_test.c | 85 + .../libsndfile-modified/tests/locale_test.c | 168 + .../tests/long_read_write_test.c | 272 ++ .../tests/lossy_comp_test.c | 2634 +++++++++++++ extern/libsndfile-modified/tests/misc_test.c | 533 +++ extern/libsndfile-modified/tests/mpeg_test.c | 348 ++ .../tests/multi_file_test.c | 238 ++ .../libsndfile-modified/tests/ogg_opus_test.c | 424 ++ extern/libsndfile-modified/tests/ogg_test.c | 348 ++ extern/libsndfile-modified/tests/pcm_test.def | 34 + extern/libsndfile-modified/tests/pcm_test.tpl | 919 +++++ .../tests/peak_chunk_test.c | 371 ++ .../tests/pedantic-header-test.sh.in | 58 + .../libsndfile-modified/tests/pipe_test.def | 14 + .../libsndfile-modified/tests/pipe_test.tpl | 362 ++ extern/libsndfile-modified/tests/raw_test.c | 189 + .../libsndfile-modified/tests/rdwr_test.def | 32 + .../libsndfile-modified/tests/rdwr_test.tpl | 105 + .../tests/scale_clip_test.def | 56 + .../tests/scale_clip_test.tpl | 440 +++ extern/libsndfile-modified/tests/sftest.c | 67 + extern/libsndfile-modified/tests/sfversion.c | 48 + extern/libsndfile-modified/tests/stdin_test.c | 206 + extern/libsndfile-modified/tests/stdio_test.c | 141 + .../libsndfile-modified/tests/stdout_test.c | 169 + .../libsndfile-modified/tests/string_test.c | 907 +++++ .../tests/test_wrapper.sh.in | 380 ++ extern/libsndfile-modified/tests/ulaw_test.c | 259 ++ extern/libsndfile-modified/tests/utils.def | 52 + extern/libsndfile-modified/tests/utils.tpl | 961 +++++ .../tests/virtual_io_test.c | 237 ++ .../tests/win32_ordinal_test.c | 148 + extern/libsndfile-modified/tests/win32_test.c | 318 ++ .../tests/write_read_test.def | 75 + .../tests/write_read_test.tpl | 1208 ++++++ extern/libsndfile-modified/vcpkg.json | 39 + 367 files changed, 106200 insertions(+), 10 deletions(-) create mode 100644 extern/libsndfile-modified/.editorconfig create mode 100644 extern/libsndfile-modified/.gitattributes create mode 100644 extern/libsndfile-modified/.github/workflows/action.yml create mode 100644 extern/libsndfile-modified/.github/workflows/cifuzz.yml create mode 100644 extern/libsndfile-modified/.gitignore create mode 100644 extern/libsndfile-modified/AUTHORS create mode 100644 extern/libsndfile-modified/Building-for-Android.md create mode 100644 extern/libsndfile-modified/CHANGELOG.md create mode 100644 extern/libsndfile-modified/CMakeLists.txt create mode 100644 extern/libsndfile-modified/CODEOWNERS create mode 100644 extern/libsndfile-modified/CONTRIBUTING.md create mode 100644 extern/libsndfile-modified/COPYING create mode 100644 extern/libsndfile-modified/ChangeLog create mode 100644 extern/libsndfile-modified/MODIFIED.md create mode 100644 extern/libsndfile-modified/Makefile.am create mode 100644 extern/libsndfile-modified/NEWS.OLD create mode 100644 extern/libsndfile-modified/Octave/Makefile.am create mode 100644 extern/libsndfile-modified/Octave/PKG_ADD create mode 100644 extern/libsndfile-modified/Octave/Readme.txt create mode 100644 extern/libsndfile-modified/Octave/format.h create mode 100644 extern/libsndfile-modified/Octave/octave_test.m create mode 100755 extern/libsndfile-modified/Octave/octave_test.sh create mode 100644 extern/libsndfile-modified/Octave/sndfile.cc create mode 100644 extern/libsndfile-modified/Octave/sndfile_load.m create mode 100644 extern/libsndfile-modified/Octave/sndfile_play.m create mode 100644 extern/libsndfile-modified/Octave/sndfile_save.m create mode 100644 extern/libsndfile-modified/README create mode 100644 extern/libsndfile-modified/README.md create mode 100644 extern/libsndfile-modified/SECURITY.md create mode 100755 extern/libsndfile-modified/Scripts/android-configure.sh create mode 100755 extern/libsndfile-modified/Scripts/asan-configure.sh create mode 100644 extern/libsndfile-modified/Scripts/build-test-tarball.mk.in create mode 100755 extern/libsndfile-modified/Scripts/clang-sanitize.sh create mode 100755 extern/libsndfile-modified/Scripts/cmake-build.sh create mode 100755 extern/libsndfile-modified/Scripts/cstyle.py create mode 100755 extern/libsndfile-modified/Scripts/git-pre-commit-hook create mode 100755 extern/libsndfile-modified/Scripts/linux-to-win-cross-configure.sh create mode 100755 extern/libsndfile-modified/Scripts/static-deps-build.mk create mode 100644 extern/libsndfile-modified/Win32/README-precompiled-dll.txt create mode 100644 extern/libsndfile-modified/Win32/testprog.c create mode 100644 extern/libsndfile-modified/cmake/CMakeAutoGen.cmake create mode 100644 extern/libsndfile-modified/cmake/CMakeAutoGenScript.cmake create mode 100644 extern/libsndfile-modified/cmake/CheckCPUArch.c.in create mode 100644 extern/libsndfile-modified/cmake/CheckCPUArch.cmake create mode 100644 extern/libsndfile-modified/cmake/ClipMode.cmake create mode 100644 extern/libsndfile-modified/cmake/FindFLAC.cmake create mode 100644 extern/libsndfile-modified/cmake/FindOgg.cmake create mode 100644 extern/libsndfile-modified/cmake/FindOpus.cmake create mode 100644 extern/libsndfile-modified/cmake/FindSndio.cmake create mode 100644 extern/libsndfile-modified/cmake/FindSpeex.cmake create mode 100644 extern/libsndfile-modified/cmake/FindVorbis.cmake create mode 100644 extern/libsndfile-modified/cmake/Findmp3lame.cmake create mode 100644 extern/libsndfile-modified/cmake/Findmpg123.cmake create mode 100644 extern/libsndfile-modified/cmake/SetupABIVersions.cmake create mode 100644 extern/libsndfile-modified/cmake/SndFileChecks.cmake create mode 100644 extern/libsndfile-modified/cmake/SndFileConfig.cmake.in create mode 100644 extern/libsndfile-modified/cmake/TestInline.c.in create mode 100644 extern/libsndfile-modified/cmake/TestInline.cmake create mode 100644 extern/libsndfile-modified/cmake/TestLargeFiles.cmake create mode 100644 extern/libsndfile-modified/cmake/sqlite/FindSQLite3.cmake create mode 100644 extern/libsndfile-modified/configure.ac create mode 100644 extern/libsndfile-modified/docs/FAQ.md create mode 100644 extern/libsndfile-modified/docs/_config.yml create mode 100644 extern/libsndfile-modified/docs/_includes/logo.html create mode 100644 extern/libsndfile-modified/docs/_layouts/default.html create mode 100644 extern/libsndfile-modified/docs/_layouts/home.html create mode 100644 extern/libsndfile-modified/docs/_layouts/page.html create mode 100644 extern/libsndfile-modified/docs/api.md create mode 100644 extern/libsndfile-modified/docs/bugs.md create mode 100644 extern/libsndfile-modified/docs/command.md create mode 100644 extern/libsndfile-modified/docs/development.md create mode 100644 extern/libsndfile-modified/docs/donate.md create mode 100644 extern/libsndfile-modified/docs/embedded_files.md create mode 100644 extern/libsndfile-modified/docs/formats.md create mode 100644 extern/libsndfile-modified/docs/index.md create mode 100644 extern/libsndfile-modified/docs/libsndfile.css create mode 100644 extern/libsndfile-modified/docs/libsndfile.jpg create mode 100644 extern/libsndfile-modified/docs/linux_games_programming.txt create mode 100644 extern/libsndfile-modified/docs/lists.md create mode 100644 extern/libsndfile-modified/docs/new_file_type_howto.md create mode 100644 extern/libsndfile-modified/docs/octave.md create mode 100644 extern/libsndfile-modified/docs/print.css create mode 100644 extern/libsndfile-modified/docs/sndfile_info.md create mode 100644 extern/libsndfile-modified/docs/tutorial.md create mode 100644 extern/libsndfile-modified/docs/win32.md create mode 100644 extern/libsndfile-modified/examples/generate.c create mode 100644 extern/libsndfile-modified/examples/generate.cs create mode 100644 extern/libsndfile-modified/examples/list_formats.c create mode 100644 extern/libsndfile-modified/examples/make_sine.c create mode 100644 extern/libsndfile-modified/examples/sfprocess.c create mode 100644 extern/libsndfile-modified/examples/sndfile-loopify.c create mode 100644 extern/libsndfile-modified/examples/sndfile-to-text.c create mode 100644 extern/libsndfile-modified/examples/sndfilehandle.cc create mode 100644 extern/libsndfile-modified/include/sndfile.hh create mode 100644 extern/libsndfile-modified/m4/ax_add_fortify_source.m4 create mode 100644 extern/libsndfile-modified/m4/ax_append_compile_flags.m4 create mode 100644 extern/libsndfile-modified/m4/ax_append_flag.m4 create mode 100644 extern/libsndfile-modified/m4/ax_append_link_flags.m4 create mode 100644 extern/libsndfile-modified/m4/ax_check_compile_flag.m4 create mode 100644 extern/libsndfile-modified/m4/ax_check_link_flag.m4 create mode 100644 extern/libsndfile-modified/m4/ax_compiler_vendor.m4 create mode 100644 extern/libsndfile-modified/m4/ax_compiler_version.m4 create mode 100644 extern/libsndfile-modified/m4/ax_recursive_eval.m4 create mode 100644 extern/libsndfile-modified/m4/ax_require_defined.m4 create mode 100644 extern/libsndfile-modified/m4/clip_mode.m4 create mode 100644 extern/libsndfile-modified/m4/extra_pkg.m4 create mode 100644 extern/libsndfile-modified/m4/flexible_array.m4 create mode 100644 extern/libsndfile-modified/m4/mkoctfile_version.m4 create mode 100644 extern/libsndfile-modified/m4/octave.m4 create mode 100644 extern/libsndfile-modified/make_lite.py create mode 100644 extern/libsndfile-modified/man/sndfile-cmp.1 create mode 100644 extern/libsndfile-modified/man/sndfile-concat.1 create mode 100644 extern/libsndfile-modified/man/sndfile-convert.1 create mode 100644 extern/libsndfile-modified/man/sndfile-info.1 create mode 100644 extern/libsndfile-modified/man/sndfile-interleave.1 create mode 100644 extern/libsndfile-modified/man/sndfile-metadata-get.1 create mode 100644 extern/libsndfile-modified/man/sndfile-play.1 create mode 100644 extern/libsndfile-modified/man/sndfile-salvage.1 create mode 100644 extern/libsndfile-modified/ossfuzz/.gitignore create mode 100755 extern/libsndfile-modified/ossfuzz/ci_oss.sh create mode 100755 extern/libsndfile-modified/ossfuzz/ossfuzz.sh create mode 100644 extern/libsndfile-modified/ossfuzz/sndfile_alt_fuzzer.cc create mode 100644 extern/libsndfile-modified/ossfuzz/sndfile_fuzz_header.h create mode 100644 extern/libsndfile-modified/ossfuzz/sndfile_fuzzer.cc create mode 100644 extern/libsndfile-modified/ossfuzz/standaloneengine.cc create mode 100644 extern/libsndfile-modified/ossfuzz/testinput.h create mode 100644 extern/libsndfile-modified/programs/common.c create mode 100644 extern/libsndfile-modified/programs/common.h create mode 100644 extern/libsndfile-modified/programs/sndfile-cmp.c create mode 100644 extern/libsndfile-modified/programs/sndfile-concat.c create mode 100644 extern/libsndfile-modified/programs/sndfile-convert.c create mode 100644 extern/libsndfile-modified/programs/sndfile-deinterleave.c create mode 100644 extern/libsndfile-modified/programs/sndfile-info.c create mode 100644 extern/libsndfile-modified/programs/sndfile-interleave.c create mode 100644 extern/libsndfile-modified/programs/sndfile-metadata-get.c create mode 100644 extern/libsndfile-modified/programs/sndfile-metadata-set.c create mode 100644 extern/libsndfile-modified/programs/sndfile-play.c create mode 100644 extern/libsndfile-modified/programs/sndfile-salvage.c create mode 100755 extern/libsndfile-modified/programs/test-sndfile-metadata-set.py create mode 100644 extern/libsndfile-modified/regtest/Readme.txt create mode 100644 extern/libsndfile-modified/regtest/checksum.c create mode 100644 extern/libsndfile-modified/regtest/database.c create mode 100644 extern/libsndfile-modified/regtest/regtest.h create mode 100644 extern/libsndfile-modified/regtest/sndfile-regtest.c create mode 100644 extern/libsndfile-modified/sndfile.pc.in create mode 100644 extern/libsndfile-modified/src/ALAC/ALACAudioTypes.h create mode 100644 extern/libsndfile-modified/src/ALAC/ALACBitUtilities.c create mode 100644 extern/libsndfile-modified/src/ALAC/ALACBitUtilities.h create mode 100644 extern/libsndfile-modified/src/ALAC/ALACDecoder.h create mode 100644 extern/libsndfile-modified/src/ALAC/ALACEncoder.h create mode 100644 extern/libsndfile-modified/src/ALAC/EndianPortable.h create mode 100644 extern/libsndfile-modified/src/ALAC/LICENSE create mode 100644 extern/libsndfile-modified/src/ALAC/ag_dec.c create mode 100644 extern/libsndfile-modified/src/ALAC/ag_enc.c create mode 100644 extern/libsndfile-modified/src/ALAC/aglib.h create mode 100644 extern/libsndfile-modified/src/ALAC/alac_codec.h create mode 100644 extern/libsndfile-modified/src/ALAC/alac_decoder.c create mode 100644 extern/libsndfile-modified/src/ALAC/alac_decoder.h create mode 100644 extern/libsndfile-modified/src/ALAC/alac_encoder.c create mode 100644 extern/libsndfile-modified/src/ALAC/dp_dec.c create mode 100644 extern/libsndfile-modified/src/ALAC/dp_enc.c create mode 100644 extern/libsndfile-modified/src/ALAC/dplib.h create mode 100644 extern/libsndfile-modified/src/ALAC/matrix_dec.c create mode 100644 extern/libsndfile-modified/src/ALAC/matrix_enc.c create mode 100644 extern/libsndfile-modified/src/ALAC/matrixlib.h create mode 100644 extern/libsndfile-modified/src/ALAC/shift.h create mode 100644 extern/libsndfile-modified/src/G72x/ChangeLog create mode 100644 extern/libsndfile-modified/src/G72x/README create mode 100644 extern/libsndfile-modified/src/G72x/README.original create mode 100644 extern/libsndfile-modified/src/G72x/g721.c create mode 100644 extern/libsndfile-modified/src/G72x/g723_16.c create mode 100644 extern/libsndfile-modified/src/G72x/g723_24.c create mode 100644 extern/libsndfile-modified/src/G72x/g723_40.c create mode 100644 extern/libsndfile-modified/src/G72x/g72x.c create mode 100644 extern/libsndfile-modified/src/G72x/g72x.h create mode 100644 extern/libsndfile-modified/src/G72x/g72x_priv.h create mode 100644 extern/libsndfile-modified/src/G72x/g72x_test.c create mode 100644 extern/libsndfile-modified/src/GSM610/COPYRIGHT create mode 100644 extern/libsndfile-modified/src/GSM610/ChangeLog create mode 100644 extern/libsndfile-modified/src/GSM610/README create mode 100644 extern/libsndfile-modified/src/GSM610/add.c create mode 100644 extern/libsndfile-modified/src/GSM610/code.c create mode 100644 extern/libsndfile-modified/src/GSM610/config.h create mode 100644 extern/libsndfile-modified/src/GSM610/decode.c create mode 100644 extern/libsndfile-modified/src/GSM610/gsm.h create mode 100644 extern/libsndfile-modified/src/GSM610/gsm610_priv.h create mode 100644 extern/libsndfile-modified/src/GSM610/gsm_create.c create mode 100644 extern/libsndfile-modified/src/GSM610/gsm_decode.c create mode 100644 extern/libsndfile-modified/src/GSM610/gsm_destroy.c create mode 100644 extern/libsndfile-modified/src/GSM610/gsm_encode.c create mode 100644 extern/libsndfile-modified/src/GSM610/gsm_option.c create mode 100644 extern/libsndfile-modified/src/GSM610/long_term.c create mode 100644 extern/libsndfile-modified/src/GSM610/lpc.c create mode 100644 extern/libsndfile-modified/src/GSM610/preprocess.c create mode 100644 extern/libsndfile-modified/src/GSM610/rpe.c create mode 100644 extern/libsndfile-modified/src/GSM610/short_term.c create mode 100644 extern/libsndfile-modified/src/GSM610/table.c create mode 100644 extern/libsndfile-modified/src/aiff.c create mode 100644 extern/libsndfile-modified/src/alac.c create mode 100644 extern/libsndfile-modified/src/alaw.c create mode 100644 extern/libsndfile-modified/src/au.c create mode 100644 extern/libsndfile-modified/src/audio_detect.c create mode 100644 extern/libsndfile-modified/src/avr.c create mode 100755 extern/libsndfile-modified/src/binheader_writef_check.py create mode 100644 extern/libsndfile-modified/src/broadcast.c create mode 100644 extern/libsndfile-modified/src/caf.c create mode 100644 extern/libsndfile-modified/src/cart.c create mode 100644 extern/libsndfile-modified/src/chanmap.c create mode 100644 extern/libsndfile-modified/src/chanmap.h create mode 100644 extern/libsndfile-modified/src/chunk.c create mode 100644 extern/libsndfile-modified/src/command.c create mode 100644 extern/libsndfile-modified/src/common.c create mode 100644 extern/libsndfile-modified/src/common.h create mode 100644 extern/libsndfile-modified/src/config.h.cmake create mode 100644 extern/libsndfile-modified/src/create_symbols_file.py create mode 100644 extern/libsndfile-modified/src/dither.c create mode 100644 extern/libsndfile-modified/src/double64.c create mode 100644 extern/libsndfile-modified/src/dwd.c create mode 100644 extern/libsndfile-modified/src/dwvw.c create mode 100644 extern/libsndfile-modified/src/file_io.c create mode 100644 extern/libsndfile-modified/src/flac.c create mode 100644 extern/libsndfile-modified/src/float32.c create mode 100644 extern/libsndfile-modified/src/g72x.c create mode 100644 extern/libsndfile-modified/src/gsm610.c create mode 100644 extern/libsndfile-modified/src/htk.c create mode 100644 extern/libsndfile-modified/src/id3.c create mode 100644 extern/libsndfile-modified/src/id3.h create mode 100644 extern/libsndfile-modified/src/ima_adpcm.c create mode 100644 extern/libsndfile-modified/src/ima_oki_adpcm.c create mode 100644 extern/libsndfile-modified/src/ima_oki_adpcm.h create mode 100644 extern/libsndfile-modified/src/interleave.c create mode 100644 extern/libsndfile-modified/src/ircam.c create mode 100644 extern/libsndfile-modified/src/macos.c create mode 100755 extern/libsndfile-modified/src/make-static-lib-hidden-privates.sh create mode 100644 extern/libsndfile-modified/src/mat4.c create mode 100644 extern/libsndfile-modified/src/mat5.c create mode 100644 extern/libsndfile-modified/src/mpc2k.c create mode 100644 extern/libsndfile-modified/src/mpeg.c create mode 100644 extern/libsndfile-modified/src/mpeg.h create mode 100644 extern/libsndfile-modified/src/mpeg_decode.c create mode 100644 extern/libsndfile-modified/src/mpeg_l3_encode.c create mode 100644 extern/libsndfile-modified/src/ms_adpcm.c create mode 100644 extern/libsndfile-modified/src/new.c create mode 100644 extern/libsndfile-modified/src/nist.c create mode 100644 extern/libsndfile-modified/src/nms_adpcm.c create mode 100644 extern/libsndfile-modified/src/ogg.c create mode 100644 extern/libsndfile-modified/src/ogg.h create mode 100644 extern/libsndfile-modified/src/ogg_opus.c create mode 100644 extern/libsndfile-modified/src/ogg_pcm.c create mode 100644 extern/libsndfile-modified/src/ogg_speex.c create mode 100644 extern/libsndfile-modified/src/ogg_vcomment.c create mode 100644 extern/libsndfile-modified/src/ogg_vcomment.h create mode 100644 extern/libsndfile-modified/src/ogg_vorbis.c create mode 100644 extern/libsndfile-modified/src/paf.c create mode 100644 extern/libsndfile-modified/src/pcm.c create mode 100644 extern/libsndfile-modified/src/pvf.c create mode 100644 extern/libsndfile-modified/src/raw.c create mode 100644 extern/libsndfile-modified/src/rf64.c create mode 100644 extern/libsndfile-modified/src/rx2.c create mode 100644 extern/libsndfile-modified/src/sd2.c create mode 100644 extern/libsndfile-modified/src/sds.c create mode 100644 extern/libsndfile-modified/src/sf_unistd.h create mode 100644 extern/libsndfile-modified/src/sfconfig.h create mode 100644 extern/libsndfile-modified/src/sfendian.h create mode 100644 extern/libsndfile-modified/src/sndfile.c create mode 100644 extern/libsndfile-modified/src/strings.c create mode 100644 extern/libsndfile-modified/src/svx.c create mode 100644 extern/libsndfile-modified/src/test_audio_detect.c create mode 100644 extern/libsndfile-modified/src/test_binheader_writef.c create mode 100644 extern/libsndfile-modified/src/test_broadcast_var.c create mode 100644 extern/libsndfile-modified/src/test_cart_var.c create mode 100644 extern/libsndfile-modified/src/test_conversions.c create mode 100644 extern/libsndfile-modified/src/test_endswap.def create mode 100644 extern/libsndfile-modified/src/test_endswap.tpl create mode 100644 extern/libsndfile-modified/src/test_file_io.c create mode 100644 extern/libsndfile-modified/src/test_float.c create mode 100644 extern/libsndfile-modified/src/test_ima_oki_adpcm.c create mode 100644 extern/libsndfile-modified/src/test_log_printf.c create mode 100644 extern/libsndfile-modified/src/test_main.c create mode 100644 extern/libsndfile-modified/src/test_main.h create mode 100644 extern/libsndfile-modified/src/test_nms_adpcm.c create mode 100644 extern/libsndfile-modified/src/test_strncpy_crlf.c create mode 100644 extern/libsndfile-modified/src/txw.c create mode 100644 extern/libsndfile-modified/src/ulaw.c create mode 100644 extern/libsndfile-modified/src/version-metadata.rc.in create mode 100644 extern/libsndfile-modified/src/voc.c create mode 100644 extern/libsndfile-modified/src/vox_adpcm.c create mode 100644 extern/libsndfile-modified/src/w64.c create mode 100644 extern/libsndfile-modified/src/wav.c create mode 100644 extern/libsndfile-modified/src/wavlike.c create mode 100644 extern/libsndfile-modified/src/wavlike.h create mode 100644 extern/libsndfile-modified/src/windows.c create mode 100644 extern/libsndfile-modified/src/wve.c create mode 100644 extern/libsndfile-modified/src/xi.c create mode 100644 extern/libsndfile-modified/tests/aiff_rw_test.c create mode 100644 extern/libsndfile-modified/tests/alaw_test.c create mode 100644 extern/libsndfile-modified/tests/benchmark-0.0.28 create mode 100644 extern/libsndfile-modified/tests/benchmark-1.0.0 create mode 100644 extern/libsndfile-modified/tests/benchmark-1.0.0rc2 create mode 100644 extern/libsndfile-modified/tests/benchmark-1.0.18pre16-hendrix create mode 100644 extern/libsndfile-modified/tests/benchmark-1.0.18pre16-mingus create mode 100644 extern/libsndfile-modified/tests/benchmark-1.0.6pre10-coltrane create mode 100644 extern/libsndfile-modified/tests/benchmark-1.0.6pre10-miles create mode 100644 extern/libsndfile-modified/tests/benchmark-latest-coltrane create mode 100644 extern/libsndfile-modified/tests/benchmark.def create mode 100644 extern/libsndfile-modified/tests/benchmark.tpl create mode 100644 extern/libsndfile-modified/tests/channel_test.c create mode 100644 extern/libsndfile-modified/tests/checksum_test.c create mode 100644 extern/libsndfile-modified/tests/chunk_test.c create mode 100644 extern/libsndfile-modified/tests/command_test.c create mode 100644 extern/libsndfile-modified/tests/compression_size_test.c create mode 100644 extern/libsndfile-modified/tests/cpp_test.cc create mode 100644 extern/libsndfile-modified/tests/cue_test.c create mode 100644 extern/libsndfile-modified/tests/dft_cmp.c create mode 100644 extern/libsndfile-modified/tests/dft_cmp.h create mode 100644 extern/libsndfile-modified/tests/dither_test.c create mode 100644 extern/libsndfile-modified/tests/dwvw_test.c create mode 100644 extern/libsndfile-modified/tests/error_test.c create mode 100644 extern/libsndfile-modified/tests/external_libs_test.c create mode 100644 extern/libsndfile-modified/tests/fix_this.c create mode 100644 extern/libsndfile-modified/tests/floating_point_test.def create mode 100644 extern/libsndfile-modified/tests/floating_point_test.tpl create mode 100644 extern/libsndfile-modified/tests/format_check_test.c create mode 100644 extern/libsndfile-modified/tests/generate.c create mode 100644 extern/libsndfile-modified/tests/generate.h create mode 100644 extern/libsndfile-modified/tests/header_test.def create mode 100644 extern/libsndfile-modified/tests/header_test.tpl create mode 100644 extern/libsndfile-modified/tests/headerless_test.c create mode 100644 extern/libsndfile-modified/tests/largefile_test.c create mode 100644 extern/libsndfile-modified/tests/locale_test.c create mode 100644 extern/libsndfile-modified/tests/long_read_write_test.c create mode 100644 extern/libsndfile-modified/tests/lossy_comp_test.c create mode 100644 extern/libsndfile-modified/tests/misc_test.c create mode 100644 extern/libsndfile-modified/tests/mpeg_test.c create mode 100644 extern/libsndfile-modified/tests/multi_file_test.c create mode 100644 extern/libsndfile-modified/tests/ogg_opus_test.c create mode 100644 extern/libsndfile-modified/tests/ogg_test.c create mode 100644 extern/libsndfile-modified/tests/pcm_test.def create mode 100644 extern/libsndfile-modified/tests/pcm_test.tpl create mode 100644 extern/libsndfile-modified/tests/peak_chunk_test.c create mode 100644 extern/libsndfile-modified/tests/pedantic-header-test.sh.in create mode 100644 extern/libsndfile-modified/tests/pipe_test.def create mode 100644 extern/libsndfile-modified/tests/pipe_test.tpl create mode 100644 extern/libsndfile-modified/tests/raw_test.c create mode 100644 extern/libsndfile-modified/tests/rdwr_test.def create mode 100644 extern/libsndfile-modified/tests/rdwr_test.tpl create mode 100644 extern/libsndfile-modified/tests/scale_clip_test.def create mode 100644 extern/libsndfile-modified/tests/scale_clip_test.tpl create mode 100644 extern/libsndfile-modified/tests/sftest.c create mode 100644 extern/libsndfile-modified/tests/sfversion.c create mode 100644 extern/libsndfile-modified/tests/stdin_test.c create mode 100644 extern/libsndfile-modified/tests/stdio_test.c create mode 100644 extern/libsndfile-modified/tests/stdout_test.c create mode 100644 extern/libsndfile-modified/tests/string_test.c create mode 100644 extern/libsndfile-modified/tests/test_wrapper.sh.in create mode 100644 extern/libsndfile-modified/tests/ulaw_test.c create mode 100644 extern/libsndfile-modified/tests/utils.def create mode 100644 extern/libsndfile-modified/tests/utils.tpl create mode 100644 extern/libsndfile-modified/tests/virtual_io_test.c create mode 100644 extern/libsndfile-modified/tests/win32_ordinal_test.c create mode 100644 extern/libsndfile-modified/tests/win32_test.c create mode 100644 extern/libsndfile-modified/tests/write_read_test.def create mode 100644 extern/libsndfile-modified/tests/write_read_test.tpl create mode 100644 extern/libsndfile-modified/vcpkg.json diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 801e61503..4bb18b71b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,14 +18,14 @@ jobs: strategy: matrix: config: - #- { name: 'Windows MSVC x86', os: windows-latest, compiler: msvc, arch: x86 } - #- { name: 'Windows MSVC x86_64', os: windows-latest, compiler: msvc, arch: x86_64 } + - { name: 'Windows MSVC x86', os: windows-latest, compiler: msvc, arch: x86 } + - { name: 'Windows MSVC x86_64', os: windows-latest, compiler: msvc, arch: x86_64 } #- { name: 'Windows MinGW x86', os: ubuntu-20.04, compiler: mingw, arch: x86 } #- { name: 'Windows MinGW x86_64', os: ubuntu-20.04, compiler: mingw, arch: x86_64 } - { name: 'macOS x86_64', os: macos-13, arch: x86_64 } - { name: 'macOS ARM', os: macos-latest, arch: arm64 } - #- { name: 'Linux x86_64', os: ubuntu-20.04, arch: x86_64 } - #- { name: 'Linux ARM', os: ubuntu-18.04, arch: armhf } + - { name: 'Linux x86_64', os: ubuntu-20.04, arch: x86_64 } + - { name: 'Linux ARM', os: ubuntu-18.04, arch: armhf } fail-fast: true name: ${{ matrix.config.name }} @@ -190,7 +190,6 @@ jobs: cmake \ -B ${PWD}/build \ - -DCMAKE_DCMAKE_POLICY_VERSION_MINIMUM=3.5 \ -DCMAKE_INSTALL_PREFIX=/usr \ -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \ -DWARNINGS_ARE_ERRORS=${USE_WAE} \ diff --git a/.gitmodules b/.gitmodules index f3ef8bbd3..434b5ab17 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,10 +2,6 @@ path = extern/SDL url = https://github.com/libsdl-org/SDL.git branch = release-2.28.x -[submodule "extern/libsndfile"] - path = extern/libsndfile - url = https://github.com/libsndfile/libsndfile.git - branch = master [submodule "extern/fmt"] path = extern/fmt url = https://github.com/fmtlib/fmt.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 7fbc64636..997abc02b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -287,7 +287,7 @@ if (USE_SNDFILE) set(BUILD_EXAMPLES OFF CACHE BOOL "a" FORCE) set(ENABLE_EXTERNAL_LIBS OFF CACHE BOOL "come on" FORCE) set(ENABLE_MPEG OFF CACHE BOOL "come on" FORCE) - add_subdirectory(extern/libsndfile EXCLUDE_FROM_ALL) + add_subdirectory(extern/libsndfile-modified EXCLUDE_FROM_ALL) list(APPEND DEPENDENCIES_LIBRARIES sndfile) message(STATUS "Using vendored libsndfile") endif() diff --git a/extern/libsndfile-modified/.editorconfig b/extern/libsndfile-modified/.editorconfig new file mode 100644 index 000000000..f8911427f --- /dev/null +++ b/extern/libsndfile-modified/.editorconfig @@ -0,0 +1,16 @@ +root = true + +[*] +insert_final_newline = true + +[*.{h,hpp,c,tpl,def}] +indent_style = tab +tab_width = 4 + +[*.py] +indent_style = space +indent_size = 4 + +[*.yml] +indent_style = space +indent_size = 2 diff --git a/extern/libsndfile-modified/.gitattributes b/extern/libsndfile-modified/.gitattributes new file mode 100644 index 000000000..7638b1f56 --- /dev/null +++ b/extern/libsndfile-modified/.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/extern/libsndfile-modified/.github/workflows/action.yml b/extern/libsndfile-modified/.github/workflows/action.yml new file mode 100644 index 000000000..4c24215a7 --- /dev/null +++ b/extern/libsndfile-modified/.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$<$: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$<$: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$<$: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$<$: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: | + autoreconf -vif + 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/extern/libsndfile-modified/.github/workflows/cifuzz.yml b/extern/libsndfile-modified/.github/workflows/cifuzz.yml new file mode 100644 index 000000000..58ef9c4a0 --- /dev/null +++ b/extern/libsndfile-modified/.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/extern/libsndfile-modified/.gitignore b/extern/libsndfile-modified/.gitignore new file mode 100644 index 000000000..05f79a937 --- /dev/null +++ b/extern/libsndfile-modified/.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/extern/libsndfile-modified/AUTHORS b/extern/libsndfile-modified/AUTHORS new file mode 100644 index 000000000..9ef64da31 --- /dev/null +++ b/extern/libsndfile-modified/AUTHORS @@ -0,0 +1,235 @@ +Original author: + +The main author of libsndfile is Erik de Castro Lopo +apart from code in the following directories: + + - src/GSM610 : Written by Jutta Degener and Carsten + Bormann . They should not be contacted in relation to + libsndfile or the GSM 6.10 code that is part of libsndfile. Their original + code can be found at: + + http://kbs.cs.tu-berlin.de/~jutta/toast.html + + - src/G72x : Released by Sun Microsystems, Inc. to the public domain. Minor + modifications were required to integrate these files into libsndfile. The + changes are listed in src/G72x/ChangeLog. + +Current maintainers: + +After the release of version 1.0.30, @erikd transferred the project to +[the libsndfile team](https://github.com/libsndfile) consisting of: + +* Erik de Castro Lopo aka @erikd +* David Seifert aka @SoapGentoo +* Arthur Taylor aka @arthurt +* @evpobr + +Current releaser is David Seifert: + +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v2 + +mQINBFppABgBEAC42ZiNvV7BTIgR6TQy0YnF54fx3mVRP1u8Mq00UZa7reAsNKh7 +1H60j0W4s6+4pVVIKGfpVGxLwUdJe+KVCYw1Cd3YW6uMf5zZrC/ZWqnJiH/n6S6o +1l4INII2o6YbGBnzIWBPRo7PlOL+mvgKTLpBSJPnhD8XDGN5wRiV8rL2+6Dptg0F +nJt7oxECGF3OD3gk6HMel0o82CVkIqMtNaX1L/bhcdF7K0Rp2MXPZMmpn1izW5sI +asN1G9+w+Zwj7kMJzq1Aw3ac+rsX4SEYdvXjS2QhDHQUIr6LXri3D2WbcEqIZj2R +JVoVwblsrG11dYXFDBbgrq4NhgTBsxHYDlkr/qF2W+kbPC/nhSqTVZeCYvTBZbOQ ++RqyN/I0izukglnWmV1jGijFA8snyP8efx732hw/24zRYmtXOtnEITUpw8WOeZCq +6uiHaQ+eopnY2ojBg9BI7WZm0AFn58xxT9soMsyFOUFgXTqaWFZWlJ3fhZE8/0v8 +JEu/kPGE5aJReT3b34B+Bojkj74XR+h2u7iJJBHMTE8RwGoUOZHer/XsL9xlcdks +I+7TCjiq++ShaSSt2XsJmw2BhREohrjW/2KkwmvT3b44RMpKPB4WTH+++aqJQNeM +IqmswOMoZvzEZezInj7WVY/r0WEei1Y6wt1tBrJ/cFf1oQBM1UmphxcrfQARAQAB +tB9EYXZpZCBTZWlmZXJ0IDxzb2FwQGdlbnRvby5vcmc+iQJUBBMBCgA+BQsJCAcD +BRUKCQgLBRYCAwEAAh4BAheAAhsBFiEEMdlcq22A0mIkShdQpHYg6AHkfpUFAl/V +CvoFCQkuceIACgkQpHYg6AHkfpXYxA//aiJW1NwunpmzEc62id8lRMnoLHWVjISZ +b+xSlm+hk4LYq+ZbthJDzKcT86/3DJOSE1zQw9wLuCao9IW2UfFJQBtR+TAfbagG +0Yyk/kMcLoFJxnG1ywdJWypCAauuIhia52Z7PmmjsBbFwr6LygDwSQmZAyACMAs7 +TLQe+yERc2RNDsIEsquLSxxRF0Spk9gagWtKgrPc2XBjuNtQDwW7JgsOUoEeHyxC +29fRUjC3o/pG2I6iAZp17OROZI5yl4TSORrSBDGIi2sayxyxP0x+IPKtrCUcBGNx +wGp+56bP/V0hA6sgCPh/iwvqLoeibso6l/Kd4ltVAEQnHTd6fr8g+wLEUXfbJVTR +7aeFUoaFmWjSPlQrNr6HlxSLV/kRx9kVJp1Pn16vkfVBF7fG7iDLiqphwEeQg5ND +nmGeKAbRRNxFHyBHf0XRsaYiFZQckguO+71XSRtVx8/YP5nyNbtl9y1h/4JlT6Gy +t7hb5twYFQyQrKss83E/Bo1sRdHpj0ibtqb4ZbYANbh482E6yFhAkuo8YjVTJipI +1Ve8EBKnX3R+pDt147uyysNvtPVXML+sWpGSMVSm4NA8uT3F5nqxVwj+SeXy3Wq/ +CHQ2VBKGBC655G+wFD5C6O7cTx2MwH+2H8tzhWm+gFlI3MFKEXa/PC+YUC/diYcb +BrApavriTRa5Ag0EWmkAZgEQAPXMD3mZI+ChvBysXZWksC88/uSEwFeb3XkcRm7v +04GN7hcz+bfrmnUTB3tuE/ZQgv+u7ZjetvH1aEKieznn/GjnWoOBoJusOYvfAQeF +0mQVi118QiOZRCnEZpkz+RY9TiXVgrZJg+AGqHZ3Ol4GkInEV2NWgH37Xal+HkFl +rwI2U7mL0kZRG+LAVCQHKzqU0R0HE1XyJ4qf0awtG5Qi/TZvgXBdZPDXgr8i9Vlf +UUu10c2XnXM0Av/YAlZmBFjVYrSOUCFenqSVqL+s9sTCVdWlJrGjrr3Ja4uT3kl2 +rLva0AR4oSQoxt8adKohmFz0vzOkQtCoRzhrCwoo3JvNjKdSNoOP1nSsxlO5ji8r +ih5d+ajPgi580XyHLnrvG7vobR48qqscv1hizKuCgTacOTe6Db2Gqc8xF6v8HhJa +KwWJtmFllIfN/tIvZ6BbbgHQn0IGf4CYnWf0SksPZqpBmTRpD2jfBxcj2UEg+AR3 +LARjuyUVpFJScyu6ExQG+6O+ByLL31iWP5MgUrza1rIpriPa3NT3rZ3DG2pvQrS3 +ySsrPzH7VRX8L1ThSMSzjwF96aMsd14s7XzR4EzNuWwZDukfs0yavZk6l4o1M0mb +tbJi7hE4cz13KRHYvIkKMdZGYUnzRzZUDlsj2imakk3BR6GXnxZ1ST6062g+QxiL +AJFLABEBAAGJBHIEGAEKACYCGwIWIQQx2VyrbYDSYiRKF1CkdiDoAeR+lQUCX9UL +DQUJCS5xpwJAwXQgBBkBCgAdFiEEuNUxXaAAcsCoYIifzjbhFyAuOEIFAlppAGYA +CgkQzjbhFyAuOELmrQ/9H9wrWsWa21STZdxUmyU2sh9VXAWEHl1Ey0fVTznDM0Fl +zx5YSR/TmmnE36rpaz31Ttkx8SP914oV+mMgseecdya9Bf6uZL9Cv7V3KEsJBRL/ +ncrOWQBHP/Xy1X+mLD6A19xq7H4RihSLj0LeK2YVjrJzJ7wMf4mKXuBayQeAHImU +WRCRTbmK3umh2nB5V0iPd/XZEIiYtiTPe+7E/va6+0bBvOumF3a+Z0iui7eU4hFC +7Jk71D0dcg09SlIaNoMOrw7cMC3j2pMdKtsj8+0I6WBv14PhhqPAsnjdf7I/4NfK +L7Jav8T/gDS01uA2Jxm72d+wr+eSjOBXa6x8CEbTqfkjAGxsWENThCp6zDkaXSDd +JsV0va47vjzG8+wTDAvPy5IxIM/KZZdl4uWM+mF5K+q+eSTOHe7aLF2OdcussoBA +A18zm994dAkG1COX/qpxanxx2bv/2IvCGPg+x6JtAN8ji2kncWu3dWGQdE5XbVjc +fDwgsUPpp04G27Mr/x+HpEbgZ5SdA0dAqJktlNvCcHALhlblCWrsh/1QNjT/2iG8 +wsjcpEy/s4tWAuV4PTa4xvZ1JPS7Z7Eo5aBy9ZGOWG9SrHEiHnhkUsiswbHBOEjd +pBSkmNElDcv9fRUahVCTPfvWBATFDrQyMjJBSm+cV8c/iFQM7isVSu8W7E0eetsJ +EKR2IOgB5H6Vv9sP/1dxTvH0N0UoEoxIG/hnirEkbRpljdvqy4/uikYBKyQgSbo8 +VITTjea7gIhDztil9WZYt35jbOmoaGM2Z6TP2LEDOWgljYUNq9pl9Sc2GS8cNtEO +WxExzGOc1Flo730dX3A85Ks3+0WPXZjLDcRRcPVkFd5WLQQDV1YVYopWkuQBC+Br +4q3uv+sk+bw6gDa9+zFBbDuegdsYuTXrFHoxHz2GRv9Yb7ULCMgpFeNKDgtQq91u +RqewoTwQp9tlp91LH/hh7R0Q4DRgeFDkLnVRXwSKjVvCrT5cBgImGwtFTGS4egoy +MDKd/KKjZllp1ahRCln1XfmFQyQVMVvuF/JTtt31n6KwXwK2yxIlXB01xvRH+Ees +AWeRYWKWXydaAY/9Ve0/PLFlgsr/XUGvt0GoEKe7odD3nZgg6015+/8JTroKw19L +NZkhdfFMl11Zi0j5k3UbyzjYVpFSd8K2o0VoOG1LFsPp8tlRxNoVzpId0CX1au/p +y1H7Wy/39mzriRG3rw+mJAQbBjN09putCltXFXpOEWk08n/N3vufCVQUoSu/2Bqw +2HYj8VtToQp+O5dG3XxvDHINtInP1yr2Wcw2plna0KoXLwv/lZgDm3LN+eCWpG6d +N/xk25DTSqTHArUQIEkhcHYK6GnyxUcvoKtG88hXtqEPYXiK08FZYAUPTnDYuQIN +BFppAIkBEADDjvQZUs1NoqJpxkD2QDBudU1DBCaeI1D6CancMtb5FebPUxgFlDMd +CBGOun48dY5i87gDhT/qS3gP/Mv9rjKJmcG9JHfhpXdW73owxrcsQ96nxxVJNEVl +UHJw00z8C9eGWqr0SzSoE33K/PkzSkgtsaotF6+3uCerWulweulmGa5dpVfV0mbS +aVw8VmrhZ5NmCeodyy/lR85rPik5pb32NT6v7xBkgkfS0VYtPB2E5gW1pXX/jEOi +Mfq9idOEP9lxrNXV9j49Lr0JQCwAcrYbQ2+VPe6eacJEjzJ/6HiUqhPrYdnvydmb +hU+xmv2NjGp2UnDZDEhzQfwm6fMx+8Nx2uPzCnXQGoyRBwiC/KcdW0F1ZPKdSXqH +NKoOF62pLvIMSmfI3ZVOrTohArfr1kFEYVDv9Nl7oY+qg2rZEc2srOF74a9Z46bR +TDPsEQzE2UMCvu3+rofhSD7aRotlKeDCvbe2s0yE4Man457Xc3LXh8Gva8CzCOLE +2eMhNTsHIZk68WgXp3/uvE4Xy42myrk1AV8XXDdlWgx0Kc/I6tE59O5NVPSfuGvH +1a15KKx0F6euEnYDKKpQ5PDR6dSn61po0tfbt96m044G/xQFjrfhHei4jji9Ogd9 +vlXVAi2vn3+NCSHFP5l3igLByBHy9iLIdmz7yQuus/1nwRmxOHOf2QARAQABiQI8 +BBgBCgAmAhsMFiEEMdlcq22A0mIkShdQpHYg6AHkfpUFAl/VCxkFCQkucZAACgkQ +pHYg6AHkfpVPSRAAmheYkYJmtDbkzPBBnj5mbCIQN1/G5PI9eixc/TXWFOXtcjU1 +mJlJpSidHJyLRrx7r0c+N+s8vnY/JuUBsNoMJMER+Mv/CFW4iFi59V534SyAb2S0 +7NINJnFNkXBY62CDz9KsMuv/MdSv2yLhPH2Tfrm/eDRQesj1PanE4U1cgjWyJRc/ +IOlaRHvTasWDLgwbQi8ykt+4xUWzL/YKHzB+KyyzBK7vPBXqySX8ka4BOw7SDwG5 +lX2gtmhk4AGBwVChLXKflqVx1WXj4DPOt0kmOKVnKFyvUijK58M0A2FMgFMXDTIS +DRtoZPdx/rkODXxgS+W+27NcYAnxJiM0cQqizEnQh7PQ1KzgdChPejYXMKe9lwdn +ssMUxrBpbuAuagEf+pebNjD2eaNR4p8kfaDdGn53q55ysDvoyxKvnVQGSk1FAR9Q +s4N5a4f02U7dzlyEhEfIcuUlRCfnlpn4n725YIhHheDig5zKWoEZCkNIfiRcGzDl +8Drj+tlZiUR+gDkIoWSBaCkKbIQlc8qCYy6Hm7oZBaol6xKlUnTMK2rjK8fR4i8r +bVDWBAaWj3jcDHJ0Jg3fS/qBpeya/JXMp89TR8NK5Ys7PZpWbor+puXBYyXDAVx3 +rXQ7JBA5klHPxrgjso1S/LqwscKLENtrVjdjhryLBmPifrmofJRnrpiHIEa5Ag0E +WmkAswEQAL0hKwsRybQzkNGpJP+ElLSwFHd7XQhr+qIwLllpumWtnIK/DHmv8SpW +FqAYajmRTXipFcBHH25x2jIIliZidn0a9826l+sMzrFadMC6/W4pitP71TeqZzwn +pAuHs14YL7Wiy0aJQnfbCpRzPq3kYyOXmhmY7lPWO0WdUpR6W8wUbleK5XOVDDRx +aIC/M3hhDOxZOMzQ+pdn4BaOFQQ0ygsRkqOudbuc0R1giYRt1i6gMeT8gfzL9jlw +HcJ+aVnxdUQQ4uC47oKo/+lg7qh7LsiW79pQC1Bcdm8lhRmqtxe6ub60ecjax3XU +1ILIEfIFCv6M7LRUAwz0bqk35spgkJqrGGKkdeWEKAFHg2QWR2F0zy+HdlPLfKxO +uhaccpwc9EJtf744GS0SXa2AXr32j56n7CFcEjFcIQPBC6OJn6eA3hOVUYGZ7SrT +4fsmZiFAdGEkvLKFuNhju1Hj2EJQUY1pm4GSBco7BR8x+QqoYrt5clU3WxRMNfTR +0Rtuzsh4xskXNVMMgvKOahAtxENv2M2Cx6zJPVL5dmaysP7d6QRVeOQA5PwkcZ5Q +qK6JtDZj2jpaKQH4Za715kiIcdqMDSkwxa6avc0kARHvfFcBR4hwDm1GAlaKG7eH +8TOGGQIk8x2F3s4l8mTJVLWTP/uJYnkYBdqANYo5t1NIQLvwLFV3ABEBAAGJAjwE +GAEKACYCGyAWIQQx2VyrbYDSYiRKF1CkdiDoAeR+lQUCX9ULIwUJCS5xcAAKCRCk +diDoAeR+leekD/sF7aHH0W35ckWrXZlfSp0qHPWrBUaLBI9OAUHenRhgs4SbK0D4 +wqEiu0C5iDQojpXAeALQ8g/1pUsZ1yuFqYbGYWrHkA0Pm+P3tAGB4LMZ41YfvROP +uaiW/+IMJbWllgRtaDt8/NtCgs30WI9I+az5M29HcGfvEwEUykrBx3dE9T+1ui3O +capdd+GMvdAAsX5PyVkjWgZ7GrZeH8mG7UysYfT4qthxEtQfZ/u8ceSduKA46ugh +C2eafIDNvluqn7BU4oKxME61u6C8BN2yHLI6LV0Tr4z5H8joVbM4BSFMwLVGlsXf +HhB8kLiErN6bXolxsjARlmYiD9S9H2AcYidr6RYXf2EVFSpBG59xn1WTDN+DsHQf +7btNPEPl/OPxa3OQjG+xn8USddiP0N0B4xsyzMNCCKDgvXXcIhX55KG9eh3Tc98S +fEyhxu8ybZBIGmTJysPKxijfvSgQF+RPNTsz9lvXqkoK7RTgeYMschpjJEznCLbt +M6eTDb5z0G5uLXh6+dYxtDOlPogI5OHd+G51LwCjvrQ+AtIUCgafuemwA9mpFT2b +svb/qcxSVUb44bVaNHn1JHebX2YbokGtBOm1x2PI5fT8n6YIIYz3jKYOZAYdUT7x +6qURyNjOfG4aPJIATwuh4GSNuxUG40+yuT+XfQF24mu1esS1J3wzRloJ7w== +=K3x+ +-----END PGP PUBLIC KEY BLOCK----- + +Previous releasers: + +Version 1.0.29-1.0.30 - @evpobr. + +The public GPG key: + +-----BEGIN PGP MESSAGE----- + +yMMwAnicrVJ7UFRVHF50SdiJ2AknHmYM19IhFrmPva91hnBKHMkcSyAyY7nn3nN3 +L7AP9qVoO5Lja1YUycgJ4iUFWYluTlE4Oi6PxdhpCkesIWiAQIbXqlSs1Ex1l7H/ +6r/OP2fOd77vm+/3za8nZqVCFVEfk/xkgPyrMiLgO+FUFIze8R5AgEUoR3QHkBK4 +fMFSAdod+hJJQHQIiqEYBzECYByBs4AnGBYDGIYDjqEYHMc4nKB5ntICkQSAxCke +RTEaJ3AthWJaWccItIhyiAYRJbMB2qw2yeyQbVmA8aKAQxbHCZbXApxhIIqTIiug +AiZiPA8IUhQZXhYaLfawQg4HODvcKFlkTH7ol+P9C/9/zu1cthMJlJG5NM+RFEUC +nsIomiJIBhMIUmAwNky0Q5uZM0GZDV1WC7Ahbg0iYy6Jh+FaH/4ZJIfRCf6L7yi3 +hoG9EOgfSvVAMgtyd7LCBW12yWJGdJjM5B1SWItpWQwjtBjOahC4zyrZoF4KM0ia +YlD5aBCrDbpkSxrwIkpwUO6YIHCUAjwOKEIUBFaAIsWKAJfrF7XyoJAGkIaUPD9g +aSBwIkUIOIqEhykzWxAdKcfkDLKlXTKYOYfTBhF3l2+PUhGhUjwSuSK8UwpVtPqf +TTv+gVoRyKt70PuZxj6oi7ZkZP481vcc2vJ6cV774dld3s3n3+3w+cXdW9YaVvc9 +ni8Nv6aOUqx5b/+Lexria1wn7c1DOxVnikYSV50eY0o7Lwatz3qqg6RHWVOVF3zm +lai7u7ud7r7vh5Lrm+95j06OeWN+29SbkNVeW9X1Vs651NsF9K1jV7xzkRdz6N4f +Vy+5B37qTr18Lclk9lx7o3cmP/+6Jbbl3qvj7w/PvTnVDyYiuxtSZlvtCZ2JT6yv +21rw8tLXnDHhwv0/7kfnpgSNXxKLA/tyPRsunLxp8tw4e6zx6PGbwsxKsTopg9u1 +dkdzBxWf+VVb/tbUzZNtUzUpj0l1fiSUtu1UaHxwdOnj2JlI4fdfdyAh/5GqvbY5 +7YKy0hgabi89Ffen+qUNtZ+f90258OevKhf6S+p+qelSRh/64ZOihg87D857slVZ +5wqttfExWb7LymH/oVjTpcWFt4u/uP3pC8YrwfY+ad2NpDuW5oqPZrKOFCoGzqgb +t1jSF1Vph1c0qtZUds+PaAqpp/Mqhjo0yavKiid91emBiPaeb3s2uW8d9J6YXZiu +T8p7tK+8yHp3ov4dcCk3lNY28s13ZePrW8ceVGc3zOT01/ibotLjdFZn9tmd67a3 +iCrDaJM7Y/9TY8XzHdPbTZ2wPG7bxFBg2LSx6WootqI1dF2fGutPzE0bzJzW/w3x +usYz +=XFTp +-----END PGP MESSAGE----- + +Versions before 1.0.29 - Erik de Castro Lopo. + +The public GPG key: + +-----BEGIN PGP SIGNATURE----- + +iQIzBAABCAAdFiEEapGlzyLCTJmjXgE/z9z5H7JCrO0FAljgv0wACgkQz9z5H7JC +rO2RhxAAnIuHquhkhaY8CVsIOGImMxEF8RKDyFoioV9RnckNzBb592EYxU9hS0MM +cT6xPZU0bJa8CvmCxEABMlkk60JP4VmmOtWxD8EEyktbHGyao80mDR82yVKYv78L +zTRzz/JoTncgwWz/QataMbkAfy3KpxkwDW87az0kzkqGuSm3Jg3medt+t/iBe0Wm +jcxIexxEZCmIhty6VyaVEkGWax0zdJHe7aD9FK2C/R3DU5Byp4e9pcp/a8v74G1n +dgD4S3YlqvJGuU9S6QD4PzsoWD1X8f6pHzxpRP/OkqHAe11sSRo6sSYYCjsYi9Ca +IJSlVC1nMx9OUxxAA8ZqtnztOo7GZcJ5NAL5X3GNV6YfQ7Bqxvtr6QG26F06MB6i +p08UC7NC0bxFsD3f07wY22QnbnM052rniTn5sqQZv+GVls6t1b3u1iHzEjAjlgvi +eOjVVt/A8iaOzMbKC/3+SZ9/GYqbSAQOCIoWAXmhV9IaMQyQeLCIC1YD5NMGBXal +HPfSHV0hSUDbKjAYXFigJRzFU125bXTgg+v13Kd0KklIEjoaZYZLAYs0BupXdjBf +jSPv8pwUaXJkv9/bGH0Ot1fvwDqPDOlGFINQbGAWdxwsdhiYBeXMFeFNTEfiqEMz +BhhMxKa+Mfd9fkrX4NNigGW5QgRBS+FHNLf6ZfiXSnBGjjxMcbI= +=UUA0 +-----END PGP SIGNATURE----- + +Others: + + 2013-03-07 Michael Pruett + 2013-02-11 Chris Roberts c.roberts@csrfm.com + 2012-03-17 IOhannes m zmoelnig + 2013-02-21 Jan Starry + 2012-01-20 Bodo + 2011-06-23 Tim van der Molen + 2010-12-01 Tim Blechmann + 2010-10-04 Matti Nykyri + 2010-09-17 Brian Lewis + 2010-02-22 Robin Gareus + 2010-01-07 Christian Weisgerber and Jacob Meuserto + 2009-10-18 Olivier Tristan + 2009-10-14, 2009-08-30 Uli Franke + 2009-06-24, 2008-11-19, 2004-09-22, 2004-06-17, 2003-05-03, 2003-05-02 Conrad Parker + 2009-05-22 Lennart Poettering + 2008-07-03, 2006-10-22, 2006-10-18 Fons Adriaensen + 2008-04-19 David Yeo + 2008-01-20 Yair K. + 2007-12-03 Robs + 2007-07-12 Ed Schouten + 2007-06-07 Trent Apted + 2007-04-14, 2003-12-12 André Pang + 2007-04-14 Reuben Thomas + 2006-11-09 Jonathan Woithe + 2006-03-26 Diego 'Flameeyes' Pettenò + 2006-03-17 Paul Davis + 2006-03-09 Jesse Chappell + 2006-01-09, 2005-12-28 John ffitch + 2005-09-21 David A. van Leeuwen + 2005-08-15 Mo DeJong + 2005-04-30 David Viens + 2004-12-29 Steve Baker + 2004-09-05 Denis Cote + 2004-06-28 Stanko Juzbasic + 2004-02-14 Frank Neumann + 2003-08-15 Axel Röbel + 2003-08-06 Peter Miller + 2003-07-21 Tero Pelander + 2003-02-10 Antoine Mathys + 2002-12-30 Marek Peteraj diff --git a/extern/libsndfile-modified/Building-for-Android.md b/extern/libsndfile-modified/Building-for-Android.md new file mode 100644 index 000000000..eb5a0d350 --- /dev/null +++ b/extern/libsndfile-modified/Building-for-Android.md @@ -0,0 +1,46 @@ +# Building for Android + +Assuming the Android Ndk is installed at location `/path/to/toolchain`, building +libsndfile for Android (arm-linux-androideabi) should be as simple as: +``` +autoreconf -vif +export ANDROID_TOOLCHAIN_HOME=/path/to/android/toolchain +./Scripts/android-configure.sh +make +``` +The `Scripts/android-configure.sh` contains four of variables; `ANDROID_NDK_VER`, +`ANDROID_GCC_VER`, `ANDROID_API_VER` and `ANDROID_TARGET` that can be overridden +by setting them before the script is run. + +Since I (erikd), do almost zero Android development, I am happy accept patches +for this documentation and script to improve its utility for real Android +developers. + +--- + +## Using CMake + +(Tested on Linux) + +For convenience, export the following variables: + +``` +export ANDROID_ABI=arm64-v8a +export ANDROID_PLATFORM_API_LEVEL=29 +export NDK_ROOT=/path/to/android/ndk +``` + +Set `ANDROID_ABI`, `ANDROID_PLATFORM_API_LEVEL` according to your target system. Now cd into the libsndfile root directory, and run + +``` +cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE=$NDK_ROOT/build/cmake/android.toolchain.cmake -DANDROID_ABI=$ANDROID_ABI -DANDROID_PLATFORM=$ANDROID_PLATFORM_API_LEVEL +``` + +cd into `build` and run make + +``` +cd build +make [-j ] +``` + +This will build libsndfile for android. diff --git a/extern/libsndfile-modified/CHANGELOG.md b/extern/libsndfile-modified/CHANGELOG.md new file mode 100644 index 000000000..122085300 --- /dev/null +++ b/extern/libsndfile-modified/CHANGELOG.md @@ -0,0 +1,190 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [1.2.2] - 2023-08-13 + +### Fixed + +* Fixed invalid regex in src/create_symbols_file.py +* Fixed passing null pointer to printf %s in tests + +## [1.2.1] - 2023-08-12 + +### Added + +* RISC OS support to `sndfile-play`, thanks @ccawley2011 +* Move semantics to `SndFileHandle` C++ class, thanks @haydaralaidrus + +### Fixed + +* Various typos, thanks @@uniontech-lilinjie +* Handling of absolute `CMAKE_INSTALL_LIBDIR`/`CMAKE_INSTALL_INCLUDEDIR`, thanks + @Staudey (issue #908) +* Add `localtime_s` support to `sndfile-metadata-set`, thanks @neheb (issue #907) +* Linking with CMake against `Ogg::ogg`, thanks @FtZPetruska +* CMake `mpg123` module handling bugs, thanks @FtZPetruska +* CMake dependencies handling, thanks @FtZPetruska +* Various `Ogg` & `Opus` format fixes, thanks @weiliang (issue #888) +* Redefining `ssize_t` when building with Autotools, thanks @ccawley2011 + (issue #934) +* Bug related to incorrect `realloc` use, thanks @Halmoni100 +* Style errors, thanks to @arthurt +* AIFF format related bugs, thanks to @arthurt +* Reading of MP3 files without Xing or INFO headers, thanks @arthurt +* Coding style of `src/mpeg_decode.c`, thanks @arthurt +* Various documentation types, thanks @luzpaz +* Intrinsics inclusion for MSVC and ARM64/ARM64EC, thanks @frysee +* `sf_open_fd`() regression, thanks @brentr (PR #950) +* WAV format related bug, thanks @magnus-nomono (issue #930) + +### Removed + +* Obsolete file `libsndfile.spec.in``, thanks @janstary + +## [1.2.0] - 2022-12-25 + +### 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 + +* MPEG Encode/Decode Support. + + Uses libmpg123 for decode, liblame for encode. Encoding and decoding support + is independent of each other and is split into separate files. MPEG support + is generalized as subformats, `SF_FORMAT_MPEG_LAYER`(I,II,III) so that it + might be used by other containers (`MPEG1WAVEFORMAT` for example), but also + contains a major format `SF_FORMAT_MPEG` for 'mp3 files.' + + Encoding Status: + * Layer III encoding + * ID3v1 writing + * ID3v2 writing + * Lame/Xing Tag writing + * Bitrate selection command + * VBR or CBR + + Decoding Status: + * Layers I/II/III decoding + * ID3v1 reading + * ID3v2 reading + * Seeking +* New fuzzer for OSS-Fuzz, thanks @DavidKorczynski. +* This `CHANGELOG.md`. All notable changes to this project will be documented in + this file. The old `NEWS` file has been renamed to `NEWS.OLD` and is no longer + updated. +* Add support for decoding MPEG III Audio in WAV files. +* `SECURITY.md` file to give people instructions for reporting security + vulnerabilities, thanks @zidingz. +* Support for [Vcpkg manifest mode](https://vcpkg.readthedocs.io/en/latest/users/manifests/). + + If you have problems with manifest mode, disable it with `VCPKG_MANIFEST_MODE` + switch. +* [Export CMake targets from the build tree (PR #802)](https://cmake.org/cmake/help/latest/guide/importing-exporting/index.html#exporting-targets-from-the-build-tree) +* CIFuzz fuzzer, thanks to @AdamKorcz (PR #796) + +### Changed + +* `SFC_SET_DITHER_ON_READ` and `SFC_SET_DITHER_ON_WRITE` enums comments in + public header, thanks @SmiVan (issue #677). +* `ENABLE_SNDFILE_WINDOWS_PROTOTYPES` define is deprecated and not needed + anymore. + + Previously, in order for the [`sf_wchar_open`()](http://libsndfile.github.io/libsndfile/api.html#open) + function to become available on the Windows platform, it was required to + perform certain actions: + + ```c + #include + #define ENABLE_SNDFILE_WINDOWS_PROTOTYPES 1 + #including + ``` + + These steps are no longer required and the `sf_wchar_open`() function is + always available on the Windows platform. +* Use UTF-8 as internal path encoding on Windows platform. + + This is an internal change to unify and simplify the handling of file paths. + + On the Windows platform, the file path is always converted to UTF-8 and + converted to UTF-16 only for calls to WinAPI functions. + + The behavior of the functions for opening files on other platforms does not + change. +* Switch to .xz over .bz2 for release tarballs. +* Disable static builds using Autotools by default. If you want static + libraries, pass --enable-static to ./configure + +### Fixed + +* Typo in `docs/index.md`. +* Typo in `programs/sndfile-convert.c`, thanks @fjl. +* Memory leak in `caf_read_header`(), credit to OSS-Fuzz ([issue 30375](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=30375)). +* Stack overflow in `guess_file_type`(), thanks @bobsayshilol, credit to + OSS-Fuzz ([issue 29339](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=29339)). +* Abort in fuzzer, thanks @bobsayshilol, credit to OSS-Fuzz + ([issue 26257](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=26257)). +* Infinite loop in `svx_read_header`(), thanks @bobsayshilol, credit to OSS-Fuzz + ([issue 25442](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=25442)). +* GCC and Clang pedantic warnings, thanks @bobsayshilol. +* Normalisation issue when scaling floating point data to `int` in + `replace_read_f2i`(), thanks @bobsayshilol, (issue #702). +* Missing samples when doing a partial read of Ogg file from index till the end + of file, thanks @arthurt (issue #643). +* sndfile-salvage: Handle files > 4 GB on Windows OS +* Undefined shift in `dyn_get_32bit`(), credit to OSS-Fuzz + ([issue 27366](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=27366)). +* Integer overflow in `nms_adpcm_update`(), credit to OSS-Fuzz + ([issue 25522](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=25522)). +* Integer overflow in `psf_log_printf`(), credit to OSS-Fuzz + ([issue 28441](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=28441)), + ([issue 25624](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=25624)). +* ABI version incompatibility between Autotools and CMake build on Apple + platforms. + + Now ABI must be compatible with Autotools builds. Note that this change + requires CMake >= 3.17 for building dylib on Apple platforms. + +* Fix build with Autotools + MinGW toolchain on Windows platform. + + See https://github.com/msys2/MINGW-packages/issues/5803 for details. + +### Security + +* Heap buffer overflow in `wavlike_ima_decode_block`(), thanks @bobsayshilol, + credit to OSS-Fuzz ([issue 25530](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=25530)). +* Heap buffer overflow in `msadpcm_decode_block`(), thanks @bobsayshilol, + credit to OSS-Fuzz ([issue 26803](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=26803)). +* Heap buffer overflow in `psf_binheader_readf`(), thanks @bobsayshilol, + credit to OSS-Fuzz ([issue 26026](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=26026)). +* Index out of bounds in `psf_nms_adpcm_decode_block`(), credit to OSS-Fuzz + ([issue 25561](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=25561)). +* Heap buffer overflow in `flac_buffer_copy`(), thanks @yuawn, @bobsayshilol. +* Heap buffer overflow in `copyPredictorTo24`(), thanks @bobsayshilol, + credit to OSS-Fuzz ([issue 27503](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=27503)). +* Uninitialized variable in `psf_binheader_readf`(), thanks @shao-hua-li, + credit to OSS-Fuzz ([issue 25364](https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=25364)). + +[Unreleased]: https://github.com/libsndfile/libsndfile/compare/1.2.2...HEAD +[1.2.2]: https://github.com/libsndfile/libsndfile/compare/1.2.1...1.2.2 +[1.2.1]: https://github.com/libsndfile/libsndfile/compare/1.2.0...1.2.1 +[1.2.0]: https://github.com/libsndfile/libsndfile/compare/1.1.0...1.2.0 +[1.1.0]: https://github.com/libsndfile/libsndfile/compare/1.0.31...1.1.0 diff --git a/extern/libsndfile-modified/CMakeLists.txt b/extern/libsndfile-modified/CMakeLists.txt new file mode 100644 index 000000000..6245450bc --- /dev/null +++ b/extern/libsndfile-modified/CMakeLists.txt @@ -0,0 +1,1604 @@ +cmake_minimum_required (VERSION 3.1...3.18) + +# MSVC runtime library flags are selected by an abstraction, CMake >= 3.15 +# This policy still need to be set even with cmake_minimum_required() command above. +if (POLICY CMP0091) + if ((DEFINED ENABLE_STATIC_RUNTIME) AND (DEFINED CMAKE_MSVC_RUNTIME_LIBRARY)) + message (FATAL_ERROR "Both ENABLE_STATIC_RUNTIME and CMAKE_MSVC_RUNTIME_LIBRARY are set.") + return () + endif () + + if (DEFINED CMAKE_MSVC_RUNTIME_LIBRARY) + cmake_policy (SET CMP0091 NEW) + else () + cmake_policy (SET CMP0091 OLD) + endif () +endif () + +option (ENABLE_EXTERNAL_LIBS "Enable FLAC, Vorbis, and Opus codecs" ON) +if (ENABLE_EXTERNAL_LIBS) + list (APPEND VCPKG_MANIFEST_FEATURES "external-libs") +endif () + +option (ENABLE_MPEG "Enable MPEG codecs" ON) +if (ENABLE_MPEG) + list (APPEND VCPKG_MANIFEST_FEATURES "mpeg") +endif () + +option (ENABLE_EXPERIMENTAL "Enable experimental code" OFF) +if (ENABLE_EXPERIMENTAL) + list (APPEND VCPKG_MANIFEST_FEATURES "speex") +endif () + +option (BUILD_REGTEST "Build regtest" OFF) +if (BUILD_REGTEST) + list (APPEND VCPKG_MANIFEST_FEATURES "regtest") +endif () + +project(libsndfile VERSION 1.2.2) + +# +# Variables +# + +set (CMAKE_C_STANDARD 99) +set (CMAKE_C_STANDARD_REQUIRED TRUE) +set_property(GLOBAL PROPERTY USE_FOLDERS ON) + +set (PACKAGE_NAME ${PROJECT_NAME}) +set (CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR}) +set (CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR}) +set (CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH}) +set (CPACK_PACKAGE_VERSION_STAGE "") +set (CPACK_PACKAGE_VERSION_FULL "${PROJECT_VERSION}${CPACK_PACKAGE_VERSION_STAGE}") + +# +# System-wide includes +# + +include (GNUInstallDirs) +include (FeatureSummary) +include (CMakeDependentOption) +include (CTest) +include (CheckCCompilerFlag) + +# +# Options +# + +option (BUILD_SHARED_LIBS "Build shared libraries" OFF) +if (BUILD_SHARED_LIBS AND BUILD_TESTING) + set (BUILD_TESTING OFF) + message ("Build testing required static libraries. To prevent build errors BUILD_TESTING disabled.") +endif () +option (BUILD_PROGRAMS "Build programs" ON) +option (BUILD_EXAMPLES "Build examples" ON) +option (ENABLE_CPACK "Enable CPack support" ON) +option (ENABLE_BOW_DOCS "Enable black-on-white html docs" OFF) +if (MSVC AND (DEFINED ENABLE_STATIC_RUNTIME)) + option (ENABLE_STATIC_RUNTIME "Enable static runtime" ${ENABLE_STATIC_RUNTIME}) +elseif (MINGW) + option (ENABLE_STATIC_RUNTIME "Enable static runtime" OFF) +endif () +option (ENABLE_PACKAGE_CONFIG "Generate and install package config file" ON) +option (INSTALL_PKGCONFIG_MODULE "Generate and install pkg-config module" ON) + +list (APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") +if (CMAKE_VERSION VERSION_LESS 3.14) + list (APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/sqlite") +endif () + +# +# Setup definitions +# + +include(SndFileChecks) + +if (ENABLE_EXTERNAL_LIBS AND NOT (Vorbis_FOUND OR FLAC_FOUND OR OPUS_FOUND)) + set (ENABLE_EXTERNAL_LIBS OFF) +endif() +if(ENABLE_MPEG AND (NOT HAVE_MPEG_LIBS)) + set (ENABLE_MPEG OFF) +endif() +if (BUILD_REGTEST AND (NOT SQLITE3_FOUND)) + set (BUILD_REGTEST OFF) +endif() + +cmake_dependent_option (ENABLE_CPU_CLIP "Enable tricky cpu specific clipper" ON "CPU_CLIPS_POSITIVE;CPU_CLIPS_NEGATIVE" OFF) +if (NOT ENABLE_CPU_CLIP) + set (CPU_CLIPS_POSITIVE FALSE) + set (CPU_CLIPS_NEGATIVE FALSE) +endif () +cmake_dependent_option (ENABLE_COMPATIBLE_LIBSNDFILE_NAME "Set DLL name to libsndfile-1.dll (canonical name), sndfile.dll otherwise" OFF "WIN32;BUILD_SHARED_LIBS" OFF) +cmake_dependent_option (INSTALL_MANPAGES "Install man pages for programs" ON "BUILD_PROGRAMS" OFF) + +if (NOT MSVC) + if (CPU_IS_X86) + check_c_compiler_flag (-msse2 HAVE_MSSE2_COMPILER_FLAG) + if (HAVE_MSSE2_COMPILER_FLAG) + cmake_dependent_option (ENABLE_SSE2 "Add SSE2 compiler flag" ON "HAVE_MSSE2_COMPILER_FLAG" OFF) + endif () + endif () +endif () +if (ENABLE_SSE2) + add_compile_options (-msse2) +endif () + +set (HAVE_EXTERNAL_XIPH_LIBS ${ENABLE_EXTERNAL_LIBS}) +set (HAVE_SQLITE3 ${BUILD_REGTEST}) +set (HAVE_ALSA_ASOUNDLIB_H ${ALSA_FOUND}) +set (HAVE_SNDIO_H ${SNDIO_FOUND}) + +set (ENABLE_EXPERIMENTAL_CODE ${ENABLE_EXPERIMENTAL}) +set (HAVE_MPEG ${ENABLE_MPEG}) +set (HAVE_SPEEX ${ENABLE_EXPERIMENTAL}) + +add_feature_info (BUILD_SHARED_LIBS BUILD_SHARED_LIBS "build shared libraries") +add_feature_info (ENABLE_EXTERNAL_LIBS ENABLE_EXTERNAL_LIBS "enable FLAC, Vorbis, and Opus codecs") +add_feature_info (ENABLE_MPEG ENABLE_MPEG "enable MPEG audio (including mp3) codecs") +add_feature_info (ENABLE_EXPERIMENTAL ENABLE_EXPERIMENTAL "enable experimental code") +add_feature_info (BUILD_TESTING BUILD_TESTING "build tests") +add_feature_info (BUILD_REGTEST BUILD_REGTEST "build regtest") +add_feature_info (ENABLE_CPACK ENABLE_CPACK "enable CPack support") +add_feature_info (ENABLE_CPU_CLIP ENABLE_CPU_CLIP "Enable tricky cpu specific clipper") +add_feature_info (ENABLE_BOW_DOCS ENABLE_BOW_DOCS "enable black-on-white html docs") +add_feature_info (ENABLE_PACKAGE_CONFIG ENABLE_PACKAGE_CONFIG "generate and install package config file") +add_feature_info (INSTALL_PKGCONFIG_MODULE INSTALL_PKGCONFIG_MODULE "generate and install pkg-config module") +add_feature_info (INSTALL_MANPAGES INSTALL_MANPAGES "install man pages for programs") +if (WIN32 AND BUILD_SHARED_LIBS) + add_feature_info (ENABLE_COMPATIBLE_LIBSNDFILE_NAME ENABLE_COMPATIBLE_LIBSNDFILE_NAME "Set DLL name to libsndfile-1.dll (canonical name), sndfile.dll otherwise") +endif () + +if (HAVE_MSSE2_COMPILER_FLAG) + add_feature_info (ENABLE_SSE2 ENABLE_SSE2 "add SSE2 compiler flag") +endif () + + + + +set_package_properties (Ogg PROPERTIES + TYPE RECOMMENDED + URL "www.xiph.org/ogg/" + DESCRIPTION "library for manipulating ogg bitstreams" + PURPOSE "Required to enable Vorbis, Speex, and Opus support" + ) +set_package_properties (Vorbis PROPERTIES + TYPE RECOMMENDED + URL "www.vorbis.com/" + DESCRIPTION "open source lossy audio codec" + PURPOSE "Enables Vorbis support" + ) +set_package_properties (FLAC PROPERTIES + TYPE RECOMMENDED + URL "www.xiph.org/flac/" + DESCRIPTION "Free Lossless Audio Codec Library" + PURPOSE "Enables FLAC support" + ) +set_package_properties (mp3lame PROPERTIES + TYPE RECOMMENDED + URL "https://lame.sourceforge.io/" + DESCRIPTION "High quality MPEG Audio Layer III (MP3) encoder" + PURPOSE "Enables MPEG layer III (MP3) writing support" + ) +set_package_properties (mpg123 PROPERTIES + TYPE RECOMMENDED + URL "https://www.mpg123.de/" + DESCRIPTION "MPEG Audio Layer I/II/III decoder" + PURPOSE "Enables MPEG Audio reading support" + ) +set_package_properties(Opus PROPERTIES + TYPE RECOMMENDED + URL "www.opus-codec.org/" + DESCRIPTION "Standardized open source low-latency fullband codec" + PURPOSE "Enables experimental Opus support" + ) +set_package_properties(Speex PROPERTIES TYPE OPTIONAL + URL "www.speex.org/" + DESCRIPTION "an audio codec tuned for speech" + PURPOSE "Enables experemental Speex support" + ) +set_package_properties (SQLite3 PROPERTIES + TYPE OPTIONAL + URL "www.sqlite.org/" + DESCRIPTION "light weight SQL database engine." + PURPOSE "Enables regtest" + ) +if (BUILD_SHARED_LIBS) + set_package_properties (PythonInterp PROPERTIES + TYPE REQUIRED + URL "www.python.org/" + DESCRIPTION "Python is a widely used high-level programming language." + PURPOSE "Required to build shared libraries" + ) +endif() + +feature_summary (WHAT ALL) + +# +# Setup configuration +# + +configure_file (src/config.h.cmake src/config.h) + +if (INSTALL_PKGCONFIG_MODULE) + + set (prefix ${CMAKE_INSTALL_PREFIX}) + set (exec_prefix "\$\{prefix\}") + set (libdir "${CMAKE_INSTALL_FULL_LIBDIR}") + set (includedir "${CMAKE_INSTALL_FULL_INCLUDEDIR}") + set (VERSION ${PROJECT_VERSION}) + if (ENABLE_EXTERNAL_LIBS) + set (EXTERNAL_XIPH_REQUIRE "flac ogg vorbis vorbisenc opus") + if (ENABLE_EXPERIMENTAL) + set (EXTERNAL_XIPH_REQUIRE "${EXTERNAL_XIPH_REQUIRE} speex") + endif () + endif () + if (ENABLE_MPEG) + set (EXTERNAL_MPEG_REQUIRE "libmpg123") + set (EXTERNAL_MPEG_LIBS "-lmp3lame") + endif () + + configure_file (sndfile.pc.in sndfile.pc @ONLY) + +endif () + +# +# libsndfile +# + +# Public libsndfile headers +set (sndfile_HDRS + include/sndfile.h + include/sndfile.hh + ) + +# +# libsndfile static library +# + +add_library (sndfile + src/sfconfig.h + src/sfendian.h + src/sf_unistd.h + src/common.h + src/common.c + src/file_io.c + src/command.c + src/pcm.c + src/ulaw.c + src/alaw.c + src/float32.c + src/double64.c + src/ima_adpcm.c + src/ms_adpcm.c + src/gsm610.c + src/dwvw.c + src/vox_adpcm.c + src/interleave.c + src/strings.c + src/dither.c + src/cart.c + src/broadcast.c + src/audio_detect.c + src/ima_oki_adpcm.c + src/ima_oki_adpcm.h + src/alac.c + src/chunk.c + src/ogg.h + src/ogg.c + src/chanmap.h + src/chanmap.c + src/id3.h + src/id3.c + $<$:src/windows.c> + src/sndfile.c + src/aiff.c + src/au.c + src/avr.c + src/caf.c + src/dwd.c + src/flac.c + src/g72x.c + src/htk.c + src/ircam.c + src/macos.c + src/mat4.c + src/mat5.c + src/nist.c + src/paf.c + src/pvf.c + src/raw.c + src/rx2.c + src/sd2.c + src/sds.c + src/svx.c + src/txw.c + src/voc.c + src/wve.c + src/w64.c + src/wavlike.h + src/wavlike.c + src/wav.c + src/xi.c + src/mpc2k.c + src/rf64.c + src/ogg_vorbis.c + src/ogg_speex.c + src/ogg_pcm.c + src/ogg_opus.c + src/ogg_vcomment.h + src/ogg_vcomment.c + src/nms_adpcm.c + src/mpeg.c + src/mpeg_decode.c + src/mpeg_l3_encode.c + src/GSM610/config.h + src/GSM610/gsm.h + src/GSM610/gsm610_priv.h + src/GSM610/add.c + src/GSM610/code.c + src/GSM610/decode.c + src/GSM610/gsm_create.c + src/GSM610/gsm_decode.c + src/GSM610/gsm_destroy.c + src/GSM610/gsm_encode.c + src/GSM610/gsm_option.c + src/GSM610/long_term.c + src/GSM610/lpc.c + src/GSM610/preprocess.c + src/GSM610/rpe.c + src/GSM610/short_term.c + src/GSM610/table.c + src/G72x/g72x.h + src/G72x/g72x_priv.h + src/G72x/g721.c + src/G72x/g723_16.c + src/G72x/g723_24.c + src/G72x/g723_40.c + src/G72x/g72x.c + src/ALAC/ALACAudioTypes.h + src/ALAC/ALACBitUtilities.h + src/ALAC/EndianPortable.h + src/ALAC/aglib.h + src/ALAC/dplib.h + src/ALAC/matrixlib.h + src/ALAC/alac_codec.h + src/ALAC/shift.h + src/ALAC/ALACBitUtilities.c + src/ALAC/ag_dec.c + src/ALAC/ag_enc.c + src/ALAC/dp_dec.c + src/ALAC/dp_enc.c + src/ALAC/matrix_dec.c + src/ALAC/matrix_enc.c + src/ALAC/alac_decoder.c + src/ALAC/alac_encoder.c + ${sndfile_HDRS} + ${CMAKE_CURRENT_BINARY_DIR}/src/config.h + ) + +add_library (SndFile::sndfile ALIAS sndfile) + +target_include_directories (sndfile + PUBLIC + $ + $ + $ + PRIVATE + src + $ + ) +target_link_libraries (sndfile + PRIVATE + $<$:m> + $<$:Ogg::ogg> + $<$:Vorbis::vorbisenc> + $<$:FLAC::FLAC> + $<$,$,$>:Speex::Speex> + $<$:Opus::opus> + $<$:MPG123::libmpg123> + $<$:mp3lame::mp3lame> + ) +set_target_properties (sndfile PROPERTIES + PUBLIC_HEADER "${sndfile_HDRS}" + ) + +if (ENABLE_COMPATIBLE_LIBSNDFILE_NAME) + if (MINGW OR CYGWIN) + set_target_properties (sndfile PROPERTIES + RUNTIME_OUTPUT_NAME "sndfile-1" + ) + else () + set_target_properties (sndfile PROPERTIES + RUNTIME_OUTPUT_NAME "libsndfile-1" + ) + endif () +endif () + +if (BUILD_SHARED_LIBS) + + # + # ABI version of library. + # + + # + # Read libtool version from `configure.ac` and set libsndfile ABI version: + # + # SNDFILE_ABI_VERSION_MAJOR + # SNDFILE_ABI_VERSION_MINOR + # SNDFILE_ABI_VERSION_PATCH + # SNDFILE_ABI_VERSION + # + # and Mach-O current and compatibility versions: + # + # SNDFILE_MACHO_CURRENT_VERSION + # SNDFILE_MACHO_COMPATIBILITY_VERSION + # + + include (SetupABIVersions) + + setup_abi_versions() + + if (WIN32) + set (VERSION_MAJOR ${CPACK_PACKAGE_VERSION_MAJOR}) + set (GEN_TOOL cmake) + + set (WIN_RC_VERSION "${CPACK_PACKAGE_VERSION_MAJOR},${CPACK_PACKAGE_VERSION_MINOR},${CPACK_PACKAGE_VERSION_PATCH}") + set (CLEAN_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}") + set (PACKAGE_VERSION ${CPACK_PACKAGE_VERSION}) + + configure_file (src/version-metadata.rc.in src/version-metadata.rc @ONLY) + target_sources (sndfile PRIVATE ${PROJECT_BINARY_DIR}/src/version-metadata.rc) + endif () + + + set_target_properties (sndfile PROPERTIES + SOVERSION ${SNDFILE_ABI_VERSION_MAJOR} + VERSION ${SNDFILE_ABI_VERSION} + ) + + if (APPLE) + if (NOT (CMAKE_VERSION VERSION_LESS 3.17)) + set_target_properties (sndfile PROPERTIES + MACHO_CURRENT_VERSION ${SNDFILE_MACHO_CURRENT_VERSION} + MACHO_COMPATIBILITY_VERSION ${SNDFILE_MACHO_COMPATIBILITY_VERSION} + ) + else () + message (FATAL_ERROR "Apple platform requires cmake >= 3.17 to build dylib.") + endif () + endif () + + # Symbol files generation + + if (WIN32) + set (SYMBOL_FILENAME "sndfile.def") + set (SYMBOL_OS "win32") + elseif ((CMAKE_SYSTEM_NAME MATCHES "Darwin") OR (CMAKE_SYSTEM_NAME MATCHES "Rhapsody")) + set (SYMBOL_FILENAME "Symbols.darwin") + set (SYMBOL_OS "darwin") + elseif (CMAKE_SYSTEM_NAME MATCHES "OS2") + set (SYMBOL_FILENAME "Symbols.os2") + set (SYMBOL_OS "os2") + elseif (UNIX) + set (SYMBOL_FILENAME "Symbols.gnu-binutils") + set (SYMBOL_OS "linux") + endif () + + if (DEFINED SYMBOL_OS) + add_custom_command ( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/src/${SYMBOL_FILENAME} + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/src/create_symbols_file.py ${SYMBOL_OS} ${SNDFILE_ABI_VERSION} > ${CMAKE_CURRENT_BINARY_DIR}/src/${SYMBOL_FILENAME} + COMMENT "Generating ${SYMBOL_FILENAME}..." + ) + + add_custom_target (GENFILES DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/src/${SYMBOL_FILENAME}) + if (SYMBOL_OS MATCHES "win32") + target_sources (sndfile + PRIVATE + ${CMAKE_CURRENT_BINARY_DIR}/src/${SYMBOL_FILENAME} + ) + elseif (SYMBOL_OS MATCHES "darwin") + add_dependencies (sndfile GENFILES) + if (CMAKE_VERSION VERSION_LESS 3.13) + set_property (TARGET sndfile APPEND_STRING PROPERTY + LINK_FLAGS "-Wl,-exported_symbols_list -Wl,${CMAKE_CURRENT_BINARY_DIR}/src/${SYMBOL_FILENAME}" + ) + else () + target_link_options (sndfile PRIVATE "LINKER:-exported_symbols_list,${CMAKE_CURRENT_BINARY_DIR}/src/${SYMBOL_FILENAME}") + endif() + elseif (SYMBOL_OS MATCHES "os") + add_dependencies (sndfile GENFILES) + if (CMAKE_VERSION VERSION_LESS 3.13) + set_property (TARGET sndfile APPEND_STRING PROPERTY + LINK_FLAGS "-Wl,-export-symbols ${CMAKE_CURRENT_BINARY_DIR}/src/${SYMBOL_FILENAME}" + ) + else () + target_link_options (sndfile PRIVATE "LINKER:-export-symbols ${CMAKE_CURRENT_BINARY_DIR}/src/${SYMBOL_FILENAME}") + endif() + elseif (UNIX) + add_dependencies (sndfile GENFILES) + if (CMAKE_VERSION VERSION_LESS 3.13) + set_property (TARGET sndfile APPEND_STRING PROPERTY + LINK_FLAGS "-Wl,--version-script,${CMAKE_CURRENT_BINARY_DIR}/src/${SYMBOL_FILENAME}" + ) + else () + target_link_options (sndfile PRIVATE "LINKER:--version-script,${CMAKE_CURRENT_BINARY_DIR}/src/${SYMBOL_FILENAME}") + endif() + endif() + endif() + +endif () + +# +# Programs +# + +if (BUILD_PROGRAMS) + +# sndfile-info + + add_executable (sndfile-info + programs/sndfile-info.c + programs/common.c + programs/common.h + ) + target_link_libraries (sndfile-info + PRIVATE + sndfile + $<$:m> + ) + +# sndfile-play + + add_executable (sndfile-play + $<$>:programs/sndfile-play.c> + $<$>:programs/common.c> + $<$>:programs/sndfile-play.c> + $<$:programs/sndfile-play-beos.cpp> + ) + target_include_directories (sndfile-play + PRIVATE + src + ${CMAKE_CURRENT_BINARY_DIR}/src + ) + target_link_libraries (sndfile-play PRIVATE $<$:m>) + target_link_libraries (sndfile-play PRIVATE sndfile) + if (WIN32) + target_link_libraries(sndfile-play PRIVATE winmm) + # Maybe ALSA & Sndio are present in BeOS. They are not required + # so skip them anyway. + elseif ((NOT BEOS) AND ALSA_FOUND) + target_include_directories (sndfile-play PRIVATE ${ALSA_INCLUDE_DIRS}) + target_link_libraries (sndfile-play PRIVATE ${ALSA_LIBRARIES}) + elseif (CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") + target_link_libraries (sndfile-play PRIVATE Sndio::Sndio) + endif () + +# sndfile-convert + + add_executable (sndfile-convert + programs/sndfile-convert.c + programs/common.c + programs/common.h + ) + target_link_libraries (sndfile-convert PRIVATE sndfile $<$:m>) + +# sndfile-cmp + + add_executable (sndfile-cmp + programs/sndfile-cmp.c + programs/common.c + programs/common.h + ) + target_include_directories (sndfile-cmp + PUBLIC + src + ${CMAKE_CURRENT_BINARY_DIR}/src + ${CMAKE_CURRENT_BINARY_DIR}/tests + ) + target_link_libraries (sndfile-cmp PRIVATE sndfile $<$:m>) + +# sndfile-metadata-set + + add_executable (sndfile-metadata-set + programs/sndfile-metadata-set.c + programs/common.c + programs/common.h + ) + target_include_directories (sndfile-metadata-set + PUBLIC + src + ${CMAKE_CURRENT_BINARY_DIR}/src + ${CMAKE_CURRENT_BINARY_DIR}/tests + ) + target_link_libraries (sndfile-metadata-set PRIVATE sndfile $<$:m>) + +# sndfile-metadata-get + + add_executable (sndfile-metadata-get + programs/sndfile-metadata-get.c + programs/common.c + programs/common.h + ) + target_include_directories (sndfile-metadata-get + PUBLIC + src + ${CMAKE_CURRENT_BINARY_DIR}/src + ${CMAKE_CURRENT_BINARY_DIR}/tests + ) + target_link_libraries (sndfile-metadata-get PRIVATE sndfile $<$:m>) + +# sndfile-interleave + + add_executable (sndfile-interleave + programs/sndfile-interleave.c + programs/common.c + programs/common.h + ) + target_link_libraries (sndfile-interleave PRIVATE sndfile $<$:m>) + +# sndfile-deinterleave + + add_executable (sndfile-deinterleave + programs/sndfile-deinterleave.c + programs/common.c + programs/common.h + ) + target_link_libraries (sndfile-deinterleave PRIVATE sndfile $<$:m>) + +# sndfile-concat + + add_executable (sndfile-concat + programs/sndfile-concat.c + programs/common.c + programs/common.h + ) + target_link_libraries (sndfile-concat PRIVATE sndfile $<$:m>) + +# sndfile-salvage + + add_executable (sndfile-salvage + programs/sndfile-salvage.c + programs/common.c + programs/common.h + ) + target_include_directories (sndfile-salvage + PUBLIC + src + ${CMAKE_CURRENT_BINARY_DIR}/src + ${CMAKE_CURRENT_BINARY_DIR}/tests + ) + target_link_libraries (sndfile-salvage PRIVATE sndfile $<$:m>) + + set (SNDFILE_PROGRAM_TARGETS + sndfile-info + sndfile-play + sndfile-convert + sndfile-cmp + sndfile-metadata-set + sndfile-metadata-get + sndfile-interleave + sndfile-deinterleave + sndfile-concat + sndfile-salvage + ) + + set_target_properties(${SNDFILE_PROGRAM_TARGETS} PROPERTIES FOLDER Programs) + +endif () + +# +# Examples +# + +if (BUILD_EXAMPLES) + +# sndfile-to-text + + add_executable (sndfile-to-text examples/sndfile-to-text.c) + target_link_libraries (sndfile-to-text PRIVATE sndfile) + +# sndfile-loopify + + add_executable (sndfile-loopify examples/sndfile-loopify.c) + target_link_libraries (sndfile-loopify PRIVATE sndfile) + +# make_sine + + add_executable (make_sine examples/make_sine.c) + target_link_libraries (make_sine + PRIVATE + sndfile + $<$:m> + ) + +# sfprocess + + add_executable (sfprocess examples/sfprocess.c) + target_link_libraries (sfprocess + PRIVATE + sndfile + $<$:m> + ) + +# list_formats + + add_executable (list_formats examples/list_formats.c) + target_link_libraries (list_formats + PRIVATE + sndfile + $<$:m> + ) + +# generate + + add_executable (generate examples/generate.c) + target_link_libraries (generate PRIVATE sndfile) + +# sndfilehandle + + add_executable (sndfilehandle examples/sndfilehandle.cc) + target_link_libraries (sndfilehandle PUBLIC sndfile) + + set (SNDFILE_EXAMPLE_TARGETS + sndfile-to-text + sndfile-loopify + make_sine + sfprocess + list_formats + generate + sndfilehandle + ) + + set_target_properties(${SNDFILE_EXAMPLE_TARGETS} PROPERTIES FOLDER Examples) + + +endif () + +# +# sndfile-regtest +# + +if (BUILD_REGTEST) + + add_executable (sndfile-regtest + regtest/sndfile-regtest.c + regtest/database.c + regtest/checksum.c + ) + target_include_directories (sndfile-regtest + PUBLIC + src + ${CMAKE_CURRENT_BINARY_DIR}/src + ${CMAKE_CURRENT_BINARY_DIR}/tests + ) + target_link_libraries(sndfile-regtest + PRIVATE + sndfile + SQLite::SQLite3 + $<$:m> + ) + +endif () + +# +# Installation +# + +if (ENABLE_PACKAGE_CONFIG) + + if (WIN32 AND (NOT MINGW) AND (NOT CYGWIN)) + set (CMAKE_INSTALL_PACKAGEDIR cmake) + else () + set (CMAKE_INSTALL_PACKAGEDIR ${CMAKE_INSTALL_LIBDIR}/cmake/SndFile) + endif() + + install (TARGETS ${SNDFILE_PROGRAM_TARGETS} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ) + + install (TARGETS sndfile + EXPORT SndFileTargets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + ) + + export (EXPORT SndFileTargets NAMESPACE SndFile:: FILE ${PROJECT_BINARY_DIR}/SndFileTargets.cmake) + + include (CMakePackageConfigHelpers) + + if (ENABLE_EXTERNAL_LIBS) + set (SndFile_WITH_EXTERNAL_LIBS 1) + list (APPEND FIND_MODULES_INSTALL_LIST + ${CMAKE_CURRENT_LIST_DIR}/cmake/FindFLAC.cmake + ${CMAKE_CURRENT_LIST_DIR}/cmake/FindOgg.cmake + ${CMAKE_CURRENT_LIST_DIR}/cmake/FindOpus.cmake + ${CMAKE_CURRENT_LIST_DIR}/cmake/FindVorbis.cmake) + else () + set (SndFile_WITH_EXTERNAL_LIBS 0) + endif () + + if(ENABLE_MPEG) + set (SndFile_WITH_MPEG 1) + list (APPEND FIND_MODULES_INSTALL_LIST + ${CMAKE_CURRENT_LIST_DIR}/cmake/Findmpg123.cmake + ${CMAKE_CURRENT_LIST_DIR}/cmake/Findmp3lame.cmake) + else () + set (SndFile_WITH_MPEG 0) + endif () + + set (INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR}) + configure_package_config_file(cmake/SndFileConfig.cmake.in SndFileConfig.cmake + INSTALL_DESTINATION ${PROJECT_BINARY_DIR} + INSTALL_PREFIX ${PROJECT_BINARY_DIR} + PATH_VARS INCLUDE_INSTALL_DIR + ) + configure_package_config_file(cmake/SndFileConfig.cmake.in SndFileConfig2.cmake + INSTALL_DESTINATION ${CMAKE_INSTALL_PACKAGEDIR} + PATH_VARS INCLUDE_INSTALL_DIR + ) + write_basic_package_version_file (SndFileConfigVersion.cmake COMPATIBILITY SameMajorVersion) + + install(EXPORT SndFileTargets + NAMESPACE SndFile:: + DESTINATION ${CMAKE_INSTALL_PACKAGEDIR} + ) + install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/SndFileConfig2.cmake + RENAME SndFileConfig.cmake + DESTINATION ${CMAKE_INSTALL_PACKAGEDIR} + ) + install( + FILES + ${CMAKE_CURRENT_BINARY_DIR}/SndFileConfigVersion.cmake + DESTINATION ${CMAKE_INSTALL_PACKAGEDIR} + ) + + if (NOT BUILD_SHARED_LIBS AND FIND_MODULES_INSTALL_LIST) + file(COPY ${FIND_MODULES_INSTALL_LIST} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) + install(FILES ${FIND_MODULES_INSTALL_LIST} DESTINATION ${CMAKE_INSTALL_PACKAGEDIR}) + endif () +else () + + install (TARGETS sndfile ${sdnfile_PROGRAMS} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + +endif () + +if (INSTALL_MANPAGES) + + set (man_MANS + man/sndfile-info.1 + man/sndfile-play.1 + man/sndfile-convert.1 + man/sndfile-cmp.1 + man/sndfile-metadata-get.1 + man/sndfile-concat.1 + man/sndfile-interleave.1 + man/sndfile-salvage.1 + ) + install (FILES ${man_MANS} DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) + install (FILES man/sndfile-metadata-get.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 RENAME sndfile-metadata-set.1) + install (FILES man/sndfile-interleave.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 RENAME sndfile-deinterleave.1) +endif () + +if (ENABLE_BOW_DOCS) + set (HTML_BGCOLOUR "white") + set (HTML_FGCOLOUR "black") +else () + set (HTML_BGCOLOUR "black") + set (HTML_FGCOLOUR "white") +endif () +set (dist_doc_DATA + docs/index.md + docs/libsndfile.jpg + docs/libsndfile.css + docs/print.css + docs/api.md + docs/command.md + docs/bugs.md + docs/formats.md + docs/sndfile_info.md + docs/new_file_type_howto.md + docs/win32.md + docs/FAQ.md + docs/lists.md + docs/embedded_files.md + docs/octave.md + docs/tutorial.md + ) +install (FILES ${dist_doc_DATA} DESTINATION ${CMAKE_INSTALL_DOCDIR}) + +if (INSTALL_PKGCONFIG_MODULE) + install (FILES ${CMAKE_CURRENT_BINARY_DIR}/sndfile.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) +endif () + +# +# Testing +# + +if (BUILD_TESTING) + + enable_testing () + + include (CMakeAutoGen) + + # generate tests sources from autogen templates + lsf_autogen (tests benchmark c) + lsf_autogen (tests floating_point_test c) + lsf_autogen (tests header_test c) + lsf_autogen (tests pcm_test c) + lsf_autogen (tests pipe_test c) + lsf_autogen (tests rdwr_test c) + lsf_autogen (tests scale_clip_test c) + lsf_autogen (tests utils c h) + lsf_autogen (tests write_read_test c) + lsf_autogen (src test_endswap c) + + # utils static library + add_library(test_utils STATIC tests/utils.c) + target_include_directories (test_utils + PUBLIC + src + ${CMAKE_CURRENT_BINARY_DIR}/src + ${CMAKE_CURRENT_BINARY_DIR}/tests + ) + target_link_libraries(test_utils PRIVATE sndfile) + + ### test_main + + add_executable (test_main + src/test_main.c + src/test_main.h + src/test_conversions.c + src/test_float.c + src/test_endswap.c + src/test_audio_detect.c + src/test_log_printf.c + src/test_file_io.c + src/test_ima_oki_adpcm.c + src/test_strncpy_crlf.c + src/test_broadcast_var.c + src/test_cart_var.c + src/test_binheader_writef.c + src/test_nms_adpcm.c + ) + target_include_directories (test_main + PUBLIC + src + ${CMAKE_CURRENT_BINARY_DIR}/src + ${CMAKE_CURRENT_BINARY_DIR}/tests + ) + target_link_libraries (test_main PRIVATE sndfile) + if (MSVC) + target_compile_definitions (test_main PRIVATE _USE_MATH_DEFINES) + endif () + add_test (test_main test_main) + + ### sfversion_test + + add_executable (sfversion tests/sfversion.c) + target_include_directories (sfversion + PRIVATE + src + ${CMAKE_CURRENT_BINARY_DIR}/src + ) + target_link_libraries (sfversion sndfile) + add_test (sfversion sfversion) + set_tests_properties (sfversion PROPERTIES + PASS_REGULAR_EXPRESSION "${PACKAGE_NAME}-${CPACK_PACKAGE_VERSION_FULL}" + ) + + ### error_test + + add_executable (error_test tests/error_test.c) + target_link_libraries (error_test + PRIVATE + sndfile + test_utils + $<$:m> + ) + add_test (error_test error_test) + + ### ulaw_test + add_executable (ulaw_test tests/ulaw_test.c) + target_link_libraries (ulaw_test + PRIVATE + sndfile + test_utils + $<$:m> + ) + add_test (ulaw_test ulaw_test) + + ### alaw_test + add_executable (alaw_test tests/alaw_test.c) + target_link_libraries (alaw_test + PRIVATE + sndfile + test_utils + $<$:m> + ) + add_test (alaw_test alaw_test) + + ### dwvw_test + + add_executable (dwvw_test tests/dwvw_test.c) + target_link_libraries (dwvw_test + PRIVATE + sndfile + test_utils + $<$:m> + ) + add_test (dwvw_test dwvw_test) + + ### command_test + + add_executable (command_test tests/command_test.c) + target_link_libraries (command_test + PRIVATE + sndfile + test_utils + $<$:m> + ) + add_test (command_test command_test all) + + ### floating_point_test + + add_executable (floating_point_test + tests/dft_cmp.c + tests/floating_point_test.c + ) + target_link_libraries (floating_point_test + PRIVATE + sndfile + test_utils + $<$:m> + ) + target_include_directories (floating_point_test PRIVATE tests) + add_test (floating_point_test floating_point_test) + + ### checksum_test + + add_executable (checksum_test tests/checksum_test.c) + target_link_libraries (checksum_test + PRIVATE + sndfile + test_utils + $<$:m> + ) + add_test (checksum_test checksum_test) + + ### scale_clip_test + + add_executable (scale_clip_test tests/scale_clip_test.c) + target_link_libraries (scale_clip_test + PRIVATE + sndfile + test_utils + $<$:m> + ) + add_test (scale_clip_test scale_clip_test) + + ### headerless_test + + add_executable (headerless_test tests/headerless_test.c) + target_link_libraries (headerless_test + PRIVATE + sndfile + test_utils + $<$:m> + ) + add_test (headerless_test headerless_test) + + ### rdwr_test + + add_executable (rdwr_test tests/rdwr_test.c) + target_link_libraries (rdwr_test + PRIVATE + sndfile + test_utils + $<$:m> + ) + add_test (rdwr_test rdwr_test) + + ### locale_test + + add_executable (locale_test tests/locale_test.c) + target_link_libraries (locale_test + PRIVATE + sndfile + test_utils + $<$:m> + ) + add_test (locale_test locale_test) + + ### win32_ordinal_test + +# Disabled because we cannot test with shared sndfile library +# if (WIN32 AND BUILD_SHARED_LIBS) +# add_executable (win32_ordinal_test tests/win32_ordinal_test.c) +# target_link_libraries (win32_ordinal_test PRIVATE sndfile test_utils) +# add_test (win32_ordinal_test win32_ordinal_test) +# endif () + + ### cpp_test + + add_executable (cpp_test tests/cpp_test.cc) + target_link_libraries (cpp_test + PRIVATE + sndfile + test_utils + $<$:m> + ) + add_test (cpp_test cpp_test) + + ### external_libs_test + + add_executable (external_libs_test tests/external_libs_test.c) + target_link_libraries (external_libs_test + PRIVATE + sndfile + test_utils + $<$:m> + ) + add_test (external_libs_test external_libs_test) + + ### format_check_test + + add_executable (format_check_test tests/format_check_test.c) + target_link_libraries (format_check_test + PRIVATE + sndfile + test_utils + $<$:m> + ) + add_test (format_check_test format_check_test) + + ### channel_test + + add_executable (channel_test tests/channel_test.c) + target_link_libraries (channel_test + PRIVATE + sndfile + test_utils + $<$:m> + ) + add_test (channel_test channel_test) + + ### pcm_test + + add_executable (pcm_test tests/pcm_test.c) + target_link_libraries (pcm_test + PRIVATE + sndfile + test_utils + $<$:m> + ) + add_test (pcm_test pcm_test) + + ### common test executables + + add_executable (write_read_test + tests/generate.c + tests/write_read_test.c + ) + target_link_libraries (write_read_test + PRIVATE + sndfile + test_utils + $<$:m> + ) + target_include_directories (write_read_test PRIVATE tests) + + add_executable (lossy_comp_test tests/lossy_comp_test.c) + target_link_libraries (lossy_comp_test + PRIVATE + sndfile + test_utils + $<$:m> + ) + + add_executable (peak_chunk_test tests/peak_chunk_test.c) + target_link_libraries (peak_chunk_test + PRIVATE + sndfile + test_utils + $<$:m> + ) + + add_executable (header_test tests/header_test.c) + target_link_libraries (header_test + PRIVATE + sndfile + test_utils + $<$:m> + ) + + add_executable (misc_test tests/misc_test.c) + target_link_libraries (misc_test + PRIVATE + sndfile + test_utils + $<$:m> + ) + + add_executable (string_test tests/string_test.c) + target_link_libraries (string_test + PRIVATE + sndfile + test_utils + $<$:m> + ) + + add_executable (multi_file_test tests/multi_file_test.c) + target_link_libraries (multi_file_test + PRIVATE + sndfile + test_utils + $<$:m> + ) + + add_executable (aiff_rw_test tests/aiff_rw_test.c) + target_link_libraries (aiff_rw_test + PRIVATE + sndfile + test_utils + $<$:m> + ) + + add_executable (chunk_test tests/chunk_test.c) + target_link_libraries (chunk_test + PRIVATE + sndfile + test_utils + $<$:m> + ) + + add_executable (long_read_write_test tests/long_read_write_test.c) + target_link_libraries (long_read_write_test + PRIVATE + sndfile + test_utils + $<$:m> + ) + + add_executable (raw_test tests/raw_test.c) + target_link_libraries (raw_test + PRIVATE + sndfile + test_utils + $<$:m> + ) + + add_executable (compression_size_test tests/compression_size_test.c) + target_link_libraries (compression_size_test + PRIVATE + sndfile + test_utils + $<$:m> + ) + + add_executable (ogg_test tests/ogg_test.c) + target_link_libraries (ogg_test + PRIVATE + sndfile + test_utils + $<$:m> + ) + + add_executable (ogg_opus_test tests/ogg_opus_test.c) + target_link_libraries (ogg_opus_test + PRIVATE + sndfile + test_utils + $<$:m> + ) + + add_executable (mpeg_test tests/mpeg_test.c) + target_link_libraries (mpeg_test + PRIVATE + sndfile + test_utils + $<$:m> + ) + + add_executable (stdin_test tests/stdin_test.c) + target_link_libraries (stdin_test + PRIVATE + sndfile + test_utils + $<$:m> + ) + set_target_properties (stdin_test PROPERTIES RUNTIME_OUTPUT_DIRECTORY "tests") + + add_executable (stdout_test tests/stdout_test.c) + target_link_libraries (stdout_test + PRIVATE + sndfile + test_utils + $<$:m> + ) + set_target_properties (stdout_test PROPERTIES RUNTIME_OUTPUT_DIRECTORY "tests") + + add_executable (stdio_test tests/stdio_test.c) + target_link_libraries (stdio_test + PRIVATE + sndfile + test_utils + $<$:m> + ) + + add_executable (pipe_test tests/pipe_test.c) + target_link_libraries (pipe_test + PRIVATE + sndfile + test_utils + $<$:m> + ) + + add_executable (virtual_io_test tests/virtual_io_test.c) + target_link_libraries (virtual_io_test + PRIVATE + sndfile + test_utils + $<$:m> + ) + + ### g72x_test + + add_executable (g72x_test src/G72x/g72x_test.c) + target_include_directories (g72x_test + PRIVATE + src + ${CMAKE_CURRENT_BINARY_DIR}/src + ) + target_link_libraries (g72x_test + PRIVATE + sndfile + $<$:m> + ) + add_test (g72x_test g72x_test all) + + ### aiff-tests + + add_test (write_read_test_aiff write_read_test aiff) + add_test (lossy_comp_test_aiff_ulaw lossy_comp_test aiff_ulaw) + add_test (lossy_comp_test_aiff_alaw lossy_comp_test aiff_alaw) + add_test (lossy_comp_test_aiff_gsm610 lossy_comp_test aiff_gsm610) + add_test (peak_chunk_test_aiff peak_chunk_test aiff) + add_test (header_test_aiff header_test aiff) + add_test (misc_test_aiff misc_test aiff) + add_test (string_test_aiff string_test aiff) + add_test (multi_file_test_aiff multi_file_test aiff) + add_test (aiff_rw_test aiff_rw_test) + + ### au-tests + + add_test (write_read_test_au write_read_test au) + add_test (lossy_comp_test_au_ulaw lossy_comp_test au_ulaw) + add_test (lossy_comp_test_au_alaw lossy_comp_test au_alaw) + add_test (lossy_comp_test_au_g721 lossy_comp_test au_g721) + add_test (lossy_comp_test_au_g723 lossy_comp_test au_g723) + add_test (header_test_au header_test au) + add_test (misc_test_au misc_test au) + add_test (multi_file_test_au multi_file_test au) + + ### caf-tests + + add_test (write_read_test_caf write_read_test caf) + add_test (lossy_comp_test_caf_ulaw lossy_comp_test caf_ulaw) + add_test (lossy_comp_test_caf_alaw lossy_comp_test caf_alaw) + add_test (header_test_caf header_test caf) + add_test (peak_chunk_test_caf peak_chunk_test caf) + add_test (misc_test_caf misc_test caf) + add_test (chunk_test_caf chunk_test caf) + add_test (string_test_caf string_test caf) + add_test (long_read_write_test_alac long_read_write_test alac) + + # wav-tests + add_test (write_read_test_wav write_read_test wav) + add_test (lossy_comp_test_wav_pcm lossy_comp_test wav_pcm) + add_test (lossy_comp_test_wav_ima lossy_comp_test wav_ima) + add_test (lossy_comp_test_wav_msadpcm lossy_comp_test wav_msadpcm) + add_test (lossy_comp_test_wav_ulaw lossy_comp_test wav_ulaw) + add_test (lossy_comp_test_wav_alaw lossy_comp_test wav_alaw) + add_test (lossy_comp_test_wav_gsm610 lossy_comp_test wav_gsm610) + add_test (lossy_comp_test_wav_g721 lossy_comp_test wav_g721) + add_test (lossy_comp_test_wav_nmsadpcm lossy_comp_test wav_nmsadpcm) + add_test (peak_chunk_test_wav peak_chunk_test wav) + add_test (header_test_wav header_test wav) + add_test (misc_test_wav misc_test wav) + add_test (string_test_wav string_test wav) + add_test (multi_file_test_wav multi_file_test wav) + add_test (chunk_test_wav chunk_test wav) + + ### w64-tests + + add_test (write_read_test_w64 write_read_test w64) + add_test (lossy_comp_test_w64_ima lossy_comp_test w64_ima) + add_test (lossy_comp_test_w64_msadpcm lossy_comp_test w64_msadpcm) + add_test (lossy_comp_test_w64_ulaw lossy_comp_test w64_ulaw) + add_test (lossy_comp_test_w64_alaw lossy_comp_test w64_alaw) + add_test (lossy_comp_test_w64_gsm610 lossy_comp_test w64_gsm610) + add_test (header_test_w64 header_test w64) + add_test (misc_test_w64 misc_test w64) + + ### rf64-tests + + add_test (write_read_test_rf64 write_read_test rf64) + add_test (header_test_rf64 header_test rf64) + add_test (misc_test_rf64 misc_test rf64) + add_test (string_test_rf64 string_test rf64) + add_test (peak_chunk_test_rf64 peak_chunk_test rf64) + add_test (chunk_test_rf64 chunk_test rf64) + + ### raw-tests + add_test (write_read_test_raw write_read_test raw) + add_test (lossy_comp_test_raw_ulaw lossy_comp_test raw_ulaw) + add_test (lossy_comp_test_raw_alaw lossy_comp_test raw_alaw) + add_test (lossy_comp_test_raw_gsm610 lossy_comp_test raw_gsm610) + add_test (lossy_comp_test_vox_adpcm lossy_comp_test vox_adpcm) + add_test (raw_test raw_test) + + ### paf-tests + add_test (write_read_test_paf write_read_test paf) + add_test (header_test_paf header_test paf) + add_test (misc_test_paf misc_test paf) + + ### svx-tests + add_test (write_read_test_svx write_read_test svx) + add_test (header_test_svx header_test svx) + add_test (misc_test_svx misc_test svx) + + ### nist-tests + add_test (write_read_test_nist write_read_test nist) + add_test (lossy_comp_test_nist_ulaw lossy_comp_test nist_ulaw) + add_test (lossy_comp_test_nist_alaw lossy_comp_test nist_alaw) + add_test (header_test_nist header_test nist) + add_test (misc_test_nist misc_test nist) + + ### ircam-tests + add_test (write_read_test_ircam write_read_test ircam) + add_test (lossy_comp_test_ircam_ulaw lossy_comp_test ircam_ulaw) + add_test (lossy_comp_test_ircam_alaw lossy_comp_test ircam_alaw) + add_test (header_test_ircam header_test ircam) + add_test (misc_test_ircam misc_test ircam) + + ### voc-tests + add_test (write_read_test_voc write_read_test voc) + add_test (lossy_comp_test_voc_ulaw lossy_comp_test voc_ulaw) + add_test (lossy_comp_test_voc_alaw lossy_comp_test voc_alaw) + add_test (header_test_voc header_test voc) + add_test (misc_test_voc misc_test voc) + + ### mat4-tests + add_test (write_read_test_mat4 write_read_test mat4) + add_test (header_test_mat4 header_test mat4) + add_test (misc_test_mat4 misc_test mat4) + + ### mat5-tests + add_test (write_read_test_mat5 write_read_test mat5) + add_test (header_test_mat5 header_test mat5) + add_test (misc_test_mat5 misc_test mat5) + + ### pvf-tests + add_test (write_read_test_pvf write_read_test pvf) + add_test (header_test_pvf header_test pvf) + add_test (misc_test_pvf misc_test pvf) + + ### xi-tests + add_test (lossy_comp_test_xi_dpcm lossy_comp_test xi_dpcm) + + ### htk-tests + add_test (write_read_test_htk write_read_test htk) + add_test (header_test_htk header_test htk) + add_test (misc_test_htk misc_test htk) + + ### avr-tests + add_test (write_read_test_avr write_read_test avr) + add_test (header_test_avr header_test avr) + add_test (misc_test_avr misc_test avr) + + ### sds-tests + add_test (write_read_test_sds write_read_test sds) + add_test (header_test_sds header_test sds) + add_test (misc_test_sds misc_test sds) + + # sd2-tests + add_test (write_read_test_sd2 write_read_test sd2) + + ### wve-tests + add_test (lossy_comp_test_wve lossy_comp_test wve) + + ### mpc2k-tests + add_test (write_read_test_mpc2k write_read_test mpc2k) + add_test (header_test_mpc2k header_test mpc2k) + add_test (misc_test_mpc2k misc_test mpc2k) + + ### flac-tests + add_test (write_read_test_flac write_read_test flac) + add_test (compression_size_test_flac compression_size_test flac) + add_test (string_test_flac string_test flac) + + ### vorbis-tests + add_test (ogg_test ogg_test) + add_test (compression_size_test_vorbis compression_size_test vorbis) + add_test (lossy_comp_test_ogg_vorbis lossy_comp_test ogg_vorbis) + add_test (string_test_ogg string_test ogg) + add_test (misc_test_ogg misc_test ogg) + + ### opus-tests ### + add_test (ogg_opus_test ogg_opus_test) + add_test (compression_size_test_opus compression_size_test opus) + add_test (lossy_comp_test_ogg_opus lossy_comp_test ogg_opus) + add_test (string_test_opus string_test opus) + + ### mpeg-tests ### + add_test (mpeg_test mpeg_test) + add_test (compression_size_test_mpeg compression_size_test mpeg) + + ### io-tests + add_test (stdio_test stdio_test) + add_test (pipe_test pipe_test) + add_test (virtual_io_test virtual_io_test) + + set (SNDFILE_TEST_TARGETS + test_utils + test_main + sfversion + error_test + ulaw_test + alaw_test + dwvw_test + command_test + floating_point_test + checksum_test + scale_clip_test + headerless_test + rdwr_test + locale_test + cpp_test + external_libs_test + format_check_test + channel_test + pcm_test + write_read_test + lossy_comp_test + peak_chunk_test + header_test + misc_test + string_test + multi_file_test + aiff_rw_test + chunk_test + long_read_write_test + raw_test + compression_size_test + ogg_test + stdin_test + stdout_test + stdio_test + pipe_test + virtual_io_test + g72x_test + ) + +# if (WIN32 AND BUILD_SHARED_LIBS) +# list (APPEND SNDFILE_TEST_TARGETS win32_ordinal_test) +# endif () + + set_target_properties(${SNDFILE_TEST_TARGETS} PROPERTIES FOLDER Tests) + +endif () + +if (ENABLE_CPACK) + if ((NOT CPACK_PACKAGE_VERSION) AND CPACK_PACKAGE_VERSION_STAGE) + set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_FULL}") + endif () + include (CPack) +endif () diff --git a/extern/libsndfile-modified/CODEOWNERS b/extern/libsndfile-modified/CODEOWNERS new file mode 100644 index 000000000..d67616ee2 --- /dev/null +++ b/extern/libsndfile-modified/CODEOWNERS @@ -0,0 +1,14 @@ +# The owners of this repository. In order of suggestions as reviewers. +* @evpobr @SoapGentoo @arthurt @erikd + +# Autotools +configure.ac Makefile.am @SoapGentoo @erikd + +# CMake +CMakeLists.txt /cmake/ @evpobr + +# Ogg Opus format +/src/ogg_opus.c @arthurt + +# Documentation +/doc/ /man/ @evpobr diff --git a/extern/libsndfile-modified/CONTRIBUTING.md b/extern/libsndfile-modified/CONTRIBUTING.md new file mode 100644 index 000000000..0bf14b764 --- /dev/null +++ b/extern/libsndfile-modified/CONTRIBUTING.md @@ -0,0 +1,49 @@ +# Contributing + +## Submitting Issues + +* If your issue is that libsndfile is not able to or is incorrectly reading one + of your files, please include the output of the `sndfile-info` program run + against the file. +* If you are writing a program that uses libsndfile and you think there is a bug + in libsndfile, reduce your program to the minimal example, make sure you compile + it with warnings on (for GCC I would recommend at least `-Wall -Wextra`) and that + your program is warning free, and that is is error free when run under Valgrind + or compiled with AddressSanitizer. + +## Submitting Patches + +* Patches should pass all existing tests +* Patches should pass all pre-commit hook tests. +* Patches should always be submitted via a either Github "pull request" or a + via emailed patches created using "git format-patch". +* Patches for new features should include tests and documentation. +* Commit messages should follow the ["How to Write a Git Commit Message"](https://chris.beams.io/posts/git-commit/) guide: + 1. Separate subject from body with a blank line + 2. Limit the subject line to 50 characters + 3. Capitalize the subject line + 4. Do not end the subject line with a period + 5. Use the imperative mood in the subject line + 6. Wrap the body at 72 characters + 7. Use the body to explain what and why vs. how + + Additional rule: the commit message may contain a prefix. The prefix must + contain the name of the feature or source file related to the commit and must + end with a colon followed by the message body. + + Examples of good commit messages: + 1. Fix typo + 2. Update CHANGELOG.md + 3. Add ACT file format support + 4. ogg_vorbis: Fix granule position when seeking Vorbis streams + + Examples of bad commit messages: + 1. Fixed bug (rule 5) + 2. update docs (rule 3) + 3. Add very cool feature. (rule 4) + +* Patches to fix bugs should either pass all tests, or modify the tests in some + sane way. +* When a new feature is added for a particular file format and that feature + makes sense for other formats, then it should also be implemented for one + or two of the other formats. diff --git a/extern/libsndfile-modified/COPYING b/extern/libsndfile-modified/COPYING new file mode 100644 index 000000000..c396169ee --- /dev/null +++ b/extern/libsndfile-modified/COPYING @@ -0,0 +1,503 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + diff --git a/extern/libsndfile-modified/ChangeLog b/extern/libsndfile-modified/ChangeLog new file mode 100644 index 000000000..3843688df --- /dev/null +++ b/extern/libsndfile-modified/ChangeLog @@ -0,0 +1,3 @@ +For changes, please see the git commit history on github: + + https://github.com/libsndfile/libsndfile/commits/master diff --git a/extern/libsndfile-modified/MODIFIED.md b/extern/libsndfile-modified/MODIFIED.md new file mode 100644 index 000000000..c5296f048 --- /dev/null +++ b/extern/libsndfile-modified/MODIFIED.md @@ -0,0 +1,6 @@ +NOTICE: THIS IS A MODIFIED VERSION OF LIBSNDFILE WHICH FIXES COMPILATION WHEN USING CMAKE 4.0. + +I can't believe I had to desubmodulize this just for a ONE CHARACTER change. +no, I couldn't use Git master as they've dropped support for early 3.x CMake. + +this is commit 72f6af15e8f85157bd622ed45b979025828b7001 (tag 1.2.2). diff --git a/extern/libsndfile-modified/Makefile.am b/extern/libsndfile-modified/Makefile.am new file mode 100644 index 000000000..54035f20b --- /dev/null +++ b/extern/libsndfile-modified/Makefile.am @@ -0,0 +1,546 @@ +## Process this file with automake to produce Makefile.in + +AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/include -I$(top_builddir)/include $(OS_SPECIFIC_CFLAGS) + +DISTCHECK_CONFIGURE_FLAGS = --enable-werror + +CLEANFILES = programs/*.wav octave-workspace + +if FULL_SUITE +if BUILD_OCTAVE_MOD +SUBDIRS = Octave +endif +endif + +EXTRA_DIST = sndfile.pc.in Scripts/android-configure.sh \ + NEWS.OLD CHANGELOG.md Scripts/linux-to-win-cross-configure.sh \ + CMakeLists.txt $(cmake_files) Win32 SECURITY.md + +cmake_files = cmake/ClipMode.cmake cmake/FindFLAC.cmake \ + cmake/CMakeAutoGen.cmake cmake/CMakeAutoGenScript.cmake \ + cmake/FindOgg.cmake cmake/FindVorbis.cmake cmake/FindSndio.cmake \ + cmake/FindSpeex.cmake cmake/sqlite/FindSQLite3.cmake \ + cmake/SndFileChecks.cmake cmake/TestInline.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 + +noinst_PROGRAMS = + +#=============================================================================== + +test: check + +# Need this target to force building of test programs. +checkprograms: $(check_PROGRAMS) + +######## +# src/ # +######## + +BUILT_SOURCES = src/test_endswap.c + +SYMBOL_FILES = src/Symbols.gnu-binutils src/Symbols.darwin src/libsndfile-1.def src/Symbols.os2 src/Symbols.static + +EXTRA_DIST += src/config.h.in src/test_endswap.tpl src/test_endswap.def \ + $(SYMBOL_FILES) src/create_symbols_file.py src/binheader_writef_check.py \ + src/GSM610/README src/GSM610/COPYRIGHT src/GSM610/ChangeLog \ + src/G72x/README src/G72x/README.original src/G72x/ChangeLog \ + src/make-static-lib-hidden-privates.sh \ + src/config.h.cmake + +if USE_WIN_VERSION_FILE +WIN_VERSION_FILE = src/version-metadata.rc +else +WIN_VERSION_FILE = +endif + +#=============================================================================== + +lib_LTLIBRARIES = src/libsndfile.la +include_HEADERS = include/sndfile.h include/sndfile.hh +src_libsndfile_la_CFLAGS = $(EXTERNAL_XIPH_CFLAGS) $(MPEG_CFLAGS) +# MinGW requires -no-undefined if a DLL is to be built. +src_libsndfile_la_LDFLAGS = -no-undefined -version-info $(SHARED_VERSION_INFO) $(SHLIB_VERSION_ARG) +src_libsndfile_la_SOURCES = src/sndfile.c src/aiff.c src/au.c src/avr.c src/caf.c src/dwd.c src/flac.c src/g72x.c src/htk.c src/ircam.c \ + src/macos.c src/mat4.c src/mat5.c src/nist.c src/paf.c src/pvf.c src/raw.c src/rx2.c src/sd2.c \ + src/sds.c src/svx.c src/txw.c src/voc.c src/wve.c src/w64.c src/wavlike.c src/wav.c src/xi.c src/mpc2k.c src/rf64.c \ + src/ogg.c src/ogg.h src/ogg_vorbis.c src/ogg_speex.c src/ogg_pcm.c src/ogg_opus.c src/ogg_vcomment.c src/ogg_vcomment.h \ + src/common.h src/sfconfig.h src/sfendian.h src/wavlike.h src/sf_unistd.h src/chanmap.h src/mpeg.c +nodist_src_libsndfile_la_SOURCES = $(nodist_include_HEADERS) +src_libsndfile_la_LIBADD = src/GSM610/libgsm.la src/G72x/libg72x.la src/ALAC/libalac.la \ + src/libcommon.la $(EXTERNAL_XIPH_LIBS) -lm $(MPEG_LIBS) +EXTRA_src_libsndfile_la_DEPENDENCIES = $(SYMBOL_FILES) + +noinst_LTLIBRARIES = src/libcommon.la +src_libcommon_la_CFLAGS = $(EXTERNAL_XIPH_CFLAGS) $(MPEG_CFLAGS) +src_libcommon_la_SOURCES = src/common.c src/file_io.c src/command.c src/pcm.c src/ulaw.c src/alaw.c \ + src/float32.c src/double64.c src/ima_adpcm.c src/ms_adpcm.c src/gsm610.c src/dwvw.c src/vox_adpcm.c \ + src/interleave.c src/strings.c src/dither.c src/cart.c src/broadcast.c src/audio_detect.c \ + src/ima_oki_adpcm.c src/ima_oki_adpcm.h src/alac.c src/chunk.c src/chanmap.c \ + src/windows.c src/id3.c src/id3.h src/nms_adpcm.c src/mpeg_decode.c src/mpeg_l3_encode.c src/mpeg.h $(WIN_VERSION_FILE) + +check_PROGRAMS = src/test_main +src_test_main_SOURCES = src/test_main.c src/test_main.h src/test_conversions.c src/test_float.c src/test_endswap.c \ + src/test_audio_detect.c src/test_log_printf.c src/test_file_io.c src/test_ima_oki_adpcm.c \ + src/test_strncpy_crlf.c src/test_broadcast_var.c src/test_cart_var.c \ + src/test_binheader_writef.c src/test_nms_adpcm.c +src_test_main_LDADD = src/libcommon.la + +############## +# src/GSM610 # +############## + +noinst_LTLIBRARIES += src/GSM610/libgsm.la +src_GSM610_libgsm_la_SOURCES = src/GSM610/config.h src/GSM610/gsm.h src/GSM610/gsm610_priv.h \ + src/GSM610/add.c src/GSM610/code.c src/GSM610/decode.c src/GSM610/gsm_create.c \ + src/GSM610/gsm_decode.c src/GSM610/gsm_destroy.c src/GSM610/gsm_encode.c \ + src/GSM610/gsm_option.c src/GSM610/long_term.c src/GSM610/lpc.c src/GSM610/preprocess.c \ + src/GSM610/rpe.c src/GSM610/short_term.c src/GSM610/table.c + +############ +# src/G72x # +############ + +noinst_LTLIBRARIES += src/G72x/libg72x.la +src_G72x_libg72x_la_SOURCES = src/G72x/g72x.h src/G72x/g72x_priv.h \ + src/G72x/g721.c src/G72x/g723_16.c src/G72x/g723_24.c src/G72x/g723_40.c src/G72x/g72x.c + +check_PROGRAMS += src/G72x/g72x_test +src_G72x_g72x_test_SOURCES = src/G72x/g72x_test.c +src_G72x_g72x_test_LDADD = src/G72x/libg72x.la + +############ +# src/ALAC # +############ + +noinst_LTLIBRARIES += src/ALAC/libalac.la +src_ALAC_libalac_la_SOURCES = src/ALAC/ALACAudioTypes.h src/ALAC/ALACBitUtilities.h \ + src/ALAC/EndianPortable.h src/ALAC/aglib.h src/ALAC/dplib.h src/ALAC/matrixlib.h \ + src/ALAC/alac_codec.h src/ALAC/shift.h \ + src/ALAC/ALACBitUtilities.c src/ALAC/ag_dec.c \ + src/ALAC/ag_enc.c src/ALAC/dp_dec.c src/ALAC/dp_enc.c src/ALAC/matrix_dec.c \ + src/ALAC/matrix_enc.c src/ALAC/alac_decoder.c src/ALAC/alac_encoder.c + +#=============================================================================== +# Generate an OS specific Symbols files. This is done when the author +# builds the distribution tarball. There should be not need for the +# end user to create these files. + +# "$<" cannot portably be used in the recipe across Make implementations +# https://www.gnu.org/software/autoconf/manual/autoconf.html#g_t_0024_003c-in-Ordinary-Make-Rules +SYMBOL_SCRIPT = $(top_srcdir)/src/create_symbols_file.py + +src/Symbols.gnu-binutils: $(SYMBOL_SCRIPT) + $(PYTHON) $(SYMBOL_SCRIPT) linux $(ABI_VERSION) > $(top_srcdir)/$@ + +src/Symbols.darwin: $(SYMBOL_SCRIPT) + $(PYTHON) $(SYMBOL_SCRIPT) darwin $(ABI_VERSION) > $(top_srcdir)/$@ + +src/libsndfile-1.def: $(SYMBOL_SCRIPT) + $(PYTHON) $(SYMBOL_SCRIPT) win32 $(ABI_VERSION) > $(top_srcdir)/$@ + +src/Symbols.os2: $(SYMBOL_SCRIPT) + $(PYTHON) $(SYMBOL_SCRIPT) os2 $(ABI_VERSION) > $(top_srcdir)/$@ + +src/Symbols.static: $(SYMBOL_SCRIPT) + $(PYTHON) $(SYMBOL_SCRIPT) static $(ABI_VERSION) > $(top_srcdir)/$@ + +#=============================================================================== +# Building windows resource files (if needed). + +.rc.lo: + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --tag=RC --mode=compile $(RC) $(RCFLAGS) $< -o $@ + +#=============================================================================== +# Disable autoheader. +AUTOHEADER=echo + +######## +# docs/ # +######## + +if FULL_SUITE +dist_doc_DATA = docs/index.md docs/libsndfile.jpg docs/libsndfile.css docs/print.css docs/api.md \ + docs/command.md docs/bugs.md docs/formats.md docs/sndfile_info.md docs/new_file_type_howto.md \ + docs/win32.md docs/FAQ.md docs/lists.md docs/embedded_files.md docs/octave.md \ + docs/tutorial.md +endif + +############# +# examples/ # +############# + +check_PROGRAMS += examples/make_sine examples/sfprocess examples/list_formats examples/generate examples/sndfilehandle \ + examples/sndfile-to-text examples/sndfile-loopify + +examples_sndfile_to_text_SOURCES = examples/sndfile-to-text.c +examples_sndfile_to_text_LDADD = src/libsndfile.la + +examples_sndfile_loopify_SOURCES = examples/sndfile-loopify.c +examples_sndfile_loopify_LDADD = src/libsndfile.la + +examples_make_sine_SOURCES = examples/make_sine.c +examples_make_sine_LDADD = src/libsndfile.la + +examples_sfprocess_SOURCES = examples/sfprocess.c +examples_sfprocess_LDADD = src/libsndfile.la + +examples_list_formats_SOURCES = examples/list_formats.c +examples_list_formats_LDADD = src/libsndfile.la + +examples_generate_SOURCES = examples/generate.c +examples_generate_LDADD = src/libsndfile.la + +examples_sndfilehandle_SOURCES = examples/sndfilehandle.cc +examples_sndfilehandle_LDADD = src/libsndfile.la + +########## +# tests/ # +########## + +TESTS_ENVIRONMENT = $(SHELL) tests/test_wrapper.sh + +if ENABLE_TEST_COVERAGE +CPP_TEST = +else +CPP_TEST = tests/cpp_test +endif + +TESTS = tests/pedantic-header-test.sh + +check_PROGRAMS += tests/sfversion tests/floating_point_test tests/write_read_test \ + tests/lossy_comp_test tests/error_test tests/ulaw_test tests/alaw_test tests/dwvw_test \ + tests/peak_chunk_test tests/command_test tests/stdio_test \ + tests/pcm_test tests/headerless_test tests/pipe_test tests/header_test tests/misc_test \ + tests/raw_test tests/string_test tests/multi_file_test tests/chunk_test \ + tests/scale_clip_test tests/win32_test tests/aiff_rw_test tests/virtual_io_test \ + tests/locale_test tests/win32_ordinal_test tests/ogg_test tests/compression_size_test \ + tests/checksum_test tests/external_libs_test tests/rdwr_test tests/format_check_test $(CPP_TEST) \ + tests/channel_test tests/long_read_write_test tests/stdin_test tests/stdout_test \ + tests/dither_test tests/fix_this tests/largefile_test tests/benchmark tests/ogg_opus_test \ + tests/mpeg_test + +BUILT_SOURCES += \ + tests/write_read_test.c \ + tests/pcm_test.c \ + tests/header_test.c \ + tests/utils.c \ + tests/scale_clip_test.c \ + tests/pipe_test.c \ + tests/rdwr_test.c \ + tests/floating_point_test.c \ + tests/benchmark.c + +EXTRA_DIST += $(BUILT_SOURCES) \ + tests/write_read_test.tpl tests/write_read_test.def \ + tests/pcm_test.tpl tests/pcm_test.def \ + tests/header_test.tpl tests/header_test.def \ + tests/utils.tpl tests/utils.def \ + tests/scale_clip_test.tpl tests/scale_clip_test.def \ + tests/pipe_test.tpl tests/pipe_test.def \ + tests/rdwr_test.tpl tests/rdwr_test.def \ + tests/floating_point_test.tpl tests/floating_point_test.def \ + tests/benchmark.tpl tests/benchmark.def + +# If we're cross compiling from Linux to Windows and running the test suite +# under Wine, we need a symbolic link to the generated libsndfile DLL. + +if LINUX_MINGW_CROSS_TEST + +$(check_PROGRAMS) : libsndfile-1.dll + +libsndfile-1.dll : + $(LN_S) src/.libs/$@ $@ + +clean-local : + -rm -f libsndfile-1.dll + +endif + +#=============================================================================== + +tests_sfversion_SOURCES = tests/sfversion.c +tests_sfversion_LDADD = src/libsndfile.la + +tests_write_read_test_SOURCES = tests/utils.c tests/generate.c tests/generate.h tests/write_read_test.c tests/utils.h +tests_write_read_test_LDADD = src/libsndfile.la + +tests_lossy_comp_test_SOURCES = tests/utils.c tests/lossy_comp_test.c tests/utils.h +tests_lossy_comp_test_LDADD = src/libsndfile.la + +tests_fix_this_SOURCES = tests/utils.c tests/fix_this.c tests/utils.h +tests_fix_this_LDADD = src/libsndfile.la + +tests_error_test_SOURCES = tests/error_test.c tests/utils.c tests/utils.h +tests_error_test_LDADD = src/libsndfile.la + +tests_ulaw_test_SOURCES = tests/utils.c tests/ulaw_test.c tests/utils.h +tests_ulaw_test_LDADD = src/libsndfile.la + +tests_alaw_test_SOURCES = tests/utils.c tests/alaw_test.c tests/utils.h +tests_alaw_test_LDADD = src/libsndfile.la + +tests_aiff_rw_test_SOURCES = tests/utils.c tests/aiff_rw_test.c tests/utils.h +tests_aiff_rw_test_LDADD = src/libsndfile.la + +tests_command_test_SOURCES = tests/command_test.c tests/utils.c tests/utils.h +tests_command_test_LDADD = src/libsndfile.la + +tests_locale_test_SOURCES = tests/locale_test.c tests/utils.c tests/utils.h +tests_locale_test_LDADD = src/libsndfile.la + +tests_largefile_test_SOURCES = tests/largefile_test.c tests/utils.c tests/utils.h +tests_largefile_test_LDADD = src/libsndfile.la + +tests_pcm_test_SOURCES = tests/pcm_test.c tests/utils.c tests/utils.h +tests_pcm_test_LDADD = src/libsndfile.la + +tests_headerless_test_SOURCES = tests/utils.c tests/headerless_test.c tests/utils.h +tests_headerless_test_LDADD = src/libsndfile.la + +tests_stdin_test_SOURCES = tests/stdin_test.c tests/utils.c tests/utils.h +tests_stdin_test_LDADD = src/libsndfile.la + +tests_stdout_test_SOURCES = tests/stdout_test.c tests/utils.h +tests_stdout_test_LDADD = src/libsndfile.la + +tests_stdio_test_SOURCES = tests/stdio_test.c tests/utils.c tests/utils.h +tests_stdio_test_LDADD = src/libsndfile.la + +tests_pipe_test_SOURCES = tests/pipe_test.c tests/utils.c tests/utils.h +tests_pipe_test_LDADD = src/libsndfile.la + +tests_benchmark_SOURCES = tests/benchmark.c tests/utils.h +tests_benchmark_LDADD = src/libsndfile.la + +tests_header_test_SOURCES = tests/header_test.c tests/utils.c tests/utils.h +tests_header_test_LDADD = src/libsndfile.la + +tests_misc_test_SOURCES = tests/misc_test.c tests/utils.c tests/utils.h +tests_misc_test_LDADD = src/libsndfile.la + +tests_raw_test_SOURCES = tests/raw_test.c tests/utils.c tests/utils.h +tests_raw_test_LDADD = src/libsndfile.la + +tests_string_test_SOURCES = tests/string_test.c tests/utils.c tests/utils.h +tests_string_test_LDADD = src/libsndfile.la + +tests_dither_test_SOURCES = tests/dither_test.c tests/utils.c tests/utils.h +tests_dither_test_LDADD = src/libsndfile.la + +tests_chunk_test_SOURCES = tests/chunk_test.c tests/utils.c tests/utils.h +tests_chunk_test_LDADD = src/libsndfile.la + +tests_multi_file_test_SOURCES = tests/multi_file_test.c tests/utils.c tests/utils.h +tests_multi_file_test_LDADD = src/libsndfile.la + +tests_virtual_io_test_SOURCES = tests/virtual_io_test.c tests/utils.c tests/utils.h +tests_virtual_io_test_LDADD = src/libsndfile.la + +tests_ogg_test_SOURCES = tests/ogg_test.c tests/utils.c tests/utils.h +tests_ogg_test_LDADD = src/libsndfile.la + +tests_ogg_opus_test_SOURCES = tests/ogg_opus_test.c tests/utils.c tests/utils.h +tests_ogg_opus_test_LDADD = src/libsndfile.la + +tests_compression_size_test_SOURCES = tests/compression_size_test.c tests/utils.c tests/utils.h tests/dft_cmp.h +tests_compression_size_test_LDADD = src/libsndfile.la + +tests_rdwr_test_SOURCES = tests/rdwr_test.c tests/utils.c tests/utils.h +tests_rdwr_test_LDADD = src/libsndfile.la + +tests_win32_test_SOURCES = tests/win32_test.c +# Link lib here so that generating the testsuite tarball works correctly. +tests_win32_test_LDADD = src/libsndfile.la + +tests_win32_ordinal_test_SOURCES = tests/win32_ordinal_test.c tests/utils.c tests/utils.h +tests_win32_ordinal_test_LDADD = src/libsndfile.la + +tests_external_libs_test_SOURCES = tests/external_libs_test.c tests/utils.c tests/utils.h +tests_external_libs_test_LDADD = src/libsndfile.la + +tests_format_check_test_SOURCES = tests/format_check_test.c tests/utils.c tests/utils.h +tests_format_check_test_LDADD = src/libsndfile.la + +tests_channel_test_SOURCES = tests/channel_test.c tests/utils.c tests/utils.h +tests_channel_test_LDADD = src/libsndfile.la + +tests_long_read_write_test_SOURCES = tests/long_read_write_test.c tests/utils.c tests/utils.h tests/dft_cmp.h +tests_long_read_write_test_LDADD = src/libsndfile.la + +tests_cpp_test_SOURCES = tests/cpp_test.cc tests/utils.c tests/utils.h +tests_cpp_test_LDADD = src/libsndfile.la + +tests_checksum_test_SOURCES = tests/checksum_test.c tests/utils.c tests/utils.h +tests_checksum_test_LDADD = src/libsndfile.la + +tests_mpeg_test_SOURCES = tests/mpeg_test.c tests/utils.c tests/utils.h +tests_mpeg_test_LDADD = src/libsndfile.la + +# Lite remove start +tests_dwvw_test_SOURCES = tests/dwvw_test.c tests/utils.c tests/utils.h +tests_dwvw_test_LDADD = src/libsndfile.la + +tests_floating_point_test_SOURCES = tests/utils.c tests/utils.h tests/dft_cmp.c tests/dft_cmp.h tests/floating_point_test.c +tests_floating_point_test_LDADD = src/libsndfile.la + +tests_peak_chunk_test_SOURCES = tests/peak_chunk_test.c tests/utils.c tests/utils.h +tests_peak_chunk_test_LDADD = src/libsndfile.la + +tests_scale_clip_test_SOURCES = tests/scale_clip_test.c tests/utils.c tests/utils.h +tests_scale_clip_test_LDADD = src/libsndfile.la +# Lite remove end + +#=============================================================================== +# Autogen generated sources. +# Coerce the multiple inputs -> multiple outputs problem +# into suffix rules by "linearising" the dependency graph. +# Yes, this sucks, but GNU make patterns aren't portable, +# see also https://github.com/libsndfile/libsndfile/issues/369 + +SUFFIXES = .tpl .def + +.tpl.def: + touch $@ + +# unconditionally running touch on the .def +# files is necessary to keep all timestamps +# consistent, in order to prevent stale files +# from calling autogen in tarball releases. +.def.c: + $(MAKE) $(AM_MAKEFLAGS) $< + cd $(top_srcdir)/$(@D) && autogen --writable $(= 3.15 without error. + * You can use your our method to set MSVC runtime library flags if none of + ENABLE_STATIC_RUNTIME and CMAKE_MSVC_RUNTIME_LIBRARY were set. + Advanced information: + * If this option is defined (set to ON or OFF), set CMP0091 policy to OLD + (we handle MSVC runtime library flags using compiler flags), set + corresponding compiler flags for user. + * NEW: If this option is not defined, set CMP0091 policy to OLD (we handle + MSVC runtime library flags using compiler flags), don't touch compiler + options, allow user to set it manually. + * NEW: If new CMake option CMAKE_MSVC_RUNTIME_LIBRARY is set, change + CMP0091 policy to NEW (we handle MSVC runtime library flags using that + option), don't touch compiler flags. + * NEW: If both ENABLE_STATIC_RUNTIME and CMAKE_MSVC_RUNTIME_LIBRARY are set, + terminate configuration with fatal error. + * For MinGW toolchain this option is experimental. If you enabled it and + then disabled again, you need to clear CMake cache (delete + CMakeCache.txt). + * Make CMake clip test faster. + * Fix CMake bug with sndio library dependency, thanks to @drhenault. + * Fix memory leak in wav_read_smpl_chunk() function, credit to OSS-Fuzz. + * Fix aiff_read_header() memory leak(), credit to OSS-Fuzz. + * Fix leak in wav_read_header(), credit to OSS-Fuzz. + * Fix leak in wavlike_read_cart_chunk(), credit to OSS-Fuzz. + * Fix memory leak in wav_read_acid_chunk(), credit to OSS-Fuzz. + * Fix memory leak in aiff_read_basc_chunk(), credit to OSS-Fuzz. + * Fix memory leak in wavlike_read_peak_chunk(), credit to OSS-Fuzz. + * Fix memory leak in aiff_read_header(), credit to OSS-Fuzz. + * Fix use of uninitialized value in exif_subchunk_parse(), credit to OSS-Fuzz. + * Fix use of uninitialized value in endswap_int64_t_array(), credit to + OSS-Fuzz. + * Fix up the fuzzer so that it can't under or overseek, + thanks to Max Dymond . + * Fix Autotools configure on macOS, thanks to @tmcguire and @nwh. + * Exclude repository-configuration from git-archive, thanks to @umlaeute. + * Use version-script when compiling with clang on Unix with Autotools, thanks + to @tstellar. + * Improve handling of SMPL chunks in WAV files, thanks to @zodf0055980. + +Version 1.0.30 (2020-09-18) + + * Fix critical CMake bug with broken ABI of shared libsndfile library. + * CMake build system considered to be stable. + * Move sndfile.h.in from src/ to include/ directory. To avoid problems, + delete old generated sndfile.h from $(top_builddir)/src. + * Huge documentation update. + * Fix opus test failures on BE platforms, thanks to + Arthur Taylor . + * Fix bug when sf_open_fd() function sometimes leaves filehandle open, even + if `close_desc` parameter is TRUE, thanks to @umläute. + * Fix infinite loops on some pathological SD2 files, thanks to + Jeremy Friesner . + * Switch to GitHub Actions for continuous integration. + * Add OSS-Fuzz tests to GitHub Actions workflow, thanks to + Max Dymond . + * Fix memory leak in wavlike_read_bext_chunk() function, credit to OSS-Fuzz. + * Fix undefined behavior in avr-read_header() function, credit to OSS-Fuzz. + * Add INSTALL_PKGCONFIG_MODULE CMake option to control sndfile.pc file + installation, see README.md for details. + * Add INSTALL_MANPAGES CMake option, see README.md for details. + * Fix ENABLE_COMPATIBLE_LIBSNDFILE_NAME CMake option, now it works on MinGW + platform too. + * Fix ENABLE_CPACK CMake option, see README.md for details. + * Fix ENABLE_STATIC_RUNTIME and CMAKE_MSVC_RUNTIME_LIBRARY behavior, see + README.md for details. + * Fix CMake man pages installation bug when sndfile-deinterleave.1 and + sndfile-metadata-set.1 were not installed. + * Fix sndfile-regtest paths handling on Windows platform, thanks to + Gisle Vanem . + +Version 1.0.29 (2020-08-15) + * Add support for Opus files. + * Autotool build system improvements. + * CMake build system improvements. + * Fixes for: CVE-2017-12562, CVE-2017-17456, CVE-2017-17457, CVE-2018-19661, + CVE-2018-19662, CVE-2018-19758 and CVE-2019-3832. + * Add BWF v2 loudness parameters. + * Wave64: Permit and skip arbitrary chunks prior to the data chunk. + * Fix ASAN crash in wavlike_ima_seek(). + * Fix IMA-ADPCM encoding for AIFF files. + * sndfile-convert: Handle gsm, vox and opus extensions the same way. + * Add SFC_SET_OGG_PAGE_LATENCY_MS command to get Ogg page latency for Ogg Opus + files. + * Fix parsing of some SD2 files. + * Documentation updates. + * Minor bug fixes and improvements. + +Version 1.0.28 (2017-04-02) + * Fix buffer overruns in FLAC and ID3 handling code. + * Move to variable length header storage. + * Fix detection of Large File Support for 32 bit systems. + * Remove large stack allocations in ALAC handling code. + * Remove all use of Variable Length Arrays. + * Minor bug fixes and improvements. + +Version 1.0.27 (2016-06-19) + * Fix an SF_INFO seekable flag regression introduced in 1.0.26. + * Fix potential infinite loops on malformed input files. + * Add string metadata read/write for CAF and RF64. + * Add handling of CUE chunks. + * Fix endian-ness issues in PAF files. + * Minor bug fixes and improvements. + +Version 1.0.26 (2015-11-22) + * Fix for CVE-2014-9496, SD2 buffer read overflow. + * Fix for CVE-2014-9756, file_io.c divide by zero. + * Fix for CVE-2015-7805, AIFF heap write overflow. + * Add support for ALAC encoder in a CAF container. + * Add support for Cart chunks in WAV files. + * Minor bug fixes and improvements. + +Version 1.0.25 (2011-07-13) + * Fix for Secunia Advisory SA45125, heap overflow in PAF file handler. + * Accept broken WAV files with blockalign == 0. + * Minor bug fixes and improvements. + +Version 1.0.24 (2011-03-23) + * WAV files now have an 18 byte u-law and A-law fmt chunk. + * Document virtual I/O functionality. + * Two new methods rawHandle() and takeOwnership() in sndfile.hh. + * AIFF fix for non-zero offset value in SSND chunk. + * Minor bug fixes and improvements. + +Version 1.0.23 (2010-10-10) + * Add version metadata to Windows DLL. + * Add a missing 'inline' to sndfile.hh. + * Update docs. + * Minor bug fixes and improvements. + +Version 1.0.22 (2010-10-04) + * Couple of fixes for SDS file writer. + * Fixes arising from static analysis. + * Handle FLAC files with ID3 meta data at start of file. + * Handle FLAC files which report zero length. + * Other minor bug fixes and improvements. + +Version 1.0.21 (2009-12-13) + * Add a couple of new binary programs to programs/ dir. + * Remove sndfile-jackplay (now in sndfile-tools package). + * Add windows only function sf_wchar_open(). + * Bunch of minor bug fixes. + +Version 1.0.20 (2009-05-14) + * Fix potential heap overflow in VOC file parser (Tobias Klein, http://www.trapkit.de/). + +Version 1.0.19 (2009-03-02) + * Fix for CVE-2009-0186 (Alin Rad Pop, Secunia Research). + * Huge number of minor bug fixes as a result of static analysis. + +Version 1.0.18 (2009-02-07) + * Add Ogg/Vorbis support (thanks to John ffitch). + * Remove captive FLAC library. + * Many new features and bug fixes. + * Generate Win32 and Win64 pre-compiled binaries. + +Version 1.0.17 (2006-08-31) + * Add sndfile.hh C++ wrapper. + * Update Win32 MinGW build instructions. + * Minor bug fixes and cleanups. + +Version 1.0.16 (2006-04-30) + * Add support for Broadcast (BEXT) chunks in WAV files. + * Implement new commands SFC_GET_SIGNAL_MAX and SFC_GET_MAX_ALL_CHANNELS. + * Add support for RIFX (big endian WAV variant). + * Fix configure script bugs. + * Fix bug in INST and MARK chunk writing for AIFF files. + +Version 1.0.15 (2006-03-16) + * Fix some ia64 issues. + * Fix precompiled DLL. + * Minor bug fixes. + +Version 1.0.14 (2006-02-19) + * Really fix MinGW compile problems. + * Minor bug fixes. + +Version 1.0.13 (2006-01-21) + * Fix for MinGW compiler problems. + * Allow readin/write of instrument chunks from WAV and AIFF files. + * Compile problem fix for Solaris compiler. + * Minor cleanups and bug fixes. + +Version 1.0.12 (2005-09-30) + * Add support for FLAC and Apple's Core Audio Format (CAF). + * Add virtual I/O interface (still needs docs). + * Cygwin and other Win32 fixes. + * Minor bug fixes and cleanups. + +Version 1.0.11 (2004-11-15) + * Add support for SD2 files. + * Add read support for loop info in WAV and AIFF files. + * Add more tests. + * Improve type safety. + * Minor optimisations and bug fixes. + +Version 1.0.10 (2004-06-15) + * Fix AIFF read/write mode bugs. + * Add support for compiling Win32 DLLS using MinGW. + * Fix problems resulting in failed compiles with gcc-2.95. + * Improve test suite. + * Minor bug fixes. + +Version 1.0.9 (2004-03-30) + * Add handling of AVR (Audio Visual Research) files. + * Improve handling of WAVEFORMATEXTENSIBLE WAV files. + * Fix for using pipes on Win32. + +Version 1.0.8 (2004-03-14) + * Correct peak chunk handing for files with > 16 tracks. + * Fix for WAV files with huge number of CUE chunks. + +Version 1.0.7 (2004-02-25) + * Fix clip mode detection on ia64, MIPS and other CPUs. + * Fix two MacOSX build problems. + +Version 1.0.6 (2004-02-08) + * Added support for native Win32 file access API (Ross Bencina). + * New mode to add clippling then a converting from float/double to integer + would otherwise wrap around. + * Fixed a bug in reading/writing files > 2Gig on Linux, Solaris and others. + * Many minor bug fixes. + * Other random fixes for Win32. + +Version 1.0.5 (2003-05-03) + * Added support for HTK files. + * Added new function sf_open_fd() to allow for secure opening of temporary + files as well as reading/writing sound files embedded within larger + container files. + * Added string support for AIFF files. + * Minor bug fixes and code cleanups. + +Version 1.0.4 (2003-02-02) + * Added suport of PVF and XI files. + * Added functionality for setting and retreiving strings from sound files. + * Minor code cleanups and bug fixes. + +Version 1.0.3 (2002-12-09) + * Minor bug fixes. + +Version 1.0.2 (2002-11-24) + * Added support for VOX ADPCM. + * Improved error reporting. + * Added version scripting on Linux and Solaris. + * Minor bug fixes. + +Version 1.0.1 (2002-09-14) + * Added MAT and MAT5 file formats. + * Minor bug fixes. + +Version 1.0.0 (2002-08-16) + * Final release for 1.0.0. + +Version 1.0.0rc6 (2002-08-14) + * Release candidate 6 for the 1.0.0 series. + * MacOS9 fixes. + +Version 1.0.0rc5 (2002-08-10) + * Release candidate 5 for the 1.0.0 series. + * Changed the definition of sf_count_t which was causing problems when + libsndfile was compiled with other libraries (ie WxWindows). + * Minor bug fixes. + * Documentation cleanup. + +Version 1.0.0rc4 (2002-08-03) + * Release candidate 4 for the 1.0.0 series. + * Minor bug fixes. + * Fix broken Win32 "make check". + +Version 1.0.0rc3 (2002-08-02) + * Release candidate 3 for the 1.0.0 series. + * Fix bug where libsndfile was reading beyond the end of the data chunk. + * Added on-the-fly header updates on write. + * Fix a couple of documentation issues. + +Version 1.0.0rc2 (2002-06-24) + * Release candidate 2 for the 1.0.0 series. + * Fix compile problem for Win32. + +Version 1.0.0rc1 (2002-06-24) + * Release candidate 1 for the 1.0.0 series. + +Version 0.0.28 (2002-04-27) + * Last official release of 0.0.X series of the library. + +Version 0.0.8 (1999-02-16) + * First official release. diff --git a/extern/libsndfile-modified/Octave/Makefile.am b/extern/libsndfile-modified/Octave/Makefile.am new file mode 100644 index 000000000..3f0078e18 --- /dev/null +++ b/extern/libsndfile-modified/Octave/Makefile.am @@ -0,0 +1,79 @@ +## Process this file with automake to produce Makefile.in + +# Prevent any extension. +EXEEXT = + +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) --tag=CXX --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ + +EXTRA_DIST = sndfile_load.m sndfile_save.m sndfile_play.m \ + octave_test.m octave_test.sh $(oct_module_srcs) PKG_ADD + +octconfigdir = $(exec_prefix)/share/octave/site/m +octconfig_DATA = sndfile_load.m sndfile_save.m sndfile_play.m + +OCTAVE_DEST_MDIR = @OCTAVE_DEST_MDIR@ +OCTAVE_DEST_ODIR = @OCTAVE_DEST_ODIR@/sndfile + +OCT_CXXFLAGS = @OCT_CXXFLAGS@ +OCT_LIB_DIR = @OCT_LIB_DIR@ +OCT_LIBS = @OCT_LIBS@ + +SNDFILEDIR = $(top_builddir)/src +AM_CPPFLAGS = -I$(SNDFILEDIR) + +oct_module_srcs = sndfile.cc +oct_module_files = sndfile.oct PKG_ADD + +# Make these noinst so they can be installed manually. +noinst_DATA = $(oct_module_files) + + +# Used by shave which cleans up automake generated Makefile output. +V = @ +Q = $(V:1=) +QUIET_GEN = $(Q:@=@echo ' GEN '$@;) + + +# Use Octave's mkoctfile to do all the heavy lifting. Unfortunately, its +# a little dumb so we need to guide it carefully. +sndfile.oct : sndfile.o + $(QUIET_GEN) $(MKOCTFILE) -v $(INCLUDES) $(top_builddir)/Octave/$+ -L$(SNDFILEDIR)/.libs -L$(SNDFILEDIR) -lsndfile -o $(top_builddir)/Octave/$@ > /dev/null + +sndfile.o : sndfile.cc + $(QUIET_GEN) $(MKOCTFILE) -v $(INCLUDES) -c $+ -o $(top_builddir)/Octave/$@ > /dev/null + +# Allow for the test being run in the build dir, but the test script +# being located in the source dir. +check : + octave_src_dir=$(srcdir) $(srcdir)/octave_test.sh + + +# Since the octave modules are installed in a special location, a custom install +# and uninstall routine must be specified. +install-exec-local : $(oct_module_files) + @$(NORMAL_INSTALL) + test -z "$(OCTAVE_DEST_ODIR)" || $(mkdir_p) "$(DESTDIR)$(OCTAVE_DEST_ODIR)" + @list='$(oct_module_files)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + || test -f $$p1 \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(INSTALL) '$$p' '$(DESTDIR)$(OCTAVE_DEST_ODIR)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(INSTALL) "$$p" "$(DESTDIR)$(OCTAVE_DEST_ODIR)/$$f" || exit 1; \ + else :; fi; \ + done + +uninstall-local : + @$(NORMAL_UNINSTALL) + @list='$(oct_module_files)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f '$(DESTDIR)$(OCTAVE_DEST_ODIR)/$$f'"; \ + rm -f "$(DESTDIR)$(OCTAVE_DEST_ODIR)/$$f"; \ + done + +clean-local : + rm -f sndfile.o sndfile.oct + @if test $(abs_builddir) != $(abs_srcdir) ; then rm -f PKG_ADD ; fi diff --git a/extern/libsndfile-modified/Octave/PKG_ADD b/extern/libsndfile-modified/Octave/PKG_ADD new file mode 100644 index 000000000..3efd68855 --- /dev/null +++ b/extern/libsndfile-modified/Octave/PKG_ADD @@ -0,0 +1,3 @@ +autoload ("sfread", "sndfile.oct"); +autoload ("sfversion", "sndfile.oct"); +autoload ("sfwrite", "sndfile.oct"); diff --git a/extern/libsndfile-modified/Octave/Readme.txt b/extern/libsndfile-modified/Octave/Readme.txt new file mode 100644 index 000000000..c38605bff --- /dev/null +++ b/extern/libsndfile-modified/Octave/Readme.txt @@ -0,0 +1,23 @@ +The libsndfile Modules for GNU Octave +===================================== + +These modules are currently known to work with version 3.0 of GNU Octave on +Linux. They have not been tested elsewhere. + + +Build Requirements +------------------ + +In order to build these libsndfile related modules for GNU Octave on a Debian +GNU/Linux (or Debian derived) system, you will need (on top of what is normally +required to build libsndfile) the package: + + octaveX.Y-headers + +where X.Y matches the version number of your installation of GNU Octave. + +The configure script in the top level libsndfile directory will detect the +presence and correct versions of the Octave build tools. The building of these +modules will only go ahead if everything is correct. + + diff --git a/extern/libsndfile-modified/Octave/format.h b/extern/libsndfile-modified/Octave/format.h new file mode 100644 index 000000000..ce769b2c6 --- /dev/null +++ b/extern/libsndfile-modified/Octave/format.h @@ -0,0 +1,21 @@ +/* +** Copyright (C) 2007-2011 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +int format_of_str (const std::string & fmt) ; + +void string_of_format (std::string & fmt, int format) ; diff --git a/extern/libsndfile-modified/Octave/octave_test.m b/extern/libsndfile-modified/Octave/octave_test.m new file mode 100644 index 000000000..25a922e89 --- /dev/null +++ b/extern/libsndfile-modified/Octave/octave_test.m @@ -0,0 +1,52 @@ +# Copyright (C) 2007-2011 Erik de Castro Lopo +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# These tests are nowhere near comprehensive. + +printf (" Running Octave tests : ") ; +fflush (stdout) ; + +filename = "whatever" ; +srate_out = 32000 ; +fmt_out = "wav-float" ; + +t = (2 * pi / srate_out * (0:srate_out-1))' ; +data_out = sin (440.0 * t) ; + +# Write out a file. +sfwrite (filename, data_out, srate_out, fmt_out) ; + +# Read it back in again. +[ data_in, srate_in, fmt_in ] = sfread (filename) ; + +if (srate_in != srate_out) + error ("\n\nSample rate mismatch : %d -> %d.\n\n", srate_out, srate_in) ; + endif + +# Octave strcmp return 1 for the same. +if (strcmp (fmt_in, fmt_out) != 1) + error ("\n\nFormat error : '%s' -> '%s'.\n\n", fmt_out, fmt_in) ; + endif + +err = max (abs (data_out - data_in)) ; + +if (err > 1e-7) + error ("err : %g\n", err) ; + endif + +printf ("ok") ; + +unlink (filename) ; diff --git a/extern/libsndfile-modified/Octave/octave_test.sh b/extern/libsndfile-modified/Octave/octave_test.sh new file mode 100755 index 000000000..3c6f36e23 --- /dev/null +++ b/extern/libsndfile-modified/Octave/octave_test.sh @@ -0,0 +1,81 @@ +#!/bin/bash + + +# Check where we're being run from. +if test -d Octave ; then + cd Octave + octave_src_dir=$(pwd) +elif test -z "$octave_src_dir" ; then + echo + echo "Error : \$octave_src_dir is undefined." + echo + exit 1 +else + octave_src_dir=$(cd $octave_src_dir && pwd) + fi + +# Find libsndfile shared object. +libsndfile_lib_location="" + +if test -f "../src/.libs/libsndfile.so" ; then + libsndfile_lib_location="../src/.libs/" +elif test -f "../src/libsndfile.so" ; then + libsndfile_lib_location="../src/" +elif test -f "../src/.libs/libsndfile.dylib" ; then + libsndfile_lib_location="../src/.libs/" +elif test -f "../src/libsndfile.dylib" ; then + libsndfile_lib_location="../src/" +else + echo + echo "Not able to find the libsndfile shared lib we've just built." + echo "This may cause the following test to fail." + echo + fi + +libsndfile_lib_location=`(cd $libsndfile_lib_location && pwd)` + + +# Find sndfile.oct +sndfile_oct_location="" + +if test -f .libs/sndfile.oct ; then + sndfile_oct_location=".libs" +elif test -f sndfile.oct ; then + sndfile_oct_location="." +else + echo "Not able to find the sndfile.oct binaries we've just built." + exit 1 + fi + +case `file -b $sndfile_oct_location/sndfile.oct` in + ELF*) + ;; + Mach*) + echo "Tests don't work on this platform." + exit 0 + ;; + *) + echo "Not able to find the sndfile.oct binary we just built." + exit 1 + ;; + esac + + +# Make sure the TERM environment variable doesn't contain anything wrong. +unset TERM +# echo "octave_src_dir : $octave_src_dir" +# echo "libsndfile_lib_location : $libsndfile_lib_location" +# echo "sndfile_oct_location : $sndfile_oct_location" + +if test ! -f PKG_ADD ; then + cp $octave_src_dir/PKG_ADD . + fi + +export LD_LIBRARY_PATH="$libsndfile_lib_location:$LD_LIBRARY_PATH" + +octave_script="$octave_src_dir/octave_test.m" + +(cd $sndfile_oct_location && octave -qH $octave_script) +res=$? +echo +exit $res diff --git a/extern/libsndfile-modified/Octave/sndfile.cc b/extern/libsndfile-modified/Octave/sndfile.cc new file mode 100644 index 000000000..6e9cd44cc --- /dev/null +++ b/extern/libsndfile-modified/Octave/sndfile.cc @@ -0,0 +1,405 @@ +/* +** Copyright (C) 2007-2011 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include + +#include "sndfile.h" + +#define FOUR_GIG (0x100000000LL) +#define BUFFER_FRAMES 8192 + + +static int format_of_str (const std::string & fmt) ; +static void string_of_format (std::string & fmt, int format) ; + + +DEFUN_DLD (sfversion, args, nargout , +"-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{version} =} sfversion ()\n\ +@cindex Reading sound files\n\ +Return a string containing the libsndfile version.\n\ +@seealso{sfread, sfwrite}\n\ +@end deftypefn") +{ char buffer [256] ; + octave_value_list retval ; + + /* Bail out if the input parameters are bad. */ + if (args.length () != 0 || nargout > 1) + { print_usage () ; + return retval ; + } ; + + sf_command (NULL, SFC_GET_LIB_VERSION, buffer, sizeof (buffer)) ; + + std::string version (buffer) ; + + retval.append (version) ; + return retval ; +} /* sfversion */ + + +DEFUN_DLD (sfread, args, nargout , +"-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{data},@var{srate},@var{format} =} sfread (@var{filename})\n\ +@cindex Reading sound files\n\ +Read a sound file from disk using libsndfile.\n\ +@seealso{sfversion, sfwrite}\n\ +@end deftypefn") +{ SNDFILE * file ; + SF_INFO sfinfo ; + + octave_value_list retval ; + + int nargin = args.length () ; + + /* Bail out if the input parameters are bad. */ + if ((nargin != 1) || !args (0) .is_string () || nargout < 1 || nargout > 3) + { print_usage () ; + return retval ; + } ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + std::string filename = args (0).string_value () ; + + if ((file = sf_open (filename.c_str (), SFM_READ, &sfinfo)) == NULL) + { error ("sfread: couldn't open file %s : %s", filename.c_str (), sf_strerror (NULL)) ; + return retval ; + } ; + + if (sfinfo.frames > FOUR_GIG) + printf ("This is a really huge file (%lld frames).\nYou may run out of memory trying to load it.\n", (long long) sfinfo.frames) ; + + dim_vector dim = dim_vector () ; + dim.resize (2) ; + dim (0) = sfinfo.frames ; + dim (1) = sfinfo.channels ; + + /* Should I be using Matrix instead? */ + NDArray out (dim, 0.0) ; + + float buffer [BUFFER_FRAMES * sfinfo.channels] ; + int readcount ; + sf_count_t total = 0 ; + + do + { readcount = sf_readf_float (file, buffer, BUFFER_FRAMES) ; + + /* Make sure we don't read more frames than we allocated. */ + if (total + readcount > sfinfo.frames) + readcount = sfinfo.frames - total ; + + for (int ch = 0 ; ch < sfinfo.channels ; ch++) + { for (int k = 0 ; k < readcount ; k++) + out (total + k, ch) = buffer [k * sfinfo.channels + ch] ; + } ; + + total += readcount ; + } while (readcount > 0 && total < sfinfo.frames) ; + + retval.append (out.squeeze ()) ; + + if (nargout >= 2) + retval.append ((octave_uint32) sfinfo.samplerate) ; + + if (nargout >= 3) + { std::string fmt ("") ; + string_of_format (fmt, sfinfo.format) ; + retval.append (fmt) ; + } ; + + /* Clean up. */ + sf_close (file) ; + + return retval ; +} /* sfread */ + +DEFUN_DLD (sfwrite, args, nargout , +"-*- texinfo -*-\n\ +@deftypefn {Function File} sfwrite (@var{filename},@var{data},@var{srate},@var{format})\n\ +Write a sound file to disk using libsndfile.\n\ +@seealso{sfread, sfversion}\n\ +@end deftypefn\n\ +") +{ SNDFILE * file ; + SF_INFO sfinfo ; + + octave_value_list retval ; + + int nargin = args.length () ; + + /* Bail out if the input parameters are bad. */ + if (nargin != 4 || !args (0).is_string () || !args (1).is_real_matrix () + || !args (2).is_real_scalar () || !args (3).is_string () + || nargout != 0) + { print_usage () ; + return retval ; + } ; + + std::string filename = args (0).string_value () ; + std::string format = args (3).string_value () ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + sfinfo.format = format_of_str (format) ; + if (sfinfo.format == 0) + { error ("Bad format '%s'", format.c_str ()) ; + return retval ; + } ; + + sfinfo.samplerate = lrint (args (2).scalar_value ()) ; + if (sfinfo.samplerate < 1) + { error ("Bad sample rate : %d.\n", sfinfo.samplerate) ; + return retval ; + } ; + + Matrix data = args (1).matrix_value () ; + long rows = args (1).rows () ; + long cols = args (1).columns () ; + + if (cols > rows) + { error ("Audio data should have one column per channel, but supplied data " + "has %ld rows and %ld columns.\n", rows, cols) ; + return retval ; + } ; + + sfinfo.channels = cols ; + + if ((file = sf_open (filename.c_str (), SFM_WRITE, &sfinfo)) == NULL) + { error ("Couldn't open file %s : %s", filename.c_str (), sf_strerror (NULL)) ; + return retval ; + } ; + + float buffer [BUFFER_FRAMES * sfinfo.channels] ; + int writecount ; + long total = 0 ; + + do + { + writecount = BUFFER_FRAMES ; + + /* Make sure we don't read more frames than we allocated. */ + if (total + writecount > rows) + writecount = rows - total ; + + for (int ch = 0 ; ch < sfinfo.channels ; ch++) + { for (int k = 0 ; k < writecount ; k++) + buffer [k * sfinfo.channels + ch] = data (total + k, ch) ; + } ; + + if (writecount > 0) + sf_writef_float (file, buffer, writecount) ; + + total += writecount ; + } while (writecount > 0 && total < rows) ; + + /* Clean up. */ + sf_close (file) ; + + return retval ; +} /* sfwrite */ + + +static void +str_split (const std::string & str, const std::string & delim, std::vector & output) +{ + unsigned int offset = 0 ; + size_t delim_index = 0 ; + + delim_index = str.find (delim, offset) ; + + while (delim_index != std::string::npos) + { + output.push_back (str.substr(offset, delim_index - offset)) ; + offset += delim_index - offset + delim.length () ; + delim_index = str.find (delim, offset) ; + } + + output.push_back (str.substr (offset)) ; +} /* str_split */ + +static int +hash_of_str (const std::string & str) +{ + int hash = 0 ; + + for (unsigned k = 0 ; k < str.length () ; k++) + hash = (hash * 3) + tolower (str [k]) ; + + return hash ; +} /* hash_of_str */ + +static int +major_format_of_hash (const std::string & str) +{ int hash ; + + hash = hash_of_str (str) ; + + switch (hash) + { + case 0x5c8 : /* 'wav' */ return SF_FORMAT_WAV ; + case 0xf84 : /* 'aiff' */ return SF_FORMAT_AIFF ; + case 0x198 : /* 'au' */ return SF_FORMAT_AU ; + case 0x579 : /* 'paf' */ return SF_FORMAT_PAF ; + case 0x5e5 : /* 'svx' */ return SF_FORMAT_SVX ; + case 0x1118 : /* 'nist' */ return SF_FORMAT_NIST ; + case 0x5d6 : /* 'voc' */ return SF_FORMAT_VOC ; + case 0x324a : /* 'ircam' */ return SF_FORMAT_IRCAM ; + case 0x505 : /* 'w64' */ return SF_FORMAT_W64 ; + case 0x1078 : /* 'mat4' */ return SF_FORMAT_MAT4 ; + case 0x1079 : /* 'mat5' */ return SF_FORMAT_MAT5 ; + case 0x5b8 : /* 'pvf' */ return SF_FORMAT_PVF ; + case 0x1d1 : /* 'xi' */ return SF_FORMAT_XI ; + case 0x56f : /* 'htk' */ return SF_FORMAT_HTK ; + case 0x5aa : /* 'sds' */ return SF_FORMAT_SDS ; + case 0x53d : /* 'avr' */ return SF_FORMAT_AVR ; + case 0x11d0 : /* 'wavx' */ return SF_FORMAT_WAVEX ; + case 0x569 : /* 'sd2' */ return SF_FORMAT_SD2 ; + case 0x1014 : /* 'flac' */ return SF_FORMAT_FLAC ; + case 0x504 : /* 'caf' */ return SF_FORMAT_CAF ; + case 0x5f6 : /* 'wve' */ return SF_FORMAT_WVE ; + default : break ; + } ; + + printf ("%s : hash '%s' -> 0x%x\n", __func__, str.c_str (), hash) ; + + return 0 ; +} /* major_format_of_hash */ + +static int +minor_format_of_hash (const std::string & str) +{ int hash ; + + hash = hash_of_str (str) ; + + switch (hash) + { + case 0x1085 : /* 'int8' */ return SF_FORMAT_PCM_S8 ; + case 0x358a : /* 'uint8' */ return SF_FORMAT_PCM_U8 ; + case 0x31b0 : /* 'int16' */ return SF_FORMAT_PCM_16 ; + case 0x31b1 : /* 'int24' */ return SF_FORMAT_PCM_24 ; + case 0x31b2 : /* 'int32' */ return SF_FORMAT_PCM_32 ; + case 0x3128 : /* 'float' */ return SF_FORMAT_FLOAT ; + case 0x937d : /* 'double' */ return SF_FORMAT_DOUBLE ; + case 0x11bd : /* 'ulaw' */ return SF_FORMAT_ULAW ; + case 0xfa1 : /* 'alaw' */ return SF_FORMAT_ALAW ; + case 0xfc361 : /* 'ima_adpcm' */ return SF_FORMAT_IMA_ADPCM ; + case 0x5739a : /* 'ms_adpcm' */ return SF_FORMAT_MS_ADPCM ; + case 0x9450 : /* 'gsm610' */ return SF_FORMAT_GSM610 ; + case 0x172a3 : /* 'g721_32' */ return SF_FORMAT_G721_32 ; + case 0x172d8 : /* 'g723_24' */ return SF_FORMAT_G723_24 ; + case 0x172da : /* 'g723_40' */ return SF_FORMAT_G723_40 ; + default : break ; + } ; + + printf ("%s : hash '%s' -> 0x%x\n", __func__, str.c_str (), hash) ; + + return 0 ; +} /* minor_format_of_hash */ + + +static const char * +string_of_major_format (int format) +{ + switch (format & SF_FORMAT_TYPEMASK) + { + case SF_FORMAT_WAV : return "wav" ; + case SF_FORMAT_AIFF : return "aiff" ; + case SF_FORMAT_AU : return "au" ; + case SF_FORMAT_PAF : return "paf" ; + case SF_FORMAT_SVX : return "svx" ; + case SF_FORMAT_NIST : return "nist" ; + case SF_FORMAT_VOC : return "voc" ; + case SF_FORMAT_IRCAM : return "ircam" ; + case SF_FORMAT_W64 : return "w64" ; + case SF_FORMAT_MAT4 : return "mat4" ; + case SF_FORMAT_MAT5 : return "mat5" ; + case SF_FORMAT_PVF : return "pvf" ; + case SF_FORMAT_XI : return "xi" ; + case SF_FORMAT_HTK : return "htk" ; + case SF_FORMAT_SDS : return "sds" ; + case SF_FORMAT_AVR : return "avr" ; + case SF_FORMAT_WAVEX : return "wavx" ; + case SF_FORMAT_SD2 : return "sd2" ; + case SF_FORMAT_FLAC : return "flac" ; + case SF_FORMAT_CAF : return "caf" ; + case SF_FORMAT_WVE : return "wfe" ; + default : break ; + } ; + + return "unknown" ; +} /* string_of_major_format */ + +static const char * +string_of_minor_format (int format) +{ + switch (format & SF_FORMAT_SUBMASK) + { + case SF_FORMAT_PCM_S8 : return "int8" ; + case SF_FORMAT_PCM_U8 : return "uint8" ; + case SF_FORMAT_PCM_16 : return "int16" ; + case SF_FORMAT_PCM_24 : return "int24" ; + case SF_FORMAT_PCM_32 : return "int32" ; + case SF_FORMAT_FLOAT : return "float" ; + case SF_FORMAT_DOUBLE : return "double" ; + case SF_FORMAT_ULAW : return "ulaw" ; + case SF_FORMAT_ALAW : return "alaw" ; + case SF_FORMAT_IMA_ADPCM : return "ima_adpcm" ; + case SF_FORMAT_MS_ADPCM : return "ms_adpcm" ; + case SF_FORMAT_GSM610 : return "gsm610" ; + case SF_FORMAT_G721_32 : return "g721_32" ; + case SF_FORMAT_G723_24 : return "g723_24" ; + case SF_FORMAT_G723_40 : return "g723_40" ; + default : break ; + } ; + + return "unknown" ; +} /* string_of_minor_format */ + +static int +format_of_str (const std::string & fmt) +{ + std::vector split ; + + str_split (fmt, "-", split) ; + + if (split.size () != 2) + return 0 ; + + int major_fmt = major_format_of_hash (split.at (0)) ; + if (major_fmt == 0) + return 0 ; + + int minor_fmt = minor_format_of_hash (split.at (1)) ; + if (minor_fmt == 0) + return 0 ; + + return major_fmt | minor_fmt ; +} /* format_of_str */ + +static void +string_of_format (std::string & fmt, int format) +{ + char buffer [64] ; + + snprintf (buffer, sizeof (buffer), "%s-%s", string_of_major_format (format), string_of_minor_format (format)) ; + + fmt = buffer ; + + return ; +} /* string_of_format */ diff --git a/extern/libsndfile-modified/Octave/sndfile_load.m b/extern/libsndfile-modified/Octave/sndfile_load.m new file mode 100644 index 000000000..c66198fa3 --- /dev/null +++ b/extern/libsndfile-modified/Octave/sndfile_load.m @@ -0,0 +1,52 @@ +## Copyright (C) 2002-2011 Erik de Castro Lopo +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2, or (at your option) +## any later version. +## +## This program is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this file. If not, write to the Free Software Foundation, +## 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {} sndfile_load (@var{filename}) +## Load data from the file given by @var{filename}. +## @end deftypefn + +## Author: Erik de Castro Lopo +## Description: Load the sound data from the given file name + +function [data fs] = sndfile_load (filename) + +if (nargin != 1), + error ("Need an input filename") ; + endif + +samplerate = -1 ; +samplingrate = -1 ; +wavedata = -1 ; + + +eval (sprintf ('load -f %s', filename)) ; + +if (samplerate > 0), + fs = samplerate ; +elseif (samplingrate > 0), + fs = samplingrate ; +else + error ("Not able to find sample rate.") ; + endif + +if (max (size (wavedata)) > 1), + data = wavedata ; +else + error ("Not able to find waveform data.") ; + endif + +endfunction diff --git a/extern/libsndfile-modified/Octave/sndfile_play.m b/extern/libsndfile-modified/Octave/sndfile_play.m new file mode 100644 index 000000000..e8a34a74c --- /dev/null +++ b/extern/libsndfile-modified/Octave/sndfile_play.m @@ -0,0 +1,59 @@ +## Copyright (C) 2002-2011 Erik de Castro Lopo +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2, or (at your option) +## any later version. +## +## This program is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this file. If not, write to the Free Software Foundation, +## 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {} sndfile_play (@var{data, fs}) +## Play @var{data} at sample rate @var{fs} using the sndfile-play +## program. +## @end deftypefn + +## Author: Erik de Castro Lopo +## Description: Play the given data as a sound file + +function sndfile_play (data, fs) + +if nargin != 2, + error ("Need two input arguments: data and fs.") ; + endif + +if (max (size (fs)) > 1), + error ("Second parameter fs must be a single value.") ; + endif + +[nr nc] = size (data) ; + +if (nr > nc), + data = data' ; + endif + +samplerate = fs ; +wavedata = data ; + +filename = tmpnam () ; + +cmd = sprintf ("save -mat-binary %s fs data", filename) ; + +eval (cmd) ; + +cmd = sprintf ("sndfile-play %s", filename) ; + +[output, status] = system (cmd) ; + +if (status), + disp (outout) ; + endif + +endfunction diff --git a/extern/libsndfile-modified/Octave/sndfile_save.m b/extern/libsndfile-modified/Octave/sndfile_save.m new file mode 100644 index 000000000..5b7e7c7d0 --- /dev/null +++ b/extern/libsndfile-modified/Octave/sndfile_save.m @@ -0,0 +1,53 @@ +## Copyright (C) 2002-2011 Erik de Castro Lopo +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 2, or (at your option) +## any later version. +## +## This program is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this file. If not, write to the Free Software Foundation, +## 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +## -*- texinfo -*- +## @deftypefn {Function File} {} sndfile_save (@var{filename, data, fs}) +## Save the given @var{data} as audio data to the given at @var{fs}. Set +## the sample rate to @var{fs}. +## @end deftypefn + +## Author: Erik de Castro Lopo +## Description: Save data as a sound file + +function sndfile_save (filename, data, fs) + +if nargin != 3, + error ("Need three input arguments: filename, data and fs.") ; + endif + +if (! isstr (filename)), + error ("First parameter 'filename' is must be a string.") ; + endif + +if (max (size (fs)) > 1), + error ("Second parameter 'fs' must be a single value, not an array or matrix.") ; + endif + +[nr nc] = size (data) ; + +if (nr > nc), + data = data' ; + endif + +samplerate = fs ; +wavedata = data ; + +str = sprintf ("save -mat-binary %s samplerate wavedata", filename) ; + +eval (str) ; + +endfunction diff --git a/extern/libsndfile-modified/README b/extern/libsndfile-modified/README new file mode 100644 index 000000000..a24ad277b --- /dev/null +++ b/extern/libsndfile-modified/README @@ -0,0 +1,78 @@ +NOTICE: THIS IS A MODIFIED VERSION OF LIBSNDFILE WHICH FIXES COMPILATION WHEN USING CMAKE 4.0. + +--- + +libsndfile is a library of C routines for reading and writing +files containing sampled audio data. + +The src/ directory contains the source code for library itself. + +The doc/ directory contains the libsndfile documentation. + +The examples/ directory contains examples of how to write code using +libsndfile. + +The tests/ directory contains programs which link against libsndfile +and test its functionality. + +The src/GSM610 directory contains code written by Jutta Degener and Carsten +Bormann. Their original code can be found at : + http://kbs.cs.tu-berlin.de/~jutta/toast.html + +The src/G72x directory contains code written and released by Sun Microsystems +under a suitably free license. + +The src/ALAC directory contains code written and released by Apple Inc and +released under the Apache license. + + +LINUX +----- +Wherever possible, you should use the packages supplied by your Linux +distribution. + +If you really do need to compile from source it should be as easy as: + + ./configure + make + make install + +Since libsndfile optionally links against libFLAC, libogg, libvorbis and +libopus, you will need to install appropriate versions of these libraries +before running configure as above. + +You can use CMake now to build under Linux, also under Windows and MacOS, see +README.md for details. CMake toolchain is usable, but still exterimental. + + +UNIX +---- +Compile as for Linux. + + +Win32/Win64 +----------- + +Official Windows binaries are compiled with Autotools and MinGW, but you can use +CMake to generate solution for Visual Studio. Details are described in +README.md. + +It is still recommended to use the libsndfile binaries available on the +libsndfile web site. + +MacOSX +------ +Building on MacOSX should be the same as building it on any other Unix. + + +CONTACTS +-------- + +libsndfile was written by Erik de Castro Lopo (erikd AT mega-nerd DOT com). +The libsndfile home page is at : + + http://libsndfile.github.io/libsndfile/ + +Bugs and support questions can be raised at : + + https://github.com/libsndfile/libsndfile/issues diff --git a/extern/libsndfile-modified/README.md b/extern/libsndfile-modified/README.md new file mode 100644 index 000000000..31019a4bc --- /dev/null +++ b/extern/libsndfile-modified/README.md @@ -0,0 +1,319 @@ +NOTICE: THIS IS A MODIFIED VERSION OF LIBSNDFILE WHICH FIXES COMPILATION WHEN USING CMAKE 4.0. + +--- + +# libsndfile + +![C/C++ CI](https://github.com/libsndfile/libsndfile/workflows/C/C++%20CI/badge.svg) + +libsndfile is a C library for reading and writing files containing sampled audio +data. + +## Authors + +The libsndfile project was originally developed and maintained by +Erik de Castro Lopo aka @erikd. The project was developed +on Github at . + +After the release of version 1.0.30, @erikd transferred the project to +[the libsndfile team](https://github.com/libsndfile), see [AUTHORS](AUTHORS) +for details. + +## Hacking + +The canonical source code repository for libsndfile is at +. + +You can grab the source code using: + + git clone https://github.com/libsndfile/libsndfile.git + +For building for Android see [BuildingForAndroid][BuildingForAndroid]. + +There are currently two build systems: the traditional GNU autotool based one and +modern CMake based build system. Use of the CMake build system is documented +below. + +Setting up a build environment for libsndfile on Debian or Ubuntu is as simple as: + + sudo apt install autoconf autogen automake build-essential libasound2-dev \ + libflac-dev libogg-dev libtool libvorbis-dev libopus-dev libmp3lame-dev \ + libmpg123-dev pkg-config python + +For other Linux distributions or any of the *BSDs, the setup should be similar +although the package install tools and package names may be slightly different. + +Similarly on Mac OS X, assuming [brew] is already installed: + + brew install autoconf autogen automake flac libogg libtool libvorbis opus mpg123 pkg-config + +Once the build environment has been set up, building and testing libsndfile is +as simple as: + + autoreconf -vif + ./configure --enable-werror + make + make check + +## The CMake build system + +Although Autotools is the primary and recommended build toolchain, CMake meta +build generator is also available. The build process with CMake takes +place in two stages. First, standard build files are created from configuration +scripts. Then the platform's native build tools are used for the actual +building. CMake can produce Microsoft Visual Studio project and solution files, +Unix Makefiles, Xcode projects and [many more](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html). + +Some IDE support CMake natively or with plugins, check you IDE documentation + for details. + +### Requirements + +1. C99-compliant compiler toolchain (tested with GCC, Clang and Visual + Studio 2015) +2. CMake 3.1.3 or newer + +There are some recommended packages to enable all features of libsndfile: + +1. Ogg, Vorbis and FLAC libraries and headers to enable these formats support +2. ALSA development package under Linux to build sndfile-play utility +3. Sndio development package under BSD to build sndfile-play utility + +### Building from command line + +CMake can handle out-of-place builds, enabling several builds from +the same source tree, and cross-compilation. The ability to build a directory +tree outside the source tree is a key feature, ensuring that if a build +directory is removed, the source files remain unaffected. + + mkdir CMakeBuild + cd CMakeBuild + +Then run `cmake` command with directory where CMakeLists.txt script is located +as argument (relative paths are supported): + + cmake .. + +This command will configure and write build script or solution to CMakeBuild +directory. CMake is smart enough to create Unix makefiles under Linux or Visual +Studio solution if you have Visual Studio installed, but you can configure +[generator](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html) +with `-G` command line parameter: + + cmake .. -G"Unix Makefiles" + +The build procedure depends on the selected generator. With "Unix Makefiles" you +can type: + + make & make install + +With "Visual Studio" and some other generators you can open solution or project +from `CMakeBuild` directory and build using IDE. + +Finally, you can use unified command: + + cmake --build . + +CMake also provides Qt-based cross platform GUI, cmake-gui. Using it is trivial +and does not require detailed explanations. + +### Configuring CMake + +You can pass additional options with `/D=` when you run +`cmake` command. Some useful system options: + +* `CMAKE_C_FLAGS` - additional C compiler flags +* `CMAKE_BUILD_TYPE` - configuration type, `DEBUG`, `RELEASE`, `RELWITHDEBINFO` + or `MINSIZEREL`. `DEBUG` is default +* `CMAKE_INSTALL_PREFIX` - build install location, the same as `--prefix` option + of `configure` script + + Useful libsndfile options: + +* `BUILD_SHARED_LIBS` - build shared library (DLL under Windows) when `ON`, + build static library othervise. This option is `OFF` by default. +* `BUILD_PROGRAMS` - build libsndfile's utilities from `programs/` directory, + `ON` by default. +* `BUILD_EXAMPLES` - build examples, `ON` by default. +* `BUILD_TESTING` - build tests. Then you can run tests with `ctest` command, + `ON` by default. Setting `BUILD_SHARED_LIBS` to `ON` disables this option. +* `ENABLE_EXTERNAL_LIBS` - enable Ogg, Vorbis, FLAC and Opus support. This + option is available and set to `ON` if all dependency libraries were found. +* `ENABLE_MPEG` - MP3 support. This option is available and set to `ON` if all + dependency libraries were found. +* `ENABLE_CPU_CLIP` - enable tricky cpu specific clipper. Enabled and set to + `ON` when CPU clips negative\positive. Don't touch it if you are not sure +* `ENABLE_BOW_DOCS` - enable black-on-white documentation theme, `OFF` by + default. +* `ENABLE_EXPERIMENTAL` - enable experimental code. Don't use it if you are + not sure. This option is `OFF` by default. +* `ENABLE_CPACK` - enable [CPack](https://cmake.org/cmake/help/latest/module/CPack.html) support. + This option is `ON` by default. +* `ENABLE_PACKAGE_CONFIG` - generate and install [package config file](https://cmake.org/cmake/help/latest/manual/cmake-packages.7.html#config-file-packages). +* `INSTALL_PKGCONFIG_MODULE` - generate and install [pkg-config module](https://people.freedesktop.org/~dbn/pkg-config-guide.html). +* `INSTALL_MANPAGES` - install [man pages](https://en.wikipedia.org/wiki/Man_page) for programs. This option is `ON` by default +* `ENABLE_STATIC_RUNTIME` - enable static runtime on Windows platform (MSVC and + MinGW), `OFF` by default. + + **Note**: For MSVC compiler this option is deprecated for CMake >= 3.15, see + policy [CMP0091](https://cmake.org/cmake/help/latest/policy/CMP0091.html). + Use `CMAKE_MSVC_RUNTIME_LIBRARY` option instead. + + **Note**: For MinGW toolchain this option is experimental. If you enabled it + and then disabled again, you need to clear CMake cache (delete CMakeCache.txt). +* `ENABLE_COMPATIBLE_LIBSNDFILE_NAME` - set DLL name to `libsndfile-1.dll` + (canonical name) on Windows platform, `sndfile.dll` otherwise, `OFF` by + default. Library name can be different depending on platform. The well known + DLL name on Windows platform is `libsndfile-1.dll`, because the only way to + build Windows library before was MinGW toolchain with Autotools. This name + is native for MinGW ecosystem, Autotools constructs it using MinGW platform + rules from `sndfile` target. But when you build with CMake using native + Windows compiler, the name is `sndfile.dll`. This is name for native Windows + platform, because Windows has no library naming rules. It is preffered + because you can search library using package manager or CMake's + `find_library` command on any platform using the same `sndfile` name. + +* `ENABLE_SSE2` - add compiler flag to enable SSE2 if required, `ON` by default. + + This option is for X86 and GCC compatible compilers configurations only. + + If you compile for other SIMD set, e.g. AVX2, you may want to set + `ENABLE_SSE2` to `OFF`. + + **Note**: This option is not active for X64 configuration, because SSE2 is + always available in this mode and all optimizations are enabled by default. + +Deprecated options: + +* `DISABLE_EXTERNAL_LIBS` - disable Ogg, Vorbis and FLAC support. Replaced by + `ENABLE_EXTERNAL_LIBS` +* `DISABLE_CPU_CLIP` - disable tricky cpu specific clipper. Replaced by + `ENABLE_CPU_CLIP` +* `BUILD_STATIC_LIBS` - build static library. Use `BUILD_SHARED_LIBS` instead + +### Linking from CMake projects + +First you need to add `FindOgg.cmake`, `FindVorbis.cmake`, `FindFLAC.cmake` and +`FindOpus.cmake` files to some directory inside your CMake project (usually +`cmake`) and add it to `CMAKE_MODULE_PATH`: + + project(SomeApplication) + + list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) + +Now you can search `libsndfile` library from your `CMakeLists.txt` + with this command: + + find_package(SndFile) + +`SndFile_FOUND` is set to `ON` when library is found. + +If `libsndfile` dependency is critical, you can add `REQUIRED` to + `find_package`: + + find_package(SndFile REQUIRED) + +With with option `find_package` will terminate configuration process + if `libsndfile` is not found. + +You can also add version check: + + find_package(SndFile 1.0.29) + +`find_package` will report error, if `libsndfile` version is < 1.0.29. + +You can combine `REQUIRED` and version if you need. + +To link `libsndfile` library use: + + target_link_libraries(my_application PRIVATE SndFile::sndfile) + +### Notes for Windows users + +#### System CRT library + +First advice about Visual Studio [system CRT libraries](https://docs.microsoft.com/en-us/cpp/c-runtime-library/c-run-time-library-reference?view=vs-2019), +it is system code linked as static or dynamic library to every C application. + +You can find related option in Visual Studio project properties: + + C/C++ -> Code Generation -> Runtime Library + +Dynamic version of system CRT library is default and it means that end user needs +to have the same runtime library installed on his system. Most likely it is so, +but if it is not, the user will see this error message using libsndfile DLL: + + "The program can't start because .dll is missing from your computer. Try reinstalling the program to fix this problem. " + +To avoid this, you may want to enable static CRT library linking. In this case +the size of your DLL will increase slightly the size will increase slightly, but +you can redistribute the libsndfile DLL without having to install the correct +version of the system CRT library. + +CMake project will use dynamic system CRT libraries by default, just like +Visual Studio does. But you can change it using `ENABLE_STATIC_RUNTIME` or +`CMAKE_MSVC_RUNTIME_LIBRARY` options. + +**Note**: You cannot use both options at the same time, it will lead to a +configuration error. + +If you have CMake >= 3.15 you should use +[`CMAKE_MSVC_RUNTIME_LIBRARY`](https://cmake.org/cmake/help/v3.15/variable/CMAKE_MSVC_RUNTIME_LIBRARY.html) option. + +This will enable static linking: + + cmake .. -D"MultiThreaded$<$:Debug>" + +You can use libsndfile `ENABLE_STATIC_RUNTIME` option to to control CRT library +linking for CMake project: `OFF` or unset (default) for dynamic, and `ON` for +static linking: + + cmake .. -DENABLE_STATIC_RUNTIME=ON + +**Note**: This option is deprecated and may be removed in far future because we +have standard option `CMAKE_MSVC_RUNTIME_LIBRARY` now. + +#### Using Vcpkg package manager + +Second advice is about Ogg, Vorbis FLAC and Opus support. Searching external +libraries under Windows is a little bit tricky. The best way is to use +[Vcpkg](https://github.com/Microsoft/vcpkg). + +Install Vcpkg and then add this parameter to cmake command line: + + -DCMAKE_TOOLCHAIN_FILE=/scripts/buildsystems/vcpkg.cmake + +You also need to set `VCPKG_TARGET_TRIPLET` if you want to use static libraries: + + -DVCPKG_TARGET_TRIPLET=x64-windows-static + +Then you need to install static libogg, libvorbis, libflac, libopus, mpg123 and +mp3lame Vcpkg packages. + +After 1.1.0beta2 you don't need to install dependencies manually. Libsndfile +now supports [Vcpkg manifest mode](https://vcpkg.readthedocs.io/en/latest/users/manifests/) +and all dependencies are installed automatically. + +However, you can turn off the manifest mode and return to the classic mode using +the `VCPKG_MANIFEST_MODE` parameter from the command line: + + -DVCPKG_MANIFEST_MODE=OFF + +In classic mode, you need to install the required libraries manually: + + vcpkg install libvorbis:x64-windows-static libflac:x64-windows-static + opus:x64-windows-static mp3lame:x86-windows-static mpg123:x86-windows-static + libvorbis:x86-windows-static libflac:x86-windows-static + opus:x86-windows-static mp3lame:x86-windows-static mpg123:x86-windows-static + +**Note**: Use must use the same CRT library for external libraries and the +libsndfile library itself. For `*-static` triplets Vcpkg uses +[static CRT](https://vcpkg.readthedocs.io/en/latest/users/triplets/). + +## Submitting Patches + +See [CONTRIBUTING.md](CONTRIBUTING.md) for details. + +[brew]: http://brew.sh/ +[github]: http://libsndfile.github.io/libsndfile/ +[BuildingForAndroid]: https://github.com/libsndfile/libsndfile/blob/master/Building-for-Android.md diff --git a/extern/libsndfile-modified/SECURITY.md b/extern/libsndfile-modified/SECURITY.md new file mode 100644 index 000000000..b75e7be2d --- /dev/null +++ b/extern/libsndfile-modified/SECURITY.md @@ -0,0 +1,11 @@ +# Security Policy + +## Supported Versions + +| Version | Supported | +| ------- | ------------------ | +| 1.1.x | :white_check_mark: | + +## Reporting a Vulnerability + +Please send report privately to evpobr@gmail.com, and include how would you like to be credited. diff --git a/extern/libsndfile-modified/Scripts/android-configure.sh b/extern/libsndfile-modified/Scripts/android-configure.sh new file mode 100755 index 000000000..accb386ca --- /dev/null +++ b/extern/libsndfile-modified/Scripts/android-configure.sh @@ -0,0 +1,96 @@ +#!/bin/bash -e + +# Copyright (C) 2013-2016 Erik de Castro Lopo +# +# All rights reserved. +# +# 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. +# * Neither the author nor the names of any 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 COPYRIGHT OWNER 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. + +# Android NDK version number; eg r10, r10b etc +ANDROID_NDK_VER=${ANDROID_NDK_VER:-r10} + +# Android NDK gcc version; eg 4.8, 4.9 etc. +ANDROID_GCC_VER=${ANDROID_GCC_VER:-4.9} + +# Android API version; eg 14 (Android 4.0), 21 (Android 5.0) etc. +ANDROID_API_VER=${ANDROID_API_VER:-14} + +ANDROID_TARGET=${ANDROID_TARGET:-arm-linux-androideabi} + +if test -z ${ANDROID_TOOLCHAIN_HOME} ; then + echo "Environment variable ANDROID_TOOLCHAIN_HOME not defined." + echo "This should point to the directory containing the Android NDK." + exit 1 + fi + +#------------------------------------------------------------------------------- +# No more user config beyond here. + +BUILD_MACHINE=$(uname -s | tr 'A-Z' 'a-z')-$(uname -m) + +function die_with { + echo $1 + exit 1 +} + +export CROSS_COMPILE=${ANDROID_TARGET} + +# Don't forget to adjust this to your NDK path +export ANDROID_NDK=${ANDROID_TOOLCHAIN_HOME}/android-ndk-${ANDROID_NDK_VER} +test -d ${ANDROID_NDK} || die_with "Error : ANDROID_NDK '$ANDROID_NDK' does not exist." + +export ANDROID_PREFIX=${ANDROID_NDK}/toolchains/arm-linux-androideabi-${ANDROID_GCC_VER}/prebuilt/${BUILD_MACHINE} +test -d ${ANDROID_PREFIX} || die_with "Error : ANDROID_PREFIX '$ANDROID_PREFIX' does not exist." + +export SYSROOT=${ANDROID_NDK}/platforms/android-${ANDROID_API_VER}/arch-arm +test -d ${SYSROOT} || die_with "Error : SYSROOT '$SYSROOT' does not exist." + +export CROSS_PREFIX=${ANDROID_PREFIX}/bin/${CROSS_COMPILE} +test -f ${CROSS_PREFIX}-gcc || die_with "Error : CROSS_PREFIX compiler '${CROSS_PREFIX}-gcc' does not exist." + + +# Non-exhaustive lists of compiler + binutils +# Depending on what you compile, you might need more binutils than that +export CPP=${CROSS_PREFIX}-cpp +export AR=${CROSS_PREFIX}-ar +export AS=${CROSS_PREFIX}-as +export NM=${CROSS_PREFIX}-nm +export CC=${CROSS_PREFIX}-gcc +export CXX=${CROSS_PREFIX}-g++ +export LD=${CROSS_PREFIX}-ld +export RANLIB=${CROSS_PREFIX}-ranlib + +# Don't mix up .pc files from your host and build target +export PKG_CONFIG_PATH=${PREFIX}/lib/pkgconfig + +# Set up the needed FLAGS. +export CFLAGS="${CFLAGS} -gstabs --sysroot=${SYSROOT} -I${SYSROOT}/usr/include -I${ANDROID_PREFIX}/include" +export CXXFLAGS="${CXXFLAGS} -gstabs -fno-exceptions --sysroot=${SYSROOT} -I${SYSROOT}/usr/include -I${ANDROID_PREFIX}/include -I${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_GCC_VER}/include/ -I${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_GCC_VER}/libs/armeabi/include" + +export CPPFLAGS="${CFLAGS}" +export LDFLAGS="${LDFLAGS} -L${SYSROOT}/usr/lib -L${ANDROID_PREFIX}/lib" + +# Create a symlink to the gdbclient. +test -h gdbclient || ln -s ${ANDROID_PREFIX}/bin/arm-linux-androideabi-gdb gdbclient + +./configure --host=${CROSS_COMPILE} --with-sysroot=${SYSROOT} "$@" diff --git a/extern/libsndfile-modified/Scripts/asan-configure.sh b/extern/libsndfile-modified/Scripts/asan-configure.sh new file mode 100755 index 000000000..0ac43b946 --- /dev/null +++ b/extern/libsndfile-modified/Scripts/asan-configure.sh @@ -0,0 +1,4 @@ +#!/bin/bash -eu + +CFLAGS="-fsanitize=address -g" CXXFLAGS=${CFLAGS} ./configure + diff --git a/extern/libsndfile-modified/Scripts/build-test-tarball.mk.in b/extern/libsndfile-modified/Scripts/build-test-tarball.mk.in new file mode 100644 index 000000000..5dac9d94b --- /dev/null +++ b/extern/libsndfile-modified/Scripts/build-test-tarball.mk.in @@ -0,0 +1,61 @@ +#!/usr/bin/make -f + +# This is probably only going to work with GNU Make. +# This in a separate file instead of in Makefile.am because Automake complains +# about the GNU Make-isms. + +EXEEXT = @EXEEXT@ + +PACKAGE_VERSION = @PACKAGE_VERSION@ + +HOST_TRIPLET = @HOST_TRIPLET@ + +SRC_BINDIR = @SRC_BINDIR@ +TEST_BINDIR = @TEST_BINDIR@ + +LIBRARY := $(SRC_BINDIR)libsndfile.so.$(LIB_VERSION) + +LIB_VERSION := $(shell echo $(PACKAGE_VERSION) | sed -e 's/[a-z].*//') + +TESTNAME = libsndfile-testsuite-$(HOST_TRIPLET)-$(PACKAGE_VERSION) + +TARBALL = $(TESTNAME).tar.gz + +# Find the test programs by grepping the script for the programs it executes. +testprogs := $(shell grep '^\./' tests/test_wrapper.sh | sed -e "s|./||" -e "s/ .*//" | sort | uniq) +# Also add the programs not found by the above. +testprogs += tests/sfversion$(EXEEXT) tests/stdin_test$(EXEEXT) tests/stdout_test$(EXEEXT) \ + tests/cpp_test$(EXEEXT) tests/win32_test$(EXEEXT) + +libfiles := $(shell if test ! -z $(EXEEXT) ; then echo "src/libsndfile-1.def src/.libs/libsndfile-1.dll" ; elif test -f $(LIBRARY) ; then echo $(LIBRARY) ; fi ; fi) + +testbins := $(testprogs) $(libfiles) + +all : $(TARBALL) + +clean : + rm -rf $(TARBALL) $(TESTNAME)/ + +check : $(TESTNAME)/test_wrapper.sh + (cd ./$(TESTNAME)/ && ./test_wrapper.sh) + +$(TARBALL) : $(TESTNAME)/test_wrapper.sh + tar zcf $@ $(TESTNAME) + rm -rf $(TESTNAME) + @echo + @echo "Created : $(TARBALL)" + @echo + +$(TESTNAME)/test_wrapper.sh : tests/test_wrapper.sh tests/pedantic-header-test.sh + rm -rf $(TESTNAME) + mkdir -p $(TESTNAME)/tests/ + echo + echo $(testbins) + echo + cp $(testbins) $(TESTNAME)/tests/ + cp tests/test_wrapper.sh $(TESTNAME)/ + cp tests/pedantic-header-test.sh $(TESTNAME)/tests/ + chmod u+x $@ + +tests/test_wrapper.sh : tests/test_wrapper.sh.in + make $@ diff --git a/extern/libsndfile-modified/Scripts/clang-sanitize.sh b/extern/libsndfile-modified/Scripts/clang-sanitize.sh new file mode 100755 index 000000000..2898883c2 --- /dev/null +++ b/extern/libsndfile-modified/Scripts/clang-sanitize.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +# This is known to work with clang-3.4 from Debian testing/unstable. +# 2013/07/14 + +export CC=clang +export CXX=clang++ +export CFLAGS="-O3 -fsanitize=address,integer,undefined" +export CXXFLAGS="-O3 -fsanitize=address,integer,undefined" + +./configure --enable-gcc-werror + +make clean all check diff --git a/extern/libsndfile-modified/Scripts/cmake-build.sh b/extern/libsndfile-modified/Scripts/cmake-build.sh new file mode 100755 index 000000000..10260f3f0 --- /dev/null +++ b/extern/libsndfile-modified/Scripts/cmake-build.sh @@ -0,0 +1,9 @@ +#!/bin/bash -eu + +rm -rf CMakeCache.txt CMakeFiles/ _Build + +mkdir _Build +cd _Build +cmake .. +cmake --build . +ctest -V diff --git a/extern/libsndfile-modified/Scripts/cstyle.py b/extern/libsndfile-modified/Scripts/cstyle.py new file mode 100755 index 000000000..8e1df27e3 --- /dev/null +++ b/extern/libsndfile-modified/Scripts/cstyle.py @@ -0,0 +1,256 @@ +#!/usr/bin/python -tt +# +# Copyright (C) 2005-2017 Erik de Castro Lopo +# +# Released under the 2 clause BSD license. + +""" +This program checks C code for compliance to coding standards used in +libsndfile and other projects I run. +""" + +import re +import sys + + +class Preprocessor: + """ + Preprocess lines of C code to make it easier for the CStyleChecker class to + test for correctness. Preprocessing works on a single line at a time but + maintains state between consecutive lines so it can preprocessess multi-line + comments. + Preprocessing involves: + - Strip C++ style comments from a line. + - Strip C comments from a series of lines. When a C comment starts and + ends on the same line it will be replaced with 'comment'. + - Replace arbitrary C strings with the zero length string. + - Replace '#define f(x)' with '#define f (c)' (The C #define requires that + there be no space between defined macro name and the open paren of the + argument list). + Used by the CStyleChecker class. + """ + def __init__ (self): + self.comment_nest = 0 + self.leading_space_re = re.compile ('^(\t+| )') + self.trailing_space_re = re.compile ('(\t+| )$') + self.define_hack_re = re.compile ("(#\s*define\s+[a-zA-Z0-9_]+)\(") + + def comment_nesting (self): + """ + Return the currect comment nesting. At the start and end of the file, + this value should be zero. Inside C comments it should be 1 or + (possibly) more. + """ + return self.comment_nest + + def __call__ (self, line): + """ + Strip the provided line of C and C++ comments. Stripping of multi-line + C comments works as expected. + """ + + line = self.define_hack_re.sub (r'\1 (', line) + + line = self.process_strings (line) + + # Strip C++ style comments. + if self.comment_nest == 0: + line = re.sub ("( |\t*)//.*", '', line) + + # Strip C style comments. + open_comment = line.find ('/*') + close_comment = line.find ('*/') + + if self.comment_nest > 0 and close_comment < 0: + # Inside a comment block that does not close on this line. + return "" + + if open_comment >= 0 and close_comment < 0: + # A comment begins on this line but doesn't close on this line. + self.comment_nest += 1 + return self.trailing_space_re.sub ('', line [:open_comment]) + + if open_comment < 0 and close_comment >= 0: + # Currently open comment ends on this line. + self.comment_nest -= 1 + return self.trailing_space_re.sub ('', line [close_comment + 2:]) + + if open_comment >= 0 and close_comment > 0 and self.comment_nest == 0: + # Comment begins and ends on this line. Replace it with 'comment' + # so we don't need to check whitespace before and after the comment + # we're removing. + newline = line [:open_comment] + "comment" + line [close_comment + 2:] + return self.__call__ (newline) + + return line + + def process_strings (self, line): + """ + Given a line of C code, return a string where all literal C strings have + been replaced with the empty string literal "". + """ + for k in range (0, len (line)): + if line [k] == '"': + start = k + for k in range (start + 1, len (line)): + if line [k] == '"' and line [k - 1] != '\\': + return line [:start + 1] + '"' + self.process_strings (line [k + 1:]) + return line + + +class CStyleChecker: + """ + A class for checking the whitespace and layout of a C code. + """ + def __init__ (self, debug): + self.debug = debug + self.filename = None + self.error_count = 0 + self.line_num = 1 + self.orig_line = '' + self.trailing_newline_re = re.compile ('[\r\n]+$') + self.indent_re = re.compile ("^\s*") + self.last_line_indent = "" + self.last_line_indent_curly = False + self.re_checks = \ + [ ( re.compile (" "), "multiple space instead of tab" ) + , ( re.compile ("\t "), "space after tab" ) + , ( re.compile ("[^ ];"), "missing space before semi-colon" ) + , ( re.compile ("{[^\s}]"), "missing space after open brace" ) + , ( re.compile ("[^{\s]}"), "missing space before close brace" ) + , ( re.compile ("[ \t]+$"), "contains trailing whitespace" ) + + , ( re.compile (",[^\s\n]"), "missing space after comma" ) + , ( re.compile (";[^\s]"), "missing space after semi-colon" ) + , ( re.compile ("=[^\s\"'=]"), "missing space after assignment" ) + + # Open and close parenthesis. + , ( re.compile ("[^\s\(\[\*&']\("), "missing space before open parenthesis" ) + , ( re.compile ("\)(-[^>]|[^,'\s\n\)\]-])"), "missing space after close parenthesis" ) + , ( re.compile ("\s(do|for|if|when)\s.*{$"), "trailing open parenthesis at end of line" ) + , ( re.compile ("\( [^;]"), "space after open parenthesis" ) + , ( re.compile ("[^;] \)"), "space before close parenthesis" ) + + # Open and close square brace. + , ( re.compile ("[^\s\(\]]\["), "missing space before open square brace" ) + , ( re.compile ("\][^,\)\]\[\s\.-]"), "missing space after close square brace" ) + , ( re.compile ("\[ "), "space after open square brace" ) + , ( re.compile (" \]"), "space before close square brace" ) + + # Space around operators. + , ( re.compile ("[^\s][\*/%+-][=][^\s]"), "missing space around opassign" ) + , ( re.compile ("[^\s][<>!=^/][=]{1,2}[^\s]"), "missing space around comparison" ) + + # Parens around single argument to return. + , ( re.compile ("\s+return\s+\([a-zA-Z0-9_]+\)\s+;"), "parens around return value" ) + + # Parens around single case argument. + , ( re.compile ("\s+case\s+\([a-zA-Z0-9_]+\)\s+:"), "parens around single case argument" ) + + # Open curly at end of line. + , ( re.compile ("\)\s*{\s*$"), "open curly brace at end of line" ) + + # Pre and post increment/decrment. + , ( re.compile ("[^\(\[][+-]{2}[a-zA-Z0-9_]"), "space after pre increment/decrement" ) + , ( re.compile ("[a-zA-Z0-9_][+-]{2}[^\)\,]]"), "space before post increment/decrement" ) + ] + + def get_error_count (self): + """ + Return the current error count for this CStyleChecker object. + """ + return self.error_count + + def check_files (self, files): + """ + Run the style checker on all the specified files. + """ + for filename in files: + self.check_file (filename) + + def check_file (self, filename): + """ + Run the style checker on the specified file. + """ + self.filename = filename + cfile = open (filename, "r") + + self.line_num = 1 + + preprocess = Preprocessor () + while 1: + line = cfile.readline () + if not line: + break + + line = self.trailing_newline_re.sub ('', line) + self.orig_line = line + + self.line_checks (preprocess (line)) + + self.line_num += 1 + + cfile.close () + self.filename = None + + # Check for errors finding comments. + if preprocess.comment_nesting () != 0: + print ("Weird, comments nested incorrectly.") + sys.exit (1) + + return + + def line_checks (self, line): + """ + Run the style checker on provided line of text, but within the context + of how the line fits within the file. + """ + + indent = len (self.indent_re.search (line).group ()) + if re.search ("^\s+}", line): + if not self.last_line_indent_curly and indent != self.last_line_indent: + None # self.error ("bad indent on close curly brace") + self.last_line_indent_curly = True + else: + self.last_line_indent_curly = False + + # Now all the regex checks. + for (check_re, msg) in self.re_checks: + if check_re.search (line): + self.error (msg) + + if re.search ("[a-zA-Z0-9][<>!=^/&\|]{1,2}[a-zA-Z0-9]", line): + if not re.search (".*#include.*[a-zA-Z0-9]/[a-zA-Z]", line): + self.error ("missing space around operator") + + self.last_line_indent = indent + return + + def error (self, msg): + """ + Print an error message and increment the error count. + """ + print ("%s (%d) : %s" % (self.filename, self.line_num, msg)) + if self.debug: + print ("'" + self.orig_line + "'") + self.error_count += 1 + +#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +if len (sys.argv) < 1: + print ("Usage : yada yada") + sys.exit (1) + +# Create a new CStyleChecker object +if sys.argv [1] == '-d' or sys.argv [1] == '--debug': + cstyle = CStyleChecker (True) + cstyle.check_files (sys.argv [2:]) +else: + cstyle = CStyleChecker (False) + cstyle.check_files (sys.argv [1:]) + + +if cstyle.get_error_count (): + sys.exit (1) + +sys.exit (0) diff --git a/extern/libsndfile-modified/Scripts/git-pre-commit-hook b/extern/libsndfile-modified/Scripts/git-pre-commit-hook new file mode 100755 index 000000000..dc70e735f --- /dev/null +++ b/extern/libsndfile-modified/Scripts/git-pre-commit-hook @@ -0,0 +1,84 @@ +#!/bin/sh + +if git rev-parse --verify HEAD >/dev/null 2>&1 ; then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 + fi + +# Redirect output to stderr. +exec 1>&2 + +#------------------------------------------------------------------------------- +# Prevent files with non-ascii filenames from being committed. + +if test $(git diff --cached --name-only --diff-filter=A -z $against | LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 ; then + echo "Error: Attempt to add a non-ascii file name." + echo + echo "This can cause problems if you want to work" + echo "with people on other platforms." + echo + echo "To be portable it is advisable to rename the file ..." + echo + echo "Commit aborted." + exit 1 + fi + +#------------------------------------------------------------------------------- +# Check the formatting of all C files. + +# http://man.openbsd.org/sed#r +# http://man.openbsd.org/sed#E +# http://netbsd.gw.com/cgi-bin/man-cgi?sed++NetBSD-current +# https://github.com/freebsd/freebsd/blob/master/usr.bin/sed/main.c +# http://git.savannah.gnu.org/gitweb/?p=sed.git;a=blob;f=sed/sed.c +# GNU has -r and -E (undocumented); MacOS has -E but not -r; Sunos has neither. +files=$(git diff-index --name-status --cached HEAD | grep -v ^D | sed -E "s/^[A-Z]+[A-Z0-9]*[ \t]+/ /") + +cfiles="" +for f in $files ; do + if test `dirname $f` = "src/ALAC" ; then + echo "Skipping cstyle checking on $f" + elif test `echo $f | grep -c "\.[ch]$"` -gt 0 ; then + cfiles="$cfiles $f" + fi + done + +if test -n "$cfiles" ; then + Scripts/cstyle.py $cfiles + if test $? -ne 0 ; then + echo + echo "Commit aborted. Fix the above error before trying again." + exit 1 + fi + fi + +#------------------------------------------------------------------------------- +# Check the copyright notice of all files to be commited. + +user=`git config --global user.email` +year=`date +"%Y"` + +missing_copyright_year="" +if test $user = "erikd@mega-nerd.com" ; then + for f in $files ; do + if test `head -5 $f | grep -i copyright | grep -c -i $user` -gt 0 ; then + user_copyright=`grep -i copyright $f | grep $user | grep -c $year` + if test $user_copyright -lt 1 ; then + missing_copyright_year="$missing_copyright_year $f" + fi + fi + done + fi + +if test -n "$missing_copyright_year" ; then + echo "Missing current year in the copyright notice of the following files:" + for f in $missing_copyright_year ; do + echo " $f" + done + echo "Commit aborted." + exit 1 + fi + +exit 0 diff --git a/extern/libsndfile-modified/Scripts/linux-to-win-cross-configure.sh b/extern/libsndfile-modified/Scripts/linux-to-win-cross-configure.sh new file mode 100755 index 000000000..c1fdc072b --- /dev/null +++ b/extern/libsndfile-modified/Scripts/linux-to-win-cross-configure.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +case "$1" in + w32) + compiler_name=i686-w64-mingw32 + ;; + w64) + compiler_name=x86_64-w64-mingw32 + ;; + *) + echo "$0 (w32|w64) " + exit 0 + ;; + esac + +shift + +build_cpu=$(dpkg-architecture -qDEB_BUILD_GNU_CPU) +build_host=$build_cpu-linux + +./configure --host=$compiler_name --target=$compiler_name --build=$build_host \ + --program-prefix='' --disable-sqlite --disable-static $@ diff --git a/extern/libsndfile-modified/Scripts/static-deps-build.mk b/extern/libsndfile-modified/Scripts/static-deps-build.mk new file mode 100755 index 000000000..bbf2f0d7d --- /dev/null +++ b/extern/libsndfile-modified/Scripts/static-deps-build.mk @@ -0,0 +1,125 @@ +#!/usr/bin/make -f + +# If this is set to true (via the environment) then CRC checking will be +# disabled in libogg giving fuzzers a better chance at finding something. +disable_ogg_crc ?= false + +# Build libsndfile as a dynamic/shared library, but statically link to +# libFLAC, libogg, libopus and libvorbis + +ogg_version = libogg-1.3.4 +ogg_sha256sum = c163bc12bc300c401b6aa35907ac682671ea376f13ae0969a220f7ddf71893fe + +vorbis_version = libvorbis-1.3.7 +vorbis_sha256sum = b33cc4934322bcbf6efcbacf49e3ca01aadbea4114ec9589d1b1e9d20f72954b + +flac_version = flac-1.3.3 +flac_sha256sum = 213e82bd716c9de6db2f98bcadbc4c24c7e2efe8c75939a1a84e28539c4e1748 + +opus_version = opus-1.3.1 +opus_sha256sum = 65b58e1e25b2a114157014736a3d9dfeaad8d41be1c8179866f144a2fb44ff9d + +#------------------------------------------------------------------------------- +# Code follows. + +ogg_tarball = $(ogg_version).tar.xz +vorbis_tarball = $(vorbis_version).tar.xz +flac_tarball = $(flac_version).tar.xz +opus_tarball = $(opus_version).tar.gz + +download_url = http://downloads.xiph.org/releases/ +tarball_dir = Build/Tarballs +stamp_dir = Build/Stamp + +build_dir = $(shell pwd)/Build +config_options = --prefix=$(build_dir) --disable-shared --enable-option-checking + +pwd = $(shell pwd) + +help : + @echo + @echo "This script will build libsndfile as a dynamic/shared library but statically linked" + @echo "to libFLAC, libogg and libvorbis. It should work on Linux and Mac OS X. It might" + @echo "work on Windows with a correctly set up MinGW." + @echo + @echo "It requires all the normal build tools require to build libsndfile plus wget." + @echo + +config : Build/Stamp/configure + +build : Build/Stamp/build + +clean : + rm -rf Build/flac-* Build/libogg-* Build/libvorbis-* Build/opus-* + rm -rf Build/bin Build/include Build/lib Build/share + rm -f Build/Stamp/install Build/Stamp/extract Build/Stamp/sha256sum Build/Stamp/build-ogg + +Build/Stamp/init : + mkdir -p $(stamp_dir) $(tarball_dir) + touch $@ + +Build/Tarballs/$(flac_tarball) : Build/Stamp/init + (cd $(tarball_dir) && wget $(download_url)flac/$(flac_tarball) -O $(flac_tarball)) + touch $@ + +Build/Tarballs/$(ogg_tarball) : Build/Stamp/init + (cd $(tarball_dir) && wget $(download_url)ogg/$(ogg_tarball) -O $(ogg_tarball)) + touch $@ + +Build/Tarballs/$(vorbis_tarball) : Build/Stamp/init + (cd $(tarball_dir) && wget $(download_url)vorbis/$(vorbis_tarball) -O $(vorbis_tarball)) + touch $@ + +Build/Tarballs/$(opus_tarball) : Build/Stamp/init + (cd $(tarball_dir) && wget https://archive.mozilla.org/pub/opus/$(opus_tarball) -O $(opus_tarball)) + touch $@ + +Build/Stamp/tarballs : Build/Tarballs/$(flac_tarball) Build/Tarballs/$(ogg_tarball) Build/Tarballs/$(vorbis_tarball) Build/Tarballs/$(opus_tarball) + touch $@ + +Build/Stamp/sha256sum : Build/Stamp/tarballs + test `sha256sum $(tarball_dir)/$(ogg_tarball) | sed "s/ .*//"` = $(ogg_sha256sum) + test `sha256sum $(tarball_dir)/$(vorbis_tarball) | sed "s/ .*//"` = $(vorbis_sha256sum) + test `sha256sum $(tarball_dir)/$(flac_tarball) | sed "s/ .*//"` = $(flac_sha256sum) + test `sha256sum $(tarball_dir)/$(opus_tarball) | sed "s/ .*//"` = $(opus_sha256sum) + touch $@ + +Build/Stamp/extract : Build/Stamp/sha256sum + # (cd Build && tar xf Tarballs/$(ogg_tarball)) + (cd Build && tar xf Tarballs/$(flac_tarball)) + (cd Build && tar xf Tarballs/$(vorbis_tarball)) + (cd Build && tar xf Tarballs/$(opus_tarball)) + touch $@ + +Build/Stamp/build-ogg : Build/Stamp/sha256sum +ifeq ($(disable_ogg_crc), true) + echo "Ogg/CRC enabled" + (cd Build && git clone https://github.com/xiph/ogg $(ogg_version)) + (cd Build/$(ogg_version) && autoreconf -vif && CFLAGS=-fPIC ./configure $(config_options) --disable-crc && make all install) +else + echo "Ogg/CRC disabled" + (cd Build && tar xf Tarballs/$(ogg_tarball)) + (cd Build/$(ogg_version) && CFLAGS=-fPIC ./configure $(config_options) && make all install) +endif + touch $@ + +Build/Stamp/install-libs : Build/Stamp/extract Build/Stamp/build-ogg + (cd Build/$(vorbis_version) && CFLAGS=-fPIC ./configure $(config_options) && make all install) + (cd Build/$(flac_version) && CFLAGS=-fPIC ./configure $(config_options) && make all install) + (cd Build/$(opus_version) && CFLAGS=-fPIC ./configure $(config_options) && make all install) + touch $@ + +configure : configure.ac + autoreconf -vif + +Build/Stamp/configure : Build/Stamp/install-libs configure + PKG_CONFIG_LIBDIR=Build/lib/pkgconfig ./configure + sed -i 's#^EXTERNAL_XIPH_CFLAGS.*#EXTERNAL_XIPH_CFLAGS = -I$(pwd)/Build/include#' Makefile + sed -i 's#^EXTERNAL_XIPH_LIBS.*#EXTERNAL_XIPH_LIBS = -static $(pwd)/Build/lib/libFLAC.la $(pwd)/Build/lib/libvorbis.la $(pwd)/Build/lib/libvorbisenc.la $(pwd)/Build/lib/libopus.la $(pwd)/Build/lib/libogg.la -dynamic #' Makefile + make clean + touch $@ + +Build/Stamp/build : Build/Stamp/configure + make all check + touch $@ + diff --git a/extern/libsndfile-modified/Win32/README-precompiled-dll.txt b/extern/libsndfile-modified/Win32/README-precompiled-dll.txt new file mode 100644 index 000000000..bde812421 --- /dev/null +++ b/extern/libsndfile-modified/Win32/README-precompiled-dll.txt @@ -0,0 +1,40 @@ +Notes on Using the Pre-compiled libsndfile DLL. +=============================================== + +In order to use this pre-compiled DLL with Visual Studio, you will need to +generate a .LIB file from the DLL. + +This can be achieved as follows: + + 1) In a CMD window, change to the directory containing this file and + run the command: + + lib /machine:i386 /def:libsndfile-1.def + +You now have two files: + + libsndfile-1.dll + libsndfile-1.lib + +to be used with VisualStudio. + +If the lib command fails with a command saying "'lib' is not recognized as +an internal or external command, operable program or batch file", you need +to find the location of "lib.exe" and add that directory to your PATH +environment variable. Another alternative is to use the "Visual Studio 2005 +Command Prompt" Start menu item: + + Start -> + All Programs -> + Visual Studio 2005 -> + Visual Studio Tools -> + Visual Studio 2005 Command Prompt + +If for some reason these instructions don't work for you or you are still +not able to use the libsndfile DLL with you project, please do not contact +the main author of libsndfile. Instead, join the libsndfile-users mailing +list : + + http://www.mega-nerd.com/libsndfile/lists.html + +and ask a question there. diff --git a/extern/libsndfile-modified/Win32/testprog.c b/extern/libsndfile-modified/Win32/testprog.c new file mode 100644 index 000000000..d26d844ad --- /dev/null +++ b/extern/libsndfile-modified/Win32/testprog.c @@ -0,0 +1,16 @@ +/* Simple test program to make sure that Win32 linking to libsndfile is +** working. +*/ + +#include + +#include "sndfile.h" + +int +main (void) +{ static char strbuffer [256] ; + sf_command (NULL, SFC_GET_LIB_VERSION, strbuffer, sizeof (strbuffer)) ; + puts (strbuffer) ; + return 0 ; +} + diff --git a/extern/libsndfile-modified/cmake/CMakeAutoGen.cmake b/extern/libsndfile-modified/cmake/CMakeAutoGen.cmake new file mode 100644 index 000000000..f82dc137c --- /dev/null +++ b/extern/libsndfile-modified/cmake/CMakeAutoGen.cmake @@ -0,0 +1,46 @@ +# CMake implementation of AutoGen +# Copyright (C) 2017 Anonymous Maarten + +set(AUTOGEN_SCRIPT "${CMAKE_MODULE_PATH}/CMakeAutoGenScript.cmake") + +function(lsf_autogen DIR_REL NAME_WE) + set(EXTS ${ARGN}) + set(INPUT "${CMAKE_CURRENT_SOURCE_DIR}/${DIR_REL}/${NAME_WE}.def") + set(OUTPUTS) + foreach(EXT ${EXTS}) + list(APPEND OUTPUTS "${NAME_WE}.${EXT}") + endforeach() + add_autogen_target("${INPUT}" "${CMAKE_CURRENT_BINARY_DIR}/${DIR_REL}" ${OUTPUTS}) +endfunction() + +function(add_autogen_target INPUT OUTPUTDIR) + set(OUTPUTFILES "${ARGN}") + + if (OUTPUTDIR) + set(PREFIX "${OUTPUTDIR}/") + else() + set(PREFIX "") + endif() + + set(ARTIFACTS) + foreach(OUTPUTFILE ${OUTPUTFILES}) + list(APPEND ARTIFACTS "${PREFIX}${OUTPUTFILE}") + endforeach() + + set(EXTRA_ARGS) + if (AUTOGEN_DEBUG) + list(APPEND EXTRA_ARGS "-DDEBUG=1") + endif() + if (OUTPUTDIR) + list(APPEND EXTRA_ARGS "-DOUTPUTDIR=${OUTPUTDIR}") + endif() + + add_custom_command( + OUTPUT ${ARTIFACTS} + COMMAND ${CMAKE_COMMAND} "-DDEFINITION=${INPUT}" ${EXTRA_ARGS} -P "${AUTOGEN_SCRIPT}" + MAIN_DEPENDENCY "${INPUT}" + DEPENDS "${AUTOGEN_SCRIPT}" + COMMENT "CMakeAutoGen: generating ${OUTPUTFILES}" + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" + ) +endfunction() diff --git a/extern/libsndfile-modified/cmake/CMakeAutoGenScript.cmake b/extern/libsndfile-modified/cmake/CMakeAutoGenScript.cmake new file mode 100644 index 000000000..ade53e198 --- /dev/null +++ b/extern/libsndfile-modified/cmake/CMakeAutoGenScript.cmake @@ -0,0 +1,442 @@ +# CMake implementation of AutoGen +# Copyright (C) 2017 Anonymous Maarten + +set(WS " \t\r\n") + +function(cutoff_first_occurrence TEXT OCCURRENCE RESULT) + string(FIND "${TEXT}" "${OCCURRENCE}" OCCURRENCE_INDEX) + if (OCCURRENCE_INDEX EQUAL -1) + set(${TEXT} "" PARENT_SCOPE) + return() + endif() + + string(LENGTH "${OCCURRENCE}" OCCURRENCE_LENGTH) + math(EXPR CUTOFF_INDEX "${OCCURRENCE_INDEX}+${OCCURRENCE_LENGTH}") + string(SUBSTRING "${TEXT}" ${CUTOFF_INDEX} -1 TEXT_REMAINDER) + set(${RESULT} "${TEXT_REMAINDER}" PARENT_SCOPE) + + endfunction() + +function(read_definition DEFINITION_FILENAME TEMPLATE_FILENAME DATA) + file(READ "${DEFINITION_FILENAME}" DEFINITION_CONTENTS) + + string(REGEX MATCH "autogen definitions ([a-zA-Z\\._-]+);[${WS}]*" TEMPLATE_MATCH "${DEFINITION_CONTENTS}") + if (NOT TEMPLATE_MATCH) + message(FATAL_ERROR "${DEFINITION_FILENAME} doest not contain an AutoGen definition.") + endif() + + get_filename_component(DEFINITION_DIR "${DEFINITION_FILENAME}" PATH) + set(${TEMPLATE_FILENAME} "${DEFINITION_DIR}/${CMAKE_MATCH_1}" PARENT_SCOPE) + if (DEBUG) + message("found: TEMPLATE_FILENAME=${CMAKE_MATCH_1}") + endif() + + cutoff_first_occurrence("${DEFINITION_CONTENTS}" "${TEMPLATE_MATCH}" DEFINITION_CONTENTS) + + set(DEFINITION "") + + while (1) + string(REGEX MATCH "([a-zA-Z_][a-zA-Z0-9_]*)[${WS}]*=[${WS}]*{[${WS}]*" GROUPSTART_MATCH "${DEFINITION_CONTENTS}") + if (NOT GROUPSTART_MATCH) + break() + endif() + set(GROUPNAME "${CMAKE_MATCH_1}") + cutoff_first_occurrence("${DEFINITION_CONTENTS}" "${GROUPSTART_MATCH}" DEFINITION_CONTENTS) + if (DEBUG) + message("found: GROUPNAME=${GROUPNAME}") + endif() + set(NBKEYS 0) + set(GROUP_KEY_VALUES "") + while (1) + string(REGEX MATCH "^([a-zA-Z_][a-zA-Z0-9_]*)[${WS}]*=[${WS}]*(([\"']([${WS}a-zA-Z0-9_%\\\"<>\(\)\\.*+/?:,\\-]+)[\"'])|([a-zA-Z0-9_%\\]+))[${WS}]*;[${WS}]*" KEY_VALUE_MATCH "${DEFINITION_CONTENTS}") + if (NOT KEY_VALUE_MATCH) + break() + endif() + set(KEY "${CMAKE_MATCH_1}") + if ("${CMAKE_MATCH_4}" STREQUAL "") + set(VALUE "${CMAKE_MATCH_5}") + else() + string(REPLACE "\\\"" "\"" VALUE "${CMAKE_MATCH_4}") + #set(VALUE "${CMAKE_MATCH_4}") + endif() + + if (DEBUG) + message("found: KEY=${KEY}, VALUE=${VALUE}") + endif() + math(EXPR NBKEYS "${NBKEYS}+1") + list(APPEND GROUP_KEY_VALUES "${KEY}" "${VALUE}") + cutoff_first_occurrence("${DEFINITION_CONTENTS}" "${KEY_VALUE_MATCH}" DEFINITION_CONTENTS) + endwhile() + string(REGEX MATCH "^[${WS}]*}[${WS}]*;[${WS}]*" GROUPEND_MATCH "${DEFINITION_CONTENTS}") + if (NOT GROUPEND_MATCH) + message(FATAL_ERROR "Group ${GROUPNAME} did not finish.") + endif() + cutoff_first_occurrence("${DEFINITION_CONTENTS}" "${GROUPEND_MATCH}" DEFINITION_CONTENTS) + list(APPEND DEFINITION "${GROUPNAME}" ${NBKEYS} ${GROUP_KEY_VALUES}) + endwhile() + set(${DATA} "${DEFINITION}" PARENT_SCOPE) +endfunction() + +function(match_autogen_group TEXT START POS0 POS1 MATCH FOUND) + string(SUBSTRING "${TEXT}" "${START}" -1 TEXT) + string(REGEX MATCH "\\[\\+[${WS}]*([ a-zA-Z0-9=_$%\\(\\)\"\\+\\-]+)[${WS}]*\\+\\]" MATCH_GROUP "${TEXT}") + if ("${MATCH_GROUP}" STREQUAL "") + set(${FOUND} 0 PARENT_SCOPE) + return() + endif() + string(FIND "${TEXT}" "${MATCH_GROUP}" START_TEXT) + math(EXPR POS0_var "${START}+${START_TEXT}") + string(LENGTH "${MATCH_GROUP}" MATCH_LENGTH) + math(EXPR POS1_var "${POS0_var}+${MATCH_LENGTH}") + set(${POS0} "${POS0_var}" PARENT_SCOPE) + set(${POS1} "${POS1_var}" PARENT_SCOPE) + set(${FOUND} 1 PARENT_SCOPE) + string(STRIP "${CMAKE_MATCH_1}" CONTENT) + set("${MATCH}" "${CONTENT}" PARENT_SCOPE) +endfunction() + +function(append_output SUFFICES_FILENAMES TEXT POS0 POS1 FILTER) + math(EXPR POS_LENGTH "${POS1}-${POS0}") + string(LENGTH "${TEXT}" TEXT_LENGTH) + string(SUBSTRING "${TEXT}" "${POS0}" "${POS_LENGTH}" TEXT_APPEND) + if (DEBUG) + message("appending ${POS0}:${POS1}, length=${POS_LENGTH}") + endif() + append_output_text("${SUFFICES_FILENAMES}" "${TEXT_APPEND}" "${FILTER}") +endfunction() + +function(append_output_text SUFFICES_FILENAMES TEXT_APPEND FILTER) + string(LENGTH "${TEXT_APPEND}" TEXT_LENGTH) + list(LENGTH SUFFICES_FILENAMES NB) + math(EXPR NB_END "${NB}-1") + foreach(INDEX RANGE 0 ${NB_END} 3) + math(EXPR INDEX_1 "${INDEX}+1") + math(EXPR INDEX_2 "${INDEX}+2") + list(GET SUFFICES_FILENAMES ${INDEX} SUFFIX) + list(GET SUFFICES_FILENAMES ${INDEX_1} FILENAME) + list(GET SUFFICES_FILENAMES ${INDEX_2} TEMPFILENAME) + set(WRITE_OK 1) + if (FILTER) + if (NOT "${SUFFIX}" STREQUAL "${FILTER}") + set(WRITE_OK 0) + endif() + endif() + if (WRITE_OK) + if (DEBUG) + message("Write: ${TEXT_LENGTH} characters to ${FILENAME}") + endif() + file(APPEND "${TEMPFILENAME}" "${TEXT_APPEND}") + endif() + endforeach() +endfunction() + +function(output_finish SUFFICES_FILENAMES) + list(LENGTH SUFFICES_FILENAMES NB) + math(EXPR NB_END "${NB}-1") + foreach(INDEX RANGE 0 ${NB_END} 3) + math(EXPR INDEX_1 "${INDEX}+1") + math(EXPR INDEX_2 "${INDEX}+2") + list(GET SUFFICES_FILENAMES ${INDEX_1} FILENAME) + list(GET SUFFICES_FILENAMES ${INDEX_2} TEMPFILENAME) + file(RENAME "${TEMPFILENAME}" "${FILENAME}") + endforeach() +endfunction() + +function(stack_push STACK_ARG) + set(STACK_LIST "${${STACK_ARG}}") + string(REPLACE ";" " " NEWITEM "${ARGN}") + if (DEBUG) + list(LENGTH STACK_LIST STACK_LENGTH) + message("Pushing \"${NEWITEM}\" onto stack (length=${STACK_LENGTH})") + endif() + list(APPEND STACK_LIST "${NEWITEM}") + set(${STACK_ARG} "${STACK_LIST}" PARENT_SCOPE) +endfunction() + +function(stack_pop STACK_ARG ITEM) + set(STACK_LIST "${${STACK_ARG}}") + list(LENGTH STACK_LIST STACK_LENGTH) + if (STACK_LENGTH EQUAL 0) + message(FATAL_ERROR "ENDFOR: stack is empty") + endif() + math(EXPR LAST_ITEM_INDEX "${STACK_LENGTH}-1") + list(GET STACK_LIST "${LAST_ITEM_INDEX}" LAST_ITEM) + list(REMOVE_AT STACK_LIST "${LAST_ITEM_INDEX}") + string(REPLACE " " ";" LAST_ITEM_LIST "${LAST_ITEM}") + if (DEBUG) + message("Popping \"${LAST_ITEM}\" from stack (length=${STACK_LENGTH})") + endif() + set(${ITEM} "${LAST_ITEM_LIST}" PARENT_SCOPE) + set(${STACK_ARG} "${STACK_LIST}" PARENT_SCOPE) +endfunction() + +function(stack_top STACK_ARG ITEM) + set(STACK_LIST "${${STACK_ARG}}") + list(LENGTH STACK_LIST STACK_LENGTH) + if (STACK_LENGTH EQUAL 0) + message(FATAL_ERROR "ENDFOR: stack is empty") + endif() + math(EXPR LAST_ITEM_INDEX "${STACK_LENGTH}-1") + list(GET STACK_LIST "${LAST_ITEM_INDEX}" LAST_ITEM) + string(REPLACE " " ";" LAST_ITEM_LIST "${LAST_ITEM}") + if (DEBUG) + message("Top of stack: \"${LAST_ITEM}\" from stack (length=${STACK_LENGTH})") + endif() + set(${ITEM} "${LAST_ITEM_LIST}" PARENT_SCOPE) +endfunction() + +function(stack_find_key STACK_LIST TEMPLATE_PARAMETERS KEY VALUE) + list(REVERSE STACK_LIST) + foreach(STACK_ITEM ${STACK_LIST}) + string(REPLACE " " ";" STACK_ITEM_LIST "${STACK_ITEM}") + list(GET STACK_ITEM_LIST 3 TP_INDEX) + math(EXPR TP_SIZE_INDEX "${TP_INDEX}+1") + list(GET TEMPLATE_PARAMETERS ${TP_SIZE_INDEX} TP_SIZE) + math(EXPR TP_KV_INDEX_START "${TP_INDEX}+2") + math(EXPR TP_KV_INDEX_END "${TP_KV_INDEX_START}+2*${TP_SIZE}-1") + foreach(TP_KV_INDEX RANGE ${TP_KV_INDEX_START} ${TP_KV_INDEX_END} 2) + list(GET TEMPLATE_PARAMETERS ${TP_KV_INDEX} TP_KEY) + if("${TP_KEY}" STREQUAL "${KEY}") + math(EXPR TP_VALUE_INDEX "${TP_KV_INDEX}+1") + list(GET TEMPLATE_PARAMETERS ${TP_VALUE_INDEX} TP_VALUE) + set(${VALUE} "${TP_VALUE}" PARENT_SCOPE) + return() + endif() + endforeach() + endforeach() + message(FATAL_ERROR "Unknown KEY=${KEY}") +endfunction() + +function(template_parameters_find_next_groupname_index TEMPLATE_PARAMETERS GROUPNAME INDEX_LAST INDEX_NEXT) + if (${INDEX_LAST} LESS 0) + set(INDEX 0) + else () + math(EXPR INDEX_1 "1+(${INDEX_LAST})") + list(GET TEMPLATE_PARAMETERS ${INDEX_1} GROUPNAME_INDEX_SIZE) + math(EXPR INDEX "${INDEX_LAST}+1+2*${GROUPNAME_INDEX_SIZE}+1") + endif() + list(LENGTH TEMPLATE_PARAMETERS PARAMETERS_LENGTH) + while (${INDEX} LESS ${PARAMETERS_LENGTH}) + list(GET TEMPLATE_PARAMETERS ${INDEX} GROUPNAME_AT_INDEX) + if ("${GROUPNAME}" STREQUAL "${GROUPNAME_AT_INDEX}") + set("${INDEX_NEXT}" ${INDEX} PARENT_SCOPE) + return() + endif() + math(EXPR INDEX_1 "${INDEX}+1") + list(GET TEMPLATE_PARAMETERS ${INDEX_1} GROUPNAME_INDEX_SIZE) + math(EXPR INDEX "${INDEX}+1+2*${GROUPNAME_INDEX_SIZE}+1") + endwhile() + set("${INDEX_NEXT}" -1 PARENT_SCOPE) +endfunction() + +function(calculate_line_number TEXT POSITION LINENUMBER_ARG) + #math(EXPR INDEX_MAX "${POSITION}-1") + string(SUBSTRING "${TEXT}" 0 ${POSITION} SUBTEXT) + string(REGEX MATCHALL "\n" MATCH_NEWLINES "${SUBTEXT}") + list(LENGTH MATCH_NEWLINES NBLINES) + math(EXPR NBLINES "${NBLINES}+1") + set(${LINENUMBER_ARG} ${NBLINES} PARENT_SCOPE) +endfunction() + +function(parse_template TEMPLATE_FILENAME OUTPUT_DIR TEMPLATE_PARAMETERS) + file(READ ${TEMPLATE_FILENAME} TEMPLATE_CONTENTS) + set(POSITION 0) + match_autogen_group("${TEMPLATE_CONTENTS}" "${POSITION}" POS0 POS1 AUTOGEN FOUND) + if (NOT FOUND) + message(FATAL_ERROR "Header of template not found") + endif() + string(REGEX MATCH "AutoGen5 template ([ a-zA-Z0-9]*)" SUFFICES_MATCH "${AUTOGEN}") + if (NOT SUFFICES_MATCH) + message(FATAL_ERROR "No output suffices found") + endif() + string(STRIP "${CMAKE_MATCH_1}" SUFFICES) + string(REPLACE " " ";" SUFFICES "${SUFFICES}") + set(SUFFICES_FILENAMES "") + get_filename_component(TEMPLATE_NAME_WE "${TEMPLATE_FILENAME}" NAME_WE) + foreach(SUFFIX ${SUFFICES}) + if ("${OUTPUT_DIR}" STREQUAL "") + set(DIR_PREFIX "") + else() + set(DIR_PREFIX "${OUTPUT_DIR}/") + endif() + string(RANDOM LENGTH 64 RANDOMSTRING) + set(FILENAME "${DIR_PREFIX}${TEMPLATE_NAME_WE}.${SUFFIX}") + set(TEMPFILENAME "${DIR_PREFIX}${TEMPLATE_NAME_WE}${RANDOMSTRING}.${SUFFIX}") + list(APPEND SUFFICES_FILENAMES "${SUFFIX}" "${FILENAME}" "${TEMPFILENAME}") + file(WRITE "${FILENAME}" "") + endforeach() + if (DEBUG) + message("Output files: ${SUFFICES_FILENAMES}") + endif() + set(WRITE_FILTER "") + append_output("${SUFFICES_FILENAMES}" "${TEMPLATE_CONTENTS}" 0 "${POS0}" "${WRITE_FILTER}") + math(EXPR POS1 "${POS1}+1") + set(POSITION "${POS1}") + if (DEBUG) + message("Output: ${SUFFICES_FILENAMES}") + endif() + + set(STACK "") + while (1) + match_autogen_group("${TEMPLATE_CONTENTS}" "${POSITION}" POS0 POS1 GROUP_MATCH FOUND) + if (NOT FOUND) + if (DEBUG) + message("No group found. Dumping rest of file.") + endif() + if (NOT "${STACK}" STREQUAL "") + message(FATAL_ERROR "Stack not empty at end of file") + endif() + string(LENGTH "${TEMPLATE_CONTENTS}" TEXT_LENGTH) + append_output("${SUFFICES_FILENAMES}" "${TEMPLATE_CONTENTS}" ${POSITION} ${TEXT_LENGTH} "${WRITE_FILTER}") + break() + endif() + append_output("${SUFFICES_FILENAMES}" "${TEMPLATE_CONTENTS}" ${POSITION} ${POS0} "${WRITE_FILTER}") + set(POSITION "${POS1}") + + if (GROUP_MATCH MATCHES "^FOR") + string(REPLACE " " ";" GROUP_MATCH_LIST "${GROUP_MATCH}") + list(GET GROUP_MATCH_LIST 1 FOR_KEY) + template_parameters_find_next_groupname_index("${TEMPLATE_PARAMETERS}" "${FOR_KEY}" -1 FOR_INDEX) + if (DEBUG) + message("FOR_KEY: ${FOR_KEY}") + message("FOR_INDEX: ${FOR_INDEX}") + endif() + if (${FOR_KEY} LESS 0) + message(FATAL_ERROR "FOR has key with empty list. Not implemented yet..") + endif() + stack_push(STACK FOR ${POSITION} ${FOR_KEY} ${FOR_INDEX}) + elseif (GROUP_MATCH MATCHES "^ENDFOR") + string(REPLACE " " ";" GROUP_MATCH_LIST "${GROUP_MATCH}") + list(GET GROUP_MATCH_LIST 1 ENDFOR_KEY) + stack_pop(STACK FOR_ITEM) + list(GET FOR_ITEM 0 FOR_FOR) + if (NOT "${FOR_FOR}" STREQUAL "FOR") + message(FATAL_ERROR "ENDFOR does not match last item: ${FOR_FOR}") + endif() + list(GET FOR_ITEM 1 FOR_POSITION) + list(GET FOR_ITEM 2 FOR_KEY) + if (NOT "${FOR_KEY}" STREQUAL "${ENDFOR_KEY}") + calculate_line_number("${TEMPLATE_CONTENTS}" "${POSITION}" LINENUMBER) + message("FOR and ENDFOR do not match. (line number ${LINENUMBER}) (FOR:${FOR_KEY}, ENDFOR:${ENDFOR_KEY})") + endif() + list(GET FOR_ITEM 3 FOR_INDEX_PREV) + template_parameters_find_next_groupname_index("${TEMPLATE_PARAMETERS}" "${FOR_KEY}" ${FOR_INDEX_PREV} FOR_INDEX) + if (DEBUG) + message("FOR_INDEX was ${FOR_INDEX_PREV}, is now ${FOR_INDEX}") + endif() + if (${FOR_INDEX} LESS 0) + if (DEBUG) + message("ENDFOR: FOR_INDEX < 0 (no more key) ==> Continue") + endif() + else() + set(POSITION ${FOR_POSITION}) + stack_push(STACK FOR ${FOR_POSITION} ${FOR_KEY} ${FOR_INDEX}) + if (DEBUG) + message("ENDFOR: FOR_INDEX >= 0 (more keys available) ==> Back to position=${FOR_POSITION}") + endif() + endif() + elseif (GROUP_MATCH MATCHES "^CASE") + string(REGEX MATCH "^CASE[${WS}]+\\(([a-zA-Z]+)\\)" CASE_MATCH "${GROUP_MATCH}") + if ("${CASE_MATCH}" STREQUAL "") + message(FATAL_ERROR "Wrong CASE syntax") + endif() + set(CASE_KEY "${CMAKE_MATCH_1}") + if (DEBUG) + message("CASE: KEY=${CASE_KEY}") + endif() + stack_push(STACK CASE "${CASE_KEY}" ${POSITION}) + elseif (GROUP_MATCH MATCHES "^==") + math(EXPR POSITION "${POSITION}+1") + string(REGEX MATCH "^==[${WS}]+([a-zA-Z_][a-zA-Z0-9_]*)" CASE_MATCH "${GROUP_MATCH}") + if ("${CASE_MATCH}" STREQUAL "") + message(FATAL_ERROR "Wrong == syntax") + endif() + stack_top(STACK CASE_ITEM) + list(GET CASE_ITEM 0 CASE_CASE) + if(NOT "${CASE_CASE}" STREQUAL "CASE") + message(FATAL_ERROR "== block must be in CASE. Top of stack=${CASE_CASE}") + endif() + set(CASE_VALUE "${CMAKE_MATCH_1}") + if (DEBUG) + message("case: == VALUE=${CASE_VALUE}") + endif() + list(GET CASE_ITEM 1 CASE_KEY) + if ("${CASE_KEY}" STREQUAL "suffix") + if (DEBUG) + message("Setting write filter to ${CASE_VALUE}") + endif() + set(WRITE_FILTER "${CASE_VALUE}") + else() + message(FATAL_ERROR "CASE: unsupported argument ${CASE_KEY}") + endif() + elseif (GROUP_MATCH MATCHES "^ESAC") + stack_pop(STACK CASE_ITEM) + if (DEBUG) + message("ESAC") + endif() + list(GET CASE_ITEM 0 CASE_CASE) + if (NOT "${CASE_CASE}" STREQUAL "CASE") + message(FATAL_ERROR "ESAC does not match last item: ${CASE_CASE}") + endif() + if ("${CASE_KEY}" STREQUAL "suffix") + if (DEBUG) + message("Removing write filter") + endif() + set(WRITE_FILTER "") + else() + message(FATAL_ERROR "CASE: unsupported argument ${CASE_KEY}") + endif() + else() + string(REGEX MATCH "\\(([a-zA-Z0-9_$%\"${WS}\\+\\-]+)\\)" PARENTHESE_MATCH "${GROUP_MATCH}") + if (NOT "${PARENTHESE_MATCH}" STREQUAL "") + set(PARENTHESE_CONTENT "${CMAKE_MATCH_1}") + string(REPLACE " " ";" PARENTHESE_LIST "${PARENTHESE_CONTENT}") + list(GET PARENTHESE_LIST 0 PARENTHESE_COMMAND) + if ("${PARENTHESE_COMMAND}" STREQUAL "get") + list(GET PARENTHESE_LIST 1 KEY_QUOTED) + string(REGEX MATCH "\\\"([a-zA-Z_${WS}]+)\\\"" KEY_MATCH "${KEY_QUOTED}") + if ("${KEY_MATCH}" STREQUAL "") + message(FATAL_ERROR "get: empty key") + endif() + set(KEY "${CMAKE_MATCH_1}") + if (DEBUG) + message("Get: key=${KEY}") + endif() + stack_find_key("${STACK}" "${TEMPLATE_PARAMETERS}" "${KEY}" VALUE) + if (DEBUG) + message("Get key=${KEY} ==> value=${VALUE}") + endif() + append_output_text("${SUFFICES_FILENAMES}" "${VALUE}" "${WRITE_FILTER}") + elseif("${PARENTHESE_COMMAND}" STREQUAL "tpl-file-line") + list(GET PARENTHESE_LIST 1 FORMAT_LINE) + calculate_line_number("${TEMPLATE_CONTENTS}" "${POSITION}" LINENUMBER) + append_output_text("${SUFFICES_FILENAMES}" "${LINENUMBER}" "${WRITE_FILTER}") + else() + message(FATAL_ERROR "Unknown parenthese command: ${PARENTHESE_COMMAND}") + endif() + else() + message(FATAL_ERROR "Unknown command: ${GROUP_MATCH}") + endif() + endif() + + endwhile() + if (NOT "${STACK}" STREQUAL "") + message(FATAL_ERROR "STACK was not empty at EOF") + endif() + output_finish("${SUFFICES_FILENAMES}") +endfunction() + +if ("${DEFINITION}" STREQUAL "") + message(FATAL_ERROR "Need definition file") +endif() +if (NOT EXISTS "${DEFINITION}") + message(FATAL_ERROR "Definition file does not exist (${DEFINITION})") +endif() + +read_definition("${DEFINITION}" TEMPLATE_FILENAME DATA) +if (DEBUG) + message("${TEMPLATE_FILENAME}") + message("${DATA}") +endif() + +parse_template("${TEMPLATE_FILENAME}" "${OUTPUTDIR}" "${DATA}") diff --git a/extern/libsndfile-modified/cmake/CheckCPUArch.c.in b/extern/libsndfile-modified/cmake/CheckCPUArch.c.in new file mode 100644 index 000000000..549313947 --- /dev/null +++ b/extern/libsndfile-modified/cmake/CheckCPUArch.c.in @@ -0,0 +1,7 @@ +int main(void) { +#if @CHECK_CPU_ARCH_DEFINES@ + return 0; +#else + fail +#endif +} diff --git a/extern/libsndfile-modified/cmake/CheckCPUArch.cmake b/extern/libsndfile-modified/cmake/CheckCPUArch.cmake new file mode 100644 index 000000000..1fdb3c864 --- /dev/null +++ b/extern/libsndfile-modified/cmake/CheckCPUArch.cmake @@ -0,0 +1,23 @@ +macro (_CHECK_CPU_ARCH ARCH ARCH_DEFINES VARIABLE) + if (NOT DEFINED HAVE_${VARIABLE}) + message (STATUS "Check CPU architecture is ${ARCH}") + set (CHECK_CPU_ARCH_DEFINES ${ARCH_DEFINES}) + configure_file (${PROJECT_SOURCE_DIR}/cmake/CheckCPUArch.c.in ${PROJECT_BINARY_DIR}/CMakeFiles/CMakeTmp/CheckCPUArch.c @ONLY) + try_compile (HAVE_${VARIABLE} "${PROJECT_BINARY_DIR}" + "${PROJECT_BINARY_DIR}/CMakeFiles/CMakeTmp/CheckCPUArch.c") + if(HAVE_${VARIABLE}) + message (STATUS "Check CPU architecture is ${ARCH} - yes") + set (${VARIABLE} 1 CACHE INTERNAL "Result of CHECK_CPU_ARCH_X64" FORCE) + else () + message (STATUS "Check CPU architecture is ${ARCH} - no") + endif () + endif () +endmacro (_CHECK_CPU_ARCH) + +macro (CHECK_CPU_ARCH_X64 VARIABLE) + _CHECK_CPU_ARCH (x64 "defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)" ${VARIABLE}) +endmacro (CHECK_CPU_ARCH_X64) + +macro (CHECK_CPU_ARCH_X86 VARIABLE) + _CHECK_CPU_ARCH (x86 "defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) ||defined( __i386) || defined(_M_IX86)" ${VARIABLE}) +endmacro (CHECK_CPU_ARCH_X86) diff --git a/extern/libsndfile-modified/cmake/ClipMode.cmake b/extern/libsndfile-modified/cmake/ClipMode.cmake new file mode 100644 index 000000000..0241e0379 --- /dev/null +++ b/extern/libsndfile-modified/cmake/ClipMode.cmake @@ -0,0 +1,92 @@ +include (CheckCSourceRuns) +include (CMakePushCheckState) + +macro (CLIP_MODE) + if ((NOT DEFINED CPU_CLIPS_NEGATIVE) AND (NOT DEFINED CPU_CLIPS_POSITIVE)) + set (CLIP_MODE_POSITIVE_MESSAGE "Target processor clips on positive float to int conversion") + set (CLIP_MODE_NEGATIVE_MESSAGE "Target processor clips on negative float to int conversion") + + message (STATUS "Checking processor clipping capabilities...") + + if (CMAKE_CROSSCOMPILING) + + set (CLIP_MSG "disabled") + set (CPU_CLIPS_POSITIVE FALSE CACHE BOOL ${CLIP_MODE_POSITIVE_MESSAGE}) + set (CPU_CLIPS_NEGATIVE FALSE CACHE BOOL ${CLIP_MODE_NEGATIVE_MESSAGE}) + + else (NOT CMAKE_CROSSCOMPILING) + + cmake_push_check_state () + + set (CMAKE_REQUIRED_QUIET TRUE) + if (LIBM_REQUIRED) + set (CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${M_LIBRARY}) + endif () + + check_c_source_runs ( + " + #define _ISOC9X_SOURCE 1 + #define _ISOC99_SOURCE 1 + #define __USE_ISOC99 1 + #define __USE_ISOC9X 1 + #include + int main (void) + { double fval ; + int k, ival ; + + fval = 1.0 * 0x7FFFFFFF ; + for (k = 0 ; k < 100 ; k++) + { ival = (lrint (fval)) >> 24 ; + if (ival != 127) + return 1 ; + + fval *= 1.2499999 ; + } ; + + return 0 ; + } + " + CPU_CLIPS_POSITIVE) + + check_c_source_runs ( + " + #define _ISOC9X_SOURCE 1 + #define _ISOC99_SOURCE 1 + #define __USE_ISOC99 1 + #define __USE_ISOC9X 1 + #include + int main (void) + { double fval ; + int k, ival ; + + fval = -8.0 * 0x10000000 ; + for (k = 0 ; k < 100 ; k++) + { ival = (lrint (fval)) >> 24 ; + if (ival != -128) + return 1 ; + + fval *= 1.2499999 ; + } ; + + return 0 ; + } + " + CPU_CLIPS_NEGATIVE) + + cmake_pop_check_state () + + if (CPU_CLIPS_POSITIVE AND (NOT CPU_CLIPS_NEGATIVE)) + set (CLIP_MSG "positive") + elseif (CPU_CLIPS_NEGATIVE AND (NOT CPU_CLIPS_POSITIVE)) + set (CLIP_MSG "negative") + elseif (CPU_CLIPS_POSITIVE AND CPU_CLIPS_NEGATIVE) + set (CLIP_MSG "both") + else () + set (CLIP_MSG "none") + endif () + + endif (CMAKE_CROSSCOMPILING) + + message (STATUS "Checking processor clipping capabilities... ${CLIP_MSG}") + endif () +endmacro (CLIP_MODE) diff --git a/extern/libsndfile-modified/cmake/FindFLAC.cmake b/extern/libsndfile-modified/cmake/FindFLAC.cmake new file mode 100644 index 000000000..34917067c --- /dev/null +++ b/extern/libsndfile-modified/cmake/FindFLAC.cmake @@ -0,0 +1,67 @@ +# - Find FLAC +# Find the native FLAC includes and libraries +# +# FLAC_INCLUDE_DIRS - where to find FLAC headers. +# FLAC_LIBRARIES - List of libraries when using libFLAC. +# FLAC_FOUND - True if libFLAC found. +# FLAC_DEFINITIONS - FLAC compile definitons + +if (FLAC_INCLUDE_DIR) + # Already in cache, be silent + set (FLAC_FIND_QUIETLY TRUE) +endif () + +find_package (Ogg QUIET) + +find_package (PkgConfig QUIET) +pkg_check_modules(PC_FLAC QUIET flac) + +set(FLAC_VERSION ${PC_FLAC_VERSION}) + +find_path (FLAC_INCLUDE_DIR FLAC/stream_decoder.h + HINTS + ${PC_FLAC_INCLUDEDIR} + ${PC_FLAC_INCLUDE_DIRS} + ${FLAC_ROOT} + ) + +# MSVC built libraries can name them *_static, which is good as it +# distinguishes import libraries from static libraries with the same extension. +find_library (FLAC_LIBRARY + NAMES + FLAC + libFLAC + libFLAC_dynamic + libFLAC_static + HINTS + ${PC_FLAC_LIBDIR} + ${PC_FLAC_LIBRARY_DIRS} + ${FLAC_ROOT} + ) + +# Handle the QUIETLY and REQUIRED arguments and set FLAC_FOUND to TRUE if +# all listed variables are TRUE. +include (FindPackageHandleStandardArgs) +find_package_handle_standard_args (FLAC + REQUIRED_VARS + FLAC_LIBRARY + FLAC_INCLUDE_DIR + Ogg_FOUND + VERSION_VAR + FLAC_VERSION + ) + +if (FLAC_FOUND) + set (FLAC_INCLUDE_DIRS ${FLAC_INCLUDE_DIR}) + set (FLAC_LIBRARIES ${FLAC_LIBRARY} ${OGG_LIBRARIES}) + if (NOT TARGET FLAC::FLAC) + add_library(FLAC::FLAC UNKNOWN IMPORTED) + set_target_properties(FLAC::FLAC PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${FLAC_INCLUDE_DIR}" + IMPORTED_LOCATION "${FLAC_LIBRARY}" + INTERFACE_LINK_LIBRARIES Ogg::ogg + ) + endif () +endif () + +mark_as_advanced(FLAC_INCLUDE_DIR FLAC_LIBRARY) diff --git a/extern/libsndfile-modified/cmake/FindOgg.cmake b/extern/libsndfile-modified/cmake/FindOgg.cmake new file mode 100644 index 000000000..9cf5ce430 --- /dev/null +++ b/extern/libsndfile-modified/cmake/FindOgg.cmake @@ -0,0 +1,61 @@ +# - Find ogg +# Find the native ogg includes and libraries +# +# OGG_INCLUDE_DIRS - where to find ogg.h, etc. +# OGG_LIBRARIES - List of libraries when using ogg. +# OGG_FOUND - True if ogg found. + +if (OGG_INCLUDE_DIR) + # Already in cache, be silent + set(OGG_FIND_QUIETLY TRUE) +endif () + +find_package (PkgConfig QUIET) +pkg_check_modules (PC_OGG QUIET ogg>=1.3.0) + +set (OGG_VERSION ${PC_OGG_VERSION}) + +find_path (OGG_INCLUDE_DIR ogg/ogg.h + HINTS + ${PC_OGG_INCLUDEDIR} + ${PC_OGG_INCLUDE_DIRS} + ${OGG_ROOT} + ) +# MSVC built ogg may be named ogg_static. +# The provided project files name the library with the lib prefix. +find_library (OGG_LIBRARY + NAMES + ogg + ogg_static + libogg + libogg_static + HINTS + ${PC_OGG_LIBDIR} + ${PC_OGG_LIBRARY_DIRS} + ${OGG_ROOT} + ) +# Handle the QUIETLY and REQUIRED arguments and set OGG_FOUND +# to TRUE if all listed variables are TRUE. +include (FindPackageHandleStandardArgs) +find_package_handle_standard_args (Ogg + REQUIRED_VARS + OGG_LIBRARY + OGG_INCLUDE_DIR + VERSION_VAR + OGG_VERSION + ) + +if (OGG_FOUND) + set (OGG_LIBRARIES ${OGG_LIBRARY}) + set (OGG_INCLUDE_DIRS ${OGG_INCLUDE_DIR}) + + if(NOT TARGET Ogg::ogg) + add_library(Ogg::ogg UNKNOWN IMPORTED) + set_target_properties(Ogg::ogg PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${OGG_INCLUDE_DIRS}" + IMPORTED_LOCATION "${OGG_LIBRARIES}" + ) + endif () +endif () + +mark_as_advanced (OGG_INCLUDE_DIR OGG_LIBRARY) diff --git a/extern/libsndfile-modified/cmake/FindOpus.cmake b/extern/libsndfile-modified/cmake/FindOpus.cmake new file mode 100644 index 000000000..a83686bdd --- /dev/null +++ b/extern/libsndfile-modified/cmake/FindOpus.cmake @@ -0,0 +1,67 @@ +# - Find opus +# Find the native opus includes and libraries +# +# OPUS_INCLUDE_DIRS - where to find opus.h, etc. +# OPUS_LIBRARIES - List of libraries when using opus. +# OPUS_FOUND - True if Opus found. + +if (OPUS_INCLUDE_DIR) + # Already in cache, be silent + set(OPUS_FIND_QUIETLY TRUE) +endif () + +find_package (Ogg QUIET) + +find_package (PkgConfig QUIET) +pkg_check_modules(PC_OPUS QUIET opus>=1.1) + +set (OPUS_VERSION ${PC_OPUS_VERSION}) + +find_path (OPUS_INCLUDE_DIR opus/opus.h + HINTS + ${PC_OPUS_INCLUDEDIR} + ${PC_OPUS_INCLUDE_DIRS} + ${OPUS_ROOT} + ) + +# MSVC built opus may be named opus_static. +# The provided project files name the library with the lib prefix. + +find_library (OPUS_LIBRARY + NAMES + opus + opus_static + libopus + libopus_static + HINTS + ${PC_OPUS_LIBDIR} + ${PC_OPUS_LIBRARY_DIRS} + ${OPUS_ROOT} + ) + +# Handle the QUIETLY and REQUIRED arguments and set OPUS_FOUND +# to TRUE if all listed variables are TRUE. +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args (Opus + REQUIRED_VARS + OPUS_LIBRARY + OPUS_INCLUDE_DIR + OGG_FOUND + VERSION_VAR + OPUS_VERSION + ) + +if (OPUS_FOUND) + set (OPUS_LIBRARIES ${OPUS_LIBRARY}) + set (OPUS_INCLUDE_DIRS ${OPUS_INCLUDE_DIR}) + + if (NOT TARGET Opus::opus) + add_library (Opus::opus UNKNOWN IMPORTED) + set_target_properties (Opus::opus PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${OPUS_INCLUDE_DIRS}" + IMPORTED_LOCATION "${OPUS_LIBRARIES}" + ) + endif () +endif () + +mark_as_advanced(OPUS_INCLUDE_DIR OPUS_LIBRARY) diff --git a/extern/libsndfile-modified/cmake/FindSndio.cmake b/extern/libsndfile-modified/cmake/FindSndio.cmake new file mode 100644 index 000000000..6b9b40986 --- /dev/null +++ b/extern/libsndfile-modified/cmake/FindSndio.cmake @@ -0,0 +1,61 @@ +# - Find SoundIO (sndio) includes and libraries +# +# SNDIO_FOUND - True if SNDIO_INCLUDE_DIR & SNDIO_LIBRARY are +# found +# SNDIO_LIBRARIES - Set when SNDIO_LIBRARY is found +# SNDIO_INCLUDE_DIRS - Set when SNDIO_INCLUDE_DIR is found +# +# SNDIO_INCLUDE_DIR - where to find sndio.h, etc. +# SNDIO_LIBRARY - the sndio library +# + +if (SNDIO_INCLUDE_DIR) + # Already in cache, be silent + set (SNDIO_FIND_QUIETLY TRUE) +endif () + +find_package (PkgConfig QUIET) +pkg_check_modules (PC_SNDIO QUIET sndio) + +set (SNDIO_VERSION ${PC_SNDIO_VERSION}) + +find_path (SNDIO_INCLUDE_DIR + NAMES + sndio.h + HINTS + ${PC_SNDIO_INCLUDEDIR} + ${PC_SNDIO_INCLUDE_DIRS} + ${SNDIO_ROOT} + ) + +find_library (SNDIO_LIBRARY + NAMES + sndio + HINTS + ${PC_SNDIO_LIBDIR} + ${PC_SNDIO_LIBRARY_DIRS} + ${SNDIO_ROOT} + ) + +include (FindPackageHandleStandardArgs) +find_package_handle_standard_args (Sndio + REQUIRED_VARS + SNDIO_LIBRARY + SNDIO_INCLUDE_DIR + VERSION_VAR + SNDIO_VERSION + ) + +if (SNDIO_FOUND) + set (SNDIO_LIBRARIES ${SNDIO_LIBRARY}) + set (SNDIO_INCLUDE_DIRS ${SNDIO_INCLUDE_DIR}) + if (NOT TARGET Sndio::Sndio) + add_library (Sndio::Sndio UNKNOWN IMPORTED) + set_target_properties (Sndio::Sndio PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${SNDIO_INCLUDE_DIRS}" + IMPORTED_LOCATION "${SNDIO_LIBRARIES}" + ) + endif() +endif() + +mark_as_advanced (SNDIO_INCLUDE_DIR SNDIO_LIBRARY) diff --git a/extern/libsndfile-modified/cmake/FindSpeex.cmake b/extern/libsndfile-modified/cmake/FindSpeex.cmake new file mode 100644 index 000000000..c28fe60cb --- /dev/null +++ b/extern/libsndfile-modified/cmake/FindSpeex.cmake @@ -0,0 +1,55 @@ +# - Find Speex +# Find the native Speex includes and libraries +# +# SPEEX_INCLUDE_DIRS - where to find speex.h, etc. +# SPEEX_LIBRARIES - List of libraries when using Speex. +# SPEEX_FOUND - True if Speex found. + +if (SPEEX_INCLUDE_DIR) + set (SPEEX_FIND_QUIETLY TRUE) +endif () + +find_package (PkgConfig QUIET) +pkg_check_modules (PC_SPEEX QUIET speex) + +set (SPEEX_VERSION ${PC_SPEEX_VERSION}) + +find_path (SPEEX_INCLUDE_DIR speex/speex.h + HINTS + ${PC_SPEEX_INCLUDEDIR} + ${PC_SPEEX_INCLUDE_DIRS} + ${SPEEX_ROOT} + ) +find_library (SPEEX_LIBRARY + NAMES + speex + libspeex + HINTS + ${PC_SPEEX_LIBDIR} + ${PC_SPEEX_LIBRARY_DIRS} + ${SPEEX_ROOT} + ) + +include (FindPackageHandleStandardArgs) +find_package_handle_standard_args (Speex + REQUIRED_VARS + SPEEX_LIBRARY + SPEEX_INCLUDE_DIR + VERSION_VAR + SPEEX_VERSION + ) + +if (SPEEX_FOUND) + set (SPEEX_LIBRARIES ${SPEEX_LIBRARY}) + set (SPEEX_INCLUDE_DIRS ${SPEEX_INCLUDE_DIR}) + + if (NOT TARGET Speex::Speex) + add_library (Speex::Speex UNKNOWN IMPORTED) + set_target_properties (Speex::Speex PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${SPEEX_INCLUDE_DIRS}" + IMPORTED_LOCATION "${SPEEX_LIBRARIES}" + ) + endif () +endif () + +mark_as_advanced (SPEEX_INCLUDE_DIR SPEEX_LIBRARY) diff --git a/extern/libsndfile-modified/cmake/FindVorbis.cmake b/extern/libsndfile-modified/cmake/FindVorbis.cmake new file mode 100644 index 000000000..57e60557f --- /dev/null +++ b/extern/libsndfile-modified/cmake/FindVorbis.cmake @@ -0,0 +1,210 @@ +#[=======================================================================[.rst: +FindVorbis +---------- + +Finds the native vorbis, vorbisenc amd vorbisfile includes and libraries. + +Imported Targets +^^^^^^^^^^^^^^^^ + +This module provides the following imported targets, if found: + +``Vorbis::vorbis`` + The Vorbis library +``Vorbis::vorbisenc`` + The VorbisEnc library +``Vorbis::vorbisfile`` + The VorbisFile library + +Result Variables +^^^^^^^^^^^^^^^^ + +This will define the following variables: + +``Vorbis_Vorbis_INCLUDE_DIRS`` + List of include directories when using vorbis. +``Vorbis_Enc_INCLUDE_DIRS`` + List of include directories when using vorbisenc. +``Vorbis_File_INCLUDE_DIRS`` + List of include directories when using vorbisfile. +``Vorbis_Vorbis_LIBRARIES`` + List of libraries when using vorbis. +``Vorbis_Enc_LIBRARIES`` + List of libraries when using vorbisenc. +``Vorbis_File_LIBRARIES`` + List of libraries when using vorbisfile. +``Vorbis_FOUND`` + True if vorbis and requested components found. +``Vorbis_Vorbis_FOUND`` + True if vorbis found. +``Vorbis_Enc_FOUND`` + True if vorbisenc found. +``Vorbis_Enc_FOUND`` + True if vorbisfile found. + +Cache variables +^^^^^^^^^^^^^^^ + +The following cache variables may also be set: + +``Vorbis_Vorbis_INCLUDE_DIR`` + The directory containing ``vorbis/vorbis.h``. +``Vorbis_Enc_INCLUDE_DIR`` + The directory containing ``vorbis/vorbisenc.h``. +``Vorbis_File_INCLUDE_DIR`` + The directory containing ``vorbis/vorbisenc.h``. +``Vorbis_Vorbis_LIBRARY`` + The path to the vorbis library. +``Vorbis_Enc_LIBRARY`` + The path to the vorbisenc library. +``Vorbis_File_LIBRARY`` + The path to the vorbisfile library. + +Hints +^^^^^ + +A user may set ``Vorbis_ROOT`` to a vorbis installation root to tell this module where to look. + +#]=======================================================================] + +if (Vorbis_Vorbis_INCLUDE_DIR) + # Already in cache, be silent + set (Vorbis_FIND_QUIETLY TRUE) +endif () + +set (Vorbis_Vorbis_FIND_QUIETLY TRUE) +set (Vorbis_Enc_FIND_QUIETLY TRUE) +set (Vorbis_File_FIND_QUIETLY TRUE) + +find_package (Ogg QUIET) + +find_package (PkgConfig QUIET) +pkg_check_modules (PC_Vorbis_Vorbis QUIET vorbis) +pkg_check_modules (PC_Vorbis_Enc QUIET vorbisenc) +pkg_check_modules (PC_Vorbis_File QUIET vorbisfile) + +set (Vorbis_VERSION ${PC_Vorbis_Vorbis_VERSION}) + +find_path (Vorbis_Vorbis_INCLUDE_DIR vorbis/codec.h + HINTS + ${PC_Vorbis_Vorbis_INCLUDEDIR} + ${PC_Vorbis_Vorbis_INCLUDE_DIRS} + ${Vorbis_ROOT} + ) + +find_path (Vorbis_Enc_INCLUDE_DIR vorbis/vorbisenc.h + HINTS + ${PC_Vorbis_Enc_INCLUDEDIR} + ${PC_Vorbis_Enc_INCLUDE_DIRS} + ${Vorbis_ROOT} + ) + +find_path (Vorbis_File_INCLUDE_DIR vorbis/vorbisfile.h + HINTS + ${PC_Vorbis_File_INCLUDEDIR} + ${PC_Vorbis_File_INCLUDE_DIRS} + ${Vorbis_ROOT} + ) + +find_library (Vorbis_Vorbis_LIBRARY + NAMES + vorbis + vorbis_static + libvorbis + libvorbis_static + HINTS + ${PC_Vorbis_Vorbis_LIBDIR} + ${PC_Vorbis_Vorbis_LIBRARY_DIRS} + ${Vorbis_ROOT} + ) + +find_library (Vorbis_Enc_LIBRARY + NAMES + vorbisenc + vorbisenc_static + libvorbisenc + libvorbisenc_static + HINTS + ${PC_Vorbis_Enc_LIBDIR} + ${PC_Vorbis_Enc_LIBRARY_DIRS} + ${Vorbis_ROOT} + ) + +find_library (Vorbis_File_LIBRARY + NAMES + vorbisfile + vorbisfile_static + libvorbisfile + libvorbisfile_static + HINTS + ${PC_Vorbis_File_LIBDIR} + ${PC_Vorbis_File_LIBRARY_DIRS} + ${Vorbis_ROOT} + ) + +include (FindPackageHandleStandardArgs) + +if (Vorbis_Vorbis_LIBRARY AND Vorbis_Vorbis_INCLUDE_DIR AND Ogg_FOUND) + set (Vorbis_Vorbis_FOUND TRUE) +endif () + +if (Vorbis_Enc_LIBRARY AND Vorbis_Enc_INCLUDE_DIR AND Vorbis_Vorbis_FOUND) + set (Vorbis_Enc_FOUND TRUE) +endif () + +if (Vorbis_Vorbis_FOUND AND Vorbis_File_LIBRARY AND Vorbis_File_INCLUDE_DIR) + set (Vorbis_File_FOUND TRUE) +endif () + +find_package_handle_standard_args (Vorbis + REQUIRED_VARS + Vorbis_Vorbis_LIBRARY + Vorbis_Vorbis_INCLUDE_DIR + Ogg_FOUND + HANDLE_COMPONENTS + VERSION_VAR Vorbis_VERSION) + + +if (Vorbis_Vorbis_FOUND) + set (Vorbis_Vorbis_INCLUDE_DIRS ${VORBIS_INCLUDE_DIR}) + set (Vorbis_Vorbis_LIBRARIES ${VORBIS_LIBRARY} ${OGG_LIBRARIES}) + if (NOT TARGET Vorbis::vorbis) + add_library (Vorbis::vorbis UNKNOWN IMPORTED) + set_target_properties (Vorbis::vorbis PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${Vorbis_Vorbis_INCLUDE_DIR}" + IMPORTED_LOCATION "${Vorbis_Vorbis_LIBRARY}" + INTERFACE_LINK_LIBRARIES Ogg::ogg + ) + endif () + + if (Vorbis_Enc_FOUND) + set (Vorbis_Enc_INCLUDE_DIRS ${Vorbis_Enc_INCLUDE_DIR}) + set (Vorbis_Enc_LIBRARIES ${Vorbis_Enc_LIBRARY} ${Vorbis_Enc_LIBRARIES}) + if (NOT TARGET Vorbis::vorbisenc) + add_library (Vorbis::vorbisenc UNKNOWN IMPORTED) + set_target_properties (Vorbis::vorbisenc PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${Vorbis_Enc_INCLUDE_DIR}" + IMPORTED_LOCATION "${Vorbis_Enc_LIBRARY}" + INTERFACE_LINK_LIBRARIES Vorbis::vorbis + ) + endif () + endif () + + if (Vorbis_File_FOUND) + set (Vorbis_File_INCLUDE_DIRS ${Vorbis_File_INCLUDE_DIR}) + set (Vorbis_File_LIBRARIES ${Vorbis_File_LIBRARY} ${Vorbis_File_LIBRARIES}) + if (NOT TARGET Vorbis::vorbisfile) + add_library (Vorbis::vorbisfile UNKNOWN IMPORTED) + set_target_properties (Vorbis::vorbisfile PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${Vorbis_File_INCLUDE_DIR}" + IMPORTED_LOCATION "${Vorbis_File_LIBRARY}" + INTERFACE_LINK_LIBRARIES Vorbis::vorbis + ) + endif () + endif () + +endif () + +mark_as_advanced (Vorbis_Vorbis_INCLUDE_DIR Vorbis_Vorbis_LIBRARY) +mark_as_advanced (Vorbis_Enc_INCLUDE_DIR Vorbis_Enc_LIBRARY) +mark_as_advanced (Vorbis_File_INCLUDE_DIR Vorbis_File_LIBRARY) diff --git a/extern/libsndfile-modified/cmake/Findmp3lame.cmake b/extern/libsndfile-modified/cmake/Findmp3lame.cmake new file mode 100644 index 000000000..223dd08f5 --- /dev/null +++ b/extern/libsndfile-modified/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/extern/libsndfile-modified/cmake/Findmpg123.cmake b/extern/libsndfile-modified/cmake/Findmpg123.cmake new file mode 100644 index 000000000..36bb2389a --- /dev/null +++ b/extern/libsndfile-modified/cmake/Findmpg123.cmake @@ -0,0 +1,95 @@ +#[=======================================================================[.rst: +Findmpg123 +------- + +Finds the mpg123 library. + +Imported Targets +^^^^^^^^^^^^^^^^ + +This module provides the following imported targets, if found: + +``MPG123::libmpg123`` + The mpg123 library + +Result Variables +^^^^^^^^^^^^^^^^ + +This will define the following variables: + +``mpg123_FOUND`` + True if the system has the mpg123 package. +``mpg123_VERSION`` + The version of mpg123 that was found on the system. + +Cache Variables +^^^^^^^^^^^^^^^ + +The following cache variables may also be set: + +``mpg123_INCLUDE_DIR`` + The directory containing ``mpg123.h``. +``mpg123_LIBRARY`` + The path to the mpg123 library. + +#]=======================================================================] + +if (mpg123_INCLUDE_DIR) + # Already in cache, be silent + set(mpg123_FIND_QUIETLY TRUE) +endif () + +find_package (PkgConfig QUIET) +pkg_check_modules(PC_MPG123 QUIET libmpg123>=1.25.10) + +find_path (mpg123_INCLUDE_DIR mpg123.h + HINTS + ${PC_MPG123_INCLUDEDIR} + ${PC_MPG123_INCLUDE_DIRS} + ${mpg123_ROOT} + ) + +# MSVC built mpg123 may be named mpg123_static. +# The provided project files name the library with the lib prefix. + +find_library (mpg123_LIBRARY + NAMES + mpg123 + mpg123_static + libmpg123 + libmpg123_static + HINTS + ${PC_MPG123_LIBDIR} + ${PC_MPG123_LIBRARY_DIRS} + ${mpg123_ROOT} + ) + +if (PC_MPG123_FOUND) + set (mpg123_VERSION ${PC_MPG123_VERSION}) +elseif (mpg123_INCLUDE_DIR) + file (READ "${mpg123_INCLUDE_DIR}/mpg123.h" _mpg123_h) + string (REGEX MATCH "[0-9]+.[0-9]+.[0-9]+" _mpg123_version_re "${_mpg123_h}") + set (mpg123_VERSION "${_mpg123_version_re}") +endif () + +# Handle the QUIETLY and REQUIRED arguments and set mpg123_FOUND +# to TRUE if all listed variables are TRUE. +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args (mpg123 + REQUIRED_VARS + mpg123_LIBRARY + mpg123_INCLUDE_DIR + VERSION_VAR + mpg123_VERSION + ) + +if (mpg123_FOUND AND NOT TARGET MPG123::libmpg123) + add_library (MPG123::libmpg123 UNKNOWN IMPORTED) + set_target_properties (MPG123::libmpg123 + PROPERTIES + IMPORTED_LOCATION "${mpg123_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${mpg123_INCLUDE_DIR}" + ) +endif () + +mark_as_advanced(mpg123_INCLUDE_DIR mpg123_LIBRARY) diff --git a/extern/libsndfile-modified/cmake/SetupABIVersions.cmake b/extern/libsndfile-modified/cmake/SetupABIVersions.cmake new file mode 100644 index 000000000..331a2bd9a --- /dev/null +++ b/extern/libsndfile-modified/cmake/SetupABIVersions.cmake @@ -0,0 +1,56 @@ +# Inspiration: https://github.com/ros2-dotnet/Fast-RTPS + +macro (SETUP_ABI_VERSIONS) + + file (STRINGS ${PROJECT_SOURCE_DIR}/configure.ac CONFIGURE_AC_CONTENT) + file (STRINGS + configure.ac + SNDFILE_LT_CURRENT_TMP + REGEX "^m4_define\\(\\[?lt_current\\]?, *\\[?[0-9]+\\]?\\)" + ) + string (REGEX REPLACE "m4_define\\(\\[?lt_current\\]?, *\\[?([0-9]+)\\]?\\)" + "\\1" + SNDFILE_LT_CURRENT + ${SNDFILE_LT_CURRENT_TMP} + ) + + file (STRINGS + configure.ac + SNDFILE_LT_REVISION_TMP + REGEX "^m4_define\\(\\[?lt_revision\\]?, *\\[?[0-9]+\\]?\\)" + ) + string (REGEX REPLACE "m4_define\\(\\[?lt_revision\\]?, *\\[?([0-9]+)\\]?\\)" + "\\1" + SNDFILE_LT_REVISION + ${SNDFILE_LT_REVISION_TMP} + ) + + file (STRINGS + configure.ac + SNDFILE_LT_AGE_TMP + REGEX "^m4_define\\(\\[?lt_age\\]?, *\\[?[0-9]+\\]?\\)" + ) + string (REGEX REPLACE "m4_define\\(\\[?lt_age\\]?, *\\[?([0-9]+)\\]?\\)" + "\\1" + SNDFILE_LT_AGE + ${SNDFILE_LT_AGE_TMP} + ) + + # + # Calculate CMake compatible ABI version from libtool version. + # + + math (EXPR SNDFILE_ABI_VERSION_MAJOR "${SNDFILE_LT_CURRENT} - ${SNDFILE_LT_AGE}") + set (SNDFILE_ABI_VERSION_MINOR ${SNDFILE_LT_AGE}) + set (SNDFILE_ABI_VERSION_PATCH ${SNDFILE_LT_REVISION}) + set (SNDFILE_ABI_VERSION "${SNDFILE_ABI_VERSION_MAJOR}.${SNDFILE_ABI_VERSION_MINOR}.${SNDFILE_ABI_VERSION_PATCH}") + + # + # Apple platform current and compatibility versions. + # + + math (EXPR SNDFILE_MACHO_CURRENT_VERSION_MAJOR "${SNDFILE_ABI_VERSION_MAJOR} + ${SNDFILE_ABI_VERSION_MINOR} + 1") + set (SNDFILE_MACHO_CURRENT_VERSION "${SNDFILE_MACHO_CURRENT_VERSION_MAJOR}.${SNDFILE_ABI_VERSION_PATCH}.0") + set (SNDFILE_MACHO_COMPATIBILITY_VERSION "${SNDFILE_MACHO_CURRENT_VERSION_MAJOR}.0.0") + +endmacro (SETUP_ABI_VERSIONS) diff --git a/extern/libsndfile-modified/cmake/SndFileChecks.cmake b/extern/libsndfile-modified/cmake/SndFileChecks.cmake new file mode 100644 index 000000000..2ad8ccde0 --- /dev/null +++ b/extern/libsndfile-modified/cmake/SndFileChecks.cmake @@ -0,0 +1,256 @@ +include (CheckFunctionExists) +include (CheckIncludeFile) +include (CheckLibraryExists) +include (CheckSymbolExists) +include (CheckTypeSize) +include (TestBigEndian) + +include (TestInline) +include (ClipMode) +include (TestLargeFiles) +include (CheckCPUArch) + +test_large_files (_LARGEFILES) + +if (LARGE_FILES_DEFINITIONS) + add_definitions(${LARGE_FILES_DEFINITIONS}) +endif () + +if (CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") + find_package (Sndio) +elseif (NOT WIN32) + find_package (ALSA) +endif () + +if (VCPKG_TOOLCHAIN AND (NOT CMAKE_VERSION VERSION_LESS 3.15)) + set (CMAKE_FIND_PACKAGE_PREFER_CONFIG ON) +endif () + +if (CMAKE_FIND_PACKAGE_PREFER_CONFIG) + find_package (Ogg 1.3 CONFIG) + find_package (Vorbis CONFIG COMPONENTS Enc) + find_package (FLAC CONFIG) + find_package (Opus CONFIG) + + include (FindPackageHandleStandardArgs) + find_package_handle_standard_args (Ogg CONFIG_MODE) + find_package_handle_standard_args (Vorbis CONFIG_MODE) + find_package_handle_standard_args (FLAC CONFIG_MODE) + find_package_handle_standard_args (Opus CONFIG_MODE) +else () + find_package (Ogg 1.3) + find_package (Vorbis COMPONENTS Enc) + find_package (FLAC) + find_package (Opus) +endif () +if (Vorbis_FOUND AND FLAC_FOUND AND Opus_FOUND) + set (HAVE_EXTERNAL_XIPH_LIBS 1) +else () + set (HAVE_EXTERNAL_XIPH_LIBS 0) +endif () + +find_package (mp3lame) +find_package (mpg123 1.25.10) +if (TARGET mp3lame::mp3lame AND (TARGET MPG123::libmpg123)) + set (HAVE_MPEG_LIBS 1) +else () + set (HAVE_MPEG_LIBS 0) +endif() + +find_package (Speex) +find_package (SQLite3) + +check_include_file (byteswap.h HAVE_BYTESWAP_H) +check_include_file (dlfcn.h HAVE_DLFCN_H) +check_include_file (direct.h HAVE_DIRECT_H) +check_include_file (endian.h HAVE_ENDIAN_H) +check_include_file (inttypes.h HAVE_INTTYPES_H) +check_include_file (io.h HAVE_IO_H) +check_include_file (stdint.h HAVE_STDINT_H) +check_include_file (sys/time.h HAVE_SYS_TIME_H) +check_include_file (sys/types.h HAVE_SYS_TYPES_H) +check_include_file (unistd.h HAVE_UNISTD_H) +check_include_file (immintrin.h HAVE_IMMINTRIN_H) +check_include_file (stdbool.h HAVE_STDBOOL_H) + +check_cpu_arch_x86 (CPU_IS_X86) +check_cpu_arch_x64 (CPU_IS_X64) +if ((CPU_IS_X86 OR CPU_IS_X64) AND HAVE_IMMINTRIN_H) + set (HAVE_SSE2 1) +endif () + +# Never checked +# check_include_file (stdlib.h HAVE_STDLIB_H) +# check_include_file (string.h HAVE_STRING_H) +# check_include_file (strings.h HAVE_STRINGS_H) +# check_include_file (sys/stat.h HAVE_SYS_STAT_H) +# check_include_file (memory.h HAVE_MEMORY_H) + +if (BUILD_TESTING) + check_include_file (locale.h HAVE_LOCALE_H) + check_include_file (sys/wait.h HAVE_SYS_WAIT_H) +endif () + +check_type_size (int64_t SIZEOF_INT64_T) +check_type_size (long SIZEOF_LONG) +check_type_size (long\ long SIZEOF_LONG_LONG) +check_type_size (ssize_t SIZEOF_SSIZE_T) +check_type_size (wchar_t SIZEOF_WCHAR_T) + +# Never used +# check_type_size (loff_t SIZEOF_LOFF_T) +# check_type_size (offt64_t SIZEOF_OFF64_T) + +# Never checked +# check_type_size (size_t SIZEOF_SIZE_T) + +# Used in configre.ac +# check_type_size (double SIZEOF_DOUBLE) +# check_type_size (float SIZEOF_FLOAT) +# check_type_size (int SIZEOF_INT) +# check_type_size (short SIZEOF_SHORT) + +if (ENABLE_TESTING) + check_type_size (void* SIZEOF_VOIDP) +endif() + +if (NOT WIN32) + check_library_exists (m floor "" LIBM_REQUIRED) + if (LIBM_REQUIRED) + list (APPEND CMAKE_REQUIRED_LIBRARIES m) + endif () +endif () + +check_library_exists (sqlite3 sqlite3_close "" HAVE_SQLITE3) + +check_function_exists (fstat HAVE_FSTAT) +check_function_exists (fstat64 HAVE_FSTAT64) +check_function_exists (gettimeofday HAVE_GETTIMEOFDAY) +check_function_exists (gmtime HAVE_GMTIME) +check_function_exists (gmtime_r HAVE_GMTIME_R) +check_function_exists (localtime HAVE_LOCALTIME) +check_function_exists (localtime_r HAVE_LOCALTIME_R) +check_function_exists (lseek HAVE_LSEEK) +check_function_exists (open HAVE_OPEN) +check_function_exists (read HAVE_READ) +check_function_exists (write HAVE_WRITE) +check_function_exists (lrint HAVE_LRINT) +check_function_exists (lrintf HAVE_LRINTF) + +if (NOT WIN32) + check_function_exists (ftruncate HAVE_FTRUNCATE) + check_function_exists (fsync HAVE_FSYNC) +endif () + +if (BUILD_TESTING) + check_function_exists (pipe HAVE_PIPE) + check_function_exists (setlocale HAVE_SETLOCALE) + check_function_exists (waitpid HAVE_WAITPID) +endif () + +# Never checked +# check_function_exists (calloc HAVE_CALLOC) +# check_function_exists (free HAVE_FREE) +# check_function_exists (getpagesize HAVE_GETPAGESIZE) +# check_function_exists (malloc HAVE_MALLOC) +# check_function_exists (realloc HAVE_REALLOC) +# check_function_exists (snprintf HAVE_SNPRINTF) +# check_function_exists (vsnprintf HAVE_VSNPRINTF) +# check_function_exists (floor HAVE_FLOOR) +# check_function_exists (fmod HAVE_FMOD) + +# Never used +# check_function_exists (mmap HAVE_MMAP) +# check_function_exists (ceil HAVE_CEIL) +# check_function_exists (lround HAVE_LROUND) +# check_function_exists (lseek64 HAVE_LSEEK64) + + +check_symbol_exists (S_IRGRP sys/stat.h HAVE_DECL_S_IRGRP) + +test_big_endian (WORDS_BIGENDIAN) +if (WORDS_BIGENDIAN) + set (CPU_IS_BIG_ENDIAN 1) +else () + set (CPU_IS_LITTLE_ENDIAN 1) +endif () + +if (WIN32) + set (OS_IS_WIN32 1) + set (USE_WINDOWS_API 1) + if (BUILD_SHARED_LIBS) + set (WIN32_TARGET_DLL 1) + endif () + if (MINGW) + add_definitions (-D__USE_MINGW_ANSI_STDIO=1) + endif () +endif () + +if (CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") + set (OS_IS_OPENBSD 1) +endif () + + +if (CMAKE_COMPILER_IS_GNUCC OR (CMAKE_C_COMPILER_ID MATCHES "Clang")) + set (COMPILER_IS_GCC 1) +endif () + +test_inline () +clip_mode () + +if (MSVC) + add_definitions (-D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE) +endif (MSVC) + +if (DEFINED ENABLE_STATIC_RUNTIME) + if (MSVC) + if (ENABLE_STATIC_RUNTIME) + foreach (flag_var + CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE + CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO + CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE + CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO + ) + if (${flag_var} MATCHES "/MD") + string (REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") + endif () + endforeach (flag_var) + else () + foreach (flag_var + CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE + CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO + CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE + CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO + ) + if (${flag_var} MATCHES "/MT") + string (REGEX REPLACE "/MT" "/MD" ${flag_var} "${${flag_var}}") + endif (${flag_var} MATCHES "/MT") + endforeach (flag_var) + endif ( ) + elseif (MINGW) + if (ENABLE_STATIC_RUNTIME) + if (CMAKE_C_COMPILER_ID STREQUAL GNU) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -static-libgcc") + set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "${CMAKE_SHARED_LIBRARY_LINK_C_FLAGS} -static-libgcc -s") + endif () + if (CMAKE_CXX_COMPILER_ID STREQUAL GNU) + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -static-libstdc++") + set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "${CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS} -static-libgcc -static-libstdc++ -s") + endif () + if (CMAKE_C_COMPILER_ID STREQUAL Clang) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -static") + set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "${CMAKE_SHARED_LIBRARY_LINK_C_FLAGS} -static") + endif () + if (CMAKE_CXX_COMPILER_ID STREQUAL Clang) + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static") + set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "${CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS} -static") + endif () + endif () + else () + message (AUTHOR_WARNING "ENABLE_STATIC_RUNTIME option is for MSVC or MinGW only.") + endif () +endif () + +if (BUILD_SHARED_LIBS) + find_package (PythonInterp REQUIRED) +endif() diff --git a/extern/libsndfile-modified/cmake/SndFileConfig.cmake.in b/extern/libsndfile-modified/cmake/SndFileConfig.cmake.in new file mode 100644 index 000000000..f3923357b --- /dev/null +++ b/extern/libsndfile-modified/cmake/SndFileConfig.cmake.in @@ -0,0 +1,46 @@ +set(SndFile_VERSION @PROJECT_VERSION@) +set(SndFile_VERSION_MAJOR @PROJECT_VERSION_MAJOR@) +set(SndFile_VERSION_MINOR @PROJECT_VERSION_MINOR@) +set(SndFile_VERSION_PATCH @PROJECT_VERSION_PATCH@) + +set (SndFile_WITH_EXTERNAL_LIBS @SndFile_WITH_EXTERNAL_LIBS@) +set (SndFile_WITH_MPEG @SndFile_WITH_MPEG@) + +@PACKAGE_INIT@ + +include (CMakeFindDependencyMacro) + +if (NOT @BUILD_SHARED_LIBS@) + list (APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}) +endif () + +if (SndFile_WITH_EXTERNAL_LIBS AND NOT @BUILD_SHARED_LIBS@) + find_dependency (Ogg 1.3) + find_dependency (Vorbis) + find_dependency (FLAC) + find_dependency (Opus) +endif () + +if (SndFile_WITH_MPEG AND NOT @BUILD_SHARED_LIBS@) + find_dependency (mp3lame) + find_dependency (mpg123) +endif () + +if (NOT @BUILD_SHARED_LIBS@) + list (REMOVE_ITEM CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}) +endif () + +include (${CMAKE_CURRENT_LIST_DIR}/SndFileTargets.cmake) + +set_and_check (SndFile_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@") +set (SNDFILE_INCLUDE_DIR ${SndFile_INCLUDE_DIR}) + +set (SndFile_LIBRARY SndFile::sndfile) +set (SNDFILE_LIBRARY SndFile::sndfile) +set (SndFile_LIBRARIES SndFile::sndfile) +set (SNDFILE_LIBRARIES SndFile::sndfile) + + +check_required_components(SndFile) + +set (SNDFILE_FOUND 1) diff --git a/extern/libsndfile-modified/cmake/TestInline.c.in b/extern/libsndfile-modified/cmake/TestInline.c.in new file mode 100644 index 000000000..2aed64334 --- /dev/null +++ b/extern/libsndfile-modified/cmake/TestInline.c.in @@ -0,0 +1,10 @@ +static @INLINE_KEYWORD@ void test_inline(void) +{ + return; +} + +int main (void) +{ + test_inline (); + return 0; +} diff --git a/extern/libsndfile-modified/cmake/TestInline.cmake b/extern/libsndfile-modified/cmake/TestInline.cmake new file mode 100644 index 000000000..ef15c0785 --- /dev/null +++ b/extern/libsndfile-modified/cmake/TestInline.cmake @@ -0,0 +1,54 @@ +macro (TEST_INLINE) + if (NOT DEFINED INLINE_CODE) + message (STATUS "Checking for inline...") + set (INLINE_KEYWORD "inline") + configure_file (cmake/TestInline.c.in ${PROJECT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/TestInline.c) + try_compile (HAVE_INLINE "${CMAKE_CURRENT_BINARY_DIR}" + "${PROJECT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/TestInline.c") + if (HAVE_INLINE) + message (STATUS "Checking for inline... supported") + else () + message (STATUS "Checking for inline... not supported") + + message (STATUS "Checking for __inline...") + set (INLINE_KEYWORD "__inline") + configure_file (cmake/TestInline.c.in ${PROJECT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/TestInline.c) + try_compile (HAVE___INLINE "${CMAKE_CURRENT_BINARY_DIR}" + "${PROJECT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/TestInline.c") + if (HAVE___INLINE) + message (STATUS "Checking for __inline... supported") + else () + message (STATUS "Checking for __inline... not supported") + + message (STATUS "Checking for __inline__...") + set (INLINE_KEYWORD "__inline__") + configure_file (cmake/TestInline.c.in ${PROJECT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/TestInline.c) + try_compile (HAVE___INLINE "${CMAKE_CURRENT_BINARY_DIR}" + "${PROJECT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/TestInline.c") + if (HAVE___INLINE) + message (STATUS "Checking for __inline__... supported") + + message (STATUS "Checking for __inline__...") + set (INLINE_KEYWORD "__inline__") + configure_file (cmake/TestInline.c.in ${PROJECT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/cmake/TestInline.c) + try_compile (HAVE___INLINE__ "${CMAKE_CURRENT_BINARY_DIR}" + "${PROJECT_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/TestInline.c") + else () + message (STATUS "Checking for __inline__... not supported") + set (INLINE_KEYWORD "") + endif () + + endif () + endif () + + if (HAVE_INLINE) + set (INLINE_CODE "/* #undef inline */" CACHE INTERNAL "") + elseif (HAVE___INLINE) + set (INLINE_CODE "#define inline __inline" CACHE INTERNAL "") + elseif (HAVE___INLINE__) + set (INLINE_CODE "#define inline __inline__" CACHE INTERNAL "") + else () + set (INLINE_CODE "#define inline " CACHE INTERNAL "") + endif () + endif () +endmacro (TEST_INLINE) diff --git a/extern/libsndfile-modified/cmake/TestLargeFiles.cmake b/extern/libsndfile-modified/cmake/TestLargeFiles.cmake new file mode 100644 index 000000000..075407b4a --- /dev/null +++ b/extern/libsndfile-modified/cmake/TestLargeFiles.cmake @@ -0,0 +1,121 @@ +include (CheckIncludeFile) +include (CheckTypeSize) +include (CMakePushCheckState) + +macro (TEST_LARGE_FILES VARIABLE) + +if (NOT DEFINED ${VARIABLE}) + + cmake_push_check_state() + + message (STATUS "") + message (STATUS "") + message (STATUS "Checking large files support...") + + if (WIN32) + set (${VARIABLE} 1 CACHE INTERNAL "Result of tests for large file support" FORCE) + message (STATUS "") + message (STATUS "Result of checking large files support: supported with WinAPI") + else () + + message (STATUS "") + check_include_file(sys/types.h HAVE_SYS_TYPES_H) + check_include_file(stdint.h HAVE_STDINT_H) + check_include_file(stddef.h HAVE_STDDEF_H) + message (STATUS "") + + message (STATUS "Checking size of off_t without any definitions:") + check_type_size (off_t SIZEOF_OFF_T) + message (STATUS "Checking of off_t without any definitions: ${SIZEOF_OFF_T}") + if (SIZEOF_OFF_T EQUAL 8) + set (LARGE_FILES_DEFINITIONS "" CACHE INTERNAL "64-bit off_t required definitions") + set (FILE64 TRUE) + else () + unset (HAVE_SIZEOF_OFF_T CACHE) + unset (SIZEOF_OFF_T CACHE) + unset (SIZEOF_OFF_T_CODE CACHE) + cmake_pop_check_state() + set (FILE64 FALSE) + endif () + + if (NOT FILE64) + set (CMAKE_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} /D_FILE_OFFSET_BITS=64) + message (STATUS "") + message (STATUS "Checking size of off_t with _FILE_OFFSET_BITS=64:") + check_type_size (off_t SIZEOF_OFF_T) + message (STATUS "Checking size of off_t with _FILE_OFFSET_BITS=64: ${SIZEOF_OFF_T}") + if (SIZEOF_OFF_T EQUAL 8) + set (_FILE_OFFSET_BITS 64 CACHE INTERNAL "") + set (_FILE_OFFSET_BITS_CODE "#define _FILE_OFFSET_BITS 64" CACHE INTERNAL "") + set (LARGE_FILES_DEFINITIONS ${LARGE_FILES_DEFINITIONS} "/D_FILE_OFFSET_BITS=64" CACHE INTERNAL "64-bit off_t required definitions") + set (FILE64 TRUE) + else () + set (_FILE_OFFSET_BITS_CODE "" CACHE INTERNAL "") + unset (HAVE_SIZEOF_OFF_T CACHE) + unset (SIZEOF_OFF_T CACHE) + unset (SIZEOF_OFF_T_CODE CACHE) + cmake_pop_check_state() + set (FILE64 FALSE) + endif () + endif () + + if (NOT FILE64) + set (CMAKE_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} /D_LARGE_FILES) + message (STATUS "") + message (STATUS "Checking size of off_t with _LARGE_FILES:") + check_type_size (off_t SIZEOF_OFF_T) + message (STATUS "Checking size of off_t with _LARGE_FILES: ${SIZEOF_OFF_T}") + if (SIZEOF_OFF_T EQUAL 8) + set (_LARGE_FILES 1 CACHE INTERNAL "") + set (LARGE_FILES_DEFINITIONS ${LARGE_FILES_DEFINITIONS} "/D_LARGE_FILES" CACHE INTERNAL "64-bit off_t required definitions") + set (FILE64 TRUE) + else () + unset (HAVE_SIZEOF_OFF_T CACHE) + unset (SIZEOF_OFF_T CACHE) + unset (SIZEOF_OFF_T_CODE CACHE) + cmake_pop_check_state() + set (FILE64 FALSE) + endif () + endif () + + if (NOT FILE64) + set (CMAKE_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} /D_LARGEFILE_SOURCE) + unset (HAVE_SIZEOF_OFF_T CACHE) + unset (SIZEOF_OFF_T CACHE) + unset (SIZEOF_OFF_T_CODE CACHE) + message (STATUS "") + message (STATUS "Checking size of off_t with _LARGEFILE_SOURCE:") + check_type_size (off_t SIZEOF_OFF_T) + message (STATUS "Checking size of off_t with _LARGEFILE_SOURCE: ${SIZEOF_OFF_T}") + if (SIZEOF_OFF_T EQUAL 8) + set (_LARGEFILE_SOURCE 1 CACHE INTERNAL "") + set (LARGE_FILES_DEFINITIONS ${LARGE_FILES_DEFINITIONS} "/D_LARGEFILE_SOURCE" CACHE INTERNAL "64-bit off_t required definitions") + set (FILE64 TRUE) + else () + cmake_pop_check_state() + set (FILE64 FALSE) + endif () + endif () + + message (STATUS "") + if (FILE64) + set (${VARIABLE} 1 CACHE INTERNAL "Result of tests for large file support" FORCE) + if (NOT SIZEOF_OFF_T_REQURED_DEFINITIONS) + message (STATUS "Result of checking large files support: supported") + else () + message (STATUS "Result of checking large files support: supported with ${LARGE_FILES_DEFINITIONS}") + message (STATUS "Add LARGE_FILES_DEFINITIONS to your compiler definitions or configure with _FILE_OFFSET_BITS,") + message (STATUS "_FILE_OFFSET_BITS_CODE, _LARGE_FILES and _LARGEFILE_SOURCE variables.") + endif () + else () + message ("Result of checking large files support: not supported") + set (${VARIABLE} 0 CACHE INTERNAL "Result of test for large file support" FORCE) + endif () + message ("") + message ("") + + endif () + +endif (NOT DEFINED ${VARIABLE}) + +endmacro (TEST_LARGE_FILES VARIABLE) diff --git a/extern/libsndfile-modified/cmake/sqlite/FindSQLite3.cmake b/extern/libsndfile-modified/cmake/sqlite/FindSQLite3.cmake new file mode 100644 index 000000000..a0385caaa --- /dev/null +++ b/extern/libsndfile-modified/cmake/sqlite/FindSQLite3.cmake @@ -0,0 +1,56 @@ +# - Find SQLite3 +# Find the native SQLite3 includes and libraries +# +# SQLite3_INCLUDE_DIRS - where to find sqlite3.h, etc. +# SQLite3_LIBRARIES - List of libraries when using SQLite3. +# SQLite3_FOUND - True if SQLite3 found. + +if (SQLite3_INCLUDE_DIR) + # Already in cache, be silent + set (SQLite3_FIND_QUIETLY TRUE) +endif () + +find_package (PkgConfig QUIET) +pkg_check_modules (PC_SQLite3 QUIET sqlite3) + +set (SQLite3_VERSION ${PC_SQLite3_VERSION}) + +find_path (SQLite3_INCLUDE_DIR sqlite3.h + HINTS + ${PC_SQLite3_INCLUDEDIR} + ${PC_SQLite3_INCLUDE_DIRS} + ${SQLite3_ROOT} + ) + +find_library (SQLite3_LIBRARY + NAMES + sqlite3 + HINTS + ${PC_SQLite3_LIBDIR} + ${PC_SQLite3_LIBRARY_DIRS} + ${SQLite3_ROOT} + ) + +include (FindPackageHandleStandardArgs) + +find_package_handle_standard_args (SQLite3 + REQUIRED_VARS + SQLite3_LIBRARY + SQLite3_INCLUDE_DIR + VERSION_VAR + SQLite3_VERSION + ) + +if (SQLite3_FOUND) + set (SQLite3_INCLUDE_DIRS ${SQLite3_INCLUDE_DIR}) + set (SQLite3_LIBRARIES ${SQLite3_LIBRARY}) + if (NOT TARGET SQLite::SQLite3) + add_library (SQLite::SQLite3 UNKNOWN IMPORTED) + set_target_properties (SQLite::SQLite3 PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${SQLite3_INCLUDE_DIRS}" + IMPORTED_LOCATION "${SQLite3_LIBRARIES}" + ) + endif () +endif () + +mark_as_advanced (SQLite3_INCLUDE_DIR SQLite3_LIBRARY) diff --git a/extern/libsndfile-modified/configure.ac b/extern/libsndfile-modified/configure.ac new file mode 100644 index 000000000..dc0d5e1d7 --- /dev/null +++ b/extern/libsndfile-modified/configure.ac @@ -0,0 +1,761 @@ +dnl Copyright (C) 1999-2022 Erik de Castro Lopo . + +dnl Require autoconf version >= 2.69 +AC_PREREQ([2.69]) + +AC_INIT([libsndfile],[1.2.2],[sndfile@mega-nerd.com], + [libsndfile],[http://libsndfile.github.io/libsndfile/]) + +dnl Check whether we want to set defaults for CFLAGS, CXXFLAGS, CPPFLAGS and LDFLAGS +AC_MSG_CHECKING([whether configure should try to set CFLAGS/CXXFLAGS/CPPFLAGS/LDFLAGS]) +AS_IF([test "x${CFLAGS+set}" = "xset" || test "x${CXXFLAGS+set}" = "xset" || test "x${CPPFLAGS+set}" = "xset" || test "x${LDFLAGS+set}" = "xset"], [ + enable_flags_setting=no + : ${CFLAGS=""} + : ${CXXFLAGS=""} + ], [ + enable_flags_setting=yes + dnl Set to empty flags so AC_PROG_CC and + dnl AC_PROG_CXX do not add -g -O2 + CFLAGS="" + CXXFLAGS="" + ]) +AC_MSG_RESULT([${enable_flags_setting}]) + +dnl Put config stuff in 'build-aux'. +AC_CONFIG_AUX_DIR([build-aux]) + +AC_CONFIG_SRCDIR([src/sndfile.c]) +AC_CANONICAL_HOST + +AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_HEADERS([src/config.h]) + +AM_INIT_AUTOMAKE([1.14 foreign dist-xz no-dist-gzip serial-tests subdir-objects]) +AM_SILENT_RULES([yes]) + +dnl ==================================================================================== + +AC_PROG_CC +AC_PROG_CC_C99 + +AS_IF([test "x$ac_cv_prog_cc_c99" = "xno"], [ + AC_MSG_ERROR([libsndfile requires a C99 capable compiler!]) + ]) + +AC_USE_SYSTEM_EXTENSIONS +AC_PROG_CXX + +AC_LANG([C]) +AX_COMPILER_VENDOR +AX_COMPILER_VERSION + +AC_LANG_PUSH([C++]) +AX_COMPILER_VENDOR +AX_COMPILER_VERSION +AC_LANG_POP([C++]) + +AC_PROG_SED +AM_PROG_AR + +LT_INIT([disable-static win32-dll]) +LT_PROG_RC + +AC_PROG_INSTALL +AC_PROG_LN_S + +AM_PATH_PYTHON + +AC_CHECK_PROG([HAVE_AUTOGEN], [autogen], [yes], [no]) +AC_CHECK_PROG([HAVE_WINE], [wine], [yes], [no]) +AC_CHECK_PROG([HAVE_XCODE_SELECT], [xcode-select], [yes], [no]) + +dnl ------------------------------------------------------------------------------------ +dnl Rules for library version information: +dnl +dnl 1. Start with version information of `0:0:0' for each libtool library. +dnl 2. Update the version information only immediately before a public release of +dnl your software. More frequent updates are unnecessary, and only guarantee +dnl that the current interface number gets larger faster. +dnl 3. If the library source code has changed at all since the last update, then +dnl increment revision (`c:r:a' becomes `c:r+1:a'). +dnl 4. If any interfaces have been added, removed, or changed since the last update, +dnl increment current, and set revision to 0. +dnl 5. If any interfaces have been added since the last public release, then increment +dnl age. +dnl 6. If any interfaces have been removed since the last public release, then set age +dnl to 0. + +dnl This is libtool version of library, we add it to `--version-info` property. + +m4_define([lt_current], [1]) +m4_define([lt_revision], [37]) +m4_define([lt_age], [0]) + +dnl This is ABI version for linker scripts, CMake uses the same format for +dnl VERSION property of shared library. +dnl The formula is: c:r:a -> c-a:a:r + +m4_define([abi_version_major], [m4_eval(lt_current - lt_age)]) +m4_define([abi_version_minor], [lt_age]) +m4_define([abi_version_patch], [lt_revision]) + +dnl ------------------------------------------------------------------------------------ + +AC_CHECK_HEADERS([endian.h]) +AC_CHECK_HEADERS([byteswap.h]) +AC_CHECK_HEADERS([locale.h]) +AC_CHECK_HEADERS([sys/time.h]) +AC_CHECK_HEADERS([immintrin.h]) +AC_CHECK_HEADERS([stdbool.h]) + +AC_HEADER_SYS_WAIT + +AC_CHECK_DECLS([S_IRGRP]) +AS_IF([test "x$ac_cv_have_decl_S_IRGRP" = "xyes"], [ + AC_DEFINE_UNQUOTED([HAVE_DECL_S_IRGRP], [1], [Set to 1 if S_IRGRP is defined.]) + ], [ + AC_DEFINE_UNQUOTED([HAVE_DECL_S_IRGRP], [0], [Set to 0 if S_IRGRP is not defined.]) + ]) + +AM_CONDITIONAL([LINUX_MINGW_CROSS_TEST], + [test "x${build_os}:${host_os}:${HAVE_WINE}" = "xlinux-gnu:mingw32msvc:yes"]) + +dnl ==================================================================================== +dnl Couple of initializations here. Fill in real values later. + +SHLIB_VERSION_ARG="" + +dnl ==================================================================================== +dnl Finished checking, handle options. + +AC_ARG_ENABLE(experimental, + AS_HELP_STRING([--enable-experimental], [enable experimental code])) + +AS_IF([test "x$enable_experimental" = "xyes"], [ + EXPERIMENTAL_CODE=1 + ], [ + EXPERIMENTAL_CODE=0 + ]) +AC_DEFINE_UNQUOTED([ENABLE_EXPERIMENTAL_CODE], [${EXPERIMENTAL_CODE}], [Set to 1 to enable experimental code.]) + +AC_ARG_ENABLE([werror], + [AS_HELP_STRING([--enable-werror], [enable -Werror in all Makefiles])]) + +AC_ARG_ENABLE([cpu-clip], + [AS_HELP_STRING([--disable-cpu-clip], [disable tricky cpu specific clipper])]) + +AC_ARG_ENABLE([bow-docs], + [AS_HELP_STRING([--enable-bow-docs], [enable black-on-white html docs])]) + +AC_ARG_ENABLE([sqlite], + [AS_HELP_STRING([--disable-sqlite], [disable use of sqlite])]) + +AC_ARG_ENABLE([alsa], + [AS_HELP_STRING([--disable-alsa], [disable ALSA support (default=autodetect)])], [], [enable_alsa=auto]) + +AC_ARG_ENABLE([external-libs], + [AS_HELP_STRING([--disable-external-libs], [disable use of FLAC, Ogg and Vorbis [[default=no]]])]) + +AC_ARG_ENABLE([mpeg], + [AS_HELP_STRING([--disable-mpeg], [disable use of LAME/MPG123 for MPEG (MP3) [[defaults=no]]])]) + +AC_ARG_ENABLE(octave, + [AS_HELP_STRING([--enable-octave], [enable building of GNU Octave module])]) + +AC_ARG_ENABLE([full-suite], + [AS_HELP_STRING([--disable-full-suite], [disable building and installing programs, documentation, only build library [[default=no]]])]) +AM_CONDITIONAL([FULL_SUITE], [test "x$enable_full_suite" != "xno"]) + +AC_ARG_ENABLE([test-coverage], + [AS_HELP_STRING([--enable-test-coverage], [enable test coverage])]) +AM_CONDITIONAL([ENABLE_TEST_COVERAGE], [test "x$enable_test_coverage" = "xyes"]) + +AC_ARG_ENABLE([ossfuzzers], + [AS_HELP_STRING([--enable-ossfuzzers], [Whether to generate the fuzzers for OSS-Fuzz])]) +AM_CONDITIONAL([USE_OSSFUZZERS], [test "x$enable_ossfuzzers" = "xyes"]) + +AC_SUBST([LIB_FUZZING_ENGINE]) +AM_CONDITIONAL([USE_OSSFUZZ_FLAG], [test "x$LIB_FUZZING_ENGINE" = "x-fsanitize=fuzzer"]) +AM_CONDITIONAL([USE_OSSFUZZ_STATIC], [test -f "$LIB_FUZZING_ENGINE"]) + +dnl ==================================================================================== +dnl Check types and their sizes. + +AC_CHECK_SIZEOF([wchar_t], [4]) +AC_CHECK_SIZEOF([short], [2]) +AC_CHECK_SIZEOF([int], [4]) +AC_CHECK_SIZEOF([long], [4]) +AC_CHECK_SIZEOF([float], [4]) +AC_CHECK_SIZEOF([double], [4]) +AC_CHECK_SIZEOF([void*], [8]) +AC_CHECK_SIZEOF([size_t], [4]) +AC_CHECK_SIZEOF([int64_t], [8]) +AC_CHECK_SIZEOF([long long], [8]) + +dnl Check for common 64 bit file offset types. +AC_CHECK_SIZEOF([off_t], [1]) + +AS_IF([test "x$enable_largefile:$ac_cv_sizeof_off_t" = "xno:8"], [ + AC_MSG_ERROR(["Error : Cannot disable large file support because sizeof (off_t) == 8."]) + ]) + +AS_CASE([$host_os], + [mingw32*], [ + AC_DEFINE([__USE_MINGW_ANSI_STDIO], [1], [Set to 1 to use C99 printf/snprintf in MinGW.]) + ], + + [ + AS_IF([test "x$ac_cv_sizeof_off_t" = "x8"], [ + dnl If sizeof (off_t) is 8, no further checking is needed. + ], [ + dnl Save the old sizeof (off_t) value and then unset it to see if it + dnl changes when Large File Support is enabled. + pre_largefile_sizeof_off_t=$ac_cv_sizeof_off_t + unset ac_cv_sizeof_off_t + + AC_SYS_LARGEFILE + AS_IF([test "x$ac_cv_sys_largefile_CFLAGS" = "xno"], [ + ac_cv_sys_largefile_CFLAGS="" + ]) + AS_IF([test "x$ac_cv_sys_largefile_LDFLAGS" = "xno"], [ + ac_cv_sys_largefile_LDFLAGS="" + ]) + AS_IF([test "x$ac_cv_sys_largefile_LIBS" = "xno"], [ + ac_cv_sys_largefile_LIBS="" + ]) + + AC_CHECK_SIZEOF(off_t,1) + ]) + ]) + +AC_TYPE_SSIZE_T + +dnl ==================================================================================== +dnl Determine endian-ness of host processor. + +AC_C_BIGENDIAN([ + dnl big-endian + ac_cv_c_big_endian=1 + ac_cv_c_little_endian=0 + ], [ + dnl little-endian + ac_cv_c_big_endian=0 + ac_cv_c_little_endian=1 + ]) + +AC_DEFINE_UNQUOTED([CPU_IS_BIG_ENDIAN], [${ac_cv_c_big_endian}], [Host processor is big endian.]) +AC_DEFINE_UNQUOTED([CPU_IS_LITTLE_ENDIAN], [${ac_cv_c_little_endian}], [Host processor is little endian.]) + +dnl ==================================================================================== +dnl Check for functions. + +AC_CHECK_FUNCS([malloc calloc realloc free]) +AC_CHECK_FUNCS([open read write lseek lseek64]) +AC_CHECK_FUNCS([fstat fstat64 ftruncate fsync]) +AC_CHECK_FUNCS([snprintf vsnprintf]) +AC_CHECK_FUNCS([gmtime gmtime_r localtime localtime_r gettimeofday]) +AC_CHECK_FUNCS([mmap getpagesize]) +AC_CHECK_FUNCS([setlocale]) +AC_CHECK_FUNCS([pipe waitpid]) + +AC_SEARCH_LIBS([floor], [m], [], [ + AC_MSG_ERROR([unable to find the floor() function!]) + ]) +AC_CHECK_FUNCS([floor ceil fmod lrint lrintf]) + +dnl ==================================================================================== +dnl Check for requirements for building plugins for other languages/enviroments. + +dnl Octave maths environment http://www.octave.org/ +AS_IF([test "x$cross_compiling" = "xno"], [ + AS_IF([test "x$enable_octave" = "xno"], [ + AM_CONDITIONAL(BUILD_OCTAVE_MOD, false) + ], [ + AC_OCTAVE_BUILD + ]) + ], [ + AM_CONDITIONAL(BUILD_OCTAVE_MOD, false) + ]) + +dnl ==================================================================================== +dnl Check for Ogg, Vorbis and FLAC. + +HAVE_EXTERNAL_XIPH_LIBS=0 +EXTERNAL_XIPH_CFLAGS="" +EXTERNAL_XIPH_LIBS="" +EXTERNAL_XIPH_REQUIRE="" + +dnl Check for pkg-config outside the if statement. +PKG_PROG_PKG_CONFIG +AX_REQUIRE_DEFINED([PKG_INSTALLDIR]) +PKG_INSTALLDIR + +AS_IF([test -n "$PKG_CONFIG"], [ + AS_IF([test "x$enable_external_libs" = "xno"], [ + AC_MSG_WARN([[*** External libs (FLAC, Ogg, Vorbis) disabled. ***]]) + ], [ + PKG_CHECK_MOD_VERSION(FLAC, flac >= 1.3.1, ac_cv_flac=yes, ac_cv_flac=no) + + dnl Make sure the FLAC_CFLAGS value is sane. + FLAC_CFLAGS=`echo $FLAC_CFLAGS | $SED "s|include/FLAC|include|"` + + PKG_CHECK_MOD_VERSION(OGG, ogg >= 1.3.0, ac_cv_ogg=yes, ac_cv_ogg=no) + + AS_IF([test "x$enable_experimental" = "xyes"], [ + PKG_CHECK_MOD_VERSION(SPEEX, speex >= 1.2, ac_cv_speex=yes, ac_cv_speex=no) + ], [ + SPEEX_CFLAGS="" + SPEEX_LIBS="" + ]) + + dnl Vorbis versions earlier than 1.2.3 have bugs that cause the libsndfile + dnl test suite to fail on MIPS, PowerPC and others. + dnl See: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=549899 + PKG_CHECK_MOD_VERSION(VORBIS, vorbis >= 1.2.3, ac_cv_vorbis=yes, ac_cv_vorbis=no) + PKG_CHECK_MOD_VERSION(VORBISENC, vorbisenc >= 1.2.3, ac_cv_vorbisenc=yes, ac_cv_vorbisenc=no) + + PKG_CHECK_MOD_VERSION(OPUS, opus >= 1.1, ac_cv_opus=yes, ac_cv_opus=no) + enable_external_libs=yes + ]) + + AS_IF([test "x$ac_cv_flac$ac_cv_ogg$ac_cv_vorbis$ac_cv_vorbisenc$ac_cv_opus" = "xyesyesyesyesyes"], [ + HAVE_EXTERNAL_XIPH_LIBS=1 + enable_external_libs=yes + + EXTERNAL_XIPH_CFLAGS="$FLAC_CFLAGS $VORBIS_CFLAGS $VORBISENC_CFLAGS $SPEEX_CFLAGS $OPUS_CFLAGS $OGG_CFLAGS " + EXTERNAL_XIPH_LIBS="$FLAC_LIBS $VORBIS_LIBS $VORBISENC_LIBS $SPEEX_LIBS $OPUS_LIBS $OGG_LIBS " + EXTERNAL_XIPH_REQUIRE="flac ogg vorbis vorbisenc opus" + + if test x$ac_cv_speex = "xyes" ; then + EXTERNAL_XIPH_REQUIRE="$EXTERNAL_XIPH_REQUIRE speex" + fi + ], [ + AS_ECHO([""]) + AC_MSG_WARN([[*** One or more of the external libraries (ie libflac, libogg,]]) + AC_MSG_WARN([[*** libvorbis and libopus) is either missing (possibly only the development]]) + AC_MSG_WARN([[*** headers) or is of an unsupported version.]]) + AC_MSG_WARN([[***]]) + AC_MSG_WARN([[*** Unfortunately, for ease of maintenance, the external libs]]) + AC_MSG_WARN([[*** are an all or nothing affair.]]) + AS_ECHO([""]) + enable_external_libs=no + ]) + ]) + +AC_DEFINE_UNQUOTED([HAVE_EXTERNAL_XIPH_LIBS], [$HAVE_EXTERNAL_XIPH_LIBS], [Will be set to 1 if flac, ogg, vorbis, and opus are available.]) + +dnl ==================================================================================== +dnl Check for MPEG libraris liblame + +ac_cv_lame="no" +ac_cv_mpg123="no" +HAVE_MPEG=0 +EXTERNAL_MPEG_REQUIRE="" +EXTERNAL_MPEG_LIBS="" + +AS_IF([test -n "$PKG_CONFIG"], [ + AS_IF([test "x$enable_mpeg" = "xno"], [ + AC_MSG_WARN([[*** MPEG (Lame/MPG123) disabled. ***]]) + ], [ + AC_CHECK_HEADER(lame/lame.h, + lame_header_found="yes", + lame_header_found="no") + AC_SEARCH_LIBS(lame_set_VBR_q, [lame mp3lame], [lame_lib_found="yes"], [lame_lib_found="no"]) + AS_IF([test "x$lame_lib_found$lame_header_found" = "xyesyes"], [ + ac_cv_lame="yes" + ], [ + AC_MSG_WARN([["MPEG support selected but external Lame library cannot be found.]]) + ]) + + PKG_CHECK_MOD_VERSION([MPG123], [libmpg123 >= 1.25.10], [ + ac_cv_mpg123="yes" + ], [ + AC_MSG_WARN([["MPEG support selected but external MPG123 library cannot be found.]]) + ]) + + AS_IF([test "x$ac_cv_lame$ac_cv_mpg123" = "xyesyes"], [ + enable_mpeg="yes" + HAVE_MPEG=1 + EXTERNAL_MPEG_REQUIRE="libmpg123" + EXTERNAL_MPEG_LIBS="-lmp3lame" + MPEG_CFLAGS="$MPG123_CFLAGS" + MPEG_LIBS="$MPG123_LIBS" + ], [ + enable_mpeg="no" + AS_ECHO([""]) + AC_MSG_WARN([[*** MPEG support disabled.]]) + AS_ECHO([""]) + ]) + ]) + ]) + +AC_DEFINE_UNQUOTED([HAVE_MPEG], [$HAVE_MPEG], [Will be set to 1 if lame, mpg123 mpeg support is available.]) + +dnl ==================================================================================== +dnl Check for libsqlite3 (only used in regtest). + +ac_cv_sqlite3=0 +AS_IF([test "x$enable_sqlite" != "xno"], [ + PKG_CHECK_MOD_VERSION([SQLITE3], [sqlite3 >= 3.2], [ac_cv_sqlite3=1], [ac_cv_sqlite3=0]) + ]) + +AC_DEFINE_UNQUOTED([HAVE_SQLITE3], [${ac_cv_sqlite3}], [Set to 1 if you have libsqlite3.]) +AM_CONDITIONAL([HAVE_SQLITE3], [test "x$ac_cv_sqlite3" = "x1"]) + +dnl ==================================================================================== +dnl Determine if the processor can do clipping on float to int conversions. + +AS_IF([test "x$enable_cpu_clip" != "xno"], [ + MN_C_CLIP_MODE + ], [ + AS_ECHO(["checking processor clipping capabilities... disabled"]) + ac_cv_c_clip_positive=0 + ac_cv_c_clip_negative=0 + ]) + +AC_DEFINE_UNQUOTED([CPU_CLIPS_POSITIVE], [${ac_cv_c_clip_positive}], + [Host processor clips on positive float to int conversion.]) +AC_DEFINE_UNQUOTED([CPU_CLIPS_NEGATIVE], [${ac_cv_c_clip_negative}], + [Host processor clips on negative float to int conversion.]) + +dnl ==================================================================================== +dnl Host OS specific stuff. + +OS_SPECIFIC_CFLAGS="" +OS_SPECIFIC_LINKS="" +os_is_win32=0 +os_is_openbsd=0 +use_windows_api=0 +AS_CASE([$host_os], + [darwin* | rhapsody*], [ + AS_IF([test "x$HAVE_XCODE_SELECT" = "xyes"], [ + developer_path=`xcode-select --print-path` + ], [ + developer_path="/Developer" + ]) + OS_SPECIFIC_LINKS="-framework CoreAudio -framework AudioToolbox -framework CoreFoundation"], + [mingw*], [ + os_is_win32=1 + use_windows_api=1 + OS_SPECIFIC_LINKS="-lwinmm"], + [openbsd*], [ + os_is_openbsd=1 + ]) + +AC_DEFINE_UNQUOTED([OS_IS_WIN32], [${os_is_win32}], [Set to 1 if compiling for Win32]) +AC_DEFINE_UNQUOTED([OS_IS_OPENBSD], [${os_is_openbsd}], [Set to 1 if compiling for OpenBSD]) +AC_DEFINE_UNQUOTED([USE_WINDOWS_API], [${use_windows_api}], [Set to 1 to use the native windows API]) +AM_CONDITIONAL(USE_WIN_VERSION_FILE, test ${use_windows_api} -eq 1) + +dnl ==================================================================================== +dnl Check for ALSA. + +AS_IF([test "x$enable_alsa" != "xno"], [ + PKG_CHECK_MODULES([ALSA], [alsa], [ + dnl actually test whether ALSA really works, in + dnl order to dodge wrong cross-compilation pickups + save_CFLAGS="${CFLAGS}" + save_LIBS="${LIBS}" + CFLAGS="${CFLAGS} ${ALSA_CFLAGS}" + LIBS="${LIBS} ${ALSA_LIBS}" + AC_CHECK_HEADERS([alsa/asoundlib.h]) + AS_IF([test "x$ac_cv_header_alsa_asoundlib_h" = "xyes"], [ + dnl ALSA definitely works + AC_DEFINE([HAVE_ALSA], [1], [Set to 1 if you have alsa]) + alsa_works="yes" + ], [ + dnl picked up wrong ALSA + alsa_works="no" + + dnl reset flags + ALSA_CFLAGS="" + ALSA_LIBS="" + ]) + CFLAGS="${save_CFLAGS}" + LIBS="${save_LIBS}" + ], [ + dnl could not find ALSA + alsa_works="no" + ]) + + AS_IF([test "x$alsa_works" = "xno"], [ + AS_IF([test "x$enable_alsa" = "xyes"], [ + dnl explicitly passed --enable-alsa, hence error out loud and clearly + AC_MSG_ERROR([You explicitly requested alsa support, but alsa could not be found!]) + ], [ + dnl did not explicitly pass --enable-alsa, relying on default automagic on + enable_alsa="no (auto)" + ]) + ]) + ]) + +dnl ==================================================================================== +dnl Check for OpenBSD's sndio. + +SNDIO_LIBS="" +HAVE_SNDIO_H=0 +AS_CASE([$host_os], + [openbsd*], [ + AC_CHECK_HEADERS(sndio.h) + AS_IF([test "x$ac_cv_header_sndio_h" = "xyes"], [ + SNDIO_LIBS="-lsndio" + HAVE_SNDIO_H=1 + ]) + ]) + +AC_DEFINE_UNQUOTED([HAVE_SNDIO_H], [${HAVE_SNDIO_H}], [Set to 1 if is available.]) + +dnl ==================================================================================== +dnl Test for sanity when cross-compiling. + +AS_IF([test "x$ac_cv_sizeof_short" != "x2"], [ + AC_MSG_WARN([[******************************************************************]]) + AC_MSG_WARN([[*** sizeof (short) != 2. ]]) + AC_MSG_WARN([[******************************************************************]]) + ]) + +AS_IF([test "x$ac_cv_sizeof_int" != "x4"], [ + AC_MSG_WARN([[******************************************************************]]) + AC_MSG_WARN([[*** sizeof (int) != 4 ]]) + AC_MSG_WARN([[******************************************************************]]) + ]) + +AS_IF([test "x$ac_cv_sizeof_float" != "x4"], [ + AC_MSG_WARN([[******************************************************************]]) + AC_MSG_WARN([[*** sizeof (float) != 4. ]]) + AC_MSG_WARN([[******************************************************************]]) + ]) + +AS_IF([test "x$ac_cv_sizeof_double" != "x8"], [ + AC_MSG_WARN([[******************************************************************]]) + AC_MSG_WARN([[*** sizeof (double) != 8. ]]) + AC_MSG_WARN([[******************************************************************]]) + ]) + +AS_IF([test "x$ac_cv_prog_HAVE_AUTOGEN" = "xno"], [ + AC_MSG_WARN([[Touching files in directory tests/.]]) + touch tests/*.c tests/*.h + ]) + +dnl ==================================================================================== +dnl Settings for the HTML documentation. + +AS_IF([test "x$enable_bow_docs" = "xyes"], [ + HTML_BGCOLOUR="white" + HTML_FGCOLOUR="black" + ], [ + HTML_BGCOLOUR="black" + HTML_FGCOLOUR="white" + ]) + +dnl ==================================================================================== +dnl Now use the information from the checking stage. + +win32_target_dll=0 +COMPILER_IS_GCC=0 + +AS_IF([test "x$enable_flags_setting" = "xyes"], [ + AX_APPEND_COMPILE_FLAGS([-O2 -pipe], [CFLAGS]) + + AC_LANG_PUSH([C++]) + AX_APPEND_COMPILE_FLAGS([-O2 -pipe], [CXXFLAGS]) + AC_LANG_POP([C++]) + + AS_CASE([${host_os}], + [darwin*], [ + ldflags_test="-Wl,-dead_strip_dylibs"], + [linux*], [ + ldflags_test="-Wl,-O1 -Wl,--as-needed -Wl,--no-undefined -Wl,--gc-sections"] + ) + AX_APPEND_LINK_FLAGS([${ldflags_test}], [LDFLAGS]) + ]) + +AS_IF([test "x$enable_werror" = "xyes"], [ + AX_APPEND_COMPILE_FLAGS([-Werror], [CFLAGS]) + + AC_LANG_PUSH([C++]) + AX_APPEND_COMPILE_FLAGS([-Werror], [CXXFLAGS]) + AC_LANG_POP([C++]) + ]) + +common_flags="-Wall -Wextra -Wpointer-arith -Wcast-align -Wcast-qual -Wshadow -Wwrite-strings -Wundef -Wuninitialized -Winit-self" +common_cflags="${common_flags}" +dnl Clang doesn't know about -Wno-format-truncation +dnl and would spew tons of warnings otherwise. +AS_IF([test "x$ax_cv_c_compiler_vendor" = "xgnu"], [ + common_cflags+=" -Wno-format-truncation" + ]) +common_cxxflags="${common_flags}" +AS_IF([test "x$ax_cv_cxx_compiler_vendor" = "xgnu"], [ + common_cxxflags+=" -Wno-format-truncation" + ]) + +AX_APPEND_COMPILE_FLAGS([${common_cflags} -Wvla -Wbad-function-cast -Wnested-externs -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Waggregate-return], [CFLAGS]) + +AC_LANG_PUSH([C++]) +AX_APPEND_COMPILE_FLAGS([${common_cxxflags} -Wctor-dtor-privacy -Wnon-virtual-dtor -Woverloaded-virtual -Wreorder -Wsign-promo], [CXXFLAGS]) +AC_LANG_POP([C++]) + +AS_IF([test "x$enable_test_coverage" = "xyes"], [ + AX_APPEND_COMPILE_FLAGS([-coverage], [CFLAGS]) + ]) + +dnl some distributions (such as Gentoo) have _FORTIFY_SOURCE always +dnl enabled. We test for this situation in order to prevent polluting +dnl the console with messages of macro redefinitions. +AX_ADD_FORTIFY_SOURCE + +AS_IF([test "x$ax_cv_c_compiler_vendor" = "xgnu"], [ + dnl OS specific tweaks. + AS_CASE([$host_os], + [darwin* | rhapsody*], [ + dnl Disable -Wall, -pedantic and -Wshadow for Apple Darwin/Rhapsody. + dnl System headers on these systems are broken. + temp_CFLAGS=`echo $CFLAGS | $SED "s/-Wall -pedantic//" | $SED "s/-Wshadow//" | $SED "s/-Waggregate-return//"` + CFLAGS=$temp_CFLAGS + SHLIB_VERSION_ARG="-Wl,-exported_symbols_list -Wl,\$(top_srcdir)/src/Symbols.darwin"], + [mingw*], [ + SHLIB_VERSION_ARG="-Wc,-static-libgcc -Wl,\$(top_srcdir)/src/libsndfile-1.def" + win32_target_dll=1 + AS_IF([test "x$enable_shared" = "xno"], [ + win32_target_dll=0 + ]) + AX_APPEND_COMPILE_FLAGS([-mstackrealign], [CFLAGS]) + ], + [os2*], [ + SHLIB_VERSION_ARG="-Wl,-export-symbols \$(top_srcdir)/src/Symbols.os2" + ]) + + COMPILER_IS_GCC=1 + ]) + +AS_CASE([$host_os], [linux*|kfreebsd*-gnu*|gnu*], [SHLIB_VERSION_ARG="-Wl,--version-script=\$(top_srcdir)/src/Symbols.gnu-binutils"]) + +AC_DEFINE_UNQUOTED([WIN32_TARGET_DLL], [${win32_target_dll}], [Set to 1 if windows DLL is being built.]) +AC_DEFINE_UNQUOTED([COMPILER_IS_GCC], [${COMPILER_IS_GCC}], [Set to 1 if the compile is GNU GCC.]) + +CFLAGS="$CFLAGS $OS_SPECIFIC_CFLAGS" + +AS_IF([test "x$CFLAGS" = "x"], [ + AC_MSG_ERROR(["Error in configure script. CFLAGS has been screwed up."]) + ]) + +HOST_TRIPLET="${host_cpu}-${host_vendor}-${host_os}" + +AC_DEFINE_UNQUOTED([HOST_TRIPLET], [${HOST_TRIPLET}], [The host triplet of the compiled binary.]) + +AS_IF([test "$HOST_TRIPLET" = "x86_64-w64-mingw32"], [ + OS_SPECIFIC_LINKS=" -static-libgcc $OS_SPECIFIC_LINKS" + ]) + +WIN_RC_VERSION=`echo $PACKAGE_VERSION | $SED -e "s/pre.*//" -e "s/beta.*//" -e "s/\./,/g"` + + +AS_IF([test "x$enable_static" = "xno"], [ + SRC_BINDIR=src/.libs/ + TEST_BINDIR=tests/.libs/ + ], [ + SRC_BINDIR=src/ + TEST_BINDIR=tests/ + ]) + +dnl ------------------------------------------------------------------------------- + +AC_SUBST(HOST_TRIPLET) + +AC_SUBST(HTML_BGCOLOUR) +AC_SUBST(HTML_FGCOLOUR) + +AC_SUBST(SHLIB_VERSION_ARG) +AC_SUBST([SHARED_VERSION_INFO], [lt_current:lt_revision:lt_age]) +AC_SUBST([ABI_VERSION], [abi_version_major.abi_version_minor.abi_version_patch]) +AC_SUBST(CLEAN_VERSION) +AC_SUBST(VERSION_MAJOR) +AC_SUBST(GEN_TOOL) + +AC_SUBST(WIN_RC_VERSION) + +AC_SUBST(HAVE_EXTERNAL_XIPH_LIBS) +AC_SUBST(HAVE_MPEG) +AC_SUBST(OS_SPECIFIC_CFLAGS) +AC_SUBST(OS_SPECIFIC_LINKS) +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) +AC_SUBST(MPEG_CFLAGS) +AC_SUBST(MPEG_LIBS) +AC_SUBST(SRC_BINDIR) +AC_SUBST(TEST_BINDIR) + +AC_CONFIG_FILES([ + Makefile Octave/Makefile + src/version-metadata.rc + tests/test_wrapper.sh tests/pedantic-header-test.sh + sndfile.pc + Scripts/build-test-tarball.mk + ]) +AC_OUTPUT + +dnl ==================================================================================== + +AS_IF([test -z "$PKG_CONFIG"], [ + AS_ECHO([" *****************************************************************"]) + AS_ECHO([" *** The pkg-config program is missing. ***"]) + AS_ECHO([" *** External FLAC/Ogg/Vorbis libs cannot be found without it. ***"]) + AS_ECHO([" *** http://pkg-config.freedesktop.org/wiki/ ***"]) + AS_ECHO([" *****************************************************************"]) + ]) + +AX_RECURSIVE_EVAL([$libdir], [full_absolute_libdir]) +AX_RECURSIVE_EVAL([$bindir], [full_absolute_bindir]) +AX_RECURSIVE_EVAL([$pkgconfigdir], [full_absolute_pkgconfigdir]) +AX_RECURSIVE_EVAL([$htmldir], [full_absolute_htmldir]) +AC_MSG_RESULT([ +-=-=-=-=-=-=-=-=-=-= Configuration Complete =-=-=-=-=-=-=-=-=-=-=- + + Configuration summary : + + libsndfile version : .................. ${VERSION} + + Host CPU : ............................ ${host_cpu} + Host Vendor : ......................... ${host_vendor} + Host OS : ............................. ${host_os} + + CFLAGS : .............................. ${CFLAGS} + CXXFLAGS : ............................ ${CXXFLAGS} + CPPFLAGS : ............................ ${CPPFLAGS} + LDFLAGS : ............................. ${LDFLAGS} + + Experimental code : ................... ${enable_experimental:-no} + Using ALSA in example programs : ...... ${enable_alsa:-no} + External FLAC/Ogg/Vorbis/Opus : ....... ${enable_external_libs:-no} + External MPEG Lame/MPG123 : ........... ${enable_mpeg:-no} + Building Octave interface : ........... ${OCTAVE_BUILD} + + Tools : + + C Compiler Vendor is : ................ ${ax_cv_c_compiler_vendor} (${ax_cv_c_compiler_version}) + CXX Compiler Vendor is : .............. ${ax_cv_cxx_compiler_vendor} (${ax_cv_cxx_compiler_version}) + + Sanitizer enabled : ................... ${enable_sanitizer:-no} + + Installation directories : + + Library directory : ................... ${full_absolute_libdir} + Program directory : ................... ${full_absolute_bindir} + Pkgconfig directory : ................. ${full_absolute_pkgconfigdir} + HTML docs directory : ................. ${full_absolute_htmldir} + +Compiling some other packages against libsndfile may require +the addition of '$full_absolute_pkgconfigdir' to the +PKG_CONFIG_PATH environment variable. +]) + +dnl Remove symlink created by Scripts/android-configure.sh. +rm -f gdbclient diff --git a/extern/libsndfile-modified/docs/FAQ.md b/extern/libsndfile-modified/docs/FAQ.md new file mode 100644 index 000000000..e7c98e255 --- /dev/null +++ b/extern/libsndfile-modified/docs/FAQ.md @@ -0,0 +1,482 @@ +--- +layout: default +title: libsndfile : Frequently Asked Questions. +--- + +# libsndfile : Frequently Asked Questions + +1. [Do you plan to support XYZ codec in libsndfile?](#Q001) +2. [In version 0 the SF\_INFO struct had a pcmbitwidth field but version 1 does not. Why?](#Q002) +3. [Compiling is really slow on MacOS X. Why?](#Q003) +4. [When trying to compile libsndfile on Solaris I get a "bad substitution" error during linking. What can I do to fix this?](#Q004) +5. [Why doesn't libsndfile do interleaving/de-interleaving?](#Q005) +6. [What's the best format for storing temporary files?](#Q006) +7. [On Linux/Unix/MacOS X, what's the best way of detecting the presence of libsndfile?](#Q007) +8. [I have libsndfile installed and now I want to use it. I just want a simple Makefile\! What do I do?](#Q008) +9. [How about adding the ability to write/read sound files to/from memory buffers?](#Q009) +10. [Reading a 16 bit PCM file as normalised floats and then writing them back changes some sample values. Why?](#Q010) +11. [I'm having problems with u-law encoded WAV files generated by libsndfile in Winamp. Why?](#Q011) +12. [I'm looking at sf\_read\*. What are items? What are frames?](#Q012) +13. [Why can't libsndfile open this Sound Designer II (SD2) file?](#Q013) +14. [I'd like to statically link libsndfile to my closed source application. Can I buy a license so that this is possible?](#Q014) +15. [My program is crashing during a call to a function in libsndfile. Is this a bug in libsndfile?](#Q015) +16. [Will you accept a fix for compiling libsndfile with compiler X?](#Q016) +17. [Can libsndfile read/write files from/to UNIX pipes?](#Q017) +18. [Is it possible to build a Universal Binary on Mac OS X?](#Q018) +19. [I have project files for Visual Studio / XCode / Whatever. Why don't you distribute them with libsndfile?](#Q019) +20. [Why doesn't libsndfile support MP3?](#Q020) +21. [How do I use libsndfile in a closed source or commercial program and comply with the license?](#Q021) +22. [What versions of windows does libsndfile work on?](#Q022) +23. [I'm cross compiling libsndfile for another platform. How can I run the test suite?](#Q023) + +----- + +## Q1 : Do you plan to support XYZ codec in libsndfile? {#Q001} + +If source code for XYZ codec is available under a suitable license (LGPL, BSD, +MIT etc) then yes, I'd like to add it. + +If suitable documentation is available on how to decode and encode the format +then maybe, depending on how much work is involved. + +If XYZ is some proprietary codec where no source code or documentation is +available then no. + +So if you want support for XYZ codec, first find existing source code or +documentation. If you can't find either then the answer is no. + +## Q2 : In version 0 the SF\_INFO struct had a pcmbitwidth field but version 1 does not. Why? {#Q002} + +This was dropped for a number of reasons: + +- pcmbitwidth makes little sense on compressed or floating point formats +- with the new API you really don't need to know it + +As documented [here](api.md#note-1) there is now a well defined behaviour which +ensures that no matter what the bit width of the source file, the scaling always +does something sensible. This makes it safe to read 8, 16, 24 and 32 bit PCM +files using `sf_read_short()` and always have the optimal behaviour. + +## Q3 : Compiling is really slow on MacOS X. Why? {#Q003} + +When you configure and compile libsndfile, it uses the /bin/sh shell for a +number of tasks (ie configure script and libtool). Older versions of OS X +(10.2?) shipped a really crappy Bourne shell as /bin/sh which resulted in +**really** slow compiles. Newer version of OS X ship GNU Bash as /bin/sh and +this answer doesn't apply in that case. + +To fix this I suggest that you install the GNU Bash shell, rename /bin/sh to +/bin/sh.old and make a symlink from /bin/sh to the bash shell. Bash is designed +to behave as a Bourne shell when it is called as /bin/sh. + +When I did this on my iBook running MacOS X, compile times dropped from 13 +minutes to 3 minutes. + +## Q4 : When trying to compile libsndfile on Solaris I get a "bad substitution" error on linking. Why? {#Q004} + +It seems that the Solaris Bourne shell disagrees with GNU libtool. + +To fix this I suggest that you install the GNU Bash shell, rename /bin/sh to +/bin/sh.old and make a symlink from /bin/sh to the bash shell. Bash is designed +to behave as a Bourne shell when it is called as /bin/sh. + +## Q5 : Why doesn't libsndfile do interleaving/de-interleaving? {#Q005} + +This problem is bigger than it may seem at first. + +For a stereo file, it is a pretty safe bet that a simple interleaving/ +de-interleaving could satisfy most users. However, for files with more than 2 +channels this is unlikely to be the case. If the user has a 4 channel file and +want to play that file on a stereo output sound card they either want the first +2 channels or they want some mixed combination of the 4 channels. + +When you add more channels, the combinations grow exponentially and it becomes +increasingly difficult to cover even a sensible subset of the possible +combinations. On top of that, coding any one style of interleaver/de-interleaver +is trivial, while coding one that can cover all combinations is far from +trivial. This means that this feature will not be added any time soon. + +## Q6 : What's the best format for storing temporary files? {#Q006} + +When you want to store temporary data there are a number of requirements: + +- A simple, easy to parse header. +- The format must provide the fastest possible read and write rates (ie avoid + conversions and encoding/decoding). +- The file format must be reasonably common and playable by most players. +- Able to store data in either endian-ness. + +The format which best meets these requirements is AU, which allows data to be +stored in any one of short, int, float and double (among others) formats. + +For instance, if an application uses float data internally, its temporary files +should use a format of (SF_ENDIAN_CPU | SF_FORMAT_AU | SF_FORMAT_FLOAT) which +will store big endian float data in big endian CPUs and little endian float data +on little endian CPUs. Reading and writing this format will not require any +conversions or byte swapping regardless of the host CPU. + +## Q7 : On Linux/Unix/MaxOS X, what's the best way of detecting the presence of libsndfile using autoconf? {#Q007} + +libsndfile uses the pkg-config (man pkg-config) method of registering itself +with the host system. The best way of detecting its presence is using something +like this in configure.ac (or configure.in): + + PKG_CHECK_MODULES(SNDFILE, sndfile >= 1.0.2, ac_cv_sndfile=1, ac_cv_sndfile=0) + + AC_DEFINE_UNQUOTED([HAVE_SNDFILE],${ac_cv_sndfile}, + [Set to 1 if you have libsndfile.]) + + AC_SUBST(SNDFILE_CFLAGS) + AC_SUBST(SNDFILE_LIBS) + +This will automatically set the **SNDFILE_CFLAGS** and **SNDFILE_LIBS** +variables which can be used in Makefile.am like this: + + SNDFILE_CFLAGS = @SNDFILE_CFLAGS@ + SNDFILE_LIBS = @SNDFILE_LIBS@ + +If you install libsndfile from source, you will probably need to set the +**PKG_CONFIG_PATH** environment variable as suggested at the end of the +libsndfile configure process. For instance on my system I get this: + + -=-=-=-=-=-=-=-=-=-= Configuration Complete =-=-=-=-=-=-=-=-=-=- + + Configuration summary : + + Version : ..................... 1.0.5 + Experimental code : ........... no + + Tools : + + Compiler is GCC : ............. yes + GCC major version : ........... 3 + + Installation directories : + + Library directory : ........... /usr/local/lib + Program directory : ........... /usr/local/bin + Pkgconfig directory : ......... /usr/local/lib/pkgconfig + + Compiling some other packages against libsndfile may require + the addition of "/usr/local/lib/pkgconfig" to the + PKG_CONFIG_PATH environment variable. + +## Q8 : I have libsndfile installed and now I want to use it. I just want a simple Makefile\! What do I do? {#Q008} + +The **pkg-config** program makes finding the correct compiler flag values and +library location far easier. During the installation of libsndfile, a file named +**sndfile.pc** is installed in the directory **${libdir}/pkgconfig** (ie if +libsndfile is installed in **/usr/local/lib**, **sndfile.pc** will be installed +in **/usr/local/lib/pkgconfig/**). + +In order for pkg-config to find sndfile.pc it may be necessary to point the +environment variable **PKG_CONFIG_PATH** in the right direction. + + export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig + +Then, to compile a C file into an object file, the command would be: + + gcc `pkg-config --cflags sndfile` -c somefile.c + +and to link a number of objects into an executable that links against +libsndfile, the command would be: + + gcc `pkg-config --libs sndfile` obj1.o obj2.o -o program + +## Q9 : How about adding the ability to write/read sound files to/from memory buffers? {#Q009} + +This has been [added](api.md#open_virtual) for version 1.0.12. + +## Q10 : Reading a 16 bit PCM file as normalised floats and then writing them back changes some sample values. Why? {#Q010} + +This is caused by the fact that the conversion from 16 bit short to float is +done by dividing by 32768 (0x8000 in hexadecimal) while the conversion from +float to 16 bit short is done by multiplying by 32767 (0x7FFF in hex). So for +instance, a value in a 16 bit PCM file of 20000 gets read as a floating point +number of 0.6103515625 (20000.0 / 0x8000). Converting that back to a 16 bit +short results in a value of 19999.3896484375 (0.6103515625 \* 0x7FFF) which then +gets rounded down to 19999. + +You will notice that for this particular case, the error is 1 in 20000 or +0.005%. Interestingly, for values of less than 16369, dividing by 0x8000 +followed by multiplying by 0x7FFF and then rounding the result, gives back the +original value. It turns out that as long as the host operating system supplies +the 1999 ISO C Standard functions **lrintf** and **lrint** (or a replacement has +been supplied) then the maximum possible error is 1 in 16369 or about 0.006%. + +Regardless of the size of the error, the reason why this is done is rather +subtle. + +In a file containing 16 bit PCM samples, the values are restricted to the range +[-32768, 32767] while we want floating point values in the range [-1.0, 1.0]. +The only way to do this conversion is to do a floating point division by a value +of 0x8000. Converting the other way, the only way to ensure that floating point +values in the range [-1.0, 1.0] are within the valid range allowed by a 16 bit +short is to multiply by 0x7FFF. + +Some people would say that this is a severe short-coming of libsndfile. I would +counter that anybody who is constantly converting back and forth between 16 bit +shorts and normalised floats is going to suffer other losses in audio quality +that they should also be concerned about. + +Since this problem only occurs when converting between integer data on disk and +normalized floats in the application, it can be avoided by using something other +than normalized floats in the application. Alternatives to normalized floats are +the **short** and **int** data types (ie using sf_read_short or sf_read_int) or +using un-normalized floats (see +[SFC_SET_NORM_FLOAT](command.html#sfc_set_norm_float)). + +Another way to deal with this problem is to consider 16 bit short data as a +final destination format only, not as an intermediate storage format. All +intermediate data (ie which is going to be processed further) should be stored +in floating point format which is supported by all of the most common file +formats. If floating point files are considered too large (2 times the size of a +16 bit PCM file), it would also be possible to use 24 bit PCM as an intermediate +storage format (and which is also supported by most common file types). + +## Q11 : I'm having problems with u-law encoded WAV files generated by libsndfile in Winamp. Why? {#Q011} + +This is actually a Winamp problem. The official Microsoft spec suggests that the +'fmt ' chunk should be 18 bytes. Unfortunately at least one of Microsoft's own +applications (Sound Recorder on Win98 I believe) did not accept 18 bytes 'fmt ' +chunks. + +Michael Lee did some experimenting and found that: + +> I have checked that Windows Media Player 9, QuickTime Player 6.4, RealOne +> Player 2.0 and GoldWave 5.06 can all play u-law files with 16-byte or 18-byte +> 'fmt ' chunk. Only Winamp (2.91) and foobar2000 are unable to play u-law files +> with 16-byte 'fmt ' chunk. + +Even this is a very small sampling of all the players out there. For that reason +it is probably not a good idea to change this now because there is the risk of +breaking something that currently works. + +## Q12 : I'm looking at sf_read*. What are items? What are frames? {#Q012} + +An `item` is a single sample of the data type you are reading; ie a single +`short` value for `sf_read_short` or a single `float` for `sf_read_float`. + +For a sound file with only one channel, a frame is the same as a item (ie a +single sample) while for multi channel sound files, a single frame contains a +single item for each channel. + +Here are two simple, correct examples, both of which are assumed to be working +on a stereo file, first using items: + +```c +#define CHANNELS 2 +short data [CHANNELS * 100] ; +sf_count items_read = sf_read_short (file, data, 200) ; +assert (items_read == 200) ; +``` + +and now reading the exact same amount of data using frames: + +```c +#define CHANNELS 2 +short data [CHANNELS * 100] ; +sf_count frames_read = sf_readf_short (file, data, 100) ; +assert (frames_read == 100) ; +``` + +## Q13 : Why can't libsndfile open this Sound Designer II (SD2) file? {#Q013} + +This is somewhat complicated. First some background. + +SD2 files are native to the Apple Macintosh platform and use features of the Mac +filesystem (file resource forks) to store the file's sample rate, number of +channels, sample width and more. When you look at a file and its resource fork +on Mac OS X it looks like this: + + -rw-r--r-- 1 erikd erikd 46512 Oct 18 22:57 file.sd2 + -rw-r--r-- 1 erikd erikd 538 Oct 18 22:57 file.sd2/rsrc + +Notice how the file itself looks like a directory containing a single file named +**rsrc**. When libsndfile is compiled for MacOS X, it should open (for write and +read) SD2 file with resource forks like this without any problems. It will also +handle files with the resource fork in a separate file as described below. + +When SD2 files are moved to other platforms, the resource fork of the file can +sometimes be dropped altogether. All that remains is the raw audio data and no +information about the number of channels, sample rate or bit width which makes +it a little difficult for libsndfile to open the file. + +However, it is possible to safely move an SD2 file to a Linux or Windows +machine. For instance, when an SD2 file is copied from inside MacOS X to a +windows shared directory or a Samba share (ie Linux), MacOS X is clever enough +to store the resource fork of the file in a separate hidden file in the same +directory like this: + + -rw-r--r-- 1 erikd erikd 538 Oct 18 22:57 ._file.sd2 + -rw-r--r-- 1 erikd erikd 46512 Oct 18 22:57 file.sd2 + +Regardless of what platform it is running on, when libsndfile is asked to open a +file named **"foo"** and it can't recognize the file type from the data in the +file, it will attempt to open the resource fork and if that fails, it then tries +to open a file named **"._foo"** to see if the file has a valid resource fork. +This is the same regardless of whether the file is being opened for read or +write. + +In short, libsndfile should open SD2 files with a valid resource fork on all of +the platforms that libsndfile supports. If a file has lost its resource fork, +the only option is the open the file using the SF_FORMAT_RAW option and guessing +its sample rate, channel count and bit width. + +Occasionally, when SD2 files are moved to other systems, the file is +[BinHexed](http://www.macdisk.com/binhexen.php3) which wraps the resource fork +and the data fork together. For these files, it would be possible to write a +BinHex parser but there is not a lot to gain considering how rare these BinHexed +SD2 files are. + +## Q14 : I'd like to statically link libsndfile to my closed source application. Can I buy a license so that this is possible? {#Q014} + +Unfortunately no. libsndfile contains code written by other people who have +agreed that their code be used under the GNU LGPL but no more. Even if they were +to agree, there would be significant difficulties in dividing up the payments +fairly. + +The **only** way you can legally use libsndfile as a statically linked library +is if your application is released under the GNU GPL or LGPL. + +## Q15 : My program is crashing during a call to a function in libsndfile. Is this a bug in libsndfile? {#Q015} + +libsndfile is being used by large numbers of people all over the world without +any problems like this. That means that it is much more likely that your code +has a bug than libsndfile. However, it is still possible that there is a bug in +libsndfile. + +To figure out whether it is your code or libsndfile you should do the following: + +- Make sure you are compiling your code with warnings switched on and that you + fix as many warnings as possible. With the GNU compiler (gcc) I would + recommend at least **-W -Wall -Werror** which will force you to fix all + warnings before you can run the code. +- Try using a memory debugger. [Valgrind](http://valgrind.kde.org/) on x86 Linux + is excellent. [Purify](http://www.ibm.com/software/awdtools/purify/) also has + a good reputation. +- If the code is clean after the above two steps and you still get a crash in + libsndfile, then send me a small snippet of code (no more than 30-40 lines) + which includes the call to sf_open() and also shows how all variables passed + to/returned from sf_open() are defined. + +## Q16 : Will you accept a fix for compiling libsndfile with compiler X? {#Q016} + +If compiler X is a C++ compiler then no. C and C++ are different enough to make +writing code that compiles as valid C and valid C++ too difficult. I would +rather spend my time fixing bugs and adding features. + +If compiler X is a C compiler then I will do what I can as long as that does not +hamper the correctness, portability and maintainability of the existing code. It +should be noted however that libsndfile uses features specified by the 1999 ISO +C Standard. This can make compiling libsndfile with some older compilers +difficult. + +## Q17 : Can libsndfile read/write files from/to UNIX pipes? {#Q017} + +Yes, libsndfile can read files from pipes. Unfortunately, the write case is much +more complicated. + +File formats like AIFF and WAV have information at the start of the file (the +file header) which states the length of the file, the number of sample frames +etc. This information must be filled in correctly when the file header is +written, but this information is not reliably known until the file is closed. +This means that libsndfile cannot write AIFF, WAV and many other file types to a +pipe. + +However, there is at least one file format (AU) which is specifically designed +to be written to a pipe. Like AIFF and WAV, AU has a header with a sample frames +field, but it is specifically allowable to set that frames field to 0x7FFFFFFF +if the file length is not known when the header is written. The AU file format +can also hold data in many of the standard formats (ie SF_FORMAT_PCM_16, +SF_FORMAT_PCM_24, SF_FORMAT_FLOAT etc) as well as allowing data in both big and +little endian format. + +See also [FAQ Q6](#Q006). + +## Q18 : Is it possible to build a Universal Binary on Mac OS X? {#Q018} + +Yes, but you must do two separate configure/build/test runs; one on PowerPC and +one on Intel. It is then possible to merge the binaries into a single universal +binary using one of the programs in the Apple tool chain. + +It is **not** possible to build a working universal binary via a single +compile/build run on a single CPU. + +The problem is that the libsndfile build process detects features of the CPU its +being built for during the configure process and when building a universal +binary, configure is only run once and that data is then used for both CPUs. +That configure data will be wrong for one of those CPUs. You will still be able +to compile libsndfile, and the test suite will pass on the machine you compiled +it on. However, if you take the universal binary test suite programs compiled on +one CPU and run them on the other, the test suite will fail. + +Part of the problem is that the CPU endian-ness is detected at configure time. +Yes, I know the Apple compiler defines one of the macros \_\_LITTLE\_ENDIAN\_\_ +and \_\_BIG\_ENDIAN\_\_, but those macros are not part of the 1999 ISO C +Standard and they are not portable. + +Endian issues are not the only reason why the cross compiled binary will fail. +The configure script also detects other CPU specific idiosyncrasies to provide +more optimized code. + +Finally, the real show stopper problem with universal binaries is the problem +with the test suite. libsndfile contains a huge, comprehensive test suite. When +you compile a universal binary and run the test suite, you only test the native +compile. The cross compiled binary (the one with the much higher chance of +having problems) cannot be tested. + +Now, if you have read this far you're probably thinking there must be a way to +fix this and there probably is. The problem is that its a hell of a lot of work +and would require significant changes to the configure process, the internal +code and the test suite. In addition, these changes must not break compilation +on any of the platforms libsndfile is currently working on. + +## Q19 : I have project files for Visual Studio / XCode / Whatever. Why don't you distribute them with libsndfile? {#Q019} + +Use CMake project. + +## Q20 : Why doesn't libsndfile support MP3? {#Q020} + +~~In the past, MP3 was not supported because the technology behind MP3 was +patented. Those patents have now expired and there is an +[open ticket](https://github.com/libsndfile/libsndfile/issues/258) to implement +MP3 support.~~ + +**Update :** Starting from version 1.1.0 libsndfile supports MP3 format. + +## Q21 : How do I use libsndfile in a closed source or commercial program and comply with the license? {#Q021} + +Here is a checklist of things you need to do to make sure your use of libsndfile +in a closed source or commercial project complies with the license libsndfile is +released under, the GNU Lesser General Public License (LGPL): + +- Make sure you are linking to libsndfile as a shared library (Linux and Unix + systems), Dynamic Link Library (Microsoft Windows) or dynlib (Mac OS X). If + you are using some other operating system that doesn't allow dynamically + linked libraries, you will not be able to use libsndfile unless you release + the source code to your program. +- In the licensing documentation for your program, add a statement that your + software depends on libsndfile and that libsndfile is released under the GNU + Lesser General Public License, either + [version 2.1](http://www.gnu.org/licenses/lgpl-2.1.txt) or optionally + [version 3](http://www.gnu.org/licenses/lgpl.txt). +- Include the text for both versions of the license, possibly as separate files + named libsndfile_lgpl_v2_1.txt and libsndfile_lgpl_v3.txt. + +## Q22 : What versions of Windows does libsndfile work on? {#Q022} + +New versions of libsndfile binary releases require Wiindows Vista. If you need +Windows XP support, you can build DLL from sources, we don't use specific WinXP +features. + +## Q23 : I'm cross compiling libsndfile for another platform. How can I run the test suite? {#Q023} + +Since version 1.0.21 the top level Makefile has an extra make target, +'test-tarball'. Building this target creates a tarball called called: + + ` libsndfile-testsuite-${host_triplet}-${version}.tar.gz` + +in the top level directory. This tarball can then be copied to the target +platform. Once untarred and test script `test_wrapper.sh` can be run from the +top level of the extracted tarball. diff --git a/extern/libsndfile-modified/docs/_config.yml b/extern/libsndfile-modified/docs/_config.yml new file mode 100644 index 000000000..4c626e0e2 --- /dev/null +++ b/extern/libsndfile-modified/docs/_config.yml @@ -0,0 +1,8 @@ +--- +author: "The libsndfile team" +version: "1.2.2" + +markdown: kramdown +plugins: + - jekyll-default-layout +--- diff --git a/extern/libsndfile-modified/docs/_includes/logo.html b/extern/libsndfile-modified/docs/_includes/logo.html new file mode 100644 index 000000000..f17a03431 --- /dev/null +++ b/extern/libsndfile-modified/docs/_includes/logo.html @@ -0,0 +1 @@ + diff --git a/extern/libsndfile-modified/docs/_layouts/default.html b/extern/libsndfile-modified/docs/_layouts/default.html new file mode 100644 index 000000000..76c2cb8bf --- /dev/null +++ b/extern/libsndfile-modified/docs/_layouts/default.html @@ -0,0 +1,18 @@ + + + + + + {{ page.title }} + + + + + {{ content }} +
+
+

The libsndfile home page is here.

+

The libsndfile version: {{ site.version }}.

+
+ + diff --git a/extern/libsndfile-modified/docs/_layouts/home.html b/extern/libsndfile-modified/docs/_layouts/home.html new file mode 100644 index 000000000..6c8119d12 --- /dev/null +++ b/extern/libsndfile-modified/docs/_layouts/home.html @@ -0,0 +1,34 @@ +--- +layout: default +keywords: WAV AIFF AU SVX PAF NIST W64 libsndfile sound audio dsp Linux +robots: nofollow +title: libsndfile home page +--- + + + +
+
+ {{ content }} +
+
diff --git a/extern/libsndfile-modified/docs/_layouts/page.html b/extern/libsndfile-modified/docs/_layouts/page.html new file mode 100644 index 000000000..21c7d9b39 --- /dev/null +++ b/extern/libsndfile-modified/docs/_layouts/page.html @@ -0,0 +1,10 @@ +--- +layout: default +--- + + +
+
+ {{ content }} +
+
diff --git a/extern/libsndfile-modified/docs/api.md b/extern/libsndfile-modified/docs/api.md new file mode 100644 index 000000000..e17f5ad9c --- /dev/null +++ b/extern/libsndfile-modified/docs/api.md @@ -0,0 +1,744 @@ +--- +layout: page +title: The libsndfile API +--- + +# libsndfile + +Libsndfile is a library designed to allow the reading and writing of many different sampled sound file formats (such as +MS Windows WAV and the Apple/SGI AIFF format) through one standard library interface. + +During read and write operations, formats are seamlessly converted between the format the application program has +requested or supplied and the file's data format. The application programmer can remain blissfully unaware of issues +such as file endian-ness and data format. See [Note 1](#note-1) and [Note 2](#note-2). + +Every effort is made to keep these documents up-to-date, error free and unambiguous. However, since maintaining the +documentation is the least fun part of working on libsndfile, these docs can and do fall behind the behaviour of the +library. If any errors, omissions or ambiguities are found, please notify me (erikd) at mega-nerd dot com. + +To supplement this reference documentation, there are simple example programs included in the source code tarball. The +test suite which is also part of the source code tarball is also a good place to look for the correct usage of the +library functions. + +**Finally, if you think there is some feature missing from libsndfile, check that it isn't already implemented (and +documented) [here](command.md).** + +## Synopsis + +```c +#include ; +#include ; +``` + +| Name | Description | +|:------------------------------------------------------------------------------------------------------------|:--------------------------------------- | +| [sf_open, sf_wchar_open](#open) | File open functions. | +| [sf_open_fd](#open_fd) | Open sound file using file descriptor. | +| [sf_open_virtual](#open_virtual) | Open sound file using virtual API. | +| [sf_format_check](#check) | Validate sound file info. | +| [sf_seek](#seek) | Seek position in sound file. | +| [sf_command](command.md) | Command interface. | +| [sf_error, sf_strerror, sf_error_number, sf_perror, sf_error_str](#error) | Error functions. | +| [sf_close](#close) | File close function. | +| [sf_write_sync](#write_sync) | Write sync function. | +| [sf_read_short, sf_read_int, sf_read_float, sf_read_double](#read) | File items read functions. | +| [sf_readf_short, sf_readf_int, sf_readf_float, sf_readf_double](#readf) | File frames read functions. | +| [sf_write_short, sf_write_int, sf_write_float, sf_write_double](#write) | File items write functions. | +| [sf_writef_short, sf_writef_int, sf_writef_float, sf_writef_double](#writef) | File frames write functions. | +| [sf_read_raw, sf_write_raw](#raw) | Raw read/write functions. | +| [sf_get_string, sf_set_string](#string) | Functions for reading and writing string data. | +| [sf_version_string](#version_string) | Retrieve library version string. | +| [sf_current_byterate](#current_byterate) | Retrieve current byterate. | +| [sf_set_chunk, sf_get_chunk_iterator, sf_next_chunk_iterator, sf_get_chunk_size, sf_get_chunk_data](#chunk) | RIFF chunks API. | + +SNDFILE* is an anonymous pointer to data which is private to the library. + +## File Open Function {#open} + +```c +SNDFILE* sf_open (const char *path, int mode, SF_INFO *sfinfo) ; +``` + +The sf_open() function opens the sound file at the specified path. The filename is byte encoded, but may be utf-8 on +Linux, while on Mac OS X it will use the filesystem character set. On Windows, there is also a Windows specific +sf_wchar_open() that takes a UTF16_BE encoded filename. + +```c +SNDFILE* sf_wchar_open (LPCWSTR wpath, int mode, SF_INFO *sfinfo) ; +``` + +The SF_INFO structure is for passing data between the calling function and the library when opening a file for reading +or writing. It is defined in sndfile.h as follows: + +```c +typedef struct +{ sf_count_t frames ; /* Used to be called samples. */ + int samplerate ; + int channels ; + int format ; + int sections ; + int seekable ; + } SF_INFO ; +``` + +The mode parameter for this function can be any one of the following three values: + +SFM_READ +: read only mode + +SFM_WRITE +: write only mode + +SFM_RDWR +: read/write mode + +When opening a file for read, the **format** field should be set to zero before +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 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**. + +The **format** field in the above **SF_INFO** structure is made up of the +bit-wise OR of a major format type (values between 0x10000 and 0x08000000), a +minor format type (with values less than 0x10000) and an optional endian-ness +value. The currently understood formats are listed in *sndfile.h* as follows and +also include bitmasks for separating major and minor file types. Not all +combinations of endian-ness and major and minor file types are valid. + +| Name | Value | Description | +|:-------------------------|:-----------|:-------------------------------------------| +| **Major formats.** | +| SF_FORMAT_WAV | 0x010000 | Microsoft WAV format (little endian). | +| SF_FORMAT_AIFF | 0x020000 | Apple/SGI AIFF format (big endian). | +| SF_FORMAT_AU | 0x030000 | Sun/NeXT AU format (big endian). | +| SF_FORMAT_RAW | 0x040000 | RAW PCM data. | +| SF_FORMAT_PAF | 0x050000 | Ensoniq PARIS file format. | +| SF_FORMAT_SVX | 0x060000 | Amiga IFF / SVX8 / SV16 format. | +| SF_FORMAT_NIST | 0x070000 | Sphere NIST format. | +| SF_FORMAT_VOC | 0x080000 | VOC files. | +| SF_FORMAT_IRCAM | 0x0A0000 | Berkeley/IRCAM/CARL | +| SF_FORMAT_W64 | 0x0B0000 | Sonic Foundry's 64 bit RIFF/WAV | +| SF_FORMAT_MAT4 | 0x0C0000 | Matlab (tm) V4.2 / GNU Octave 2.0 | +| SF_FORMAT_MAT5 | 0x0D0000 | Matlab (tm) V5.0 / GNU Octave 2.1 | +| SF_FORMAT_PVF | 0x0E0000 | Portable Voice Format | +| SF_FORMAT_XI | 0x0F0000 | Fasttracker 2 Extended Instrument | +| SF_FORMAT_HTK | 0x100000 | HMM Tool Kit format | +| SF_FORMAT_SDS | 0x110000 | Midi Sample Dump Standard | +| SF_FORMAT_AVR | 0x120000 | Audio Visual Research | +| SF_FORMAT_WAVEX | 0x130000 | MS WAVE with WAVEFORMATEX | +| SF_FORMAT_SD2 | 0x160000 | Sound Designer 2 | +| SF_FORMAT_FLAC | 0x170000 | FLAC lossless file format | +| SF_FORMAT_CAF | 0x180000 | Core Audio File format | +| SF_FORMAT_WVE | 0x190000 | Psion WVE format | +| SF_FORMAT_OGG | 0x200000 | Xiph OGG container | +| SF_FORMAT_MPC2K | 0x210000 | Akai MPC 2000 sampler | +| SF_FORMAT_RF64 | 0x220000 | RF64 WAV file | +| SF_FORMAT_MPEG | 0x230000 | MPEG-1/2 audio stream | +| **Subtypes.** | +| SF_FORMAT_PCM_S8 | 0x0001 | Signed 8 bit data | +| SF_FORMAT_PCM_16 | 0x0002 | Signed 16 bit data | +| SF_FORMAT_PCM_24 | 0x0003 | Signed 24 bit data | +| SF_FORMAT_PCM_32 | 0x0004 | Signed 32 bit data | +| SF_FORMAT_PCM_U8 | 0x0005 | Unsigned 8 bit data (WAV and RAW only) | +| SF_FORMAT_FLOAT | 0x0006 | 32 bit float data | +| SF_FORMAT_DOUBLE | 0x0007 | 64 bit float data | +| SF_FORMAT_ULAW | 0x0010 | U-Law encoded. | +| SF_FORMAT_ALAW | 0x0011 | A-Law encoded. | +| SF_FORMAT_IMA_ADPCM | 0x0012 | IMA ADPCM. | +| SF_FORMAT_MS_ADPCM | 0x0013 | Microsoft ADPCM. | +| SF_FORMAT_GSM610 | 0x0020 | GSM 6.10 encoding. | +| SF_FORMAT_VOX_ADPCM | 0x0021 | OKI / Dialogix ADPCM | +| SF_FORMAT_NMS_ADPCM_16 | 0x0022 | 16kbs NMS G721-variant encoding. | +| SF_FORMAT_NMS_ADPCM_24 | 0x0023 | 24kbs NMS G721-variant encoding. | +| SF_FORMAT_NMS_ADPCM_32 | 0x0024 | 32kbs NMS G721-variant encoding. | +| SF_FORMAT_G721_32 | 0x0030 | 32kbs G721 ADPCM encoding. | +| SF_FORMAT_G723_24 | 0x0031 | 24kbs G723 ADPCM encoding. | +| SF_FORMAT_G723_40 | 0x0032 | 40kbs G723 ADPCM encoding. | +| SF_FORMAT_DWVW_12 | 0x0040 | 12 bit Delta Width Variable Word encoding. | +| SF_FORMAT_DWVW_16 | 0x0041 | 16 bit Delta Width Variable Word encoding. | +| SF_FORMAT_DWVW_24 | 0x0042 | 24 bit Delta Width Variable Word encoding. | +| SF_FORMAT_DWVW_N | 0x0043 | N bit Delta Width Variable Word encoding. | +| SF_FORMAT_DPCM_8 | 0x0050 | 8 bit differential PCM (XI only) | +| SF_FORMAT_DPCM_16 | 0x0051 | 16 bit differential PCM (XI only) | +| SF_FORMAT_VORBIS | 0x0060 | Xiph Vorbis encoding. | +| SF_FORMAT_OPUS | 0x0064 | Xiph/Skype Opus encoding. | +| SF_FORMAT_ALAC_16 | 0x0070 | Apple Lossless Audio Codec (16 bit). | +| SF_FORMAT_ALAC_20 | 0x0071 | Apple Lossless Audio Codec (20 bit). | +| SF_FORMAT_ALAC_24 | 0x0072 | Apple Lossless Audio Codec (24 bit). | +| SF_FORMAT_ALAC_32 | 0x0073 | Apple Lossless Audio Codec (32 bit). | +| SF_FORMAT_MPEG_LAYER_I | 0x0080 | MPEG-1 Audio Layer I. | +| SF_FORMAT_MPEG_LAYER_II | 0x0081 | MPEG-1 Audio Layer II. | +| SF_FORMAT_MPEG_LAYER_III | 0x0082 | MPEG-2 Audio Layer III. | +| **Endian-ness options.** | +| SF_ENDIAN_FILE | 0x00000000 | Default file endian-ness. | +| SF_ENDIAN_LITTLE | 0x10000000 | Force little endian-ness. | +| SF_ENDIAN_BIG | 0x20000000 | Force big endian-ness. | +| SF_ENDIAN_CPU | 0x30000000 | Force CPU endian-ness. | +| SF_FORMAT_SUBMASK | 0x0000FFFF | | +| SF_FORMAT_TYPEMASK | 0x0FFF0000 | | +| SF_FORMAT_ENDMASK | 0x30000000 | | + +Every call to **sf_open**() should be matched with a call to +[**sf_close**()](#close) to free up memory allocated during the call to **sf_open**(). + +On success, the sf_open function returns a non-NULL pointer which should be passed as the first parameter to all +subsequent libsndfile calls dealing with that audio file. On fail, the sf_open function returns a NULL pointer. An +explanation of the error can obtained by passing NULL to [**sf_strerror**()](#error). + +### File Descriptor Open {#open_fd} + +```c +SNDFILE* sf_open_fd (int fd, int mode, SF_INFO *sfinfo, int close_desc) ; +``` + +**Note:** On Microsoft Windows, this function does not work if the application +and the libsndfile DLL are linked to different versions of the Microsoft C +runtime DLL. + +The second open function takes a file descriptor of a file that has already been +opened. Care should be taken to ensure that the mode of the file represented by +the descriptor matches the mode argument. This function is useful in the +following circumstances: + +* Opening temporary files securely (ie use the **tmpfile**() to return a FILE* + pointer and then using fileno() to retrieve the file descriptor which is then + passed to libsndfile). +* Opening files with file names using OS specific character encodings and then + passing the file descriptor to **sf_open_fd**(). +* Opening sound files embedded within larger files. [More info](embedded_files.md). + +Every call to `sf_open_fd`() should be matched with a call to sf_close() to free +up memory allocated during the call to sf_open_fd(). + +When sf_close() is called, the file descriptor is only closed if the +**close_desc** parameter was TRUE when the sf_open_fd() function was called. + +On success, the sf_open_fd() function returns a non-NULL pointer which should be +passed as the first parameter to all subsequent libsndfile calls dealing with +that audio file. On fail, the sf_open_fd() function returns a NULL pointer. + +### Virtual File Open Function {#open_virtual} + +```c +SNDFILE* sf_open_virtual (SF_VIRTUAL_IO *sfvirtual, int mode, SF_INFO *sfinfo, void *user_data) ; +``` + +Opens a soundfile from a virtual file I/O context which is provided by the +caller. This is usually used to interface libsndfile to write/read from memory +with a stream or buffer based system. Apart from the sfvirtual and the user_data +parameters this function behaves like [sf_open()](#open). + +```c + typedef struct + { sf_vio_get_filelen get_filelen ; + sf_vio_seek seek ; + sf_vio_read read ; + sf_vio_write write ; + sf_vio_tell tell ; + } SF_VIRTUAL_IO ; +``` + +Libsndfile calls the callbacks provided by the SF_VIRTUAL_IO structure when +opening, reading and writing to the virtual file context. The user_data pointer +is a user defined context which will be available in the callbacks. + +```c +typedef sf_count_t (*sf_vio_get_filelen) (void *user_data) ; +typedef sf_count_t (*sf_vio_seek) (sf_count_t offset, int whence, void *user_data) ; +typedef sf_count_t (*sf_vio_read) (void *ptr, sf_count_t count, void *user_data) ; +typedef sf_count_t (*sf_vio_write) (const void *ptr, sf_count_t count, void *user_data) ; +typedef sf_count_t (*sf_vio_tell) (void *user_data) ; +``` + +#### sf_vio_get_filelen + +```c +typedef sf_count_t (*sf_vio_get_filelen) (void *user_data) ; +``` + +The virtual file context must return the length of the virtual file in bytes. + +#### sf_vio_seek + +```c +typedef sf_count_t (*sf_vio_seek) (sf_count_t offset, int whence, void *user_data) ; +``` + +The virtual file context must seek to offset using the seek mode provided by +whence which is one of SEEK_CUR, SEEK_SET, SEEK_END. + +The return value must contain the new offset in the file. + +#### sf_vio_read + +```c +typedef sf_count_t (*sf_vio_read) (void *ptr, sf_count_t count, void *user_data) ; +``` + +The virtual file context must copy ("read") "count" bytes into the buffer +provided by ptr and return the count of actually copied bytes. + +#### sf_vio_write + +```c +typedef sf_count_t (*sf_vio_write) (const void *ptr, sf_count_t count, void *user_data) ; +``` + +The virtual file context must process "count" bytes stored in the buffer passed +with ptr and return the count of actually processed bytes. + +#### sf_vio_tell + +```c +typedef sf_count_t (*sf_vio_tell) (void *user_data) ; +``` + +Return the current position of the virtual file context. + +## Format Check Function {#chek} + +```c +int sf_format_check (const SF_INFO *info) ; +``` + +This function allows the caller to check if a set of parameters in the SF_INFO +struct is valid before calling [sf_open](#open) (SFM_WRITE). + +sf_format_check() returns TRUE if the parameters are valid and FALSE otherwise. + +## File Seek Functions + +```c +sf_count_t sf_seek (SNDFILE *sndfile, sf_count_t frames, int whence) ; +``` + +The file seek functions work much like lseek in unistd.h with the exception that +the non-audio data is ignored and the seek only moves within the audio data +section of the file. In addition, seeks are defined in number of (multichannel) +frames. Therefore, a seek in a stereo file from the current position forward +with an offset of 1 would skip forward by one sample of both channels. + +like lseek(), the whence parameter can be any one of the following three values: + +SEEK_SET +: The offset is set to the start of the audio data plus offset (multichannel) +frames. + +SEEK_CUR +: The offset is set to its current location plus offset (multichannel) frames. + +SEEK_END +: The offset is set to the end of the data plus offset (multichannel) frames. + +Internally, libsndfile keeps track of the read and write locations using +separate read and write pointers. If a file has been opened with a mode of +SFM_RDWR, bitwise OR-ing the standard whence values above with either SFM_READ +or SFM_WRITE allows the read and write pointers to be modified separately. +If the SEEK_* values are used on their own, the read and write pointers are +both modified. + +Note that the frames offset can be negative and in fact should be when SEEK_END +is used for the whence parameter. + +sf_seek will return the offset in (multichannel) frames from the start of the +audio data or -1 if an error occurred (ie an attempt is made to seek beyond the +start or end of the file). + +## Error Reporting Functions {#error} + +```c +int sf_error (SNDFILE *sndfile) ; +``` + +This function returns the current error number for the given SNDFILE. + +The error number may be one of the following: + +| Name | Value | +|:----------------------------|:------| +| SF_ERR_NO_ERROR | 0 | +| SF_ERR_UNRECOGNISED_FORMAT | 1 | +| SF_ERR_SYSTEM | 2 | +| SF_ERR_MALFORMED_FILE | 3 | +| SF_ERR_UNSUPPORTED_ENCODING | 4 | + +or any one of many other internal error values. +Applications should only test the return value against error values defined in +\; as the internal error values are subject to change at any time. +For errors not in the above list, the function sf_error_number() can be used to +convert it to an error string. + +```c +const char* sf_strerror (SNDFILE *sndfile) ; +const char* sf_error_number (int errnum) ; +``` + +The error functions sf_strerror () and sf_error_number () convert the library's +internal error enumerations into text strings. + +```c +int sf_perror (SNDFILE *sndfile) ; +int sf_error_str (SNDFILE *sndfile, char* str, size_t len) ; +``` + +The functions sf_perror() and sf_error_str() are deprecated and will be dropped +from the library at some later date. + +## File Close Function {#close} + +```c +int sf_close (SNDFILE *sndfile) ; +``` + +The close function closes the file, deallocates its internal buffers and returns +0 on success or an error value otherwise. + +## Write Sync Function {#write_sync} + +```c +void sf_write_sync (SNDFILE *sndfile) ; +``` + +If the file is opened SFM_WRITE or SFM_RDWR, call the operating system's +function to force the writing of all file cache buffers to disk. If the file is +opened SFM_READ no action is taken. + +## File Read Functions {#read} + +```c +sf_count_t sf_read_short (SNDFILE *sndfile, short *ptr, sf_count_t items) ; +sf_count_t sf_read_int (SNDFILE *sndfile, int *ptr, sf_count_t items) ; +sf_count_t sf_read_float (SNDFILE *sndfile, float *ptr, sf_count_t items) ; +sf_count_t sf_read_double (SNDFILE *sndfile, double *ptr, sf_count_t items) ; +``` + +{: #readf} +```c +sf_count_t sf_readf_short (SNDFILE *sndfile, short *ptr, sf_count_t frames) ; +sf_count_t sf_readf_int (SNDFILE *sndfile, int *ptr, sf_count_t frames) ; +sf_count_t sf_readf_float (SNDFILE *sndfile, float *ptr, sf_count_t frames) ; +sf_count_t sf_readf_double (SNDFILE *sndfile, double *ptr, sf_count_t frames) ; +``` + +The file read functions fill the array pointed to by ptr with the requested +number of items or frames. + +For the frames-count functions, the frames parameter specifies the number of +frames. A frame is just a block of samples, one for each channel. + +**Care must be taken to ensure that there is enough space in the array pointed +to by ptr, to take (frames \* channels) number of items (shorts, ints, floats or +doubles).** + +For the items-count functions, the items parameter must be an integer product +of the number of channels or an error will occur. Here, an item is just a +sample. + +Note: The only difference between the "items" and "frames" versions of each read +function is the units in which the object count is specified - calling +sf_readf_short() with a count argument of N, on a SNDFILE with C channels, is +the same as calling sf_read_short with a count argument of N\*C. The buffer +pointed to by "ptr" should be the same number of bytes in each case. + +Note: The data type used by the calling program and the data format of the file +do not need to be the same. For instance, it is possible to open a 16 bit PCM +encoded WAV file and read the data using sf_read_float(). The library seamlessly +converts between the two formats on-the-fly. See [Note 1](#note-1). + +The sf_read_XXXX and sf_readf_XXXX functions return the number of items or +frames read, respectively. Unless the end of the file was reached during the +read, the return value should equal the number of objects requested. Attempts to +read beyond the end of the file will not result in an error but will cause the +read functions to return less than the number of objects requested or 0 if +already at the end of the file. When the buffer is not is not completely filled, +unused buffer space is filled by zeroes. + +## File Write Functions {#write} + +```c +sf_count_t sf_write_short (SNDFILE *sndfile, short *ptr, sf_count_t items) ; +sf_count_t sf_write_int (SNDFILE *sndfile, int *ptr, sf_count_t items) ; +sf_count_t sf_write_float (SNDFILE *sndfile, float *ptr, sf_count_t items) ; +sf_count_t sf_write_double (SNDFILE *sndfile, double *ptr, sf_count_t items) ; +``` + +{: #writef} +```c +sf_count_t sf_writef_short (SNDFILE *sndfile, short *ptr, sf_count_t frames) ; +sf_count_t sf_writef_int (SNDFILE *sndfile, int *ptr, sf_count_t frames) ; +sf_count_t sf_writef_float (SNDFILE *sndfile, float *ptr, sf_count_t frames) ; +sf_count_t sf_writef_double (SNDFILE *sndfile, double *ptr, sf_count_t frames) ; +``` + +The file write functions write the data in the array pointed to by ptr to the +file. + +For items-count functions, the items parameter specifies the size of the array +and must be an integer product of the number of channels or an error will occur. + +For the frames-count functions, the array is expected to be large enough to hold +a number of items equal to the product of frames and the number of channels. + +As with the read functions [above](#read), the only difference in the items and +frames version of each write function is the units in which the buffer size is +specified. Again, the data type used by the calling program and the data format +of the file do not need to be the same ([Note 1](#note-1)). + +The sf_write_XXXX and sf_writef_XXXX functions respectively return the number of +items or frames written (which should be the same as the items or frames +parameter). + +## Raw File Read and Write Functions {#raw} + +```c +sf_count_t sf_read_raw (SNDFILE *sndfile, void *ptr, sf_count_t bytes) ; +sf_count_t sf_write_raw (SNDFILE *sndfile, void *ptr, sf_count_t bytes) ; +``` + +**Note:** Unless you are writing an external decoder/encode that uses libsndfile +to handle the file headers, you should not be using these functions. + +The raw read and write functions read raw audio data from the audio file (not to +be confused with reading RAW header-less PCM files). The number of bytes read or +written must always be an integer multiple of the number of channels multiplied +by the number of bytes required to represent one sample from one channel. + +The raw read and write functions return the number of bytes read or written +(which should be the same as the bytes parameter). + +**Note : The result of using of both regular reads/writes and raw reads/writes +on compressed file formats other than SF_FORMAT_ALAW and SF_FORMAT_ULAW is +undefined.** + +See also : [SFC_RAW_NEEDS_ENDSWAP](command.md#sfc_raw_needs_endswap). + +## Functions for Reading and Writing String Data {#string} + +```c +const char* sf_get_string (SNDFILE *sndfile, int str_type) ; +int sf_set_string (SNDFILE *sndfile, int str_type, const char* str) ; +``` + +These functions allow strings to be set on files opened for write and to be +retrieved from files opened for read where supported by the given file type. The +**str_type** parameter can be any one of the following string types: + +| Name | Value | Description | +|:-------------------|:------|:--------------| +| SF_STR_TITLE | 0x01 | Title. | +| SF_STR_COPYRIGHT | 0x02 | Copyright. | +| SF_STR_SOFTWARE | 0x03 | Software. | +| SF_STR_ARTIST | 0x04 | Artist. | +| SF_STR_COMMENT | 0x05 | Comment. | +| SF_STR_DATE | 0x06 | Date. | +| SF_STR_ALBUM | 0x07 | Album. | +| SF_STR_LICENSE | 0x08 | License. | +| SF_STR_TRACKNUMBER | 0x09 | Track number. | +| SF_STR_GENRE | 0x10 | Genre. | + +The sf_get_string() function returns the specified string if it exists and a +NULL pointer otherwise. In addition to the string ids above, SF_STR_FIRST (== +SF_STR_TITLE) and SF_STR_LAST (always the same as the highest numbers string id) +are also available to allow iteration over all the available string ids. + +The sf_set_string() function sets the string data. It returns zero on success +and non-zero on error.The error code can be converted to a string using +sf_error_number(). + +Strings passed to and retrieved from these two functions are assumed to be +utf-8. However, while formats like Ogg/Vorbis and FLAC fully support utf-8, +others like WAV and AIFF officially only support ASCII. Writing utf-8 strings to +WAV and AIF files with libsndfile will work when read back with libsndfile, but +may not work with other programs. + +The suggested method of dealing with tags retrieved using sf_get_string() is to +assume they are utf-8. Similarly if you have a string in some exotic format like +utf-16, it should be encoded to utf-8 before being written using libsndfile. + +## Function for retrieving library version {#version_string} + +```c +const char *sf_version_string (void) ; +``` + +Return the library version string. + +## Function for retrieving current byterate {#current_byterate} + +```c +int sf_current_byterate (SNDFILE *sndfile) ; +``` + +Return the current byterate at this point in the file. The byte rate in this +case is the number of bytes per second of audio data. For instance, for a +stereo, 18 bit PCM encoded file with an 16kHz sample rate, the byte rate +would be 2 (stereo) \* 2 (two bytes per sample) * 16000 => 64000 bytes/sec. + +For some file formats the returned value will be accurate and exact, for some +it will be a close approximation, for some it will be the average bitrate for +the whole file and for some it will be a time varying value that was accurate +when the file was most recently read or written. + +To get the bitrate, multiple this value by 8. + +`sf_current_byterate` returns byte per second or -1 if byterate is +unknown. + +## Functions to get and set chunks from within a sound file + +These functions allow the getting and setting of chunks within a sound file (for +those formats which allow it). + +These functions fail safely. Specifically, they will not allow you to overwrite +existing chunks or add extra versions of format specific reserved chunks but +should allow you to retrieve any and all chunks (may not be implemented for all +chunks or all file formats). + +### sf_set_chunk + +```c +int sf_set_chunk (SNDFILE *sndfile, const SF_CHUNK_INFO *chunk_info) ; +``` + +Set the specified chunk info (must be done before any audio data is written to +the file). This will fail for format specific reserved chunks. The +`chunk_info->data` pointer must be valid until the file is closed. + +The `SF_CHUNK_INFO` struct is documented as follows: + +```c +struct SF_CHUNK_INFO +{ char id [64] ; /* The chunk identifier. */ + unsigned id_size ; /* The size of the chunk identifier. */ + unsigned datalen ; /* The size of that data. */ + void *data ; /* Pointer to the data. */ +} ; + typedef struct SF_CHUNK_INFO SF_CHUNK_INFO ; +``` + +`sf_set_chunk` returns `SF_ERR_NO_ERROR` on success or non-zero on failure. + +### sf_get_chunk_iterator + +```c +SF_CHUNK_ITERATOR * +sf_get_chunk_iterator (SNDFILE *sndfile, const SF_CHUNK_INFO *chunk_info) ; +``` + +Get an iterator for all chunks matching `chunk_info`. + +`SF_CHUNK_ITERATOR` is an opaque structure to an iterator over the all chunks of +a given id and defined as follows: + +```c +typedef struct SF_CHUNK_ITERATOR SF_CHUNK_ITERATOR ; +``` + +The iterator will point to the first chunk matching `chunk_info`. Chunks are +matching, if (`chunk_info->id`) matches the first (`chunk_info->id_size`) bytes +of a chunk found in the `SNDFILE*` handle. If `chunk_info` is `NULL`, an +iterator to all chunks in the `SNDFILE*` handle is returned. The values of +`chunk_info->datalen` and `chunk_info->data` are ignored. If no matching chunks +are found in the sndfile, `NULL` is returned. + +The returned iterator will stay valid until one of the following occurs: + +* The sndfile is closed. +* A new chunk is added using [`sf_set_chunk()`](#sf_set_chunk). +* Another chunk iterator function is called on the same `SNDFILE*` + handle that causes the iterator to be modified. + +The memory for the iterator belongs to the SNDFILE* handle and is freed when +[sf_close](#close) is called. + +### sf_next_chunk_iterator + +```c +sf_next_chunk_iterator (SF_CHUNK_ITERATOR * iterator) ; +``` + +Iterate through chunks by incrementing the iterator. + +Increments the iterator and returns a handle to the new one. After this call, +iterator will no longer be valid, and you must use the newly returned handle +from now on. The returned handle can be used to access the next chunk matching +the criteria as defined in [sf_get_chunk_iterator](#sf_get_chunk_iterator). +If iterator points to the last chunk, this will free all resources associated +with iterator and return `NULL`. The returned iterator will stay valid until +`sf_get_next_chunk_iterator` is called again, the sndfile is closed or a new +chunk us added. + +### sf_get_chunk_size + +```c +int +sf_get_chunk_size (const SF_CHUNK_ITERATOR * it, SF_CHUNK_INFO * chunk_info) ; +``` + +Get the size of the specified chunk. + +If the specified chunk exists, the size will be returned in the `datalen` field +of the `SF_CHUNK_INFO` struct. Additionally, the id of the chunk will be copied +to the `id` field of the `SF_CHUNK_INFO` struct and it's `id_size` field will be +updated accordingly. + +If the chunk doesn't exist `chunk_info->datalen` will be zero, and the `id` and +`id_size` fields will be undefined. + +The function will return `SF_ERR_NO_ERROR` on success or non-zero on failure. + +### sf_get_chunk_data + +```c +int +sf_get_chunk_data (const SF_CHUNK_ITERATOR *it, SF_CHUNK_INFO *chunk_info) ; +``` + +Get the specified chunk data. + +If the specified chunk exists, up to `chunk_info->datalen` bytes of the chunk +data will be copied into the `chunk_info->data` buffer (allocated by the caller) +and the `chunk_info->datalen` field updated to reflect the size of the data. The +`id` and `id_size` field will be updated according to the retrieved chunk. If +the chunk doesn't exist `chunk_info->datalen` will be zero, and the `id` and +`id_size` fields will be undefined. + +The function will return `SF_ERR_NO_ERROR` on success or non-zero on failure. + +## Note 1 + +When converting between integer PCM formats of differing size (e.g. using +sf_read_int() to read a 16 bit PCM encoded WAV file) libsndfile obeys one simple +rule: + +Whenever integer data is moved from one sized container to another sized +container, the most significant bit in the source container will become the most +significant bit in the destination container. + +When converting between integer data and floating point data, different rules +apply. The default behaviour when reading floating point data (sf_read_float() +or sf_read_double ()) from a file with integer data is normalisation. Regardless +of whether data in the file is 8, 16, 24 or 32 bit wide, the data will be read +as floating point data in the range [-1.0, 1.0]. Similarly, data in the range +[-1.0, 1.0] will be written to an integer PCM file so that a data value of 1.0 +will be the largest allowable integer for the given bit width. This +normalisation can be turned on or off using the [sf_command](command.md) +interface. + +## Note 2 + +Reading a file containing floating point data (allowable with WAV, AIFF, AU and +other file formats) using integer read methods (sf_read_short() or +sf_read_int()) can produce unexpected results. For instance the data in the file +may have a maximum absolute value < 1.0 which would mean that all sample +values read from the file will be zero. In order to read these files correctly +using integer read methods, it is recommended that you use the +[sf_command](command.md) interface, a command of +[SFC_SET_SCALE_FLOAT_INT_READ](command.md#sfc_set_scale_float_int_read) and a +parameter of SF_TRUE to force correct scaling. diff --git a/extern/libsndfile-modified/docs/bugs.md b/extern/libsndfile-modified/docs/bugs.md new file mode 100644 index 000000000..9f2f00ce5 --- /dev/null +++ b/extern/libsndfile-modified/docs/bugs.md @@ -0,0 +1,47 @@ +--- +layout: page +--- + +# Reporting Bugs in libsndfile + +Before even attempting to report a bug in libsndfile please make sure you have +read the [Frequently Asked Questions](FAQ.md). If you are having a problem +writing code using libsndfile make sure you read the +[Application Programming Interface](api.md) documentation. + +That said, I am interested in finding and fixing all genuine bugs in libsndfile. +Bugs I want to fix include any of the following problems (and probably others): + +- Compilation problems on new platforms. +- Errors being detected during the `make check` process. +- Segmentation faults occurring inside libsndfile. +- libsndfile hanging when opening a file. +- Supported sound file types being incorrectly read or written. +- Omissions, errors or spelling mistakes in the documentation. + +When submitting a bug report you must include: + +- Your system (CPU and memory size should be enough). +- The operating system you are using. +- Whether you are using a package provided by your distribution or you compiled + it yourself. +- If you compiled it yourself, the compiler you are using. (Also make sure to + run `make check`.) +- A description of the problem. +- Information generated by the sndfile-info program (see next paragraph). +- If you are having problems with sndfile-play and ALSA on Linux, I will need + information about your kernel, ALSA version, compiler version, whether you + compiled the kernel/ALSA your self or installed from a package etc. + +If libsndfile compiles and installs correctly but has difficulty reading a +particular file or type of file you should run the **sndfile-info** program +(from the examples directory of the libsndfile distribution) on the file. See +[here](sndfile_info.md) for an example of the use of the **sndfile-info** +program. + +Please do not send me a sound file which fails to open under libsndfile unless +I specifically ask you to. The above information should usually suffice for most +problems. + +Once you have the above information you should submit a ticket on the libsndfile +[GitHub issue tracker](https://github.com/libsndfile/libsndfile/issues). diff --git a/extern/libsndfile-modified/docs/command.md b/extern/libsndfile-modified/docs/command.md new file mode 100644 index 000000000..53e01926c --- /dev/null +++ b/extern/libsndfile-modified/docs/command.md @@ -0,0 +1,2016 @@ +--- +layout: page +title: libsndfile : the sf_command function. +--- + +# sf_command + +```c +int sf_command (SNDFILE *sndfile, int cmd, void *data, int datasize) ; +``` + +This function allows the caller to retrieve information from or change aspects +of the library behaviour. Examples include retrieving a string containing the +library version or changing the scaling applied to floating point sample data +during read and write. Most of these operations are performed on a per-file +basis. + +The cmd parameter is an integer identifier which is defined in *sndfile.h*. All +of the valid command identifiers have names beginning with "SFC_". Data is +passed to and returned from the library by use of a void pointer. The library +will not read or write more than datasize bytes from the void pointer. For some +calls no data is required in which case data should be NULL and datasize may be +used for some other purpose. + +The available commands are as follows: + +| Name | Description | +|:------------------------------------------------------------------|:--------------------------------------------------------| +| [SFC_GET_LIB_VERSION](#sfc_get_lib_version) | Retrieve the version of the library as a string. | +| [SFC_GET_LOG_INFO](#sfc_get_log_info) | Retrieve the internal per-file operation log. | +| [SFC_GET_CURRENT_SF_INFO](#sfc_get_current_sf_info) | Retrieve `SF_INFO` struct of opened file. | +| [SFC_CALC_SIGNAL_MAX](#sfc_calc_signal_max) | Calculate the measured maximum signal value. | +| [SFC_CALC_NORM_SIGNAL_MAX](#sfc_calc_norm_signal_max) | Calculate the measured normalised maximum signal value. | +| [SFC_CALC_MAX_ALL_CHANNELS](#sfc_calc_max_all_channels) | Calculate the peak value for each channel. | +| [SFC_CALC_NORM_MAX_ALL_CHANNELS](#sfc_calc_norm_max_all_channels) | Calculate the normalised peak for each channel. | +| [SFC_GET_SIGNAL_MAX](#sfc_get_signal_max) | Retrieve the peak value for the file. | +| [SFC_GET_MAX_ALL_CHANNELS](#sfc_get_max_all_channels) | Retrieve the peak value for each channel. | +| [SFC_SET_NORM_FLOAT](#sfc_set_norm_float) | Set float normalisation behaviour. | +| [SFC_SET_NORM_DOUBLE](#sfc_set_norm_double) | Set double normalisation behaviour. | +| [SFC_GET_NORM_FLOAT](#sfc_get_norm_float) | Get float normalisation behaviour. | +| [SFC_GET_NORM_DOUBLE](#sfc_get_norm_double) | Get double normalisation behaviour. | +| [SFC_SET_SCALE_FLOAT_INT_READ](#sfc_set_scale_float_int_read) | Control scale factor on read. | +| [SFC_SET_SCALE_INT_FLOAT_WRITE](#sfc_set_scale_int_float_write) | Control scale factor on write. | +| [SFC_GET_SIMPLE_FORMAT_COUNT](#sfc_get_simple_format_count) | Get simple formats count. | +| [SFC_GET_SIMPLE_FORMAT](#sfc_get_simple_format) | Get information about a simple format. | +| [SFC_GET_FORMAT_INFO](#sfc_get_format_info) | Get information about a major or subtype format. | +| [SFC_GET_FORMAT_MAJOR_COUNT](#sfc_get_format_major_count) | Get the number of major formats. | +| [SFC_GET_FORMAT_MAJOR](#sfc_get_format_major) | Get information about a major format type. | +| [SFC_GET_FORMAT_SUBTYPE_COUNT](#sfc_get_format_subtype_count) | Get the number of subformats. | +| [SFC_GET_FORMAT_SUBTYPE](#sfc_get_format_subtype) | Get information about a subformat. | +| [SFC_SET_ADD_PEAK_CHUNK](#sfc_set_add_peak_chunk) | Control PEAK chunk write to WAV and AIFF. | +| [SFC_UPDATE_HEADER_NOW](#sfc_update_header_now) | Update the file header in write mode on demand. | +| [SFC_SET_UPDATE_HEADER_AUTO](#sfc_set_update_header_auto) | Update the file header on each write. | +| [SFC_FILE_TRUNCATE](#sfc_file_truncate) | Truncate a file open for write or for read/write. | +| [SFC_SET_RAW_START_OFFSET](#sfc_set_raw_start_offset) | Change the data start offset for raw files. | +| SFC_SET_DITHER_ON_WRITE | Not implemented. | +| SFC_SET_DITHER_ON_READ | Not implemented. | +| SFC_GET_DITHER_INFO_COUNT | Not implemented. | +| SFC_GET_DITHER_INFO | Not implemented. | +| [SFC_SET_CLIPPING](#sfc_set_clipping) | Control automatic clipping behaviour. | +| [SFC_GET_CLIPPING](#sfc_get_clipping) | Get current clipping setting. | +| [SFC_GET_EMBED_FILE_INFO](#sfc_get_embed_file_info) | Get information about embedded audio files. | +| [SFC_WAVEX_GET_AMBISONIC](#sfc_wavex_get_ambisonic) | Test a WAVEX file for Ambisonic format. | +| [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. | +| [SFC_SET_BROADCAST_INFO](#sfc_set_broadcast_info) | Set the Broadcast Chunk info. | +| [SFC_GET_CHANNEL_MAP_INFO](#sfc_get_channel_map_info) | Get the channel map info. | +| [SFC_SET_CHANNEL_MAP_INFO](#sfc_set_channel_map_info) | Set the channel map info. | +| [SFC_SET_CART_INFO](#sfc_set_cart_info) | Set the Cart Chunk info. | +| [SFC_GET_CART_INFO](#sfc_get_cart_info) | Get the Cart Chunk info. | +| [SFC_GET_LOOP_INFO](#sfc_get_loop_info) | Get loop info. | +| [SFC_GET_INSTRUMENT](#sfc_get_instrument) | Get instrument info. | +| [SFC_SET_INSTRUMENT](#sfc_set_instrument) | Set instrument info. | +| [SFC_GET_CUE_COUNT](#sfc_get_cue_count) | Get the cue marker count. | +| [SFC_GET_CUE](#sfc_get_cue) | Get cue marker info. | +| [SFC_SET_CUE](#sfc_set_cue) | Set cue marker info. | +| [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_LIB_VERSION + +Retrieve the version of the library as a string. + +### Parameters + +sndfile +: Not used + +cmd +: SFC_GET_LIB_VERSION + +data +: A pointer to a char buffer + +datasize +: The size of the buffer + +### Examples + +```c +char buffer [128] ; +sf_command (NULL, SFC_GET_LIB_VERSION, buffer, sizeof (buffer)) ; +``` + +### Return value + +This call will return the length of the retrieved version string. + +### Notes + +The string returned in the buffer passed to this function will not overflow the +buffer and will always be null terminated . + +## SFC_GET_LOG_INFO + +Retrieve the internal per-file operation log. + +This log buffer can often contain a good reason for why libsndfile failed to +open a particular file. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_GET_LOG_INFO + +data +: A pointer to a char buffer + +datasize +: The size of the buffer + +Example: + +```c +char buffer [2048] ; +sf_command (sndfile, SFC_GET_LOG_INFO, buffer, sizeof (buffer)) ; +``` + +### Return value + +This call will return the length of the retrieved version string. + +### Notes + +The string returned in the buffer passed to this function will not overflow the +buffer and will always be null terminated. + +## SFC_GET_CURRENT_SF_INFO + +Retrieve `SF_INFO` struct of opened file. + +`SFC_GET_CURRENT_SF_INFO` command copies `SF_INFO` struct of `sndfile` object to +provided buffer. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_GET_CURRENT_SF_INFO + +data +: A pointer to a valid SF_INFO* pointer + +datasize +: sizeof (SF_INFO) + +### Examples + +```c +SF_INFO sfinfo ; +sf_command (sndfile, SFC_GET_CURRENT_SF_INFO, sfinfo, sizeof (SF_INFO)) ; +``` + +### Return value + +Zero on success, non-zero otherwise. + +## SFC_CALC_SIGNAL_MAX + +Retrieve the measured maximum signal value. This involves reading through the +whole file which can be slow on large files. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_CALC_SIGNAL_MAX + +data +: A pointer to a double + +datasize +: sizeof (double) + +### Examples + +```c +double max_val ; +sf_command (sndfile, SFC_CALC_SIGNAL_MAX, &max_val, sizeof (max_val)) ; +``` + +### Return value + +Zero on success, non-zero otherwise. + +## SFC_CALC_NORM_SIGNAL_MAX + +Retrieve the measured normalised maximum signal value. This involves reading +through the whole file which can be slow on large files. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_CALC_NORM_SIGNAL_MAX + +data +: A pointer to a double + +datasize +: sizeof (double) + +### Examples + +```c +double max_val ; +sf_command (sndfile, SFC_CALC_NORM_SIGNAL_MAX, &max_val, sizeof (max_val)) ; +``` + +### Return value + +Zero on success, non-zero otherwise. + +## SFC_CALC_MAX_ALL_CHANNELS + +Calculate the peak value (ie a single number) for each channel. This involves +reading through the whole file which can be slow on large files. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_CALC_MAX_ALL_CHANNELS + +data +: A pointer to a double + +datasize +: sizeof (double) * number_of_channels + +### Examples + +```c +double peaks [number_of_channels] ; +sf_command (sndfile, SFC_CALC_MAX_ALL_CHANNELS, peaks, sizeof (peaks)) ; +``` + +### Return value + +Zero if peaks have been calculated successfully and non-zero otherwise. + +## SFC_CALC_NORM_MAX_ALL_CHANNELS + +Calculate the normalised peak for each channel. This involves reading through +the whole file which can be slow on large files. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_CALC_NORM_MAX_ALL_CHANNELS + +data +: A pointer to a double + +datasize +: sizeof (double) * number_of_channels + +### Examples + +```c +double peaks [number_of_channels] ; +sf_command (sndfile, SFC_CALC_NORM_MAX_ALL_CHANNELS, peaks, sizeof (peaks)) ; +``` + +### Return value + +Zero if peaks have been calculated successfully and non-zero otherwise. + +## SFC_GET_SIGNAL_MAX + +Retrieve the peak value for the file as stored in the file header. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_GET_SIGNAL_MAX + +data +: A pointer to a double + +datasize +: sizeof (double) + +### Examples + +```c +double max_peak ; +sf_command (sndfile, SFC_GET_SIGNAL_MAX, &max_peak, sizeof (max_peak)) ; +``` + +### Return value + +SF_TRUE if the file header contained the peak value. SF_FALSE +otherwise. + +## SFC_GET_MAX_ALL_CHANNELS + +Retrieve the peak value for the file as stored in the file header. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_GET_SIGNAL_MAX + +data +: A pointer to an array of doubles + +datasize +: sizeof (double) * number_of_channels + +### Example + +```c +double peaks [number_of_channels] ; +sf_command (sndfile, SFC_GET_MAX_ALL_CHANNELS, peaks, sizeof (peaks)) ; +``` + +### Return value + +SF_TRUE if the file header contains per channel peak values for the file, +SF_FALSE otherwise. + +## SFC_SET_NORM_FLOAT + +This command only affects data read from or written to using the +floating point +functions: + +```c +size_t sf_read_float (SNDFILE *sndfile, float *ptr, size_t items) ; +size_t sf_readf_float (SNDFILE *sndfile, float *ptr, size_t frames) ; + +size_t sf_write_float (SNDFILE *sndfile, float *ptr, size_t items) ; +size_t sf_writef_float (SNDFILE *sndfile, float *ptr, size_t frames) ; +``` + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_SET_NORM_FLOAT + +data +: NULL + +datasize +: SF_TRUE or SF_FALSE + +For read operations setting normalisation to SF_TRUE means that the data from +all subsequent reads will be be normalised to the range [-1.0, 1.0]. + +For write operations, setting normalisation to SF_TRUE means than all data +supplied to the float write functions should be in the range [-1.0, 1.0] and +will be scaled for the file format as necessary. + +For both cases, setting normalisation to SF_FALSE means that no scaling will +take place. + +### Examples + +```c +sf_command (sndfile, SFC_SET_NORM_FLOAT, NULL, SF_TRUE) ; + +sf_command (sndfile, SFC_SET_NORM_FLOAT, NULL, SF_FALSE) ; +``` + +### Return value + +Returns the previous float normalisation mode. + +## SFC_SET_NORM_DOUBLE + +This command only affects data read from or written to using the double +precision floating point +functions: + +```c +size_t sf_read_double (SNDFILE *sndfile, double *ptr, size_t items) ; +size_t sf_readf_double (SNDFILE *sndfile, double *ptr, size_t frames) ; + +size_t sf_write_double (SNDFILE *sndfile, double *ptr, size_t items) ; +size_t sf_writef_double (SNDFILE *sndfile, double *ptr, size_t frames) ; +``` + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_SET_NORM_DOUBLE + +data +: NULL + +datasize +: SF_TRUE or SF_FALSE + +For read operations setting normalisation to SF_TRUE means that the data from +all subsequent reads will be be normalised to the range [-1.0, 1.0]. + +For write operations, setting normalisation to SF_TRUE means than all data +supplied to the double write functions should be in the range [-1.0, 1.0] and +will be scaled for the file format as necessary. + +For both cases, setting normalisation to SF_FALSE means that no scaling will +take place. + +### Examples + +```c +sf_command (sndfile, SFC_SET_NORM_DOUBLE, NULL, SF_TRUE) ; + +sf_command (sndfile, SFC_SET_NORM_DOUBLE, NULL, SF_FALSE) ; +``` + +### Return value + +Returns the previous double normalisation mode. + +## SFC_GET_NORM_FLOAT + +Retrieve the current float normalisation mode. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_GET_NORM_FLOAT + +data +: NULL + +datasize +: anything + +### Examples + +```c +normalisation = sf_command (sndfile, SFC_GET_NORM_FLOAT, NULL, 0) ; +``` + +### Return value + +Returns TRUE if normalisation is on and FALSE otherwise. + +## SFC_GET_NORM_DOUBLE + +Retrieve the current float normalisation mode. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_GET_NORM_DOUBLE + +data +: NULL + +datasize +: anything + +Example: + +```c +normalisation = sf_command (sndfile, SFC_GET_NORM_DOUBLE, NULL, 0) ; +``` + +### Return value + +Returns TRUE if normalisation is on and FALSE otherwise. + +## SFC_SET_SCALE_FLOAT_INT_READ + +Set/clear the scale factor when integer (short/int) data is read from a file +containing floating point data. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd: +SFC_SET_SCALE_FLOAT_INT_READ + +data +: NULL + +datasize +: TRUE or FALSE + +Example: + +```c +sf_command (sndfile, SFC_SET_SCALE_FLOAT_INT_READ, NULL, SF_TRUE) ; +``` + +### Return value + +Returns the previous `SFC_SET_SCALE_FLOAT_INT_READ` setting for this file. + +## SFC_SET_SCALE_INT_FLOAT_WRITE + +Set/clear the scale factor when integer (short/int) data is written to a file as +floating point data. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_SET_SCALE_INT_FLOAT_WRITE + +data +: NULL + +datasize +: TRUE or FALSE + +### Examples + +```c +sf_command (sndfile, SFC_SET_SCALE_INT_FLOAT_WRITE, NULL, SF_TRUE) ; +``` + +### Return value + +Returns the previous `SFC_SET_SCALE_INT_FLOAT_WRITE` setting for this file. + +## SFC_GET_SIMPLE_FORMAT_COUNT + +Retrieve the number of simple formats supported by libsndfile. + +### Parameters + +sndfile +: Not used. + +cmd +: SFC_GET_SIMPLE_FORMAT_COUNT + +data +: a pointer to an int + +datasize +: sizeof (int) + +### Examples + +```c +int count ; +sf_command (sndfile, SFC_GET_SIMPLE_FORMAT_COUNT, &count, sizeof (int)) ; +``` + +### Return value + +`0`. + +## SFC_GET_SIMPLE_FORMAT + +Retrieve information about a simple format. + +### Parameters + +sndfile +: Not used. + +cmd +: SFC_GET_SIMPLE_FORMAT + +data +: a pointer to an SF_FORMAT_INFO struct + +datasize +: sizeof (SF_FORMAT_INFO) + +The SF_FORMAT_INFO struct is defined in *sndfile.h* as: + +```c +typedef struct +{ int format ; + const char *name ; + const char *extension ; +} SF_FORMAT_INFO ; +``` + +When `sf_command()` is called with `SF_GET_SIMPLE_FORMAT`, the value of the +format field should be the format number (ie 0 \<= format \<= count value +obtained using `SF_GET_SIMPLE_FORMAT_COUNT). + +### Examples + +```c +SF_FORMAT_INFO format_info ; +int k, count ; + +sf_command (sndfile, SFC_GET_SIMPLE_FORMAT_COUNT, &count, sizeof (int)) ; + +for (k = 0 ; k < count ; k++) +{ format_info.format = k ; + sf_command (sndfile, SFC_GET_SIMPLE_FORMAT, &format_info, sizeof (format_info)) ; + printf ("%08x %s %s\n", format_info.format, format_info.name, format_info.extension) ; + } ; +``` + +### Return value + +0 on success and non-zero otherwise. + +The value of the format field of the `SF_FORMAT_INFO` struct will be a value +which can be placed in the format field of an `SF_INFO` struct when a file is to +be opened for write. The name field will contain a char\* pointer to the name of +the string, eg. "WAV (Microsoft 16 bit PCM)". The extension field will contain +the most commonly used file extension for that file type. + +## SFC_GET_FORMAT_INFO + +Retrieve information about a major or subtype format. + +### Parameters + +sndfile +: Not used. + +cmd +: SFC_GET_FORMAT_INFO + +data +: a pointer to an SF_FORMAT_INFO struct + +datasize +: sizeof (SF_FORMAT_INFO) + +The `SF_FORMAT_INFO` struct is defined in \ as: + +```c +typedef struct +{ int format ; + const char *name ; + const char *extension ; +} SF_FORMAT_INFO ; +``` + +When `sf_command()` is called with `SF_GET_FORMAT_INFO`, the format field is +examined and if (format & `SF_FORMAT_TYPEMASK`) is a valid format then the +struct is filled in with information about the given major type. If (format & +`SF_FORMAT_TYPEMASK`) is FALSE and (format & `SF_FORMAT_SUBMASK`) is a valid +subtype format then the struct is filled in with information about the given +subtype. + +### Examples + +```c +SF_FORMAT_INFO format_info ; + +format_info.format = SF_FORMAT_WAV ; +sf_command (sndfile, SFC_GET_FORMAT_INFO, &format_info, sizeof (format_info)) ; +printf ("%08x %s %s\n", format_info.format, format_info.name, format_info.extension) ; + +format_info.format = SF_FORMAT_ULAW ; +sf_command (sndfile, SFC_GET_FORMAT_INFO, &format_info, sizeof (format_info)) ; +printf ("%08x %s\n", format_info.format, format_info.name) ; +``` + +### Return value + +0 on success and non-zero otherwise. + +## SFC_GET_FORMAT_MAJOR_COUNT + +Retrieve the number of major formats. + +### Parameters + +sndfile +: Not used. + +cmd +: SFC_GET_FORMAT_MAJOR_COUNT + +data +: a pointer to an int + +datasize +: sizeof (int) + +### Examples + +```c +int count ; +sf_command (sndfile, SFC_GET_FORMAT_MAJOR_COUNT, &count, sizeof (int)) ; +``` + +### Return value + +0. + +## SFC_GET_FORMAT_MAJOR + +Retrieve information about a major format type. + +### Parameters + +sndfile +: Not used. + +cmd +: SFC_GET_FORMAT_MAJOR + +data +: a pointer to an SF_FORMAT_INFO struct + +datasize +: sizeof (SF_FORMAT_INFO) + +### Examples + +```c +SF_FORMAT_INFO format_info ; +int k, count ; + +sf_command (sndfile, SFC_GET_FORMAT_MAJOR_COUNT, &count, sizeof (int)) ; + +for (k = 0 ; k < count ; k++) +{ format_info.format = k ; + sf_command (sndfile, SFC_GET_FORMAT_MAJOR, &format_info, sizeof (format_info)) ; + printf ("%08x %s %s\n", format_info.format, format_info.name, format_info.extension) ; + } ; +``` + +For a more comprehensive example, see the program `list_formats.c` in the +`examples/` directory of the libsndfile source code distribution. + +### Return value + +0 on success and non-zero otherwise. + +The value of the format field will be one of the major format identifiers such +as `SF_FORMAT_WAV` or `SF_FORMAT`_AIFF. The name field will contain a char\* +pointer to the name of the string, eg. "WAV (Microsoft)". The extension field +will contain the most commonly used file extension for that file type. + +## SFC_GET_FORMAT_SUBTYPE_COUNT + +Retrieve the number of subformats. + +### Parameters + +sndfile +: Not used. + +cmd +: SFC_GET_FORMAT_SUBTYPE_COUNT + +data +: a pointer to an int + +datasize +: sizeof (int) + +### Examples + +```c +int count ; +sf_command (sndfile, SFC_GET_FORMAT_SUBTYPE_COUNT, &count, sizeof (int)) ; +``` + +### Return value + +Returns zero. + +## SFC_GET_FORMAT_SUBTYPE + +Enumerate the subtypes (this function does not translate a subtype into a string +describing that subtype). A typical use case might be retrieving a string +description of all subtypes so that a dialog box can be filled in. + +### Parameters + +sndfile +: Not used. + +cmd +: SFC_GET_FORMAT_SUBTYPE + +data +: a pointer to an SF_FORMAT_INFO struct + +datasize +: sizeof (SF_FORMAT_INFO) + +### Examples + +Example 1: Retrieve all sybtypes supported by the WAV format. + +```c +SF_FORMAT_INFO format_info ; +int k, count ; + +sf_command (sndfile, SFC_GET_FORMAT_SUBTYPE_COUNT, &count, sizeof (int)) ; + +for (k = 0 ; k < count ; k++) +{ format_info.format = k ; + sf_command (sndfile, SFC_GET_FORMAT_SUBTYPE, &format_info, sizeof (format_info)) ; + if (! sf_format_check (format_info.format | SF_FORMAT_WAV)) + continue ; + printf ("%08x %s\n", format_info.format, format_info.name) ; + } ; +``` + +Example 2: Print a string describing the `SF_FORMAT_PCM_16` subtype. + +```c +SF_FORMAT_INFO format_info ; +int k, count ; + +sf_command (sndfile, SFC_GET_FORMAT_SUBTYPE_COUNT, &count, sizeof (int)) ; + +for (k = 0 ; k < count ; k++) +{ format_info.format = k ; + sf_command (sndfile, SFC_GET_FORMAT_SUBTYPE, &format_info, sizeof (format_info)) ; + if (format_info.format == SF_FORMAT_PCM_16) + { printf ("%08x %s\n", format_info.format, format_info.name) ; + break ; + } ; + } ; +``` + +For a more comprehensive example, see the program `list_formats.c` in the +`examples/` directory of the libsndfile source code distribution. + +### Return value + +0 on success and non-zero otherwise. + +The value of the format field will be one of the major format identifiers such +as `SF_FORMAT_WAV` or `SF_FORMAT_AIFF`. The name field will contain a char\* +pointer to the name of the string; for instance "WAV (Microsoft)" or "AIFF +(Apple/SGI)". The extension field will be a NULL pointer. + +## SFC_SET_ADD_PEAK_CHUNK + +By default, WAV and AIFF files which contain floating point data (subtype +`SF_FORMAT_FLOAT` or `SF_FORMAT_DOUBLE`) have a PEAK chunk. By using this +command, the addition of a PEAK chunk can be turned on or off. + +**Note**: This call must be made before any data is written to the file. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_SET_ADD_PEAK_CHUNK + +data +: Not used (should be NULL) + +datasize +: TRUE or FALSE. + +### Examples + +```c +/* Turn on the PEAK chunk. */ +sf_command (sndfile, SFC_SET_ADD_PEAK_CHUNK, NULL, SF_TRUE) ; + +/* Turn off the PEAK chunk. */ +sf_command (sndfile, SFC_SET_ADD_PEAK_CHUNK, NULL, SF_FALSE) ; +``` + +### Return value + +Returns SF_TRUE if the peak chunk will be written after this call. Returns +SF_FALSE if the peak chunk will not be written after this call. + +## SFC_UPDATE_HEADER_NOW + +The header of an audio file is normally written by libsndfile when the file is +closed using [**sf_close()**](api.md#file-close-function). + +There are however situations where large files are being generated and it would +be nice to have valid data in the header before the file is complete. Using this +command will update the file header to reflect the amount of data written to the +file so far. Other programs opening the file for read (before any more data is +written) will then read a valid sound file header. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_UPDATE_HEADER_NOW + +data +: Not used (should be NULL) + +datasize +: Not used. + +### Examples + +```c +/* Update the header now. */ +sf_command (sndfile, SFC_UPDATE_HEADER_NOW, NULL, 0) ; +``` + +### Return value + +Returns zero. + +## SFC_SET_UPDATE_HEADER_AUTO + +Similar to `SFC_UPDATE_HEADER_NOW` but updates the header at the end of every +call to the [sf_write\*](api.md#write) functions. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_SET_UPDATE_HEADER_AUTO + +data +: Not used (should be NULL) + +datasize +: `SF_TRUE` or `SF_FALSE` + +### Examples + +```c +/* Turn on auto header update. */ +sf_command (sndfile, SFC_SET_UPDATE_HEADER_AUTO, NULL, SF_TRUE) ; + +/* Turn off auto header update. */ +sf_command (sndfile, SFC_SET_UPDATE_HEADER_AUTO, NULL, SF_FALSE) ; +``` + +### Return value + +TRUE if auto update header is now on; FALSE otherwise. + +## SFC_FILE_TRUNCATE + +Truncate a file that was opened for write or read/write. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_FILE_TRUNCATE + +data +: A pointer to an sf_count_t. + +datasize +: sizeof (sf_count_t) + +Truncate the file to the number of frames specified by the sf_count_t pointed to +by data. After this command, both the read and the write pointer will be at the +new end of the file. This command will fail (returning non-zero) if the +requested truncate position is beyond the end of the file. + +### Examples + +```c +/* Truncate the file to a length of 20 frames. */ +sf_count_t frames = 20 ; +sf_command (sndfile, SFC_FILE_TRUNCATE, &frames, sizeof (frames)) ; +``` + +### Return value + +Zero on success, non-zero otherwise. + +## SFC_SET_RAW_START_OFFSET + +Change the data start offset for files opened up as `SF_FORMAT_RAW`. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_SET_RAW_START_OFFSET + +data +: A pointer to an sf_count_t. + +datasize +: sizeof (sf_count_t) + +For a file opened as format `SF_FORMAT_RAW`, set the data offset to the value +given by `data`. + +### Examples + +```c +/* Reset the data offset to 5 bytes from the start of the file. */ +sf_count_t offset = 5 ; +sf_command (sndfile, SFC_SET_RAW_START_OFFSET, &offset, sizeof (offset)) ; +``` + +### Return value + +Zero on success, non-zero otherwise. + +## SFC_SET_CLIPPING + +Turn on/off automatic clipping when doing floating point to integer conversion. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_SET_CLIPPING + +data +: NULL + +datasize +: SF_TRUE or SF_FALSE. + +Turn on (datasize == SF_TRUE) or off (datasize == SF_FALSE) clipping. + +### Examples + +```c +sf_command (sndfile, SFC_SET_CLIPPING, NULL, SF_TRUE) ; +``` + +### Return value + +Clipping mode (SF_TRUE or SF_FALSE). + +## SFC_GET_CLIPPING + +Turn on/off automatic clipping when doing floating point to integer conversion. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_GET_CLIPPING + +data +: NULL + +datasize +: 0 + +Retrieve the current cliiping setting. + +### Examples + +```c +sf_command (sndfile, SFC_GET_CLIPPING, NULL, 0) ; +``` + +### Return value + +Clipping mode (SF_TRUE or SF_FALSE). + +## SFC_GET_EMBED_FILE_INFO + +Get the file offset and file length of a file enbedded within another larger +file. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_GET_EMBED_FILE_INFO + +data +: a pointer to an SF_EMBED_FILE_INFO struct + +datasize +: sizeof (SF_EMBED_FILE_INFO) + +The `SF_EMBED_FILE_INFO` struct is defined in *sndfile.h* as: + +```c +typedef struct +{ sf_count_t offset ; + sf_count_t length ; +} SF_EMBED_FILE_INFO ; +``` + +### Return value + +0 on success and non-zero otherwise. + +The value of the offset field of the `SF_EMBED_FILE_INFO` struct will be the +offsets in bytes from the start of the outer file to the start of the audio +file. The value of the offset field of the `SF_EMBED_FILE_INFO` struct will be +the length in bytes of the embedded file. + +## SFC_WAVEX_GET_AMBISONIC + +Test if the current file has the GUID of a WAVEX file for any of the Ambisonic +formats. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_WAVEX_GET_AMBISONIC + +data +: NULL + +datasize +: 0 + +The Ambisonic WAVEX formats are defined here: +. + +### Return value + +`SF_AMBISONIC_NONE(0x40)` or `SF_AMBISONIC_B_FORMAT(0x41)` or zero if the file +format does not support ambisonic formats. + +## SFC_WAVEX_SET_AMBISONIC + +Set the GUID of a new WAVEX file to indicate an Ambisonics format. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_WAVEX_SET_AMBISONIC + +data +: NULL + +datasize +: SF_AMBISONIC_NONE or SF_AMBISONIC_B_FORMAT + +Turn on (`SF_AMBISONIC_B_FORMAT(0x41)`) or off (`SF_AMBISONIC_NONE(0x40)`) +encoding. This command is currently only supported for files with +`SF_FORMAT_WAVEX` format. + +The Ambisonic WAVEX formats are defined here: + +. + +### Return value + +Return the ambisonic value that has just been set or zero if the +file format does not support ambisonic encoding. + +## SFC_SET_VBR_ENCODING_QUALITY + +Set the Variable Bit Rate encoding quality. The encoding quality value +should be between 0.0 (lowest quality) and 1.0 (highest quality). +Currently this command is only implemented for FLAC and Ogg/Vorbis files. +It has no effect on un-compressed file formats. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_SET_VBR_ENCODING_QUALITY + +data +: A pointer to a double value + +datasize +: sizeof (double) + +The command must be sent before any audio data is written to the file. + +### Return value + +SF_TRUE if VBR encoding quality was set. SF_FALSE otherwise. + +## SFC_SET_OGG_PAGE_LATENCY_MS + +Set page latency for Ogg Opus file in milliseconds. The value should be between +50.0 and 1600.0. This command is only implemented for Ogg Opus files. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_SET_OGG_PAGE_LATENCY_MS + +data +: A pointer to a double value + +datasize +: sizeof (double) + +### Return value + +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 +compression level) and 1.0 (highest compression level). Currently this command is +only implemented for FLAC and Ogg/Vorbis files. It has no effect on +uncompressed file formats. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_SET_COMPRESSION_LEVEL + +data +: A pointer to a double value + +datasize +: sizeof (double) + +The command must be sent before any audio data is written to the file. + +### Return value + +SF_TRUE if compression level was set. SF_FALSE otherwise. + +## SFC_RAW_DATA_NEEDS_ENDSWAP + +Determine if raw data read using [sf_read_raw()](api.md#raw) needs to be end +swapped on the host CPU. + +For instance, will return SF_TRUE on when reading WAV containing +`SF_FORMAT_PCM_16` data on a big endian machine and `SF_FALSE` on a +little endian machine. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_RAW_DATA_NEEDS_ENDSWAP + +data +: NULL + +datasize +: 0 + +### Return value + +`SF_TRUE` or `SF_FALSE`. + +## SFC_GET_BROADCAST_INFO + +Retrieve the Broadcast Extension Chunk from WAV (and related) files. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_GET_BROADCAST_INFO + +data +: a pointer to an SF_BROADCAST_INFO struct + +datasize +: sizeof (SF_BROADCAST_INFO) + +The SF_BROADCAST_INFO struct is defined in *sndfile.h* as: + +```c +typedef struct +{ char description [256] ; + char originator [32] ; + char originator_reference [32] ; + char origination_date [10] ; + char origination_time [8] ; + unsigned int time_reference_low ; + unsigned int time_reference_high ; + short version ; + char umid [64] ; + char reserved [190] ; + unsigned int coding_history_size ; + char coding_history [256] ; +} SF_BROADCAST_INFO ; +``` + +### Return value + +`SF_TRUE` if the file contained a Broadcast Extension chunk or `SF_FALSE` +otherwise. + +## SFC_SET_BROADCAST_INFO + +Set the Broadcast Extension Chunk for WAV (and related) files. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_SET_BROADCAST_INFO + +data +: a pointer to an SF_BROADCAST_INFO struct + +datasize +: sizeof (SF_BROADCAST_INFO) + +### Return value + +`SF_TRUE` if setting the Broadcast Extension chunk was successful and `SF_FALSE` +otherwise. + +## SFC_GET_CHANNEL_MAP_INFO + +Retrieve the channel map contained in an AIFF or CAF Channel Layout chunk. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_GET_CHANNEL_MAP_INFO + +data +: a pointer to an array of int, the same size as the number of channels in the +file + +datasize +: number of channels * sizeof (int) + +Channel map positions are defined in an enum in *sndfile.h*: + +| Name | Value | Description | +|:-------------------------------------|:------|:------------------------------------------------------------------| +| SF_CHANNEL_MAP_INVALID | 0 | | +| SF_CHANNEL_MAP_MONO | 1 | | +| SF_CHANNEL_MAP_LEFT | 2 | Apple calls this 'Left' | +| SF_CHANNEL_MAP_RIGHT | 3 | Apple calls this 'Right' | +| SF_CHANNEL_MAP_CENTER | 4 | Apple calls this 'Center' | +| SF_CHANNEL_MAP_FRONT_LEFT | 5 | | +| SF_CHANNEL_MAP_FRONT_RIGHT | 6 | | +| SF_CHANNEL_MAP_FRONT_CENTER | 7 | | +| SF_CHANNEL_MAP_REAR_CENTER | 8 | Apple calls this 'Center Surround', Msft calls this 'Back Center' | +| SF_CHANNEL_MAP_REAR_LEFT | 9 | Apple calls this 'Left Surround', Msft calls this 'Back Left' | +| SF_CHANNEL_MAP_REAR_RIGHT | 10 | Apple calls this 'Right Surround', Msft calls this 'Back Right' | +| SF_CHANNEL_MAP_LFE | 11 | Apple calls this 'LFEScreen', Msft calls this 'Low Frequency' | +| SF_CHANNEL_MAP_FRONT_LEFT_OF_CENTER | 12 | Apple calls this 'Left Center' | +| SF_CHANNEL_MAP_FRONT_RIGHT_OF_CENTER | 13 | Apple calls this 'Right Center' | +| SF_CHANNEL_MAP_SIDE_LEFT | 14 | Apple calls this 'Left Surround Direct' | +| SF_CHANNEL_MAP_SIDE_RIGHT | 15 | Apple calls this 'Right Surround Direct' | +| SF_CHANNEL_MAP_TOP_CENTER | 16 | Apple calls this 'Top Center Surround' | +| SF_CHANNEL_MAP_TOP_FRONT_LEFT | 17 | Apple calls this 'Vertical Height Left' | +| SF_CHANNEL_MAP_TOP_FRONT_RIGHT | 18 | Apple calls this 'Vertical Height Right' | +| SF_CHANNEL_MAP_TOP_FRONT_CENTER | 19 | Apple calls this 'Vertical Height Center' | +| SF_CHANNEL_MAP_TOP_REAR_LEFT | 20 | Apple and MS call this 'Top Back Left' | +| SF_CHANNEL_MAP_TOP_REAR_RIGHT | 21 | Apple and MS call this 'Top Back Right' | +| SF_CHANNEL_MAP_TOP_REAR_CENTER | 22 | Apple and MS call this 'Top Back Center' | +| SF_CHANNEL_MAP_AMBISONIC_B_W | 23 | | +| SF_CHANNEL_MAP_AMBISONIC_B_X | 24 | | +| SF_CHANNEL_MAP_AMBISONIC_B_Y | 25 | | +| SF_CHANNEL_MAP_AMBISONIC_B_Z | 26 | | +| SF_CHANNEL_MAP_MAX | 27 | | + +### Return value + +`SF_TRUE` if the file contained a Channel Layout chunk or `SF_FALSE` otherwise. + +## SFC_SET_CHANNEL_MAP_INFO + +Set the channel map contained in an AIFF or CAF Channel Layout chunk. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_SET_CHANNEL_MAP_INFO + +data +: a pointer to an array of int, the same size as the number of channels in the +file + +datasize +: number of channels * sizeof (int) + +### Return value + +`SF_TRUE` if setting the Channel Layout chunk was successful and `SF_FALSE` +otherwise. + +## SFC_GET_CART_INFO + +Retrieve the Cart Chunk from WAV (and related) files. Based on AES46 standard +for CartChunk (see [CartChunk.org](http://www.cartchunk.org/) for more +information. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_GET_CART_INFO + +data +: a pointer to an SF_CART_INFO struct + +datasize +: sizeof (SF_CART_INFO) + +The SF_CART_INFO struct is defined in *sndfile.h* as: + +```c +#define SF_CART_INFO_VAR(p_tag_text_size) \ + struct + { char version [4] ; + char title [64] ; + char artist [64] ; + char cut_id [64] ; + char client_id [64] ; + char category [64] ; + char classification [64] ; + char out_cue [64] ; + char start_date [10] ; + char start_time [8] ; + char end_date [10] ; + char end_time [8] ; + char producer_app_id [64] ; + char producer_app_version [64] ; + char user_def [64] ; + long level_reference ; + SF_CART_TIMER post_timers [8] ; + char reserved [276] ; + char url [1024] ; + unsigned int tag_text_size ; + char tag_text[p_tag_text_size] ; + } +``` + +### Return value + +`SF_TRUE` if the file contained a Cart chunk or `SF_FALSE` otherwise. + +## SFC_SET_CART_INFO + +Set the Cart Chunk for WAV (and related) files. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_SET_CART_INFO + +data +: a pointer to an SF_CART_INFO struct + +datasize +: sizeof (SF_CART_INFO) + +### Return value + +SF_TRUE if setting the Cart chunk was successful and SF_FALSE otherwise. + +## SFC_GET_LOOP_INFO + +Retrieve loop information for file including time signature, length in beats and +original MIDI base note + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_GET_LOOP_INFO + +data +: a pointer to an SF_LOOP_INFO struct + +datasize +: sizeof (SF_LOOP_INFO) + +The SF_LOOP_INFO struct is defined in *sndfile.h* as: + +```c +typedef struct +{ short time_sig_num ; /* any positive integer > 0 */ + short time_sig_den ; /* any positive power of 2 > 0 */ + int loop_mode ; /* see SF_LOOP enum */ + + int num_beats ; /* this is NOT the amount of quarter notes !!!*/ + /* a full bar of 4/4 is 4 beats */ + /* a full bar of 7/8 is 7 beats */ + + float bpm ; /* suggestion, as it can be calculated using other fields:*/ + /* file's length, file's sampleRate and our time_sig_den*/ + /* -> bpms are always the amount of _quarter notes_ per minute */ + + int root_key ; /* MIDI note, or -1 for None */ + int future [6] ; +} SF_LOOP_INFO ; +``` + +### Examples + +```c +SF_LOOP_INFO loop; +sf_command (sndfile, SFC_GET_LOOP_INFO, &loop, sizeof (loop)) ; +``` + +### Return value + +`SF_TRUE` if the file header contains loop information for the file, `SF_FALSE` +otherwise. + +## SFC_GET_INSTRUMENT + +Retrieve instrument information from file including MIDI base note, keyboard +mapping and looping information (start/stop and mode). + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_GET_INSTRUMENT + +data +: a pointer to an SF_INSTRUMENT struct + +datasize +: sizeof (SF_INSTRUMENT) + +The `SF_INSTRUMENT` struct is defined in *sndfile.h* as: + +```c +typedef struct +{ int gain ; + char basenote, detune ; + char velocity_lo, velocity_hi ; + char key_lo, key_hi ; + int loop_count ; + + struct + { int mode ; + unsigned int start ; + unsigned int end ; + unsigned int count ; + } loops [16] ; /* make variable in a sensible way */ +} SF_INSTRUMENT ; +``` + +`mode` values are defined as: + +| Name | Value | Description | +|:--------------------|:------|:------------| +| SF_LOOP_NONE | 800 | | +| SF_LOOP_FORWARD | 801 | | +| SF_LOOP_BACKWARD | 802 | | +| SF_LOOP_ALTERNATING | 803 | | + +### Examples + +```c +SF_INSTRUMENT inst ; +sf_command (sndfile, SFC_GET_INSTRUMENT, &inst, sizeof (inst)) ; +``` + +### Return value + +`SF_TRUE` if the file header contains instrument information for the file, +`SF_FALSE` otherwise. + +## SFC_SET_INSTRUMENT + +Set the instrument information for the file. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_SET_INSTRUMENT + +data +: a pointer to an SF_INSTRUMENT struct + +datasize +: sizeof (SF_INSTRUMENT) + +### Examples + +```c +SF_INSTRUMENT inst ; +sf_command (sndfile, SFC_SET_INSTRUMENT, &inst, sizeof (inst)) ; +``` + +### Return value + +`SF_TRUE` if the file header contains instrument information for the file, +`SF_FALSE` otherwise. + +## SFC_GET_CUE_COUNT + +Retrieve the number of cue markers available for retrieval using the +[SFC_GET_CUE](#sfc_get_cue) command. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_GET_CUE_COUNT + +data +: a pointer to a uint32_t + +datasize +: sizeof (uint32_t) + +### Examples + +```c +uint32_t cue_count ; +sf_command (sndfile, SFC_GET_CUE_COUNT, &cue_count, sizeof (cue_count)) ; +``` + +### Return value + +`SF_TRUE` if the file header contains cue marker information for the file, +`SF_FALSE` otherwise. + +## SFC_GET_CUE + +Retrieve cue marker information from file. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_GET_CUE + +data +: a pointer to an SF_CUES struct + +datasize +: sizeof (SF_CUES) + +The SF_CUES struct is defined in *sndfile.h* as: + +```c +typedef struct +{ int cue_count ; + + struct + { int32_t indx ; + uint32_t position ; + int32_t fcc_chunk ; + int32_t chunk_start ; + int32_t block_start ; + uint32_t sample_offset ; + char name [256] ; + } cue_points [100] ; +} SF_CUES ; +``` + +There is also an SF_CUES_VAR \#define that allows reading/writing more than 100 +cue markers. + +### Examples + +```c +SF_CUES cues ; +sf_command (sndfile, SFC_GET_CUE, &cues, sizeof (cues)) ; +``` + +### Return value + +`SF_TRUE` if the file header contains cue marker information for the file, +`SF_FALSE` otherwise. + +## SFC_SET_CUE + +Set the cue marker information for the file. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_SET_CUE + +data +: a pointer to an SF_CUES struct + +datasize +: sizeof (SF_CUES) + +### Examples + +```c +SF_CUES cues ; +sf_command (sndfile, SFC_SET_CUE, &cues, sizeof (cues)) ; +``` + +### Return value + +`SF_TRUE` if the file header contains cue marker information for the file, +`SF_FALSE` otherwise. + +## SFC_RF64_AUTO_DOWNGRADE + +Enable auto downgrade from RF64 to WAV. + +The EBU recommendation is that when writing RF64 files and the resulting file is +less than 4Gig in size, it should be downgraded to a WAV file (WAV files have a +maximum size of 4Gig). libsndfile doesn't follow the EBU recommendations +exactly, mainly because the test suite needs to be able test reading/writing +RF64 files without having to generate files larger than 4 gigabytes. + +Note: This command should be issued before the first bit of audio data has been +written to the file. Calling this command after audio data has been written will +return the current value of this setting, but will not allow it to be changed. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_RF64_AUTO_DOWNGRADE + +data +: NULL + +datasize +: SF_TRUE or SF_FALSE + +### Examples + +```c +/* Enable auto downgrade on file close. */ +sf_command (sndfile, SFC_RF64_AUTO_DOWNGRADE, NULL, SF_TRUE) ; +``` + +### Return value + +Returns `SF_TRUE` if `SFC_RF64_AUTO_DOWNGRADE` is set and `SF_FALSE` otherwise. + +## SFC_GET_ORIGINAL_SAMPLERATE + +Get original samplerate metadata. + +The Opus audio codec stores audio data independent of samplerate, but only +supports encoding or decoding at 8000Hz, 12000Hz, 16000Hz, 24000Hz or 48000Hz. +Opus includes a header field to record the original source input samplerate, and +a samplerate converter may be used if needed. + +This command gets the original samplerate header field. It does not enable any +(non-existent) samplerate conversion, nor change the current decoder samplerate. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_GET_ORIGINAL_SAMPLERATE + +data +: pointer to an integer + +datasize +: sizeof (int) + +### Examples + +```c +/* Get the original sample rate */ +int original_samplerate ; +sf_command (sndfile, SFC_GET_ORIGINAL_SAMPLERATE, &original_samplerate, sizeof (original_samplerate)) ; +``` + +### Return value + +Returns `SF_TRUE` on success, `SF_FALSE` otherwise. + +The passed integer is set to the value of the original samplerate. + +## SFC_SET_ORIGINAL_SAMPLERATE + +Set original samplerate metadata. + +The Opus audio codec stores audio data independent of samplerate, but only +supports encoding or decoding at 8000Hz, 12000Hz, 16000Hz, 24000Hz or 48000Hz. +Opus includes a header field to record the original source input samplerate, and +a samplerate converter may be used if needed. + +When writing an Opus file this command sets the original samplerate header field +to the provided value, which is then stored in the file. This has no effect on +the current encoder samplerate. + +When reading an Opus file this command overrides the original samplerate value +as read from the file. libsndfile uses this value to choose what samplerate to +decode at, rounding up to the nearest valid Opus samplerate. After a successful +call, the file samplerate and frames count may have changed. + +Note: This command should be issued before the first bit of audio data has been +read from or written to the file. + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_SET_ORIGINAL_SAMPLERATE + +data +: pointer to an integer + +datasize +: sizeof (int) + +### Examples + +```c +/* Store the original sample rate as 44100 */ +int original_samplerate 44100; +sf_command (sndfile, SFC_SET_ORIGINAL_SAMPLERATE, &original_samplerate, sizeof (input_samplerate)) ; +``` + +### Return value + +Returns SF_TRUE on success, SF_FALSE otherwise. + +On write, can only succeed if no data has been written. On read, if successful, +[SFC_GET_CURRENT_SF_INFO](#sfc_get_current_sf_info) should be called to +determine the new frames count and samplerate + +## SFC_GET_BITRATE_MODE + +Get bitrate mode. + +The bitrate mode is one of: + +| Name | Value | Description | +|:-------------------------|:------|:------------------| +| SF_BITRATE_MODE_CONSTANT | 800 | Constant bitrate. | +| SF_BITRATE_MODE_AVERAGE | 801 | Average bitrate. | +| SF_BITRATE_MODE_VARIABLE | 802 | Variable bitrate. | + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_GET_BITRATE_MODE + +data +: NULL + +datasize +: anything + +### Return value + +Returns one of `SF_BITRATE_MODE_XXX` on success, `-1` otherwise. + +## SFC_SET_BITRATE_MODE + +Set bitrate mode. + +The bitrate mode is one of: + +| Name | Value | Description | +|:-------------------------|:------|:------------------| +| SF_BITRATE_MODE_CONSTANT | 800 | Constant bitrate. | +| SF_BITRATE_MODE_AVERAGE | 801 | Average bitrate. | +| SF_BITRATE_MODE_VARIABLE | 802 | Variable bitrate. | + +### Parameters + +sndfile +: A valid SNDFILE* pointer + +cmd +: SFC_SET_BITRATE_MODE + +data +: pointer to an integer + +datasize +: sizeof (int) + +### Return value + +Returns `SF_TRUE` on success, `SF_FALSE` otherwise. diff --git a/extern/libsndfile-modified/docs/development.md b/extern/libsndfile-modified/docs/development.md new file mode 100644 index 000000000..7d417ea6d --- /dev/null +++ b/extern/libsndfile-modified/docs/development.md @@ -0,0 +1,18 @@ +--- +layout: page +--- + +# libsndfile Development + +libsndfile is being developed by a small community of users and hackers. People +interested in helping can raise an issue on Github. + +The main repository can be found on Github: + + + +and includes [instructions](https://github.com/libsndfile/libsndfile/blob/master/README.md) +on how to build libsndfile from the Git repo. + +If you are interested in how to add a new format to a libsndfile, you may find +this [FAQ](new_file_type_howto.md) helpful. diff --git a/extern/libsndfile-modified/docs/donate.md b/extern/libsndfile-modified/docs/donate.md new file mode 100644 index 000000000..dd10769c5 --- /dev/null +++ b/extern/libsndfile-modified/docs/donate.md @@ -0,0 +1,60 @@ +--- +layout: page +title: libsndfile : donate. +--- + +{% include logo.html %} + +Dear libsndfile user, + +This library was developed on Linux for Linux. I am not a Windows user and +maintaining this library for Windows costs me significant amounts of time above +and beyond the time taken to make it work on Linux and Unix-like systems. + +I therefore ask Windows users of libsndfile to donate to ensure that +libsndfile's support for Windows continues. As long as donations continue to +flow in at a decentrate, I will continue to release precompiled Windows binaries +in sync with the Linux/Unix version. If donations are poor, support for windows +will fall behind. + +You are free to donate any amount you chose. As a guideline: + +* If you are simply a user of libsndfile that would like to ensure that the + development of libsndfile continues, a donation of $10US would be more than + adequate. +* If you are shareware author that distributes libsndfile with your app and + makes more than $1000 a year from your shareware, a one off donation of $50 + would be appropriate. +* If your company is a commercial software house that distributes one or more + products that ship with libsndfile, a donation of $100 every second or third + year would be appropriate. + +Donations can be made in Bitcoin to the Bitcoin address +**15hVWemFiH6DLJ22SBYPk9b4fgWtxBEvfQ** which can be verified by checking the +following GPG signature. + + -----BEGIN PGP SIGNED MESSAGE----- + Hash: SHA256 + + libsndfile Bitcoin address : 15hVWemFiH6DLJ22SBYPk9b4fgWtxBEvfQ + -----BEGIN PGP SIGNATURE----- + Version: GnuPG v1.4.12 (GNU/Linux) + + iQIcBAEBCAAGBQJSK7MUAAoJEEXYQ7zIiotIgXEP/R8hy65tlV7TiPw9bY9BklXS + /Vl8FU2RhDkBt61ZmxbfDTybyQ5Vce/3wWph15L4RvpoX1OyeintQFmwwuPjOGiq + eIz0nT9vDorG37Xdo5NZNBu9Tp1Od9MNtxFaAsRWFrDfvKEKljBHrcfM972cYrAp + DaFd0Ik+bHKom9iQXFB7TFd0w2V4uszVMQDUGqb/vRNeRURZS7ypeMNwc8tZyTKR + waEGMTa5sxxRjs7MqGRxSovnFT7JV3TNfdkBInUliIR/XvrudFR9J4Fiv+8Dk9P8 + WNjm6uFxvgIqiu1G9bjrwwr+DsBju93ljGNcZoayAKw5vwbX6KTcCbc31k9dP8Hf + p6YdmPlZVKZmva+P3nLSJBTlxNu24Jm+ha+ZM/svDXTaPFWC8l5FP17kK0Bj8wCq + N7pDz6RchEn10u+HdhfT1XiUjxj0zNXrr0GGj9apjl0RlT0O49eBttV0oXIdBRLi + nTEaOWITpCgu7ggw1kWXHIWEncuiaSuJy/iH8PgNepWVj/6PxQRMrTqG4ux2Snk8 + Ua4vO8YHLMZX/XvSUS7eMtgfM7AO6YjJ/ac9bQif9bh6LsYEVVklysMUin6ZRS7Z + Cms23FnqeQKtJOzdvqSJiV06lK6fP+tYdM4WSYn+AfL4IfYl2v48xXVU8XOOK9BH + bJPKMDcz1ZvfYtX5mSW1 + =WXGB + -----END PGP SIGNATURE----- + +Thanks and regards, +Erik de Castro Lopo +Main libsndfile author and maintainer diff --git a/extern/libsndfile-modified/docs/embedded_files.md b/extern/libsndfile-modified/docs/embedded_files.md new file mode 100644 index 000000000..e55f2ede8 --- /dev/null +++ b/extern/libsndfile-modified/docs/embedded_files.md @@ -0,0 +1,21 @@ +--- +layout: page +--- + +# Embedded Sound Files + +By using the open SNDFILE with a file descriptor function: + + SNDFILE* sf_open_fd (int fd, int mode, SF_INFO *sfinfo, int close_desc) ; + +it is possible to open sound files embedded within larger files. There are +however a couple of caveats: + +* Read/Write mode (SFM_RDWR) is not supported. +* Writing of embedded files is only supported at the end of the file. +* Reading of embedded files is only supported at file offsets greater than zero. +* Not all file formats are supported (currently only WAV, AIFF and AU). + +The test program **multi_file_test.c** in the **tests/** directory of the source +code tarball shows how this functionality is used to read and write embedded +files. diff --git a/extern/libsndfile-modified/docs/formats.md b/extern/libsndfile-modified/docs/formats.md new file mode 100644 index 000000000..1d96737d0 --- /dev/null +++ b/extern/libsndfile-modified/docs/formats.md @@ -0,0 +1,53 @@ +--- +layout: page +title: libsndfile: Supported formats +--- + +# libsndfile : Supported formats + +The following table lists the file formats and encodings that libsndfile can +read and write. The file formats are arranged across the top and encodings along +the left edge. + +{:.formats-table} +| | Microsoft WAV | SGI / Apple AIFF / AIFC |Sun / DEC / NeXT AU / SND | Headerless RAW | Paris Audio File PAF | Commodore Amiga IFF / SVX | Sphere Nist WAV | IRCAM SF | Creative VOC | Soundforge W64 | GNU Octave 2.0 MAT4 | GNU Octave 2.1 MAT5 | Portable Voice Format PVF | Fasttracker 2 XI | HMM Tool Kit HTK | Apple CAF | Sound Designer II SD2 | Free Lossless Audio Codec FLAC | +|:-------------------|:-------------:|:-----------------------:|:------------------------:|:--------------:|:--------------------:|:-------------------------:|:---------------:|:--------:|:------------:|:--------------:|:-------------------:|:-------------------:|:-------------------------:|:----------------:|:----------------:|:---------:|:---------------------:|:------------------------------:| +| Unsigned 8 bit PCM | R/W | R/W | | R/W | | | | | R/W | R/W | | R/W | | | | | | | +| Signed 8 bit PCM | | R/W | R/W | R/W | R/W | R/W | R/W | | | | | | R/W | | | R/W | R/W | R/W | +| Signed 16 bit PCM | R/W | R/W | R/W | R/W | R/W | R/W | R/W | R/W | R/W | R/W | R/W | R/W | R/W | | R/W | R/W | R/W | R/W | +| Signed 24 bit PCM | R/W | R/W | R/W | R/W | R/W | | R/W | | | R/W | | | | | | R/W | R/W | R/W | +| Signed 32 bit PCM | R/W | R/W | R/W | R/W | | | R/W | R/W | | R/W | R/W | R/W | R/W | | | R/W | | | +| 32 bit float | R/W | R/W | R/W | R/W | | | | R/W | | R/W | R/W | R/W | | | | R/W | | | +| 64 bit double | R/W | R/W | R/W | R/W | | | | | | R/W | R/W | R/W | | | | R/W | | | +| u-law encoding | R/W | R/W | R/W | R/W | | | R/W | R/W | R/W | R/W | | | | | | R/W | | | +| A-law encoding | R/W | R/W | R/W | R/W | | | R/W | R/W | R/W | R/W | | | | | | R/W | | | +| IMA ADPCM | R/W | | | | | | | | | R/W | | | | | | | | | +| MS ADPCM | R/W | | | | | | | | | R/W | | | | | | | | | +| GSM 6.10 | R/W | R/W | | R/W | | | | | | R/W | | | | | | | | | +| G721 ADPCM 32kbps | R/W | | R/W | | | | | | | | | | | | | | | | +| G723 ADPCM 24kbps | | | R/W | | | | | | | | | | | | | | | | +| G723 ADPCM 40kbps | | | R/W | | | | | | | | | | | | | | | | +| 12 bit DWVW | | R/W | | R/W | | | | | | | | | | | | | | | +| 16 bit DWVW | | R/W | | R/W | | | | | | | | | | | | | | | +| 24 bit DWVW | | R/W | | R/W | | | | | | | | | | | | | | | +| Ok Dialogic ADPCM | | | | R/W | | | | | | | | | | | | | | | +| 8 bit DPCM | | | | | | | | | | | | | | R/W | | | | | +| 16 bit DPCM | | | | | | | | | | | | | | R/W | | | | | + +From version 1.0.18, libsndfile also reads and writes +[FLAC](https://xiph.org/flac/) and [Ogg/Vorbis](https://xiph.org/vorbis/). + +From version 1.0.29, libsndfile can read and write +[Ogg/Opus](https://opus-codec.org/). + +From version 1.1.0, libsndfile can read and write MP3. + +Some of the file formats I am also interested in adding are: + +- Kurzweil K2000 sampler files. +- Ogg Speex. + +Other file formats may also be added on request. + +If you are interested in how to add a new format to a libsndfile, you may find +this [FAQ](new_file_type_howto.md) helpful. diff --git a/extern/libsndfile-modified/docs/index.md b/extern/libsndfile-modified/docs/index.md new file mode 100644 index 000000000..bc5890dbb --- /dev/null +++ b/extern/libsndfile-modified/docs/index.md @@ -0,0 +1,322 @@ +--- +layout: home +title: The libsndfile Home Page +--- + +Libsndfile is a C library for reading and writing files containing sampled sound +(such as MS Windows WAV and the Apple/SGI AIFF format) through one standard +library interface. It is released in source code format under the +[Gnu Lesser General Public License](http://www.gnu.org/copyleft/lesser.html). + +The library was written to compile and run on a Linux system but should compile +and run on just about any Unix (including MacOS X). +There are also pre-compiled binaries available for 32 and 64 bit windows. + +It was designed to handle both little-endian (such as WAV) and big-endian (such +as AIFF) data, and to compile and run correctly on little-endian (such as Intel +and DEC/Compaq Alpha) processor systems as well as big-endian processor systems +such as Motorola 68k, Power PC, MIPS and Sparc. Hopefully the design of the +library will also make it easy to extend for reading and writing new sound file +formats. + +It has been compiled and tested (at one time or another) on the following +systems: + +* Every platform supported by Debian GNU/Linux including x86_64-linux-gnu, + i486-linux-gnu, powerpc-linux-gnu, sparc-linux-gnu, alpha-linux-gnu, + mips-linux-gnu and armel-linux-gnu. +* powerpc-apple-darwin7.0 (Mac OS X 10.3) +* sparc-sun-solaris2.8 (using gcc) +* mips-sgi-irix5.3 (using gcc) +* QNX 6.0 +* i386-unknown-openbsd2.9 +* Microsoft Windows + +At the moment, each new release is being tested on i386 Linux, x86_64 Linux, +PowerPC Linux, Win32 and Win64. + +## Features + +libsndfile has the following main features : + +* Ability to read and write a large number of [file formats](formats.html). +* A simple, elegant and easy to use Applications Programming Interface. +* Usable on Unix, Win32, MacOS and others. +* On the fly format conversion, including endian-ness swapping, type conversion + and bitwidth scaling. +* Optional normalisation when reading floating point data from files containing + integer data. +* Ability to open files in read/write mode. +* The ability to write the file header without closing the file (only on files + open for write or read/write). +* Ability to query the library about all supported formats and retrieve text + strings describing each format. + +libsndfile has a comprehensive test suite so that each release is as bug free +as possible. +When new bugs are found, new tests are added to the test suite to ensure that +these bugs don't creep back into the code. +When new features are added, tests are added to the test suite to make sure that +these features continue to work correctly even when they are old features. + +## History + +My first attempt at reading and writing WAV files was in 1990 or so under +Windows 3.1. I started using Linux in early 1995 and contributed some code to +the [wavplay](http://www.vaxxine.com/ve3wwg/gnuwave.html) program. That +contributed code would eventually mutate into this library. As one of my +interests is Digital Signal Processing (DSP) I decided that as well as reading +data from an audio file in the native format (typically 16 bit short integers) +it would also be useful to be able to have the library do the conversion to +floating point numbers for DSP applications. It then dawned on me that whatever +file format (anything from 8 bit unsigned chars, to 32 bit floating point +numbers) the library should be able to convert the data to whatever format the +library user wishes to use it in. For example, in a sound playback program, the +library caller typically wants the sound data in 16 bit short integers to dump +into a sound card even though the data in the file may be 32 bit floating point +numbers (ie Microsoft's WAVE_FORMAT_IEEE_FLOAT format). Another example would be +someone doing speech recognition research who has recorded some speech as a 16 +bit WAV file but wants to process it as double precision floating point numbers. + +Here is the release history for libsndfile: + +* Version 0.0.8 (Feb 15 1999) First official release. +* Version 0.0.28 (Apr 26 2002) Final release of version 0 of libsndfile. +* Version 1.0.0rc1 (Jun 24 2002) Release candidate 1 of version 1 of libsndfile. +* Version 1.0.0rc6 (Aug 14 2002) MacOS 9 fixes. +* Version 1.0.0 (Aug 16 2002) First 1.0.X release. +* Version 1.0.1 (Sep 14 2002) Added MAT4 and MAT5 file formats. +* Version 1.0.2 (Nov 24 2002) Added VOX ADPCM format. +* Version 1.0.3 (Dec 09 2002) Fixes for Linux on ia64 CPUs. +* Version 1.0.4 (Feb 02 2003) New file formats and functionality. +* Version 1.0.5 (May 03 2003) One new file format and new functionality. +* Version 1.0.6 (Feb 08 2004) Large file fix for Linux/Solaris, new + functionality and Win32 improvements. +* Version 1.0.7 (Feb 24 2004) Fix build problems on MacOS X and fix ia64/MIPS + etc clip mode detection. +* Version 1.0.8 (Mar 14 2004) Minor bug fixes. +* Version 1.0.9 (Mar 30 2004) Add AVR format. Improve handling of some WAV + files. +* Version 1.0.10 (Jun 15 2004) Minor bug fixes. Fix support for Win32 MinGW + compiler. +* Version 1.0.11 (Nov 15 2004) Add SD2 file support, reading of loop data in WAV + and AIFF. Minor bug fixes. +* Version 1.0.12 (Sep 30 2005) Add FLAC and CAF file support, virtual I/O + interface. Minor bug fixes and cleanups. +* Version 1.0.13 (Jan 21 2006) Add read/write of instrument chunks. Minor bug + fixes. +* Version 1.0.14 (Feb 19 2006) Minor bug fixes. Start shipping windows + binary/source ZIP. +* Version 1.0.15 (Mar 16 2006) Minor bug fixes. +* Version 1.0.16 (Apr 30 2006) Add support for RIFX. Other minor feature + enhancements and bug fixes. +* Version 1.0.17 (Aug 31 2006) Add C++ wrapper sndfile.hh. Minor bug fixes and + cleanups. +* Version 1.0.18 (Feb 07 2009) Add Ogg/Vorbis support, remove captive + libraries, many new features and bug fixes. Generate Win32 and Win64 + pre-compiled binaries. +* Version 1.0.19 (Mar 02 2009) Fix for CVE-2009-0186. Huge number of minor fixes + as a result of static analysis. +* Version 1.0.20 (May 14 2009) Fix for potential heap overflow. +* Version 1.0.21 (December 13 2009) Bunch of minor bug fixes. +* Version 1.0.22 (October 04 2010) Bunch of minor bug fixes. +* Version 1.0.23 (October 10 2010) Minor bug fixes. +* Version 1.0.24 (March 23 2011) Minor bug fixes. +* Version 1.0.25 (July 13 2011) Fix for Secunia Advisory SA45125. Minor bug + fixes and improvements. +* Version 1.0.26 (November 22 2015) Fix for CVE-2014-9496, CVE-2014-9756 and + CVE-2015-7805. Add ALAC/CAF support. Minor bug fixes and improvements. +* Version 1.0.27 (June 19 2016) Fix a seek regression in 1.0.26. Add metadata + read/write for CAF and RF64. FIx PAF endian-ness issue. +* Version 1.0.28 (April 2 2017) Fix buffer overruns in FLAC and ID3 handling + code. Reduce default header memory requirements. Fix detection of Large File + Support for 32 bit systems. +* Version 1.0.29 (August 15 2020) Opus support, build system improvements and + bug fixes. +* Version 1.0.30 (September 19 2020) Bugfix release. Fix file descriptor leaks + in sf_open_fd () function. Fix critical CMake bug leading to broken ABI on + Linux platforms. Other numerous fixes to CMake build system, consider it + stable now. Fix some memory leaks. Fix handling of some SD2 files. Update + documentation. Integrate GitHub Actions for faster test builds and Oss-Fuzz + for fuzzing tests. Move sndfile.h.in from src/ to include/ directory. To avoid + problems, delete old generated sndfile.h from $(top_builddir)/src. +* Version 1.0.31 (January 24 2021) Bugfix release. Fix multiple memory leaks + reported by OSS-Fuzz. More SSE2-optimized functions for x86 and amd64. +* Version 1.1.0 (March 27 2022) Minor release, backward compatible with previous + releases. Added long-awaited MP3 support. Numerous improvements and bugfixes. +* Version 1.2.0 (December 25 2022) Various bugfixes, + removed artificial samplerate limit +* Version 1.2.1 (August 12 2023) Patch release, various bugfixes. +* Version 1.2.2 (August 13 2023) Patch release, various bugfixes. + +## Similar or Related Projects + +* [SoX](http://sox.sourceforge.net/) is a program for converting between sound + file formats. +* [Wavplay](http://www.hitsquad.com/smm/programs/WavPlay/) started out as a + minimal WAV file player under Linux and has mutated into Gnuwave, a + client/server application for more general multimedia and games sound + playback. +* [Audiofile](http://www.68k.org/~michael/audiofile/) (libaudiofile) is a + library similar to libsndfile but with a different programming interface. The + author Michael Pruett has set out to clone (and fix some bugs in) the + libaudiofile library which ships with SGI's IRIX OS. +* [sndlib.tar.gz](ftp://ccrma-ftp.stanford.edu/pub/Lisp/sndlib.tar.gz) is + another library written by Bill Schottstaedt of CCRMA. + +## Licensing + +libsndfile is released under the terms of the GNU Lesser General Public License, +of which there are two versions; +[version 2.1](http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html) +and +[version 3](http://www.gnu.org/copyleft/lesser.html). +To maximise the compatibility of libsndfile, the user may choose to use +libsndfile under either of the above two licenses. +You can also read a simple explanation of the ideas behind the GPL and the LGPL +[here](http://www.gnu.org/copyleft/lesser.html). + +You can use libsndfile with +[Free Software](http://www.gnu.org/), +[Open Source](http://www.opensource.org/), +proprietary, shareware or other closed source applications as long as libsndfile +is used as a dynamically loaded library and you abide by a small number of other +conditions (read the LGPL for more info). +With applications released under the GNU GPL you can also use libsndfile +statically linked to your application. + +I would like to see libsndfile used as widely as possible but I would prefer it +if you released software that uses libsndfile as +[Free Software](http://www.gnu.org/) +or +[Open Source](http://www.opensource.org/). +However, if you put in a great deal of effort building a significant application +which simply uses libsndfile for file I/O, then I have no problem with you +releasing that as closed source and charging as much money as you want for it as +long as you abide by [the license](http://www.gnu.org/copyleft/lesser.html). + +## Download + +Check latest version on +[GitHub Releases page](https://github.com/libsndfile/libsndfile/releases/). + +Binaries and source packages are signed by current releaser David Seifert aka +@SoapGentoo. You can verify signatures with his public GPG key: + +``` +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v2 + +mQINBFppABgBEAC42ZiNvV7BTIgR6TQy0YnF54fx3mVRP1u8Mq00UZa7reAsNKh7 +1H60j0W4s6+4pVVIKGfpVGxLwUdJe+KVCYw1Cd3YW6uMf5zZrC/ZWqnJiH/n6S6o +1l4INII2o6YbGBnzIWBPRo7PlOL+mvgKTLpBSJPnhD8XDGN5wRiV8rL2+6Dptg0F +nJt7oxECGF3OD3gk6HMel0o82CVkIqMtNaX1L/bhcdF7K0Rp2MXPZMmpn1izW5sI +asN1G9+w+Zwj7kMJzq1Aw3ac+rsX4SEYdvXjS2QhDHQUIr6LXri3D2WbcEqIZj2R +JVoVwblsrG11dYXFDBbgrq4NhgTBsxHYDlkr/qF2W+kbPC/nhSqTVZeCYvTBZbOQ ++RqyN/I0izukglnWmV1jGijFA8snyP8efx732hw/24zRYmtXOtnEITUpw8WOeZCq +6uiHaQ+eopnY2ojBg9BI7WZm0AFn58xxT9soMsyFOUFgXTqaWFZWlJ3fhZE8/0v8 +JEu/kPGE5aJReT3b34B+Bojkj74XR+h2u7iJJBHMTE8RwGoUOZHer/XsL9xlcdks +I+7TCjiq++ShaSSt2XsJmw2BhREohrjW/2KkwmvT3b44RMpKPB4WTH+++aqJQNeM +IqmswOMoZvzEZezInj7WVY/r0WEei1Y6wt1tBrJ/cFf1oQBM1UmphxcrfQARAQAB +tB9EYXZpZCBTZWlmZXJ0IDxzb2FwQGdlbnRvby5vcmc+iQJUBBMBCgA+BQsJCAcD +BRUKCQgLBRYCAwEAAh4BAheAAhsBFiEEMdlcq22A0mIkShdQpHYg6AHkfpUFAl/V +CvoFCQkuceIACgkQpHYg6AHkfpXYxA//aiJW1NwunpmzEc62id8lRMnoLHWVjISZ +b+xSlm+hk4LYq+ZbthJDzKcT86/3DJOSE1zQw9wLuCao9IW2UfFJQBtR+TAfbagG +0Yyk/kMcLoFJxnG1ywdJWypCAauuIhia52Z7PmmjsBbFwr6LygDwSQmZAyACMAs7 +TLQe+yERc2RNDsIEsquLSxxRF0Spk9gagWtKgrPc2XBjuNtQDwW7JgsOUoEeHyxC +29fRUjC3o/pG2I6iAZp17OROZI5yl4TSORrSBDGIi2sayxyxP0x+IPKtrCUcBGNx +wGp+56bP/V0hA6sgCPh/iwvqLoeibso6l/Kd4ltVAEQnHTd6fr8g+wLEUXfbJVTR +7aeFUoaFmWjSPlQrNr6HlxSLV/kRx9kVJp1Pn16vkfVBF7fG7iDLiqphwEeQg5ND +nmGeKAbRRNxFHyBHf0XRsaYiFZQckguO+71XSRtVx8/YP5nyNbtl9y1h/4JlT6Gy +t7hb5twYFQyQrKss83E/Bo1sRdHpj0ibtqb4ZbYANbh482E6yFhAkuo8YjVTJipI +1Ve8EBKnX3R+pDt147uyysNvtPVXML+sWpGSMVSm4NA8uT3F5nqxVwj+SeXy3Wq/ +CHQ2VBKGBC655G+wFD5C6O7cTx2MwH+2H8tzhWm+gFlI3MFKEXa/PC+YUC/diYcb +BrApavriTRa5Ag0EWmkAZgEQAPXMD3mZI+ChvBysXZWksC88/uSEwFeb3XkcRm7v +04GN7hcz+bfrmnUTB3tuE/ZQgv+u7ZjetvH1aEKieznn/GjnWoOBoJusOYvfAQeF +0mQVi118QiOZRCnEZpkz+RY9TiXVgrZJg+AGqHZ3Ol4GkInEV2NWgH37Xal+HkFl +rwI2U7mL0kZRG+LAVCQHKzqU0R0HE1XyJ4qf0awtG5Qi/TZvgXBdZPDXgr8i9Vlf +UUu10c2XnXM0Av/YAlZmBFjVYrSOUCFenqSVqL+s9sTCVdWlJrGjrr3Ja4uT3kl2 +rLva0AR4oSQoxt8adKohmFz0vzOkQtCoRzhrCwoo3JvNjKdSNoOP1nSsxlO5ji8r +ih5d+ajPgi580XyHLnrvG7vobR48qqscv1hizKuCgTacOTe6Db2Gqc8xF6v8HhJa +KwWJtmFllIfN/tIvZ6BbbgHQn0IGf4CYnWf0SksPZqpBmTRpD2jfBxcj2UEg+AR3 +LARjuyUVpFJScyu6ExQG+6O+ByLL31iWP5MgUrza1rIpriPa3NT3rZ3DG2pvQrS3 +ySsrPzH7VRX8L1ThSMSzjwF96aMsd14s7XzR4EzNuWwZDukfs0yavZk6l4o1M0mb +tbJi7hE4cz13KRHYvIkKMdZGYUnzRzZUDlsj2imakk3BR6GXnxZ1ST6062g+QxiL +AJFLABEBAAGJBHIEGAEKACYCGwIWIQQx2VyrbYDSYiRKF1CkdiDoAeR+lQUCX9UL +DQUJCS5xpwJAwXQgBBkBCgAdFiEEuNUxXaAAcsCoYIifzjbhFyAuOEIFAlppAGYA +CgkQzjbhFyAuOELmrQ/9H9wrWsWa21STZdxUmyU2sh9VXAWEHl1Ey0fVTznDM0Fl +zx5YSR/TmmnE36rpaz31Ttkx8SP914oV+mMgseecdya9Bf6uZL9Cv7V3KEsJBRL/ +ncrOWQBHP/Xy1X+mLD6A19xq7H4RihSLj0LeK2YVjrJzJ7wMf4mKXuBayQeAHImU +WRCRTbmK3umh2nB5V0iPd/XZEIiYtiTPe+7E/va6+0bBvOumF3a+Z0iui7eU4hFC +7Jk71D0dcg09SlIaNoMOrw7cMC3j2pMdKtsj8+0I6WBv14PhhqPAsnjdf7I/4NfK +L7Jav8T/gDS01uA2Jxm72d+wr+eSjOBXa6x8CEbTqfkjAGxsWENThCp6zDkaXSDd +JsV0va47vjzG8+wTDAvPy5IxIM/KZZdl4uWM+mF5K+q+eSTOHe7aLF2OdcussoBA +A18zm994dAkG1COX/qpxanxx2bv/2IvCGPg+x6JtAN8ji2kncWu3dWGQdE5XbVjc +fDwgsUPpp04G27Mr/x+HpEbgZ5SdA0dAqJktlNvCcHALhlblCWrsh/1QNjT/2iG8 +wsjcpEy/s4tWAuV4PTa4xvZ1JPS7Z7Eo5aBy9ZGOWG9SrHEiHnhkUsiswbHBOEjd +pBSkmNElDcv9fRUahVCTPfvWBATFDrQyMjJBSm+cV8c/iFQM7isVSu8W7E0eetsJ +EKR2IOgB5H6Vv9sP/1dxTvH0N0UoEoxIG/hnirEkbRpljdvqy4/uikYBKyQgSbo8 +VITTjea7gIhDztil9WZYt35jbOmoaGM2Z6TP2LEDOWgljYUNq9pl9Sc2GS8cNtEO +WxExzGOc1Flo730dX3A85Ks3+0WPXZjLDcRRcPVkFd5WLQQDV1YVYopWkuQBC+Br +4q3uv+sk+bw6gDa9+zFBbDuegdsYuTXrFHoxHz2GRv9Yb7ULCMgpFeNKDgtQq91u +RqewoTwQp9tlp91LH/hh7R0Q4DRgeFDkLnVRXwSKjVvCrT5cBgImGwtFTGS4egoy +MDKd/KKjZllp1ahRCln1XfmFQyQVMVvuF/JTtt31n6KwXwK2yxIlXB01xvRH+Ees +AWeRYWKWXydaAY/9Ve0/PLFlgsr/XUGvt0GoEKe7odD3nZgg6015+/8JTroKw19L +NZkhdfFMl11Zi0j5k3UbyzjYVpFSd8K2o0VoOG1LFsPp8tlRxNoVzpId0CX1au/p +y1H7Wy/39mzriRG3rw+mJAQbBjN09putCltXFXpOEWk08n/N3vufCVQUoSu/2Bqw +2HYj8VtToQp+O5dG3XxvDHINtInP1yr2Wcw2plna0KoXLwv/lZgDm3LN+eCWpG6d +N/xk25DTSqTHArUQIEkhcHYK6GnyxUcvoKtG88hXtqEPYXiK08FZYAUPTnDYuQIN +BFppAIkBEADDjvQZUs1NoqJpxkD2QDBudU1DBCaeI1D6CancMtb5FebPUxgFlDMd +CBGOun48dY5i87gDhT/qS3gP/Mv9rjKJmcG9JHfhpXdW73owxrcsQ96nxxVJNEVl +UHJw00z8C9eGWqr0SzSoE33K/PkzSkgtsaotF6+3uCerWulweulmGa5dpVfV0mbS +aVw8VmrhZ5NmCeodyy/lR85rPik5pb32NT6v7xBkgkfS0VYtPB2E5gW1pXX/jEOi +Mfq9idOEP9lxrNXV9j49Lr0JQCwAcrYbQ2+VPe6eacJEjzJ/6HiUqhPrYdnvydmb +hU+xmv2NjGp2UnDZDEhzQfwm6fMx+8Nx2uPzCnXQGoyRBwiC/KcdW0F1ZPKdSXqH +NKoOF62pLvIMSmfI3ZVOrTohArfr1kFEYVDv9Nl7oY+qg2rZEc2srOF74a9Z46bR +TDPsEQzE2UMCvu3+rofhSD7aRotlKeDCvbe2s0yE4Man457Xc3LXh8Gva8CzCOLE +2eMhNTsHIZk68WgXp3/uvE4Xy42myrk1AV8XXDdlWgx0Kc/I6tE59O5NVPSfuGvH +1a15KKx0F6euEnYDKKpQ5PDR6dSn61po0tfbt96m044G/xQFjrfhHei4jji9Ogd9 +vlXVAi2vn3+NCSHFP5l3igLByBHy9iLIdmz7yQuus/1nwRmxOHOf2QARAQABiQI8 +BBgBCgAmAhsMFiEEMdlcq22A0mIkShdQpHYg6AHkfpUFAl/VCxkFCQkucZAACgkQ +pHYg6AHkfpVPSRAAmheYkYJmtDbkzPBBnj5mbCIQN1/G5PI9eixc/TXWFOXtcjU1 +mJlJpSidHJyLRrx7r0c+N+s8vnY/JuUBsNoMJMER+Mv/CFW4iFi59V534SyAb2S0 +7NINJnFNkXBY62CDz9KsMuv/MdSv2yLhPH2Tfrm/eDRQesj1PanE4U1cgjWyJRc/ +IOlaRHvTasWDLgwbQi8ykt+4xUWzL/YKHzB+KyyzBK7vPBXqySX8ka4BOw7SDwG5 +lX2gtmhk4AGBwVChLXKflqVx1WXj4DPOt0kmOKVnKFyvUijK58M0A2FMgFMXDTIS +DRtoZPdx/rkODXxgS+W+27NcYAnxJiM0cQqizEnQh7PQ1KzgdChPejYXMKe9lwdn +ssMUxrBpbuAuagEf+pebNjD2eaNR4p8kfaDdGn53q55ysDvoyxKvnVQGSk1FAR9Q +s4N5a4f02U7dzlyEhEfIcuUlRCfnlpn4n725YIhHheDig5zKWoEZCkNIfiRcGzDl +8Drj+tlZiUR+gDkIoWSBaCkKbIQlc8qCYy6Hm7oZBaol6xKlUnTMK2rjK8fR4i8r +bVDWBAaWj3jcDHJ0Jg3fS/qBpeya/JXMp89TR8NK5Ys7PZpWbor+puXBYyXDAVx3 +rXQ7JBA5klHPxrgjso1S/LqwscKLENtrVjdjhryLBmPifrmofJRnrpiHIEa5Ag0E +WmkAswEQAL0hKwsRybQzkNGpJP+ElLSwFHd7XQhr+qIwLllpumWtnIK/DHmv8SpW +FqAYajmRTXipFcBHH25x2jIIliZidn0a9826l+sMzrFadMC6/W4pitP71TeqZzwn +pAuHs14YL7Wiy0aJQnfbCpRzPq3kYyOXmhmY7lPWO0WdUpR6W8wUbleK5XOVDDRx +aIC/M3hhDOxZOMzQ+pdn4BaOFQQ0ygsRkqOudbuc0R1giYRt1i6gMeT8gfzL9jlw +HcJ+aVnxdUQQ4uC47oKo/+lg7qh7LsiW79pQC1Bcdm8lhRmqtxe6ub60ecjax3XU +1ILIEfIFCv6M7LRUAwz0bqk35spgkJqrGGKkdeWEKAFHg2QWR2F0zy+HdlPLfKxO +uhaccpwc9EJtf744GS0SXa2AXr32j56n7CFcEjFcIQPBC6OJn6eA3hOVUYGZ7SrT +4fsmZiFAdGEkvLKFuNhju1Hj2EJQUY1pm4GSBco7BR8x+QqoYrt5clU3WxRMNfTR +0Rtuzsh4xskXNVMMgvKOahAtxENv2M2Cx6zJPVL5dmaysP7d6QRVeOQA5PwkcZ5Q +qK6JtDZj2jpaKQH4Za715kiIcdqMDSkwxa6avc0kARHvfFcBR4hwDm1GAlaKG7eH +8TOGGQIk8x2F3s4l8mTJVLWTP/uJYnkYBdqANYo5t1NIQLvwLFV3ABEBAAGJAjwE +GAEKACYCGyAWIQQx2VyrbYDSYiRKF1CkdiDoAeR+lQUCX9ULIwUJCS5xcAAKCRCk +diDoAeR+leekD/sF7aHH0W35ckWrXZlfSp0qHPWrBUaLBI9OAUHenRhgs4SbK0D4 +wqEiu0C5iDQojpXAeALQ8g/1pUsZ1yuFqYbGYWrHkA0Pm+P3tAGB4LMZ41YfvROP +uaiW/+IMJbWllgRtaDt8/NtCgs30WI9I+az5M29HcGfvEwEUykrBx3dE9T+1ui3O +capdd+GMvdAAsX5PyVkjWgZ7GrZeH8mG7UysYfT4qthxEtQfZ/u8ceSduKA46ugh +C2eafIDNvluqn7BU4oKxME61u6C8BN2yHLI6LV0Tr4z5H8joVbM4BSFMwLVGlsXf +HhB8kLiErN6bXolxsjARlmYiD9S9H2AcYidr6RYXf2EVFSpBG59xn1WTDN+DsHQf +7btNPEPl/OPxa3OQjG+xn8USddiP0N0B4xsyzMNCCKDgvXXcIhX55KG9eh3Tc98S +fEyhxu8ybZBIGmTJysPKxijfvSgQF+RPNTsz9lvXqkoK7RTgeYMschpjJEznCLbt +M6eTDb5z0G5uLXh6+dYxtDOlPogI5OHd+G51LwCjvrQ+AtIUCgafuemwA9mpFT2b +svb/qcxSVUb44bVaNHn1JHebX2YbokGtBOm1x2PI5fT8n6YIIYz3jKYOZAYdUT7x +6qURyNjOfG4aPJIATwuh4GSNuxUG40+yuT+XfQF24mu1esS1J3wzRloJ7w== +=K3x+ +-----END PGP PUBLIC KEY BLOCK----- +``` + +## See Also + +* [sndfile-tools](https://github.com/libsndfile/sndfile-tools): a small +collection of programs which use libsndfile. diff --git a/extern/libsndfile-modified/docs/libsndfile.css b/extern/libsndfile-modified/docs/libsndfile.css new file mode 100644 index 000000000..3386bc3cb --- /dev/null +++ b/extern/libsndfile-modified/docs/libsndfile.css @@ -0,0 +1,101 @@ +body { + background : black ; + color : white ; + font-family : arial, helvetica, sans-serif ; + line-height: 1.5 ; + margin-left: 6%; + margin-right: 6%; +} +td { + font-family : arial, helvetica, sans-serif ; + background : black ; + color : white ; +} +center { + font-family : arial, helvetica, sans-serif ; +} +p { + font-family : arial, helvetica, sans-serif ; + text-align : left ; +} +.indent_block { + font-family : arial, helvetica, sans-serif ; + text-align : left ; +} +br { + font-family : arial, helvetica, sans-serif ; +} +form { + font-family : arial, helvetica, sans-serif ; +} +ul { + font-family : arial, helvetica, sans-serif ; + text-align : left ; +} +ol { + font-family : arial, helvetica, sans-serif ; + text-align : left ; +} +dl { + font-family : arial, helvetica, sans-serif ; + text-align : left ; +} +h1 { + font-size : xx-large ; + background : black ; + color : #5050FF ; + text-align : left ; +} +h2 { + font-size : x-large ; + background : black ; + color : #5050FF ; + text-align : left ; +} +h3 { + font-size : large ; + background : black ; + color : #5050FF ; + text-align : left ; +} +h4 { + font-size : medium ; + background : black ; + color : #5050FF ; + text-align : left ; +} +pre { + font-family : courier, monospace ; + font-size : medium ; +} +code, +kbd, +samp, +var { + font-family: "Courier New", monospace, serif; + font-size: 1em; +} +a:link { color : #9090FF ; } +a:visited { color : #5050FF ; } +a:active { color : #FF00FF ; } +a:hover { background-color : #202080 ; } + +table.formats-table { + text-align: center; + font-size: small; + border-collapse: collapse; +} + +table.formats-table, table.formats-table th, table.formats-table td { + border: 1px solid white; +} + +.image-logo { + display: block; + margin-left: auto; + margin-right: auto; +} + +nav { + text-align: center; +} diff --git a/extern/libsndfile-modified/docs/libsndfile.jpg b/extern/libsndfile-modified/docs/libsndfile.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7855b92d0e635df3f22cf41ad371c700fa8508e5 GIT binary patch literal 22043 zcmbq)Wl&sA(C*?A5?BcCEbb6o13`lYS=`;-H9&9{cMTR`ad!#s1a}Cs5Zv7^Z+&&^ z)~&k#?wmg}HGR6LyG~8l)BT*+#n-<8tglkCQUEwO008do0lcmNzPzpe|Hgkx{{J+* zz5Ut^0HOkn;T#a)r~vRlI0PWvYaf98?VN}R|0xIj?}3bhiiUuMjtCF;?oB`y>rDU- z0S*Zf2?Yfe6$uG|00)nVgbY9dqM~8rP;z_}Q#QhN3XDHP$D`uRtND!&;`eBr+Wf@J zC+_TC-#|@6%cByMa85_h{l(ZVwXmr8O)2SHY>@shqX2k>H>GfIrr)-ufdF`TcmN^- zA`0T$X%ODd_}?}VfQ(Ivg7cq6CtNB{qrmv7H+yHOpikn?t~A^{#s#(Yc=*(`T<)oj zb(`m}%K!`nxHnf3fB;dzOTYt{ju7rcXb^bq)ux2MQ#z0>7~*} zk#tN8a}als_|Bmoo&Tvv*TP!29&%%ES1}n2(TYIH(7I2IQf|hxu9w$k)w^wAR8M~K z0_@R`|9RPafSghdf!hiT3)9VL@vzJ3{;7Fu2y&xIKDZMQOXf#(#lt~*Vvw2u^?P{G z43U5-2V7OA5j;i$o%~~RUj4f<~Nt+|8q*k_+axB`!j;+4ZzXSa^77U^bGWe8PuI0RyBmH zDT47|0bdWa|1=-YHtaA}95Kwd`FB;vhR)2lEqvQ3uDU$m9xX7iCti9ODt!{^@U{Ll zNNrIxmGp!vu^!$!der|4=sA66Dpsk8K%T}2HTfsLh1>HT{gDjH z-o>-@o7>l%l)CMXT^{eQUqmBq7MBZ{yiWN2{R13C^mYA31k#a-X$s7sxY{fnncuOkw)UL?b4t3}j+Ig;WxaW}NtF;IMQHq` z?_PSlNtFr^?p^_+WbFT@3Y1YnHAJEaJFzErjGR7dq_}D{mizH;J~*X>RgOia44|&1jCx-iyM1}*ICcsf7!&^d5)k&! z)4+sJGI?eeoc!td>p(+43F?brQ0z09@iuM#_6}?VUWL*LIhH^-StntZZvm}I=M{39 zoND)a;y-VG3yKmh@MWx5D0BZ-idkgKO{pH>Qg^U-aVsrQApUhpH=U61$F;gMO zeg{4|Yy>W#a!;W2F?k##=w1P3QNys!5YJH2TExjs$xc6dszub(w@y z>)Hm=&k|kQRQWqf%^ydjF-E@6ESvW^TY7{pd>)h&W8tM-sSYh8?cpb0w{G!i)L~0L zQIyjPH*!@uy%6+L-t4Xn!ILP!x`_NEZ4A#oO3}xkT#jf68Hl?&fs};b*3Lfa-#mWk z78Ji7#r$1b_Rq;WI+cY~SlAGS49Qffh+&lv>pQh_5VaD}q#prDfK?M@qYaUmEjoH9 z!uzgttQEfjtbWqBD#{&JpLlG5CI7*OwUL-nIIT`o<~YaJV?Qk!J&<9;TnwIA-KQs` zzG#!2ajJz!cP3$8m~nY%;S$lcIH%mV4uwlS$X%wgS8+w7I$kG%&rVvu!{#6Dg~@C1w&!U^>-^ zSP5-JGBe1h*RG&PE2PLtGyD9R3)NCl8{!O#SFg0=fQOeAKWmpl%fUfAQjeo0DwDzH z_FcZ==W}*$e<)^A1D_HXkjT}eyg#7xad>DO`Z1Bd6k{Hd-9^Ez<8+8YC6RMH6utkA zXdh^%;v>NhZ{;5+9GE8)StY<6=hWX0Uy$8S9AxVi{eZN9VM?~eA-y3!3U*+YsvEH7 z)yM<4pY15B=5V`YowX%@>SvfO4#yr0AeUe4*Hli)sS|3j7cBSvy_T$+IZTA{DJHmkOmw6_p~QIS6qiZATA3W3;wb@vuP+Tjr+ z&@#wi@#yFR#0_atjWnjG@e7pYV4bwO@0MQ2EJ8!EsA|OO@Hi0ObS!fD)9wK7_Ybr~ z&g_&L+!fvtGU0o??Yv4SkplDkVf7%g0|Ogp{luG8%;rI!0@3CHHpUuVdyidi)cd^VC1cFCLwVeQw#? zz7UOGCtQSO^_M`^EkcP?4u=HcUO|Rp?Q$!=3i$<^HOiqDUFd!f@p$ zCK7wo9453!7O$%XZWv&R2ssLn{SJKc{9T}x1~2R>VbGSlR^@nz@e1HFNgX|TA@S)V zv#E&evW-XbA~!&K%Pei8|MPgPu5p9whsjj{3rZ4+q+#B9ip-4XW0BG zlPm_Te(M2`=Z7x>$5~S1KUc2{#VU@tHDqo~j|MhJE5NKucmGEou71~C78?0f|njBfW4rzD`JUBCYx zU~xV_dA=zLIezY#(QR-|aW7$;VmjQ)TjYJMjD1*UsL-YAm&QR#D?Q_^**Dr(Nr-CJIT?gp#;<|8S|1IN(spAgFwE~{1!3RIj zBfab|m8P>KzX@#l{EB|6R)00`kEf<`(RJ0+9Q@MZe$}z?OSb)yH_0`zo^LB%M@zf&?8XRuI{%Tdp4L%Z;Z?Q_mX$L6GWUi ztXaUus)5>6Gk0;5*RMP@e0;AO(yv|Nz(7@xM&LB{Q_U&f=Y~v0T{DT0j7#J4G1-YI zoe)LB-!^iT;6$iwgpi1PWkrf}$w*^Z7CL*z7!FXr0{C3`gNU4AF1}&u?eH1; zZn>D^Ag*t_Y+Lg(#tu*NNzN%8;ZuDb^3=80z06-_-&1^(A>JD4G-UzDPbzN73dRY1 z8K|{P{3#wPNVm}PXA@e{k9%wqzAktGF$RGrL8&nWJlvIDdaW*&BrB z`rYgq{nK*>)0u4rKuCjH$r#WMnm#>_qysR9nh;b*bq@Pq3|~`4Pl~JwC*QnWQJj2u zHx=+A$AN=K)FX+iqn#f*cXA8-3KMIXw97iKGTG36ENVh)Y0eqnnLe-Uxp`=cBF)jz z>62m_(Qf=$W3CrNvHUB}TE+z#nJwIcVveMoO@6#D&w*#?>qN+UAIVo~9V+KpM_+H_ z#Twlh3nUsxF=|lOcJjs_(h#`-PPO7{w5T77+(DA@;hf_H0*(hC z2>>Qjv*T1Ho>%YATACll5{_?VEh1p`38kFqi8);Vu)8&3geJJ%g1$J>7Q{ascE{i$ zVKIsX>Mm;zv}i&Y3M? zP5&X%&R&<7KNZovmyyQ5E>bM1!Y#WPv{@3-R4h#6kJysr9YuxX!wy1Z*fW9Gcx{PiO5RcbBRi zy1(94pqHW05u7%+Rb2Zt)`#JUaYT_Z&0s^M8a)|Iov?$h=JrmwDE^6?!~!qn(W_do zy-#4UHmotNLxeO^Yu2PGd2tOxCJqY4UO<6nS;m?4#A0FK*As;KWB^MiR7uCBaaEPQ zqI&%GS^^u-|6X`zDjRPPY1pK&;~xsLI=}@F8CQsaRFy}!H`1(?m@#+ze(@W6d_Yg7 z7#d5Y=PW374*Mxz4i_n_B8ly8nLET-2#}#T)NkLCkNF8ojNwze_s2i$Joc=IcA~h8 z0dbx!ynXqv?|l+;&*y(Qj!0fe8k7o)25cYb`FmNMC4xtni?wM3SS>z(BzLiNU)ZbU zi5nrJG5)-Wa*42Udc8eZpp!C7s+w%lW$ki%{=D4twYM%ubLY;>e-3={+_jB#@54gm z6|49yV||3DOC&cJc6;+JgUW55_wwF<{mF*Q2Gn;By^Rkbk8PXOyjG@Gk?1#-k|GT^ zls?_;79&P6`45drlm4AInCOU3-VVqR>OpqoVn;L+gOTcX%(2)ByuV8PCQrtoK6x1FwKf=`e&dq1!FI zK{7XsWAclIfPW=t*EfUtiS^Jt zj*=>k7}-EtA~6H)kI36TTh!#~Nj^9q@X$52IL0w(i?HGxRqJsDdHu~dkyilKgTM1` zr`0Rquzq6@qKG;Cyy|ZIh7iGRRYW9cynL+F7V6iS)iJf=2p?`B`nPCB@4~~g7np=3 zOtJ>T;z6s%zq)GVUo}N7ij9ut5r?b;gBNcNSMlowL?#Y=!7%N^> z5wE1THRr=f_xJAR7xG%i@T%#AB*^TA!$F8DZ2JD~#bfFYTq_ZM^oM%P;{G-Dq!`)Z zBtTw2gh%Wgegf8%M6B5mgwHDC{E$!-s&|HEt(6~J^AdrpSR$(n{Fn@Q#n*h2?ni7` zWD8-6I$e=%8cf3_%#1!+M;bzCY6?{$Dsw+JH-JvT&i0Z6_X1C1o7N}kjjpkY+(#%Q9wcKF z`2;NDZ1`9t=Nra1cV$R*OC?Cr1asnTBaD9R;w*7Oqsh%cP!+DH}l@ z`Qh+E(M`SS!dIo$bR-Sl0Ggi54L zxh4Y~U*vX6)%1l>&6li}+zj?cCmyrGtzyncUH1!(T29U3h0^TdcD{qGn#?jJbQSZ1 zUJM1aCV^qlJN6)dL)DDTE%D|HI4t~j#79bcGx4mHqx+3@EtV3BfRy1sr|H(Juh1bH8 zCly*z)wO;cU0@H&G5+Z~-oGNVPyOfTXV<_1w-cdzQ|?6i-+bqX$E9|dtbTCg*tR}| z)ik(q`vH^#!(_6dpM{Xo!VyCDe*>I^HI;>dIAI(^rLcp@1v>f)@cp|%%zuwp81Wl@ z;m0b?MAnTq6hI}ci}X&YoPZ=F^_k3hQ52A%IMmWsfh1Fb7R0?5l;FlxivI8MK(%s3 zxHS;4UynAm9K@x4hg%gVmCvn_EOB-BBpPsg?|ksh2>a+O-=Dvuxy%q)Jf*a6VoTXe zU3|nE4*q0V`Zm$oj!p9LKx4Ba9qs&dV!GMVHlR;5&al_QnS$j&DJ zNdZ6XU+X_AYL=Lzt(EK!R_TTYpQhOXFIf~;KPd~+l(bGXWf!zYzHNi(=$}z>Fm-Om zQ5$4ans`ZRun3nV)GyOlQ#}XW6G@dpxz;Q9;Ah~Lv1 zOt=-RSLOLAR3v2Jq9p~=Bk_)7{X30R5+sFE7Gd`0dInordCf|@?U(R!Ly+v;qlcr6 zv9(aGet0yFZuTyNFWj)<Dny`TdXF(Wj;1Khfu))76{Z+T68P0|4?Dbue(i{|g* z0Pqk#a_ir?5xH8iWw=lWtdeOUZeQpt;MWL;JHYG*$=xEt7Y)qix?gk1}_Wk zn$e~QLFc=WcbD!I@kiE>2G2_7k;ox4J_5R7u2Q9xj=_vS<341P(-#5Xvl>GCh;I(Y z?VdANwCmBRX^A9F;+fZz>6bj)=Mq2|I6B>d)Ma3Y)ghWyGlCnJPor!pAsR)k?>IKp zf^}rN4GAh^R+-l`|EbNi%dJjKRF>Ypy!ZNSO(V@=JI=G^MB3Yg!qNSt{l*?(qJQct&gg=ctgd0<=P<`9;c;0OV$%U9 z-M7-kyKe8@rL0kRM_-XDr1j&f7#q9Zftp1Qo03!ddB-x?&d0?kIzBh&{o>(p=Ft4? zD8;WW;_X$4z%NO`iDUi<7kgYrM7n;2|5n~AHwhi}Y0`FE34AnF7>%X8X$w3OyE7dHSSy9#r3T~1%f14J=J^n94*Bj|gn-GJL!=Y=7vSAkUg zAEj}+mVCUdp;RrAg9XY}3Uc}h4+iO-T7h}Pd{&NG)?8&-Gc*}JJdM9nN-TY}oJV-d zW;sIE-WkJ@vd)i42zc5um(t@urH!wNQtU(J1l5;xl+W^CM}j z=uC)Z0)6Wvb>5R;TQToWGmfokGm3QOfm$Ipe#3O1eI{b_sHKkHSvZ$Zf1@;BTnpI= z1|kju*i1ce!Ni;FL!3gpu%Yasytt0jDd&dafpV(M+Ko#3yX}iJTQcKi3Q6XzNgn(Z z>Ti9~gK-z~ZsBA*M(hq=)O-rWQVT%6RY~{4_=mlynU+GsY(gWjW(~vel~r3xM>qFK74(EZO?QJS^e7Z^W z@>uyO{Xf~7EKfeO*#VA(9d5GF2+CpL&Pnt-l{{R|P04_0WyPIOP$RWJ7{fL3VYd9{2s4kjSnFl zHV`X&>QPmD0|@*#e^$B$F|;9g}TDc)T-Z)YPrQN}-%FmSJ6 zD{TIY`SrQN7Dtn#cES1kd=1fjHPr;W6r@7p`J)NZEl3$il;i8=4Nf)Md(bc^KlybK zU|y$SStX6@+bI=IW>f_kxV%OmFxN<1sQCK|prw|w084r)xx1@LvdS^i3sWWue~b9g zT9}a8*!Dgv>G2PBoQP>|gb-N$P*PT~s9APUNIybY7-)?7?DQeQBa3|uw9WW8*T`3l42#K$6C;} z2|r2Fpm^}Mki+S5;dHM3YJx}VNbf*E^Ra;cR>v%8iyK(zLI|%A^gPwSSO||F^?qi*Y**;HxDNWz)YRwlLAzQIiKshX#&b5jL-MfR z@EfM(vv}we#>AGxpYzAcWR_}K4r3`;ug%C% zzl#p_2+v(Yk*uZm58lxE6`rjV^Cj1srCz(K&6a z0|tf(NsZ~c>G+m5npnmuGz`X_)zib~OB~zMibFenl45hz+?g2fg#pC#&y&vnneaBxjQC*hW?8Ustv#YsX zRkt85AWdFZ9XZ2~ES9z-b95TF<4wi?4`RDJN^6qh%Nyzg|arHmXWB+ zVlC*@T*|0u`8Fz%#X1OS?tW5Lpjx34cC(hMLd(Ufi6Bt^e%WYfGU{0f|F!0)%qEAv zJrIak>8q`D6a%34_&F<$WB*$QVeR`cuu5N5L0Uf&ua9s4Z+EcFwOY zBLz}bPN2!py@5;>A97_W^V9X1nERA^3S zw`w~43to+>4$P&8H`|0G)=rP;f2DG0(>UxSunm5|P2N~xa=C*P_k%>k^4yyK4p_u+%>n!2~pz#RErDU?yz^5vE14?F82y zQmU3}gu6N-sxUmAq@o*@FNu1H4V(I#WVB7oM0*AEVp(A6&Tc_sVDB--A{nl-DqYVU zu2AYLpkgKe`H3xc5+d&~@^0*ROXhV=TX>D(KyJn{?cxrel|B-p@o=`Xv;W<|)<=kg z+c#gKKJ}kdB`1eECBcg)vkq3Y-RJ*Wc<|bNMGr@Ryby^u9Av)gBZT{ILw*35gOazcD~)gq4X8;N9feo{?NXA2-n{ShcYJ?V)Ys=OeW zEipKFSW>&uqX%$2wi;Jie$WN`Bz28c8*G4|Suf4Zv)Dx0SVc&v=u!&z>=T$CYRZ+o z|1L6Kbm6XiCDXV)U_04+@P}>8|9k~()hT>ESvg~lsj~VJG17+oyUTn@nXRAyq5kD- zo$jE8HO0!(Zj4JH;F^Ukq7yGau&Sf&13$5AhdbTTEOhWJ&+;_JuXqMqevpd8Q{zc^ z6b2idT-Yc&A#b=%XRi63SD5Lnk z%b9oAB);{pMV6kpLW>KLowZQrnLFO?N)aRrTN5IPKMB^hRWL87;iuj7nY%EVLP8L~ z8?~tYjQ>IWwg2NUu^3Q;=1p54j_%y4^Bb?iDr{{%>h{!pM+9&CSYI|ayTT_qk)eVS z=0S9eHevcsGag;N9->~>tpY73;noQ8P}9S<$F~goc6ZgWwi@%(2~yL~B4$Dsd@r7< z#%rLUE@M-qJ~&iqIF?19f?m#55|m0JN!UyCorxUd&ts{5tHAR9hGV(APKouAsCV_3 z61@-HFa>>Z^iBh3Xt*Gel1;pk_V#crX(!^7`?Sz2z!I`nmf^*LE7|-CXnj#{GajIU zZV3$;mmTB&GjqXnaeF^b#RBEwmzv`@i?OJ9A2|ozrVi?dUfU`_Qq17lnwBK7-S}5{ zq6%$rTrG1_@xIu6t~Td{hmIkH2szhyLPFRv&T3b+@sfS}aug2{~?m!nUAn0wm4 z(SA;4n5<8Y8qb(fmyS2@(cI=KCCb=xou8=6Hj~qmWQ05Q(X3FsoN2AtJaW;k@FCl{ z)*mcLyJ16L;MVT6Y`sSqtb&_l6g1^HBx#_HUJSK9$R{+~j~M+aYfDv2eZ4NTU1v^7 zn$bwnV4dBXQf}qA6l?VmTitzC+qA4sTE7<79k)z81CPMO*s#nUSAHU_y4zKEe(fvF z9czFu10k+upHdOqSQ{uL{Vv_^aQS}|!0_4|mqTasSwrg;V8+^DpriUsq1kj@1A6&{F&FfrczXY^fqBq6`N-e~ zeOS)jhwtyIh#)^tGw;%Dk$we8$G!sA$VdWiyRhyq%S0_-0V!>-07>bvl}40@ue^`X zJL3U+^~=7GRLQD#4@YWXNrli=eO#er(Zg0Y|Fnrk@_qV^)7wPuS3u5;)#Xv-D}d+O z{T1+SCF&I*m_I*B_)^*z5R3B)SZEjBBFVKjI1_ynoy2G|S%$i29zEnk87-!8M)xvc zB*n8O?QAW|o_b$8OEh9iZioE|1>f4AC$)a^B7&*%=fHrp2g<!L;Rz2KDMYY^L9Xk>?GSZus9;opybv}M& z-UbKA%f0Lx{ezz}j&jlIeK=!cUsJR?VtAX*yDoKxoV=NH|E%J6qg$vcs+N=;!E%)JN^Q4-vQIC7zn@XnHyGCsJlfm9jcs(wtjGM*8Cz ziD>^2koi+I;VFh7lp!YDpk*=PuuTG%z1}nZ;zQ^4{0G;*Z6ls*sE*y}(j83=7g3rG zg$Z{9&e80A#5c4AEiwr~c-e-*4@NBtMheuGA;e9YmUVtLtMb1XI97BX+GECBNLdC% z*tL3V!c4H~g9W$(hfG}-6d***C7(c8-Ao^DgtzIFqu3tgYxPrjR=k>uT|u=Kylime z)$-&xSz@J?#b%z5P7FLBLKpZ)(IbI7+QZfOzL-OU20DbMGEUFAvwwSgV_V|JnVp`w z{pWrsG-;4KU@$57jmO2N*z>5!X5z;=LA2-c>sY+#yi@IUnbXpo>&rFTJFG~I8nAy{ zB(;vvcuDyC8dC_(Aw8spP%z~OKU<{y&O6#!mEqIS@chW6e_p-TlhB-E^40Z($IY*8 z0c&)B5AMV=aoMU;91Vdfhud?&UxpiJjl_Fr3E#F#t*x$+ji_OkpXQ3%!KGKy4fprK zPylAD2sy35Zz?DxYJ`r(`fN==_`@bXamc*?pE>pKV>PXly{?PFL}U`*^!2x^Dd9FX z0&_kU{2@~&-Y!P=O1m~j(}xvX{j$<(B@H+YxuGX7CU#4O9YaI(jgqIIyJ#JLxD!;s z7n)0#Gh}(d5tMwxy!z@`o#QozzT`(p8nXTn_~8b35<^;S#qfRqL9a!1 zDcm`NMf{Wmli(OS{qgDHUqZD)BklDgbD7JttP1J2;gOQrxV57Dp-cVd+nC9ILxvK2 zPQK*t;BS(Z!PsjIhVXp);w8a&jYU);P>V9@2gWV_p$gqAx1iOlu0##Dfc9jx$n85V zBsz?uTBk+Z73w1KC5;&{1H${6tyksjt{%~Mw%JBL6nn(leI~!;q)EkZs)B$>B+*Pc1Is2(c>LBC%2LHS8kDT! zj0xp)sI=3SLOVtY9LBl1@vsSnO3D<16Y3Or0>taeBB>m3^%3EN48+8O$nFS%YM?vW zxn|NV0z;#z^gywU=IE~(ucBbO^aApEjy`{|p)|^Fh^hoz@u!uM)EqT$@9*+l%7_Sl z`LaXyiju*xpEb96>(>-3OVYJ6t5OHngqJ33|Gn3k-Se^|`6e&TjqEBSX+brfXAL}1 zuKq-f6>F1(u976rVL)(Xm*HN^Nw%hPRaQG^$v1VLowy=LOh9G*elj;jV`5c~SC)t= zXea6M`-pmj-Z~t?bOYI(jWu@VZ!=w!f>Y;+MCG%b9jQrj61oD8RoQXf)fmu2`e4W=I!enz7ddq1HUHW(z2ko4)2td?#o>ZXuxy4>3XD!2R7&xF*>q z@gkL@pgVIVn!t%N+(S_?ZGKE*y_`dn_~xA+&$@&Ekjea#ubi%S=dV_l6Jaqjp)zlu z5;v^BYMpj=zKM%!YtoTL$%M7%qmJ5r$(q{k1+@-zH~LNc?8H;-u9=Z_JbQeh^UYJ# zV#E1MhPN-1q~Hk(TJUHf3*swa#)#zSdF1Cu)eY7m332mm{fKoF+P+gF;j*6m^C)lw zuCkXBwM+Bf_HIVBaE4{XvT&1S&hekuTX`pH$F;}`L4kzYFIYGCRGN4Vy0%<8RYbU#=(h|AA9fC%)sy3F6TY=E%wYTf z6g;qc*ZWfF=zd&zcPheq&JhJ!nxqhqoHK!G$kmqe?sMo)oR8`OyDCpEx{|g-^t67` zf0+p|Bi~E5^kr`Hzr3$kF{koiR>fUuZGEJY5@%B04Gc)zp-QB;tR#eOSFfHJkhb^O zcZO}bna#$fMQuFTuv4VXUsO?Wu54G^DY0F|5=+DO*I_`JK;d8N zYbW-9)%5!@_c`fLt)bIHqA%MQOBPy z-MUwh#wWf&&YERLZ098XRCm7dZxh^RGz zn1(>Y({wds#6@ef=Vj7wq3=w`?r4PsYHFRfa^G~%$^n5Ttak^sy1^Pmv=j}j0xp#c zQr3To2->;`DTFAQ9wIPG8sFxpSTqWTHMZE@Ft~;6)S64T*RfBc6BJTP3mC!bmLp}w zPts$UeoRA|jR#Ggf1DC0>r~i+$&3q~_#c2`kumCpQ{0008J^2`Ww@D`F}i*X1)t{Q z`f+n@Yb}c1t<@ZoTt_a>iwM4+4ex%Tv_cO9aQ0oK2jYA+b-GDP2*fWc`0!70+P-Y@ z=yWh+{`gh(aanVWpkva4+k9SUHxrr$tkPMznwUF|;N{TJ~8p2~`e*vT_Hr-W~VWYINwmQLMEr|mzCi>iEk>~w!W1beH zd|!v=JV7pvqHL6t-{7g!D0pt7 zOBn!`jmi*whu|kUpw6GU%SfC+FT!(f&dc)lTe4sJ$@1ScBA*I)GvmXfYDZ_!Gt?6??^e`qyO|)Ia;7rl1wX%PhxrmvP2klFtckCbsO2~+TrPOd zWmtO1hba=cCVz00JJekVd#GFl5x@^`RE?SjgN@?U`l<)%CY*<<#OKn~Uj{#EKmrZ> ztqe<>Ik=s`kK3mlFNA@KCOsg*ZI^+U?Zw^Ov^|cI$O@N?66lqC@+&~*W-CCOGoXR< z>Zs3)?+lpFzzR@Sd|IxW{FL?WyAp1hwht(&2ncL=1q>`XY<8k{H5kOb0xH8o+1`NP%q81P!Za>#XYYS%KrsJ{h>;v zgbAA6r7IZ5Ce6031t&_=E)IL@9X?eWQa%6VVmj8g>c2Tq*NllLDM^vnxfK5sR0Ms|KZEpS_Sq{7Bb&KIdjT>g6A!M ztxidHTWHBqCi>XTB`Y<6vA$Hs`Y9NzJ(U5!bB`0Lz$!@O5b#^XrrknV=A((n;$z!v zGnrqDpicZ4MAL77`6vpbusUHE{*yD4XEj8XAcW~Lz95(Nr$3Ju3YbL6mLy#Xm1rL$ zOnVn>V>GUw`>?7|ird4RE*w1kl$pdSM>cecw>Es~WKT6H>;x?f?cnyYF^hF^vjkF= zz5?7NGlAbRyQ#vT18VfUPT*VbR7Cj>_|9)n46C@-s_*}Pu#d<)#|>HinDBbM^Omw4!s!9 zv`e$dXcYWc?=l%^H84X8zSR9;LzcAC2+RGGcCbr6!TB#W8<2+KLqnZC? zhTSk#3EwbmL!po2X0DcOU0WnLM^3ieJTq0gYLWu+9$mH~{?w&Y(O8FEz{;DT_)d9T ziYaTD(?rIHD6-^tbB(Y4q322S$?Zi(yJlCC%X|#&esNw8PaSS9Bfm+?K&&0lJmM^x z?qIvMroDBN-+6Q-XCCq%B-V$d+=1lrnz&O7`O#iPp=C+?trBz3mCkvzev2eWYugf* zNvk?7xDLpBPx+5;(>eOfNlo|wH^BzmIWIr8P(yOw7%#0 zYF@EdZ<90;TNB#iu)aeg*W(vN%}nP{{Z1O{tzrDj77* z%-kMqC$dPZ3QJiLFcyU`CRV%`xD~u75372=tn#OsbQsa!`}EEx2Kox1VNQX>W; zWBQOlMve2sX?E0ceUQ!5&Il*;qoR-SlHW4EVBMjYnfkb#)Q*JT9n(c+Jk=2%Om~1 z7bIRO)oAQ}5$!hQqWK8%&evMAFUkMHlp2M^?KsWZoWUtHG>i+2Cn7AHgDhbf#?*5N zTyYpw3HOPq7*R#Ndm}!P%HhWz7Y3 zMRgDp##%GUzM(qQ6Pp~mMngSdzOwA;pl1Yy0~(Q0ns)u30M?%e&J-met5mYvS9RNs z$X{e9O2mOM>rwn^=U7_wR0kt_^)he6hShteg(+&Y0v}Myq2@bvLn|6~$T>BgFB7?V5|O5x-0PjDAnD9G!Zb&` zF5!}7um6ZTuz;df=;ol7xr1Njwl%UFv2OLy(=oJMI&!|hcXFxd+c7%DDtIrmBG|;E z?xnwYW%9!~z5LE4pYxu=%;9WFc+58kXq)x79@=N6&Q=%yTVqh13yH~K#Qzmwzi?5| z;#IlnX@*eS2GSI+1@;PL&6Lw-pAs()a^z6Y*}M_wH#VDdh&4CM>IgeM!hkV3JExE$ zQmvZNs8SU6&C3=-b%AwCrMLzw_PXVuZ0l(kR?cXZamI$>w4wO^E?Rydm~-eO8bK?2 zdVrN88$7N1m5XbE`VR7+A-k9pg7n`9Edx z;$f!7>>RbIaGKR@Wf|^DfkuetDB+WcA;lR_5x)hfx>CxT)eI!1z1R|p^YfhsJMcHl zi1&S}?1mOU`hD(<8Lt*ZL1Sgls%`xs7rTgRxywO2rOQZysYJ~8x+tf8%W z1x#35{K(<`%ZVlXhDVsRBKu}k8voT5vYG1Z;8u#yIaEaZ)g_PKmt5IVJm^p)GSgo> zZ0QUeTZmIf$iYKvDXHlI zI65&rI6n}WM^A}kk&wxIXEYcL=|(ib>4`$FYcWvocQHnSX#iOkunu1VwJx73NK=ll zey*xAo-HqZb9@}jX^lUCNS=$K5ALTMQlb{BG|Z^UTffgY_RyWRy_KtfEEGcK*m8}U zo*mg*}6?4@<2!{R=kNq^1h?wK6SC)J*tc{@NLI7VM*aq)i zUTU|m$*ZSnsMzuBLM+y>h>gVj&S$1Vw=$Z&y`c1Yl*HR^aERlP=s0Vzuq*Sk=F(?j zzB)i3=nF%GX1Od*tcGbc!BHKk$CN@Y7JK-6s4#!>{h<2e7c1XM+w8R69hNl68dD~= z!a5rnjTgU!IQ@3Z1Sg|ot?95e|Jdf}TNS$G>CvmUrN#d5j!PAbxr}O6qk_=HcD!JL z%Eyz_k3r;@#@6hH(W1NCXwjE?3yQ?Q6`Fju8;K+0a(@^1v6(E(3FOC@-}neb9N}a{ zOI=bzNrf~qzg}vnn`tz*fPy-N65^9WT7c5RIyLaKNl7;q zv{IF0HuG>l&feZ?+qmhe%fRg^`FT4&*=;V_8Sd>$P^y5Y>D1tv+BjO4w^bm0{RBex$ zvDt%mFK!G()jKNvVpmRSGOKKA5GHP2=L{iK?{bZ>`FD|IoKglPY`x2;(XD92l!S4wc7k+oK7}gOtGq&EuziLiT3g zaoUhmNq7;2Q(7+6Vm4*1%8YH*Dqv0_=zf=u5j<|hm_PWbj)Q@jvqFjpLje?l-BRU{x?KSoah@CX|FIo+(@dq$%ODex+f} zXjJ>0e@k+CJ7nXW*&I_7dRz8k1W%L>RuU5`G9t!yX<64vuA~`E7{et+JN$NM#&qJi~X zElDT*!Oav3Z6Fv{l)WB*b*)qm?PSI)nyX+R1+=KLVGTs2iw4Z7D>)cAQDz2K+#1r>blbHnMnD$a7TsQzmq zSXV!2%XDb6^3Ec8z5PsGaS0PQ@~m!;oEu4Agk^)=C#&Xi_3N?;?Pb3DLjukTVu{JA ze~m9ZTH*jGzUoQacqQk#;q~YHsbv!D5?tjA00>~UQyHebGt#wn$;=l!$`K$*%>?T z294!x_E3HX_?VoNCY)Y9GGU)vI$5%>#gVXmqjFK+#@OZMYz8gF=O|>v((|>Pq@c%ZFTy0a zp1q8pXZmqrqxMptck`S4HF!g#xG9S^RYHXAqxr66k9{l%vd4g#`uwe^`?OyR$Lsy+@`i?im@*7UfY znk~oJGZpSk}(FOV*QmM|iVIbDPSCQA=pz!i<&cscYU-vU5dwOMSrDU1< z-HCL)2VN!Nw8&>RuazN}`2mQFHKoz3KnK0Qq6Q9W?Fzp6t3hD~@CcIXmA9nPnXlWQ z6sEi%HM+f)`A7G5dE8oCS*rFXBHSZ08ju^$9l z=JHmkp;NrwNigU7o}=8iRaAl>v&BvV6qo^7?1udc3|R{N;#9pGnlLgIoo}Ya>=Srg zBBRUrNieQMwfo89u>Z|x80{Mz>+yW~xosgYadL~Vd-|PmhTcH=f^)ti)sj;e-MU|o z$<}rOF>2I_0anLi`^TJ7_hBwPSrhc0K#2kX2|VIi3RM5V?(%J-73F}&Pw z8Ti7kNbvttEj4A(nsCMQKo5R-01=~=3GQ3JfWeJvly!XxJ z*)_Ldme>1XO0z>-HF9uk<9WQ9)zuI;AKs+L9k=VVHz+P51d%?yw2p^{Q?^`DEqj;BuL7YP z7YoqR(%(RLSa>nj#8+pfSZUbsQ_c9j9PLyb)YNOTGt4Egdc_lYGeq8}J$n$7cF`yA zY8FHfB?&tJj}D>hNOrnos0%i`^z#bI0z#T`=${bdll(#_$VLPUh zhq$RWA<9v3%cCXPLH7C0GzWQ8$9+sWldUVp50(VEt>+1~OI7Wfb$a_IXhoUAGASPo zW}O%APPm^EseXWcEC#ezHJshg^hPPmeX7kUFKm|K}gq$DB(%Z zS*5bdu>5y&2w!zxXOzb~^;*+d8%tZAtGZ`m>9}i^!(5NnMYYim#j9*3cVk`)L;NjI zYkatTX!@<7yrt=NZjw&6j8;JxFK5UR1{t*@qK;$-@%C8>8@~w@s&~Fa3Suh(#`YGw z4l(1se)KtdSf+8I=tl->z*3YOJPe^%mK%qlJ88Ym%|soKjF}y(>qC_nc9n)jOACGMqjU3p z#}jrH<|g=_kP0V;g2)1f$mqZwYT)0v*G;X!CbD0NO$P~Cfj1_- zXnele@hx%Xi;aTlUI~u{NyiT&hwhcNMQe0^cEvH-TO~f! zTS|O@OB;(ZJGk+WP95t!ya^c1ox2pkAihH|D$l#`s#VPacEZ``4yax!P?6_%z>p?3#b<+l0?zuEts7^9ZtA=-oVMgoci?YO4G~L zbeTABCmq3wO|HoA;lAIW=&5X3@Ssia$6_6K=CgQb{?S=aYNQ=rN{)0eM#`qv4>Y8| zS(%k47AE~cV2}NNaeKW!0r6&#(EUlL+wCwb! z+&b1^j?IX8AVS^)JdHo-duc&w z{g-=yjT~u?-sYQkIWlfYBlW8P-u%wE9rw`v=L{BcZP82Fh+loDHuG-rB=@GCrB7~` z#iyVyfT>iPk>OYs!YzYoEaz4Z@Pc(wUx42oQdBoV0_@HCOsGa&s?0(^GR5lsIVVkP zy=)G;pVchf4K)EtiAwjm-fzb@hQ2pDoSi?;4E56l>Cp$p4Lb+tNAp7Ltu|B3my*mY ztf}Ja3S9qUjkh&f#X28!Bc@KWYj^AiuI{)+PV5hqv5b`G-BE2dSz-j z_42F+l%7xJkpbv55OLS;O8#?6tQ;p27NI45R@UoU$sp++;lMjJ!RBx-TU`%-lq}Nt-kP&U$rg1C=+4(&WBD(;@e#Go+OWbAiL^=SxO}) z0}=v-=gJ`nQ%}2V`BHsN0W8c;+#DVRHG$;5FJ2pCC8%FMuSD*qXb5=y;Jw9GvcS*r z4adxPy=9L~+o2u?E2sS+4h9gtX|rOjeF-EJ1(H%SE_t~(1psa+`o#rWdB;iofmZnZ zo3Z8&U{gh&LOoW9+kNLf@#s34=lH;~P*9O8Bk;tv!-y&wKno1z5(!RKZ?X_Zv4yHd zt^7sj>OCL3UKkK16{O#;meWoeb|*C?0GCm- zUV=lHRjb6x=QA~NGLZFjI2islSk1H9r}%s6DvgqjtiI_ELu=n+mP=6I-Mxrj`mX?B za(Q%;jz*`->tb+C&kyB)*nXyAhOHEMEZb!>7EHGeB?ndrG!7+0;HuChRe;IHq>PeU zYOnEa%v1dZR$r{eCLbvVc5@ZreANDz0N7^_p zQ5db?5eBB7?jBTRWdV$lot#J0@Z6?>1JrP{z6!eM=o)|cxM6otd(f#s-xGO0z)nFV z4~;H_?v&R>B&L1gtffB*{jpD6Wa&mtr$clOr&kV6IxXvMz^JN>R-4bYyrZIj{`_Im zSnBHx%ltw-=;eladm>NEm%VE%oxy>JIS|4C4nr4Uk)-zlrYlY8Q+XK`ckGruse zu&^ur2wXsOiUFJVBFXsy%|B{0;3~J|5Y-1cBcNVKZXOjWIlbIN)x6WcGsh}ji}T^% zaGwGhJYyM_4?|m*HSYhc;S9n!Dn ztBBrLRF+tA+AF_0!jQ!wzmMeR5!8$W+)~TU{cYg5ma|G-k-MZG_ zq+LYwtPVBomB7Q$d}+cenJF$#hgJb3><1v@$-8H&{h`qS+Pt!|8Cn>3s(91{uTq@q z)csJ)yPP)yLS)@e3oTmA4(bpgHL2iPdThk?Ce7xzX`zL(t;zPHZ6*Y+sDp}?p&fje z;qx59&l9>RGd6`2=aunfKiu?QIjTi&N;tRX!17O-t5tFj?;9F(*wOAv&2${R;oT`| zC~CGQ=b~#x9N{0`a2qZQe{>2k>8}%fQi+97s1(W`?YQk!nfS28{BAx8JwzwHkZXt7 z((fCG<%z*^_m)8u(P}j%)Ih}I!ONl;xhx-NDwEp~9yEBD`RlToT-FW!>_?zG4TEofG32E_& z;m2o*&s-Jn5UVOmZh;{SvS&GQ5vu=A!S6o4b+5ghV}&WS`|o6Y0CAnNzI`;EPCh)5 z%l=-0^N$)1xcon#hMVqHU4m|_=R~1huqyvQIulWG*3DbTbb#HJ*{#U4jRT!7gd9*- z^G|<>PW|Eh9sZ$fQn^E|F^U?jNP#yR6aY&4DEv?!1$6xfGip1g=J;CQ_VV;=Mfw~) zLT5}L0m~b)#%{C3ianaf?^jIZA9@jSyls^lx$n#T@EMfDHP&IEU+uUHR|I(OIHysFKF_(f1#JyzB#eg2Agb zPX8^GJCLcbY@=Zl0iPE-pB-0$b8Pe+YphZYjt2IAJuQAWmiS-brK +To: erikd@fake-domain-name.com +Subject: Can you help with a problem? +Date: Tue, 20 Jul 2004 22:49:21 +0100 + +Hi, + +I'm trying to get the source examples in the "Programming Linux Games" +(NoStarch, Loki Software + John R. Hall) which use sndfile.h/libsndfile. + +While I can guess some of the newer versions of function calls and +enumerations, there are some which I cannot guess. + +Would you be able to translate them to the current version of +enumeration and function calls so that I can update the source? + +These are the three currently failing me: + + sf_open_read(filename, SF_INFO *sfinfo) (guess: sf_open(filename,SFM_READ, &sfinfo)) + SF_FORMAT_PCM (guess: either SF_FORMAT_PCM_U8 or _RAW) + SF_INFO.pcmbitwidth (guess: no idea!) + +There are probably more. I'm happy to send you the source files for +sound calls, scan the pages or anything else. Failing that, is there +somewhere with the changes listed so I can try and fix the code for myself? + +Thanks + +TTFN + +Paul + +================================================================================ + +Date: Wed, 21 Jul 2004 17:38:08 +1000 +From: Erik de Castro Lopo +To: Paul +Subject: Re: Can you help with a problem? + +On Tue, 20 Jul 2004 22:49:21 +0100 +Paul wrote: + +> Hi, +> +> I'm trying to get the source examples in the "Programming Linux Games" +> (NoStarch, Loki Software + John R. Hall) which use sndfile.h/libsndfile. +> +> While I can guess some of the newer versions of function calls and +> enumerations, there are some which I cannot guess. +> +> Would you be able to translate them to the current version of +> enumeration and function calls so that I can update the source? +> +> These are the three currently failing me: +> +> sf_open_read(filename, SF_INFO *sfinfo) (guess: sf_open(filename, +> SFM_READ, &sfinfo)) + +yes. + +> SF_FORMAT_PCM (guess: either SF_FORMAT_PCM_U8 or _RAW) + +Actually this list: + + SF_FORMAT_PCM_U8 + SF_FORMAT_PCM_S8 + SF_FORMAT_PCM_16 + SF_FORMAT_PCM_24 + SF_FORMAT_PCM_32 + +> SF_INFO.pcmbitwidth (guess: no idea!) + +WIth the above change, pcmbitwidth becomes redundant. + +> There are probably more. I'm happy to send you the source files for +> sound calls, scan the pages or anything else. Failing that, is there +> somewhere with the changes listed so I can try and fix the code for +> myself? + +Version 1.0.0 came out some time ago, but I think this: + + http://www.mega-nerd.com/libsndfile/version-1.html + +lists most of the changes. You should also look at the API docs: + + http://www.mega-nerd.com/libsndfile/api.html + +HTH, +Erik +-- ++-----------------------------------------------------------+ + Erik de Castro Lopo nospam@fake-domain-name.com ++-----------------------------------------------------------+ +"There is no reason why anyone would want a computer in their home" +Ken Olson, DEC, 1977 + +================================================================================ + +From: PFJ +To: Erik de Castro Lopo +Subject: Re: Can you help with a problem? +Date: Wed, 21 Jul 2004 09:07:39 +0100 + + +Hi Erik, + +Thanks for getting back to me. + +> > sf_open_read(filename, SF_INFO *sfinfo) (guess: sf_open(filename, SFM_READ, &sfinfo)) +> +> yes. + +Yay! + +> > SF_FORMAT_PCM (guess: either SF_FORMAT_PCM_U8 or _RAW) +> +> Actually this list: +> +> SF_FORMAT_PCM_U8 +> SF_FORMAT_PCM_S8 +> SF_FORMAT_PCM_16 +> SF_FORMAT_PCM_24 +> SF_FORMAT_PCM_32 + +I know, but the source code explicitly has SF_FORMAT_PCM which given the +code afterwards would equate to one of the above, but given that PCM +files can have a varied bitwidth the author probably wanted to cover all +bases. + +> Version 1.0.0 came out some time ago, but I think this: +> +> http://www.mega-nerd.com/libsndfile/version-1.html +> +> lists most of the changes. You should also look at the API docs: +> +> http://www.mega-nerd.com/libsndfile/api.html + +I'll download them and see what I can gleen. + +Thanks again for getting back to me + +TTFN + +Paul + +================================================================================ + +Date: Wed, 21 Jul 2004 18:20:29 +1000 +From: Erik de Castro Lopo +To: PFJ +Subject: Re: Can you help with a problem? + +On Wed, 21 Jul 2004 09:07:39 +0100 +PFJ wrote: + +> I know, but the source code explicitly has SF_FORMAT_PCM which given the +> code afterwards would equate to one of the above, but given that PCM +> files can have a varied bitwidth the author probably wanted to cover all +> bases. + +But surely the existing code does something like: + + sfinfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM; + sfinfo.pcmbitwidth = 16; + +which can be directly translated to: + + sfinfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16; + +and the same for pcmbitwitdhs of 24 and 32. For pcmbitwidth of 8 +you need to know that WAV files use SF_FORMAT_PCM_U8 and AIFF +files use SF_FORMAT_PCM_S8. That's all there is to it. + +Erik +-- ++-----------------------------------------------------------+ + Erik de Castro Lopo nospam@fake-domain-name.com ++-----------------------------------------------------------+ +"Python addresses true pseudocode's two major failings: that it +isn't standardized, and it isn't executable." +- Grant R. Griffin in comp.dsp + +================================================================================ + +Subject: Re: Can you help with a problem? +From: PFJ +To: Erik de Castro Lopo +Date: Wed, 21 Jul 2004 09:50:55 +0100 + +Hi Erik, + +> > I know, but the source code explicitly has SF_FORMAT_PCM which given the +> > code afterwards would equate to one of the above, but given that PCM +> > files can have a varied bitwidth the author probably wanted to cover all +> > bases. +> +> But surely the existing code does something like: +> +> sfinfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM; +> sfinfo.pcmbitwidth = 16; + +If only! + +The actual code is this + +int LoadSoundFile(char *filename, sound_p sound) +{ + SNDFILE *file; + SF_INFO file_info; + short *buffer_short = NULL; + u_int8_t *buffer_8 = NULL; + int16_t *buffer_16 = NULL; + unsigned int i; + + /* Open the file and retrieve sample information. */ + file = sf_open_read(filename, &file_info); + // I've sorted this one already - PFJ + + /* Make sure the format is acceptable. */ + if ((file_info.format & 0x0F) != SF_FORMAT_PCM) { + printf("'%s' is not a PCM-based audio file.\n", filename); + sf_close(file); + return -1; + } + + if ((file_info.pcmbitwidth == 8) && (file_info.channels == 1)) { + sound->format = AL_FORMAT_MONO8; + } else if ((file_info.pcmbitwidth == 8) && (file_info.channels == 2)) { + sound->format = AL_FORMAT_STEREO8; + } else if ((file_info.pcmbitwidth == 16) && (file_info.channels == 1)) { + sound->format = AL_FORMAT_MONO16; + } else if ((file_info.pcmbitwidth == 16) && (file_info.channels == 2)) { + sound->format = AL_FORMAT_STEREO16; + } else { + printf("Unknown sample format in %s.\n", filename); + sf_close(file); + return -1; + } + + /* Allocate buffers. */ + buffer_short = (short *)malloc(file_info.samples * file_info.channels * sizeof (short)); + + buffer_8 = (u_int8_t *)malloc(file_info.samples * file_info.channels * file_info.pcmbitwidth / 8); + + buffer_16 = (int16_t *)buffer_8; + + if (buffer_short == NULL || buffer_8 == NULL) { + printf("Unable to allocate enough memory for '%s'.\n", filename); + goto error_cleanup; + } + + /* Read the entire sound file. */ + if (sf_readf_short(file,buffer_short,file_info.samples) == (size_t)-1) { + printf("Error while reading samples from '%s'.\n", filename); + goto error_cleanup; + } + + + + /* Fill in the sound data structure. */ + sound->freq = file_info.samplerate; + sound->size = file_info.samples * file_info.channels * file_info.pcmbitwidth / 8; + + /* Give our sound data to OpenAL. */ + alGenBuffers(1, &sound->name); + if (alGetError() != AL_NO_ERROR) { + printf("Error creating an AL buffer name for %s.\n", filename); + goto error_cleanup; + } + + alBufferData(sound->name, sound->format, buffer_8, sound->size,sound->freq); + if (alGetError() != AL_NO_ERROR) { + printf("Error sending buffer data to OpenAL for %s.\n", filename); + goto error_cleanup; + } + + /* Close the file and return success. */ + sf_close(file); + free(buffer_short); + free(buffer_8); + + return 0; + + error_cleanup: + if (file != NULL) fclose(file); + free(buffer_short); + free(buffer_8); + return -1; +} + +As you can see, the PCM material in the listing will not currently +compile and for the other sndfile material, it probably won't either. + +Any help would be appreciated. + +TTFN + +Paul + +================================================================================ + +From: Erik de Castro Lopo +To: PFJ +Subject: Re: Can you help with a problem? +Date: Wed, 21 Jul 2004 19:36:46 +1000 + +On Wed, 21 Jul 2004 09:50:55 +0100 +PFJ wrote: + +> Hi Erik, +> +> > > I know, but the source code explicitly has SF_FORMAT_PCM which given the +> > > code afterwards would equate to one of the above, but given that PCM +> > > files can have a varied bitwidth the author probably wanted to cover all +> > > bases. +> > +> > But surely the existing code does something like: +> > +> > sfinfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM; +> > sfinfo.pcmbitwidth = 16; +> +> If only! + +No, really. + +Drop this completely: + +> /* Make sure the format is acceptable. */ +> if ((file_info.format & 0x0F) != SF_FORMAT_PCM) { +> printf("'%s' is not a PCM-based audio file.\n", filename); +> sf_close(file); +> return -1; +> } + +Replace this block: + +> if ((file_info.pcmbitwidth == 8) && (file_info.channels == 1)) { +> sound->format = AL_FORMAT_MONO8; +> } else if ((file_info.pcmbitwidth == 8) && (file_info.channels == 2)) { +> sound->format = AL_FORMAT_STEREO8; +> } else if ((file_info.pcmbitwidth == 16) && (file_info.channels == 1)) { +> sound->format = AL_FORMAT_MONO16; +> } else if ((file_info.pcmbitwidth == 16) && (file_info.channels == 2)) { +> sound->format = AL_FORMAT_STEREO16; +> } else { +> printf("Unknown sample format in %s.\n", filename); +> sf_close(file); +> return -1; +> } + +with: + + int pcmbitwidth = 0; + + if (file_info.format & SF_FORMAT_SUBMASK != SF_FORMAT_PCM_16) + { printf("'%s' is not a PCM-based audio file.\n", filename); + sf_close(file); + return -1; + } + + if (file_info.channels < 1 || file_info.channels > 2) + { printf("'%s' bad channel count.\n", filename); + sf_close(file); + return -1; + } + + switch (file_info.format & SF_FORMAT_SUBMASK + file_info.channels << 16) + { case (SF_FORMAT_PCM_U8 + 1 << 16): + sound->format = AL_FORMAT_MONO8; + pcmbitwidth = 8; + break; + case (SF_FORMAT_PCM_U8 + 2 << 16): + sound->format = AL_FORMAT_STEREO8; + pcmbitwidth = 8; + break; + case (SF_FORMAT_PCM_16 + 1 << 16): + sound->format = AL_FORMAT_MONO16; + pcmbitwidth = 16; + break; + case (SF_FORMAT_PCM_16 + 2 << 16): + sound->format = AL_FORMAT_STEREO16; + pcmbitwidth = 16; + break; + default: + printf("Unknown sample format in %s.\n", filename); + sf_close(file); + return -1; + } + +> /* Allocate buffers. */ +> buffer_short = (short *)malloc(file_info.samples * +> file_info.channels * +> sizeof (short)); +> +> buffer_8 = (u_int8_t *)malloc(file_info.samples * +> file_info.channels * +> file_info.pcmbitwidth / 8); + +Use pcmbitwidth as calculated above. + +> buffer_16 = (int16_t *)buffer_8; +> +> if (buffer_short == NULL || buffer_8 == NULL) { +> printf("Unable to allocate enough memory for '%s'.\n", filename); +> goto error_cleanup; +> } +> +> /* Read the entire sound file. */ +> if (sf_readf_short(file,buffer_short,file_info.samples) == (size_t)- 1) { + +Replace "(size_t) - 1" with " < 0". + +> As you can see, the PCM material in the listing will not currently +> compile and for the other sndfile material, it probably won't either. + +None of the changes above should have been very difficult to figure +out. + +Erik +-- ++-----------------------------------------------------------+ + Erik de Castro Lopo nospam@fake-domain-name.com ++-----------------------------------------------------------+ +Microsoft is finally bringing all of its Windows operating system families +under one roof. It will combine all of the features of CE, stability and +support of ME and the speed of NT. +It will be called Windows CEMENT... + diff --git a/extern/libsndfile-modified/docs/lists.md b/extern/libsndfile-modified/docs/lists.md new file mode 100644 index 000000000..46b25473d --- /dev/null +++ b/extern/libsndfile-modified/docs/lists.md @@ -0,0 +1,27 @@ +--- +layout: page +title: libsndfile Mailing Lists +--- + +# libsndfile Mailing Lists + +**Note**: These mailing lists are not maintained by the libsndfile team anymore. +Use [GitHub issues and pull requests instead](https://docs.github.com/en/free-pro-team@latest/github/collaborating-with-issues-and-pull-requests). + +There are three mailing lists for libsndfile: + + - **libsndfile-announce@mega-nerd.com**   + [Subscribe](mailto:libsndfile-announce-request@mega-nerd.com?subject=subscribe) + A list which will announce each new release of libsndfile. No one can + post to this list except the author. +- **libsndfile-devel@mega-nerd.com**   + [Subscribe](mailto:libsndfile-devel-request@mega-nerd.com?subject=subscribe) + A list for discussing bugs, porting issues and feature requests. + Posting is restricted to subscribers. +- **libsndfile-users@mega-nerd.com**   + [Subscribe](mailto:libsndfile-users-request@mega-nerd.com?subject=subscribe) + A list for discussing the use of libsndfile in other programs. + Posting is restricted to subscribers. + +The libsndfile-devel and libsndfile-users list will automatically receive a copy +of all emails to the libsndfile-announce list. diff --git a/extern/libsndfile-modified/docs/new_file_type_howto.md b/extern/libsndfile-modified/docs/new_file_type_howto.md new file mode 100644 index 000000000..bb4220812 --- /dev/null +++ b/extern/libsndfile-modified/docs/new_file_type_howto.md @@ -0,0 +1,134 @@ +--- +layout: page +--- + +# How to add new file format + + Original : Wed May 23 19:05:07 EST 2001 + Update 1 : Fri Jul 11 22:12:38 EST 2003 + +This document will attempt to explain as fully as possible how to add code to +libsndfile to allow the reading and writing of new file types. By new file +type I particularly mean a new header type rather than a new encoding method +for an existing file type. + +This HOWTO will take the form of a step by step guide. It will assume that you +have all required tools including : + +- gcc +- make (should really be the GNU version) +- autoconf +- automake +- libtool + +These should all be available on the GNU ftp site: . + +To help make these steps clearer let's suppose we are adding support for the +Whacky file format whose files contain 'W','A','C' and 'K' as the first four +bytes of the file format. Lets also assume that Whacky files contain PCM encoded +data. + +## Step 1 + +Create a new .c file in the src/ directory of the libsndfile source tree. The +file name should be reasonable descriptive so that is is obvious that files of +the new type are handled by this file. In this particular case the file might +be named 'whacky.c'. + +## Step 2 + +Add your new source code file to the build process. + +Edit the file src/Makefile.am and add the name of your file handler to the +FILESPECIFIC list of handlers. This list looks something like this: + + FILESPECIFIC = aiff.c au.c au_g72x.c nist.c paf.c raw.c samplitude.c \ + svx.c wav.c wav_float.c wav_gsm610.c wav_ima_adpcm.c \ + wav_ms_adpcm.c + +Then, run the script named 'reconf' in the libsndfile top level directory, +which will run autoconf and other associated tools. Finally run "./configure" +in the top level directory. You may want to use the "--disable-gcc-opt" option +to disable gcc optimisations and make debugging with gdb/ddd easier. + +## Step 3 + +Add a unique identifier for the new file type. + +Edit src/sndfile.h and find the enum containing the SF_FORMAT_XXX identifiers. +Since you will be adding a major file type you should add your identifier to the +top part of the list where the values are above 0x10000 in value. The easiest +way to do this is to find the largest value in the list, add 0x10000 to it and +make that your new identifier value. The identifier should be something like +SF_FORMAT_WACK. + +## Step 4 + +Add code to the file type recogniser function. + +Edit src/sndfile.c and find the function guess_file_type (). This function +reads the first 3 ints of the file and from that makes a guess at the file +type. In our case we would add: + + if (buffer [0] == MAKE_MARKER ('W','A','C','K')) + return SF_FORMAT_WACK ; + +The use of the MAKE_MARKER macro should be pretty obvious and it is defined at +the top of file should you need to have a look at it. + +## Step 5 + +Add a call to your open function from psf_open_file (). + +Edit src/sndfile.c and find the switch statement in psf_open_file (). It starts +like this: + + switch (filetype) + { case SF_FORMAT_WAV : + error = wav_open (psf) ; + break ; + + case SF_FORMAT_AIFF : + error = aiff_open (psf) ; + break ; + +Towards the bottom of this switch statement your should add one for the new file +type. Something like: + + case SF_FORMAT_WACK : + sf_errno = whacky_open (psf) ; + break ; + +## Step 6 + +Add prototypes for new open read and open write functions. + +Edit src/common.h, go to the bottom of the file and add something like + + int whacky_open (SF_PRIVATE *psf) ; + +## Step 7 + +Implement your open read function. The best way to do this is by coding +something much like one of the other file formats. The file src/au.c might be a +good place to start. + +In src/whacky.c you should now implement the function whacky_open() which +was prototyped in src/common.h. This function should return 0 on success and +a non-zero number on error. + +Error values are defined in src/common.h in a enum which starts at SFE_NO_ERROR. +When adding a new error value, you also need to add an error string to the +SndfileErrors array in src/sndfile.c. + +To parse the header of your new file type you should avoid using standard read/ +write/seek functions (and the fread/fwrite/fseek etc) and instead use +psf_binheader_readf () which is implemented and documented in src/common.h. + +During the parsing process, you should also print logging information to +libsndfile's internal log buffer using the psf_log_printf() function. + +At the end of the open read process, you should have set a number of fields in +the SF_PRIVATE structure pointed to by psf. + +**THIS FILE IS INCOMPLETE** diff --git a/extern/libsndfile-modified/docs/octave.md b/extern/libsndfile-modified/docs/octave.md new file mode 100644 index 000000000..f619ca69c --- /dev/null +++ b/extern/libsndfile-modified/docs/octave.md @@ -0,0 +1,71 @@ +--- +layout: page +--- + +# libsndfile and GNU Octave + +[GNU Octave](http://www.octave.org/) is a high-level interactive language for +numerical computations. There are currently two development streams, a stable +2.0.X series and a development 2.1.X series. Octave reads and writes data in +binary formats that were originally developed for +[MATLAB](http://www.mathworks.com/). Version 2.0.X of Octave uses binary data +files compatible with MATLAB version 4.2 while Octave 2.1.X uses binary data +files compatible with MATLAB version 5.0 as well as being able to read the older +MATLAB 4.2 format. + +From version 1.0.1 of libsndfile onwards, libsndfile has the ability of reading +and writing a small subset of the binary data files used by both versions of GNU +Octave. This gives people using GNU Octave for audio based work an easy method +of moving audio data between GNU Octave and other programs which use libsndfile. + +For instance it is now possible to do the following: + +* Load a WAV file into a sound file editor such as + [Sweep](http://www.metadecks.org/software/sweep/). +* Save it as a MAT4 file. +* Load the data into Octave for manipulation. +* Save the modified data. +* Reload it in Sweep. + +Another example would be using the MAT4 or MAT5 file formats as a format which +can be easily loaded into Octave for viewing/analyzing as well as a format which +can be played with command line players such as the one included with +libsndfile. + +## Details + +Octave, like most programming languages, uses variables to store data, and +Octave variables can contain both arrays and matrices. It is also able to store +one or more of these variables in a file. When reading Octave files, libsndfile +expects a file to contain two variables and their associated data. The first +variable should contain a variable holding the file sample rate while the second +variable contains the audio data. + +For example, to generate a sine wave and store it as a binary file which is +compatible with libsndfile, do the following: + + octave:1 > samplerate = 44100 ; + octave:2 > wavedata = sin ((0:1023)*2*pi/1024) ; + octave:3 > save sine.mat samplerate wavedata + +The process of reading and writing files compatible with libsndfile can be made +easier by use of two Octave script files: + + octave:4 > [data fs] = sndfile_load ("sine.mat") ; + octave:5 > sndfile_save ("sine2.mat", data, fs) ; + +In addition, libsndfile contains a command line program which which is able to +play the correct types of Octave files. Using this command line player +**sndfile-play** and a third Octave script file allows Octave data to be played +from within Octave on any of the platforms which **sndfile-play** supports (at +the moment: Linux, MacOS X, Solaris and Win32). + + octave:6 > sndfile_play (data, fs) ; + +These three Octave scripts are installed automatically in Octave's site script +directory when libsndfile is installed (except on Win32) ie when libsndfile is +being installed into /usr/local, the Octave scripts will be installed in +/usr/local/share/octave/site/m/. + +There are some other Octave scripts for audio to be found +[here](http://octave.sourceforge.net/audio/index.html). diff --git a/extern/libsndfile-modified/docs/print.css b/extern/libsndfile-modified/docs/print.css new file mode 100644 index 000000000..deb5b13da --- /dev/null +++ b/extern/libsndfile-modified/docs/print.css @@ -0,0 +1,14 @@ +body { + background:white; + color:black; +} + +h1{ + background:white; + color:black; +} + +h2 { + background:white; + color:#666; +} diff --git a/extern/libsndfile-modified/docs/sndfile_info.md b/extern/libsndfile-modified/docs/sndfile_info.md new file mode 100644 index 000000000..78d3548d6 --- /dev/null +++ b/extern/libsndfile-modified/docs/sndfile_info.md @@ -0,0 +1,36 @@ +--- +layout: page +title: sndfile-info +--- + +Here is an example of the output from the **sndfile-info** program +distributed with libsndfile. + +This file was opened and parsed correctly but had been truncated so that +the values in the **FORM** and **SSND** chunks were incorrect. + +``` + erikd@hendrix > examples/sndfile-info truncated.aiff + truncated.aiff + size : 200000 + FORM : 307474 (should be 199992) + AIFF + COMM : 18 + Sample Rate : 16000 + Samples : 76857 + Channels : 2 + Sample Size : 16 + SSND : 307436 (should be 199946) + Offset : 0 + Block Size : 0 + + -------------------------------- + Sample Rate : 16000 + Frames : 76857 + Channels : 2 + Bit Width : 16 + Format : 0x00020001 + Sections : 1 + Seekable : TRUE + Signal Max : 32766 +``` diff --git a/extern/libsndfile-modified/docs/tutorial.md b/extern/libsndfile-modified/docs/tutorial.md new file mode 100644 index 000000000..848c17526 --- /dev/null +++ b/extern/libsndfile-modified/docs/tutorial.md @@ -0,0 +1,10 @@ +--- +layout: page +--- + +# libsndfile Tutorial + +**More coming soon.** + +For now, the best place to look for example code is the `examples/` directory of the source code distribution and the +libsndfile test suite which is located in the `tests/` directory of the source code distribution. diff --git a/extern/libsndfile-modified/docs/win32.md b/extern/libsndfile-modified/docs/win32.md new file mode 100644 index 000000000..6106517b1 --- /dev/null +++ b/extern/libsndfile-modified/docs/win32.md @@ -0,0 +1,18 @@ +--- +layout: page +--- + +# Building libsndfile on Win32 + +**Note : For pre-compiled binaries for windows, both for win32 and win64, see +the main web page.** + +There are currently two build systems; the official GNU autotool based one and +a more limited and experimental CMake based build system. + +libsndfile is written to be compiled by a compiler which supports large chunks +of the 1999 ISO C Standard (tested with GCC, Clang and Visual Studio 2015). + +It is recommended to use CMake and Visual Studio to build libsndfile on Windows +but you can try the [MinGW](http://www.mingw.org/) compiler suite with Autotools +or CMake buildsystem. diff --git a/extern/libsndfile-modified/examples/generate.c b/extern/libsndfile-modified/examples/generate.c new file mode 100644 index 000000000..9b59f4ade --- /dev/null +++ b/extern/libsndfile-modified/examples/generate.c @@ -0,0 +1,131 @@ +/* +** Copyright (C) 2002-2011 Erik de Castro Lopo +** +** All rights reserved. +** +** 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 author nor the names of any 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 COPYRIGHT OWNER 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 +#include +#include +#include + +#include + +#define BUFFER_LEN 4096 + +static void encode_file (const char *infilename, const char *outfilename, int filetype) ; + +int +main (int argc, char **argv) +{ + if (argc != 2) + { puts ("\nEncode a single input file into a number of different output ") ; + puts ("encodings. These output encodings can then be moved to another ") ; + puts ("OS for testing.\n") ; + puts (" Usage : generate \n") ; + exit (1) ; + } ; + + /* A couple of standard WAV files. Make sure Win32 plays these. */ + encode_file (argv [1], "pcmu8.wav" , SF_FORMAT_WAV | SF_FORMAT_PCM_U8) ; + encode_file (argv [1], "pcm16.wav" , SF_FORMAT_WAV | SF_FORMAT_PCM_16) ; + encode_file (argv [1], "imaadpcm.wav", SF_FORMAT_WAV | SF_FORMAT_MS_ADPCM) ; + encode_file (argv [1], "msadpcm.wav", SF_FORMAT_WAV | SF_FORMAT_IMA_ADPCM) ; + encode_file (argv [1], "gsm610.wav" , SF_FORMAT_WAV | SF_FORMAT_GSM610) ; + + /* Soundforge W64. */ + encode_file (argv [1], "pcmu8.w64" , SF_FORMAT_W64 | SF_FORMAT_PCM_U8) ; + encode_file (argv [1], "pcm16.w64" , SF_FORMAT_W64 | SF_FORMAT_PCM_16) ; + encode_file (argv [1], "imaadpcm.w64", SF_FORMAT_W64 | SF_FORMAT_MS_ADPCM) ; + encode_file (argv [1], "msadpcm.w64", SF_FORMAT_W64 | SF_FORMAT_IMA_ADPCM) ; + encode_file (argv [1], "gsm610.w64" , SF_FORMAT_W64 | SF_FORMAT_GSM610) ; + + return 0 ; +} /* main */ + +/*============================================================================================ +** Helper functions and macros. +*/ + +#define PUT_DOTS(k) \ + { while (k--) \ + putchar ('.') ; \ + putchar (' ') ; \ + } + +/*======================================================================================== +*/ + +static void +encode_file (const char *infilename, const char *outfilename, int filetype) +{ static float buffer [BUFFER_LEN] ; + + SNDFILE *infile, *outfile ; + SF_INFO sfinfo ; + int k, readcount ; + + printf (" %s -> %s ", infilename, outfilename) ; + fflush (stdout) ; + + k = 16 - strlen (outfilename) ; + PUT_DOTS (k) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + if (! (infile = sf_open (infilename, SFM_READ, &sfinfo))) + { printf ("Error : could not open file : %s\n", infilename) ; + puts (sf_strerror (NULL)) ; + exit (1) ; + } + + sfinfo.format = filetype ; + + if (! sf_format_check (&sfinfo)) + { sf_close (infile) ; + printf ("Invalid encoding\n") ; + return ; + } ; + + if (! (outfile = sf_open (outfilename, SFM_WRITE, &sfinfo))) + { printf ("Error : could not open file : %s\n", outfilename) ; + puts (sf_strerror (NULL)) ; + exit (1) ; + } ; + + while ((readcount = (int) sf_read_float (infile, buffer, BUFFER_LEN)) > 0) + sf_write_float (outfile, buffer, readcount) ; + + sf_close (infile) ; + sf_close (outfile) ; + + printf ("ok\n") ; + + return ; +} /* encode_file */ + diff --git a/extern/libsndfile-modified/examples/generate.cs b/extern/libsndfile-modified/examples/generate.cs new file mode 100644 index 000000000..1817856fa --- /dev/null +++ b/extern/libsndfile-modified/examples/generate.cs @@ -0,0 +1,250 @@ +/* (c) 2004 James Robson, http://www.arbingersys.com +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +** +** **************************** +** +** How to use: +** - libsndfile.dll must have already been compiled and be in this +** application's search path +** +** - You must edit this file to point to the file you want to convert. Set +** the following line of code (found in the Main() function further below) +** to the name of a .WAV file that exists on your system. +** 186: string sfn = "input.wav"; +** +** - From a command prompt type +** csc generate.cs +** +** - Run the resulting executable 'generate.exe' +** +** +** Note: You will obviously need the csc compiler and the .NET runtime. I think +** these are freely available for download from Microsoft's website +** (part of the .NET SDK?). +*/ + + +using System; +using System.Runtime.InteropServices; +using sf_count_t = System.Int64; //alias; see SF_INFO struct + +#if PLATFORM_64 +using size_t = System.UInt64; +#else +using size_t = System.UInt32; +#endif + + +class lsndf_example { + + +//sound file formats + public enum lsndf_frmts { + SF_FORMAT_WAV = 0x010000, /* Microsoft WAV format (little endian). */ + SF_FORMAT_AIFF = 0x020000, /* Apple/SGI AIFF format (big endian). */ + SF_FORMAT_AU = 0x030000, /* Sun/NeXT AU format (big endian). */ + SF_FORMAT_RAW = 0x040000, /* RAW PCM data. */ + SF_FORMAT_PAF = 0x050000, /* Ensoniq PARIS file format. */ + SF_FORMAT_SVX = 0x060000, /* Amiga IFF / SVX8 / SV16 format. */ + SF_FORMAT_NIST = 0x070000, /* Sphere NIST format. */ + SF_FORMAT_VOC = 0x080000, /* VOC files. */ + SF_FORMAT_IRCAM = 0x0A0000, /* Berkeley/IRCAM/CARL */ + SF_FORMAT_W64 = 0x0B0000, /* Sonic Foundry's 64 bit RIFF/WAV */ + SF_FORMAT_MAT4 = 0x0C0000, /* Matlab (tm) V4.2 / GNU Octave 2.0 */ + SF_FORMAT_MAT5 = 0x0D0000, /* Matlab (tm) V5.0 / GNU Octave 2.1 */ + SF_FORMAT_PVF = 0x0E0000, /* Portable Voice Format */ + SF_FORMAT_XI = 0x0F0000, /* Fasttracker 2 Extended Instrument */ + SF_FORMAT_HTK = 0x100000, /* HMM Tool Kit format */ + SF_FORMAT_SDS = 0x110000, /* Midi Sample Dump Standard */ + + /* Subtypes from here on. */ + + SF_FORMAT_PCM_S8 = 0x0001, /* Signed 8 bit data */ + SF_FORMAT_PCM_16 = 0x0002, /* Signed 16 bit data */ + SF_FORMAT_PCM_24 = 0x0003, /* Signed 24 bit data */ + SF_FORMAT_PCM_32 = 0x0004, /* Signed 32 bit data */ + + SF_FORMAT_PCM_U8 = 0x0005, /* Unsigned 8 bit data (WAV and RAW only) */ + + SF_FORMAT_FLOAT = 0x0006, /* 32 bit float data */ + SF_FORMAT_DOUBLE = 0x0007, /* 64 bit float data */ + + SF_FORMAT_ULAW = 0x0010, /* U-Law encoded. */ + SF_FORMAT_ALAW = 0x0011, /* A-Law encoded. */ + SF_FORMAT_IMA_ADPCM = 0x0012, /* IMA ADPCM. */ + SF_FORMAT_MS_ADPCM = 0x0013, /* Microsoft ADPCM. */ + + SF_FORMAT_GSM610 = 0x0020, /* GSM 6.10 encoding. */ + SF_FORMAT_VOX_ADPCM = 0x0021, /* OKI / Dialogix ADPCM */ + + SF_FORMAT_G721_32 = 0x0030, /* 32kbs G721 ADPCM encoding. */ + SF_FORMAT_G723_24 = 0x0031, /* 24kbs G723 ADPCM encoding. */ + SF_FORMAT_G723_40 = 0x0032, /* 40kbs G723 ADPCM encoding. */ + + SF_FORMAT_DWVW_12 = 0x0040, /* 12 bit Delta Width Variable Word encoding. */ + SF_FORMAT_DWVW_16 = 0x0041, /* 16 bit Delta Width Variable Word encoding. */ + SF_FORMAT_DWVW_24 = 0x0042, /* 24 bit Delta Width Variable Word encoding. */ + SF_FORMAT_DWVW_N = 0x0043, /* N bit Delta Width Variable Word encoding. */ + + SF_FORMAT_DPCM_8 = 0x0050, /* 8 bit differential PCM (XI only) */ + SF_FORMAT_DPCM_16 = 0x0051, /* 16 bit differential PCM (XI only) */ + + + /* Endian-ness options. */ + + SF_ENDIAN_FILE = 0x00000000, /* Default file endian-ness. */ + SF_ENDIAN_LITTLE = 0x10000000, /* Force little endian-ness. */ + SF_ENDIAN_BIG = 0x20000000, /* Force big endian-ness. */ + SF_ENDIAN_CPU = 0x30000000, /* Force CPU endian-ness. */ + + SF_FORMAT_SUBMASK = 0x0000FFFF, + SF_FORMAT_TYPEMASK = 0x0FFF0000, + SF_FORMAT_ENDMASK = 0x30000000 + } + + +//modes and other + public enum lsndf_tf + { /* True and false */ + SF_FALSE = 0, + SF_TRUE = 1, + + /* Modes for opening files. */ + SFM_READ = 0x10, + SFM_WRITE = 0x20, + SFM_RDWR = 0x30 + } + + +//important SF_INFO structure + [StructLayout(LayoutKind.Sequential)] + public struct SF_INFO + { + public sf_count_t frames ; // Used to be called samples. Changed to avoid confusion. + public int samplerate ; + public int channels ; + public int format ; + public int sections ; + public int seekable ; + }; + + +//function declarations +//Note: Not all functions have been prototyped here. Only the ones necessary to +// make this application work. The below code should give some clues as to +// how to add the rest since they have a lot of parameter and return type +// similarities. + [DllImport("libsndfile.dll")] + public static extern IntPtr sf_open ([MarshalAs(UnmanagedType.LPStr)] string path, int mode, ref SF_INFO sfinfo); + + [DllImport("libsndfile.dll")] + static extern int sf_error (IntPtr sndfile); + + [DllImport("libsndfile.dll")] + static extern IntPtr sf_strerror (IntPtr sndfile); + + [DllImport("libsndfile.dll")] + static extern int sf_format_check (ref SF_INFO info); + + [DllImport("libsndfile.dll")] + static extern sf_count_t sf_read_float (IntPtr sndfile, float[] ptr, sf_count_t items); + + [DllImport("libsndfile.dll")] + static extern sf_count_t sf_write_float (IntPtr sndfile, float[] ptr, sf_count_t items); + + [DllImport("libsndfile.dll")] + static extern int sf_close (IntPtr sndfile); + + + public const sf_count_t BUFFER_LEN = 4096; + + +//program entry + static void Main( ) { + + +//declarations + SF_INFO sfinfo = new SF_INFO(); + float[] buffer = new float[BUFFER_LEN]; + sf_count_t rcnt; + +//set the input file + string sfn = "input.wav"; //set to a file on YOUR system + //string sfn = "noexist.wav"; //test with non-existent file + +//set the output file + string ofn = "output.wav"; + +//read in sound file to convert + IntPtr infile = sf_open (sfn, (int)lsndf_tf.SFM_READ, ref sfinfo); + +//exit if error was thrown + if ( (int)infile == 0 ) { + Console.WriteLine("Error opening " + sfn); + Console.WriteLine("Error #" + sf_error(infile)); + return; + } + +//set the file type for the output file +//uncomment one and only one of the statements below to change the output +//file encoding. + //sfinfo.format = (int)(lsndf_frmts.SF_FORMAT_WAV | lsndf_frmts.SF_FORMAT_PCM_U8); + //sfinfo.format = (int)(lsndf_frmts.SF_FORMAT_WAV | lsndf_frmts.SF_FORMAT_PCM_16); + //sfinfo.format = (int)(lsndf_frmts.SF_FORMAT_WAV | lsndf_frmts.SF_FORMAT_MS_ADPCM); + sfinfo.format = (int)(lsndf_frmts.SF_FORMAT_WAV | lsndf_frmts.SF_FORMAT_IMA_ADPCM); + //sfinfo.format = (int)(lsndf_frmts.SF_FORMAT_WAV | lsndf_frmts.SF_FORMAT_GSM610); + /* Soundforge W64. */ + //sfinfo.format = (int)(lsndf_frmts.SF_FORMAT_W64 | lsndf_frmts.SF_FORMAT_PCM_U8); + //sfinfo.format = (int)(lsndf_frmts.SF_FORMAT_W64 | lsndf_frmts.SF_FORMAT_PCM_16); + //sfinfo.format = (int)(lsndf_frmts.SF_FORMAT_W64 | lsndf_frmts.SF_FORMAT_MS_ADPCM); + //sfinfo.format = (int)(lsndf_frmts.SF_FORMAT_W64 | lsndf_frmts.SF_FORMAT_IMA_ADPCM); + //sfinfo.format = (int)(lsndf_frmts.SF_FORMAT_W64 | lsndf_frmts.SF_FORMAT_GSM610); + + +//check that SF_INFO is valid + if ( sf_format_check(ref sfinfo) == 0 ) { + Console.WriteLine("sf_format_check failed. Invalid encoding"); + return; + } + +//open output file + IntPtr outfile = sf_open (ofn, (int)lsndf_tf.SFM_WRITE, ref sfinfo); + +//exit if error was thrown + if ( (int)outfile == 0 ) { + Console.WriteLine("Error opening " + ofn); + Console.WriteLine("Error #" + sf_error(outfile)); + return; + } + +//infile -> outfile + Console.Write(sfn + " -> " + ofn); + while ( (rcnt = sf_read_float (infile, buffer, BUFFER_LEN)) > 0) { + Console.Write("."); + sf_write_float (outfile, buffer, BUFFER_LEN); + } + Console.WriteLine("done."); + +//close up shop + sf_close(infile); + sf_close(outfile); + + + } //main() + + +} //class lsndf_example {} + diff --git a/extern/libsndfile-modified/examples/list_formats.c b/extern/libsndfile-modified/examples/list_formats.c new file mode 100644 index 000000000..348c81b07 --- /dev/null +++ b/extern/libsndfile-modified/examples/list_formats.c @@ -0,0 +1,76 @@ +/* +** Copyright (C) 2001-2014 Erik de Castro Lopo +** +** All rights reserved. +** +** 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 author nor the names of any 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 COPYRIGHT OWNER 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 +#include +#include +#include + +#include + +int +main (void) +{ SF_FORMAT_INFO info ; + SF_INFO sfinfo ; + int format, major_count, subtype_count, m, s ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + printf ("Version : %s\n\n", sf_version_string ()) ; + + sf_command (NULL, SFC_GET_FORMAT_MAJOR_COUNT, &major_count, sizeof (int)) ; + sf_command (NULL, SFC_GET_FORMAT_SUBTYPE_COUNT, &subtype_count, sizeof (int)) ; + + sfinfo.channels = 1 ; + for (m = 0 ; m < major_count ; m++) + { info.format = m ; + sf_command (NULL, SFC_GET_FORMAT_MAJOR, &info, sizeof (info)) ; + printf ("%s (extension \"%s\")\n", info.name, info.extension) ; + + format = info.format ; + + for (s = 0 ; s < subtype_count ; s++) + { info.format = s ; + sf_command (NULL, SFC_GET_FORMAT_SUBTYPE, &info, sizeof (info)) ; + + format = (format & SF_FORMAT_TYPEMASK) | info.format ; + + sfinfo.format = format ; + if (sf_format_check (&sfinfo)) + printf (" %s\n", info.name) ; + } ; + puts ("") ; + } ; + puts ("") ; + + return 0 ; +} /* main */ + diff --git a/extern/libsndfile-modified/examples/make_sine.c b/extern/libsndfile-modified/examples/make_sine.c new file mode 100644 index 000000000..b905b2af5 --- /dev/null +++ b/extern/libsndfile-modified/examples/make_sine.c @@ -0,0 +1,100 @@ +/* +** Copyright (C) 1999-2012 Erik de Castro Lopo +** +** All rights reserved. +** +** 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 author nor the names of any 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 COPYRIGHT OWNER 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 +#include +#include +#include + +#include + +#ifndef M_PI +#define M_PI 3.14159265358979323846264338 +#endif + +#define SAMPLE_RATE 44100 +#define SAMPLE_COUNT (SAMPLE_RATE * 4) /* 4 seconds */ +#define AMPLITUDE (1.0 * 0x7F000000) +#define LEFT_FREQ (344.0 / SAMPLE_RATE) +#define RIGHT_FREQ (466.0 / SAMPLE_RATE) + +int +main (void) +{ SNDFILE *file ; + SF_INFO sfinfo ; + int k ; + int *buffer ; + + if (! (buffer = malloc (2 * SAMPLE_COUNT * sizeof (int)))) + { printf ("Error : Malloc failed.\n") ; + return 1 ; + } ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + sfinfo.samplerate = SAMPLE_RATE ; + sfinfo.frames = SAMPLE_COUNT ; + sfinfo.channels = 2 ; + sfinfo.format = (SF_FORMAT_WAV | SF_FORMAT_PCM_24) ; + + if (! (file = sf_open ("sine.wav", SFM_WRITE, &sfinfo))) + { printf ("Error : Not able to open output file.\n") ; + free (buffer) ; + return 1 ; + } ; + + if (sfinfo.channels == 1) + { for (k = 0 ; k < SAMPLE_COUNT ; k++) + buffer [k] = (int) (AMPLITUDE * sin (LEFT_FREQ * 2 * k * M_PI)) ; + } + else if (sfinfo.channels == 2) + { for (k = 0 ; k < SAMPLE_COUNT ; k++) + { buffer [2 * k] = (int) (AMPLITUDE * sin (LEFT_FREQ * 2 * k * M_PI)) ; + buffer [2 * k + 1] = (int) (AMPLITUDE * sin (RIGHT_FREQ * 2 * k * M_PI)) ; + } ; + } + else + { printf ("Error : make_sine can only generate mono or stereo files.\n") ; + sf_close (file) ; + free (buffer) ; + return 1 ; + } ; + + if (sf_write_int (file, buffer, sfinfo.channels * SAMPLE_COUNT) != + sfinfo.channels * SAMPLE_COUNT) + puts (sf_strerror (file)) ; + + sf_close (file) ; + free (buffer) ; + return 0 ; +} /* main */ + diff --git a/extern/libsndfile-modified/examples/sfprocess.c b/extern/libsndfile-modified/examples/sfprocess.c new file mode 100644 index 000000000..ce1bda8aa --- /dev/null +++ b/extern/libsndfile-modified/examples/sfprocess.c @@ -0,0 +1,144 @@ +/* +** Copyright (C) 2001-2013 Erik de Castro Lopo +** +** All rights reserved. +** +** 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 author nor the names of any 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 COPYRIGHT OWNER 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 +#include + +/* Include this header file to use functions from libsndfile. */ +#include + +/* This will be the length of the buffer used to hold.frames while +** we process them. +*/ +#define BUFFER_LEN 1024 + +/* libsndfile can handle more than 6 channels but we'll restrict it to 6. */ +#define MAX_CHANNELS 6 + +/* Function prototype. */ +static void process_data (double *data, int count, int channels) ; + + +int +main (void) +{ /* This is a buffer of double precision floating point values + ** which will hold our data while we process it. + */ + static double data [BUFFER_LEN] ; + + /* A SNDFILE is very much like a FILE in the Standard C library. The + ** sf_open function return an SNDFILE* pointer when they sucessfully + ** open the specified file. + */ + SNDFILE *infile, *outfile ; + + /* A pointer to an SF_INFO struct is passed to sf_open. + ** On read, the library fills this struct with information about the file. + ** On write, the struct must be filled in before calling sf_open. + */ + SF_INFO sfinfo ; + int readcount ; + const char *infilename = "input.wav" ; + const char *outfilename = "output.wav" ; + + /* The SF_INFO struct must be initialized before using it. + */ + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + /* Here's where we open the input file. We pass sf_open the file name and + ** a pointer to an SF_INFO struct. + ** On successful open, sf_open returns a SNDFILE* pointer which is used + ** for all subsequent operations on that file. + ** If an error occurs during sf_open, the function returns a NULL pointer. + ** + ** If you are trying to open a raw headerless file you will need to set the + ** format and channels fields of sfinfo before calling sf_open(). For + ** instance to open a raw 16 bit stereo PCM file you would need the following + ** two lines: + ** + ** sfinfo.format = SF_FORMAT_RAW | SF_FORMAT_PCM_16 ; + ** sfinfo.channels = 2 ; + */ + if (! (infile = sf_open (infilename, SFM_READ, &sfinfo))) + { /* Open failed so print an error message. */ + printf ("Not able to open input file %s.\n", infilename) ; + /* Print the error message from libsndfile. */ + puts (sf_strerror (NULL)) ; + return 1 ; + } ; + + if (sfinfo.channels > MAX_CHANNELS) + { printf ("Not able to process more than %d channels\n", MAX_CHANNELS) ; + sf_close (infile) ; + return 1 ; + } ; + /* Open the output file. */ + if (! (outfile = sf_open (outfilename, SFM_WRITE, &sfinfo))) + { printf ("Not able to open output file %s.\n", outfilename) ; + puts (sf_strerror (NULL)) ; + sf_close (infile) ; + return 1 ; + } ; + + /* While there are.frames in the input file, read them, process + ** them and write them to the output file. + */ + while ((readcount = (int) sf_read_double (infile, data, BUFFER_LEN))) + { process_data (data, readcount, sfinfo.channels) ; + sf_write_double (outfile, data, readcount) ; + } ; + + /* Close input and output files. */ + sf_close (infile) ; + sf_close (outfile) ; + + return 0 ; +} /* main */ + +static void +process_data (double *data, int count, int channels) +{ double channel_gain [MAX_CHANNELS] = { 0.5, 0.8, 0.1, 0.4, 0.4, 0.9 } ; + int k, chan ; + + /* Process the data here. + ** If the soundfile contains more then 1 channel you need to take care of + ** the data interleaving youself. + ** Current we just apply a channel dependant gain. + */ + + for (chan = 0 ; chan < channels ; chan ++) + for (k = chan ; k < count ; k+= channels) + data [k] *= channel_gain [chan] ; + + return ; +} /* process_data */ + diff --git a/extern/libsndfile-modified/examples/sndfile-loopify.c b/extern/libsndfile-modified/examples/sndfile-loopify.c new file mode 100644 index 000000000..12b6b6bb6 --- /dev/null +++ b/extern/libsndfile-modified/examples/sndfile-loopify.c @@ -0,0 +1,175 @@ +/* +** Copyright (C) 1999-2015 Erik de Castro Lopo +** +** All rights reserved. +** +** 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 author nor the names of any 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 COPYRIGHT OWNER 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. +*/ + +/* +** A quick/rough hack to add SF_INSTRUMENT data to a file. It compiles, but +** no guarantees beyond that. Happy to receive patches to fix/improve it. +** +** Code for this was stolen from programs/sndfile-convert.c and related code. +*/ + +#include +#include +#include +#include + +#include + +#define BUFFER_LEN (1 << 14) + +const char * program_name (const char * argv0) ; +static void sfe_copy_data_int (SNDFILE *outfile, SNDFILE *infile, int channels) ; +static void add_instrument_data (SNDFILE *outfile, const SF_INFO * in_info) ; + +static void +usage_exit (const char *progname) +{ + printf ("\nUsage : %s \n", progname) ; + puts ("") ; + exit (1) ; +} /* usage_exit */ + +int +main (int argc, char * argv []) +{ const char *progname, *infilename, *outfilename ; + SNDFILE *infile = NULL, *outfile = NULL ; + SF_INFO in_sfinfo, out_sfinfo ; + + progname = program_name (argv [0]) ; + + if (argc < 3 || argc > 5) + usage_exit (progname) ; + + infilename = argv [argc-2] ; + outfilename = argv [argc-1] ; + + if (strcmp (infilename, outfilename) == 0) + { printf ("Error : Input and output filenames are the same.\n\n") ; + usage_exit (progname) ; + } ; + + if (strlen (infilename) > 1 && infilename [0] == '-') + { printf ("Error : Input filename (%s) looks like an option.\n\n", infilename) ; + usage_exit (progname) ; + } ; + + if (outfilename [0] == '-') + { printf ("Error : Output filename (%s) looks like an option.\n\n", outfilename) ; + usage_exit (progname) ; + } ; + + memset (&in_sfinfo, 0, sizeof (in_sfinfo)) ; + + if ((infile = sf_open (infilename, SFM_READ, &in_sfinfo)) == NULL) + { printf ("Not able to open input file %s.\n", infilename) ; + puts (sf_strerror (NULL)) ; + return 1 ; + } ; + + memcpy (&out_sfinfo, &in_sfinfo, sizeof (out_sfinfo)) ; + /* Open the output file. */ + if ((outfile = sf_open (outfilename, SFM_WRITE, &out_sfinfo)) == NULL) + { printf ("Not able to open output file %s : %s\n", outfilename, sf_strerror (NULL)) ; + sf_close (infile) ; + return 1 ; + } ; + + /* Add the loop data */ + add_instrument_data (outfile, &in_sfinfo) ; + + /* Copy the audio data */ + sfe_copy_data_int (outfile, infile, in_sfinfo.channels) ; + + sf_close (infile) ; + sf_close (outfile) ; + + return 0 ; +} /* main */ + +const char * +program_name (const char * argv0) +{ const char * tmp ; + + tmp = strrchr (argv0, '/') ; + argv0 = tmp ? tmp + 1 : argv0 ; + + /* Remove leading libtool name mangling. */ + if (strstr (argv0, "lt-") == argv0) + return argv0 + 3 ; + + return argv0 ; +} /* program_name */ + +static void +sfe_copy_data_int (SNDFILE *outfile, SNDFILE *infile, int channels) +{ static int data [BUFFER_LEN] ; + int frames, readcount ; + + frames = BUFFER_LEN / channels ; + readcount = frames ; + + while (readcount > 0) + { readcount = (int) sf_readf_int (infile, data, frames) ; + sf_writef_int (outfile, data, readcount) ; + } ; + + return ; +} /* sfe_copy_data_int */ + +static void +add_instrument_data (SNDFILE *file, const SF_INFO *info) +{ SF_INSTRUMENT instr ; + + memset (&instr, 0, sizeof (instr)) ; + + instr.gain = 1 ; + instr.basenote = 0 ; + instr.detune = 0 ; + instr.velocity_lo = 0 ; + instr.velocity_hi = 0 ; + instr.key_lo = 0 ; + instr.key_hi = 0 ; + instr.loop_count = 1 ; + + instr.loops [0].mode = SF_LOOP_FORWARD ; + instr.loops [0].start = 0 ; + instr.loops [0].end = info->frames ; + instr.loops [0].count = 0 ; + + if (sf_command (file, SFC_SET_INSTRUMENT, &instr, sizeof (instr)) == SF_FALSE) + { printf ("\n\nLine %d : sf_command (SFC_SET_INSTRUMENT) failed.\n\n", __LINE__) ; + exit (1) ; + } ; + + return ; +} /* add_instrument_data */ + diff --git a/extern/libsndfile-modified/examples/sndfile-to-text.c b/extern/libsndfile-modified/examples/sndfile-to-text.c new file mode 100644 index 000000000..58ee06947 --- /dev/null +++ b/extern/libsndfile-modified/examples/sndfile-to-text.c @@ -0,0 +1,168 @@ +/* +** Copyright (C) 2008-2016 Erik de Castro Lopo +** +** All rights reserved. +** +** 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 author nor the names of any 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 COPYRIGHT OWNER 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 +#include +#include +#include +#include + +#include + +#define BLOCK_SIZE 4096 + +#ifdef DBL_DECIMAL_DIG + #define OP_DBL_Digs (DBL_DECIMAL_DIG) +#else + #ifdef DECIMAL_DIG + #define OP_DBL_Digs (DECIMAL_DIG) + #else + #define OP_DBL_Digs (DBL_DIG + 3) + #endif +#endif + +static void +print_usage (char *progname) +{ printf ("\nUsage : %s [--full-precision] \n", progname) ; + puts ("\n" + " Where the output file will contain a line for each frame\n" + " and a column for each channel.\n" + ) ; + +} /* print_usage */ + +static int +convert_to_text (SNDFILE * infile, FILE * outfile, int channels, int full_precision) +{ float *buf ; + sf_count_t frames ; + int k, m, readcount ; + + buf = malloc (BLOCK_SIZE * sizeof (float)) ; + if (buf == NULL) + { printf ("Error : Out of memory.\n\n") ; + return 1 ; + } ; + + frames = BLOCK_SIZE / channels ; + + while ((readcount = (int) sf_readf_float (infile, buf, frames)) > 0) + { for (k = 0 ; k < readcount ; k++) + { for (m = 0 ; m < channels ; m++) + if (full_precision) + fprintf (outfile, " %.*e", OP_DBL_Digs - 1, buf [k * channels + m]) ; + else + fprintf (outfile, " % 12.10f", buf [k * channels + m]) ; + fprintf (outfile, "\n") ; + } ; + } ; + + free (buf) ; + + return 0 ; +} /* convert_to_text */ + +int +main (int argc, char * argv []) +{ char *progname, *infilename, *outfilename ; + SNDFILE *infile = NULL ; + FILE *outfile = NULL ; + SF_INFO sfinfo ; + int full_precision = 0 ; + int ret = 1 ; + + progname = strrchr (argv [0], '/') ; + progname = progname ? progname + 1 : argv [0] ; + + switch (argc) + { case 4 : + if (!strcmp ("--full-precision", argv [3])) + { print_usage (progname) ; + goto cleanup ; + } ; + full_precision = 1 ; + argv++ ; + case 3 : + break ; + default: + print_usage (progname) ; + goto cleanup ; + } ; + + infilename = argv [1] ; + outfilename = argv [2] ; + + if (strcmp (infilename, outfilename) == 0) + { printf ("Error : Input and output filenames are the same.\n\n") ; + print_usage (progname) ; + goto cleanup ; + } ; + + if (infilename [0] == '-') + { printf ("Error : Input filename (%s) looks like an option.\n\n", infilename) ; + print_usage (progname) ; + goto cleanup ; + } ; + + if (outfilename [0] == '-') + { printf ("Error : Output filename (%s) looks like an option.\n\n", outfilename) ; + print_usage (progname) ; + goto cleanup ; + } ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + if ((infile = sf_open (infilename, SFM_READ, &sfinfo)) == NULL) + { printf ("Not able to open input file %s.\n", infilename) ; + puts (sf_strerror (NULL)) ; + goto cleanup ; + } ; + + /* Open the output file. */ + if ((outfile = fopen (outfilename, "w")) == NULL) + { printf ("Not able to open output file %s : %s\n", outfilename, sf_strerror (NULL)) ; + goto cleanup ; + } ; + + fprintf (outfile, "# Converted from file %s.\n", infilename) ; + fprintf (outfile, "# Channels %d, Sample rate %d\n", sfinfo.channels, sfinfo.samplerate) ; + + ret = convert_to_text (infile, outfile, sfinfo.channels, full_precision) ; + +cleanup : + + sf_close (infile) ; + if (outfile != NULL) + fclose (outfile) ; + + return ret ; +} /* main */ + diff --git a/extern/libsndfile-modified/examples/sndfilehandle.cc b/extern/libsndfile-modified/examples/sndfilehandle.cc new file mode 100644 index 000000000..c9a1931ae --- /dev/null +++ b/extern/libsndfile-modified/examples/sndfilehandle.cc @@ -0,0 +1,84 @@ +/* +** Copyright (C) 2007-2011 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include +#include + +#include + +#define BUFFER_LEN 1024 + +static void +create_file (const char * fname, int format) +{ static short buffer [BUFFER_LEN] ; + + SndfileHandle file ; + int channels = 2 ; + int srate = 48000 ; + + printf ("Creating file named '%s'\n", fname) ; + + file = SndfileHandle (fname, SFM_WRITE, format, channels, srate) ; + + memset (buffer, 0, sizeof (buffer)) ; + + file.write (buffer, BUFFER_LEN) ; + + puts ("") ; + /* + ** The SndfileHandle object will automatically close the file and + ** release all allocated memory when the object goes out of scope. + ** This is the Resource Acquisition Is Initailization idom. + ** See : http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization + */ +} /* create_file */ + +static void +read_file (const char * fname) +{ static short buffer [BUFFER_LEN] ; + + SndfileHandle file ; + + file = SndfileHandle (fname) ; + + printf ("Opened file '%s'\n", fname) ; + printf (" Sample rate : %d\n", file.samplerate ()) ; + printf (" Channels : %d\n", file.channels ()) ; + + file.read (buffer, BUFFER_LEN) ; + + puts ("") ; + + /* RAII takes care of destroying SndfileHandle object. */ +} /* read_file */ + +int +main (void) +{ const char * fname = "test.wav" ; + + puts ("\nSimple example showing usage of the C++ SndfileHandle object.\n") ; + + create_file (fname, SF_FORMAT_WAV | SF_FORMAT_PCM_16) ; + + read_file (fname) ; + + puts ("Done.\n") ; + return 0 ; +} /* main */ + + diff --git a/extern/libsndfile-modified/include/sndfile.hh b/extern/libsndfile-modified/include/sndfile.hh new file mode 100644 index 000000000..f8beb719e --- /dev/null +++ b/extern/libsndfile-modified/include/sndfile.hh @@ -0,0 +1,484 @@ +/* +** Copyright (C) 2005-2017 Erik de Castro Lopo +** +** All rights reserved. +** +** 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 author nor the names of any 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 COPYRIGHT OWNER 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. +*/ + +/* +** The above modified BSD style license (GPL and LGPL compatible) applies to +** this file. It does not apply to libsndfile itself which is released under +** the GNU LGPL or the libsndfile test suite which is released under the GNU +** GPL. +** This means that this header file can be used under this modified BSD style +** license, but the LGPL still holds for the libsndfile library itself. +*/ + +/* +** sndfile.hh -- A lightweight C++ wrapper for the libsndfile API. +** +** All the methods are inlines and all functionality is contained in this +** file. There is no separate implementation file. +** +** API documentation is in the doc/ directory of the source code tarball +** and at http://libsndfile.github.io/libsndfile/api.html. +** +** This file is intended to compile with C++98 and newer. +*/ + +#ifndef SNDFILE_HH +#define SNDFILE_HH + +#include + +#include +#include // for std::nothrow + +#if ((defined (_MSC_VER) && (_MSC_VER >= 1600)) || (__cplusplus >= 201100L)) +#define SF_NULL nullptr +#else +#define SF_NULL NULL +#endif + +class SndfileHandle +{ private : + struct SNDFILE_ref + { SNDFILE_ref (void) ; + ~SNDFILE_ref (void) ; + + SNDFILE *sf ; + SF_INFO sfinfo ; + int ref ; + } ; + + SNDFILE_ref *p ; + + public : + /* Default constructor */ + SndfileHandle (void) : p (SF_NULL) {} ; + SndfileHandle (const char *path, int mode = SFM_READ, + int format = 0, int channels = 0, int samplerate = 0) ; + SndfileHandle (std::string const & path, int mode = SFM_READ, + int format = 0, int channels = 0, int samplerate = 0) ; + SndfileHandle (int fd, bool close_desc, int mode = SFM_READ, + int format = 0, int channels = 0, int samplerate = 0) ; + SndfileHandle (SF_VIRTUAL_IO &sfvirtual, void *user_data, int mode = SFM_READ, + int format = 0, int channels = 0, int samplerate = 0) ; + +#ifdef _WIN32 + SndfileHandle (const wchar_t *wpath, int mode = SFM_READ, + int format = 0, int channels = 0, int samplerate = 0) ; +#endif + + ~SndfileHandle (void) ; + + SndfileHandle (const SndfileHandle &orig) ; + SndfileHandle & operator = (const SndfileHandle &rhs) ; + +#if (__cplusplus >= 201100L) + SndfileHandle (SndfileHandle &&orig) noexcept ; + SndfileHandle & operator = (SndfileHandle &&rhs) noexcept ; +#endif + + /* Mainly for debugging/testing. */ + int refCount (void) const { return (p == SF_NULL) ? 0 : p->ref ; } + + operator bool () const { return (p != SF_NULL) ; } + + bool operator == (const SndfileHandle &rhs) const { return (p == rhs.p) ; } + + sf_count_t frames (void) const { return p ? p->sfinfo.frames : 0 ; } + int format (void) const { return p ? p->sfinfo.format : 0 ; } + int channels (void) const { return p ? p->sfinfo.channels : 0 ; } + int samplerate (void) const { return p ? p->sfinfo.samplerate : 0 ; } + + int error (void) const ; + const char * strError (void) const ; + + int command (int cmd, void *data, int datasize) ; + + sf_count_t seek (sf_count_t frames, int whence) ; + + void writeSync (void) ; + + int setString (int str_type, const char* str) ; + + const char* getString (int str_type) const ; + + static int formatCheck (int format, int channels, int samplerate) ; + + sf_count_t read (short *ptr, sf_count_t items) ; + sf_count_t read (int *ptr, sf_count_t items) ; + sf_count_t read (float *ptr, sf_count_t items) ; + sf_count_t read (double *ptr, sf_count_t items) ; + + sf_count_t write (const short *ptr, sf_count_t items) ; + sf_count_t write (const int *ptr, sf_count_t items) ; + sf_count_t write (const float *ptr, sf_count_t items) ; + sf_count_t write (const double *ptr, sf_count_t items) ; + + sf_count_t readf (short *ptr, sf_count_t frames) ; + sf_count_t readf (int *ptr, sf_count_t frames) ; + sf_count_t readf (float *ptr, sf_count_t frames) ; + sf_count_t readf (double *ptr, sf_count_t frames) ; + + sf_count_t writef (const short *ptr, sf_count_t frames) ; + sf_count_t writef (const int *ptr, sf_count_t frames) ; + sf_count_t writef (const float *ptr, sf_count_t frames) ; + sf_count_t writef (const double *ptr, sf_count_t frames) ; + + sf_count_t readRaw (void *ptr, sf_count_t bytes) ; + sf_count_t writeRaw (const void *ptr, sf_count_t bytes) ; + + /**< Raw access to the handle. SndfileHandle keeps ownership. */ + SNDFILE * rawHandle (void) ; + + /**< Take ownership of handle, if reference count is 1. */ + SNDFILE * takeOwnership (void) ; +} ; + +/*============================================================================== +** Nothing but implementation below. +*/ + +inline +SndfileHandle::SNDFILE_ref::SNDFILE_ref (void) +: sf (SF_NULL), sfinfo (), ref (1) +{} + +inline +SndfileHandle::SNDFILE_ref::~SNDFILE_ref (void) +{ if (sf != SF_NULL) sf_close (sf) ; } + +inline +SndfileHandle::SndfileHandle (const char *path, int mode, int fmt, int chans, int srate) +: p (SF_NULL) +{ + p = new (std::nothrow) SNDFILE_ref () ; + + if (p != SF_NULL) + { p->ref = 1 ; + + p->sfinfo.frames = 0 ; + p->sfinfo.channels = chans ; + p->sfinfo.format = fmt ; + p->sfinfo.samplerate = srate ; + p->sfinfo.sections = 0 ; + p->sfinfo.seekable = 0 ; + + p->sf = sf_open (path, mode, &p->sfinfo) ; + } ; + + return ; +} /* SndfileHandle const char * constructor */ + +inline +SndfileHandle::SndfileHandle (std::string const & path, int mode, int fmt, int chans, int srate) +: p (SF_NULL) +{ + p = new (std::nothrow) SNDFILE_ref () ; + + if (p != SF_NULL) + { p->ref = 1 ; + + p->sfinfo.frames = 0 ; + p->sfinfo.channels = chans ; + p->sfinfo.format = fmt ; + p->sfinfo.samplerate = srate ; + p->sfinfo.sections = 0 ; + p->sfinfo.seekable = 0 ; + + p->sf = sf_open (path.c_str (), mode, &p->sfinfo) ; + } ; + + return ; +} /* SndfileHandle std::string constructor */ + +inline +SndfileHandle::SndfileHandle (int fd, bool close_desc, int mode, int fmt, int chans, int srate) +: p (SF_NULL) +{ + if (fd < 0) + return ; + + p = new (std::nothrow) SNDFILE_ref () ; + + if (p != SF_NULL) + { p->ref = 1 ; + + p->sfinfo.frames = 0 ; + p->sfinfo.channels = chans ; + p->sfinfo.format = fmt ; + p->sfinfo.samplerate = srate ; + p->sfinfo.sections = 0 ; + p->sfinfo.seekable = 0 ; + + p->sf = sf_open_fd (fd, mode, &p->sfinfo, close_desc) ; + } ; + + return ; +} /* SndfileHandle fd constructor */ + +inline +SndfileHandle::SndfileHandle (SF_VIRTUAL_IO &sfvirtual, void *user_data, int mode, int fmt, int chans, int srate) +: p (SF_NULL) +{ + p = new (std::nothrow) SNDFILE_ref () ; + + if (p != SF_NULL) + { p->ref = 1 ; + + p->sfinfo.frames = 0 ; + p->sfinfo.channels = chans ; + p->sfinfo.format = fmt ; + p->sfinfo.samplerate = srate ; + p->sfinfo.sections = 0 ; + p->sfinfo.seekable = 0 ; + + p->sf = sf_open_virtual (&sfvirtual, mode, &p->sfinfo, user_data) ; + } ; + + return ; +} /* SndfileHandle std::string constructor */ + +inline +SndfileHandle::~SndfileHandle (void) +{ if (p != SF_NULL && -- p->ref == 0) + delete p ; +} /* SndfileHandle destructor */ + + +inline +SndfileHandle::SndfileHandle (const SndfileHandle &orig) +: p (orig.p) +{ if (p != SF_NULL) + ++ p->ref ; +} /* SndfileHandle copy constructor */ + +inline SndfileHandle & +SndfileHandle::operator = (const SndfileHandle &rhs) +{ + if (&rhs == this) + return *this ; + if (p != SF_NULL && -- p->ref == 0) + delete p ; + + p = rhs.p ; + if (p != SF_NULL) + ++ p->ref ; + + return *this ; +} /* SndfileHandle copy assignment */ + +#if (__cplusplus >= 201100L) + +inline +SndfileHandle::SndfileHandle (SndfileHandle &&orig) noexcept +: p (orig.p) +{ + orig.p = SF_NULL ; +} /* SndfileHandle move constructor */ + +inline SndfileHandle & +SndfileHandle::operator = (SndfileHandle &&rhs) noexcept +{ + if (&rhs == this) + return *this ; + if (p != SF_NULL && -- p->ref == 0) + delete p ; + + p = rhs.p ; + rhs.p = SF_NULL ; + + return *this ; +} /* SndfileHandle move assignment */ + +#endif + +inline int +SndfileHandle::error (void) const +{ return sf_error (p->sf) ; } + +inline const char * +SndfileHandle::strError (void) const +{ return sf_strerror (p->sf) ; } + +inline int +SndfileHandle::command (int cmd, void *data, int datasize) +{ return sf_command (p->sf, cmd, data, datasize) ; } + +inline sf_count_t +SndfileHandle::seek (sf_count_t frame_count, int whence) +{ return sf_seek (p->sf, frame_count, whence) ; } + +inline void +SndfileHandle::writeSync (void) +{ sf_write_sync (p->sf) ; } + +inline int +SndfileHandle::setString (int str_type, const char* str) +{ return sf_set_string (p->sf, str_type, str) ; } + +inline const char* +SndfileHandle::getString (int str_type) const +{ return sf_get_string (p->sf, str_type) ; } + +inline int +SndfileHandle::formatCheck (int fmt, int chans, int srate) +{ + SF_INFO sfinfo ; + + sfinfo.frames = 0 ; + sfinfo.channels = chans ; + sfinfo.format = fmt ; + sfinfo.samplerate = srate ; + sfinfo.sections = 0 ; + sfinfo.seekable = 0 ; + + return sf_format_check (&sfinfo) ; +} + +/*---------------------------------------------------------------------*/ + +inline sf_count_t +SndfileHandle::read (short *ptr, sf_count_t items) +{ return sf_read_short (p->sf, ptr, items) ; } + +inline sf_count_t +SndfileHandle::read (int *ptr, sf_count_t items) +{ return sf_read_int (p->sf, ptr, items) ; } + +inline sf_count_t +SndfileHandle::read (float *ptr, sf_count_t items) +{ return sf_read_float (p->sf, ptr, items) ; } + +inline sf_count_t +SndfileHandle::read (double *ptr, sf_count_t items) +{ return sf_read_double (p->sf, ptr, items) ; } + +inline sf_count_t +SndfileHandle::write (const short *ptr, sf_count_t items) +{ return sf_write_short (p->sf, ptr, items) ; } + +inline sf_count_t +SndfileHandle::write (const int *ptr, sf_count_t items) +{ return sf_write_int (p->sf, ptr, items) ; } + +inline sf_count_t +SndfileHandle::write (const float *ptr, sf_count_t items) +{ return sf_write_float (p->sf, ptr, items) ; } + +inline sf_count_t +SndfileHandle::write (const double *ptr, sf_count_t items) +{ return sf_write_double (p->sf, ptr, items) ; } + +inline sf_count_t +SndfileHandle::readf (short *ptr, sf_count_t frame_count) +{ return sf_readf_short (p->sf, ptr, frame_count) ; } + +inline sf_count_t +SndfileHandle::readf (int *ptr, sf_count_t frame_count) +{ return sf_readf_int (p->sf, ptr, frame_count) ; } + +inline sf_count_t +SndfileHandle::readf (float *ptr, sf_count_t frame_count) +{ return sf_readf_float (p->sf, ptr, frame_count) ; } + +inline sf_count_t +SndfileHandle::readf (double *ptr, sf_count_t frame_count) +{ return sf_readf_double (p->sf, ptr, frame_count) ; } + +inline sf_count_t +SndfileHandle::writef (const short *ptr, sf_count_t frame_count) +{ return sf_writef_short (p->sf, ptr, frame_count) ; } + +inline sf_count_t +SndfileHandle::writef (const int *ptr, sf_count_t frame_count) +{ return sf_writef_int (p->sf, ptr, frame_count) ; } + +inline sf_count_t +SndfileHandle::writef (const float *ptr, sf_count_t frame_count) +{ return sf_writef_float (p->sf, ptr, frame_count) ; } + +inline sf_count_t +SndfileHandle::writef (const double *ptr, sf_count_t frame_count) +{ return sf_writef_double (p->sf, ptr, frame_count) ; } + +inline sf_count_t +SndfileHandle::readRaw (void *ptr, sf_count_t bytes) +{ return sf_read_raw (p->sf, ptr, bytes) ; } + +inline sf_count_t +SndfileHandle::writeRaw (const void *ptr, sf_count_t bytes) +{ return sf_write_raw (p->sf, ptr, bytes) ; } + +inline SNDFILE * +SndfileHandle::rawHandle (void) +{ return (p ? p->sf : SF_NULL) ; } + +inline SNDFILE * +SndfileHandle::takeOwnership (void) +{ + if (p == SF_NULL || (p->ref != 1)) + return SF_NULL ; + + SNDFILE * sf = p->sf ; + p->sf = SF_NULL ; + delete p ; + p = SF_NULL ; + return sf ; +} + +#ifdef _WIN32 + +inline +SndfileHandle::SndfileHandle (const wchar_t *wpath, int mode, int fmt, int chans, int srate) +: p (SF_NULL) +{ + p = new (std::nothrow) SNDFILE_ref () ; + + if (p != SF_NULL) + { p->ref = 1 ; + + p->sfinfo.frames = 0 ; + p->sfinfo.channels = chans ; + p->sfinfo.format = fmt ; + p->sfinfo.samplerate = srate ; + p->sfinfo.sections = 0 ; + p->sfinfo.seekable = 0 ; + + p->sf = sf_wchar_open (wpath, mode, &p->sfinfo) ; + } ; + + return ; +} /* SndfileHandle const wchar_t * constructor */ + +#endif + +#endif /* SNDFILE_HH */ + diff --git a/extern/libsndfile-modified/m4/ax_add_fortify_source.m4 b/extern/libsndfile-modified/m4/ax_add_fortify_source.m4 new file mode 100644 index 000000000..7e1531279 --- /dev/null +++ b/extern/libsndfile-modified/m4/ax_add_fortify_source.m4 @@ -0,0 +1,80 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_add_fortify_source.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_ADD_FORTIFY_SOURCE +# +# DESCRIPTION +# +# Check whether -D_FORTIFY_SOURCE=2 can be added to CPPFLAGS without macro +# redefinition warnings, other cpp warnings or linker. Some distributions +# (such as Gentoo Linux) enable _FORTIFY_SOURCE globally in their +# compilers, leading to unnecessary warnings in the form of +# +# :0:0: error: "_FORTIFY_SOURCE" redefined [-Werror] +# : note: this is the location of the previous definition +# +# which is a problem if -Werror is enabled. This macro checks whether +# _FORTIFY_SOURCE is already defined, and if not, adds -D_FORTIFY_SOURCE=2 +# to CPPFLAGS. +# +# Newer mingw-w64 msys2 package comes with a bug in +# headers-git-7.0.0.5546.d200317d-1. It broke -D_FORTIFY_SOURCE support, +# and would need -lssp or -fstack-protector. See +# https://github.com/msys2/MINGW-packages/issues/5803. Try to actually +# link it. +# +# LICENSE +# +# Copyright (c) 2017 David Seifert +# Copyright (c) 2019 Reini Urban +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 4 + +AC_DEFUN([AX_ADD_FORTIFY_SOURCE],[ + ac_save_cflags=$CFLAGS + ac_cwerror_flag=yes + AX_CHECK_COMPILE_FLAG([-Werror],[CFLAGS="$CFLAGS -Werror"]) + AC_MSG_CHECKING([whether to add -D_FORTIFY_SOURCE=2 to CPPFLAGS]) + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([], + [[ + #ifndef _FORTIFY_SOURCE + return 0; + #else + this_is_an_error; + #endif + ]] + )], + AC_LINK_IFELSE([ + AC_LANG_SOURCE([[ + #define _FORTIFY_SOURCE 2 + #include + int main() { + char *s = " "; + strcpy(s, "x"); + return strlen(s)-1; + } + ]] + )], + [ + AC_MSG_RESULT([yes]) + CFLAGS=$ac_save_cflags + CPPFLAGS="$CPPFLAGS -D_FORTIFY_SOURCE=2" + ], [ + AC_MSG_RESULT([no]) + CFLAGS=$ac_save_cflags + ], + ), + [ + AC_MSG_RESULT([no]) + CFLAGS=$ac_save_cflags + ]) +]) diff --git a/extern/libsndfile-modified/m4/ax_append_compile_flags.m4 b/extern/libsndfile-modified/m4/ax_append_compile_flags.m4 new file mode 100644 index 000000000..5b6f1af51 --- /dev/null +++ b/extern/libsndfile-modified/m4/ax_append_compile_flags.m4 @@ -0,0 +1,67 @@ +# ============================================================================ +# https://www.gnu.org/software/autoconf-archive/ax_append_compile_flags.html +# ============================================================================ +# +# SYNOPSIS +# +# AX_APPEND_COMPILE_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS], [INPUT]) +# +# DESCRIPTION +# +# For every FLAG1, FLAG2 it is checked whether the compiler works with the +# flag. If it does, the flag is added FLAGS-VARIABLE +# +# If FLAGS-VARIABLE is not specified, the current language's flags (e.g. +# CFLAGS) is used. During the check the flag is always added to the +# current language's flags. +# +# If EXTRA-FLAGS is defined, it is added to the current language's default +# flags (e.g. CFLAGS) when the check is done. The check is thus made with +# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to +# force the compiler to issue an error when a bad flag is given. +# +# INPUT gives an alternative input source to AC_COMPILE_IFELSE. +# +# NOTE: This macro depends on the AX_APPEND_FLAG and +# AX_CHECK_COMPILE_FLAG. Please keep this macro in sync with +# AX_APPEND_LINK_FLAGS. +# +# LICENSE +# +# Copyright (c) 2011 Maarten Bosmans +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 6 + +AC_DEFUN([AX_APPEND_COMPILE_FLAGS], +[AX_REQUIRE_DEFINED([AX_CHECK_COMPILE_FLAG]) +AX_REQUIRE_DEFINED([AX_APPEND_FLAG]) +for flag in $1; do + AX_CHECK_COMPILE_FLAG([$flag], [AX_APPEND_FLAG([$flag], [$2])], [], [$3], [$4]) +done +])dnl AX_APPEND_COMPILE_FLAGS diff --git a/extern/libsndfile-modified/m4/ax_append_flag.m4 b/extern/libsndfile-modified/m4/ax_append_flag.m4 new file mode 100644 index 000000000..e8c5312af --- /dev/null +++ b/extern/libsndfile-modified/m4/ax_append_flag.m4 @@ -0,0 +1,71 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_append_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_APPEND_FLAG(FLAG, [FLAGS-VARIABLE]) +# +# DESCRIPTION +# +# FLAG is appended to the FLAGS-VARIABLE shell variable, with a space +# added in between. +# +# If FLAGS-VARIABLE is not specified, the current language's flags (e.g. +# CFLAGS) is used. FLAGS-VARIABLE is not changed if it already contains +# FLAG. If FLAGS-VARIABLE is unset in the shell, it is set to exactly +# FLAG. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 7 + +AC_DEFUN([AX_APPEND_FLAG], +[dnl +AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_SET_IF +AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])]) +AS_VAR_SET_IF(FLAGS,[ + AS_CASE([" AS_VAR_GET(FLAGS) "], + [*" $1 "*], [AC_RUN_LOG([: FLAGS already contains $1])], + [ + AS_VAR_APPEND(FLAGS,[" $1"]) + AC_RUN_LOG([: FLAGS="$FLAGS"]) + ]) + ], + [ + AS_VAR_SET(FLAGS,[$1]) + AC_RUN_LOG([: FLAGS="$FLAGS"]) + ]) +AS_VAR_POPDEF([FLAGS])dnl +])dnl AX_APPEND_FLAG diff --git a/extern/libsndfile-modified/m4/ax_append_link_flags.m4 b/extern/libsndfile-modified/m4/ax_append_link_flags.m4 new file mode 100644 index 000000000..6f7f17456 --- /dev/null +++ b/extern/libsndfile-modified/m4/ax_append_link_flags.m4 @@ -0,0 +1,65 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_append_link_flags.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_APPEND_LINK_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS], [INPUT]) +# +# DESCRIPTION +# +# For every FLAG1, FLAG2 it is checked whether the linker works with the +# flag. If it does, the flag is added FLAGS-VARIABLE +# +# If FLAGS-VARIABLE is not specified, the linker's flags (LDFLAGS) is +# used. During the check the flag is always added to the linker's flags. +# +# If EXTRA-FLAGS is defined, it is added to the linker's default flags +# when the check is done. The check is thus made with the flags: "LDFLAGS +# EXTRA-FLAGS FLAG". This can for example be used to force the linker to +# issue an error when a bad flag is given. +# +# INPUT gives an alternative input source to AC_COMPILE_IFELSE. +# +# NOTE: This macro depends on the AX_APPEND_FLAG and AX_CHECK_LINK_FLAG. +# Please keep this macro in sync with AX_APPEND_COMPILE_FLAGS. +# +# LICENSE +# +# Copyright (c) 2011 Maarten Bosmans +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 6 + +AC_DEFUN([AX_APPEND_LINK_FLAGS], +[AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG]) +AX_REQUIRE_DEFINED([AX_APPEND_FLAG]) +for flag in $1; do + AX_CHECK_LINK_FLAG([$flag], [AX_APPEND_FLAG([$flag], [m4_default([$2], [LDFLAGS])])], [], [$3], [$4]) +done +])dnl AX_APPEND_LINK_FLAGS diff --git a/extern/libsndfile-modified/m4/ax_check_compile_flag.m4 b/extern/libsndfile-modified/m4/ax_check_compile_flag.m4 new file mode 100644 index 000000000..dcabb92a1 --- /dev/null +++ b/extern/libsndfile-modified/m4/ax_check_compile_flag.m4 @@ -0,0 +1,74 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) +# +# DESCRIPTION +# +# Check whether the given FLAG works with the current language's compiler +# or gives an error. (Warnings, however, are ignored) +# +# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on +# success/failure. +# +# If EXTRA-FLAGS is defined, it is added to the current language's default +# flags (e.g. CFLAGS) when the check is done. The check is thus made with +# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to +# force the compiler to issue an error when a bad flag is given. +# +# INPUT gives an alternative input source to AC_COMPILE_IFELSE. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this +# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 5 + +AC_DEFUN([AX_CHECK_COMPILE_FLAG], +[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF +AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl +AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ + ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS + _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" + AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], + [AS_VAR_SET(CACHEVAR,[yes])], + [AS_VAR_SET(CACHEVAR,[no])]) + _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) +AS_VAR_IF(CACHEVAR,yes, + [m4_default([$2], :)], + [m4_default([$3], :)]) +AS_VAR_POPDEF([CACHEVAR])dnl +])dnl AX_CHECK_COMPILE_FLAGS diff --git a/extern/libsndfile-modified/m4/ax_check_link_flag.m4 b/extern/libsndfile-modified/m4/ax_check_link_flag.m4 new file mode 100644 index 000000000..819409a20 --- /dev/null +++ b/extern/libsndfile-modified/m4/ax_check_link_flag.m4 @@ -0,0 +1,74 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_check_link_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) +# +# DESCRIPTION +# +# Check whether the given FLAG works with the linker or gives an error. +# (Warnings, however, are ignored) +# +# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on +# success/failure. +# +# If EXTRA-FLAGS is defined, it is added to the linker's default flags +# when the check is done. The check is thus made with the flags: "LDFLAGS +# EXTRA-FLAGS FLAG". This can for example be used to force the linker to +# issue an error when a bad flag is given. +# +# INPUT gives an alternative input source to AC_LINK_IFELSE. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this +# macro in sync with AX_CHECK_{PREPROC,COMPILE}_FLAG. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 5 + +AC_DEFUN([AX_CHECK_LINK_FLAG], +[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF +AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl +AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [ + ax_check_save_flags=$LDFLAGS + LDFLAGS="$LDFLAGS $4 $1" + AC_LINK_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], + [AS_VAR_SET(CACHEVAR,[yes])], + [AS_VAR_SET(CACHEVAR,[no])]) + LDFLAGS=$ax_check_save_flags]) +AS_VAR_IF(CACHEVAR,yes, + [m4_default([$2], :)], + [m4_default([$3], :)]) +AS_VAR_POPDEF([CACHEVAR])dnl +])dnl AX_CHECK_LINK_FLAGS diff --git a/extern/libsndfile-modified/m4/ax_compiler_vendor.m4 b/extern/libsndfile-modified/m4/ax_compiler_vendor.m4 new file mode 100644 index 000000000..4ca808955 --- /dev/null +++ b/extern/libsndfile-modified/m4/ax_compiler_vendor.m4 @@ -0,0 +1,87 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_compiler_vendor.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_COMPILER_VENDOR +# +# DESCRIPTION +# +# Determine the vendor of the C/C++ compiler, e.g., gnu, intel, ibm, sun, +# hp, borland, comeau, dec, cray, kai, lcc, metrowerks, sgi, microsoft, +# watcom, etc. The vendor is returned in the cache variable +# $ax_cv_c_compiler_vendor for C and $ax_cv_cxx_compiler_vendor for C++. +# +# LICENSE +# +# Copyright (c) 2008 Steven G. Johnson +# Copyright (c) 2008 Matteo Frigo +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 16 + +AC_DEFUN([AX_COMPILER_VENDOR], +[AC_CACHE_CHECK([for _AC_LANG compiler vendor], ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor, + dnl Please add if possible support to ax_compiler_version.m4 + [# note: don't check for gcc first since some other compilers define __GNUC__ + vendors="intel: __ICC,__ECC,__INTEL_COMPILER + ibm: __xlc__,__xlC__,__IBMC__,__IBMCPP__ + pathscale: __PATHCC__,__PATHSCALE__ + clang: __clang__ + cray: _CRAYC + fujitsu: __FUJITSU + gnu: __GNUC__ + sun: __SUNPRO_C,__SUNPRO_CC + hp: __HP_cc,__HP_aCC + dec: __DECC,__DECCXX,__DECC_VER,__DECCXX_VER + borland: __BORLANDC__,__CODEGEARC__,__TURBOC__ + comeau: __COMO__ + kai: __KCC + lcc: __LCC__ + sgi: __sgi,sgi + microsoft: _MSC_VER + metrowerks: __MWERKS__ + watcom: __WATCOMC__ + portland: __PGI + tcc: __TINYC__ + unknown: UNKNOWN" + for ventest in $vendors; do + case $ventest in + *:) vendor=$ventest; continue ;; + *) vencpp="defined("`echo $ventest | sed 's/,/) || defined(/g'`")" ;; + esac + AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,[ + #if !($vencpp) + thisisanerror; + #endif + ])], [break]) + done + ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor=`echo $vendor | cut -d: -f1` + ]) +]) diff --git a/extern/libsndfile-modified/m4/ax_compiler_version.m4 b/extern/libsndfile-modified/m4/ax_compiler_version.m4 new file mode 100644 index 000000000..8a8e28a98 --- /dev/null +++ b/extern/libsndfile-modified/m4/ax_compiler_version.m4 @@ -0,0 +1,492 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_compiler_version.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_COMPILER_VERSION +# +# DESCRIPTION +# +# This macro retrieves the compiler version and returns it in the cache +# variable $ax_cv_c_compiler_version for C and $ax_cv_cxx_compiler_version +# for C++. +# +# Version is returned as epoch:major.minor.patchversion +# +# Epoch is used in order to have an increasing version number in case of +# marketing change. +# +# Epoch use: * borland compiler use chronologically 0turboc for turboc +# era, +# +# 1borlanc BORLANDC++ before 5, 2cppbuilder for cppbuilder era, +# 3borlancpp for return of BORLANDC++ (after version 5.5), +# 4cppbuilder for cppbuilder with year version, +# and 5xe for XE era. +# +# An empty string is returned otherwise. +# +# LICENSE +# +# Copyright (c) 2014 Bastien ROUCARIES +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 9 + +# for intel +AC_DEFUN([_AX_COMPILER_VERSION_INTEL], + [ dnl + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + [__INTEL_COMPILER/100],, + AC_MSG_FAILURE([[[$0]] unknown intel compiler version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + [(__INTEL_COMPILER%100)/10],, + AC_MSG_FAILURE([[[$0]] unknown intel compiler version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch, + [(__INTEL_COMPILER%10)],, + AC_MSG_FAILURE([[[$0]] unknown intel compiler version])) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch" + ]) + +# for IBM +AC_DEFUN([_AX_COMPILER_VERSION_IBM], + [ dnl + dnl check between z/OS C/C++ and XL C/C++ + AC_COMPILE_IFELSE([ + AC_LANG_PROGRAM([], + [ + #if defined(__COMPILER_VER__) + choke me; + #endif + ])], + [ + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + [__xlC__/100],, + AC_MSG_FAILURE([[[$0]] unknown IBM compiler major version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + [__xlC__%100],, + AC_MSG_FAILURE([[[$0]] unknown IBM compiler minor version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch, + [__xlC_ver__/0x100],, + AC_MSG_FAILURE([[[$0]] unknown IBM compiler patch version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_build, + [__xlC_ver__%0x100],, + AC_MSG_FAILURE([[[$0]] unknown IBM compiler build version])) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_build" + ], + [ + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch, + [__xlC__%1000],, + AC_MSG_FAILURE([[[$0]] unknown IBM compiler patch version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + [(__xlC__/10000)%10],, + AC_MSG_FAILURE([[[$0]] unknown IBM compiler minor version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + [(__xlC__/100000)%10],, + AC_MSG_FAILURE([[[$0]] unknown IBM compiler major version])) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch" + ]) +]) + +# for pathscale +AC_DEFUN([_AX_COMPILER_VERSION_PATHSCALE],[ + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + __PATHCC__,, + AC_MSG_FAILURE([[[$0]] unknown pathscale major])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + __PATHCC_MINOR__,, + AC_MSG_FAILURE([[[$0]] unknown pathscale minor])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch, + [__PATHCC_PATCHLEVEL__],, + AC_MSG_FAILURE([[[$0]] unknown pathscale patch level])) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch" + ]) + +# for clang +AC_DEFUN([_AX_COMPILER_VERSION_CLANG],[ + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + __clang_major__,, + AC_MSG_FAILURE([[[$0]] unknown clang major])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + __clang_minor__,, + AC_MSG_FAILURE([[[$0]] unknown clang minor])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch, + [__clang_patchlevel__],,0) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch" + ]) + +# for crayc +AC_DEFUN([_AX_COMPILER_VERSION_CRAY],[ + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + _RELEASE,, + AC_MSG_FAILURE([[[$0]] unknown crayc release])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + _RELEASE_MINOR,, + AC_MSG_FAILURE([[[$0]] unknown crayc minor])) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor" + ]) + +# for fujitsu +AC_DEFUN([_AX_COMPILER_VERSION_FUJITSU],[ + AC_COMPUTE_INT(ax_cv_[]_AC_LANG_ABBREV[]_compiler_version, + __FCC_VERSION,, + AC_MSG_FAILURE([[[$0]]unknown fujitsu release])) + ]) + +# for GNU +AC_DEFUN([_AX_COMPILER_VERSION_GNU],[ + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + __GNUC__,, + AC_MSG_FAILURE([[[$0]] unknown gcc major])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + __GNUC_MINOR__,, + AC_MSG_FAILURE([[[$0]] unknown gcc minor])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch, + [__GNUC_PATCHLEVEL__],, + AC_MSG_FAILURE([[[$0]] unknown gcc patch level])) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch" + ]) + +# For sun +AC_DEFUN([_AX_COMPILER_VERSION_SUN],[ + m4_define([_AX_COMPILER_VERSION_SUN_NUMBER], + [ + #if defined(__SUNPRO_CC) + __SUNPRO_CC + #else + __SUNPRO_C + #endif + ]) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_until59, + !!(_AX_COMPILER_VERSION_SUN_NUMBER < 0x1000),, + AC_MSG_FAILURE([[[$0]] unknown sun release version])) + AS_IF([test "X$_ax_[]_AC_LANG_ABBREV[]_compiler_version_until59" = X1], + [dnl + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch, + _AX_COMPILER_VERSION_SUN_NUMBER % 0x10,, + AC_MSG_FAILURE([[[$0]] unknown sun patch version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + (_AX_COMPILER_VERSION_SUN_NUMBER / 0x10) % 0x10,, + AC_MSG_FAILURE([[[$0]] unknown sun minor version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + (_AX_COMPILER_VERSION_SUN_NUMBER / 0x100),, + AC_MSG_FAILURE([[[$0]] unknown sun major version])) + ], + [dnl + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch, + _AX_COMPILER_VERSION_SUN_NUMBER % 0x10,, + AC_MSG_FAILURE([[[$0]] unknown sun patch version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + (_AX_COMPILER_VERSION_SUN_NUMBER / 0x100) % 0x100,, + AC_MSG_FAILURE([[[$0]] unknown sun minor version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + (_AX_COMPILER_VERSION_SUN_NUMBER / 0x1000),, + AC_MSG_FAILURE([[[$0]] unknown sun major version])) + ]) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch" +]) + +AC_DEFUN([_AX_COMPILER_VERSION_HP],[ + m4_define([_AX_COMPILER_VERSION_HP_NUMBER], + [ + #if defined(__HP_cc) + __HP_cc + #else + __HP_aCC + #endif + ]) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_untilA0121, + !!(_AX_COMPILER_VERSION_HP_NUMBER <= 1),, + AC_MSG_FAILURE([[[$0]] unknown hp release version])) + AS_IF([test "X$_ax_[]_AC_LANG_ABBREV[]_compiler_version_untilA0121" = X1], + [dnl By default output last version with this behavior. + dnl it is so old + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="01.21.00" + ], + [dnl + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch, + (_AX_COMPILER_VERSION_HP_NUMBER % 100),, + AC_MSG_FAILURE([[[$0]] unknown hp release version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + ((_AX_COMPILER_VERSION_HP_NUMBER / 100)%100),, + AC_MSG_FAILURE([[[$0]] unknown hp minor version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + ((_AX_COMPILER_VERSION_HP_NUMBER / 10000)%100),, + AC_MSG_FAILURE([[[$0]] unknown hp major version])) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch" + ]) +]) + +AC_DEFUN([_AX_COMPILER_VERSION_DEC],[dnl + m4_define([_AX_COMPILER_VERSION_DEC_NUMBER], + [ + #if defined(__DECC_VER) + __DECC_VER + #else + __DECCXX_VER + #endif + ]) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch, + (_AX_COMPILER_VERSION_DEC_NUMBER % 10000),, + AC_MSG_FAILURE([[[$0]] unknown dec release version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + ((_AX_COMPILER_VERSION_DEC_NUMBER / 100000UL)%100),, + AC_MSG_FAILURE([[[$0]] unknown dec minor version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + ((_AX_COMPILER_VERSION_DEC_NUMBER / 10000000UL)%100),, + AC_MSG_FAILURE([[[$0]] unknown dec major version])) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch" + ]) + +# borland +AC_DEFUN([_AX_COMPILER_VERSION_BORLAND],[dnl + m4_define([_AX_COMPILER_VERSION_TURBOC_NUMBER], + [ + #if defined(__TURBOC__) + __TURBOC__ + #else + choke me + #endif + ]) + m4_define([_AX_COMPILER_VERSION_BORLANDC_NUMBER], + [ + #if defined(__BORLANDC__) + __BORLANDC__ + #else + __CODEGEARC__ + #endif + ]) + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM(, + _AX_COMPILER_VERSION_TURBOC_NUMBER)], + [dnl TURBOC + AC_COMPUTE_INT( + _ax_[]_AC_LANG_ABBREV[]_compiler_version_turboc_raw, + _AX_COMPILER_VERSION_TURBOC_NUMBER,, + AC_MSG_FAILURE([[[$0]] unknown turboc version])) + AS_IF( + [test $_ax_[]_AC_LANG_ABBREV[]_compiler_version_turboc_raw -lt 661 || test $_ax_[]_AC_LANG_ABBREV[]_compiler_version_turboc_raw -gt 1023], + [dnl compute normal version + AC_COMPUTE_INT( + _ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + _AX_COMPILER_VERSION_TURBOC_NUMBER % 0x100,, + AC_MSG_FAILURE([[[$0]] unknown turboc minor version])) + AC_COMPUTE_INT( + _ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + (_AX_COMPILER_VERSION_TURBOC_NUMBER/0x100)%0x100,, + AC_MSG_FAILURE([[[$0]] unknown turboc major version])) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="0turboc:$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor"], + [dnl special version + AS_CASE([$_ax_[]_AC_LANG_ABBREV[]_compiler_version_turboc_raw], + [661],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="0turboc:1.00"], + [662],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="0turboc:1.01"], + [663],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="0turboc:2.00"], + [ + AC_MSG_WARN([[[$0]] unknown turboc version between 0x295 and 0x400 please report bug]) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="" + ]) + ]) + ], + # borlandc + [ + AC_COMPUTE_INT( + _ax_[]_AC_LANG_ABBREV[]_compiler_version_borlandc_raw, + _AX_COMPILER_VERSION_BORLANDC_NUMBER,, + AC_MSG_FAILURE([[[$0]] unknown borlandc version])) + AS_CASE([$_ax_[]_AC_LANG_ABBREV[]_compiler_version_borlandc_raw], + dnl BORLANDC++ before 5.5 + [512] ,[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="1borlanc:2.00"], + [1024],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="1borlanc:3.00"], + [1024],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="1borlanc:3.00"], + [1040],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="1borlanc:3.1"], + [1106],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="1borlanc:4.0"], + [1280],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="1borlanc:5.0"], + [1312],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="1borlanc:5.02"], + dnl C++ Builder era + [1328],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="2cppbuilder:3.0"], + [1344],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="2cppbuilder:4.0"], + dnl BORLANDC++ after 5.5 + [1360],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="3borlancpp:5.5"], + [1361],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="3borlancpp:5.51"], + [1378],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="3borlancpp:5.6.4"], + dnl C++ Builder with year number + [1392],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="4cppbuilder:2006"], + [1424],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="4cppbuilder:2007"], + [1555],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="4cppbuilder:2009"], + [1569],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="4cppbuilder:2010"], + dnl XE version + [1584],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="5xe"], + [1600],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="5xe:2"], + [1616],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="5xe:3"], + [1632],[ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="5xe:4"], + [ + AC_MSG_WARN([[[$0]] Unknown borlandc compiler version $_ax_[]_AC_LANG_ABBREV[]_compiler_version_borlandc_raw please report bug]) + ]) + ]) + ]) + +# COMO +AC_DEFUN([_AX_COMPILER_VERSION_COMEAU], + [ dnl + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + [__COMO_VERSION__%100],, + AC_MSG_FAILURE([[[$0]] unknown comeau compiler minor version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + [(__COMO_VERSION__/100)%10],, + AC_MSG_FAILURE([[[$0]] unknown comeau compiler major version])) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor" + ]) + +# KAI +AC_DEFUN([_AX_COMPILER_VERSION_KAI],[ + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch, + [__KCC_VERSION%100],, + AC_MSG_FAILURE([[[$0]] unknown kay compiler patch version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + [(__KCC_VERSION/100)%10],, + AC_MSG_FAILURE([[[$0]] unknown kay compiler minor version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + [(__KCC_VERSION/1000)%10],, + AC_MSG_FAILURE([[[$0]] unknown kay compiler major version])) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch" + ]) + +dnl LCC +dnl LCC does not output version... + +# SGI +AC_DEFUN([_AX_COMPILER_VERSION_SGI],[ + m4_define([_AX_COMPILER_VERSION_SGI_NUMBER], + [ + #if defined(_COMPILER_VERSION) + _COMPILER_VERSION + #else + _SGI_COMPILER_VERSION + #endif + ]) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch, + [_AX_COMPILER_VERSION_SGI_NUMBER%10],, + AC_MSG_FAILURE([[[$0]] unknown SGI compiler patch version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + [(_AX_COMPILER_VERSION_SGI_NUMBER/10)%10],, + AC_MSG_FAILURE([[[$0]] unknown SGI compiler minor version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + [(_AX_COMPILER_VERSION_SGI_NUMBER/100)%10],, + AC_MSG_FAILURE([[[$0]] unknown SGI compiler major version])) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch" + ]) + +# microsoft +AC_DEFUN([_AX_COMPILER_VERSION_MICROSOFT],[ + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + _MSC_VER%100,, + AC_MSG_FAILURE([[[$0]] unknown microsoft compiler minor version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + (_MSC_VER/100)%100,, + AC_MSG_FAILURE([[[$0]] unknown microsoft compiler major version])) + dnl could be overridden + _ax_[]_AC_LANG_ABBREV[]_compiler_version_patch=0 + _ax_[]_AC_LANG_ABBREV[]_compiler_version_build=0 + # special case for version 6 + AS_IF([test "X$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major" = "X12"], + [AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch, + _MSC_FULL_VER%1000,, + _ax_[]_AC_LANG_ABBREV[]_compiler_version_patch=0)]) + # for version 7 + AS_IF([test "X$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major" = "X13"], + [AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch, + _MSC_FULL_VER%1000,, + AC_MSG_FAILURE([[[$0]] unknown microsoft compiler patch version])) + ]) + # for version > 8 + AS_IF([test $_ax_[]_AC_LANG_ABBREV[]_compiler_version_major -ge 14], + [AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch, + _MSC_FULL_VER%10000,, + AC_MSG_FAILURE([[[$0]] unknown microsoft compiler patch version])) + ]) + AS_IF([test $_ax_[]_AC_LANG_ABBREV[]_compiler_version_major -ge 15], + [AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_build, + _MSC_BUILD,, + AC_MSG_FAILURE([[[$0]] unknown microsoft compiler build version])) + ]) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_build" + ]) + +# for metrowerks +AC_DEFUN([_AX_COMPILER_VERSION_METROWERKS],[dnl + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch, + __MWERKS__%0x100,, + AC_MSG_FAILURE([[[$0]] unknown metrowerks compiler patch version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + (__MWERKS__/0x100)%0x10,, + AC_MSG_FAILURE([[[$0]] unknown metrowerks compiler minor version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + (__MWERKS__/0x1000)%0x10,, + AC_MSG_FAILURE([[[$0]] unknown metrowerks compiler major version])) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch" + ]) + +# for watcom +AC_DEFUN([_AX_COMPILER_VERSION_WATCOM],[dnl + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + __WATCOMC__%100,, + AC_MSG_FAILURE([[[$0]] unknown watcom compiler minor version])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + (__WATCOMC__/100)%100,, + AC_MSG_FAILURE([[[$0]] unknown watcom compiler major version])) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor" + ]) + +# for PGI +AC_DEFUN([_AX_COMPILER_VERSION_PORTLAND],[ + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_major, + __PGIC__,, + AC_MSG_FAILURE([[[$0]] unknown pgi major])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor, + __PGIC_MINOR__,, + AC_MSG_FAILURE([[[$0]] unknown pgi minor])) + AC_COMPUTE_INT(_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch, + [__PGIC_PATCHLEVEL__],, + AC_MSG_FAILURE([[[$0]] unknown pgi patch level])) + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version="$_ax_[]_AC_LANG_ABBREV[]_compiler_version_major.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_minor.$_ax_[]_AC_LANG_ABBREV[]_compiler_version_patch" + ]) + +# tcc +AC_DEFUN([_AX_COMPILER_VERSION_TCC],[ + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version=[`tcc -v | $SED 's/^[ ]*tcc[ ]\+version[ ]\+\([0-9.]\+\).*/\1/g'`] + ]) +# main entry point +AC_DEFUN([AX_COMPILER_VERSION],[dnl + AC_REQUIRE([AX_COMPILER_VENDOR]) + AC_REQUIRE([AC_PROG_SED]) + AC_CACHE_CHECK([for _AC_LANG compiler version], + ax_cv_[]_AC_LANG_ABBREV[]_compiler_version, + [ dnl + AS_CASE([$ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor], + [intel],[_AX_COMPILER_VERSION_INTEL], + [ibm],[_AX_COMPILER_VERSION_IBM], + [pathscale],[_AX_COMPILER_VERSION_PATHSCALE], + [clang],[_AX_COMPILER_VERSION_CLANG], + [cray],[_AX_COMPILER_VERSION_CRAY], + [fujitsu],[_AX_COMPILER_VERSION_FUJITSU], + [gnu],[_AX_COMPILER_VERSION_GNU], + [sun],[_AX_COMPILER_VERSION_SUN], + [hp],[_AX_COMPILER_VERSION_HP], + [dec],[_AX_COMPILER_VERSION_DEC], + [borland],[_AX_COMPILER_VERSION_BORLAND], + [comeau],[_AX_COMPILER_VERSION_COMEAU], + [kai],[_AX_COMPILER_VERSION_KAI], + [sgi],[_AX_COMPILER_VERSION_SGI], + [microsoft],[_AX_COMPILER_VERSION_MICROSOFT], + [metrowerks],[_AX_COMPILER_VERSION_METROWERKS], + [watcom],[_AX_COMPILER_VERSION_WATCOM], + [portland],[_AX_COMPILER_VERSION_PORTLAND], + [tcc],[_AX_COMPILER_VERSION_TCC], + [ax_cv_[]_AC_LANG_ABBREV[]_compiler_version=""]) + ]) +]) diff --git a/extern/libsndfile-modified/m4/ax_recursive_eval.m4 b/extern/libsndfile-modified/m4/ax_recursive_eval.m4 new file mode 100644 index 000000000..0625aca22 --- /dev/null +++ b/extern/libsndfile-modified/m4/ax_recursive_eval.m4 @@ -0,0 +1,56 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_recursive_eval.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_RECURSIVE_EVAL(VALUE, RESULT) +# +# DESCRIPTION +# +# Interpolate the VALUE in loop until it doesn't change, and set the +# result to $RESULT. WARNING: It's easy to get an infinite loop with some +# unsane input. +# +# LICENSE +# +# Copyright (c) 2008 Alexandre Duret-Lutz +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 1 + +AC_DEFUN([AX_RECURSIVE_EVAL], +[_lcl_receval="$1" +$2=`(test "x$prefix" = xNONE && prefix="$ac_default_prefix" + test "x$exec_prefix" = xNONE && exec_prefix="${prefix}" + _lcl_receval_old='' + while test "[$]_lcl_receval_old" != "[$]_lcl_receval"; do + _lcl_receval_old="[$]_lcl_receval" + eval _lcl_receval="\"[$]_lcl_receval\"" + done + echo "[$]_lcl_receval")`]) diff --git a/extern/libsndfile-modified/m4/ax_require_defined.m4 b/extern/libsndfile-modified/m4/ax_require_defined.m4 new file mode 100644 index 000000000..17c3eab7d --- /dev/null +++ b/extern/libsndfile-modified/m4/ax_require_defined.m4 @@ -0,0 +1,37 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_require_defined.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_REQUIRE_DEFINED(MACRO) +# +# DESCRIPTION +# +# AX_REQUIRE_DEFINED is a simple helper for making sure other macros have +# been defined and thus are available for use. This avoids random issues +# where a macro isn't expanded. Instead the configure script emits a +# non-fatal: +# +# ./configure: line 1673: AX_CFLAGS_WARN_ALL: command not found +# +# It's like AC_REQUIRE except it doesn't expand the required macro. +# +# Here's an example: +# +# AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG]) +# +# LICENSE +# +# Copyright (c) 2014 Mike Frysinger +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 2 + +AC_DEFUN([AX_REQUIRE_DEFINED], [dnl + m4_ifndef([$1], [m4_fatal([macro ]$1[ is not defined; is a m4 file missing?])]) +])dnl AX_REQUIRE_DEFINED diff --git a/extern/libsndfile-modified/m4/clip_mode.m4 b/extern/libsndfile-modified/m4/clip_mode.m4 new file mode 100644 index 000000000..4556b937a --- /dev/null +++ b/extern/libsndfile-modified/m4/clip_mode.m4 @@ -0,0 +1,124 @@ +dnl @synopsis MN_C_CLIP_MODE +dnl +dnl Determine the clipping mode when converting float to int. +dnl @version 1.0 May 17 2003 +dnl @author Erik de Castro Lopo +dnl +dnl Permission to use, copy, modify, distribute, and sell this file for any +dnl purpose is hereby granted without fee, provided that the above copyright +dnl and this permission notice appear in all copies. No representations are +dnl made about the suitability of this software for any purpose. It is +dnl provided "as is" without express or implied warranty. + + + + + + + +dnl Find the clipping mode in the following way: +dnl 1) If we are not cross compiling test it. +dnl 2) IF we are cross compiling, assume that clipping isn't done correctly. + +AC_DEFUN([MN_C_CLIP_MODE], +[AC_CACHE_CHECK(processor clipping capabilities, + ac_cv_c_clip_type, + +# Initialize to unknown +ac_cv_c_clip_positive=unknown +ac_cv_c_clip_negative=unknown + + +if test $ac_cv_c_clip_positive = unknown ; then + AC_TRY_RUN( + [[ + #define _ISOC9X_SOURCE 1 + #define _ISOC99_SOURCE 1 + #define __USE_ISOC99 1 + #define __USE_ISOC9X 1 + #include + int main (void) + { double fval ; + int k, ival ; + + fval = 1.0 * 0x7FFFFFFF ; + for (k = 0 ; k < 100 ; k++) + { ival = (lrint (fval)) >> 24 ; + if (ival != 127) + return 1 ; + + fval *= 1.2499999 ; + } ; + + return 0 ; + } + ]], + ac_cv_c_clip_positive=yes, + ac_cv_c_clip_positive=no, + ac_cv_c_clip_positive=unknown + ) + + AC_TRY_RUN( + [[ + #define _ISOC9X_SOURCE 1 + #define _ISOC99_SOURCE 1 + #define __USE_ISOC99 1 + #define __USE_ISOC9X 1 + #include + int main (void) + { double fval ; + int k, ival ; + + fval = -8.0 * 0x10000000 ; + for (k = 0 ; k < 100 ; k++) + { ival = (lrint (fval)) >> 24 ; + if (ival != -128) + return 1 ; + + fval *= 1.2499999 ; + } ; + + return 0 ; + } + ]], + ac_cv_c_clip_negative=yes, + ac_cv_c_clip_negative=no, + ac_cv_c_clip_negative=unknown + ) + fi + +if test $ac_cv_c_clip_positive = yes ; then + ac_cv_c_clip_positive=1 +else + ac_cv_c_clip_positive=0 + fi + +if test $ac_cv_c_clip_negative = yes ; then + ac_cv_c_clip_negative=1 +else + ac_cv_c_clip_negative=0 + fi + +[[ +case "$ac_cv_c_clip_positive$ac_cv_c_clip_negative" in + "00") + ac_cv_c_clip_type="none" + ;; + "10") + ac_cv_c_clip_type="positive" + ;; + "01") + ac_cv_c_clip_type="negative" + ;; + "11") + ac_cv_c_clip_type="both" + ;; + esac + ]] + +) +] + +)# MN_C_CLIP_MODE + + diff --git a/extern/libsndfile-modified/m4/extra_pkg.m4 b/extern/libsndfile-modified/m4/extra_pkg.m4 new file mode 100644 index 000000000..8a04c359f --- /dev/null +++ b/extern/libsndfile-modified/m4/extra_pkg.m4 @@ -0,0 +1,105 @@ +# extra_pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- +# +# Copyright (c) 2008-2012 Erik de Castro Lopo +# Copyright (c) 2004 Scott James Remnant . +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# -------------------------------------------------------------- +# PKG_CHECK_MOD_VERSION(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +# [ACTION-IF-NOT-FOUND]) +# +# This is a very slight modification to the macro PKG_CHECK_MODULES that +# is in the original pkg.m4 file. It prints the versions in the checking +# message (erikd@mega-nerd.com). + +AC_DEFUN([PKG_CHECK_MOD_VERSION], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl +AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl + +pkg_failed=no +AC_MSG_CHECKING([for $2 ]) + +_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) +_PKG_CONFIG([$1][_LIBS], [libs], [$2]) + +pkg_link_saved_CFLAGS=$CFLAGS +pkg_link_saved_LIBS=$LIBS + +eval "pkg_CFLAGS=\${pkg_cv_[]$1[]_CFLAGS}" +eval "pkg_LIBS=\${pkg_cv_[]$1[]_LIBS}" + +CFLAGS="$CFLAGS $pkg_CFLAGS" +LIBS="$LIBS $pkg_LIBS" + +AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [puts ("")])], pkg_link=yes, pkg_link=no) + +CFLAGS=$pkg_link_saved_CFLAGS +LIBS=$pkg_link_saved_LIBS + +AS_IF([test x$pkg_link = xno], [ + AS_ECHO_N(["link failed ... "]) + pkg_failed=yes +]) + +m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS +and $1[]_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details.]) + +if test $pkg_failed = yes; then + _PKG_SHORT_ERRORS_SUPPORTED + if test $_pkg_short_errors_supported = yes; then + $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "$2"` + else + $1[]_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"` + fi + # Put the nasty error message in config.log where it belongs + echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD + + ifelse([$4], , [AC_MSG_ERROR(dnl +[Package requirements ($2) were not met: + +$$1_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +_PKG_TEXT +])], + [AC_MSG_RESULT([no]) + $4]) +elif test $pkg_failed = untried; then + ifelse([$4], , [AC_MSG_FAILURE(dnl +[The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +_PKG_TEXT + +To get pkg-config, see .])], + [$4]) +else + $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS + $1[]_LIBS=$pkg_cv_[]$1[]_LIBS + AC_MSG_RESULT([yes]) + ifelse([$3], , :, [$3]) +fi[]dnl +])# PKG_CHECK_MOD_VERSION diff --git a/extern/libsndfile-modified/m4/flexible_array.m4 b/extern/libsndfile-modified/m4/flexible_array.m4 new file mode 100644 index 000000000..661da17b2 --- /dev/null +++ b/extern/libsndfile-modified/m4/flexible_array.m4 @@ -0,0 +1,32 @@ +dnl @synopsis MN_C99_FLEXIBLE_ARRAY +dnl +dnl Dose the compiler support the 1999 ISO C Standard "stuct hack". +dnl @version 1.1 Mar 15 2004 +dnl @author Erik de Castro Lopo +dnl +dnl Permission to use, copy, modify, distribute, and sell this file for any +dnl purpose is hereby granted without fee, provided that the above copyright +dnl and this permission notice appear in all copies. No representations are +dnl made about the suitability of this software for any purpose. It is +dnl provided "as is" without express or implied warranty. + +AC_DEFUN([MN_C99_FLEXIBLE_ARRAY], +[AC_CACHE_CHECK(C99 struct flexible array support, + ac_cv_c99_flexible_array, + +# Initialize to unknown +ac_cv_c99_flexible_array=no + +AC_TRY_LINK([[ + #include + typedef struct { + int k; + char buffer [] ; + } MY_STRUCT ; + ]], + [ MY_STRUCT *p = calloc (1, sizeof (MY_STRUCT) + 42); ], + ac_cv_c99_flexible_array=yes, + ac_cv_c99_flexible_array=no + ))] +) # MN_C99_FLEXIBLE_ARRAY + diff --git a/extern/libsndfile-modified/m4/mkoctfile_version.m4 b/extern/libsndfile-modified/m4/mkoctfile_version.m4 new file mode 100644 index 000000000..04a58e573 --- /dev/null +++ b/extern/libsndfile-modified/m4/mkoctfile_version.m4 @@ -0,0 +1,38 @@ +dnl @synopsis OCTAVE_MKOCTFILE_VERSION +dnl +dnl Find the version of mkoctfile. +dnl @version 1.0 Aug 23 2007 +dnl @author Erik de Castro Lopo +dnl +dnl Permission to use, copy, modify, distribute, and sell this file for any +dnl purpose is hereby granted without fee, provided that the above copyright +dnl and this permission notice appear in all copies. No representations are +dnl made about the suitability of this software for any purpose. It is +dnl provided "as is" without express or implied warranty. +dnl + +AC_DEFUN([OCTAVE_MKOCTFILE_VERSION], +[ + + +AC_ARG_WITH(mkoctfile, + AS_HELP_STRING([--with-mkoctfile], [choose the mkoctfile version]), + [ with_mkoctfile=$withval ]) + +test -z "$with_mkoctfile" && with_mkoctfile=mkoctfile + +AC_CHECK_PROG(HAVE_MKOCTFILE,$with_mkoctfile,yes,no) + +if test "x$ac_cv_prog_HAVE_MKOCTFILE" = "xyes" ; then + MKOCTFILE=$with_mkoctfile + + AC_MSG_CHECKING([for version of $MKOCTFILE]) + MKOCTFILE_VERSION=`$with_mkoctfile --version 2>&1 | sed 's/mkoctfile, version //g'` + AC_MSG_RESULT($MKOCTFILE_VERSION) + fi + +AC_SUBST(MKOCTFILE) +AC_SUBST(MKOCTFILE_VERSION) + +])# OCTAVE_MKOCTFILE_VERSION + diff --git a/extern/libsndfile-modified/m4/octave.m4 b/extern/libsndfile-modified/m4/octave.m4 new file mode 100644 index 000000000..fda043d05 --- /dev/null +++ b/extern/libsndfile-modified/m4/octave.m4 @@ -0,0 +1,143 @@ +dnl Evaluate an expression in octave +dnl +dnl OCTAVE_EVAL(expr,var) -> var=expr +dnl +dnl Stolen from octave-forge + +AC_DEFUN([OCTAVE_EVAL], +[ +AC_MSG_CHECKING([for $1 in $OCTAVE]) +$2=`TERM=;$OCTAVE -qfH --eval "disp($1)"` +AC_MSG_RESULT($$2) +AC_SUBST($2) +]) # OCTAVE_EVAL + +dnl @synopsis AC_OCTAVE_VERSION +dnl +dnl Find the version of Octave. +dnl @version 1.0 Aug 23 2007 +dnl @author Erik de Castro Lopo +dnl +dnl Permission to use, copy, modify, distribute, and sell this file for any +dnl purpose is hereby granted without fee, provided that the above copyright +dnl and this permission notice appear in all copies. No representations are +dnl made about the suitability of this software for any purpose. It is +dnl provided "as is" without express or implied warranty. +dnl + +AC_DEFUN([AC_OCTAVE_VERSION], +[ + +AC_ARG_WITH(octave, + AS_HELP_STRING([--with-octave], [choose the octave version]), + [ with_octave=$withval ]) + +test -z "$with_octave" && with_octave=octave + +AC_CHECK_PROG(HAVE_OCTAVE,$with_octave,yes,no) + +if test "x$ac_cv_prog_HAVE_OCTAVE" = "xyes" ; then + OCTAVE=$with_octave + OCTAVE_EVAL(OCTAVE_VERSION,OCTAVE_VERSION) + fi + +AC_SUBST(OCTAVE) +AC_SUBST(OCTAVE_VERSION) + +])# AC_OCTAVE_VERSION + +dnl @synopsis AC_OCTAVE_CONFIG_VERSION +dnl +dnl Find the version of Octave. +dnl @version 1.0 Aug 23 2007 +dnl @author Erik de Castro Lopo +dnl +dnl Permission to use, copy, modify, distribute, and sell this file for any +dnl purpose is hereby granted without fee, provided that the above copyright +dnl and this permission notice appear in all copies. No representations are +dnl made about the suitability of this software for any purpose. It is +dnl provided "as is" without express or implied warranty. +dnl + +AC_DEFUN([AC_OCTAVE_CONFIG_VERSION], +[ + +AC_ARG_WITH(octave-config, + AS_HELP_STRING([--with-octave-config], [choose the octave-config version]), + [ with_octave_config=$withval ]) + +test -z "$with_octave_config" && with_octave_config=octave-config + +AC_CHECK_PROG(HAVE_OCTAVE_CONFIG,$with_octave_config,yes,no) + +if test "x$ac_cv_prog_HAVE_OCTAVE_CONFIG" = "xyes" ; then + OCTAVE_CONFIG=$with_octave_config + AC_MSG_CHECKING([for version of $OCTAVE_CONFIG]) + OCTAVE_CONFIG_VERSION=`$OCTAVE_CONFIG --version` + AC_MSG_RESULT($OCTAVE_CONFIG_VERSION) + fi + +AC_SUBST(OCTAVE_CONFIG) +AC_SUBST(OCTAVE_CONFIG_VERSION) + +])# AC_OCTAVE_CONFIG_VERSION + +dnl @synopsis AC_OCTAVE_BUILD +dnl +dnl Check programs and headers required for building octave plugins. +dnl @version 1.0 Aug 23 2007 +dnl @author Erik de Castro Lopo +dnl +dnl Permission to use, copy, modify, distribute, and sell this file for any +dnl purpose is hereby granted without fee, provided that the above copyright +dnl and this permission notice appear in all copies. No representations are +dnl made about the suitability of this software for any purpose. It is +dnl provided "as is" without express or implied warranty. + + +AC_DEFUN([AC_OCTAVE_BUILD], +[ + +dnl Default to no. +OCTAVE_BUILD=no + +AC_OCTAVE_VERSION +OCTAVE_MKOCTFILE_VERSION +AC_OCTAVE_CONFIG_VERSION + +prog_concat="$ac_cv_prog_HAVE_OCTAVE$ac_cv_prog_HAVE_OCTAVE_CONFIG$ac_cv_prog_HAVE_MKOCTFILE" + +if test "x$prog_concat" = "xyesyesyes" ; then + if test "x$OCTAVE_VERSION" != "x$MKOCTFILE_VERSION" ; then + AC_MSG_WARN([** Mismatch between versions of octave and mkoctfile. **]) + AC_MSG_WARN([** Octave libsndfile modules will not be built. **]) + elif test "x$OCTAVE_VERSION" != "x$OCTAVE_CONFIG_VERSION" ; then + AC_MSG_WARN([** Mismatch between versions of octave and octave-config. **]) + AC_MSG_WARN([** Octave libsndfile modules will not be built. **]) + else + case "$MKOCTFILE_VERSION" in + 2.*) + AC_MSG_WARN([Octave version 2.X is not supported.]) + ;; + 3.*) + OCTAVE_DEST_ODIR=`$OCTAVE_CONFIG --oct-site-dir | sed 's%^/usr%${prefix}%'` + OCTAVE_DEST_MDIR=`$OCTAVE_CONFIG --m-site-dir | sed 's%^/usr%${prefix}%'` + + OCTAVE_BUILD=yes + ;; + *) + AC_MSG_WARN([Octave version $MKOCTFILE_VERSION is not supported.]) + ;; + esac + fi + AC_MSG_RESULT([building octave libsndfile module... $OCTAVE_BUILD]) + fi + +AC_SUBST(OCTAVE_DEST_ODIR) +AC_SUBST(OCTAVE_DEST_MDIR) + +AC_SUBST(MKOCTFILE) + +AM_CONDITIONAL(BUILD_OCTAVE_MOD, test "x$OCTAVE_BUILD" = xyes) + +])# AC_OCTAVE_BUILD diff --git a/extern/libsndfile-modified/make_lite.py b/extern/libsndfile-modified/make_lite.py new file mode 100644 index 000000000..eee69fc82 --- /dev/null +++ b/extern/libsndfile-modified/make_lite.py @@ -0,0 +1,491 @@ +#!/usr/bin/python + +import commands, os, re, string, sys, time + +def count_enclosed_functions (source): + func_count = 0 + open_brace = 0 + close_brace = 0 + for ch in source: + if ch == '{': + open_brace += 1 + elif ch == '}': + close_brace += 1 + if open_brace == close_brace: + func_count += 1 + if open_brace < close_brace: + print "count_enclosed_functions : open_brace < close_brace" + return -1 + return func_count + +def find_function_prototype (source, proto_name): + proto_re = "(^[a-zA-Z_ \t]+\s+%s[^a-zA-Z0-9_]\s*\([^\)]+\)\s+;\n)" % (proto_name) + proto_result = re.search (proto_re, source, re.MULTILINE | re.DOTALL) + if not proto_result: + return None + proto_text = proto_result.groups ()[0] + return proto_text + +def find_function_definition (source, func_name): + func_re = "(\n[a-zA-Z_ \t]+\n%s[^a-zA-Z0-9_].* /\* %s \*/\n)" % (func_name, func_name) + func_result = re.search (func_re, source, re.MULTILINE | re.DOTALL) + if not func_result: + sys.exit (1) + return None + func_text = func_result.groups ()[0] + + # Now to check that we only have one enclosing function. + func_count = count_enclosed_functions (func_text) + if func_count != 1: + return None + return func_text + +def find_include (source, inc_name): + inc_re = "(^#include\s+[\<\"]%s[\"\>]\s*)" % inc_name + inc_result = re.search (inc_re, source, re.MULTILINE | re.DOTALL) + if not inc_result: + return None + inc_text = inc_result.groups ()[0] + return inc_text + +def find_assign_statement (source, var_name): + var_re = "(^\s+%s\s*=[^;]+;)" % var_name + var_result = re.search (var_re, source, re.MULTILINE | re.DOTALL) + if not var_result: + return None + assign_text = var_result.groups ()[0] + return assign_text + +#-------------------------------------------------------------------------------- + +def remove_include (source, inc_name): + inc_text = find_include (source, inc_name) + if not inc_text: + print "remove_include : include '%s' not found. Exiting." % inc_name + sys.exit (1) + + source = string.replace (source, inc_text, "") + return source + +def remove_assign (source, assign_name): + assign_text = find_assign (source, inc_name) + if not inc_text: + print "remove_include : include '%s' not found. Exiting." % inc_name + sys.exit (1) + + source = string.replace (source, inc_text, "") + return source + +def remove_prototype (source, proto_name): + proto_text = find_function_prototype (source, proto_name) + if not proto_text: + print "remove_prototype : prototype '%s' not found. Exiting." % proto_name + sys.exit (1) + + source = string.replace (source, proto_text, "") + return source + +def remove_function (source, func_name): + func_text = find_function_definition (source, func_name) + if not func_text: + print "remove_function : function '%s' not found. Exiting." % func_name + sys.exit (1) + + source = string.replace (source, func_text, "/* Function %s() removed here. */\n" % func_name) + return source + +def remove_all_assignments (source, var): + count = 0 + while 1: + assign_text = find_assign_statement (source, var) + if not assign_text: + if count != 0: + break + print "remove_all_assignments : variable '%s' not found. Exiting." % var + sys.exit (1) + + source = string.replace (source, assign_text, "") + count += 1 + return source + + + +#---------------------------------------------------------------- + +def remove_funcs_and_protos_from_file (filename, func_list): + source_code = open (filename, 'r').read () + + for func in func_list: + source_code = remove_prototype (source_code, func) ; + source_code = remove_function (source_code, func) ; + open (filename, 'w').write (source_code) + +def remove_funcs_from_file (filename, func_list): + source_code = open (filename, 'r').read () + + for func in func_list: + source_code = remove_function (source_code, func) ; + open (filename, 'w').write (source_code) + +def remove_protos_from_file (filename, func_list): + source_code = open (filename, 'r').read () + + for func in func_list: + source_code = remove_prototype (source_code, func) ; + open (filename, 'w').write (source_code) + +def remove_includes_from_file (filename, inc_list): + source_code = open (filename, 'r').read () + + for inc in inc_list: + source_code = remove_include (source_code, inc) ; + open (filename, 'w').write (source_code) + +def remove_all_assignments_from_file (filename, var_list): + source_code = open (filename, 'r').read () + + for var in var_list: + source_code = remove_all_assignments (source_code, var) ; + open (filename, 'w').write (source_code) + +def remove_comment_start_end (filename, start_comment, end_comment): + source_code = open (filename, 'r').read () + + while 1: + start_index = string.find (source_code, start_comment) + end_index = string.find (source_code, end_comment) + if start_index < 0 or end_index < start_index: + break + end_index += len (end_comment) + source_code = source_code [:start_index-1] + source_code [end_index:] ; + + open (filename, 'w').write (source_code) + +def remove_strings_from_file (filename, str_list): + file_text = open (filename, 'r').read () + for current_str in str_list: + file_text = string.replace (file_text, current_str, '') + open (filename, 'w').write (file_text) + +def string_replace_in_file (filename, from_str, to_str): + file_text = open (filename, 'r').read () + file_text = string.replace (file_text, from_str, to_str) + open (filename, 'w').write (file_text) + +def remove_regex_from_file (filename, regex_list): + file_text = open (filename, 'r').read () + for regex in regex_list: + file_text = re.sub (regex, '', file_text, re.MULTILINE | re.DOTALL) + open (filename, 'w').write (file_text) + +#========================================================================== + +def find_configure_version (filename): + # AM_INIT_AUTOMAKE(libsndfile,0.0.21pre6) + file = open (filename) + while 1: + line = file.readline () + if re.search ("AC_INIT", line): + x = re.sub ("[^\(]+\(", "", line) + x = re.sub ("\).*\n", "", x) + x = string.split (x, ",") + package = x [0] + version = x [1] + break + file.close () + # version = re.escape (version) + return package, version + +def fix_configure_ac_file (filename): + data = open (filename, 'r').read () + data = string.replace (data, "AM_INIT_AUTOMAKE(libsndfile,", "AM_INIT_AUTOMAKE(libsndfile_lite,", 1) + + file = open (filename, 'w') + file.write (data) + file.close () + + +def make_dist_file (package, version): + print "Making dist file." + tar_gz_file = "%s-%s.tar.gz" % (package, version) + if os.path.exists (tar_gz_file): + return + if os.system ("make dist"): + sys.exit (1) + return + +def delete_files (file_list): + for file_name in file_list: + os.remove (file_name) + +#======================================================================= + +source_dir = os.getcwd () + +conf_package, conf_version = find_configure_version ('configure.ac') + +package_version = "%s-%s" % (conf_package, conf_version) +lite_version = "%s_lite-%s" % (conf_package, conf_version) + +os.system ("rm -rf %s%s.tar.gz" % (source_dir, package_version)) + +os.system ("make dist") + +make_dist_file (conf_package, conf_version) + +os.chdir ("/tmp") + +print "Uncompressing .tar.gz file." +os.system ("rm -rf %s" % package_version) +if os.system ("tar zxf %s/%s.tar.gz" % (source_dir, package_version)): + sys.exit (1) + + +print "Renaming to libsndfile_lite." +os.system ("rm -rf %s" % lite_version) +os.rename (package_version, lite_version) + +print "Changing into libsndfile_lite directory." +os.chdir (lite_version) + +print "Removing un-neeed directories." +delete_dirs = [ 'src/G72x' ] + +for dir_name in delete_dirs: + os.system ("rm -rf %s" % dir_name) + +print "Removing un-needed files." +delete_files ([ 'src/ircam.c', 'src/nist.c', + 'src/ima_adpcm.c', 'src/ms_adpcm.c', 'src/au_g72x.c', + 'src/mat4.c', 'src/mat5.c', 'src/dwvw.c', 'src/paf.c', + 'src/ogg.c', 'src/pvf.c', 'src/xi.c', 'src/htk.c', + 'src/sd2.c', 'src/rx2.c', 'src/txw.c', 'src/wve.c', + 'src/dwd.c', 'src/svx.c', 'src/voc.c', 'src/vox_adpcm.c', + 'src/sds.c' + ]) + + +print "Hacking 'configure.ac' and 'src/Makefile.am'." +remove_strings_from_file ('configure.ac', [ 'src/G72x/Makefile' ]) +remove_strings_from_file ('src/Makefile.am', [ 'G72x/libg72x.la', 'G72x', + 'ircam.c', 'nist.c', 'ima_adpcm.c', 'ms_adpcm.c', 'au_g72x.c', 'mat4.c', + 'mat5.c', 'dwvw.c', 'paf.c', 'ogg.c', 'pvf.c', 'xi.c', 'htk.c', + 'sd2.c', 'rx2.c', 'txw.c', 'wve.c', 'dwd.c', 'svx.c', 'voc.c', + 'vox_adpcm.c', 'sds.c' + ]) + +#---------------------------------------------------------------------------- + +print "Hacking header files." + +remove_protos_from_file ('src/common.h', [ 'xi_open', 'sd2_open', 'ogg_open', + 'dwvw_init', 'paf_open', 'svx_open', 'nist_open', 'rx2_open', 'mat4_open', + 'voc_open', 'txw_open', 'dwd_open', 'htk_open', 'wve_open', 'mat5_open', + 'pvf_open', 'ircam_open', 'sds_open', + 'float32_init', 'double64_init', 'aiff_ima_init', 'vox_adpcm_init', + 'wav_w64_ima_init', 'wav_w64_msadpcm_init' + ]) + +remove_protos_from_file ('src/au.h', + [ 'au_g72x_reader_init', 'au_g72x_writer_init' ]) + +remove_protos_from_file ('src/wav_w64.h', [ 'msadpcm_write_adapt_coeffs' ]) + +#---------------------------------------------------------------------------- + +print "Hacking case statements." + +remove_comment_start_end ('src/sndfile.c', '/* Lite remove start */' , '/* Lite remove end */') +remove_comment_start_end ('src/aiff.c', '/* Lite remove start */' , '/* Lite remove end */') +remove_comment_start_end ('src/au.c', '/* Lite remove start */' , '/* Lite remove end */') +remove_comment_start_end ('src/raw.c', '/* Lite remove start */' , '/* Lite remove end */') +remove_comment_start_end ('src/w64.c', '/* Lite remove start */' , '/* Lite remove end */') +remove_comment_start_end ('src/wav.c', '/* Lite remove start */' , '/* Lite remove end */') +remove_comment_start_end ('src/double64.c', '/* Lite remove start */' , '/* Lite remove end */') +remove_comment_start_end ('src/float32.c', '/* Lite remove start */' , '/* Lite remove end */') + + +#---------------------------------------------------------------------------- + +print "Hacking src/pcm.c." +remove_funcs_from_file ('src/pcm.c', [ + 'f2sc_array', 'f2sc_clip_array', 'f2uc_array', 'f2uc_clip_array', + 'f2bes_array', 'f2bes_clip_array', 'f2les_array', 'f2les_clip_array', + 'f2let_array', 'f2let_clip_array', 'f2bet_array', 'f2bet_clip_array', + 'f2bei_array', 'f2bei_clip_array', 'f2lei_array', 'f2lei_clip_array', + 'd2sc_array', 'd2sc_clip_array', 'd2uc_array', 'd2uc_clip_array', + 'd2bes_array', 'd2bes_clip_array', 'd2les_array', 'd2les_clip_array', + 'd2let_array', 'd2let_clip_array', 'd2bet_array', 'd2bet_clip_array', + 'd2bei_array', 'd2bei_clip_array', 'd2lei_array', 'd2lei_clip_array', + ]) + +remove_funcs_and_protos_from_file ('src/pcm.c', [ + 'pcm_read_sc2f', 'pcm_read_uc2f', 'pcm_read_les2f', 'pcm_read_bes2f', + 'pcm_read_let2f', 'pcm_read_bet2f', 'pcm_read_lei2f', 'pcm_read_bei2f', + 'pcm_read_sc2d', 'pcm_read_uc2d', 'pcm_read_les2d', 'pcm_read_bes2d', + 'pcm_read_let2d', 'pcm_read_bet2d', 'pcm_read_lei2d', 'pcm_read_bei2d', + 'pcm_write_f2sc', 'pcm_write_f2uc', 'pcm_write_f2bes', 'pcm_write_f2les', + 'pcm_write_f2bet', 'pcm_write_f2let', 'pcm_write_f2bei', 'pcm_write_f2lei', + 'pcm_write_d2sc', 'pcm_write_d2uc', 'pcm_write_d2bes', 'pcm_write_d2les', + 'pcm_write_d2bet', 'pcm_write_d2let', 'pcm_write_d2bei', 'pcm_write_d2lei', + + 'sc2f_array', 'uc2f_array', 'bes2f_array', 'les2f_array', + 'bet2f_array', 'let2f_array', 'bei2f_array', 'lei2f_array', + 'sc2d_array', 'uc2d_array', 'bes2d_array', 'les2d_array', + 'bet2d_array', 'let2d_array', 'bei2d_array', 'lei2d_array' + ]) + +remove_includes_from_file ('src/pcm.c', [ 'float_cast.h' ]) +remove_all_assignments_from_file ('src/pcm.c', [ + 'psf-\>write_float', 'psf\-\>write_double', + 'psf-\>read_float', 'psf\-\>read_double' ]) + +#---------------------------------------------------------------------------- +print "Hacking src/ulaw.c." +remove_funcs_and_protos_from_file ('src/ulaw.c', [ + 'ulaw_read_ulaw2f', 'ulaw_read_ulaw2d', + 'ulaw_write_f2ulaw', 'ulaw_write_d2ulaw', + 'ulaw2f_array', 'ulaw2d_array', 'f2ulaw_array', 'd2ulaw_array' + ]) + +remove_includes_from_file ('src/ulaw.c', [ 'float_cast.h' ]) +remove_all_assignments_from_file ('src/ulaw.c', [ + 'psf-\>write_float', 'psf\-\>write_double', + 'psf-\>read_float', 'psf\-\>read_double' ]) + +#---------------------------------------------------------------------------- + +print "Hacking src/alaw.c." +remove_funcs_and_protos_from_file ('src/alaw.c', [ + 'alaw_read_alaw2f', 'alaw_read_alaw2d', + 'alaw_write_f2alaw', 'alaw_write_d2alaw', + 'alaw2f_array', 'alaw2d_array', 'f2alaw_array', 'd2alaw_array' + ]) + +remove_includes_from_file ('src/alaw.c', [ 'float_cast.h' ]) +remove_all_assignments_from_file ('src/alaw.c', [ + 'psf-\>write_float', 'psf\-\>write_double', + 'psf-\>read_float', 'psf\-\>read_double' ]) + +#---------------------------------------------------------------------------- + +print "Hacking src/gsm610.c." +remove_funcs_and_protos_from_file ('src/gsm610.c', [ + 'gsm610_read_f', 'gsm610_read_d', 'gsm610_write_f', 'gsm610_write_d' + ]) + +remove_includes_from_file ('src/gsm610.c', [ 'float_cast.h' ]) +remove_all_assignments_from_file ('src/gsm610.c', [ + 'psf-\>write_float', 'psf\-\>write_double', + 'psf-\>read_float', 'psf\-\>read_double' ]) + +#---------------------------------------------------------------------------- + +print "Hacking src/float32.c." + +# string_replace_in_file ('src/float32.c', '"float_cast.h"', '') +remove_funcs_from_file ('src/float32.c', [ 'float32_init' ]) + +remove_funcs_and_protos_from_file ('src/float32.c', [ + 'host_read_f2s', 'host_read_f2i', 'host_read_f', 'host_read_f2d', + 'host_write_s2f', 'host_write_i2f', 'host_write_f', 'host_write_d2f', + 'f2s_array', 'f2i_array', 'f2d_array', 's2f_array', 'i2f_array', 'd2f_array', + 'float32_peak_update', + 'replace_read_f2s', 'replace_read_f2i', 'replace_read_f', 'replace_read_f2d', + 'replace_write_s2f', 'replace_write_i2f', 'replace_write_f', 'replace_write_d2f', + 'bf2f_array', 'f2bf_array', + 'float32_get_capability', + ]) + +#---------------------------------------------------------------------------- + +print "Hacking src/double64.c." +remove_funcs_from_file ('src/double64.c', [ 'double64_init' ]) + +remove_funcs_and_protos_from_file ('src/double64.c', [ + 'host_read_d2s', 'host_read_d2i', 'host_read_d2f', 'host_read_d', + 'host_write_s2d', 'host_write_i2d', 'host_write_f2d', 'host_write_d', + 'd2s_array', 'd2i_array', 'd2f_array', + 's2d_array', 'i2d_array', 'f2d_array', + 'double64_peak_update', 'double64_get_capability', + 'replace_read_d2s', 'replace_read_d2i', 'replace_read_d2f', 'replace_read_d', + 'replace_write_s2d', 'replace_write_i2d', 'replace_write_f2d', 'replace_write_d', + 'd2bd_read', 'bd2d_write' + ]) + +#---------------------------------------------------------------------------- + +print "Hacking test programs." +delete_files ([ 'tests/dwvw_test.c', 'tests/floating_point_test.c', + 'tests/dft_cmp.c', 'tests/peak_chunk_test.c', + 'tests/scale_clip_test.tpl', 'tests/scale_clip_test.def' + ]) + +remove_comment_start_end ('tests/write_read_test.def', '/* Lite remove start */', '/* Lite remove end */') +remove_comment_start_end ('tests/write_read_test.tpl', '/* Lite remove start */', '/* Lite remove end */') + +remove_comment_start_end ('tests/Makefile.am', '# Lite remove start', '# Lite remove end') + +remove_strings_from_file ('tests/Makefile.am', [ + 'scale_clip_test.tpl', 'scale_clip_test.def', + '\n\t./dwvw_test', + '\n\t./floating_point_test', '\n\t./scale_clip_test', + '\n\t./peak_chunk_test aiff', '\n\t./peak_chunk_test wav', + '\n\t./command_test norm', '\n\t./command_test peak', + '\n\t./lossy_comp_test wav_ima', '\n\t./lossy_comp_test wav_msadpcm', + '\n\t./lossy_comp_test au_g721', '\n\t./lossy_comp_test au_g723', + '\n\t./lossy_comp_test vox_adpcm', + '\n\t./lossy_comp_test w64_ima', '\n\t./lossy_comp_test w64_msadpcm', + 'peak_chunk_test', 'dwvw_test', 'floating_point_test', 'scale_clip_test', + + 'paf-tests', 'svx-tests', 'nist-tests', 'ircam-tests', 'voc-tests', + 'mat4-tests', 'mat5-tests', 'pvf-tests', 'xi-tests', 'htk-tests', + 'sds-tests' + ]) + +remove_comment_start_end ('tests/pcm_test.c', '/* Lite remove start */', '/* Lite remove end */') +remove_funcs_and_protos_from_file ('tests/pcm_test.c', [ + 'pcm_test_float', 'pcm_test_double' + ]) + +remove_comment_start_end ('tests/lossy_comp_test.c', '/* Lite remove start */', '/* Lite remove end */') +remove_funcs_and_protos_from_file ('tests/lossy_comp_test.c', [ + 'lcomp_test_float', 'lcomp_test_double', 'sdlcomp_test_float', 'sdlcomp_test_double', + 'smoothed_diff_float', 'smoothed_diff_double' + ]) + +remove_comment_start_end ('tests/multi_file_test.c', '/* Lite remove start */', '/* Lite remove end */') + +remove_strings_from_file ('tests/stdio_test.c', [ + '"paf",', '"svx",', '"nist",', '"ircam",', '"voc",', '"mat4",', '"mat5",', '"pvf",' + ]) + +remove_comment_start_end ('tests/pipe_test.c', '/* Lite remove start */', '/* Lite remove end */') + +#---------------------------------------------------------------------------- + +print "Fixing configure.ac file." +fix_configure_ac_file ('configure.ac') + +print "Building and testing source." + # Try --disable-shared --disable-gcc-opt +if os.system ("./reconfigure.mk && ./configure --disable-shared --disable-gcc-opt && make check"): + os.system ('PS1="FIX > " bash --norc') + sys.exit (1) + +print "Making distcheck" +if os.system ("make distcheck"): + os.system ('PS1="FIX > " bash --norc') + sys.exit (1) + +print "Copying tarball" +if os.system ("cp %s.tar.gz %s" % (lite_version, source_dir)): + print "??? %s.tar.gz ???" % lite_version + os.system ('PS1="FIX > " bash --norc') + sys.exit (1) + +os.chdir (source_dir) + +os.system ("rm -rf /tmp/%s" % lite_version) + +print "Done." diff --git a/extern/libsndfile-modified/man/sndfile-cmp.1 b/extern/libsndfile-modified/man/sndfile-cmp.1 new file mode 100644 index 000000000..88aaafe7e --- /dev/null +++ b/extern/libsndfile-modified/man/sndfile-cmp.1 @@ -0,0 +1,29 @@ +.Dd November 2, 2014 +.Dt SNDFILE-CMP 1 +.Os +.Sh NAME +.Nm sndfile-cmp +.Nd compare two audio files +.Sh SYNOPSIS +.Nm sndfile-cmp +.Ar file1 +.Ar file2 +.Sh DESCRIPTION +.Nm +compares the audio data of two sound files. +For two files to compare as being the same, their channel counts, sample rate, +audio data lengths and actual audio data must match. +Other differences such as string metadata like song title, artist etc and their +presence or absence are ignored. +.Sh EXIT STATUS +.Bl -tag -width 1n -compact +.It 0 +The audio data is the same. +.It 1 +The audio data differs. +.El +.Sh SEE ALSO +.Lk http://libsndfile.github.io/libsndfile/ +.Sh AUTHORS +.An Conrad Parker Aq Mt conrad@metadecks.org +.An Erik de Castro Lopo Aq Mt erikd@mega-nerd.com diff --git a/extern/libsndfile-modified/man/sndfile-concat.1 b/extern/libsndfile-modified/man/sndfile-concat.1 new file mode 100644 index 000000000..3ba34c74a --- /dev/null +++ b/extern/libsndfile-modified/man/sndfile-concat.1 @@ -0,0 +1,28 @@ +.Dd November 2, 2014 +.Dt SNDFILE-CONCAT 1 +.Os +.Sh NAME +.Nm sndfile-concat +.Nd concatenate audio data from two or more audio files +.Sh SYNOPSIS +.Nm sndfile-concat +.Ar infile1 +.Ar infile2 +.Ar ... +.Ar outfile +.Sh DESCRIPTION +.Nm +generates a new output file by concatenating the audio data +of two or more input files. The encoding of the output file +is the encoding used in +.Ar infile1 . +Audio data from the subsequent files are converted to this encoding. +The only restriction is that the files must have +the same number of channels. +The output file is overwritten if it already exists. +.Sh EXIT STATUS +.Ex -std +.Sh SEE ALSO +.Lk http://libsndfile.github.io/libsndfile/ +.Sh AUTHORS +.An Erik de Castro Lopo Aq Mt erikd@mega-nerd.com diff --git a/extern/libsndfile-modified/man/sndfile-convert.1 b/extern/libsndfile-modified/man/sndfile-convert.1 new file mode 100644 index 000000000..e7156eec1 --- /dev/null +++ b/extern/libsndfile-modified/man/sndfile-convert.1 @@ -0,0 +1,160 @@ +.Dd November 2, 2014 +.Dt SNDFILE-CONVERT 1 +.Os +.Sh NAME +.Nm sndfile-convert +.Nd convert sound files from one format to another +.Sh SYNOPSIS +.Nm sndfile-convert +.Op Fl override-sample-rate Ns = Ns Ar rate +.Op Fl endian Ns = Ns Cm little | big | cpu +.Op Fl normalize +.Op Ar encoding +.Ar input +.Ar output +.Sh DESCRIPTION +.Nm +converts sound files from one audio format to another. +The output file is overwritten it it already exists. +.Ss Formats +The format of the output file is determined by the filename extension. +The following file formats are currently recognized: +.Pp +.Bl -tag -compact -width ircam +.It wav +WAV (Microsoft) +.It aif +AIFF (Apple/SGI) +.It au +AU (Sun/NeXT) +.It snd +AU (Sun/NeXT) +.It raw +RAW (header-less) +.It gsm +RAW (header-less) +.It vox +RAW (header-less) +.It paf +PAF (Ensoniq PARIS, big-endian) +.It fap +PAF (Ensoniq PARIS, little-endian) +.It svx +IFF (Amiga IFF/SVX8/SV16) +.It nist +SPHERE (NIST SPeech HEader Resources) +.It sph +SPHERE (NIST SPeech HEader Resources) +.It voc +VOC (Creative Labs) +.It ircam +SF (Berkeley/IRCAM/CARL) +.It sf +SF (Berkeley/IRCAM/CARL) +.It w64 +W64 (SoundFoundry WAVE 64) +.It mat +MAT4 (GNU Octave 2.0 / Matlab 4.2) +.It mat4 +MAT4 (GNU Octave 2.0 / Matlab 4.2) +.It mat5 +MAT5 (GNU Octave 2.1 / Matlab 5.0) +.It pvf +PVF (Portable Voice Format) +.It xi +XI (FastTracker 2) +.It htk +HTK (HMM Tool Kit) +.It sds +SDS (Midi Sample Dump Standard) +.It avr +AVR (Audio Visual Research) +.It wavex +WAVEX (MS WAVE with WAVEFORMATEX) +.It sd2 +SD2 (Sound Designer II) +.It flac +FLAC (FLAC Lossless Audio Codec) +.It caf +CAF (Apple Core Audio File) +.It wve +WVE (Psion Series 3) +.It prc +WVE (Psion Series 3) +.It ogg +OGG (OGG Container format) +.It oga +OGG (OGG Container format) +.It mpc +MPC (Akai MPC 2k) +.It rf64 +RF64 (RIFF 64) +.El +.Ss Options +The following options are recoginzed: +.Pp +.Bl -tag -compact -width "override-sample-rate=XXXXX" +.It Fl override-sample-rate Ns = Ns Ar rate +Make the input use sample rate of +.Ar rate +Hz. +.It Fl endian Ns = Ns Cm little +Make the output file use little endian data. +.It Fl endian Ns = Ns Cm big +Make the output file use big endian data. +.It Fl endian Ns = Ns Cm cpu +Make the output file use CPU endianness. +.It Fl normalize +Normalize the audio data in the output file. +.El +.Ss Encodings +The optional +.Ar encoding +parameter allows setting of the data encoding for the output file. +The following encodings are currently supported: +.Pp +.Bl -tag -compact -width ima-adpcmXX +.It Fl pcms8 +signed 8 bit pcm +.It Fl pcmu8 +unsigned 8 bit pcm +.It Fl pcm16 +16 bit pcm +.It Fl pcm24 +24 bit pcm +.It Fl pcm32 +32 bit pcm +.It Fl float32 +32 bit floating point +.It Fl ulaw +ULAW +.It Fl alaw +ALAW +.It Fl ima-adpcm +IMA ADPCM (WAV only) +.It Fl ms-adpcm +MS ADPCM (WAV only) +.It Fl gsm610 +GSM6.10 (WAV only) +.It Fl dwvw12 +12 bit DWVW (AIFF only) +.It Fl dwvw16 +16 bit DWVW (AIFF only) +.It Fl dwvw24 +24 bit DWVW (AIFF only) +.It Fl vorbis +Vorbis (OGG only) +.El +.Pp +If no encoding is specified for the output file, +.Nm +will try to use the encoding of the input file. +This will not always work as most container formats +(e.g. WAV, AIFF etc) only support a small subset of encodings +(e.g. 16 bit PCM, a-law, Vorbis etc). +.Sh EXIT STATUS +.Ex -std +.Sh SEE ALSO +.Lk http://libsndfile.github.io/libsndfile/ +.Sh AUTHORS +.An Erik de Castro Lopo Aq Mt erikd@mega-nerd.com . diff --git a/extern/libsndfile-modified/man/sndfile-info.1 b/extern/libsndfile-modified/man/sndfile-info.1 new file mode 100644 index 000000000..a8c3749ad --- /dev/null +++ b/extern/libsndfile-modified/man/sndfile-info.1 @@ -0,0 +1,34 @@ +.Dd November 2, 2014 +.Dt SNDFILE-INFO 1 +.Os +.Sh NAME +.Nm sndfile-info +.Nd display information about sound files +.Sh SYNOPSIS +.Nm sndfile-info +.Op Fl -broadcast +.Op Fl -cart +.Op Fl -channel-map +.Op Fl -instrument +.Ar +.Sh DESCRIPTION +.Nm +displays basic information about sound files +such as format, number of channels, samplerate, and length. +The following options are recognized: +.Pp +.Bl -tag -compact -width channelmapXXXX +.It Fl -broadcast +Display broadcast (BWF) info. +.It Fl -cart +Display the cart chunk of a WAV (or related) file. +.It Fl -channel-map +Display channel map. +.It Fl -instrument +Display instrument info: +a base note, gain, velocity, key, and loop points. +.El +.Sh SEE ALSO +.Lk http://libsndfile.github.io/libsndfile/ +.Sh AUTHORS +.An Erik de Castro Lopo Aq Mt erikd@mega-nerd.com . diff --git a/extern/libsndfile-modified/man/sndfile-interleave.1 b/extern/libsndfile-modified/man/sndfile-interleave.1 new file mode 100644 index 000000000..0cf70764f --- /dev/null +++ b/extern/libsndfile-modified/man/sndfile-interleave.1 @@ -0,0 +1,62 @@ +.Dd November 2, 2014 +.Dt SNDFILE-INTERLEAVE 1 +.Os +.Sh NAME +.Nm sndfile-interleave , +.Nm sndfile-deinterleave +.Nd convert mono files into a multi-channel file and vice versa +.Sh SYNOPSIS +.Nm sndfile-interleave +.Ar input1 +.Ar input2 +.Ar ... +.Fl o Ar output +.Nm sndfile-deinterleave +.Ar file +.Sh DESCRIPTION +.Nm sndfile-interleave +creates a multi-channel file taking audio data +from two or more mono files as individual channels. +The format of the output file is determined by its filename suffix. +The audio parameters of the output file will be made so that +the format can accommodate each of the mono inputs; +for example, the samplerate will be the maximal samplerate +occurring in the inputs. +The output file will be overwritten if it already exists. +.Pp +.Nm sndfile-deinterleave +creates two or more mono files from a multi-channel audio file, +containing data from the individual channels. The names of the +resulting mono files are of the form +.Dq name_XY.suf +where +.Em name +and +.Em suf +are the basename and suffix of the original file. +If any file of such name already exists, it will be overwritten. +Apart from the number of channels, +the audio format of the resulting mono files +is the same as that of the original file. +.Sh EXIT STATUS +.Ex -std +.Sh EXAMPLES +Merge a mono OGG file and a mono FLAC file into a stereo WAV file: +.Bd -literal -offset indent +$ sndfile-interleave left.ogg right.flac -o stereo.wav +.Ed +.Pp +Split a multi-channel into individual mono files: +.Bd -literal -offset indent +$ sndfile-deinterleave multi.wav +Input file : multi +Output files : + multi_00.wav + multi_01.wav + multi_02.wav + multi_03.wav +.Ed +.Sh SEE ALSO +.Lk http://libsndfile.github.io/libsndfile/ +.Sh AUTHORS +.An Erik de Castro Lopo Aq Mt erikd@mega-nerd.com diff --git a/extern/libsndfile-modified/man/sndfile-metadata-get.1 b/extern/libsndfile-modified/man/sndfile-metadata-get.1 new file mode 100644 index 000000000..61dfae787 --- /dev/null +++ b/extern/libsndfile-modified/man/sndfile-metadata-get.1 @@ -0,0 +1,116 @@ +.Dd November 2, 2014 +.Dt SNDFILE-METADATA-GET 1 +.Os +.Sh NAME +.Nm sndfile-metadata-get , +.Nm sndfile-metadata-set +.Nd get or set metadata in a sound file +.Sh SYNOPSIS +.Nm sndfile-metadata-get +.Op Ar options +.Ar file +.Nm sndfile-metadata-set +.Op Ar options +.Ar file +.Nm sndfile-metadata-set +.Op Ar options +.Ar input +.Ar output +.Sh DESCRIPTION +.Nm sndfile-metadata-get +displays bext and string metadata stored in an audio file. +The following options specify what to print. +.Pp +.Bl -tag -width bext-descriptionXXXX -compact +.It Fl -all +all metadata +.It Fl -bext-description +description +.It Fl -bext-originator +originator info +.It Fl -bext-orig-ref +originator reference +.It Fl -bext-umid +Unique Material Identifier +.It Fl -bext-orig-date +origination date +.It Fl -bext-orig-time +origination time +.It Fl -bext-coding-hist +coding history +.It Fl -str-title +title +.It Fl -str-copyright +copyright +.It Fl -str-artist +artist +.It Fl -str-comment +comment +.It Fl -str-date +creation date +.It Fl -str-album +album +.It Fl -str-license +license +.El +.Pp +.Nm sndfile-metadata-set +sets bext and string metadata in an audio file if the format supports it. +If the file does not contain a BEXT chunk to be modified, +the second synopsis must be used, where another output file +capable of storing the metadata is created. +This file is overwritten if it already exists. +The following options take an argument specifying the metadata: +.Pp +.Bl -tag -width bext-coding-histXXXXXXX -compact +.It Fl -bext-description +description +.It Fl -bext-originator +originator +.It Fl -bext-orig-ref +originator reference +.It Fl -bext-umid +Unique Material Identifier +.It Fl -bext-orig-date +origination date +.It Fl -bext-orig-time +origination time +.It Fl -bext-coding-hist +coding history +.It Fl -bext-time-raf +time reference +.It Fl -str-comment +comment +.It Fl -str-title +title +.It Fl -str-copyright +copyright +.It Fl -str-artist +artist +.It Fl -str-date +date +.It Fl -str-album +album +.It Fl -str-license +license +.El +.Pp +The following options take no argument: +.Pp +.Bl -tag -width bext-coding-histXXXXXXX -compact +.It Fl -bext-auto-time-date +Set the BEXT time and date to current. +.It Fl -bext-auto-time +Set the BEXT time to current. +.It Fl -bext-auto-date +Set the BEXT date to current. +.It Fl -str-auto-date +Set the string date to current. +.El +.Sh EXIT STATUS +.Ex -std +.Sh SEE ALSO +.Lk http://libsndfile.github.io/libsndfile/ +.Lk http://tech.ebu.ch/docs/tech/tech3285.pdf +.Sh AUTHORS +.An Erik de Castro Lopo Aq Mt erikd@mega-nerd.com diff --git a/extern/libsndfile-modified/man/sndfile-play.1 b/extern/libsndfile-modified/man/sndfile-play.1 new file mode 100644 index 000000000..4d570eafd --- /dev/null +++ b/extern/libsndfile-modified/man/sndfile-play.1 @@ -0,0 +1,36 @@ +.Dd September 10, 2021 +.Dt SNDFILE-PLAY 1 +.Os +.Sh NAME +.Nm sndfile-play +.Nd play a sound file +.Sh SYNOPSIS +.Nm sndfile-play +.Ar +.Sh DESCRIPTION +.Nm +plays one or more sound files on various operating systems using standard audio +output APIs. The following table summarizes which audio API is used where: +.Pp +.Bl -tag -width MacOSX10XXX -compact +.It Linux +ALSA or OSS +.It OpenBSD +sndio +.It FreeBSD +/dev/dsp (OSS) +.It NetBSD +/dev/audio +.It Solaris +/dev/audio +.It MacOSX 10.6 +CoreAudio +.It MacOSX 10.7 +AudioToolbox +.It Win32 +waveOut +.El +.Sh SEE ALSO +.Lk http://libsndfile.github.io/libsndfile/ +.Sh AUTHORS +.An Erik de Castro Lopo Aq Mt erikd@mega-nerd.com diff --git a/extern/libsndfile-modified/man/sndfile-salvage.1 b/extern/libsndfile-modified/man/sndfile-salvage.1 new file mode 100644 index 000000000..b2010f1b1 --- /dev/null +++ b/extern/libsndfile-modified/man/sndfile-salvage.1 @@ -0,0 +1,25 @@ +.Dd November 2, 2014 +.Dt SNDFILE-SALVAGE 1 +.Os +.Sh NAME +.Nm sndfile-salvage +.Nd salvage audio data from WAV files longer than 4G +.Sh SYNOPSIS +.Nm sndfile-salvage +.Ar toolong.wav +.Ar fixed64.wav +.Sh DESCRIPTION +Audio files using the WAV file container are inherently limited to 4G of data +size fields in the WAV header being stored as unsigned 32bit integers. +Many applications have trouble with these WAV files +that are more the 4G in size. +.Nm +rewrites the WAV file into a W64 file with the same audio content. +This file is overwritten if it already exists. +.Sh EXIT STATUS +.Ex -std +.Sh SEE ALSO +.Lk http://libsndfile.github.io/libsndfile/ +.\".Lk http://en.wikipedia.org/wiki/RF64 +.Sh AUTHORS +.An Erik de Castro Lopo Aq Mt erikd@mega-nerd.com diff --git a/extern/libsndfile-modified/ossfuzz/.gitignore b/extern/libsndfile-modified/ossfuzz/.gitignore new file mode 100644 index 000000000..6e9ed16a4 --- /dev/null +++ b/extern/libsndfile-modified/ossfuzz/.gitignore @@ -0,0 +1 @@ +sndfile_fuzzer diff --git a/extern/libsndfile-modified/ossfuzz/ci_oss.sh b/extern/libsndfile-modified/ossfuzz/ci_oss.sh new file mode 100755 index 000000000..408b00d29 --- /dev/null +++ b/extern/libsndfile-modified/ossfuzz/ci_oss.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +set -ex + +PROJECT_NAME=libsndfile + +# Clone the oss-fuzz repository +git clone https://github.com/google/oss-fuzz.git /tmp/ossfuzz + +if [[ ! -d /tmp/ossfuzz/projects/${PROJECT_NAME} ]] +then + echo "Could not find the ${PROJECT_NAME} project in ossfuzz" + + # Exit with a success code while the libsndfile project is not expected to exist + # on oss-fuzz. + exit 0 +fi + +# Work out which branch to clone from, inside Docker +BRANCH=${GITHUB_REF} + +# Modify the oss-fuzz Dockerfile so that we're checking out the current reference on CI. +sed -i "s@RUN.*@RUN git config --global remote.origin.fetch '+refs/pull/*:refs/remotes/origin/pull/*' \&\& git clone https://github.com/libsndfile/libsndfile.git /src/libsndfile \&\& cd /src/libsndfile \&\& git checkout -b ${BRANCH}@" /tmp/ossfuzz/projects/${PROJECT_NAME}/Dockerfile + +# Try and build the fuzzers +pushd /tmp/ossfuzz +python3 infra/helper.py build_image --pull ${PROJECT_NAME} +python3 infra/helper.py build_fuzzers ${PROJECT_NAME} +python3 infra/helper.py check_build ${PROJECT_NAME} --engine libfuzzer --sanitizer address --architecture x86_64 +popd diff --git a/extern/libsndfile-modified/ossfuzz/ossfuzz.sh b/extern/libsndfile-modified/ossfuzz/ossfuzz.sh new file mode 100755 index 000000000..7b3666ffc --- /dev/null +++ b/extern/libsndfile-modified/ossfuzz/ossfuzz.sh @@ -0,0 +1,32 @@ +#!/bin/bash -eu + +# This script is called by the oss-fuzz main project when compiling the fuzz +# targets. This script is regression tested by ci_oss.sh. + +# Save off the current folder as the build root. +export BUILD_ROOT=$PWD + +echo "CC: ${CC:-}" +echo "CXX: ${CXX:-}" +echo "LIB_FUZZING_ENGINE: ${LIB_FUZZING_ENGINE:-}" +echo "CFLAGS: ${CFLAGS:-}" +echo "CXXFLAGS: ${CXXFLAGS:-}" +echo "OUT: ${OUT:-}" + +export MAKEFLAGS+="-j$(nproc)" + +# Install dependencies +apt-get -y install autoconf autogen automake libtool pkg-config python + +# For now, do not install the following libraries (as they won't be in the +# final image): +# libasound2-dev libflac-dev libogg-dev libopus-dev libvorbis-dev + +# Compile the fuzzer. +autoreconf -vif +./configure --disable-shared --enable-ossfuzzers +make V=1 + +# Copy the fuzzer to the output directory. +cp -v ossfuzz/sndfile_fuzzer $OUT/ +cp -v ossfuzz/sndfile_alt_fuzzer $OUT/ diff --git a/extern/libsndfile-modified/ossfuzz/sndfile_alt_fuzzer.cc b/extern/libsndfile-modified/ossfuzz/sndfile_alt_fuzzer.cc new file mode 100644 index 000000000..e69fcdf30 --- /dev/null +++ b/extern/libsndfile-modified/ossfuzz/sndfile_alt_fuzzer.cc @@ -0,0 +1,79 @@ +#include +#include +#include +#include +#include + +#include "sndfile_fuzz_header.h" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ // One byte is needed for deciding which function to target. + if (size == 0) + return 0 ; + + const uint8_t decider = *data ; + data += 1 ; + size -= 1 ; + + SF_INFO sndfile_info ; + VIO_DATA vio_data ; + SF_VIRTUAL_IO vio ; + SNDFILE *sndfile = NULL ; + int err = sf_init_file(data, size, &sndfile, &vio_data, &vio, &sndfile_info) ; + if (err) + goto EXIT_LABEL ; + + // Just the right number of channels. Create some buffer space for reading. + switch (decider % 3) + { case 0 : + { + short* read_buffer = NULL ; + read_buffer = (short*)malloc(sizeof(short) * size); + if (read_buffer == NULL) + abort() ; + + while (sf_read_short(sndfile, read_buffer, size)) + { + // Do nothing with the data. + } + free(read_buffer) ; + } + break ; + case 1 : + { + int* read_buffer = NULL ; + read_buffer = (int*)malloc(sizeof(int) * size) ; + if (read_buffer == NULL) + abort() ; + + while (sf_read_int(sndfile, read_buffer, size)) + { + // Do nothing with the data. + } + free(read_buffer) ; + } + break ; + case 2 : + { + double* read_buffer = NULL ; + read_buffer = (double*)malloc(sizeof(double) * size) ; + if (read_buffer == NULL) + abort() ; + + while (sf_read_double(sndfile, read_buffer, size)) + { + // Do nothing with the data. + } + free(read_buffer) ; + } + break ; + default : + break ; + } ; + + EXIT_LABEL: + if (sndfile != NULL) + sf_close(sndfile); + + return 0 ; +} diff --git a/extern/libsndfile-modified/ossfuzz/sndfile_fuzz_header.h b/extern/libsndfile-modified/ossfuzz/sndfile_fuzz_header.h new file mode 100644 index 000000000..898aec441 --- /dev/null +++ b/extern/libsndfile-modified/ossfuzz/sndfile_fuzz_header.h @@ -0,0 +1,119 @@ +#ifndef SNDFILE_FUZZ_HEADER_H +#define SNDFILE_FUZZ_HEADER_H + +typedef struct +{ + sf_count_t offset ; + sf_count_t length ; + const unsigned char *data ; +} VIO_DATA ; + +static sf_count_t vfget_filelen (void *user_data) +{ VIO_DATA *vf = (VIO_DATA *)user_data ; + return vf->length ; +} + +static sf_count_t vfseek (sf_count_t offset, int whence, void *user_data) +{ + VIO_DATA *vf = (VIO_DATA *)user_data ; + sf_count_t new_offset ; + + switch (whence) + { case SEEK_SET : + new_offset = offset ; + break ; + + case SEEK_CUR : + new_offset = vf->offset + offset ; + break ; + + case SEEK_END : + new_offset = vf->length + offset ; + break ; + + default : + break ; + } + + /* Ensure you can't seek outside the data */ + if (new_offset > vf->length) + { /* Trying to seek past the end of the data */ + printf("vf overseek: new_offset(%" PRId64 ") > vf->length(%" PRId64 ");" + " whence(%d), vf->offset(%" PRId64 "), offset(%" PRId64 ")\n", + new_offset, vf->length, whence, vf->offset, offset) ; + new_offset = vf->length ; + } + else if (new_offset < 0) + { /* Trying to seek before the start of the data */ + printf("vf underseek: new_offset(%" PRId64 ") < 0; whence(%d), vf->offset" + "(%" PRId64 "), vf->length(%" PRId64 "), offset(%" PRId64 ")\n", + new_offset, whence, vf->offset, vf->length, offset) ; + new_offset = 0 ; + } + vf->offset = new_offset ; + + return vf->offset ; +} + +static sf_count_t vfread (void *ptr, sf_count_t count, void *user_data) +{ VIO_DATA *vf = (VIO_DATA *)user_data ; + + if (vf->offset + count > vf->length) + count = vf->length - vf->offset ; + + memcpy(ptr, vf->data + vf->offset, count) ; + vf->offset += count ; + + return count ; +} + +static sf_count_t vfwrite (const void *ptr, sf_count_t count, void *user_data) +{ + (void)ptr ; + (void)count ; + (void)user_data ; + + // Cannot write to this virtual file. + return 0; +} + +static sf_count_t vftell (void *user_data) +{ VIO_DATA *vf = (VIO_DATA *)user_data ; + + return vf->offset ; +} + +int sf_init_file(const uint8_t *data, + size_t size, + SNDFILE **sndfile, + VIO_DATA *vio_data, + SF_VIRTUAL_IO *vio, SF_INFO *sndfile_info) +{ float* read_buffer = NULL ; + + // Initialize the virtual IO structure. + vio->get_filelen = vfget_filelen ; + vio->seek = vfseek ; + vio->read = vfread ; + vio->write = vfwrite ; + vio->tell = vftell ; + + // Initialize the VIO user data. + vio_data->data = data ; + vio_data->length = size ; + vio_data->offset = 0 ; + + memset(sndfile_info, 0, sizeof(SF_INFO)) ; + + // Try and open the virtual file. + *sndfile = sf_open_virtual(vio, SFM_READ, sndfile_info, vio_data) ; + + if (sndfile_info->channels == 0) + return -1 ; + + if (sndfile_info->channels > 1024 * 1024) + return -1 ; + + return 0; +} + +#endif diff --git a/extern/libsndfile-modified/ossfuzz/sndfile_fuzzer.cc b/extern/libsndfile-modified/ossfuzz/sndfile_fuzzer.cc new file mode 100644 index 000000000..2a3d6934b --- /dev/null +++ b/extern/libsndfile-modified/ossfuzz/sndfile_fuzzer.cc @@ -0,0 +1,39 @@ +#include +#include +#include +#include +#include +#include + +#include "sndfile_fuzz_header.h" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) +{ VIO_DATA vio_data ; + SF_VIRTUAL_IO vio ; + SF_INFO sndfile_info ; + SNDFILE *sndfile = NULL ; + float* read_buffer = NULL ; + + int err = sf_init_file(data, size, &sndfile, &vio_data, &vio, &sndfile_info) ; + if (err) + goto EXIT_LABEL ; + + // Just the right number of channels. Create some buffer space for reading. + read_buffer = (float*)malloc(sizeof(float) * sndfile_info.channels); + if (read_buffer == NULL) + abort() ; + + while (sf_readf_float(sndfile, read_buffer, 1)) + { + // Do nothing with the data. + } + +EXIT_LABEL: + + if (sndfile != NULL) + sf_close(sndfile) ; + + free(read_buffer) ; + + return 0 ; +} diff --git a/extern/libsndfile-modified/ossfuzz/standaloneengine.cc b/extern/libsndfile-modified/ossfuzz/standaloneengine.cc new file mode 100644 index 000000000..ab6408d94 --- /dev/null +++ b/extern/libsndfile-modified/ossfuzz/standaloneengine.cc @@ -0,0 +1,86 @@ +#include +#include +#include + +#include "testinput.h" + +/** + * Main procedure for standalone fuzzing engine. + * + * Reads filenames from the argument array. For each filename, read the file + * into memory and then call the fuzzing interface with the data. + */ +int main(int argc, char **argv) +{ + int ii; + for(ii = 1; ii < argc; ii++) + { + FILE *infile; + printf("[%s] ", argv[ii]); + + /* Try and open the file. */ + infile = fopen(argv[ii], "rb"); + if(infile) + { + uint8_t *buffer = NULL; + size_t buffer_len; + + printf("Opened.. "); + + /* Get the length of the file. */ + fseek(infile, 0L, SEEK_END); + buffer_len = ftell(infile); + + /* Reset the file indicator to the beginning of the file. */ + fseek(infile, 0L, SEEK_SET); + + /* Allocate a buffer for the file contents. */ + buffer = (uint8_t *)calloc(buffer_len, sizeof(uint8_t)); + if(buffer) + { + size_t result; + + /* Read all the text from the file into the buffer. */ + result = fread(buffer, sizeof(uint8_t), buffer_len, infile); + + if (result == buffer_len) + { + printf("Read %zu bytes, fuzzing.. ", buffer_len); + /* Call the fuzzer with the data. */ + LLVMFuzzerTestOneInput(buffer, buffer_len); + + printf("complete !!"); + } + else + { + fprintf(stderr, + "Failed to read %zu bytes (result %zu)\n", + buffer_len, + result); + } + + /* Free the buffer as it's no longer needed. */ + free(buffer); + buffer = NULL; + } + else + { + fprintf(stderr, + "[%s] Failed to allocate %zu bytes \n", + argv[ii], + buffer_len); + } + + /* Close the file as it's no longer needed. */ + fclose(infile); + infile = NULL; + } + else + { + /* Failed to open the file. Maybe wrong name or wrong permissions? */ + fprintf(stderr, "[%s] Open failed. \n", argv[ii]); + } + + printf("\n"); + } +} diff --git a/extern/libsndfile-modified/ossfuzz/testinput.h b/extern/libsndfile-modified/ossfuzz/testinput.h new file mode 100644 index 000000000..6ab9b515e --- /dev/null +++ b/extern/libsndfile-modified/ossfuzz/testinput.h @@ -0,0 +1,3 @@ +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); diff --git a/extern/libsndfile-modified/programs/common.c b/extern/libsndfile-modified/programs/common.c new file mode 100644 index 000000000..7ff0d41a7 --- /dev/null +++ b/extern/libsndfile-modified/programs/common.c @@ -0,0 +1,503 @@ +/* +** Copyright (C) 1999-2019 Erik de Castro Lopo +** Copyright (C) 2008 George Blood Audio +** +** All rights reserved. +** +** 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 author nor the names of any 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 COPYRIGHT OWNER 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 +#include +#include +#include +#include +#include + +#include + +#include "common.h" + +#define BUFFER_LEN 4096 + +#define MIN(x, y) ((x) < (y) ? (x) : (y)) + +int +sfe_copy_data_fp (SNDFILE *outfile, SNDFILE *infile, int channels, int normalize) +{ static double data [BUFFER_LEN], max ; + sf_count_t frames, readcount, k ; + + frames = BUFFER_LEN / channels ; + readcount = frames ; + + sf_command (infile, SFC_CALC_SIGNAL_MAX, &max, sizeof (max)) ; + if (!isnormal (max)) /* neither zero, subnormal, infinite, nor NaN */ + return 1 ; + + if (!normalize && max < 1.0) + { while (readcount > 0) + { readcount = sf_readf_double (infile, data, frames) ; + sf_writef_double (outfile, data, readcount) ; + } ; + } + else + { sf_command (infile, SFC_SET_NORM_DOUBLE, NULL, SF_FALSE) ; + + while (readcount > 0) + { readcount = sf_readf_double (infile, data, frames) ; + for (k = 0 ; k < readcount * channels ; k++) + { data [k] /= max ; + + if (!isfinite (data [k])) /* infinite or NaN */ + return 1 ; + } + sf_writef_double (outfile, data, readcount) ; + } ; + } ; + + return 0 ; +} /* sfe_copy_data_fp */ + +void +sfe_copy_data_int (SNDFILE *outfile, SNDFILE *infile, int channels) +{ static int data [BUFFER_LEN] ; + int frames, readcount ; + + frames = BUFFER_LEN / channels ; + readcount = frames ; + + while (readcount > 0) + { readcount = (int) sf_readf_int (infile, data, frames) ; + sf_writef_int (outfile, data, readcount) ; + } ; + + return ; +} /* sfe_copy_data_int */ + +/*============================================================================== +*/ + +static int +merge_broadcast_info (SNDFILE * infile, SNDFILE * outfile, int format, const METADATA_INFO * info) +{ SF_BROADCAST_INFO_2K binfo ; + int infileminor ; + + memset (&binfo, 0, sizeof (binfo)) ; + + if ((SF_FORMAT_TYPEMASK & format) != SF_FORMAT_WAV) + { printf ("Error : This is not a WAV file and hence broadcast info cannot be added to it.\n\n") ; + return 1 ; + } ; + + infileminor = SF_FORMAT_SUBMASK & format ; + + switch (infileminor) + { case SF_FORMAT_PCM_16 : + case SF_FORMAT_PCM_24 : + case SF_FORMAT_PCM_32 : + case SF_FORMAT_MPEG_LAYER_III : + break ; + + default : + printf ( + "Warning : The EBU Technical Recommendation R68-2000 states that the only\n" + " allowed encodings are Linear PCM and MPEG3. This file is not in\n" + " the right format.\n\n" + ) ; + break ; + } ; + + if (sf_command (infile, SFC_GET_BROADCAST_INFO, &binfo, sizeof (binfo)) == 0) + { if (infile == outfile) + { printf ( + "Error : Attempting in-place broadcast info update, but file does not\n" + " have a 'bext' chunk to modify. The solution is to specify both\n" + " input and output files on the command line.\n\n" + ) ; + return 1 ; + } ; + } ; + +#define REPLACE_IF_NEW(x) \ + if (info->x != NULL) \ + { memset (binfo.x, 0, sizeof (binfo.x)) ; \ + memcpy (binfo.x, info->x, MIN (strlen (info->x), sizeof (binfo.x))) ; \ + } ; + + REPLACE_IF_NEW (description) ; + REPLACE_IF_NEW (originator) ; + REPLACE_IF_NEW (originator_reference) ; + REPLACE_IF_NEW (origination_date) ; + REPLACE_IF_NEW (origination_time) ; + REPLACE_IF_NEW (umid) ; + + /* Special case loudness values */ +#define REPLACE_IF_NEW_INT(x) \ + if (info->x != NULL) \ + { binfo.x = round (atof (info->x) * 100.0) ; \ + } ; + + REPLACE_IF_NEW_INT (loudness_value) ; + REPLACE_IF_NEW_INT (loudness_range) ; + REPLACE_IF_NEW_INT (max_true_peak_level) ; + REPLACE_IF_NEW_INT (max_momentary_loudness) ; + REPLACE_IF_NEW_INT (max_shortterm_loudness) ; + + /* Special case for Time Ref. */ + if (info->time_ref != NULL) + { uint64_t ts = atoll (info->time_ref) ; + + binfo.time_reference_high = (ts >> 32) ; + binfo.time_reference_low = (ts & 0xffffffff) ; + } ; + + /* Special case for coding_history because we may want to append. */ + if (info->coding_history != NULL) + { if (info->coding_hist_append) + { int slen = (int) strlen (binfo.coding_history) ; + + while (slen > 1 && isspace (binfo.coding_history [slen - 1])) + slen -- ; + + memcpy (binfo.coding_history + slen, info->coding_history, sizeof (binfo.coding_history) - slen) ; + } + else + { size_t slen = MIN (strlen (info->coding_history), sizeof (binfo.coding_history)) ; + + memset (binfo.coding_history, 0, sizeof (binfo.coding_history)) ; + memcpy (binfo.coding_history, info->coding_history, slen) ; + binfo.coding_history_size = (uint32_t) slen ; + } ; + } ; + + if (sf_command (outfile, SFC_SET_BROADCAST_INFO, &binfo, sizeof (binfo)) == 0) + { printf ("Error : Setting of broadcast info chunks failed.\n\n") ; + return 1 ; + } ; + + return 0 ; +} /* merge_broadcast_info*/ + +static void +update_strings (SNDFILE * outfile, const METADATA_INFO * info) +{ + if (info->title != NULL) + sf_set_string (outfile, SF_STR_TITLE, info->title) ; + + if (info->copyright != NULL) + sf_set_string (outfile, SF_STR_COPYRIGHT, info->copyright) ; + + if (info->artist != NULL) + sf_set_string (outfile, SF_STR_ARTIST, info->artist) ; + + if (info->comment != NULL) + sf_set_string (outfile, SF_STR_COMMENT, info->comment) ; + + if (info->date != NULL) + sf_set_string (outfile, SF_STR_DATE, info->date) ; + + if (info->album != NULL) + sf_set_string (outfile, SF_STR_ALBUM, info->album) ; + + if (info->license != NULL) + sf_set_string (outfile, SF_STR_LICENSE, info->license) ; + +} /* update_strings */ + + + +void +sfe_apply_metadata_changes (const char * filenames [2], const METADATA_INFO * info) +{ SNDFILE *infile = NULL, *outfile = NULL ; + SF_INFO sfinfo ; + METADATA_INFO tmpinfo ; + int error_code = 0 ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + memset (&tmpinfo, 0, sizeof (tmpinfo)) ; + + if (filenames [1] == NULL) + infile = outfile = sf_open (filenames [0], SFM_RDWR, &sfinfo) ; + else + { infile = sf_open (filenames [0], SFM_READ, &sfinfo) ; + + /* Output must be WAV. */ + sfinfo.format = SF_FORMAT_WAV | (SF_FORMAT_SUBMASK & sfinfo.format) ; + outfile = sf_open (filenames [1], SFM_WRITE, &sfinfo) ; + } ; + + if (infile == NULL) + { printf ("Error : Not able to open input file '%s' : %s\n", filenames [0], sf_strerror (infile)) ; + error_code = 1 ; + goto cleanup_exit ; + } ; + + if (outfile == NULL) + { printf ("Error : Not able to open output file '%s' : %s\n", filenames [1], sf_strerror (outfile)) ; + error_code = 1 ; + goto cleanup_exit ; + } ; + + if (info->has_bext_fields && merge_broadcast_info (infile, outfile, sfinfo.format, info)) + { error_code = 1 ; + goto cleanup_exit ; + } ; + + if (infile != outfile) + { int infileminor = SF_FORMAT_SUBMASK & sfinfo.format ; + + /* If the input file is not the same as the output file, copy the data. */ + if ((infileminor == SF_FORMAT_DOUBLE) || (infileminor == SF_FORMAT_FLOAT)) + { if (sfe_copy_data_fp (outfile, infile, sfinfo.channels, SF_FALSE) != 0) + { printf ("Error : Not able to decode input file '%s'\n", filenames [0]) ; + error_code = 1 ; + goto cleanup_exit ; + } ; + } + else + sfe_copy_data_int (outfile, infile, sfinfo.channels) ; + } ; + + update_strings (outfile, info) ; + +cleanup_exit : + + if (outfile != NULL && outfile != infile) + sf_close (outfile) ; + + if (infile != NULL) + sf_close (infile) ; + + if (error_code) + exit (error_code) ; + + return ; +} /* sfe_apply_metadata_changes */ + +/*============================================================================== +*/ + +typedef struct +{ const char *ext ; + int len ; + int format ; +} OUTPUT_FORMAT_MAP ; + +/* Map a file name extension to a container format. */ +static OUTPUT_FORMAT_MAP format_map [] = +{ + { "wav", 0, SF_FORMAT_WAV }, + { "aif", 3, SF_FORMAT_AIFF }, + { "au", 0, SF_FORMAT_AU }, + { "snd", 0, SF_FORMAT_AU }, + { "raw", 0, SF_FORMAT_RAW }, + { "gsm", 0, SF_FORMAT_RAW | SF_FORMAT_GSM610 }, + { "vox", 0, SF_FORMAT_RAW | SF_FORMAT_VOX_ADPCM }, + { "paf", 0, SF_FORMAT_PAF | SF_ENDIAN_BIG }, + { "fap", 0, SF_FORMAT_PAF | SF_ENDIAN_LITTLE }, + { "svx", 0, SF_FORMAT_SVX }, + { "nist", 0, SF_FORMAT_NIST }, + { "sph", 0, SF_FORMAT_NIST }, + { "voc", 0, SF_FORMAT_VOC }, + { "ircam", 0, SF_FORMAT_IRCAM }, + { "sf", 0, SF_FORMAT_IRCAM }, + { "w64", 0, SF_FORMAT_W64 }, + { "mat", 0, SF_FORMAT_MAT4 }, + { "mat4", 0, SF_FORMAT_MAT4 }, + { "mat5", 0, SF_FORMAT_MAT5 }, + { "pvf", 0, SF_FORMAT_PVF }, + { "xi", 0, SF_FORMAT_XI }, + { "htk", 0, SF_FORMAT_HTK }, + { "sds", 0, SF_FORMAT_SDS }, + { "avr", 0, SF_FORMAT_AVR }, + { "wavex", 0, SF_FORMAT_WAVEX }, + { "sd2", 0, SF_FORMAT_SD2 }, + { "flac", 0, SF_FORMAT_FLAC }, + { "caf", 0, SF_FORMAT_CAF }, + { "wve", 0, SF_FORMAT_WVE }, + { "prc", 0, SF_FORMAT_WVE }, + { "oga", 0, SF_FORMAT_OGG }, + { "ogg", 0, SF_FORMAT_OGG | SF_FORMAT_VORBIS }, + { "opus", 0, SF_FORMAT_OGG | SF_FORMAT_OPUS }, + { "mpc", 0, SF_FORMAT_MPC2K }, + { "rf64", 0, SF_FORMAT_RF64 }, + { "mp3", 0, SF_FORMAT_MPEG | SF_FORMAT_MPEG_LAYER_III }, +} ; /* format_map */ + +int +sfe_file_type_of_ext (const char *str, int format) +{ char buffer [16], *cptr ; + int k ; + + format &= SF_FORMAT_SUBMASK ; + + if ((cptr = strrchr (str, '.')) == NULL) + return 0 ; + + strncpy (buffer, cptr + 1, 15) ; + buffer [15] = 0 ; + + for (k = 0 ; buffer [k] ; k++) + buffer [k] = tolower ((buffer [k])) ; + + for (k = 0 ; k < (int) (sizeof (format_map) / sizeof (format_map [0])) ; k++) + { if ((format_map [k].len > 0 && strncmp (buffer, format_map [k].ext, format_map [k].len) == 0) || + (strcmp (buffer, format_map [k].ext) == 0)) + { if (format_map [k].format & SF_FORMAT_SUBMASK) + return format_map [k].format ; + else + return format_map [k].format | format ; + } ; + } ; + + /* Default if all the above fails. */ + return (SF_FORMAT_WAV | SF_FORMAT_PCM_24) ; +} /* sfe_file_type_of_ext */ + +void +sfe_dump_format_map (void) +{ SF_FORMAT_INFO info ; + int k ; + + for (k = 0 ; k < ARRAY_LEN (format_map) ; k++) + { info.format = format_map [k].format ; + sf_command (NULL, SFC_GET_FORMAT_INFO, &info, sizeof (info)) ; + printf (" %-10s : %s", format_map [k].ext, info.name == NULL ? "????" : info.name) ; + if (format_map [k].format & SF_FORMAT_SUBMASK) + { info.format = format_map [k].format & SF_FORMAT_SUBMASK ; + sf_command (NULL, SFC_GET_FORMAT_INFO, &info, sizeof (info)) ; + printf (" %s", info.name == NULL ? "????" : info.name) ; + } ; + putchar ('\n') ; + + } ; + +} /* sfe_dump_format_map */ + +const char * +program_name (const char * argv0) +{ const char * tmp ; + + tmp = strrchr (argv0, '/') ; + argv0 = tmp ? tmp + 1 : argv0 ; + + /* Remove leading libtool name mangling. */ + if (strstr (argv0, "lt-") == argv0) + return argv0 + 3 ; + + return argv0 ; +} /* program_name */ + +const char * +sfe_endian_name (int format) +{ + switch (format & SF_FORMAT_ENDMASK) + { case SF_ENDIAN_FILE : return "file" ; + case SF_ENDIAN_LITTLE : return "little" ; + case SF_ENDIAN_BIG : return "big" ; + case SF_ENDIAN_CPU : return "cpu" ; + default : break ; + } ; + + return "unknown" ; +} /* sfe_endian_name */ + +const char * +sfe_container_name (int format) +{ + switch (format & SF_FORMAT_TYPEMASK) + { case SF_FORMAT_WAV : return "WAV" ; + case SF_FORMAT_AIFF : return "AIFF" ; + case SF_FORMAT_AU : return "AU" ; + case SF_FORMAT_RAW : return "RAW" ; + case SF_FORMAT_PAF : return "PAF" ; + case SF_FORMAT_SVX : return "SVX" ; + case SF_FORMAT_NIST : return "NIST" ; + case SF_FORMAT_VOC : return "VOC" ; + case SF_FORMAT_IRCAM : return "IRCAM" ; + case SF_FORMAT_W64 : return "W64" ; + case SF_FORMAT_MAT4 : return "MAT4" ; + case SF_FORMAT_MAT5 : return "MAT5" ; + case SF_FORMAT_PVF : return "PVF" ; + case SF_FORMAT_XI : return "XI" ; + case SF_FORMAT_HTK : return "HTK" ; + case SF_FORMAT_SDS : return "SDS" ; + case SF_FORMAT_AVR : return "AVR" ; + case SF_FORMAT_WAVEX : return "WAVEX" ; + case SF_FORMAT_SD2 : return "SD2" ; + case SF_FORMAT_FLAC : return "FLAC" ; + case SF_FORMAT_CAF : return "CAF" ; + case SF_FORMAT_WVE : return "WVE" ; + case SF_FORMAT_OGG : return "OGG" ; + case SF_FORMAT_MPC2K : return "MPC2K" ; + case SF_FORMAT_RF64 : return "RF64" ; + case SF_FORMAT_MPEG : return "MPEG" ; + default : break ; + } ; + + return "unknown" ; +} /* sfe_container_name */ + +const char * +sfe_codec_name (int format) +{ + switch (format & SF_FORMAT_SUBMASK) + { case SF_FORMAT_PCM_S8 : return "signed 8 bit PCM" ; + case SF_FORMAT_PCM_16 : return "16 bit PCM" ; + case SF_FORMAT_PCM_24 : return "24 bit PCM" ; + case SF_FORMAT_PCM_32 : return "32 bit PCM" ; + case SF_FORMAT_PCM_U8 : return "unsigned 8 bit PCM" ; + case SF_FORMAT_FLOAT : return "32 bit float" ; + case SF_FORMAT_DOUBLE : return "64 bit double" ; + case SF_FORMAT_ULAW : return "u-law" ; + case SF_FORMAT_ALAW : return "a-law" ; + case SF_FORMAT_IMA_ADPCM : return "IMA ADPCM" ; + case SF_FORMAT_MS_ADPCM : return "MS ADPCM" ; + case SF_FORMAT_GSM610 : return "gsm610" ; + case SF_FORMAT_VOX_ADPCM : return "Vox ADPCM" ; + case SF_FORMAT_G721_32 : return "g721 32kbps" ; + case SF_FORMAT_G723_24 : return "g723 24kbps" ; + case SF_FORMAT_G723_40 : return "g723 40kbps" ; + case SF_FORMAT_DWVW_12 : return "12 bit DWVW" ; + case SF_FORMAT_DWVW_16 : return "16 bit DWVW" ; + case SF_FORMAT_DWVW_24 : return "14 bit DWVW" ; + case SF_FORMAT_DWVW_N : return "DWVW" ; + case SF_FORMAT_DPCM_8 : return "8 bit DPCM" ; + case SF_FORMAT_DPCM_16 : return "16 bit DPCM" ; + case SF_FORMAT_VORBIS : return "Vorbis" ; + case SF_FORMAT_ALAC_16 : return "16 bit ALAC" ; + case SF_FORMAT_ALAC_20 : return "20 bit ALAC" ; + case SF_FORMAT_ALAC_24 : return "24 bit ALAC" ; + case SF_FORMAT_ALAC_32 : return "32 bit ALAC" ; + case SF_FORMAT_OPUS : return "Opus" ; + case SF_FORMAT_MPEG_LAYER_I : return "MPEG layer 1" ; + case SF_FORMAT_MPEG_LAYER_II : return "MPEG layer 2" ; + case SF_FORMAT_MPEG_LAYER_III : return "MPEG layer 3" ; + default : break ; + } ; + return "unknown" ; +} /* sfe_codec_name */ diff --git a/extern/libsndfile-modified/programs/common.h b/extern/libsndfile-modified/programs/common.h new file mode 100644 index 000000000..5ed36dbb4 --- /dev/null +++ b/extern/libsndfile-modified/programs/common.h @@ -0,0 +1,82 @@ +/* +** Copyright (C) 1999-2013 Erik de Castro Lopo +** +** All rights reserved. +** +** 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 author nor the names of any 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 COPYRIGHT OWNER 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. +*/ + + +#define ARRAY_LEN(x) ((int) (sizeof (x) / sizeof (x [0]))) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + +typedef struct +{ const char * title ; + const char * copyright ; + const char * artist ; + const char * comment ; + const char * date ; + const char * album ; + const char * license ; + + + /* Stuff to go in the 'bext' chunk of WAV files. */ + int has_bext_fields ; + int coding_hist_append ; + + const char * description ; + const char * originator ; + const char * originator_reference ; + const char * origination_date ; + const char * origination_time ; + const char * umid ; + const char * loudness_value ; + const char * loudness_range ; + const char * max_true_peak_level ; + const char * max_momentary_loudness ; + const char * max_shortterm_loudness ; + const char * coding_history ; + const char * time_ref ; +} METADATA_INFO ; + +typedef SF_BROADCAST_INFO_VAR (2048) SF_BROADCAST_INFO_2K ; + +void sfe_apply_metadata_changes (const char * filenames [2], const METADATA_INFO * info) ; + +int sfe_copy_data_fp (SNDFILE *outfile, SNDFILE *infile, int channels, int normalize) ; + +void sfe_copy_data_int (SNDFILE *outfile, SNDFILE *infile, int channels) ; + +int sfe_file_type_of_ext (const char *filename, int format) ; + +void sfe_dump_format_map (void) ; + +const char * program_name (const char * argv0) ; + +const char * sfe_endian_name (int format) ; +const char * sfe_container_name (int format) ; +const char * sfe_codec_name (int format) ; diff --git a/extern/libsndfile-modified/programs/sndfile-cmp.c b/extern/libsndfile-modified/programs/sndfile-cmp.c new file mode 100644 index 000000000..3dd992d1a --- /dev/null +++ b/extern/libsndfile-modified/programs/sndfile-cmp.c @@ -0,0 +1,155 @@ +/* +** Copyright (C) 2008-2016 Erik de Castro Lopo +** Copyright (C) 2008 Conrad Parker +** +** All rights reserved. +** +** 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 author nor the names of any 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 COPYRIGHT OWNER 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 "sfconfig.h" + +#include +#include +#include +#include + +#include + +#include "common.h" + +/* Length of comparison data buffers in units of items */ +#define BUFLEN 65536 + +static const char * progname = NULL ; +static char * filename1 = NULL, * filename2 = NULL ; + +static int +comparison_error (const char * what, sf_count_t frame_offset) +{ char buffer [128] ; + + if (frame_offset >= 0) + snprintf (buffer, sizeof (buffer), " (at frame offset %" PRId64 ")", frame_offset) ; + else + buffer [0] = 0 ; + + printf ("%s: %s of files %s and %s differ%s.\n", progname, what, filename1, filename2, buffer) ; + return 1 ; +} /* comparison_error */ + +static int +compare (void) +{ + double buf1 [BUFLEN], buf2 [BUFLEN] ; + SF_INFO sfinfo1, sfinfo2 ; + SNDFILE * sf1 = NULL, * sf2 = NULL ; + sf_count_t items, i, nread1, nread2, offset = 0 ; + int retval = 0 ; + + memset (&sfinfo1, 0, sizeof (SF_INFO)) ; + sf1 = sf_open (filename1, SFM_READ, &sfinfo1) ; + if (sf1 == NULL) + { printf ("Error opening %s.\n", filename1) ; + retval = 1 ; + goto out ; + } ; + + memset (&sfinfo2, 0, sizeof (SF_INFO)) ; + sf2 = sf_open (filename2, SFM_READ, &sfinfo2) ; + if (sf2 == NULL) + { printf ("Error opening %s.\n", filename2) ; + retval = 1 ; + goto out ; + } ; + + if (sfinfo1.samplerate != sfinfo2.samplerate) + { retval = comparison_error ("Samplerates", -1) ; + goto out ; + } ; + + if (sfinfo1.channels != sfinfo2.channels) + { retval = comparison_error ("Number of channels", -1) ; + goto out ; + } ; + + /* Calculate the framecount that will fit in our data buffers */ + items = BUFLEN / sfinfo1.channels ; + + while ((nread1 = sf_readf_double (sf1, buf1, items)) > 0) + { nread2 = sf_readf_double (sf2, buf2, nread1) ; + if (nread2 != nread1) + { retval = comparison_error ("PCM data lengths", -1) ; + goto out ; + } ; + for (i = 0 ; i < nread1 * sfinfo1.channels ; i++) + { if (buf1 [i] != buf2 [i]) + { retval = comparison_error ("PCM data", offset + i / sfinfo1.channels) ; + goto out ; + } ; + } ; + offset += nread1 ; + } ; + + if ((nread2 = sf_readf_double (sf2, buf2, items)) != 0) + { retval = comparison_error ("PCM data lengths", -1) ; + goto out ; + } ; + +out : + sf_close (sf1) ; + sf_close (sf2) ; + + return retval ; +} /* compare */ + +static void +usage_exit (void) +{ + printf ("Usage : %s \n", progname) ; + printf (" Compare the PCM data of two sound files.\n\n") ; + printf ("Using %s.\n\n", sf_version_string ()) ; + exit (1) ; +} /* usage_exit */ + +int +main (int argc, char *argv []) +{ + progname = program_name (argv [0]) ; + + if (argc != 3) + usage_exit () ; + + filename1 = argv [argc - 2] ; + filename2 = argv [argc - 1] ; + + if (strcmp (filename1, filename2) == 0) + { printf ("Error : Input filenames are the same.\n\n") ; + usage_exit () ; + } ; + + return compare () ; +} /* main */ diff --git a/extern/libsndfile-modified/programs/sndfile-concat.c b/extern/libsndfile-modified/programs/sndfile-concat.c new file mode 100644 index 000000000..49380fd00 --- /dev/null +++ b/extern/libsndfile-modified/programs/sndfile-concat.c @@ -0,0 +1,170 @@ +/* +** Copyright (C) 1999-2014 Erik de Castro Lopo +** +** All rights reserved. +** +** 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 author nor the names of any 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 COPYRIGHT OWNER 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 +#include +#include +#include + +#include + +#include "common.h" + +#define BUFFER_LEN (1 << 16) + + +static void concat_data_fp (SNDFILE *wfile, SNDFILE *rofile, int channels) ; +static void concat_data_int (SNDFILE *wfile, SNDFILE *rofile, int channels) ; + +static void +usage_exit (const char *progname) +{ + printf ("\nUsage : %s ... \n\n", progname) ; + puts ( + " Create a new output file containing the concatenated\n" + " audio data from froms ....\n" + "\n" + " The joined file will be encoded in the same format as the data\n" + " in infile1, with all the data in subsequent files automatically\n" + " converted to the correct encoding.\n" + "\n" + " The only restriction is that the two files must have the same\n" + " number of channels.\n" + ) ; + + exit (1) ; +} /* usage_exit */ + +int +main (int argc, char *argv []) +{ const char *progname, *outfilename ; + SNDFILE *outfile, **infiles ; + SF_INFO sfinfo_out, sfinfo_in ; + void (*func) (SNDFILE*, SNDFILE*, int) ; + int k ; + + progname = program_name (argv [0]) ; + + if (argc < 4) + usage_exit (progname) ; + + argv ++ ; + argc -- ; + + argc -- ; + outfilename = argv [argc] ; + + if ((infiles = calloc (argc, sizeof (SNDFILE*))) == NULL) + { printf ("\nError : Malloc failed.\n\n") ; + exit (1) ; + } ; + + memset (&sfinfo_in, 0, sizeof (sfinfo_in)) ; + + if ((infiles [0] = sf_open (argv [0], SFM_READ, &sfinfo_in)) == NULL) + { printf ("\nError : failed to open file '%s'.\n\n", argv [0]) ; + exit (1) ; + } ; + + sfinfo_out = sfinfo_in ; + + for (k = 1 ; k < argc ; k++) + { if ((infiles [k] = sf_open (argv [k], SFM_READ, &sfinfo_in)) == NULL) + { printf ("\nError : failed to open file '%s'.\n\n", argv [k]) ; + exit (1) ; + } ; + + if (sfinfo_in.channels != sfinfo_out.channels) + { printf ("\nError : File '%s' has %d channels (should have %d).\n\n", argv [k], sfinfo_in.channels, sfinfo_out.channels) ; + exit (1) ; + } ; + } ; + + if ((outfile = sf_open (outfilename, SFM_WRITE, &sfinfo_out)) == NULL) + { printf ("\nError : Not able to open input file %s.\n", outfilename) ; + puts (sf_strerror (NULL)) ; + exit (1) ; + } ; + + if ((sfinfo_out.format & SF_FORMAT_SUBMASK) == SF_FORMAT_DOUBLE || + (sfinfo_out.format & SF_FORMAT_SUBMASK) == SF_FORMAT_FLOAT) + func = concat_data_fp ; + else + func = concat_data_int ; + + for (k = 0 ; k < argc ; k++) + { func (outfile, infiles [k], sfinfo_out.channels) ; + sf_close (infiles [k]) ; + } ; + + sf_close (outfile) ; + free (infiles) ; + + return 0 ; +} /* main */ + +static void +concat_data_fp (SNDFILE *wfile, SNDFILE *rofile, int channels) +{ static double data [BUFFER_LEN] ; + int frames, readcount ; + + frames = BUFFER_LEN / channels ; + readcount = frames ; + + sf_seek (wfile, 0, SEEK_END) ; + + while (readcount > 0) + { readcount = (int) sf_readf_double (rofile, data, frames) ; + sf_writef_double (wfile, data, readcount) ; + } ; + + return ; +} /* concat_data_fp */ + +static void +concat_data_int (SNDFILE *wfile, SNDFILE *rofile, int channels) +{ static int data [BUFFER_LEN] ; + int frames, readcount ; + + frames = BUFFER_LEN / channels ; + readcount = frames ; + + sf_seek (wfile, 0, SEEK_END) ; + + while (readcount > 0) + { readcount = (int) sf_readf_int (rofile, data, frames) ; + sf_writef_int (wfile, data, readcount) ; + } ; + + return ; +} /* concat_data_int */ + diff --git a/extern/libsndfile-modified/programs/sndfile-convert.c b/extern/libsndfile-modified/programs/sndfile-convert.c new file mode 100644 index 000000000..b94686242 --- /dev/null +++ b/extern/libsndfile-modified/programs/sndfile-convert.c @@ -0,0 +1,410 @@ +/* +** Copyright (C) 1999-2019 Erik de Castro Lopo +** +** All rights reserved. +** +** 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 author nor the names of any 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 COPYRIGHT OWNER 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 +#include +#include +#include + +#include + +#include "common.h" + + +typedef struct +{ char *infilename, *outfilename ; + SF_INFO infileinfo, outfileinfo ; +} OptionData ; + +static void copy_metadata (SNDFILE *outfile, SNDFILE *infile, int channels) ; + +static void +usage_exit (const char *progname) +{ + printf ("\nUsage : %s [options] [encoding] \n", progname) ; + puts ("\n" + " where [option] may be:\n\n" + " -override-sample-rate=X : force sample rate of input to X\n" + " -endian=little : force output file to little endian data\n" + " -endian=big : force output file to big endian data\n" + " -endian=cpu : force output file same endian-ness as the CPU\n" + " -normalize : normalize the data in the output file\n" + ) ; + + puts ( + " where [encoding] may be one of the following:\n\n" + " -pcms8 : signed 8 bit pcm\n" + " -pcmu8 : unsigned 8 bit pcm\n" + " -pcm16 : 16 bit pcm\n" + " -pcm24 : 24 bit pcm\n" + " -pcm32 : 32 bit pcm\n" + " -float32 : 32 bit floating point\n" + " -float64 : 64 bit floating point\n" + " -ulaw : ULAW\n" + " -alaw : ALAW\n" + " -alac16 : 16 bit ALAC (CAF only)\n" + " -alac20 : 20 bit ALAC (CAF only)\n" + " -alac24 : 24 bit ALAC (CAF only)\n" + " -alac32 : 32 bit ALAC (CAF only)\n" + " -ima-adpcm : IMA ADPCM (WAV only)\n" + " -ms-adpcm : MS ADPCM (WAV only)\n" + " -gsm610 : GSM6.10 (WAV only)\n" + " -dwvw12 : 12 bit DWVW (AIFF only)\n" + " -dwvw16 : 16 bit DWVW (AIFF only)\n" + " -dwvw24 : 24 bit DWVW (AIFF only)\n" + " -vorbis : Vorbis (OGG only)\n" + " -opus : Opus (OGG only)\n" + ) ; + + puts ( + " If no encoding is specified, the program will try to use the encoding\n" + " of the input file in the output file. This will not always work as\n" + " most container formats (eg WAV, AIFF etc) only support a small subset\n" + " of codec formats (eg 16 bit PCM, a-law, Vorbis etc).\n" + ) ; + + puts ( + " The format of the output file is determined by the file extension of the\n" + " output file name. The following extensions are currently understood:\n" + ) ; + + sfe_dump_format_map () ; + + puts ("") ; + exit (1) ; +} /* usage_exit */ + +static void +report_format_error_exit (const char * argv0, SF_INFO * sfinfo) +{ int old_format = sfinfo->format ; + int endian = sfinfo->format & SF_FORMAT_ENDMASK ; + int channels = sfinfo->channels ; + + sfinfo->format = old_format & (SF_FORMAT_TYPEMASK | SF_FORMAT_SUBMASK) ; + + if (endian && sf_format_check (sfinfo)) + { printf ("Error : output file format does not support %s endian-ness.\n", sfe_endian_name (endian)) ; + exit (1) ; + } ; + + sfinfo->channels = 1 ; + if (sf_format_check (sfinfo)) + { printf ("Error : output file format does not support %d channels.\n", channels) ; + exit (1) ; + } ; + + printf ("\n" + "Error : output file format is invalid.\n" + "The '%s' container does not support '%s' codec data.\n" + "Run '%s --help' for clues.\n\n", + sfe_container_name (sfinfo->format), sfe_codec_name (sfinfo->format), program_name (argv0)) ; + exit (1) ; +} /* report_format_error_exit */ + +int +main (int argc, char * argv []) +{ const char *progname, *infilename, *outfilename ; + SNDFILE *infile = NULL, *outfile = NULL ; + SF_INFO sfinfo ; + int k, outfilemajor, outfileminor = 0, infileminor ; + int override_sample_rate = 0 ; /* assume no sample rate override. */ + int endian = SF_ENDIAN_FILE, normalize = SF_FALSE ; + + progname = program_name (argv [0]) ; + + if (argc < 3 || argc > 5) + usage_exit (progname) ; + + infilename = argv [argc-2] ; + outfilename = argv [argc-1] ; + + if (strcmp (infilename, outfilename) == 0) + { printf ("Error : Input and output filenames are the same.\n\n") ; + usage_exit (progname) ; + } ; + + if (strlen (infilename) > 1 && infilename [0] == '-') + { printf ("Error : Input filename (%s) looks like an option.\n\n", infilename) ; + usage_exit (progname) ; + } ; + + if (outfilename [0] == '-') + { printf ("Error : Output filename (%s) looks like an option.\n\n", outfilename) ; + usage_exit (progname) ; + } ; + + for (k = 1 ; k < argc - 2 ; k++) + { if (! strcmp (argv [k], "-pcms8")) + { outfileminor = SF_FORMAT_PCM_S8 ; + continue ; + } ; + if (! strcmp (argv [k], "-pcmu8")) + { outfileminor = SF_FORMAT_PCM_U8 ; + continue ; + } ; + if (! strcmp (argv [k], "-pcm16")) + { outfileminor = SF_FORMAT_PCM_16 ; + continue ; + } ; + if (! strcmp (argv [k], "-pcm24")) + { outfileminor = SF_FORMAT_PCM_24 ; + continue ; + } ; + if (! strcmp (argv [k], "-pcm32")) + { outfileminor = SF_FORMAT_PCM_32 ; + continue ; + } ; + if (! strcmp (argv [k], "-float32")) + { outfileminor = SF_FORMAT_FLOAT ; + continue ; + } ; + if (! strcmp (argv [k], "-float64")) + { outfileminor = SF_FORMAT_DOUBLE ; + continue ; + } ; + if (! strcmp (argv [k], "-ulaw")) + { outfileminor = SF_FORMAT_ULAW ; + continue ; + } ; + if (! strcmp (argv [k], "-alaw")) + { outfileminor = SF_FORMAT_ALAW ; + continue ; + } ; + if (! strcmp (argv [k], "-alac16")) + { outfileminor = SF_FORMAT_ALAC_16 ; + continue ; + } ; + if (! strcmp (argv [k], "-alac20")) + { outfileminor = SF_FORMAT_ALAC_20 ; + continue ; + } ; + if (! strcmp (argv [k], "-alac24")) + { outfileminor = SF_FORMAT_ALAC_24 ; + continue ; + } ; + if (! strcmp (argv [k], "-alac32")) + { outfileminor = SF_FORMAT_ALAC_32 ; + continue ; + } ; + if (! strcmp (argv [k], "-ima-adpcm")) + { outfileminor = SF_FORMAT_IMA_ADPCM ; + continue ; + } ; + if (! strcmp (argv [k], "-ms-adpcm")) + { outfileminor = SF_FORMAT_MS_ADPCM ; + continue ; + } ; + if (! strcmp (argv [k], "-gsm610")) + { outfileminor = SF_FORMAT_GSM610 ; + continue ; + } ; + if (! strcmp (argv [k], "-dwvw12")) + { outfileminor = SF_FORMAT_DWVW_12 ; + continue ; + } ; + if (! strcmp (argv [k], "-dwvw16")) + { outfileminor = SF_FORMAT_DWVW_16 ; + continue ; + } ; + if (! strcmp (argv [k], "-dwvw24")) + { outfileminor = SF_FORMAT_DWVW_24 ; + continue ; + } ; + if (! strcmp (argv [k], "-vorbis")) + { outfileminor = SF_FORMAT_VORBIS ; + continue ; + } ; + if (! strcmp (argv [k], "-opus")) + { outfileminor = SF_FORMAT_OPUS ; + continue ; + } ; + + if (strstr (argv [k], "-override-sample-rate=") == argv [k]) + { const char *ptr ; + + ptr = argv [k] + strlen ("-override-sample-rate=") ; + override_sample_rate = atoi (ptr) ; + continue ; + } ; + + if (! strcmp (argv [k], "-endian=little")) + { endian = SF_ENDIAN_LITTLE ; + continue ; + } ; + + if (! strcmp (argv [k], "-endian=big")) + { endian = SF_ENDIAN_BIG ; + continue ; + } ; + + if (! strcmp (argv [k], "-endian=cpu")) + { endian = SF_ENDIAN_CPU ; + continue ; + } ; + + if (! strcmp (argv [k], "-endian=file")) + { endian = SF_ENDIAN_FILE ; + continue ; + } ; + + if (! strcmp (argv [k], "-normalize")) + { normalize = SF_TRUE ; + continue ; + } ; + + printf ("Error : Not able to decode argument '%s'.\n", argv [k]) ; + exit (1) ; + } ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + if ((infile = sf_open (infilename, SFM_READ, &sfinfo)) == NULL) + { printf ("Not able to open input file %s.\n", infilename) ; + puts (sf_strerror (NULL)) ; + return 1 ; + } ; + + /* Update sample rate if forced to something else. */ + if (override_sample_rate) + sfinfo.samplerate = override_sample_rate ; + + infileminor = sfinfo.format & SF_FORMAT_SUBMASK ; + + if ((sfinfo.format = sfe_file_type_of_ext (outfilename, sfinfo.format)) == 0) + { printf ("Error : Not able to determine output file type for %s.\n", outfilename) ; + return 1 ; + } ; + + outfilemajor = sfinfo.format & (SF_FORMAT_TYPEMASK | SF_FORMAT_ENDMASK) ; + + if (outfileminor == 0) + outfileminor = sfinfo.format & SF_FORMAT_SUBMASK ; + + if (outfileminor != 0) + sfinfo.format = outfilemajor | outfileminor ; + else + sfinfo.format = outfilemajor | (sfinfo.format & SF_FORMAT_SUBMASK) ; + + sfinfo.format |= endian ; + + if ((sfinfo.format & SF_FORMAT_TYPEMASK) == SF_FORMAT_XI) + switch (sfinfo.format & SF_FORMAT_SUBMASK) + { case SF_FORMAT_PCM_16 : + sfinfo.format = outfilemajor | SF_FORMAT_DPCM_16 ; + break ; + + case SF_FORMAT_PCM_S8 : + case SF_FORMAT_PCM_U8 : + sfinfo.format = outfilemajor | SF_FORMAT_DPCM_8 ; + break ; + } ; + + if (sf_format_check (&sfinfo) == 0) + { sf_close (infile) ; + report_format_error_exit (argv [0], &sfinfo) ; + } ; + + 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" + "ouput file will contain the input data converted to the GSM 6.10 data format\n" + "but not re-sampled.\n" + ) ; + } ; + + /* Open the output file. */ + if ((outfile = sf_open (outfilename, SFM_WRITE, &sfinfo)) == NULL) + { printf ("Not able to open output file %s : %s\n", outfilename, sf_strerror (NULL)) ; + return 1 ; + } ; + + /* Copy the metadata */ + copy_metadata (outfile, infile, sfinfo.channels) ; + + if (normalize + || (outfileminor == SF_FORMAT_DOUBLE) || (outfileminor == SF_FORMAT_FLOAT) + || (infileminor == SF_FORMAT_DOUBLE) || (infileminor == SF_FORMAT_FLOAT) + || (infileminor == SF_FORMAT_OPUS) || (outfileminor == SF_FORMAT_OPUS) + || (infileminor == SF_FORMAT_VORBIS) || (outfileminor == SF_FORMAT_VORBIS) + || (infileminor == SF_FORMAT_MPEG_LAYER_I) + || (infileminor == SF_FORMAT_MPEG_LAYER_II) + || (infileminor == SF_FORMAT_MPEG_LAYER_III) || (outfileminor == SF_FORMAT_MPEG_LAYER_III)) + { if (sfe_copy_data_fp (outfile, infile, sfinfo.channels, normalize) != 0) + { printf ("Error : Not able to decode input file %s.\n", infilename) ; + return 1 ; + } ; + } + else + sfe_copy_data_int (outfile, infile, sfinfo.channels) ; + + sf_close (infile) ; + sf_close (outfile) ; + + return 0 ; +} /* main */ + +static void +copy_metadata (SNDFILE *outfile, SNDFILE *infile, int channels) +{ SF_INSTRUMENT inst ; + SF_CUES cues ; + SF_BROADCAST_INFO_2K binfo ; + const char *str ; + int k, chanmap [256] ; + + for (k = SF_STR_FIRST ; k <= SF_STR_LAST ; k++) + { str = sf_get_string (infile, k) ; + if (str != NULL) + sf_set_string (outfile, k, str) ; + } ; + + memset (&inst, 0, sizeof (inst)) ; + memset (&cues, 0, sizeof (cues)) ; + memset (&binfo, 0, sizeof (binfo)) ; + + if (channels < ARRAY_LEN (chanmap)) + { int size = channels * sizeof (chanmap [0]) ; + + if (sf_command (infile, SFC_GET_CHANNEL_MAP_INFO, chanmap, size) == SF_TRUE) + sf_command (outfile, SFC_SET_CHANNEL_MAP_INFO, chanmap, size) ; + } ; + + if (sf_command (infile, SFC_GET_CUE, &cues, sizeof (cues)) == SF_TRUE) + sf_command (outfile, SFC_SET_CUE, &cues, sizeof (cues)) ; + + if (sf_command (infile, SFC_GET_INSTRUMENT, &inst, sizeof (inst)) == SF_TRUE) + sf_command (outfile, SFC_SET_INSTRUMENT, &inst, sizeof (inst)) ; + + if (sf_command (infile, SFC_GET_BROADCAST_INFO, &binfo, sizeof (binfo)) == SF_TRUE) + sf_command (outfile, SFC_SET_BROADCAST_INFO, &binfo, sizeof (binfo)) ; + +} /* copy_metadata */ + diff --git a/extern/libsndfile-modified/programs/sndfile-deinterleave.c b/extern/libsndfile-modified/programs/sndfile-deinterleave.c new file mode 100644 index 000000000..42d475099 --- /dev/null +++ b/extern/libsndfile-modified/programs/sndfile-deinterleave.c @@ -0,0 +1,222 @@ +/* +** Copyright (C) 2009-2017 Erik de Castro Lopo +** +** All rights reserved. +** +** 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 author nor the names of any 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 COPYRIGHT OWNER 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 +#include +#include +#include + +#include "common.h" + +#define BUFFER_LEN 4096 +#define MAX_CHANNELS 16 + + +typedef struct +{ SNDFILE * infile ; + SNDFILE * outfile [MAX_CHANNELS] ; + + union + { double d [MAX_CHANNELS * BUFFER_LEN] ; + int i [MAX_CHANNELS * BUFFER_LEN] ; + } din ; + + union + { double d [BUFFER_LEN] ; + int i [BUFFER_LEN] ; + } dout ; + + int channels ; +} STATE ; + +static void usage_exit (void) ; + +static void deinterleave_int (STATE * state) ; +static void deinterleave_double (STATE * state) ; + +int +main (int argc, char **argv) +{ STATE *state = NULL ; + SF_INFO sfinfo ; + char pathname [512], ext [32], *cptr ; + int ch, double_split, ret = 1 ; + + if (argc != 2) + { if (argc != 1) + puts ("\nError : need a single input file.\n") ; + usage_exit () ; + goto cleanup ; + } ; + + state = calloc (1, sizeof (*state)) ; + if (!state) + { printf ("\nError : Out of memory.\n") ; + goto cleanup ; + } ; + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + if ((state->infile = sf_open (argv [1], SFM_READ, &sfinfo)) == NULL) + { printf ("\nError : Not able to open input file '%s'\n%s\n", argv [1], sf_strerror (NULL)) ; + goto cleanup ; + } ; + + if (sfinfo.channels < 2) + { printf ("\nError : Input file '%s' only has one channel.\n", argv [1]) ; + goto cleanup ; + } ; + + if (sfinfo.channels > MAX_CHANNELS) + { printf ("\nError : Input file '%s' has too many (%d) channels. Limit is %d.\n", + argv [1], sfinfo.channels, MAX_CHANNELS) ; + goto cleanup ; + } ; + + + state->channels = sfinfo.channels ; + sfinfo.channels = 1 ; + + if (snprintf (pathname, sizeof (pathname), "%s", argv [1]) > (int) sizeof (pathname)) + { printf ("\nError : Length of provided filename '%s' exceeds MAX_PATH (%d).\n", argv [1], (int) sizeof (pathname)) ; + goto cleanup ; + } ; + + if ((cptr = strrchr (pathname, '.')) == NULL) + ext [0] = 0 ; + else + { snprintf (ext, sizeof (ext), "%s", cptr) ; + cptr [0] = 0 ; + } ; + + printf ("Input file : %s\n", pathname) ; + puts ("Output files :") ; + + for (ch = 0 ; ch < state->channels ; ch++) + { char filename [520] ; + size_t count ; + + count = snprintf (filename, sizeof (filename), "%s_%02d%s", pathname, ch, ext) ; + + if (count >= sizeof (filename)) + { printf ("File name truncated to %s\n", filename) ; + } ; + + if ((state->outfile [ch] = sf_open (filename, SFM_WRITE, &sfinfo)) == NULL) + { printf ("Not able to open output file '%s'\n%s\n", filename, sf_strerror (NULL)) ; + goto cleanup ; + } ; + + printf (" %s\n", filename) ; + } ; + + switch (sfinfo.format & SF_FORMAT_SUBMASK) + { case SF_FORMAT_FLOAT : + case SF_FORMAT_DOUBLE : + case SF_FORMAT_VORBIS : + double_split = 1 ; + break ; + + default : + double_split = 0 ; + break ; + } ; + + if (double_split) + deinterleave_double (state) ; + else + deinterleave_int (state) ; + + ret = 0 ; + +cleanup : + + if (state != NULL) + { sf_close (state->infile) ; + for (ch = 0 ; ch < MAX_CHANNELS ; ch++) + if (state->outfile [ch] != NULL) + sf_close (state->outfile [ch]) ; + } ; + + free (state) ; + + return ret ; +} /* main */ + +/*------------------------------------------------------------------------------ +*/ + +static void +usage_exit (void) +{ puts ("\nUsage : sndfile-deinterleave \n") ; + puts ( + "Split a mutli-channel file into a set of mono files.\n" + "\n" + "If the input file is named 'a.wav', the output files will be named\n" + "a_00.wav, a_01.wav and so on.\n" + ) ; + printf ("Using %s.\n\n", sf_version_string ()) ; +} /* usage_exit */ + +static void +deinterleave_int (STATE * state) +{ int read_len ; + int ch, k ; + + do + { read_len = (int) sf_readf_int (state->infile, state->din.i, BUFFER_LEN) ; + + for (ch = 0 ; ch < state->channels ; ch ++) + { for (k = 0 ; k < read_len ; k++) + state->dout.i [k] = state->din.i [k * state->channels + ch] ; + sf_write_int (state->outfile [ch], state->dout.i, read_len) ; + } ; + } + while (read_len > 0) ; + +} /* deinterleave_int */ + +static void +deinterleave_double (STATE * state) +{ int read_len ; + int ch, k ; + + do + { read_len = (int) sf_readf_double (state->infile, state->din.d, BUFFER_LEN) ; + + for (ch = 0 ; ch < state->channels ; ch ++) + { for (k = 0 ; k < read_len ; k++) + state->dout.d [k] = state->din.d [k * state->channels + ch] ; + sf_write_double (state->outfile [ch], state->dout.d, read_len) ; + } ; + } + while (read_len > 0) ; + +} /* deinterleave_double */ diff --git a/extern/libsndfile-modified/programs/sndfile-info.c b/extern/libsndfile-modified/programs/sndfile-info.c new file mode 100644 index 000000000..ae4465496 --- /dev/null +++ b/extern/libsndfile-modified/programs/sndfile-info.c @@ -0,0 +1,529 @@ +/* +** Copyright (C) 1999-2019 Erik de Castro Lopo +** +** All rights reserved. +** +** 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 author nor the names of any 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 COPYRIGHT OWNER 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 +#include +#include +#include +#include +#include + +#include + +#include "common.h" + +#define BUFFER_LEN (1 << 16) + +#if (defined (WIN32) || defined (_WIN32)) +#include +#endif + +static void usage_exit (const char *progname) ; + +static void info_dump (const char *filename) ; +static int instrument_dump (const char *filename) ; +static int broadcast_dump (const char *filename) ; +static int chanmap_dump (const char *filename) ; +static int cart_dump (const char *filename) ; +static void total_dump (void) ; + +static double total_seconds = 0.0 ; + +int +main (int argc, char *argv []) +{ int k ; + + if (argc < 2 || strcmp (argv [1], "--help") == 0 || strcmp (argv [1], "-h") == 0) + usage_exit (program_name (argv [0])) ; + + if (strcmp (argv [1], "--instrument") == 0) + { int error = 0 ; + + for (k = 2 ; k < argc ; k++) + error += instrument_dump (argv [k]) ; + return error ; + } ; + + if (strcmp (argv [1], "--broadcast") == 0) + { int error = 0 ; + + for (k = 2 ; k < argc ; k++) + error += broadcast_dump (argv [k]) ; + return error ; + } ; + + if (strcmp (argv [1], "--channel-map") == 0) + { int error = 0 ; + + for (k = 2 ; k < argc ; k++) + error += chanmap_dump (argv [k]) ; + return error ; + } ; + + if (strcmp (argv [1], "--cart") == 0) + { int error = 0 ; + + for (k = 2 ; k < argc ; k++) + error += cart_dump (argv [k]) ; + return error ; + } ; + + for (k = 1 ; k < argc ; k++) + info_dump (argv [k]) ; + + if (argc > 2) + total_dump () ; + + return 0 ; +} /* main */ + +/*============================================================================== +** Print version and usage. +*/ + +static void +usage_exit (const char *progname) +{ printf ("Usage :\n %s ...\n", progname) ; + printf (" Prints out information about one or more sound files.\n\n") ; + printf (" %s --instrument \n", progname) ; + printf (" Prints out the instrument data for the given file.\n\n") ; + printf (" %s --broadcast \n", progname) ; + printf (" Prints out the broadcast WAV info for the given file.\n\n") ; + printf (" %s --channel-map \n", progname) ; + printf (" Prints out the channel map for the given file.\n\n") ; + printf (" %s --cart \n", progname) ; + printf (" Prints out the cart chunk WAV info for the given file.\n\n") ; + + printf ("Using %s.\n\n", sf_version_string ()) ; +#if (defined (_WIN32) || defined (WIN32)) + printf ("This is a Unix style command line application which\n" + "should be run in a MSDOS box or Command Shell window.\n\n") ; + printf ("Sleeping for 5 seconds before exiting.\n\n") ; + fflush (stdout) ; + + Sleep (5 * 1000) ; +#endif + exit (1) ; +} /* usage_exit */ + +/*============================================================================== +** Dumping of sndfile info. +*/ + +static double data [BUFFER_LEN] ; + +static double +calc_decibels (SF_INFO * sfinfo, double max) +{ double decibels ; + + switch (sfinfo->format & SF_FORMAT_SUBMASK) + { case SF_FORMAT_PCM_U8 : + case SF_FORMAT_PCM_S8 : + decibels = max / 0x80 ; + break ; + + case SF_FORMAT_PCM_16 : + decibels = max / 0x8000 ; + break ; + + case SF_FORMAT_PCM_24 : + decibels = max / 0x800000 ; + break ; + + case SF_FORMAT_PCM_32 : + decibels = max / 0x80000000 ; + break ; + + case SF_FORMAT_FLOAT : + case SF_FORMAT_DOUBLE : + case SF_FORMAT_VORBIS : + case SF_FORMAT_OPUS : + decibels = max / 1.0 ; + break ; + + default : + decibels = max / 0x8000 ; + break ; + } ; + + return 20.0 * log10 (decibels) ; +} /* calc_decibels */ + +static const char * +format_duration_str (double seconds) +{ static char str [128] ; + int hrs, min ; + double sec ; + + memset (str, 0, sizeof (str)) ; + + hrs = (int) (seconds / 3600.0) ; + min = (int) ((seconds - (hrs * 3600.0)) / 60.0) ; + sec = seconds - (hrs * 3600.0) - (min * 60.0) ; + + snprintf (str, sizeof (str) - 1, "%02d:%02d:%06.3f", hrs, min, sec) ; + + return str ; +} /* format_duration_str */ + +static const char * +generate_duration_str (SF_INFO *sfinfo) +{ + double seconds ; + + if (sfinfo->samplerate < 1) + return NULL ; + + if (sfinfo->frames / sfinfo->samplerate > 0x7FFFFFFF) + return "unknown" ; + + seconds = (1.0 * sfinfo->frames) / sfinfo->samplerate ; + + /* Accumulate the total of all known file durations */ + total_seconds += seconds ; + + return format_duration_str (seconds) ; +} /* generate_duration_str */ + +static void +info_dump (const char *filename) +{ static char strbuffer [BUFFER_LEN] ; + SNDFILE *file ; + SF_INFO sfinfo ; + double signal_max, decibels ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + if ((file = sf_open (filename, SFM_READ, &sfinfo)) == NULL) + { printf ("Error : Not able to open input file %s.\n", filename) ; + fflush (stdout) ; + memset (data, 0, sizeof (data)) ; + sf_command (file, SFC_GET_LOG_INFO, strbuffer, BUFFER_LEN) ; + puts (strbuffer) ; + puts (sf_strerror (NULL)) ; + return ; + } ; + + printf ("========================================\n") ; + sf_command (file, SFC_GET_LOG_INFO, strbuffer, BUFFER_LEN) ; + puts (strbuffer) ; + printf ("----------------------------------------\n") ; + + printf ("Sample Rate : %d\n", sfinfo.samplerate) ; + + if (sfinfo.frames == SF_COUNT_MAX) + printf ("Frames : unknown\n") ; + else + printf ("Frames : %" PRId64 "\n", sfinfo.frames) ; + + printf ("Channels : %d\n", sfinfo.channels) ; + printf ("Format : 0x%08X\n", sfinfo.format) ; + printf ("Sections : %d\n", sfinfo.sections) ; + printf ("Seekable : %s\n", (sfinfo.seekable ? "TRUE" : "FALSE")) ; + printf ("Duration : %s\n", generate_duration_str (&sfinfo)) ; + + if (sfinfo.frames < 100 * 1024 * 1024) + { /* Do not use sf_signal_max because it doesn't work for non-seekable files . */ + sf_command (file, SFC_CALC_SIGNAL_MAX, &signal_max, sizeof (signal_max)) ; + decibels = calc_decibels (&sfinfo, signal_max) ; + printf ("Signal Max : %g (%4.2f dB)\n", signal_max, decibels) ; + } ; + putchar ('\n') ; + + sf_close (file) ; + +} /* info_dump */ + +/*============================================================================== +** Dumping of SF_INSTRUMENT data. +*/ + +static const char * +str_of_type (int mode) +{ switch (mode) + { case SF_LOOP_NONE : return "none" ; + case SF_LOOP_FORWARD : return "fwd " ; + case SF_LOOP_BACKWARD : return "back" ; + case SF_LOOP_ALTERNATING : return "alt " ; + default : break ; + } ; + + return "????" ; +} /* str_of_mode */ + +static int +instrument_dump (const char *filename) +{ SNDFILE *file ; + SF_INFO sfinfo ; + SF_INSTRUMENT inst ; + int got_inst, k ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + if ((file = sf_open (filename, SFM_READ, &sfinfo)) == NULL) + { printf ("Error : Not able to open input file %s.\n", filename) ; + fflush (stdout) ; + memset (data, 0, sizeof (data)) ; + puts (sf_strerror (NULL)) ; + return 1 ; + } ; + + got_inst = sf_command (file, SFC_GET_INSTRUMENT, &inst, sizeof (inst)) ; + sf_close (file) ; + + if (got_inst == SF_FALSE) + { printf ("Error : File '%s' does not contain instrument data.\n\n", filename) ; + return 1 ; + } ; + + printf ("Instrument : %s\n\n", filename) ; + printf (" Gain : %d\n", inst.gain) ; + printf (" Base note : %d\n", inst.basenote) ; + printf (" Velocity : %d - %d\n", (int) inst.velocity_lo, (int) inst.velocity_hi) ; + printf (" Key : %d - %d\n", (int) inst.key_lo, (int) inst.key_hi) ; + printf (" Loop points : %d\n", inst.loop_count) ; + + for (k = 0 ; k < inst.loop_count ; k++) + printf (" %-2d Mode : %s Start : %6" PRIu32 " End : %6" PRIu32 + " Count : %6" PRIu32 "\n", k, str_of_type (inst.loops [k].mode), + inst.loops [k].start, inst.loops [k].end, inst.loops [k].count) ; + + putchar ('\n') ; + return 0 ; +} /* instrument_dump */ + +static int +broadcast_dump (const char *filename) +{ SNDFILE *file ; + SF_INFO sfinfo ; + SF_BROADCAST_INFO_2K bext ; + double time_ref_sec ; + int got_bext ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + if ((file = sf_open (filename, SFM_READ, &sfinfo)) == NULL) + { printf ("Error : Not able to open input file %s.\n", filename) ; + fflush (stdout) ; + memset (data, 0, sizeof (data)) ; + puts (sf_strerror (NULL)) ; + return 1 ; + } ; + + memset (&bext, 0, sizeof (SF_BROADCAST_INFO_2K)) ; + + got_bext = sf_command (file, SFC_GET_BROADCAST_INFO, &bext, sizeof (bext)) ; + sf_close (file) ; + + if (got_bext == SF_FALSE) + { printf ("Error : File '%s' does not contain broadcast information.\n\n", filename) ; + return 1 ; + } ; + + /* + ** From : http://www.ebu.ch/en/technical/publications/userguides/bwf_user_guide.php + ** + ** Time Reference: + ** This field is a count from midnight in samples to the first sample + ** of the audio sequence. + */ + + time_ref_sec = ((pow (2.0, 32) * bext.time_reference_high) + (1.0 * bext.time_reference_low)) / sfinfo.samplerate ; + + printf ("Description : %.*s\n", (int) sizeof (bext.description), bext.description) ; + printf ("Originator : %.*s\n", (int) sizeof (bext.originator), bext.originator) ; + printf ("Origination ref : %.*s\n", (int) sizeof (bext.originator_reference), bext.originator_reference) ; + printf ("Origination date : %.*s\n", (int) sizeof (bext.origination_date), bext.origination_date) ; + printf ("Origination time : %.*s\n", (int) sizeof (bext.origination_time), bext.origination_time) ; + + if (bext.time_reference_high == 0 && bext.time_reference_low == 0) + printf ("Time ref : 0\n") ; + else + printf ("Time ref : 0x%x%08x (%.6f seconds)\n", bext.time_reference_high, bext.time_reference_low, time_ref_sec) ; + + printf ("BWF version : %d\n", bext.version) ; + + if (bext.version >= 1) + printf ("UMID : %.*s\n", (int) sizeof (bext.umid), bext.umid) ; + + if (bext.version >= 2) + { /* 0x7fff shall be used to designate an unused value */ + /* valid range: -99.99 .. 99.99 */ + printf ("Loudness value : %6.2f LUFS\n", bext.loudness_value / 100.0) ; + /* valid range: 0.00 .. 99.99 */ + printf ("Loudness range : %6.2f LU\n", bext.loudness_range / 100.0) ; + /* valid range: -99.99 .. 99.99 */ + printf ("Max. true peak level : %6.2f dBTP\n", bext.max_true_peak_level / 100.0) ; + printf ("Max. momentary loudness : %6.2f LUFS\n", bext.max_momentary_loudness / 100.0) ; + printf ("Max. short term loudness : %6.2f LUFS\n", bext.max_shortterm_loudness / 100.0) ; + } ; + + printf ("Coding history : %.*s\n", bext.coding_history_size, bext.coding_history) ; + + return 0 ; +} /* broadcast_dump */ + +static int +chanmap_dump (const char *filename) +{ SNDFILE *file ; + SF_INFO sfinfo ; + int * channel_map ; + int got_chanmap, k ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + if ((file = sf_open (filename, SFM_READ, &sfinfo)) == NULL) + { printf ("Error : Not able to open input file %s.\n", filename) ; + fflush (stdout) ; + memset (data, 0, sizeof (data)) ; + puts (sf_strerror (NULL)) ; + return 1 ; + } ; + + if ((channel_map = calloc (sfinfo.channels, sizeof (int))) == NULL) + { printf ("Error : malloc failed.\n\n") ; + return 1 ; + } ; + + got_chanmap = sf_command (file, SFC_GET_CHANNEL_MAP_INFO, channel_map, sfinfo.channels * sizeof (int)) ; + sf_close (file) ; + + if (got_chanmap == SF_FALSE) + { printf ("Error : File '%s' does not contain channel map information.\n\n", filename) ; + free (channel_map) ; + return 1 ; + } ; + + printf ("File : %s\n\n", filename) ; + + puts (" Chan Position") ; + for (k = 0 ; k < sfinfo.channels ; k ++) + { const char * name ; + +#define CASE_NAME(x) case x : name = #x ; break ; + switch (channel_map [k]) + { CASE_NAME (SF_CHANNEL_MAP_INVALID) ; + CASE_NAME (SF_CHANNEL_MAP_MONO) ; + CASE_NAME (SF_CHANNEL_MAP_LEFT) ; + CASE_NAME (SF_CHANNEL_MAP_RIGHT) ; + CASE_NAME (SF_CHANNEL_MAP_CENTER) ; + CASE_NAME (SF_CHANNEL_MAP_FRONT_LEFT) ; + CASE_NAME (SF_CHANNEL_MAP_FRONT_RIGHT) ; + CASE_NAME (SF_CHANNEL_MAP_FRONT_CENTER) ; + CASE_NAME (SF_CHANNEL_MAP_REAR_CENTER) ; + CASE_NAME (SF_CHANNEL_MAP_REAR_LEFT) ; + CASE_NAME (SF_CHANNEL_MAP_REAR_RIGHT) ; + CASE_NAME (SF_CHANNEL_MAP_LFE) ; + CASE_NAME (SF_CHANNEL_MAP_FRONT_LEFT_OF_CENTER) ; + CASE_NAME (SF_CHANNEL_MAP_FRONT_RIGHT_OF_CENTER) ; + CASE_NAME (SF_CHANNEL_MAP_SIDE_LEFT) ; + CASE_NAME (SF_CHANNEL_MAP_SIDE_RIGHT) ; + CASE_NAME (SF_CHANNEL_MAP_TOP_CENTER) ; + CASE_NAME (SF_CHANNEL_MAP_TOP_FRONT_LEFT) ; + CASE_NAME (SF_CHANNEL_MAP_TOP_FRONT_RIGHT) ; + CASE_NAME (SF_CHANNEL_MAP_TOP_FRONT_CENTER) ; + CASE_NAME (SF_CHANNEL_MAP_TOP_REAR_LEFT) ; + CASE_NAME (SF_CHANNEL_MAP_TOP_REAR_RIGHT) ; + CASE_NAME (SF_CHANNEL_MAP_TOP_REAR_CENTER) ; + CASE_NAME (SF_CHANNEL_MAP_MAX) ; + default : name = "default" ; + break ; + } ; + + printf (" %3d %s\n", k, name) ; + } ; + + putchar ('\n') ; + free (channel_map) ; + + return 0 ; +} /* chanmap_dump */ + +static int +cart_dump (const char *filename) +{ SNDFILE *file ; + SF_INFO sfinfo ; + SF_CART_INFO_VAR (1024) cart ; + int got_cart, k ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + memset (&cart, 0, sizeof (cart)) ; + + if ((file = sf_open (filename, SFM_READ, &sfinfo)) == NULL) + { printf ("Error : Not able to open input file %s.\n", filename) ; + fflush (stdout) ; + memset (data, 0, sizeof (data)) ; + puts (sf_strerror (NULL)) ; + return 1 ; + } ; + + got_cart = sf_command (file, SFC_GET_CART_INFO, &cart, sizeof (cart)) ; + sf_close (file) ; + + if (got_cart == SF_FALSE) + { printf ("Error : File '%s' does not contain cart information.\n\n", filename) ; + return 1 ; + } ; + + printf ("Version : %.*s\n", (int) sizeof (cart.version), cart.version) ; + printf ("Title : %.*s\n", (int) sizeof (cart.title), cart.title) ; + printf ("Artist : %.*s\n", (int) sizeof (cart.artist), cart.artist) ; + printf ("Cut id : %.*s\n", (int) sizeof (cart.cut_id), cart.cut_id) ; + printf ("Category : %.*s\n", (int) sizeof (cart.category), cart.category) ; + printf ("Classification : %.*s\n", (int) sizeof (cart.classification), cart.classification) ; + printf ("Out cue : %.*s\n", (int) sizeof (cart.out_cue), cart.out_cue) ; + printf ("Start date : %.*s\n", (int) sizeof (cart.start_date), cart.start_date) ; + printf ("Start time : %.*s\n", (int) sizeof (cart.start_time), cart.start_time) ; + printf ("End date : %.*s\n", (int) sizeof (cart.end_date), cart.end_date) ; + printf ("End time : %.*s\n", (int) sizeof (cart.end_time), cart.end_time) ; + printf ("App id : %.*s\n", (int) sizeof (cart.producer_app_id), cart.producer_app_id) ; + printf ("App version : %.*s\n", (int) sizeof (cart.producer_app_version), cart.producer_app_version) ; + printf ("User defined : %.*s\n", (int) sizeof (cart.user_def), cart.user_def) ; + printf ("Level ref. : %d\n", cart.level_reference) ; + printf ("Post timers :\n") ; + + for (k = 0 ; k < ARRAY_LEN (cart.post_timers) ; k++) + if (cart.post_timers [k].usage [0]) + printf (" %d %.*s %d\n", k, (int) sizeof (cart.post_timers [k].usage), cart.post_timers [k].usage, cart.post_timers [k].value) ; + + printf ("Reserved : %.*s\n", (int) sizeof (cart.reserved), cart.reserved) ; + printf ("Url : %.*s\n", (int) sizeof (cart.url), cart.url) ; + printf ("Tag text : %.*s\n", cart.tag_text_size, cart.tag_text) ; + + return 0 ; +} /* cart_dump */ + +static void +total_dump (void) +{ printf ("========================================\n") ; + printf ("Total Duration : %s\n", format_duration_str (total_seconds)) ; +} /* total_dump */ diff --git a/extern/libsndfile-modified/programs/sndfile-interleave.c b/extern/libsndfile-modified/programs/sndfile-interleave.c new file mode 100644 index 000000000..2b44efb2c --- /dev/null +++ b/extern/libsndfile-modified/programs/sndfile-interleave.c @@ -0,0 +1,217 @@ +/* +** Copyright (C) 2009-2015 Erik de Castro Lopo +** +** All rights reserved. +** +** 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 author nor the names of any 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 COPYRIGHT OWNER 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 +#include +#include +#include + +#include "common.h" + +#define BUFFER_LEN 4096 +#define MAX_INPUTS 16 + + +typedef struct +{ SNDFILE * infile [MAX_INPUTS] ; + SNDFILE * outfile ; + + union + { double d [BUFFER_LEN] ; + int i [BUFFER_LEN] ; + } din ; + + union + + { double d [MAX_INPUTS * BUFFER_LEN] ; + int i [MAX_INPUTS * BUFFER_LEN] ; + } dout ; + + int channels ; +} STATE ; + + +static void print_usage (void) ; +static void interleave_int (STATE * state) ; +static void interleave_double (STATE * state) ; + + +int +main (int argc, char **argv) +{ STATE *state = NULL ; + SF_INFO sfinfo ; + int k, double_merge = 0 ; + int ret = 1 ; + + if (argc < 5) + { if (argc > 1) + puts ("\nError : need at least 2 input files.") ; + print_usage () ; + goto cleanup ; + } ; + + if (strcmp (argv [argc - 2], "-o") != 0) + { puts ("\nError : second last command line parameter should be '-o'.\n") ; + print_usage () ; + goto cleanup ; + } ; + + if (argc - 3 > MAX_INPUTS) + { printf ("\nError : Cannot handle more than %d input channels.\n\n", MAX_INPUTS) ; + goto cleanup ; + } ; + + state = calloc (1, sizeof (STATE)) ; + if (state == NULL) + { puts ("\nError : out of memory.\n") ; + goto cleanup ; + } ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + for (k = 1 ; k < argc - 2 ; k++) + { + if ((state->infile [k - 1] = sf_open (argv [k], SFM_READ, &sfinfo)) == NULL) + { printf ("\nError : Not able to open input file '%s'\n%s\n", argv [k], sf_strerror (NULL)) ; + goto cleanup ; + } ; + + if (sfinfo.channels != 1) + { printf ("\bError : Input file '%s' should be mono (has %d channels).\n", argv [k], sfinfo.channels) ; + goto cleanup ; + } ; + + switch (sfinfo.format & SF_FORMAT_SUBMASK) + { case SF_FORMAT_FLOAT : + case SF_FORMAT_DOUBLE : + case SF_FORMAT_VORBIS : + double_merge = 1 ; + break ; + + default : + break ; + } ; + + state->channels ++ ; + } ; + + sfinfo.channels = state->channels ; + sfinfo.format = sfe_file_type_of_ext (argv [argc - 1], sfinfo.format) ; + + if ((state->outfile = sf_open (argv [argc - 1], SFM_WRITE, &sfinfo)) == NULL) + { printf ("Not able to open output file '%s'\n%s\n", argv [argc - 1], sf_strerror (NULL)) ; + goto cleanup ; + } ; + + if (double_merge) + interleave_double (state) ; + else + interleave_int (state) ; + + ret = 0 ; + +cleanup : + + if (state != NULL) + { for (k = 0 ; k < MAX_INPUTS ; k++) + if (state->infile [k] != NULL) + sf_close (state->infile [k]) ; + sf_close (state->outfile) ; + } + + free (state) ; + + return ret ; +} /* main */ + +/*------------------------------------------------------------------------------ +*/ + + +static void +print_usage (void) +{ puts ("\nUsage : sndfile-interleave ... -o \n") ; + puts ("Merge two or more mono files into a single multi-channel file.\n") ; + printf ("Using %s.\n\n", sf_version_string ()) ; +} /* print_usage */ + + +static void +interleave_int (STATE * state) +{ int max_read_len, read_len ; + int ch, k ; + + do + { max_read_len = 0 ; + + for (ch = 0 ; ch < state->channels ; ch ++) + { read_len = (int) sf_read_int (state->infile [ch], state->din.i, BUFFER_LEN) ; + if (read_len < BUFFER_LEN) + memset (state->din.i + read_len, 0, sizeof (state->din.i [0]) * (BUFFER_LEN - read_len)) ; + + for (k = 0 ; k < BUFFER_LEN ; k++) + state->dout.i [k * state->channels + ch] = state->din.i [k] ; + + max_read_len = MAX (max_read_len, read_len) ; + } ; + + sf_writef_int (state->outfile, state->dout.i, max_read_len) ; + } + while (max_read_len > 0) ; + +} /* interleave_int */ + + +static void +interleave_double (STATE * state) +{ int max_read_len, read_len ; + int ch, k ; + + do + { max_read_len = 0 ; + + for (ch = 0 ; ch < state->channels ; ch ++) + { read_len = (int) sf_read_double (state->infile [ch], state->din.d, BUFFER_LEN) ; + if (read_len < BUFFER_LEN) + memset (state->din.d + read_len, 0, sizeof (state->din.d [0]) * (BUFFER_LEN - read_len)) ; + + for (k = 0 ; k < BUFFER_LEN ; k++) + state->dout.d [k * state->channels + ch] = state->din.d [k] ; + + max_read_len = MAX (max_read_len, read_len) ; + } ; + + sf_writef_double (state->outfile, state->dout.d, max_read_len) ; + } + while (max_read_len > 0) ; + +} /* interleave_double */ diff --git a/extern/libsndfile-modified/programs/sndfile-metadata-get.c b/extern/libsndfile-modified/programs/sndfile-metadata-get.c new file mode 100644 index 000000000..9a0963803 --- /dev/null +++ b/extern/libsndfile-modified/programs/sndfile-metadata-get.c @@ -0,0 +1,197 @@ +/* +** Copyright (C) 2008-2014 Erik de Castro Lopo +** Copyright (C) 2008-2010 George Blood Audio +** +** All rights reserved. +** +** 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 author nor the names of any 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 COPYRIGHT OWNER 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 + +#include +#include +#include +#include +#include + +#include + +#include "common.h" + +#define BUFFER_LEN (1 << 16) + +static void usage_exit (const char *progname, int exit_code) ; +static void process_args (SNDFILE * file, const SF_BROADCAST_INFO_2K * binfo, int argc, char * argv []) ; + +int +main (int argc, char *argv []) +{ SNDFILE *file ; + SF_INFO sfinfo ; + SF_BROADCAST_INFO_2K binfo ; + const char *progname ; + const char * filename = NULL ; + int start ; + + /* Store the program name. */ + progname = program_name (argv [0]) ; + + /* Check if we've been asked for help. */ + if (argc < 2 || strcmp (argv [1], "--help") == 0 || strcmp (argv [1], "-h") == 0) + usage_exit (progname, 0) ; + + if (argv [argc - 1][0] != '-') + { filename = argv [argc - 1] ; + start = 1 ; + } + else if (argv [1][0] != '-') + { filename = argv [1] ; + start = 2 ; + } + else + { printf ("Error : Either the first or the last command line parameter should be a filename.\n\n") ; + exit (1) ; + } ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + if ((file = sf_open (filename, SFM_READ, &sfinfo)) == NULL) + { printf ("Error : Open of file '%s' failed : %s\n\n", filename, sf_strerror (file)) ; + exit (1) ; + } ; + + memset (&binfo, 0, sizeof (binfo)) ; + if (sf_command (file, SFC_GET_BROADCAST_INFO, &binfo, sizeof (binfo)) == 0) + memset (&binfo, 0, sizeof (binfo)) ; + + process_args (file, &binfo, argc - 2, argv + start) ; + + sf_close (file) ; + return 0 ; +} /* main */ + +/*============================================================================== +** Print version and usage. +*/ + +static void +usage_exit (const char *progname, int exit_code) +{ printf ("\nUsage :\n %s [options] \n\nOptions:\n", progname) ; + + puts ( + " --bext-description Print the 'bext' description.\n" + " --bext-originator Print the 'bext' originator info.\n" + " --bext-orig-ref Print the 'bext' origination reference.\n" + " --bext-umid Print the 'bext' UMID.\n" + " --bext-orig-date Print the 'bext' origination date.\n" + " --bext-orig-time Print the 'bext' origination time.\n" + " --bext-loudness-value Print the 'bext' loudness value.\n" + " --bext-loudness-range Print the 'bext' loudness range.\n" + " --bext-max-truepeak Print the 'bext' max. true peak level\n" + " --bext-max-momentary Print the 'bext' max. momentary loudness\n" + " --bext-max-shortterm Print the 'bext' max. short term loudness\n" + " --bext-coding-hist Print the 'bext' coding history.\n" + ) ; + + puts ( + " --str-title Print the title metadata.\n" + " --str-copyright Print the copyright metadata.\n" + " --str-artist Print the artist metadata.\n" + " --str-comment Print the comment metadata.\n" + " --str-date Print the creation date metadata.\n" + " --str-album Print the album metadata.\n" + " --str-license Print the license metadata.\n" + ) ; + + printf ("Using %s.\n\n", sf_version_string ()) ; + exit (exit_code) ; +} /* usage_exit */ + +static void +process_args (SNDFILE * file, const SF_BROADCAST_INFO_2K * binfo, int argc, char * argv []) +{ const char * str ; + int k, do_all = 0 ; + +#define HANDLE_BEXT_ARG(cmd, name, field) \ + if (do_all || strcmp (argv [k], cmd) == 0) \ + { printf ("%-22s : %.*s\n", name, (int) sizeof (binfo->field), binfo->field) ; \ + if (! do_all) \ + continue ; \ + } ; + +#define HANDLE_BEXT_ARG_INT(cmd, name, field) \ + if (do_all || strcmp (argv [k], cmd) == 0) \ + { printf ("%-22s : %6.2f\n", name, binfo->field / 100.0) ; \ + if (! do_all) \ + continue ; \ + } ; + +#define HANDLE_STR_ARG(cmd, name, id) \ + if (do_all || strcmp (argv [k], cmd) == 0) \ + { str = sf_get_string (file, id) ; \ + printf ("%-22s : %s\n", name, str ? str : "") ; \ + if (! do_all) continue ; \ + } ; + + if (argc == 0) + { do_all = 1 ; + argc = 1 ; + } ; + + for (k = 0 ; k < argc ; k++) + { if (do_all || strcmp (argv [k], "--all") == 0) + do_all = 1 ; + + HANDLE_BEXT_ARG ("--bext-description", "Description", description) ; + HANDLE_BEXT_ARG ("--bext-originator", "Originator", originator) ; + HANDLE_BEXT_ARG ("--bext-orig-ref", "Origination ref", originator_reference) ; + HANDLE_BEXT_ARG ("--bext-umid", "UMID", umid) ; + HANDLE_BEXT_ARG ("--bext-orig-date", "Origination date", origination_date) ; + HANDLE_BEXT_ARG ("--bext-orig-time", "Origination time", origination_time) ; + HANDLE_BEXT_ARG_INT ("--bext-loudness-value", "Loudness value", loudness_value) ; + HANDLE_BEXT_ARG_INT ("--bext-loudness-range", "Loudness range", loudness_range) ; + HANDLE_BEXT_ARG_INT ("--bext-max-truepeak", "Max. true peak level", max_true_peak_level) ; + HANDLE_BEXT_ARG_INT ("--bext-max-momentary", "Max. momentary level", max_momentary_loudness) ; + HANDLE_BEXT_ARG_INT ("--bext-max-shortterm", "Max. short term level", max_shortterm_loudness) ; + HANDLE_BEXT_ARG ("--bext-coding-hist", "Coding history", coding_history) ; + + HANDLE_STR_ARG ("--str-title", "Name", SF_STR_TITLE) ; + HANDLE_STR_ARG ("--str-copyright", "Copyright", SF_STR_COPYRIGHT) ; + HANDLE_STR_ARG ("--str-artist", "Artist", SF_STR_ARTIST) ; + HANDLE_STR_ARG ("--str-comment", "Comment", SF_STR_COMMENT) ; + HANDLE_STR_ARG ("--str-date", "Create date", SF_STR_DATE) ; + HANDLE_STR_ARG ("--str-album", "Album", SF_STR_ALBUM) ; + HANDLE_STR_ARG ("--str-license", "License", SF_STR_LICENSE) ; + + if (! do_all) + { printf ("Error : Don't know what to do with command line arg '%s'.\n\n", argv [k]) ; + exit (1) ; + } ; + break ; + } ; + + return ; +} /* process_args */ diff --git a/extern/libsndfile-modified/programs/sndfile-metadata-set.c b/extern/libsndfile-modified/programs/sndfile-metadata-set.c new file mode 100644 index 000000000..33c793998 --- /dev/null +++ b/extern/libsndfile-modified/programs/sndfile-metadata-set.c @@ -0,0 +1,298 @@ +/* +** Copyright (C) 2008-2016 Erik de Castro Lopo +** Copyright (C) 2008-2010 George Blood Audio +** +** All rights reserved. +** +** 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 author nor the names of any 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 COPYRIGHT OWNER 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 + +#include +#include +#include +#include +#include + +#include + +#include "common.h" + +#define BUFFER_LEN (1 << 16) + + +static void usage_exit (const char *progname, int exit_code) ; +static void missing_param (const char * option) ; +static void read_localtime (struct tm * timedata) ; +static int has_bext_fields_set (const METADATA_INFO * info) ; + +int +main (int argc, char *argv []) +{ METADATA_INFO info ; + struct tm timedata ; + const char *progname ; + const char * filenames [2] = { NULL, NULL } ; + char date [128], time [128] ; + int k ; + + /* Store the program name. */ + progname = program_name (argv [0]) ; + + /* Check if we've been asked for help. */ + if (argc < 3 || strcmp (argv [1], "--help") == 0 || strcmp (argv [1], "-h") == 0) + usage_exit (progname, 0) ; + + /* Set all fields of the struct to zero bytes. */ + memset (&info, 0, sizeof (info)) ; + + /* Get the time in case we need it later. */ + read_localtime (&timedata) ; + + for (k = 1 ; k < argc ; k++) + { if (argv [k][0] != '-') + { if (filenames [0] == NULL) + filenames [0] = argv [k] ; + else if (filenames [1] == NULL) + filenames [1] = argv [k] ; + else + { printf ("Error : Already have two file names on the command line and then found '%s'.\n\n", argv [k]) ; + usage_exit (progname, 1) ; + } ; + continue ; + } ; + +#define HANDLE_BEXT_ARG(cmd, field) \ + if (strcmp (argv [k], cmd) == 0) \ + { k ++ ; \ + if (k == argc) missing_param (argv [k - 1]) ; \ + info.field = argv [k] ; \ + continue ; \ + } ; + + HANDLE_BEXT_ARG ("--bext-description", description) ; + HANDLE_BEXT_ARG ("--bext-originator", originator) ; + HANDLE_BEXT_ARG ("--bext-orig-ref", originator_reference) ; + HANDLE_BEXT_ARG ("--bext-umid", umid) ; + HANDLE_BEXT_ARG ("--bext-orig-date", origination_date) ; + HANDLE_BEXT_ARG ("--bext-orig-time", origination_time) ; + HANDLE_BEXT_ARG ("--bext-loudness-value", loudness_value) ; + HANDLE_BEXT_ARG ("--bext-loudness-range", loudness_range) ; + HANDLE_BEXT_ARG ("--bext-max-truepeak", max_true_peak_level) ; + HANDLE_BEXT_ARG ("--bext-max-momentary", max_momentary_loudness) ; + HANDLE_BEXT_ARG ("--bext-max-shortterm", max_shortterm_loudness) ; + HANDLE_BEXT_ARG ("--bext-coding-hist", coding_history) ; + HANDLE_BEXT_ARG ("--bext-time-ref", time_ref) ; + +#define HANDLE_STR_ARG(cmd, field) \ + if (strcmp (argv [k], cmd) == 0) \ + { k ++ ; \ + if (k == argc) missing_param (argv [k - 1]) ; \ + info.field = argv [k] ; \ + continue ; \ + } ; + + HANDLE_STR_ARG ("--str-comment", comment) ; + HANDLE_STR_ARG ("--str-title", title) ; + HANDLE_STR_ARG ("--str-copyright", copyright) ; + HANDLE_STR_ARG ("--str-artist", artist) ; + HANDLE_STR_ARG ("--str-date", date) ; + HANDLE_STR_ARG ("--str-album", album) ; + HANDLE_STR_ARG ("--str-license", license) ; + + /* Following options do not take an argument. */ + if (strcmp (argv [k], "--bext-auto-time-date") == 0) + { snprintf (time, sizeof (time), "%02d:%02d:%02d", timedata.tm_hour, timedata.tm_min, timedata.tm_sec) ; + info.origination_time = time ; + + snprintf (date, sizeof (date), "%04d-%02d-%02d", timedata.tm_year + 1900, timedata.tm_mon + 1, timedata.tm_mday) ; + info.origination_date = date ; + continue ; + } ; + + if (strcmp (argv [k], "--bext-auto-time") == 0) + { snprintf (time, sizeof (time), "%02d:%02d:%02d", timedata.tm_hour, timedata.tm_min, timedata.tm_sec) ; + info.origination_time = time ; + continue ; + } ; + + if (strcmp (argv [k], "--bext-auto-date") == 0) + { snprintf (date, sizeof (date), "%04d-%02d-%02d", timedata.tm_year + 1900, timedata.tm_mon + 1, timedata.tm_mday) ; + info.origination_date = strdup (date) ; + continue ; + } ; + + if (strcmp (argv [k], "--str-auto-date") == 0) + { snprintf (date, sizeof (date), "%04d-%02d-%02d", timedata.tm_year + 1900, timedata.tm_mon + 1, timedata.tm_mday) ; + + info.date = strdup (date) ; + continue ; + } ; + + printf ("Error : Don't know what to do with command line arg '%s'.\n\n", argv [k]) ; + usage_exit (progname, 1) ; + } ; + + /* Find out if any of the 'bext' fields are set. */ + info.has_bext_fields = has_bext_fields_set (&info) ; + + if (filenames [0] == NULL) + { printf ("Error : No input file specificed.\n\n") ; + exit (1) ; + } ; + + if (filenames [1] != NULL && strcmp (filenames [0], filenames [1]) == 0) + { printf ("Error : Input and output files are the same.\n\n") ; + exit (1) ; + } ; + + if (info.coding_history != NULL && filenames [1] == NULL) + { printf ("\n" + "Error : Trying to update coding history of an existing file which unfortunately\n" + " is not supported. Instead, create a new file using :\n" + "\n" + " %s --bext-coding-hist \"Coding history\" old_file.wav new_file.wav\n" + "\n", + progname) ; + exit (1) ; + } ; + + sfe_apply_metadata_changes (filenames, &info) ; + + return 0 ; +} /* main */ + +/*============================================================================== +** Print version and usage. +*/ + +static void +usage_exit (const char *progname, int exit_code) +{ printf ("\nUsage :\n\n" + " %s [options] \n" + " %s [options] \n" + "\n", + progname, progname) ; + + puts ( + "Where an option is made up of a pair of a field to set (one of\n" + "the 'bext' or metadata fields below) and a string. Fields are\n" + "as follows :\n" + ) ; + + puts ( + " --bext-description Set the 'bext' description.\n" + " --bext-originator Set the 'bext' originator.\n" + " --bext-orig-ref Set the 'bext' originator reference.\n" + " --bext-umid Set the 'bext' UMID.\n" + " --bext-orig-date Set the 'bext' origination date.\n" + " --bext-orig-time Set the 'bext' origination time.\n" + " --bext-loudness-value Set the 'bext' loudness value.\n" + " --bext-loudness-range Set the 'bext' loudness range.\n" + " --bext-max-truepeak Set the 'bext' max. true peak level\n" + " --bext-max-momentary Set the 'bext' max. momentary loudness\n" + " --bext-max-shortterm Set the 'bext' max. short term loudness\n" + " --bext-coding-hist Set the 'bext' coding history.\n" + " --bext-time-ref Set the 'bext' Time ref.\n" + "\n" + " --str-comment Set the metadata comment.\n" + " --str-title Set the metadata title.\n" + " --str-copyright Set the metadata copyright.\n" + " --str-artist Set the metadata artist.\n" + " --str-date Set the metadata date.\n" + " --str-album Set the metadata album.\n" + " --str-license Set the metadata license.\n" + ) ; + + puts ( + "There are also the following arguments which do not take a\n" + "parameter :\n\n" + " --bext-auto-time-date Set the 'bext' time and date to current time/date.\n" + " --bext-auto-time Set the 'bext' time to current time.\n" + " --bext-auto-date Set the 'bext' date to current date.\n" + " --str-auto-date Set the metadata date to current date.\n" + ) ; + + puts ( + "Most of the above operations can be done in-place on an existing\n" + "file. If any operation cannot be performed, the application will\n" + "exit with an appropriate error message.\n" + ) ; + + printf ("Using %s.\n\n", sf_version_string ()) ; + exit (exit_code) ; +} /* usage_exit */ + +static void +missing_param (const char * option) +{ + printf ("Error : Option '%s' needs a parameter but doesn't seem to have one.\n\n", option) ; + exit (1) ; +} /* missing_param */ + +/*============================================================================== +*/ + +static int +has_bext_fields_set (const METADATA_INFO * info) +{ + if (info->description || info->originator || info->originator_reference) + return 1 ; + + if (info->origination_date || info->origination_time || info->umid || info->coding_history || info->time_ref) + return 1 ; + + if (info->loudness_value || info->loudness_range || info->max_true_peak_level || info->max_momentary_loudness || info->max_shortterm_loudness) + return 1 ; + + return 0 ; +} /* has_bext_fields_set */ + +static void +read_localtime (struct tm * timedata) +{ time_t current ; + + time (¤t) ; + memset (timedata, 0, sizeof (struct tm)) ; + +#if defined (_WIN32) + /* If the re-entrant version is available, use it. */ + localtime_s (timedata, ¤t) ; +#elif defined (HAVE_LOCALTIME_R) + /* If the re-entrant version is available, use it. */ + localtime_r (¤t, timedata) ; +#elif defined (HAVE_LOCALTIME) + { + struct tm *tmptr ; + /* Otherwise use the standard one and copy the data to local storage. */ + if ((tmptr = localtime (¤t)) != NULL) + memcpy (timedata, tmptr, sizeof (struct tm)) ; + } +#endif + + return ; +} /* read_localtime */ diff --git a/extern/libsndfile-modified/programs/sndfile-play.c b/extern/libsndfile-modified/programs/sndfile-play.c new file mode 100644 index 000000000..48b95c133 --- /dev/null +++ b/extern/libsndfile-modified/programs/sndfile-play.c @@ -0,0 +1,860 @@ +/* +** Copyright (C) 1999-2018 Erik de Castro Lopo +** +** All rights reserved. +** +** 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 author nor the names of any 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 COPYRIGHT OWNER 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 "sfconfig.h" + +#include +#include +#include +#include + +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include + +#include "common.h" + +#if HAVE_ALSA_ASOUNDLIB_H + #define ALSA_PCM_NEW_HW_PARAMS_API + #define ALSA_PCM_NEW_SW_PARAMS_API + #include + #include +#endif + +#if defined (__ANDROID__) + +#elif defined (__linux__) || defined (__FreeBSD_kernel__) || defined (__FreeBSD__) || defined (__riscos__) + #include + #include + #include + +#elif HAVE_SNDIO_H + #include + +#elif (defined (sun) && defined (unix)) || defined(__NetBSD__) + #include + #include + #include + +#elif (OS_IS_WIN32 == 1) + #include + #include + +#endif + +#define SIGNED_SIZEOF(x) ((int) sizeof (x)) +#define BUFFER_LEN (2048) + +/*------------------------------------------------------------------------------ +** Linux/OSS functions for playing a sound. +*/ + +#if HAVE_ALSA_ASOUNDLIB_H + +static snd_pcm_t * alsa_open (int channels, unsigned srate, int realtime) ; +static int alsa_write_float (snd_pcm_t *alsa_dev, float *data, int frames, int channels) ; + +static void +alsa_play (int argc, char *argv []) +{ static float buffer [BUFFER_LEN] ; + SNDFILE *sndfile ; + SF_INFO sfinfo ; + snd_pcm_t * alsa_dev ; + int k, readcount, subformat ; + + for (k = 1 ; k < argc ; k++) + { memset (&sfinfo, 0, sizeof (sfinfo)) ; + + printf ("Playing %s\n", argv [k]) ; + if (! (sndfile = sf_open (argv [k], SFM_READ, &sfinfo))) + { puts (sf_strerror (NULL)) ; + continue ; + } ; + + if (sfinfo.channels < 1 || sfinfo.channels > 2) + { printf ("Error : channels = %d.\n", sfinfo.channels) ; + continue ; + } ; + + if ((alsa_dev = alsa_open (sfinfo.channels, (unsigned) sfinfo.samplerate, SF_FALSE)) == NULL) + continue ; + + subformat = sfinfo.format & SF_FORMAT_SUBMASK ; + + if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE) + { double scale ; + int m ; + + sf_command (sndfile, SFC_CALC_SIGNAL_MAX, &scale, sizeof (scale)) ; + if (scale > 1.0) + scale = 1.0 / scale ; + else + scale = 1.0 ; + + while ((readcount = sf_read_float (sndfile, buffer, BUFFER_LEN))) + { for (m = 0 ; m < readcount ; m++) + buffer [m] *= scale ; + alsa_write_float (alsa_dev, buffer, BUFFER_LEN / sfinfo.channels, sfinfo.channels) ; + } ; + } + else + { while ((readcount = sf_read_float (sndfile, buffer, BUFFER_LEN))) + alsa_write_float (alsa_dev, buffer, BUFFER_LEN / sfinfo.channels, sfinfo.channels) ; + } ; + + snd_pcm_drain (alsa_dev) ; + snd_pcm_close (alsa_dev) ; + + sf_close (sndfile) ; + } ; + + return ; +} /* alsa_play */ + +static snd_pcm_t * +alsa_open (int channels, unsigned samplerate, int realtime) +{ const char * device = "default" ; + snd_pcm_t *alsa_dev = NULL ; + snd_pcm_hw_params_t *hw_params ; + snd_pcm_uframes_t buffer_size ; + snd_pcm_uframes_t alsa_period_size, alsa_buffer_frames ; + snd_pcm_sw_params_t *sw_params ; + + int err ; + + if (realtime) + { alsa_period_size = 256 ; + alsa_buffer_frames = 3 * alsa_period_size ; + } + else + { alsa_period_size = 1024 ; + alsa_buffer_frames = 4 * alsa_period_size ; + } ; + + if ((err = snd_pcm_open (&alsa_dev, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) + { fprintf (stderr, "cannot open audio device \"%s\" (%s)\n", device, snd_strerror (err)) ; + goto catch_error ; + } ; + + snd_pcm_nonblock (alsa_dev, 0) ; + + if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) + { fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n", snd_strerror (err)) ; + goto catch_error ; + } ; + + if ((err = snd_pcm_hw_params_any (alsa_dev, hw_params)) < 0) + { fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n", snd_strerror (err)) ; + goto catch_error ; + } ; + + if ((err = snd_pcm_hw_params_set_access (alsa_dev, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) + { fprintf (stderr, "cannot set access type (%s)\n", snd_strerror (err)) ; + goto catch_error ; + } ; + + if ((err = snd_pcm_hw_params_set_format (alsa_dev, hw_params, SND_PCM_FORMAT_FLOAT)) < 0) + { fprintf (stderr, "cannot set sample format (%s)\n", snd_strerror (err)) ; + goto catch_error ; + } ; + + if ((err = snd_pcm_hw_params_set_rate_near (alsa_dev, hw_params, &samplerate, 0)) < 0) + { fprintf (stderr, "cannot set sample rate (%s)\n", snd_strerror (err)) ; + goto catch_error ; + } ; + + if ((err = snd_pcm_hw_params_set_channels (alsa_dev, hw_params, channels)) < 0) + { fprintf (stderr, "cannot set channel count (%s)\n", snd_strerror (err)) ; + goto catch_error ; + } ; + + if ((err = snd_pcm_hw_params_set_buffer_size_near (alsa_dev, hw_params, &alsa_buffer_frames)) < 0) + { fprintf (stderr, "cannot set buffer size (%s)\n", snd_strerror (err)) ; + goto catch_error ; + } ; + + if ((err = snd_pcm_hw_params_set_period_size_near (alsa_dev, hw_params, &alsa_period_size, 0)) < 0) + { fprintf (stderr, "cannot set period size (%s)\n", snd_strerror (err)) ; + goto catch_error ; + } ; + + if ((err = snd_pcm_hw_params (alsa_dev, hw_params)) < 0) + { fprintf (stderr, "cannot set parameters (%s)\n", snd_strerror (err)) ; + goto catch_error ; + } ; + + /* extra check: if we have only one period, this code won't work */ + snd_pcm_hw_params_get_period_size (hw_params, &alsa_period_size, 0) ; + snd_pcm_hw_params_get_buffer_size (hw_params, &buffer_size) ; + if (alsa_period_size == buffer_size) + { fprintf (stderr, "Can't use period equal to buffer size (%lu == %lu)", alsa_period_size, buffer_size) ; + goto catch_error ; + } ; + + snd_pcm_hw_params_free (hw_params) ; + + if ((err = snd_pcm_sw_params_malloc (&sw_params)) != 0) + { fprintf (stderr, "%s: snd_pcm_sw_params_malloc: %s", __func__, snd_strerror (err)) ; + goto catch_error ; + } ; + + if ((err = snd_pcm_sw_params_current (alsa_dev, sw_params)) != 0) + { fprintf (stderr, "%s: snd_pcm_sw_params_current: %s", __func__, snd_strerror (err)) ; + goto catch_error ; + } ; + + /* note: set start threshold to delay start until the ring buffer is full */ + snd_pcm_sw_params_current (alsa_dev, sw_params) ; + + if ((err = snd_pcm_sw_params_set_start_threshold (alsa_dev, sw_params, buffer_size)) < 0) + { fprintf (stderr, "cannot set start threshold (%s)\n", snd_strerror (err)) ; + goto catch_error ; + } ; + + if ((err = snd_pcm_sw_params (alsa_dev, sw_params)) != 0) + { fprintf (stderr, "%s: snd_pcm_sw_params: %s", __func__, snd_strerror (err)) ; + goto catch_error ; + } ; + + snd_pcm_sw_params_free (sw_params) ; + + snd_pcm_reset (alsa_dev) ; + +catch_error : + + if (err < 0 && alsa_dev != NULL) + { snd_pcm_close (alsa_dev) ; + return NULL ; + } ; + + return alsa_dev ; +} /* alsa_open */ + +static int +alsa_write_float (snd_pcm_t *alsa_dev, float *data, int frames, int channels) +{ static int epipe_count = 0 ; + + int total = 0 ; + int retval ; + + if (epipe_count > 0) + epipe_count -- ; + + while (total < frames) + { retval = snd_pcm_writei (alsa_dev, data + total * channels, frames - total) ; + + if (retval >= 0) + { total += retval ; + if (total == frames) + return total ; + + continue ; + } ; + + switch (retval) + { case -EAGAIN : + puts ("alsa_write_float: EAGAIN") ; + continue ; + break ; + + case -EPIPE : + if (epipe_count > 0) + { printf ("alsa_write_float: EPIPE %d\n", epipe_count) ; + if (epipe_count > 140) + return retval ; + } ; + epipe_count += 100 ; + +#if 0 + if (0) + { snd_pcm_status_t *status ; + + snd_pcm_status_alloca (&status) ; + if ((retval = snd_pcm_status (alsa_dev, status)) < 0) + fprintf (stderr, "alsa_out: xrun. can't determine length\n") ; + else if (snd_pcm_status_get_state (status) == SND_PCM_STATE_XRUN) + { struct timeval now, diff, tstamp ; + + gettimeofday (&now, 0) ; + snd_pcm_status_get_trigger_tstamp (status, &tstamp) ; + timersub (&now, &tstamp, &diff) ; + + fprintf (stderr, "alsa_write_float xrun: of at least %.3f msecs. resetting stream\n", + diff.tv_sec * 1000 + diff.tv_usec / 1000.0) ; + } + else + fprintf (stderr, "alsa_write_float: xrun. can't determine length\n") ; + } ; +#endif + + snd_pcm_prepare (alsa_dev) ; + break ; + + case -EBADFD : + fprintf (stderr, "alsa_write_float: Bad PCM state.n") ; + return 0 ; + break ; + +#if defined ESTRPIPE && ESTRPIPE != EPIPE + case -ESTRPIPE : + fprintf (stderr, "alsa_write_float: Suspend event.n") ; + return 0 ; + break ; +#endif + + case -EIO : + puts ("alsa_write_float: EIO") ; + return 0 ; + + default : + fprintf (stderr, "alsa_write_float: retval = %d\n", retval) ; + return 0 ; + break ; + } ; /* switch */ + } ; /* while */ + + return total ; +} /* alsa_write_float */ + +#endif /* HAVE_ALSA_ASOUNDLIB_H */ + +/*------------------------------------------------------------------------------ +** Linux/OSS functions for playing a sound. +*/ + +#if !defined (__ANDROID__) && (defined (__linux__) || defined (__FreeBSD_kernel__) || defined (__FreeBSD__) || defined (__riscos__)) + +static int opensoundsys_open_device (int channels, int srate) ; + +static int +opensoundsys_play (int argc, char *argv []) +{ static short buffer [BUFFER_LEN] ; + SNDFILE *sndfile ; + SF_INFO sfinfo ; + int k, audio_device, readcount, writecount, subformat ; + + for (k = 1 ; k < argc ; k++) + { memset (&sfinfo, 0, sizeof (sfinfo)) ; + + printf ("Playing %s\n", argv [k]) ; + if (! (sndfile = sf_open (argv [k], SFM_READ, &sfinfo))) + { puts (sf_strerror (NULL)) ; + continue ; + } ; + + if (sfinfo.channels < 1 || sfinfo.channels > 2) + { printf ("Error : channels = %d.\n", sfinfo.channels) ; + continue ; + } ; + + audio_device = opensoundsys_open_device (sfinfo.channels, sfinfo.samplerate) ; + + subformat = sfinfo.format & SF_FORMAT_SUBMASK ; + + if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE) + { static float float_buffer [BUFFER_LEN] ; + double scale ; + int m ; + + sf_command (sndfile, SFC_CALC_SIGNAL_MAX, &scale, sizeof (scale)) ; + if (scale < 1e-10) + scale = 1.0 ; + else + scale = 32700.0 / scale ; + + while ((readcount = sf_read_float (sndfile, float_buffer, BUFFER_LEN))) + { for (m = 0 ; m < readcount ; m++) + buffer [m] = scale * float_buffer [m] ; + writecount = write (audio_device, buffer, readcount * sizeof (short)) ; + } ; + } + else + { while ((readcount = sf_read_short (sndfile, buffer, BUFFER_LEN))) + writecount = write (audio_device, buffer, readcount * sizeof (short)) ; + } ; + + if (ioctl (audio_device, SNDCTL_DSP_POST, 0) == -1) + perror ("ioctl (SNDCTL_DSP_POST) ") ; + + if (ioctl (audio_device, SNDCTL_DSP_SYNC, 0) == -1) + perror ("ioctl (SNDCTL_DSP_SYNC) ") ; + + close (audio_device) ; + + sf_close (sndfile) ; + } ; + + return writecount ; +} /* opensoundsys_play */ + +static int +opensoundsys_open_device (int channels, int srate) +{ int fd, stereo, fmt ; + + if ((fd = open ("/dev/dsp", O_WRONLY, 0)) == -1 && + (fd = open ("/dev/sound/dsp", O_WRONLY, 0)) == -1) + { perror ("opensoundsys_open_device : open ") ; + exit (1) ; + } ; + + stereo = 0 ; + if (ioctl (fd, SNDCTL_DSP_STEREO, &stereo) == -1) + { /* Fatal error */ + perror ("opensoundsys_open_device : stereo ") ; + exit (1) ; + } ; + + if (ioctl (fd, SNDCTL_DSP_RESET, 0)) + { perror ("opensoundsys_open_device : reset ") ; + exit (1) ; + } ; + + fmt = CPU_IS_BIG_ENDIAN ? AFMT_S16_BE : AFMT_S16_LE ; + if (ioctl (fd, SNDCTL_DSP_SETFMT, &fmt) != 0) + { perror ("opensoundsys_open_device : set format ") ; + exit (1) ; + } ; + + if (ioctl (fd, SNDCTL_DSP_CHANNELS, &channels) != 0) + { perror ("opensoundsys_open_device : channels ") ; + exit (1) ; + } ; + + if (ioctl (fd, SNDCTL_DSP_SPEED, &srate) != 0) + { perror ("opensoundsys_open_device : sample rate ") ; + exit (1) ; + } ; + + if (ioctl (fd, SNDCTL_DSP_SYNC, 0) != 0) + { perror ("opensoundsys_open_device : sync ") ; + exit (1) ; + } ; + + return fd ; +} /* opensoundsys_open_device */ + +#endif /* __linux__ */ + +/*------------------------------------------------------------------------------ +** Mac OS X functions for playing a sound. +*/ + +/* MacOSX 10.8 use a new Audio API. Someone needs to write some code for it. */ + +/*------------------------------------------------------------------------------ +** Win32 functions for playing a sound. +** +** This API sucks. Its needlessly complicated and is *WAY* too loose with +** passing pointers around in integers and using char* pointers to +** point to data instead of short*. It plain sucks! +*/ + +#if (OS_IS_WIN32 == 1) + +#define WIN32_BUFFER_LEN (1 << 15) + +typedef struct +{ HWAVEOUT hwave ; + WAVEHDR whdr [2] ; + + CRITICAL_SECTION mutex ; /* to control access to BuffersInUSe */ + HANDLE Event ; /* signal that a buffer is free */ + + short buffer [WIN32_BUFFER_LEN / sizeof (short)] ; + int current, bufferlen ; + int BuffersInUse ; + + SNDFILE *sndfile ; + SF_INFO sfinfo ; + + sf_count_t remaining ; +} Win32_Audio_Data ; + + +static void +win32_play_data (Win32_Audio_Data *audio_data) +{ int thisread, readcount ; + + /* fill a buffer if there is more data and we can read it sucessfully */ + readcount = (audio_data->remaining > audio_data->bufferlen) ? audio_data->bufferlen : (int) audio_data->remaining ; + + short *lpData = (short *) (void *) audio_data->whdr [audio_data->current].lpData ; + thisread = (int) sf_read_short (audio_data->sndfile, lpData, readcount) ; + + audio_data->remaining -= thisread ; + + if (thisread > 0) + { /* Fix buffer length if this is only a partial block. */ + if (thisread < audio_data->bufferlen) + audio_data->whdr [audio_data->current].dwBufferLength = thisread * sizeof (short) ; + + /* Queue the WAVEHDR */ + waveOutWrite (audio_data->hwave, (LPWAVEHDR) &(audio_data->whdr [audio_data->current]), sizeof (WAVEHDR)) ; + + /* count another buffer in use */ + EnterCriticalSection (&audio_data->mutex) ; + audio_data->BuffersInUse ++ ; + LeaveCriticalSection (&audio_data->mutex) ; + + /* use the other buffer next time */ + audio_data->current = (audio_data->current + 1) % 2 ; + } ; + + return ; +} /* win32_play_data */ + +static void CALLBACK +win32_audio_out_callback (HWAVEOUT hwave, UINT msg, DWORD_PTR data, DWORD param1, DWORD param2) +{ Win32_Audio_Data *audio_data ; + + /* Prevent compiler warnings. */ + (void) hwave ; + (void) param1 ; + (void) param2 ; + + if (data == 0) + return ; + + /* + ** I consider this technique of passing a pointer via an integer as + ** fundamentally broken but thats the way microsoft has defined the + ** interface. + */ + audio_data = (Win32_Audio_Data*) data ; + + /* let main loop know a buffer is free */ + if (msg == MM_WOM_DONE) + { EnterCriticalSection (&audio_data->mutex) ; + audio_data->BuffersInUse -- ; + LeaveCriticalSection (&audio_data->mutex) ; + SetEvent (audio_data->Event) ; + } ; + + return ; +} /* win32_audio_out_callback */ + +static void +win32_play (int argc, char *argv []) +{ Win32_Audio_Data audio_data ; + + WAVEFORMATEX wf ; + int k, error ; + + audio_data.sndfile = NULL ; + audio_data.hwave = 0 ; + + for (k = 1 ; k < argc ; k++) + { printf ("Playing %s\n", argv [k]) ; + + if (! (audio_data.sndfile = sf_open (argv [k], SFM_READ, &(audio_data.sfinfo)))) + { puts (sf_strerror (NULL)) ; + continue ; + } ; + + audio_data.remaining = audio_data.sfinfo.frames * audio_data.sfinfo.channels ; + audio_data.current = 0 ; + + InitializeCriticalSection (&audio_data.mutex) ; + audio_data.Event = CreateEvent (0, FALSE, FALSE, 0) ; + + wf.nChannels = audio_data.sfinfo.channels ; + wf.wFormatTag = WAVE_FORMAT_PCM ; + wf.cbSize = 0 ; + wf.wBitsPerSample = 16 ; + + wf.nSamplesPerSec = audio_data.sfinfo.samplerate ; + + wf.nBlockAlign = audio_data.sfinfo.channels * sizeof (short) ; + + wf.nAvgBytesPerSec = wf.nBlockAlign * wf.nSamplesPerSec ; + + error = waveOutOpen (&(audio_data.hwave), WAVE_MAPPER, &wf, (DWORD_PTR) win32_audio_out_callback, + (DWORD_PTR) &audio_data, CALLBACK_FUNCTION) ; + if (error) + { puts ("waveOutOpen failed.") ; + audio_data.hwave = 0 ; + continue ; + } ; + + audio_data.whdr [0].lpData = (char*) audio_data.buffer ; + audio_data.whdr [1].lpData = ((char*) audio_data.buffer) + sizeof (audio_data.buffer) / 2 ; + + audio_data.whdr [0].dwBufferLength = sizeof (audio_data.buffer) / 2 ; + audio_data.whdr [1].dwBufferLength = sizeof (audio_data.buffer) / 2 ; + + audio_data.whdr [0].dwFlags = 0 ; + audio_data.whdr [1].dwFlags = 0 ; + + /* length of each audio buffer in samples */ + audio_data.bufferlen = sizeof (audio_data.buffer) / 2 / sizeof (short) ; + + /* Prepare the WAVEHDRs */ + if ((error = waveOutPrepareHeader (audio_data.hwave, &(audio_data.whdr [0]), sizeof (WAVEHDR)))) + { printf ("waveOutPrepareHeader [0] failed : %08X\n", error) ; + waveOutClose (audio_data.hwave) ; + continue ; + } ; + + if ((error = waveOutPrepareHeader (audio_data.hwave, &(audio_data.whdr [1]), sizeof (WAVEHDR)))) + { printf ("waveOutPrepareHeader [1] failed : %08X\n", error) ; + waveOutUnprepareHeader (audio_data.hwave, &(audio_data.whdr [0]), sizeof (WAVEHDR)) ; + waveOutClose (audio_data.hwave) ; + continue ; + } ; + + /* Fill up both buffers with audio data */ + audio_data.BuffersInUse = 0 ; + win32_play_data (&audio_data) ; + win32_play_data (&audio_data) ; + + /* loop until both buffers are released */ + while (audio_data.BuffersInUse > 0) + { + /* wait for buffer to be released */ + WaitForSingleObject (audio_data.Event, INFINITE) ; + + /* refill the buffer if there is more data to play */ + win32_play_data (&audio_data) ; + } ; + + waveOutUnprepareHeader (audio_data.hwave, &(audio_data.whdr [0]), sizeof (WAVEHDR)) ; + waveOutUnprepareHeader (audio_data.hwave, &(audio_data.whdr [1]), sizeof (WAVEHDR)) ; + + waveOutClose (audio_data.hwave) ; + audio_data.hwave = 0 ; + + DeleteCriticalSection (&audio_data.mutex) ; + + sf_close (audio_data.sndfile) ; + } ; + +} /* win32_play */ + +#endif /* Win32 */ + +/*------------------------------------------------------------------------------ +** OpenBSD's sndio. +*/ + +#if HAVE_SNDIO_H + +static void +sndio_play (int argc, char *argv []) +{ struct sio_hdl *hdl ; + struct sio_par par ; + short buffer [BUFFER_LEN] ; + SNDFILE *sndfile ; + SF_INFO sfinfo ; + int k, readcount ; + + for (k = 1 ; k < argc ; k++) + { printf ("Playing %s\n", argv [k]) ; + if (! (sndfile = sf_open (argv [k], SFM_READ, &sfinfo))) + { puts (sf_strerror (NULL)) ; + continue ; + } ; + + if (sfinfo.channels < 1 || sfinfo.channels > 2) + { printf ("Error : channels = %d.\n", sfinfo.channels) ; + continue ; + } ; + + if ((hdl = sio_open (NULL, SIO_PLAY, 0)) == NULL) + { fprintf (stderr, "open sndio device failed") ; + return ; + } ; + + sio_initpar (&par) ; + par.rate = sfinfo.samplerate ; + par.pchan = sfinfo.channels ; + par.bits = 16 ; + par.sig = 1 ; + par.le = SIO_LE_NATIVE ; + + if (! sio_setpar (hdl, &par) || ! sio_getpar (hdl, &par)) + { fprintf (stderr, "set sndio params failed") ; + return ; + } ; + + if (! sio_start (hdl)) + { fprintf (stderr, "sndio start failed") ; + return ; + } ; + + while ((readcount = sf_read_short (sndfile, buffer, BUFFER_LEN))) + sio_write (hdl, buffer, readcount * sizeof (short)) ; + + sio_close (hdl) ; + } ; + + return ; +} /* sndio_play */ + +#endif /* sndio */ + +/*------------------------------------------------------------------------------ +** Solaris. +*/ + +#if (defined (sun) && defined (unix)) || defined(__NetBSD__) + +static void +solaris_play (int argc, char *argv []) +{ static short buffer [BUFFER_LEN] ; + audio_info_t audio_info ; + SNDFILE *sndfile ; + SF_INFO sfinfo ; + unsigned long delay_time ; + long k, start_count, output_count, write_count, read_count ; + int audio_fd, error, done ; + + for (k = 1 ; k < argc ; k++) + { printf ("Playing %s\n", argv [k]) ; + if (! (sndfile = sf_open (argv [k], SFM_READ, &sfinfo))) + { puts (sf_strerror (NULL)) ; + continue ; + } ; + + if (sfinfo.channels < 1 || sfinfo.channels > 2) + { printf ("Error : channels = %d.\n", sfinfo.channels) ; + continue ; + } ; + + /* open the audio device - write only, non-blocking */ + if ((audio_fd = open ("/dev/audio", O_WRONLY | O_NONBLOCK)) < 0) + { perror ("open (/dev/audio) failed") ; + return ; + } ; + + /* Retrive standard values. */ + AUDIO_INITINFO (&audio_info) ; + + audio_info.play.sample_rate = sfinfo.samplerate ; + audio_info.play.channels = sfinfo.channels ; + audio_info.play.precision = 16 ; + audio_info.play.encoding = AUDIO_ENCODING_LINEAR ; + + if ((error = ioctl (audio_fd, AUDIO_SETINFO, &audio_info))) + { perror ("ioctl (AUDIO_SETINFO) failed") ; + return ; + } ; + + /* Delay time equal to 1/4 of a buffer in microseconds. */ + delay_time = (BUFFER_LEN * 1000000) / (audio_info.play.sample_rate * 4) ; + + done = 0 ; + while (! done) + { read_count = sf_read_short (sndfile, buffer, BUFFER_LEN) ; + if (read_count < BUFFER_LEN) + { memset (&(buffer [read_count]), 0, (BUFFER_LEN - read_count) * sizeof (short)) ; + /* Tell the main application to terminate. */ + done = SF_TRUE ; + } ; + + start_count = 0 ; + output_count = BUFFER_LEN * sizeof (short) ; + + while (output_count > 0) + { /* write as much data as possible */ + write_count = write (audio_fd, &(buffer [start_count]), output_count) ; + if (write_count > 0) + { output_count -= write_count ; + start_count += write_count ; + } + else + { /* Give the audio output time to catch up. */ + usleep (delay_time) ; + } ; + } ; /* while (outpur_count > 0) */ + } ; /* while (! done) */ + + close (audio_fd) ; + } ; + + return ; +} /* solaris_play */ + +#endif /* Solaris or NetBSD */ + +/*============================================================================== +** Main function. +*/ + +int +main (int argc, char *argv []) +{ + if (argc < 2) + { + printf ("\nUsage : %s \n\n", program_name (argv [0])) ; + printf ("Using %s.\n\n", sf_version_string ()) ; +#if (OS_IS_WIN32 == 1) + printf ("This is a Unix style command line application which\n" + "should be run in a MSDOS box or Command Shell window.\n\n") ; + printf ("Sleeping for 5 seconds before exiting.\n\n") ; + + Sleep (5 * 1000) ; +#endif + return 1 ; + } ; + +#if defined (__ANDROID__) + puts ("*** Playing sound not yet supported on Android.") ; + puts ("*** Please feel free to submit a patch.") ; + return 1 ; +#elif defined (__linux__) + #if HAVE_ALSA_ASOUNDLIB_H + if (access ("/proc/asound/cards", R_OK) == 0) + alsa_play (argc, argv) ; + else + #endif + opensoundsys_play (argc, argv) ; +#elif defined (__FreeBSD_kernel__) || defined (__FreeBSD__) || defined (__riscos__) + opensoundsys_play (argc, argv) ; +#elif HAVE_SNDIO_H + sndio_play (argc, argv) ; +#elif (defined (sun) && defined (unix)) || defined(__NetBSD__) + solaris_play (argc, argv) ; +#elif (OS_IS_WIN32 == 1) + win32_play (argc, argv) ; +#else + puts ("*** Playing sound not supported on this platform.") ; + puts ("*** Please feel free to submit a patch.") ; + return 1 ; +#endif + + return 0 ; +} /* main */ + diff --git a/extern/libsndfile-modified/programs/sndfile-salvage.c b/extern/libsndfile-modified/programs/sndfile-salvage.c new file mode 100644 index 000000000..1a76dc3aa --- /dev/null +++ b/extern/libsndfile-modified/programs/sndfile-salvage.c @@ -0,0 +1,302 @@ +/* +** Copyright (C) 2010-2014 Erik de Castro Lopo +** +** All rights reserved. +** +** 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 author nor the names of any 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 COPYRIGHT OWNER 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 "sfconfig.h" + +#include +#include +#include +#include +#include +#include +#include +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif +#include +#include +#include + +#include + +#include "common.h" + +#define BUFFER_LEN (1 << 16) + +#define NOT(x) (! (x)) + +#ifndef _WIN32 +typedef off_t sf_off_t ; +#else +typedef long long sf_off_t ; +#endif + + +static void usage_exit (const char *progname) ; +static void salvage_file (const char * broken_wav, const char * fixed_w64) ; + +int +main (int argc, char *argv []) +{ + if (argc != 3) + usage_exit (program_name (argv [0])) ; + + salvage_file (argv [1], argv [2]) ; + + return 0 ; +} /* main */ + +/*============================================================================== +*/ + +static void lseek_or_die (int fd, sf_off_t offset, int whence) ; +static sf_off_t get_file_length (int fd, const char * name) ; +static sf_count_t find_data_offset (int fd, int format) ; +static void copy_data (int fd, SNDFILE * sndfile, int readsize) ; + + +static void +usage_exit (const char *progname) +{ printf ("Usage :\n\n %s \n\n", progname) ; + puts ("Salvages the audio data from WAV files which are more than 4G in length.\n") ; + printf ("Using %s.\n\n", sf_version_string ()) ; + exit (1) ; +} /* usage_exit */ + +static void +salvage_file (const char * broken_wav, const char * fixed_w64) +{ SNDFILE * sndfile ; + SF_INFO sfinfo ; + sf_count_t broken_len, data_offset ; + int fd, read_size ; + + if (strcmp (broken_wav, fixed_w64) == 0) + { printf ("Error : Input and output files must be different.\n\n") ; + exit (1) ; + } ; + + if ((fd = open (broken_wav, O_RDONLY)) < 0) + { printf ("Error : Not able to open file '%s' : %s\n", broken_wav, strerror (errno)) ; + exit (1) ; + } ; + + broken_len = get_file_length (fd, broken_wav) ; + if (broken_len <= 0xffffffff) + printf ("File is not greater than 4Gig but salvaging anyway.\n") ; + + /* Grab the format info from the broken file. */ + memset (&sfinfo, 0, sizeof (sfinfo)) ; + if ((sndfile = sf_open (broken_wav, SFM_READ, &sfinfo)) == NULL) + { printf ("sf_open ('%s') failed : %s\n", broken_wav, sf_strerror (NULL)) ; + exit (1) ; + } ; + sf_close (sndfile) ; + + data_offset = find_data_offset (fd, sfinfo.format & SF_FORMAT_TYPEMASK) ; + + printf ("Offset to audio data : %" PRId64 "\n", data_offset) ; + + switch (sfinfo.format & SF_FORMAT_TYPEMASK) + { case SF_FORMAT_WAV : + case SF_FORMAT_WAVEX : + sfinfo.format = SF_FORMAT_W64 | (sfinfo.format & SF_FORMAT_SUBMASK) ; + break ; + + default : + printf ("Don't currently support this file type.\n") ; + exit (1) ; + } ; + + switch (sfinfo.format & SF_FORMAT_SUBMASK) + { case SF_FORMAT_PCM_U8 : + case SF_FORMAT_PCM_S8 : + read_size = 1 ; + break ; + + case SF_FORMAT_PCM_16 : + read_size = 2 ; + break ; + + case SF_FORMAT_PCM_24 : + read_size = 3 ; + break ; + + case SF_FORMAT_PCM_32 : + case SF_FORMAT_FLOAT : + read_size = 4 ; + break ; + + case SF_FORMAT_DOUBLE : + read_size = 8 ; + break ; + + default : + printf ("Sorry, don't currently support this file encoding type.\n") ; + exit (1) ; + } ; + + read_size *= sfinfo.channels ; + + if ((sndfile = sf_open (fixed_w64, SFM_WRITE, &sfinfo)) == NULL) + { printf ("sf_open ('%s') failed : %s\n", fixed_w64, sf_strerror (NULL)) ; + exit (1) ; + } ; + + lseek_or_die (fd, data_offset, SEEK_SET) ; + + copy_data (fd, sndfile, read_size) ; + + sf_close (sndfile) ; + + puts ("Done!") ; +} /* salvage_file */ + +/*------------------------------------------------------------------------------ +*/ + +static void +lseek_or_die (int fd, sf_off_t offset, int whence) +{ +#ifndef _WIN32 + if (lseek (fd, offset, whence) < 0) +#else + if (_lseeki64 (fd, offset, whence) < 0) +#endif + { printf ("lseek failed : %s\n", strerror (errno)) ; + exit (1) ; + } ; + + return ; +} /* lseek_or_die */ + + +static sf_off_t +get_file_length (int fd, const char * name) +{ +#ifndef _WIN32 + struct stat sbuf ; +#else + struct _stat64 sbuf ; +#endif + + if (sizeof (sbuf.st_size) != 8) + { puts ("Error : sizeof (sbuf.st_size) != 8. Was program compiled with\n" + " 64 bit file offsets?\n") ; + exit (1) ; + } ; + +#ifndef _WIN32 + if (fstat (fd, &sbuf) != 0) +#else + if (_fstat64 (fd, &sbuf) != 0) +#endif + { printf ("Error : fstat ('%s') failed : %s\n", name, strerror (errno)) ; + exit (1) ; + } ; + + return sbuf.st_size ; +} /* get_file_length */ + +static sf_count_t +find_data_offset (int fd, int format) +{ char buffer [8192], *cptr ; + const char * target = "XXXX" ; + sf_count_t offset = -1, extra ; + int rlen, slen ; + + switch (format) + { case SF_FORMAT_WAV : + case SF_FORMAT_WAVEX : + target = "data" ; + extra = 8 ; + break ; + + case SF_FORMAT_AIFF : + target = "SSND" ; + extra = 16 ; + break ; + + default : + puts ("Error : Sorry, don't handle this input file format.\n") ; + exit (1) ; + } ; + + slen = (int) strlen (target) ; + + lseek_or_die (fd, 0, SEEK_SET) ; + + printf ("Searching for '%s' maker.\n", target) ; + + if ((rlen = read (fd, buffer, sizeof (buffer))) < 0) + { printf ("Error : failed read : %s\n", strerror (errno)) ; + exit (1) ; + } ; + + cptr = memchr (buffer, target [0], rlen - slen) ; + if (cptr && memcmp (cptr, target, slen) == 0) + offset = cptr - buffer ; + else + { printf ("Error : Could not find data offset.\n") ; + exit (1) ; + } ; + + return offset + extra ; +} /* find_data_offset */ + +static void +copy_data (int fd, SNDFILE * sndfile, int readsize) +{ static char * buffer ; + sf_count_t readlen, count ; + int bufferlen, done = 0 ; + + bufferlen = readsize * 1024 ; + buffer = malloc (bufferlen) ; + + while (NOT (done) && (readlen = read (fd, buffer, bufferlen)) >= 0) + { if (readlen < bufferlen) + { readlen -= readlen % readsize ; + done = 1 ; + } ; + + if ((count = sf_write_raw (sndfile, buffer, readlen)) != readlen) + { printf ("Error : sf_write_raw returned %" PRId64 " : %s\n", count, sf_strerror (sndfile)) ; + return ; + } ; + } ; + + free (buffer) ; + + return ; +} /* copy_data */ + diff --git a/extern/libsndfile-modified/programs/test-sndfile-metadata-set.py b/extern/libsndfile-modified/programs/test-sndfile-metadata-set.py new file mode 100755 index 000000000..0006936ce --- /dev/null +++ b/extern/libsndfile-modified/programs/test-sndfile-metadata-set.py @@ -0,0 +1,198 @@ +#!/usr/bin/env python + +# Copyright (C) 2008-2016 Erik de Castro Lopo +# +# All rights reserved. +# +# 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 author nor the names of any 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 COPYRIGHT OWNER 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. + +# Simple test script for the sndfile-metadata-set program. + +from __future__ import print_function + +try: + # py2 + import commands +except ImportError: + # py3 + import subprocess as commands + +import os, sys +import time, datetime + +class Programs: + def __init__ (self, needs_exe): + if needs_exe: + extension = ".exe" + else: + extension = "" + self.meta_set_prog = "./sndfile-metadata-set" + extension + self.meta_get_prog = "./sndfile-metadata-get" + extension + self.make_sine_prog = "../examples/make_sine" + extension + + def _run_command (self, should_fail, cmd): + status, output = commands.getstatusoutput (cmd) + if should_fail and not status: + print("\n\nError : command '%s' should have failed." % cmd) + print(output) + print() + sys.exit (1) + if not should_fail and status: + print("\n\nError : command '%s' should not have failed." % cmd) + print(output) + print() + sys.exit (1) + return output + + def meta_set (self, should_fail, args): + return self._run_command (should_fail, self.meta_set_prog + " " + args) + + def meta_get (self, should_fail, args): + return self._run_command (should_fail, self.meta_get_prog + " " + args) + + def make_sine (self): + return os.system (self.make_sine_prog) + + def check_executables (self): + for name in [ self.meta_set_prog, self.meta_get_prog, self.make_sine_prog ]: + if not (os.path.isfile (name)): + print("\n\nError : Can't find executable '%s'. Have you run make?" % name) + sys.exit (1) + + +def print_test_name (name): + print(" %-30s :" % name, end="") + +def assert_info (programs, filename, arg, value): + output = programs.meta_get (False, "%s %s" % (arg, filename)) + if output.find (value) < 0: + print("\n\nError : not able to find '%s'." % value) + print(output) + sys.exit (1) + return + + +def test_empty_fail (programs): + print_test_name ("Empty fail test") + output = programs.meta_set (True, "--bext-description Alpha sine.wav") + print("ok") + +def test_copy (programs): + print_test_name ("Copy test") + output = programs.meta_set (False, "--bext-description \"First Try\" sine.wav output.wav") + assert_info (programs, "output.wav", "--bext-description", "First Try") + print("ok") + +def test_update (programs, tests): + print_test_name ("Update test") + for arg, value in tests: + output = programs.meta_set (False, "%s \"%s\" output.wav" % (arg, value)) + assert_info (programs, "output.wav", arg, value) + print("ok") + +def test_post_mod (programs, tests): + print_test_name ("Post mod test") + for arg, value in tests: + assert_info (programs, "output.wav", arg, value) + print("ok") + +def test_auto_date (programs): + print_test_name ("Auto date test") + output = programs.meta_set (False, "--bext-auto-time-date sine.wav date-time.wav") + target = datetime.date.today ().__str__ () + assert_info (programs, "date-time.wav", "--bext-orig-date", target) + print("ok") + + +#------------------------------------------------------------------------------- + +def test_coding_history (programs): + print_test_name ("Coding history test") + output = programs.meta_set (False, "--bext-coding-hist \"alpha beta\" output.wav") + output = programs.meta_get (False, "--bext-coding-hist output.wav") + print("ok") + +#------------------------------------------------------------------------------- + +def test_rewrite (programs): + print_test_name ("Rewrite test") + output = programs.meta_set (False, "--bext-originator \"Really, really long string\" output.wav") + output = programs.meta_set (False, "--bext-originator \"Short\" output.wav") + output = programs.meta_get (False, "--bext-originator output.wav") + if output.find ("really long") > 0: + print("\n\nError : output '%s' should not contain 'really long'." % output) + sys.exit (1) + print("ok") + +#=============================================================================== + +test_dir = "programs" + +print("\nTesting WAV metadata manipulation:") + +if os.path.isdir (test_dir): + os.chdir (test_dir) + +if len (sys.argv) >= 1 and sys.argv [1].endswith ("mingw32"): + needs_exe = True +else: + needs_exe = False + +programs = Programs (needs_exe) + +programs.check_executables () + +programs.make_sine () +if not os.path.isfile ("sine.wav"): + print("\n\nError : Can't file file 'sine.wav'.") + sys.exit (1) + +test_empty_fail (programs) +test_copy (programs) + +tests = [ + ("--bext-description", "Alpha"), ("--bext-originator", "Beta"), ("--bext-orig-ref", "Charlie"), + ("--bext-umid", "Delta"), ("--bext-orig-date", "2001-10-01"), ("--bext-orig-time", "01:02:03"), + ("--str-title", "Echo"), ("--str-artist", "Fox trot") + ] + +test_auto_date (programs) +test_update (programs, tests) +test_post_mod (programs, tests) + +test_update (programs, [ ("--str-artist", "Fox") ]) + +# This never worked. +# test_coding_history () + +test_rewrite (programs) + + +print() + +sys.exit (0) + diff --git a/extern/libsndfile-modified/regtest/Readme.txt b/extern/libsndfile-modified/regtest/Readme.txt new file mode 100644 index 000000000..bc038d642 --- /dev/null +++ b/extern/libsndfile-modified/regtest/Readme.txt @@ -0,0 +1,108 @@ +sndfile-regtest +=============== + +The 'sndfile-regtest' program is a regression test-suite for libsndile. + +This program is intended to allow anyone who has an interest in the +reliability and correctness of libsndfile to do their own regression +testing. From the point of view of the libsndfile developers, this +program now allows for distributed regression testing of libsndfile +which will make libsndfile better. + + +How Does it Work +---------------- +Anyone who wishes to take part in the distributed regression testing of +libsndfile can download the regression test program and install it. + +Once installed the user can start collecting files and adding them to +their own personal database. Then, as new versions of libsndfile come +out, the user should test the new library version against their database +of files (instructions below). + +Any files which were successfully added to the database in the past but +now fail the check with the new library version represent a regression. +The user should then contact the libsndfile developers so that a copy +of the test file can be made available to the developers. + + +Requirements +------------ +The regression test program uses sqlite3 as the database engine. On +Debian, the required packages are : + + sqlite3 + libsqlite3-0 + libsqlite3-dev + +but similar packages should be available on any other Linux style +system. + +The regression test currently only compiles under Unix-like systems. +At some time in the future the regression test will distributed along +with the libsndfile source code distribution. + + +Organization of Files +--------------------- +The regession test program keeps its database file in the directory it +is run from. In addition, the database only contains information about +the files, not the files themselves. + +This means that database file should probably be kept in the same +directory (or a directory above) the test files. + + +Setting it Up for the First Time +-------------------------------- +The sndfile-regtest program should be on your PATH. You can then cd into +the directory where you intend to keep you test files and +run the command: + + sndfile-regtest --create-db + +which creates a file named '.sndfile-regtest.db' in the current directory. + +Files can then be added to the database using the command: + + sndfile-regtest --add-file file1.wav + +The --add-file option allows more than one file to be added at a time +using: + + sndfile-regtest --add-file file1.wav file2.aif ..... + + +Checking Files +-------------- +One or more files that have already been added to the database can be +checked using: + + sndfile-regtest --check-file file1.wav file2.aif ..... + +It is also possible to check all files in the database using: + + sndfile-regtest --check-all + + +Running a Regression Test +------------------------- +Once you have a collection of files and a database it is possible to test +new versions of libsndfile before you install them. If for instance you +have just compiled a new version of libsndfile in the directory +/usr/src/libsndfile-X.Y.Z, then you can use an existing sndfile-regtest +binary with the new libsndfile using something like: + + LD_PRELOAD=/usr/src/libsndfile-X.Y.Z/src/.libs/libsndfile.so.X.Y.Z \ + sndfile-regtest --check-all + + +Reporting Regressions +--------------------- +Any user who finds a file which was added to the regression database with +an earlier version of libsndfile and then fails the check with a later +version of the library should contact the author (erikd at mega dash nerd +dot com). If possible place the file on a web server and email the author +a link to it. + + diff --git a/extern/libsndfile-modified/regtest/checksum.c b/extern/libsndfile-modified/regtest/checksum.c new file mode 100644 index 000000000..5714144fd --- /dev/null +++ b/extern/libsndfile-modified/regtest/checksum.c @@ -0,0 +1,117 @@ +/* +** Copyright (C) 2005-2011 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* +** A simple checksum for short, int and float data. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include + +#include + +#include "regtest.h" + +#define BIG_PRIME 999983 + +#define ARRAY_LEN(x) ((int) (sizeof (x)) / (sizeof ((x) [0]))) + +static int short_checksum (SNDFILE * file, int start) ; +static int int_checksum (SNDFILE * file, int start) ; +static int float_checksum (SNDFILE * file, int start) ; + +int +calc_checksum (SNDFILE * file, const SF_INFO * info) +{ int start ; + + /* Seed the checksum with data from the SF_INFO struct. */ + start = info->samplerate ; + start = start * BIG_PRIME + info->channels ; + start = start * BIG_PRIME + info->format ; + + switch (info->format & SF_FORMAT_SUBMASK) + { case SF_FORMAT_FLOAT : + case SF_FORMAT_DOUBLE : + return float_checksum (file, start) ; + + case SF_FORMAT_PCM_24 : + case SF_FORMAT_PCM_32 : + return int_checksum (file, start) ; + + default : + return short_checksum (file, start) ; + } ; + + return 0 ; +} /* calc_checksum */ + +/*------------------------------------------------------------------------------ +*/ + +static union +{ short s [1 << 16] ; + int i [1 << 15] ; + float f [1 << 15] ; +} data ; + +static int +short_checksum (SNDFILE * file, int start) +{ int k, count ; + + do + { count = (int) sf_read_short (file, data.s, ARRAY_LEN (data.s)) ; + for (k = 0 ; k < count ; k++) + start = start * BIG_PRIME + data.s [k] ; + } + while (count > 0) ; + + return start ; +} /* short_checksum */ + +static int +int_checksum (SNDFILE * file, int start) +{ int k, count ; + + do + { count = (int) sf_read_int (file, data.i, ARRAY_LEN (data.i)) ; + for (k = 0 ; k < count ; k++) + start = start * BIG_PRIME + data.i [k] ; + } + while (count > 0) ; + + return start ; +} /* int_checksum */ + +static int +float_checksum (SNDFILE * file, int start) +{ int k, count ; + + do + { count = (int) sf_read_float (file, data.f, ARRAY_LEN (data.f)) ; + for (k = 0 ; k < count ; k++) + start = start * BIG_PRIME + lrintf (2147483648.0f * data.f [k]) ; + } + while (count > 0) ; + + return start ; +} /* float_checksum */ + diff --git a/extern/libsndfile-modified/regtest/database.c b/extern/libsndfile-modified/regtest/database.c new file mode 100644 index 000000000..1f4c8d7bf --- /dev/null +++ b/extern/libsndfile-modified/regtest/database.c @@ -0,0 +1,542 @@ +/* +** Copyright (C) 2005-2011 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "config.h" + +#include +#include +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif +#include +#include +#ifdef HAVE_DIRECT_H +#include +#endif +#include + +#include + +#include "regtest.h" + +#if HAVE_SQLITE3 + +#include +#include + +typedef struct +{ sqlite3 *sql ; + + int count ; + int ekey_max ; + + /* Filename and pathname for file. */ + char filename [256] ; + char pathname [512] ; + + /* Storage for createding SQL commands. Must be larger than logbuf below. */ + char cmdbuf [1 << 15] ; + + /* Storage for log buffer retrieved from SNDFILE* .*/ + char logbuf [1 << 14] ; + +} REGTEST_DB ; + +/* In checksum.c */ +int calc_checksum (SNDFILE * file, const SF_INFO * info) ; + +static void get_filename_pathname (REGTEST_DB * db, const char *filepath) ; +static void single_quote_replace (char * buf) ; + +static int get_ekey_from_filename (REGTEST_DB * db, const char *filepath) ; +static int get_filename_pathname_by_ekey (REGTEST_DB * db, int ekey) ; +static int check_file_by_ekey (REGTEST_DB * db, int ekey) ; + +static int count_callback (REGTEST_DB * db, int argc, char **argv, char **colname) ; +static int ekey_max_callback (REGTEST_DB * db, int argc, char **argv, char **colname) ; +static int callback (void *unused, int argc, char **argv, char **colname) ; +static const char *db_basename (const char *fname); + +/* Windows accepts both '\\' and '/' in paths */ +#ifdef _WIN32 + #define IS_SLASH(c) ((c) == '\\' || (c) == '/') + #define HAS_DRIVELETTER(path) (isalpha ((int)(path[0])) && path[1] == ':' && IS_SLASH(path[2])) +#else + #define IS_SLASH(c) ((c) == '/') + #define HAS_DRIVELETTER(path) 0 +#endif + +REG_DB * +db_open (const char * db_name) +{ REGTEST_DB * db ; + int err ; + + if ((db = malloc (sizeof (REGTEST_DB))) == NULL) + { perror ("malloc") ; + exit (1) ; + } ; + + if ((err = sqlite3_open (db_name, &(db->sql))) != 0) + { printf ("Can't open database: %s\n", sqlite3_errmsg (db->sql)) ; + sqlite3_close (db->sql) ; + free (db) ; + exit (1) ; + } ; + + return (REG_DB *) db ; +} /* db_open */ + +int +db_create (const char * db_name) +{ REGTEST_DB * db ; + const char *cmd ; + char * errmsg = NULL ; + int err ; + + db = (REGTEST_DB *) db_open (db_name) ; + + cmd = "create table sndfile (ekey INTEGER PRIMARY KEY," + "fname VARCHAR(1)," + "fpath VARCHAR(1)," + "srate INTEGER," + "frames VARCHAR(1)," + "channels INTEGER," + "format VARCHAR(1)," + "checksum VARCHAR(1)," + "logbuf VARCHAR(1)" + ");" ; + + err = sqlite3_exec (db->sql, cmd, callback, 0, &errmsg) ; + if (err != SQLITE_OK) + printf ("Line %d : SQL error: %s\n", __LINE__, errmsg) ; + + sqlite3_close (db->sql) ; + free (db) ; + + return 0 ; +} /* db_create */ + +int +db_close (REG_DB * db_handle) +{ REGTEST_DB * db ; + + db = (REGTEST_DB *) db_handle ; + + sqlite3_close (db->sql) ; + free (db) ; + + return 0 ; +} /* db_close */ + +/*============================================================================== +*/ + +int +db_file_exists (REG_DB * db_handle, const char * filename) +{ REGTEST_DB * db ; + char * errmsg ; + int err ; + + db = (REGTEST_DB *) db_handle ; + + filename = db_basename (filename); + + snprintf (db->cmdbuf, sizeof (db->cmdbuf), "select fname from sndfile where fname='%s'", filename) ; + + db->count = 0 ; + err = sqlite3_exec (db->sql, db->cmdbuf, (sqlite3_callback) count_callback, db, &errmsg) ; + if (err == 0 && db->count == 1) + return 1 ; + + return 0 ; +} /* db_file_exists */ + +int +db_add_file (REG_DB * db_handle, const char * filepath) +{ REGTEST_DB * db ; + SNDFILE * sndfile ; + SF_INFO info ; + char * errmsg ; + int err, checksum ; + + db = (REGTEST_DB *) db_handle ; + + get_filename_pathname (db, filepath) ; + + if (db_file_exists (db_handle, filepath)) + { printf (" %s : already in database\n", db->filename) ; + return 0 ; + } ; + + memset (&info, 0, sizeof (info)) ; + sndfile = sf_open (db->pathname, SFM_READ, &info) ; + sf_command (sndfile, SFC_GET_LOG_INFO, db->logbuf, sizeof (db->logbuf)) ; + checksum = (sndfile == NULL) ? 0 : calc_checksum (sndfile, &info) ; + sf_close (sndfile) ; + + if (sndfile == NULL) + { printf (" %s : could not open : %s, filepath: '%s'\n", db->filename, sf_strerror (NULL), filepath) ; + puts (db->logbuf) ; + return 1 ; + } ; + + single_quote_replace (db->logbuf) ; + + snprintf (db->cmdbuf, sizeof (db->cmdbuf), "insert into sndfile " + "(fname, fpath, srate, frames, channels, format, checksum, logbuf) values" + "('%s','%s',%d,'%ld', %d, '0x%08x', '0x%08x', '%s');", + db->filename, db->pathname, info.samplerate, (long) info.frames, info.channels, info.format, checksum, db->logbuf) ; + + if (strlen (db->cmdbuf) >= sizeof (db->cmdbuf) - 1) + { printf ("strlen (db->cmdbuf) too long.\n") ; + exit (1) ; + } ; + + err = sqlite3_exec (db->sql, db->cmdbuf, callback, 0, &errmsg) ; + if (err != SQLITE_OK) + { printf ("Line %d : SQL error: %s\n", __LINE__, errmsg) ; + puts (db->cmdbuf) ; + } ; + + return 0 ; +} /* db_add_file */ + +int +db_check_file (REG_DB * db_handle, const char * filepath) +{ REGTEST_DB * db ; + int ekey ; + + if (db_file_exists (db_handle, filepath) == 0) + { printf ("\nFile not in database.\n\n") ; + exit (0) ; + } ; + + db = (REGTEST_DB *) db_handle ; + + ekey = get_ekey_from_filename (db, filepath) ; + + return check_file_by_ekey (db, ekey) ; +} /* db_check_file */ + +/*============================================================================== +*/ + +int +db_check_all (REG_DB * db_handle) +{ REGTEST_DB * db ; + char * errmsg ; + int err, ekey ; + + db = (REGTEST_DB *) db_handle ; + + db->ekey_max = 0 ; + + snprintf (db->cmdbuf, sizeof (db->cmdbuf), "select ekey from sndfile") ; + + err = sqlite3_exec (db->sql, db->cmdbuf, (sqlite3_callback) ekey_max_callback, db, &errmsg) ; + if (err != SQLITE_OK) + { printf ("Line %d : SQL error: %s\n", __LINE__, errmsg) ; + puts (db->cmdbuf) ; + } ; + + for (ekey = 1 ; ekey <= db->ekey_max ; ekey++) + if (get_filename_pathname_by_ekey (db, ekey) != 0) + check_file_by_ekey (db, ekey) ; + + return 0 ; +} /* db_check_all */ + + +int +db_list_all (REG_DB * db_handle) +{ + printf ("%s : %p\n", __func__, (void *) db_handle) ; + return 0 ; +} /* db_list_all */ + +int +db_del_entry (REG_DB * db_handle, const char * entry) +{ + printf ("%s : %p %s\n", __func__, (void *) db_handle, entry) ; + return 0 ; +} /* db_del_entry */ + +/*============================================================================== +*/ + +static int +get_ekey_from_filename (REGTEST_DB * db, const char *filepath) +{ char * errmsg, **result ; + int err, ekey = 0, rows, cols ; + + get_filename_pathname (db, filepath) ; + + snprintf (db->cmdbuf, sizeof (db->cmdbuf), "select ekey from sndfile where fname='%s'", db->filename) ; + + err = sqlite3_get_table (db->sql, db->cmdbuf, &result, &rows, &cols, &errmsg) ; + if (err != SQLITE_OK) + { printf ("Line %d : SQL error: %s\n", __LINE__, errmsg) ; + puts (db->cmdbuf) ; + } ; + + if (cols != 1 || rows != 1) + { printf ("Bad juju!! rows = %d cols = %d\n", rows, cols) ; + exit (1) ; + } ; + + ekey = strtol (result [1], NULL, 10) ; + + sqlite3_free_table (result) ; + + return ekey ; +} /* get_ekey_from_filename */ + +static int +get_filename_pathname_by_ekey (REGTEST_DB * db, int ekey) +{ char *errmsg, **result ; + int err, rows, cols ; + + snprintf (db->cmdbuf, sizeof (db->cmdbuf), "select fname,fpath from sndfile where ekey='%d'", ekey) ; + + err = sqlite3_get_table (db->sql, db->cmdbuf, &result, &rows, &cols, &errmsg) ; + if (err != SQLITE_OK) + { printf ("Line %d : SQL error: %s\n", __LINE__, errmsg) ; + puts (db->cmdbuf) ; + return 0 ; + } ; + + if (cols != 2 || rows != 1) + { printf ("\nError (%s %d) : rows = %d cols = %d\n", __func__, __LINE__, rows, cols) ; + exit (1) ; + } ; + + snprintf (db->filename, sizeof (db->filename), "%s", result [2]) ; + snprintf (db->pathname, sizeof (db->pathname), "%s", result [3]) ; + + sqlite3_free_table (result) ; + + return 1 ; +} /* get_filename_pathname_by_ekey */ + +static int +check_file_by_ekey (REGTEST_DB * db, int ekey) +{ SNDFILE * sndfile ; + SF_INFO info ; + char * errmsg, **result ; + int err, k, rows, cols, checksum ; + + printf (" %s : ", db->filename) ; + fflush (stdout) ; + + memset (&info, 0, sizeof (info)) ; + sndfile = sf_open (db->pathname, SFM_READ, &info) ; + sf_command (sndfile, SFC_GET_LOG_INFO, db->logbuf, sizeof (db->logbuf)) ; + checksum = (sndfile == NULL) ? 0 : calc_checksum (sndfile, &info) ; + sf_close (sndfile) ; + + if (sndfile == NULL) + { printf ("\n\nError : Could not open '%s' : %s\n", db->pathname, sf_strerror (NULL)) ; + puts (db->logbuf) ; + exit (1) ; + } ; + + single_quote_replace (db->logbuf) ; + + snprintf (db->cmdbuf, sizeof (db->cmdbuf), "select fname,srate,frames,channels,format," + "checksum,logbuf from sndfile where ekey='%d'", ekey) ; + + err = sqlite3_get_table (db->sql, db->cmdbuf, &result, &rows, &cols, &errmsg) ; + if (err != SQLITE_OK) + { printf ("Line %d : SQL error: %s\n", __LINE__, errmsg) ; + puts (db->cmdbuf) ; + } ; + + for (k = 0 ; k < cols ; k++) + { if (strcmp (result [k], "fname") == 0) + { if (strcmp (result [k + cols], db->filename) == 0) + continue ; + printf ("\n\nError : fname doesn't match : %s != %s\n", result [k + cols], db->filename) ; + } ; + + if (strcmp (result [k], "srate") == 0) + { if (strtol (result [k + cols], NULL, 10) == info.samplerate) + continue ; + printf ("\n\nError : srate doesn't match : %s == %d\n", result [k + cols], info.samplerate) ; + } ; + + if (strcmp (result [k], "frames") == 0) + { if (strtoll (result [k + cols], NULL, 10) == info.frames) + continue ; + printf ("\n\nError : frames doesn't match : %s == %ld\n", result [k + cols], (long) info.frames) ; + } ; + + if (strcmp (result [k], "channels") == 0) + { if (strtol (result [k + cols], NULL, 10) == info.channels) + continue ; + printf ("\n\nError : channels doesn't match : %s == %d\n", result [k + cols], info.channels) ; + } ; + + if (strcmp (result [k], "format") == 0) + { if (strtol (result [k + cols], NULL, 16) == info.format) + continue ; + printf ("\n\nError : format doesn't match : %s == 0x%08x\n", result [k + cols], info.format) ; + } ; + + if (strcmp (result [k], "checksum") == 0) + { int db_val = (int) strtoll (result [k + cols], NULL, 16) ; + + if (db_val == checksum) + continue ; + printf ("\n\nError : checksum doesn't match : 0x%08x == 0x%08x\n", db_val, checksum) ; + } ; + + if (strcmp (result [k], "logbuf") == 0) + continue ; + + printf ("\nHere is the old logubuffer :\n\n%s\n\nand the new :\n\n%s\n\n", result [2 * cols - 1], db->logbuf) ; + exit (1) ; + } ; + + sqlite3_free_table (result) ; + + puts ("ok") ; + + return 0 ; +} /* check_file_by_ekey */ + +/*============================================================================== +*/ + +static void +get_filename_pathname (REGTEST_DB * db, const char *filepath) +{ + const char * basename = db_basename (filepath) ; + size_t slen ; + + /* Test for a relative path + */ + if (!IS_SLASH(filepath [0]) && !HAS_DRIVELETTER(filepath)) + { memset (db->pathname, 0, sizeof (db->pathname)) ; + if (getcwd (db->pathname, sizeof (db->pathname)) == NULL) + { perror ("\ngetcwd failed") ; + exit (1) ; + } ; + + slen = strlen (db->pathname) ; + /* a '/' is fine for Windows too */ + snprintf (db->pathname + slen, sizeof (db->pathname) - slen, "/%s", filepath) ; + } + else + snprintf (db->pathname, sizeof (db->pathname), "%s", filepath) ; + + snprintf (db->filename, sizeof (db->filename), "%s", basename) ; + + basename = db_basename (db->pathname) ; + if (basename == db->pathname) + { printf ("\nError : bad pathname %s\n", filepath) ; + exit (1) ; + } ; +} /* get filename_pathname */ + +static void +single_quote_replace (char * buf) +{ while ((buf = strchr (buf, '\'')) != 0) + buf [0] = '"' ; +} /* single_quote_replace */ + +static int +count_callback (REGTEST_DB * db, int argc, char **argv, char **colname) +{ db->count ++ ; + + (void) argc ; + (void) argv ; + (void) colname ; + return 0 ; +} /* count_callback */ + +static int +ekey_max_callback (REGTEST_DB * db, int argc, char **argv, char **unused) +{ int ekey ; + + (void) argc ; + (void) unused ; + + ekey = strtol (argv [0], NULL, 10) ; + if (ekey > db->ekey_max) + db->ekey_max = ekey ; + + return 0 ; +} /* ekey_max_callback */ + +static int +callback (void *unused, int argc, char **argv, char **colname) +{ int k ; + + (void) unused ; + + for (k = 0 ; k < argc ; k++) + printf ("%s = %s\n", colname [k], argv [k] ? argv [k] : "NULL") ; + + printf ("\n") ; + + return 0 ; +} /* callback */ + +/* + * Win32: Strip drive-letter and directory from a filename. + * non-Win32: Strip directory from a filename. + */ +static const char *db_basename (const char *fname) +{ + const char *base = fname; + +#if !defined(_WIN32) + const char *slash = strrchr (base, '/'); + + if (slash) + base = slash + 1 ; +#else + if (fname[0] && fname[1] == ':') { + fname += 2; + base = fname; + } + while (*fname) { + if (IS_SLASH(*fname)) + base = fname + 1; + fname++; + } +#endif + return base ; +} + +#else + +int dummy (void) ; + +int +dummy (void) +{ /* + ** Empty dummy fnction so tha compiler doesn't winge about an + ** empty file. + */ + return 0 ; +} /* dummy */ + +#endif diff --git a/extern/libsndfile-modified/regtest/regtest.h b/extern/libsndfile-modified/regtest/regtest.h new file mode 100644 index 000000000..567d97be2 --- /dev/null +++ b/extern/libsndfile-modified/regtest/regtest.h @@ -0,0 +1,38 @@ +/* +** Copyright (C) 2005-2011 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +typedef struct REG_DB_tag REG_DB ; + +/* In database.c */ +REG_DB * db_open (const char * db_name) ; + +int db_create (const char * dbname) ; + +int db_close (REG_DB * db_handle) ; + +int db_file_exists (REG_DB * db_handle, const char * filename) ; +int db_add_file (REG_DB * db_handle, const char * filename) ; +int db_check_file (REG_DB * db_handle, const char * filename) ; + +int db_list_all (REG_DB * db_handle) ; +int db_check_all (REG_DB * db_handle) ; +int db_del_entry (REG_DB * db_handle, const char * entry) ; + +/* In checksum.c */ +int calc_checksum (SNDFILE * file, const SF_INFO * info) ; + diff --git a/extern/libsndfile-modified/regtest/sndfile-regtest.c b/extern/libsndfile-modified/regtest/sndfile-regtest.c new file mode 100644 index 000000000..a28caa2d8 --- /dev/null +++ b/extern/libsndfile-modified/regtest/sndfile-regtest.c @@ -0,0 +1,121 @@ +/* +** Copyright (C) 2005-2011 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "config.h" + +#include +#include +#include + +#include + +#if HAVE_SQLITE3 + +#include "regtest.h" + +enum +{ OPT_ADD_FILE = 0x0100, + OPT_CREATE_DB = 0x0200, + OPT_DEL_ENTRY = 0x0400, + OPT_LIST_ALL = 0x0800, + OPT_TEST_ALL = 0x1000, + OPT_VERBOSE = 0x2000 +} ; + +static void print_libsndfile_version (void) ; + +int +main (int argc, char * argv []) +{ const char *db_name = "./.sndfile-regtest.db" ; + REG_DB *reg_db ; + int k, retval ; + + if (argc < 2) + { printf ("\nUsage message goes here.\n\n") ; + exit (0) ; + } ; + + if (argc == 2 && strcmp (argv [1], "--create-db") == 0) + return db_create (db_name) ; + + reg_db = db_open (db_name) ; + + if (argc == 2) + { if (strcmp (argv [1], "--list-all") == 0) + return db_list_all (reg_db) ; + + if (strcmp (argv [1], "--check-all") == 0) + { print_libsndfile_version () ; + retval = db_check_all (reg_db) ; + puts ("\nDone.\n") ; + return retval ; + } ; + } ; + + if (argc == 3 && strcmp (argv [1], "--del-entry") == 0) + { db_del_entry (reg_db, argv [2]) ; + db_close (reg_db) ; + return 0 ; + } ; + + if (strcmp (argv [1], "--check-file") == 0) + { print_libsndfile_version () ; + + for (k = 2 ; k < argc ; k++) + db_check_file (reg_db, argv [k]) ; + db_close (reg_db) ; + return 0 ; + } ; + + if (strcmp (argv [1], "--add-file") == 0) + { print_libsndfile_version () ; + + for (k = 2 ; k < argc ; k++) + db_add_file (reg_db, argv [k]) ; + db_close (reg_db) ; + return 0 ; + } ; + + printf ("\nError : unhandled command line args :") ; + for (k = 1 ; k < argc ; k++) + printf (" %s", argv [k]) ; + puts ("\n") ; + + return 1 ; +} /* main */ + +static void +print_libsndfile_version (void) +{ char version [64] ; + + sf_command (NULL, SFC_GET_LIB_VERSION, version, sizeof (version)) ; + printf ("\nsndfile-regtest : using %s\n\n", version) ; +} /* print_lib_version */ + +#else + +int +main (void) +{ + puts ("\nThis program was not compiled with libsqlite3 and hence doesn't work.\n") ; + + return 0 ; +} /* main */ + +#endif + diff --git a/extern/libsndfile-modified/sndfile.pc.in b/extern/libsndfile-modified/sndfile.pc.in new file mode 100644 index 000000000..6b8845373 --- /dev/null +++ b/extern/libsndfile-modified/sndfile.pc.in @@ -0,0 +1,13 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: sndfile +Description: A library for reading and writing audio files +Requires: +Requires.private: @EXTERNAL_XIPH_REQUIRE@ @EXTERNAL_MPEG_REQUIRE@ +Version: @VERSION@ +Libs: -L${libdir} -lsndfile +Libs.private: @EXTERNAL_MPEG_LIBS@ +Cflags: -I${includedir} diff --git a/extern/libsndfile-modified/src/ALAC/ALACAudioTypes.h b/extern/libsndfile-modified/src/ALAC/ALACAudioTypes.h new file mode 100644 index 000000000..52d3f44a0 --- /dev/null +++ b/extern/libsndfile-modified/src/ALAC/ALACAudioTypes.h @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2011 Apple Inc. All rights reserved. + * + * @APPLE_APACHE_LICENSE_HEADER_START@ + * + * Licensed under the Apache License, Version 2.0 (the "License") ; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @APPLE_APACHE_LICENSE_HEADER_END@ + */ + +/* + File: ALACAudioTypes.h +*/ + +#ifndef ALACAUDIOTYPES_H +#define ALACAUDIOTYPES_H + +/* Force these Mac OS specific things to zero. */ +#define PRAGMA_STRUCT_ALIGN 0 +#define PRAGMA_STRUCT_PACKPUSH 0 +#define PRAGMA_STRUCT_PACK 0 +#define PRAGMA_ONCE 0 +#define PRAGMA_MARK 0 + + +#if PRAGMA_ONCE +#pragma once +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include "sfendian.h" + +#if CPU_IS_BIG_ENDIAN == 1 +#define TARGET_RT_BIG_ENDIAN 1 +#else +#define TARGET_RT_BIG_ENDIAN 0 +#endif + +#define kChannelAtomSize 12 + +enum +{ + kALAC_UnimplementedError = -4, + kALAC_FileNotFoundError = -43, + kALAC_ParamError = -50, + kALAC_MemFullError = -108, + fALAC_FrameLengthError = -666, + + /* Add for libsndfile */ + kALAC_BadBitWidth = -0x100000, + kALAC_IncompatibleVersion = -0x100001, + kALAC_BadSpecificConfigSize = -0x100002, + kALAC_ZeroChannelCount = -0x100003, + kALAC_NumSamplesTooBig = -0x100004, + kALAC_UnsupportedElement = -0x100005, +} ; + +enum +{ + kALACFormatAppleLossless = MAKE_MARKER ('a', 'l', 'a', 'c'), + kALACFormatLinearPCM = MAKE_MARKER ('l', 'p', 'c', 'm') +} ; + +enum +{ + kALACMaxChannels = 8, + kALACMaxEscapeHeaderBytes = 8, + kALACMaxSearches = 16, + kALACMaxCoefs = 16, + kALACDefaultFramesPerPacket = 4096 +} ; + +typedef uint32_t ALACChannelLayoutTag ; + +enum +{ + kALACFormatFlagIsFloat = (1 << 0), // 0x1 + kALACFormatFlagIsBigEndian = (1 << 1), // 0x2 + kALACFormatFlagIsSignedInteger = (1 << 2), // 0x4 + kALACFormatFlagIsPacked = (1 << 3), // 0x8 + kALACFormatFlagIsAlignedHigh = (1 << 4), // 0x10 +} ; + +enum +{ +#if TARGET_RT_BIG_ENDIAN + kALACFormatFlagsNativeEndian = kALACFormatFlagIsBigEndian +#else + kALACFormatFlagsNativeEndian = 0 +#endif +} ; + +// this is required to be an IEEE 64bit float +typedef double alac_float64_t ; + +// These are the Channel Layout Tags used in the Channel Layout Info portion of the ALAC magic cookie +enum +{ kALACChannelLayoutTag_Mono = (100 << 16) | 1, // C + kALACChannelLayoutTag_Stereo = (101 << 16) | 2, // L R + kALACChannelLayoutTag_MPEG_3_0_B = (113 << 16) | 3, // C L R + kALACChannelLayoutTag_MPEG_4_0_B = (116 << 16) | 4, // C L R Cs + kALACChannelLayoutTag_MPEG_5_0_D = (120 << 16) | 5, // C L R Ls Rs + kALACChannelLayoutTag_MPEG_5_1_D = (124 << 16) | 6, // C L R Ls Rs LFE + kALACChannelLayoutTag_AAC_6_1 = (142 << 16) | 7, // C L R Ls Rs Cs LFE + kALACChannelLayoutTag_MPEG_7_1_B = (127 << 16) | 8 // C Lc Rc L R Ls Rs LFE (doc: IS-13818-7 MPEG2-AAC) +} ; + +// ALAC currently only utilizes these channels layouts. There is a one for one correspondance between a +// given number of channels and one of these layout tags +static const ALACChannelLayoutTag ALACChannelLayoutTags [kALACMaxChannels] = +{ + kALACChannelLayoutTag_Mono, // C + kALACChannelLayoutTag_Stereo, // L R + kALACChannelLayoutTag_MPEG_3_0_B, // C L R + kALACChannelLayoutTag_MPEG_4_0_B, // C L R Cs + kALACChannelLayoutTag_MPEG_5_0_D, // C L R Ls Rs + kALACChannelLayoutTag_MPEG_5_1_D, // C L R Ls Rs LFE + kALACChannelLayoutTag_AAC_6_1, // C L R Ls Rs Cs LFE + kALACChannelLayoutTag_MPEG_7_1_B // C Lc Rc L R Ls Rs LFE (doc: IS-13818-7 MPEG2-AAC) +} ; + +// AudioChannelLayout from CoreAudioTypes.h. We never need the AudioChannelDescription so we remove it +struct ALACAudioChannelLayout +{ ALACChannelLayoutTag mChannelLayoutTag ; + uint32_t mChannelBitmap ; + uint32_t mNumberChannelDescriptions ; +} ; +typedef struct ALACAudioChannelLayout ALACAudioChannelLayout ; + +struct AudioFormatDescription +{ + alac_float64_t mSampleRate ; + uint32_t mFormatID ; + uint32_t mFormatFlags ; + uint32_t mBytesPerPacket ; + uint32_t mFramesPerPacket ; + uint32_t mBytesPerFrame ; + uint32_t mChannelsPerFrame ; + uint32_t mBitsPerChannel ; + uint32_t mReserved ; +} ; +typedef struct AudioFormatDescription AudioFormatDescription ; + +/* Lossless Definitions */ + +enum +{ + kALACCodecFormat = MAKE_MARKER ('a', 'l', 'a', 'c'), + kALACVersion = 0, + kALACCompatibleVersion = kALACVersion, + kALACDefaultFrameSize = 4096 +} ; + +// note: this struct is wrapped in an 'alac' atom in the sample description extension area +// note: in QT movies, it will be further wrapped in a 'wave' atom surrounded by 'frma' and 'term' atoms +typedef struct ALACSpecificConfig +{ + uint32_t frameLength ; + uint8_t compatibleVersion ; + uint8_t bitDepth ; // max 32 + uint8_t pb ; // 0 <= pb <= 255 + uint8_t mb ; + uint8_t kb ; + uint8_t numChannels ; + uint16_t maxRun ; + uint32_t maxFrameBytes ; + uint32_t avgBitRate ; + uint32_t sampleRate ; + +} ALACSpecificConfig ; + + +// The AudioChannelLayout atom type is not exposed yet so define it here +enum +{ + AudioChannelLayoutAID = MAKE_MARKER ('c', 'h', 'a', 'n') +} ; + +#if PRAGMA_STRUCT_ALIGN + #pragma options align = reset +#elif PRAGMA_STRUCT_PACKPUSH + #pragma pack (pop) +#elif PRAGMA_STRUCT_PACK + #pragma pack () +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ALACAUDIOTYPES_H */ diff --git a/extern/libsndfile-modified/src/ALAC/ALACBitUtilities.c b/extern/libsndfile-modified/src/ALAC/ALACBitUtilities.c new file mode 100644 index 000000000..d861be4f1 --- /dev/null +++ b/extern/libsndfile-modified/src/ALAC/ALACBitUtilities.c @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2011 Apple Inc. All rights reserved. + * + * @APPLE_APACHE_LICENSE_HEADER_START@ + * + * Licensed under the Apache License, Version 2.0 (the "License") ; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @APPLE_APACHE_LICENSE_HEADER_END@ + */ + +/*============================================================================= + File: ALACBitUtilities.c + + $NoKeywords: $ +=============================================================================*/ + +#include +#include "ALACBitUtilities.h" + +#define PRAGMA_MARK 0 + +// BitBufferInit +// +void BitBufferInit (BitBuffer * bits, uint8_t * buffer, uint32_t byteSize) +{ + bits->cur = buffer ; + bits->end = bits->cur + byteSize ; + bits->bitIndex = 0 ; + bits->byteSize = byteSize ; +} + +// BitBufferRead +// +uint32_t BitBufferRead (BitBuffer * bits, uint8_t numBits) +{ + uint32_t returnBits ; + + //Assert (numBits <= 16) ; + + returnBits = ((uint32_t) bits->cur [0] << 16) | ((uint32_t) bits->cur [1] << 8) | ((uint32_t) bits->cur [2]) ; + returnBits = returnBits << bits->bitIndex ; + returnBits &= 0x00FFFFFF ; + + bits->bitIndex += numBits ; + + returnBits = returnBits >> (24 - numBits) ; + + bits->cur += (bits->bitIndex >> 3) ; + bits->bitIndex &= 7 ; + + //Assert (bits->cur <= bits->end) ; + + return returnBits ; +} + +// BitBufferReadSmall +// +// Reads up to 8 bits +uint8_t BitBufferReadSmall (BitBuffer * bits, uint8_t numBits) +{ + uint16_t returnBits ; + + //Assert (numBits <= 8) ; + + returnBits = (bits->cur [0] << 8) | bits->cur [1] ; + returnBits = returnBits << bits->bitIndex ; + + bits->bitIndex += numBits ; + + returnBits = returnBits >> (16 - numBits) ; + + bits->cur += (bits->bitIndex >> 3) ; + bits->bitIndex &= 7 ; + + //Assert (bits->cur <= bits->end) ; + + return (uint8_t) returnBits ; +} + +// BitBufferReadOne +// +// Reads one byte +uint8_t BitBufferReadOne (BitBuffer * bits) +{ + uint8_t returnBits ; + + returnBits = (bits->cur [0] >> (7 - bits->bitIndex)) & 1 ; + + bits->bitIndex++ ; + + bits->cur += (bits->bitIndex >> 3) ; + bits->bitIndex &= 7 ; + + //Assert (bits->cur <= bits->end) ; + + return returnBits ; +} + +// BitBufferPeek +// +uint32_t BitBufferPeek (BitBuffer * bits, uint8_t numBits) +{ + return ((((((uint32_t) bits->cur [0] << 16) | ((uint32_t) bits->cur [1] << 8) | + ((uint32_t) bits->cur [2])) << bits->bitIndex) & 0x00FFFFFF) >> (24 - numBits)) ; +} + +// BitBufferPeekOne +// +uint32_t BitBufferPeekOne (BitBuffer * bits) +{ + return ((bits->cur [0] >> (7 - bits->bitIndex)) & 1) ; +} + +// BitBufferUnpackBERSize +// +uint32_t BitBufferUnpackBERSize (BitBuffer * bits) +{ + uint32_t size ; + uint8_t tmp ; + + for (size = 0, tmp = 0x80u ; tmp &= 0x80u ; size = (size << 7u) | (tmp & 0x7fu)) + tmp = (uint8_t) BitBufferReadSmall (bits, 8) ; + + return size ; +} + +// BitBufferGetPosition +// +uint32_t BitBufferGetPosition (BitBuffer * bits) +{ + uint8_t * begin ; + + begin = bits->end - bits->byteSize ; + + return ((uint32_t) (bits->cur - begin) * 8) + bits->bitIndex ; +} + +// BitBufferByteAlign +// +void BitBufferByteAlign (BitBuffer * bits, int32_t addZeros) +{ + // align bit buffer to next byte boundary, writing zeros if requested + if (bits->bitIndex == 0) + return ; + + if (addZeros) + BitBufferWrite (bits, 0, 8 - bits->bitIndex) ; + else + BitBufferAdvance (bits, 8 - bits->bitIndex) ; +} + +// BitBufferAdvance +// +void BitBufferAdvance (BitBuffer * bits, uint32_t numBits) +{ + if (numBits) + { + bits->bitIndex += numBits ; + bits->cur += (bits->bitIndex >> 3) ; + bits->bitIndex &= 7 ; + } +} + +// BitBufferRewind +// +void BitBufferRewind (BitBuffer * bits, uint32_t numBits) +{ + uint32_t numBytes ; + + if (numBits == 0) + return ; + + if (bits->bitIndex >= numBits) + { + bits->bitIndex -= numBits ; + return ; + } + + numBits -= bits->bitIndex ; + bits->bitIndex = 0 ; + + numBytes = numBits / 8 ; + numBits = numBits % 8 ; + + bits->cur -= numBytes ; + + if (numBits > 0) + { + bits->bitIndex = 8 - numBits ; + bits->cur-- ; + } + + if (bits->cur < (bits->end - bits->byteSize)) + { + //DebugCMsg ("BitBufferRewind: Rewound too far.") ; + + bits->cur = (bits->end - bits->byteSize) ; + bits->bitIndex = 0 ; + } +} + +// BitBufferWrite +// +void BitBufferWrite (BitBuffer * bits, uint32_t bitValues, uint32_t numBits) +{ + uint32_t invBitIndex ; + + RequireAction (bits != NULL, return ;) ; + RequireActionSilent (numBits > 0, return ;) ; + + invBitIndex = 8 - bits->bitIndex ; + + while (numBits > 0) + { + uint32_t tmp ; + uint8_t shift ; + uint8_t mask ; + uint32_t curNum ; + + curNum = MIN (invBitIndex, numBits) ; + + tmp = bitValues >> (numBits - curNum) ; + + shift = (uint8_t) (invBitIndex - curNum) ; + mask = 0xffu >> (8 - curNum) ; // must be done in two steps to avoid compiler sequencing ambiguity + mask <<= shift ; + + bits->cur [0] = (bits->cur [0] & ~mask) | (((uint8_t) tmp << shift) & mask) ; + numBits -= curNum ; + + // increment to next byte if need be + invBitIndex -= curNum ; + if (invBitIndex == 0) + { + invBitIndex = 8 ; + bits->cur++ ; + } + } + + bits->bitIndex = 8 - invBitIndex ; +} + +void BitBufferReset (BitBuffer * bits) +//void BitBufferInit (BitBuffer * bits, uint8_t * buffer, uint32_t byteSize) +{ + bits->cur = bits->end - bits->byteSize ; + bits->bitIndex = 0 ; +} + +#if PRAGMA_MARK +#pragma mark - +#endif diff --git a/extern/libsndfile-modified/src/ALAC/ALACBitUtilities.h b/extern/libsndfile-modified/src/ALAC/ALACBitUtilities.h new file mode 100644 index 000000000..97080cdfe --- /dev/null +++ b/extern/libsndfile-modified/src/ALAC/ALACBitUtilities.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2011 Apple Inc. All rights reserved. + * + * @APPLE_APACHE_LICENSE_HEADER_START@ + * + * Licensed under the Apache License, Version 2.0 (the "License") ; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @APPLE_APACHE_LICENSE_HEADER_END@ + */ + +/*============================================================================= + File: ALACBitUtilities.h + + $NoKeywords: $ +=============================================================================*/ + +#ifndef __ALACBITUTILITIES_H +#define __ALACBITUTILITIES_H + +#include + +#ifndef MIN +#define MIN(x, y) ((x) < (y) ? (x) : (y)) +#endif // MIN +#ifndef MAX +#define MAX(x, y) ((x) > (y) ? (x) : (y)) +#endif // MAX + +#define RequireAction(condition, action) if (! (condition)) { action } +#define RequireActionSilent(condition, action) if (! (condition)) { action } +#define RequireNoErr(condition, action) if (condition) { action } + +enum +{ + ALAC_noErr = 0 +} ; + + +typedef enum +{ ID_SCE = 0, /* Single Channel Element */ + ID_CPE = 1, /* Channel Pair Element */ + ID_CCE = 2, /* Coupling Channel Element */ + ID_LFE = 3, /* LFE Channel Element */ + ID_DSE = 4, /* not yet supported */ + ID_PCE = 5, + ID_FIL = 6, + ID_END = 7 +} ELEMENT_TYPE ; + +// types +typedef struct BitBuffer +{ + uint8_t * cur ; + uint8_t * end ; + uint32_t bitIndex ; + uint32_t byteSize ; + +} BitBuffer ; + +/* + BitBuffer routines + - these routines take a fixed size buffer and read/write to it + - bounds checking must be done by the client +*/ +void BitBufferInit (BitBuffer * bits, uint8_t * buffer, uint32_t byteSize) ; +uint32_t BitBufferRead (BitBuffer * bits, uint8_t numBits) ; // note: cannot read more than 16 bits at a time +uint8_t BitBufferReadSmall (BitBuffer * bits, uint8_t numBits) ; +uint8_t BitBufferReadOne (BitBuffer * bits) ; +uint32_t BitBufferPeek (BitBuffer * bits, uint8_t numBits) ; // note: cannot read more than 16 bits at a time +uint32_t BitBufferPeekOne (BitBuffer * bits) ; +uint32_t BitBufferUnpackBERSize (BitBuffer * bits) ; +uint32_t BitBufferGetPosition (BitBuffer * bits) ; +void BitBufferByteAlign (BitBuffer * bits, int32_t addZeros) ; +void BitBufferAdvance (BitBuffer * bits, uint32_t numBits) ; +void BitBufferRewind (BitBuffer * bits, uint32_t numBits) ; +void BitBufferWrite (BitBuffer * bits, uint32_t value, uint32_t numBits) ; +void BitBufferReset (BitBuffer * bits) ; + +#endif /* __BITUTILITIES_H */ diff --git a/extern/libsndfile-modified/src/ALAC/ALACDecoder.h b/extern/libsndfile-modified/src/ALAC/ALACDecoder.h new file mode 100644 index 000000000..8eb7531f8 --- /dev/null +++ b/extern/libsndfile-modified/src/ALAC/ALACDecoder.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2011 Apple Inc. All rights reserved. + * + * @APPLE_APACHE_LICENSE_HEADER_START@ + * + * Licensed under the Apache License, Version 2.0 (the "License") ; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @APPLE_APACHE_LICENSE_HEADER_END@ + */ + +/* + File: ALACDecoder.h +*/ + +#ifndef _ALACDECODER_H +#define _ALACDECODER_H + +#include + +#include "ALACAudioTypes.h" + +struct BitBuffer ; + +class ALACDecoder +{ + public: + ALACDecoder () ; + ~ALACDecoder () ; + + int32_t Init (void * inMagicCookie, uint32_t inMagicCookieSize) ; + int32_t Decode (struct BitBuffer * bits, uint8_t * sampleBuffer, uint32_t numSamples, uint32_t numChannels, uint32_t * outNumSamples) ; + + public: + // decoding parameters (public for use in the analyzer) + ALACSpecificConfig mConfig ; + + protected: + int32_t FillElement (struct BitBuffer * bits) ; + int32_t DataStreamElement (struct BitBuffer * bits) ; + + uint16_t mActiveElements ; + + // decoding buffers + int32_t * mMixBufferU ; + int32_t * mMixBufferV ; + int32_t * mPredictor ; + uint16_t * mShiftBuffer ; // note: this points to mPredictor's memory but different + // variable for clarity and type difference +} ; + +#endif /* _ALACDECODER_H */ diff --git a/extern/libsndfile-modified/src/ALAC/ALACEncoder.h b/extern/libsndfile-modified/src/ALAC/ALACEncoder.h new file mode 100644 index 000000000..eb5b79ee3 --- /dev/null +++ b/extern/libsndfile-modified/src/ALAC/ALACEncoder.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2011 Apple Inc. All rights reserved. + * + * @APPLE_APACHE_LICENSE_HEADER_START@ + * + * Licensed under the Apache License, Version 2.0 (the "License") ; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @APPLE_APACHE_LICENSE_HEADER_END@ + */ + +/* + File: ALACEncoder.h +*/ + +#pragma once + +#include + +#include "ALACAudioTypes.h" + + +struct BitBuffer ; + +class ALACEncoder +{ + public : + ALACEncoder () ; + virtual ~ALACEncoder () ; + + virtual int32_t Encode (AudioFormatDescription theInputFormat, AudioFormatDescription theOutputFormat, + unsigned char * theReadBuffer, unsigned char * theWriteBuffer, int32_t * ioNumBytes) ; + virtual int32_t Finish () ; + + void SetFastMode (bool fast) { mFastMode = fast ; } ; + + // this must be called *before* InitializeEncoder () + void SetFrameSize (uint32_t frameSize) { mFrameSize = frameSize ; } ; + + void GetConfig (ALACSpecificConfig & config) ; + uint32_t GetMagicCookieSize (uint32_t inNumChannels) ; + void GetMagicCookie (void * config, uint32_t * ioSize) ; + + virtual int32_t InitializeEncoder (AudioFormatDescription theOutputFormat) ; + + protected : + virtual void GetSourceFormat (const AudioFormatDescription * source, AudioFormatDescription * output) ; + + int32_t EncodeStereo (struct BitBuffer * bitstream, void * input, uint32_t stride, uint32_t channelIndex, uint32_t numSamples) ; + int32_t EncodeStereoFast (struct BitBuffer * bitstream, void * input, uint32_t stride, uint32_t channelIndex, uint32_t numSamples) ; + int32_t EncodeStereoEscape (struct BitBuffer * bitstream, void * input, uint32_t stride, uint32_t numSamples) ; + int32_t EncodeMono (struct BitBuffer * bitstream, void * input, uint32_t stride, uint32_t channelIndex, uint32_t numSamples) ; + + + // ALAC encoder parameters + int16_t mBitDepth ; + bool mFastMode ; + + // encoding state + int16_t mLastMixRes [kALACMaxChannels] ; + + // encoding buffers + int32_t * mMixBufferU ; + int32_t * mMixBufferV ; + int32_t * mPredictorU ; + int32_t * mPredictorV ; + uint16_t * mShiftBufferUV ; + + uint8_t * mWorkBuffer ; + + // per-channel coefficients buffers + int16_t mCoefsU [kALACMaxChannels][kALACMaxSearches][kALACMaxCoefs] ; + int16_t mCoefsV [kALACMaxChannels][kALACMaxSearches][kALACMaxCoefs] ; + + // encoding statistics + uint32_t mTotalBytesGenerated ; + uint32_t mAvgBitRate ; + uint32_t mMaxFrameBytes ; + uint32_t mFrameSize ; + uint32_t mMaxOutputBytes ; + uint32_t mNumChannels ; + uint32_t mOutputSampleRate ; +} ; diff --git a/extern/libsndfile-modified/src/ALAC/EndianPortable.h b/extern/libsndfile-modified/src/ALAC/EndianPortable.h new file mode 100644 index 000000000..aa1f449b4 --- /dev/null +++ b/extern/libsndfile-modified/src/ALAC/EndianPortable.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2011 Apple Inc. All rights reserved. +** Copyright (C) 2013-2014 Erik de Castro Lopo + * + * @APPLE_APACHE_LICENSE_HEADER_START@ + * + * Licensed under the Apache License, Version 2.0 (the "License") ; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @APPLE_APACHE_LICENSE_HEADER_END@ + */ + +// +// EndianPortable.h +// +// Copyright 2011 Apple Inc. All rights reserved. +// + +#ifndef _EndianPortable_h +#define _EndianPortable_h + +#include + +#define Swap16NtoB(x) H2BE_16 (x) +#define Swap16BtoN(x) BE2H_16 (x) + +#define Swap32NtoB(x) H2BE_32 (x) +#define Swap32BtoN(x) BE2H_32 (x) + +#endif diff --git a/extern/libsndfile-modified/src/ALAC/LICENSE b/extern/libsndfile-modified/src/ALAC/LICENSE new file mode 100644 index 000000000..7d8595490 --- /dev/null +++ b/extern/libsndfile-modified/src/ALAC/LICENSE @@ -0,0 +1,170 @@ +Apache License + +Version 2.0, January 2004 + +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the +copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other +entities that control, are controlled by, or are under common control +with that entity. For the purposes of this definition, "control" means +(i) the power, direct or indirect, to cause the direction or management +of such entity, whether by contract or otherwise, or (ii) ownership +of fifty percent (50%) or more of the outstanding shares, or (iii) +beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, +including but not limited to software source code, documentation source, +and configuration files. + +"Object" form shall mean any form resulting from mechanical +transformation or translation of a Source form, including but not +limited to compiled object code, generated documentation, and +conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object +form, made available under the License, as indicated by a copyright +notice that is included in or attached to the work (an example is +provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object +form, that is based on (or derived from) the Work and for which the +editorial revisions, annotations, elaborations, or other modifications +represent, as a whole, an original work of authorship. For the purposes +of this License, Derivative Works shall not include works that remain +separable from, or merely link (or bind by name) to the interfaces of, +the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original +version of the Work and any modifications or additions to that Work or +Derivative Works thereof, that is intentionally submitted to Licensor +for inclusion in the Work by the copyright owner or by an individual +or Legal Entity authorized to submit on behalf of the copyright owner. +For the purposes of this definition, "submitted" means any form of +electronic, verbal, or written communication sent to the Licensor +or its representatives, including but not limited to communication +on electronic mailing lists, source code control systems, and issue +tracking systems that are managed by, or on behalf of, the Licensor +for the purpose of discussing and improving the Work, but excluding +communication that is conspicuously marked or otherwise designated in +writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity +on behalf of whom a Contribution has been received by Licensor and +subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions +of this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable +copyright license to reproduce, prepare Derivative Works of, publicly +display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of +this License, each Contributor hereby grants to You a perpetual, +worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except +as stated in this section) patent license to make, have made, use, +offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such +Contributor that are necessarily infringed by their Contribution(s) +alone or by combination of their Contribution(s) with the Work to which +such Contribution(s) was submitted. If You institute patent litigation +against any entity (including a cross-claim or counterclaim in a +lawsuit) alleging that the Work or a Contribution incorporated within +the Work constitutes direct or contributory patent infringement, then +any patent licenses granted to You under this License for that Work +shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the +Work or Derivative Works thereof in any medium, with or without +modifications, and in Source or Object form, provided that You meet the +following conditions: + +You must give any other recipients of the Work or Derivative Works a +copy of this License; and + +You must cause any modified files to carry prominent notices stating +that You changed the files; and + +You must retain, in the Source form of any Derivative Works that You +distribute, all copyright, patent, trademark, and attribution notices +from the Source form of the Work, excluding those notices that do not +pertain to any part of the Derivative Works; and + +If the Work includes a "NOTICE" text file as part of its distribution, +then any Derivative Works that You distribute must include a readable +copy of the attribution notices contained within such NOTICE file, +excluding those notices that do not pertain to any part of the +Derivative Works, in at least one of the following places: within a +NOTICE text file distributed as part of the Derivative Works; within +the Source form or documentation, if provided along with the Derivative +Works; or, within a display generated by the Derivative Works, if and +wherever such third-party notices normally appear. The contents of the +NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative +Works that You distribute, alongside or as an addendum to the NOTICE +text from the Work, provided that such additional attribution notices +cannot be construed as modifying the License. You may add Your own +copyright statement to Your modifications and may provide additional +or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as +a whole, provided Your use, reproduction, and distribution of the Work +otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, +any Contribution intentionally submitted for inclusion in the Work by +You to the Licensor shall be under the terms and conditions of this +License, without any additional terms or conditions. Notwithstanding +the above, nothing herein shall supersede or modify the terms of any +separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. This License does not grant permission to use the trade +names, trademarks, service marks, or product names of the Licensor, +except as required for reasonable and customary use in describing the +origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed +to in writing, Licensor provides the Work (and each Contributor +provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR +CONDITIONS OF ANY KIND, either express or implied, including, without +limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, +MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your +exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, +whether in tort (including negligence), contract, or otherwise, unless +required by applicable law (such as deliberate and grossly negligent +acts) or agreed to in writing, shall any Contributor be liable to You +for damages, including any direct, indirect, special, incidental, or +consequential damages of any character arising as a result of this +License or out of the use or inability to use the Work (including but +not limited to damages for loss of goodwill, work stoppage, computer +failure or malfunction, or any and all other commercial damages or +losses), even if such Contributor has been advised of the possibility of +such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the +Work or Derivative Works thereof, You may choose to offer, and charge a +fee for, acceptance of support, warranty, indemnity, or other liability +obligations and/or rights consistent with this License. However, in +accepting such obligations, You may act only on Your own behalf and +on Your sole responsibility, not on behalf of any other Contributor, +and only if You agree to indemnify, defend, and hold each Contributor +harmless for any liability incurred by, or claims asserted against, such +Contributor by reason of your accepting any such warranty or additional +liability. diff --git a/extern/libsndfile-modified/src/ALAC/ag_dec.c b/extern/libsndfile-modified/src/ALAC/ag_dec.c new file mode 100644 index 000000000..37671d240 --- /dev/null +++ b/extern/libsndfile-modified/src/ALAC/ag_dec.c @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2011 Apple Inc. All rights reserved. + * + * @APPLE_APACHE_LICENSE_HEADER_START@ + * + * Licensed under the Apache License, Version 2.0 (the "License") ; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @APPLE_APACHE_LICENSE_HEADER_END@ + */ + +/* + File: ag_dec.c + + Contains: Adaptive Golomb decode routines. + + Copyright: (c) 2001-2011 Apple, Inc. +*/ + +#include +#include +#include +#include + +#include "aglib.h" +#include "ALACBitUtilities.h" +#include "ALACAudioTypes.h" + +#define CODE_TO_LONG_MAXBITS 32 +#define N_MAX_MEAN_CLAMP 0xffff +#define N_MEAN_CLAMP_VAL 0xffff +#define REPORT_VAL 40 + +#if __GNUC__ +#define ALWAYS_INLINE __attribute__ ((always_inline)) +#elif defined _MSC_VER +#define ALWAYS_INLINE __forceinline +#else +#define ALWAYS_INLINE +#endif + +/* And on the subject of the CodeWarrior x86 compiler and inlining, I reworked a lot of this + to help the compiler out. In many cases this required manual inlining or a macro. Sorry + if it is ugly but the performance gains are well worth it. + - WSK 5/19/04 +*/ + +void set_standard_ag_params (AGParamRecPtr params, uint32_t fullwidth, uint32_t sectorwidth) +{ + /* Use + fullwidth = sectorwidth = numOfSamples, for analog 1-dimensional type-short data, + but use + fullwidth = full image width, sectorwidth = sector (patch) width + for such as image (2-dim.) data. + */ + set_ag_params (params, MB0, PB0, KB0, fullwidth, sectorwidth, MAX_RUN_DEFAULT) ; +} + +void set_ag_params (AGParamRecPtr params, uint32_t m, uint32_t p, uint32_t k, uint32_t f, uint32_t s, uint32_t maxrun) +{ + params->mb = params->mb0 = m ; + params->pb = p ; + params->kb = k ; + params->wb = (1u << params->kb) - 1 ; + params->qb = QB-params->pb ; + params->fw = f ; + params->sw = s ; + params->maxrun = maxrun ; +} + +#if PRAGMA_MARK +#pragma mark - +#endif + + +// note: implementing this with some kind of "count leading zeros" assembly is a big performance win +static inline int32_t lead (int32_t m) +{ + long j ; + unsigned long c = (1ul << 31) ; + + for (j = 0 ; j < 32 ; j++) + { + if ((c & m) != 0) + break ; + c >>= 1 ; + } + return j ; +} + +#define arithmin(a, b) ((a) < (b) ? (a) : (b)) + +static inline int32_t ALWAYS_INLINE lg3a (int32_t x) +{ + int32_t result ; + + x += 3 ; + result = lead (x) ; + + return 31 - result ; +} + +static inline uint32_t ALWAYS_INLINE read32bit (uint8_t * buffer) +{ + // embedded CPUs typically can't read unaligned 32-bit words so just read the bytes + uint32_t value ; + + value = ((uint32_t) buffer [0] << 24) | ((uint32_t) buffer [1] << 16) | + ((uint32_t) buffer [2] << 8) | (uint32_t) buffer [3] ; + return value ; + +} + +#if PRAGMA_MARK +#pragma mark - +#endif + +#define get_next_fromlong(inlong, suff) ((inlong) >> (32 - (suff))) + + +static inline uint32_t ALWAYS_INLINE +getstreambits (uint8_t *in, int32_t bitoffset, int32_t numbits) +{ + uint32_t load1, load2 ; + uint32_t byteoffset = bitoffset / 8 ; + uint32_t result ; + + //Assert (numbits <= 32) ; + + load1 = read32bit (in + byteoffset) ; + + if ((numbits + (bitoffset & 0x7)) > 32) + { + int32_t load2shift ; + + result = load1 << (bitoffset & 0x7) ; + load2 = (uint32_t) in [byteoffset + 4] ; + load2shift = (8 - (numbits + (bitoffset & 0x7) - 32)) ; + load2 >>= load2shift ; + result >>= (32 - numbits) ; + result |= load2 ; + } + else + { + result = load1 >> (32 - numbits - (bitoffset & 7)) ; + } + + // a shift of >= "the number of bits in the type of the value being shifted" results in undefined + // behavior so don't try to shift by 32 + if (numbits != (sizeof (result) * 8)) + result &= ~ (0xfffffffful << numbits) ; + + return result ; +} + + +static inline int32_t dyn_get (unsigned char *in, uint32_t *bitPos, uint32_t m, uint32_t k) +{ + uint32_t tempbits = *bitPos ; + uint32_t result ; + uint32_t pre = 0, v ; + uint32_t streamlong ; + + streamlong = read32bit (in + (tempbits >> 3)) ; + streamlong <<= (tempbits & 7) ; + + /* find the number of bits in the prefix */ + { + uint32_t notI = ~streamlong ; + pre = lead (notI) ; + } + + if (pre >= MAX_PREFIX_16) + { + pre = MAX_PREFIX_16 ; + tempbits += pre ; + streamlong <<= pre ; + result = get_next_fromlong (streamlong, MAX_DATATYPE_BITS_16) ; + tempbits += MAX_DATATYPE_BITS_16 ; + + } + else + { + // all of the bits must fit within the long we have loaded + //Assert (pre+1+k <= 32) ; + + tempbits += pre ; + tempbits += 1 ; + streamlong <<= pre + 1 ; + v = get_next_fromlong (streamlong, k) ; + tempbits += k ; + + result = pre*m + v-1 ; + + if (v < 2) + { + result -= (v-1) ; + tempbits -= 1 ; + } + } + + *bitPos = tempbits ; + return result ; +} + + +static inline int32_t dyn_get_32bit (uint8_t * in, uint32_t * bitPos, int32_t m, int32_t k, int32_t maxbits) +{ + uint32_t tempbits = *bitPos ; + uint32_t v ; + uint32_t streamlong ; + uint32_t result ; + + streamlong = read32bit (in + (tempbits >> 3)) ; + streamlong <<= (tempbits & 7) ; + + /* find the number of bits in the prefix */ + { + uint32_t notI = ~streamlong ; + result = lead (notI) ; + } + + if (result >= MAX_PREFIX_32) + { + result = getstreambits (in, tempbits+MAX_PREFIX_32, maxbits) ; + tempbits += MAX_PREFIX_32 + maxbits ; + } + else + { + /* all of the bits must fit within the long we have loaded*/ + //Assert (k<=14) ; + //Assert (result= 2) + { + result += (v-1) ; + tempbits += 1 ; + } + } + } + + *bitPos = tempbits ; + + return result ; +} + +int32_t dyn_decomp (AGParamRecPtr params, BitBuffer * bitstream, int32_t * pc, int32_t numSamples, int32_t maxSize, uint32_t * outNumBits) +{ + uint8_t *in ; + int32_t *outPtr = pc ; + uint32_t bitPos, startPos, maxPos ; + uint32_t j, m, k, n, c, mz ; + int32_t del, zmode ; + uint32_t mb ; + uint32_t pb_local = params->pb ; + uint32_t kb_local = params->kb ; + uint32_t wb_local = params->wb ; + int32_t status ; + + RequireAction ((bitstream != NULL) && (pc != NULL) && (outNumBits != NULL), return kALAC_ParamError ;) ; + *outNumBits = 0 ; + + in = bitstream->cur ; + startPos = bitstream->bitIndex ; + maxPos = bitstream->byteSize * 8 ; + bitPos = startPos ; + + mb = params->mb0 ; + zmode = 0 ; + + c = 0 ; + status = ALAC_noErr ; + + while (c < (uint32_t) numSamples) + { + // bail if we've run off the end of the buffer + RequireAction (bitPos < maxPos, status = kALAC_ParamError ; goto Exit ;) ; + + m = (mb) >> QBSHIFT ; + k = lg3a (m) ; + + k = arithmin (k, kb_local) ; + m = (1 << k) - 1 ; + + n = dyn_get_32bit (in, &bitPos, m, k, maxSize) ; + + // least significant bit is sign bit + { + uint32_t ndecode = n + zmode ; + int32_t multiplier = - (int) (ndecode & 1) ; + + multiplier |= 1 ; + del = ((ndecode+1) >> 1) * (multiplier) ; + } + + *outPtr++ = del ; + + c++ ; + + mb = pb_local * (n + zmode) + mb - ((pb_local * mb) >> QBSHIFT) ; + + // update mean tracking + if (n > N_MAX_MEAN_CLAMP) + mb = N_MEAN_CLAMP_VAL ; + + zmode = 0 ; + + if (((mb << MMULSHIFT) < QB) && (c < (uint32_t) numSamples)) + { + zmode = 1 ; + k = lead (mb) - BITOFF + ((mb + MOFF) >> MDENSHIFT) ; + mz = ((1 << k) - 1) & wb_local ; + + n = dyn_get (in, &bitPos, mz, k) ; + + RequireAction (c+n <= (uint32_t) numSamples, status = kALAC_ParamError ; goto Exit ;) ; + + for (j = 0 ; j < n ; j++) + { + *outPtr++ = 0 ; + ++c ; + } + + if (n >= 65535) + zmode = 0 ; + + mb = 0 ; + } + } + +Exit: + *outNumBits = (bitPos - startPos) ; + BitBufferAdvance (bitstream, *outNumBits) ; + RequireAction (bitstream->cur <= bitstream->end, status = kALAC_ParamError ;) ; + + return status ; +} diff --git a/extern/libsndfile-modified/src/ALAC/ag_enc.c b/extern/libsndfile-modified/src/ALAC/ag_enc.c new file mode 100644 index 000000000..4737b96e3 --- /dev/null +++ b/extern/libsndfile-modified/src/ALAC/ag_enc.c @@ -0,0 +1,352 @@ +/* + * Copyright (c) 2011 Apple Inc. All rights reserved. + * Copyright (C) 2013-2014 Erik de Castro Lopo + * + * @APPLE_APACHE_LICENSE_HEADER_START@ + * + * Licensed under the Apache License, Version 2.0 (the "License") ; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @APPLE_APACHE_LICENSE_HEADER_END@ + */ + +/* + File: ag_enc.c + + Contains: Adaptive Golomb encode routines. + + Copyright: (c) 2001-2011 Apple, Inc. +*/ + +#include "aglib.h" +#include "ALACBitUtilities.h" +#include "EndianPortable.h" +#include "ALACAudioTypes.h" + +#include +#include +#include +#include + +#define CODE_TO_LONG_MAXBITS 32 +#define N_MAX_MEAN_CLAMP 0xffff +#define N_MEAN_CLAMP_VAL 0xffff +#define REPORT_VAL 40 + +#if __GNUC__ +#define ALWAYS_INLINE __attribute__ ((always_inline)) +#elif defined _MSC_VER +#define ALWAYS_INLINE __forceinline +#else +#define ALWAYS_INLINE +#endif + + +/* And on the subject of the CodeWarrior x86 compiler and inlining, I reworked a lot of this + to help the compiler out. In many cases this required manual inlining or a macro. Sorry + if it is ugly but the performance gains are well worth it. + - WSK 5/19/04 +*/ + +// note: implementing this with some kind of "count leading zeros" assembly is a big performance win +static inline int32_t lead (int32_t m) +{ + long j ; + unsigned long c = (1ul << 31) ; + + for (j = 0 ; j < 32 ; j++) + { + if ((c & m) != 0) + break ; + c >>= 1 ; + } + return j ; +} + +#define arithmin (a, b) ((a) < (b) ? (a) : (b)) + +static inline int32_t ALWAYS_INLINE lg3a (int32_t x) +{ + int32_t result ; + + x += 3 ; + result = lead (x) ; + + return 31 - result ; +} + +static inline int32_t ALWAYS_INLINE abs_func (int32_t a) +{ + // note: the CW PPC intrinsic __abs () turns into these instructions so no need to try and use it + int32_t isneg = a >> 31 ; + int32_t xorval = a ^ isneg ; + int32_t result = xorval-isneg ; + + return result ; +} + +#if PRAGMA_MARK +#pragma mark - +#endif + +static inline int32_t dyn_code (int32_t m, int32_t k, int32_t n, uint32_t *outNumBits) +{ + uint32_t divx, mod, de ; + uint32_t numBits ; + uint32_t value ; + + // Assert (n >= 0) ; + + divx = n / m ; + + if (divx >= MAX_PREFIX_16) + { + numBits = MAX_PREFIX_16 + MAX_DATATYPE_BITS_16 ; + value = (((1 << MAX_PREFIX_16) - 1) << MAX_DATATYPE_BITS_16) + n ; + } + else + { + mod = n%m ; + de = (mod == 0) ; + numBits = divx + k + 1 - de ; + value = (((1 << divx) - 1) << (numBits - divx)) + mod + 1 - de ; + + // if coding this way is bigger than doing escape, then do escape + if (numBits > MAX_PREFIX_16 + MAX_DATATYPE_BITS_16) + { + numBits = MAX_PREFIX_16 + MAX_DATATYPE_BITS_16 ; + value = (((1 << MAX_PREFIX_16) - 1) << MAX_DATATYPE_BITS_16) + n ; + } + } + + *outNumBits = numBits ; + + return (int32_t) value ; +} + + +static inline int32_t dyn_code_32bit (int32_t maxbits, uint32_t m, uint32_t k, uint32_t n, uint32_t *outNumBits, uint32_t *outValue, uint32_t *overflow, uint32_t *overflowbits) +{ + uint32_t divx, mod, de ; + uint32_t numBits ; + uint32_t value ; + int32_t didOverflow = 0 ; + + divx = n / m ; + + if (divx < MAX_PREFIX_32) + { + mod = n - (m * divx) ; + + de = (mod == 0) ; + numBits = divx + k + 1 - de ; + value = (((1 << divx) - 1) << (numBits - divx)) + mod + 1 - de ; + if (numBits > 25) + goto codeasescape ; + } + else + { +codeasescape: + numBits = MAX_PREFIX_32 ; + value = (((1 << MAX_PREFIX_32) - 1)) ; + *overflow = n ; + *overflowbits = maxbits ; + didOverflow = 1 ; + } + + *outNumBits = numBits ; + *outValue = value ; + + return didOverflow ; +} + + +static inline void ALWAYS_INLINE dyn_jam_noDeref (unsigned char *out, uint32_t bitPos, uint32_t numBits, uint32_t value) +{ + uint32_t mask ; + uint32_t curr ; + uint32_t shift ; + + //Assert (numBits <= 32) ; + + curr = psf_get_be32 (out, bitPos >> 3) ; + + shift = 32 - (bitPos & 7) - numBits ; + + mask = ~0u >> (32 - numBits) ; // mask must be created in two steps to avoid compiler sequencing ambiguity + mask <<= shift ; + + value = (value << shift) & mask ; + value |= curr & ~mask ; + + psf_put_be32 (out, bitPos >> 3, value) ; +} + + +static inline void ALWAYS_INLINE dyn_jam_noDeref_large (unsigned char *out, uint32_t bitPos, uint32_t numBits, uint32_t value) +{ + uint32_t w ; + uint32_t curr ; + uint32_t mask ; + int32_t shiftvalue = (32 - (bitPos & 7) - numBits) ; + + //Assert (numBits <= 32) ; + + curr = psf_get_be32 (out, bitPos >> 3) ; + + if (shiftvalue < 0) + { + uint8_t tailbyte ; + uint8_t *tailptr ; + + w = value >> -shiftvalue ; + mask = ~0u >> -shiftvalue ; + w |= (curr & ~mask) ; + + tailptr = out + (bitPos >> 3) + 4 ; + tailbyte = (value << ((8+shiftvalue))) & 0xff ; + *tailptr = (uint8_t) tailbyte ; + } + else + { + mask = ~0u >> (32 - numBits) ; + mask <<= shiftvalue ; // mask must be created in two steps to avoid compiler sequencing ambiguity + + w = (value << shiftvalue) & mask ; + w |= curr & ~mask ; + } + + psf_put_be32 (out, bitPos >> 3, w) ; +} + + +int32_t dyn_comp (AGParamRecPtr params, int32_t * pc, BitBuffer * bitstream, int32_t numSamples, int32_t bitSize, uint32_t * outNumBits) +{ + unsigned char * out ; + uint32_t bitPos, startPos ; + uint32_t m, k, n, c, mz, nz ; + uint32_t numBits ; + uint32_t value ; + int32_t del, zmode ; + uint32_t overflow, overflowbits ; + int32_t status ; + + // shadow the variables in params so there's not the dereferencing overhead + uint32_t mb, pb, kb, wb ; + int32_t rowPos = 0 ; + int32_t rowSize = params->sw ; + int32_t rowJump = (params->fw) - rowSize ; + int32_t * inPtr = pc ; + + *outNumBits = 0 ; + RequireAction ((bitSize >= 1) && (bitSize <= 32), return kALAC_ParamError ;) ; + + out = bitstream->cur ; + startPos = bitstream->bitIndex ; + bitPos = startPos ; + + mb = params->mb = params->mb0 ; + pb = params->pb ; + kb = params->kb ; + wb = params->wb ; + zmode = 0 ; + + c = 0 ; + status = ALAC_noErr ; + + while (c < (uint32_t) numSamples) + { + m = mb >> QBSHIFT ; + k = lg3a (m) ; + if (k > kb) + { + k = kb ; + } + m = (1 << k) - 1 ; + + del = *inPtr++ ; + rowPos++ ; + + n = (abs_func (del) << 1) - ((del >> 31) & 1) - zmode ; + //Assert (32-lead (n) <= bitSize) ; + + if (dyn_code_32bit (bitSize, m, k, n, &numBits, &value, &overflow, &overflowbits)) + { + dyn_jam_noDeref (out, bitPos, numBits, value) ; + bitPos += numBits ; + dyn_jam_noDeref_large (out, bitPos, overflowbits, overflow) ; + bitPos += overflowbits ; + } + else + { + dyn_jam_noDeref (out, bitPos, numBits, value) ; + bitPos += numBits ; + } + + c++ ; + if (rowPos >= rowSize) + { + rowPos = 0 ; + inPtr += rowJump ; + } + + mb = pb * (n + zmode) + mb - ((pb * mb) >> QBSHIFT) ; + + // update mean tracking if it's overflowed + if (n > N_MAX_MEAN_CLAMP) + mb = N_MEAN_CLAMP_VAL ; + + zmode = 0 ; + + RequireAction (c <= (uint32_t) numSamples, status = kALAC_ParamError ; goto Exit ;) ; + + if (((mb << MMULSHIFT) < QB) && (c < (uint32_t) numSamples)) + { + zmode = 1 ; + nz = 0 ; + + while (c < (uint32_t) numSamples && *inPtr == 0) + { + /* Take care of wrap-around globals. */ + ++inPtr ; + ++nz ; + ++c ; + if (++rowPos >= rowSize) + { + rowPos = 0 ; + inPtr += rowJump ; + } + + if (nz >= 65535) + { + zmode = 0 ; + break ; + } + } + + k = lead (mb) - BITOFF + ((mb + MOFF) >> MDENSHIFT) ; + mz = ((1 << k) - 1) & wb ; + + value = dyn_code (mz, k, nz, &numBits) ; + dyn_jam_noDeref (out, bitPos, numBits, value) ; + bitPos += numBits ; + + mb = 0 ; + } + } + + *outNumBits = (bitPos - startPos) ; + BitBufferAdvance (bitstream, *outNumBits) ; + +Exit: + return status ; +} diff --git a/extern/libsndfile-modified/src/ALAC/aglib.h b/extern/libsndfile-modified/src/ALAC/aglib.h new file mode 100644 index 000000000..825c4bdfd --- /dev/null +++ b/extern/libsndfile-modified/src/ALAC/aglib.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2011 Apple Inc. All rights reserved. + * + * @APPLE_APACHE_LICENSE_HEADER_START@ + * + * Licensed under the Apache License, Version 2.0 (the "License") ; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @APPLE_APACHE_LICENSE_HEADER_END@ + */ + +/* + File: aglib.h + + Copyright: (C) 2001-2011 Apple, Inc. +*/ + +#ifndef AGLIB_H +#define AGLIB_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define QBSHIFT 9 +#define QB (1 << QBSHIFT) +#define PB0 40 +#define MB0 10 +#define KB0 14 +#define MAX_RUN_DEFAULT 255 + +#define MMULSHIFT 2 +#define MDENSHIFT (QBSHIFT - MMULSHIFT - 1) +#define MOFF ((1 << (MDENSHIFT - 2))) + +#define BITOFF 24 + +/* Max. prefix of 1's. */ +#define MAX_PREFIX_16 9 +#define MAX_PREFIX_TOLONG_16 15 +#define MAX_PREFIX_32 9 + +/* Max. bits in 16-bit data type */ +#define MAX_DATATYPE_BITS_16 16 + +typedef struct AGParamRec +{ + uint32_t mb, mb0, pb, kb, wb, qb ; + uint32_t fw, sw ; + + uint32_t maxrun ; + + // fw = 1, sw = 1 ; + +} AGParamRec, *AGParamRecPtr ; + +struct BitBuffer ; + +void set_standard_ag_params (AGParamRecPtr params, uint32_t fullwidth, uint32_t sectorwidth) ; +void set_ag_params (AGParamRecPtr params, uint32_t m, uint32_t p, uint32_t k, uint32_t f, uint32_t s, uint32_t maxrun) ; + +int32_t dyn_comp (AGParamRecPtr params, int32_t * pc, struct BitBuffer * bitstream, int32_t numSamples, int32_t bitSize, uint32_t * outNumBits) ; +int32_t dyn_decomp (AGParamRecPtr params, struct BitBuffer * bitstream, int32_t * pc, int32_t numSamples, int32_t maxSize, uint32_t * outNumBits) ; + + +#ifdef __cplusplus +} +#endif + +#endif //#ifndef AGLIB_H diff --git a/extern/libsndfile-modified/src/ALAC/alac_codec.h b/extern/libsndfile-modified/src/ALAC/alac_codec.h new file mode 100644 index 000000000..e762b279a --- /dev/null +++ b/extern/libsndfile-modified/src/ALAC/alac_codec.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2011 Apple Inc. All rights reserved. + * Copyright (C) 2012-2014 Erik de Castro Lopo + * + * @APPLE_APACHE_LICENSE_HEADER_START@ + * + * Licensed under the Apache License, Version 2.0 (the "License") ; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @APPLE_APACHE_LICENSE_HEADER_END@ + */ + +/* + File: alac_codec.h +*/ + +#ifndef ALAC_CODEC_H +#define ALAC_CODEC_H + +#include + +#include "ALACAudioTypes.h" + +#define ALAC_FRAME_LENGTH 4096 + +struct BitBuffer ; + +typedef struct alac_decoder_s +{ + // decoding parameters (public for use in the analyzer) + ALACSpecificConfig mConfig ; + + uint16_t mActiveElements ; + + // decoding buffers + int32_t mMixBufferU [ALAC_FRAME_LENGTH] ; + int32_t mMixBufferV [ALAC_FRAME_LENGTH] ; + union + { + int32_t mPredictor [ALAC_FRAME_LENGTH] ; + uint16_t mShiftBuffer [ALAC_FRAME_LENGTH] ; + } u ; + uint32_t mNumChannels ; +} ALAC_DECODER ; + +typedef struct alac_encoder_s +{ + // ALAC encoder parameters + int16_t mBitDepth ; + + // encoding state + int16_t mLastMixRes [kALACMaxChannels] ; + + int32_t mFastMode ; + + // encoding buffers + int32_t mMixBufferU [ALAC_FRAME_LENGTH] ; + int32_t mMixBufferV [ALAC_FRAME_LENGTH] ; + int32_t mPredictorU [ALAC_FRAME_LENGTH] ; + int32_t mPredictorV [ALAC_FRAME_LENGTH] ; + uint16_t mShiftBufferUV [2 * ALAC_FRAME_LENGTH] ; + uint8_t mWorkBuffer [4 * ALAC_FRAME_LENGTH] ; + + // per-channel coefficients buffers + int16_t mCoefsU [kALACMaxChannels][kALACMaxSearches][kALACMaxCoefs] ; + int16_t mCoefsV [kALACMaxChannels][kALACMaxSearches][kALACMaxCoefs] ; + + // encoding statistics + uint32_t mTotalBytesGenerated ; + uint32_t mAvgBitRate ; + uint32_t mMaxFrameBytes ; + uint32_t mFrameSize ; + uint32_t mMaxOutputBytes ; + uint32_t mNumChannels ; + uint32_t mOutputSampleRate ; +} ALAC_ENCODER ; + + +int32_t alac_decoder_init (ALAC_DECODER *p, void * inMagicCookie, uint32_t inMagicCookieSize) ; +int32_t alac_encoder_init (ALAC_ENCODER *p, uint32_t samplerate, uint32_t channels, uint32_t format_flags, uint32_t frameSize) ; + +int32_t alac_decode (ALAC_DECODER *, struct BitBuffer * bits, int32_t * sampleBuffer, + uint32_t numSamples, uint32_t * outNumSamples) ; + +int32_t alac_encode (ALAC_ENCODER *p, uint32_t numSamples, + const int32_t * theReadBuffer, unsigned char * theWriteBuffer, + uint32_t * ioNumBytes) ; + +void alac_set_fastmode (ALAC_ENCODER * p, int32_t fast) ; + +uint32_t alac_get_magic_cookie_size (uint32_t inNumChannels) ; +void alac_get_magic_cookie (ALAC_ENCODER *p, void * config, uint32_t * ioSize) ; +void alac_get_source_format (ALAC_ENCODER *p, const AudioFormatDescription * source, AudioFormatDescription * output) ; + +#endif diff --git a/extern/libsndfile-modified/src/ALAC/alac_decoder.c b/extern/libsndfile-modified/src/ALAC/alac_decoder.c new file mode 100644 index 000000000..46d333060 --- /dev/null +++ b/extern/libsndfile-modified/src/ALAC/alac_decoder.c @@ -0,0 +1,652 @@ +/* + * Copyright (c) 2011 Apple Inc. All rights reserved. + * Copyright (C) 2012-2015 Erik de Castro Lopo + * + * @APPLE_APACHE_LICENSE_HEADER_START@ + * + * Licensed under the Apache License, Version 2.0 (the "License") ; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @APPLE_APACHE_LICENSE_HEADER_END@ + */ + +/* + File: ALACDecoder.cpp +*/ + +#include +#include +#include +#include + +#include "alac_codec.h" + +#include "dplib.h" +#include "aglib.h" +#include "matrixlib.h" +#include "shift.h" + +#include "ALACBitUtilities.h" +#include "EndianPortable.h" + +typedef enum +{ false = 0, + true = 1 +} bool ; + +// constants/data +const uint32_t kMaxBitDepth = 32 ; // max allowed bit depth is 32 + + +// prototypes +static int32_t alac_fill_element (struct BitBuffer * bits) ; +static int32_t alac_data_stream_element (struct BitBuffer * bits) ; + +static void Zero32 (int32_t * buffer, uint32_t numItems, uint32_t stride) ; + + +/* + Init () + - initialize the decoder with the given configuration +*/ +int32_t +alac_decoder_init (ALAC_DECODER *p, void * inMagicCookie, uint32_t inMagicCookieSize) +{ + int32_t status = ALAC_noErr ; + ALACSpecificConfig theConfig ; + uint8_t * theActualCookie = (uint8_t *) inMagicCookie ; + uint32_t theCookieBytesRemaining = inMagicCookieSize ; + + // For historical reasons the decoder needs to be resilient to magic cookies vended by older encoders. + // As specified in the ALACMagicCookieDescription.txt document, there may be additional data encapsulating + // the ALACSpecificConfig. This would consist of format ('frma') and 'alac' atoms which precede the + // ALACSpecificConfig. + // See ALACMagicCookieDescription.txt for additional documentation concerning the 'magic cookie' + + // skip format ('frma') atom if present + if (theActualCookie [4] == 'f' && theActualCookie [5] == 'r' && theActualCookie [6] == 'm' && theActualCookie [7] == 'a') + { + theActualCookie += 12 ; + theCookieBytesRemaining -= 12 ; + } + + // skip 'alac' atom header if present + if (theActualCookie [4] == 'a' && theActualCookie [5] == 'l' && theActualCookie [6] == 'a' && theActualCookie [7] == 'c') + { + theActualCookie += 12 ; + theCookieBytesRemaining -= 12 ; + } + + // read the ALACSpecificConfig + if (theCookieBytesRemaining >= sizeof (ALACSpecificConfig)) + { + theConfig.frameLength = psf_get_be32 (theActualCookie, offsetof (ALACSpecificConfig, frameLength)) ; + + if (theConfig.frameLength > ALAC_FRAME_LENGTH) + return fALAC_FrameLengthError ; + + theConfig.compatibleVersion = theActualCookie [offsetof (ALACSpecificConfig, compatibleVersion)] ; + theConfig.bitDepth = theActualCookie [offsetof (ALACSpecificConfig, bitDepth)] ; + theConfig.pb = theActualCookie [offsetof (ALACSpecificConfig, pb)] ; + theConfig.mb = theActualCookie [offsetof (ALACSpecificConfig, mb)] ; + theConfig.kb = theActualCookie [offsetof (ALACSpecificConfig, kb)] ; + theConfig.numChannels = theActualCookie [offsetof (ALACSpecificConfig, numChannels)] ; + theConfig.maxRun = psf_get_be16 (theActualCookie, offsetof (ALACSpecificConfig, maxRun)) ; + theConfig.maxFrameBytes = psf_get_be32 (theActualCookie, offsetof (ALACSpecificConfig, maxFrameBytes)) ; + theConfig.avgBitRate = psf_get_be32 (theActualCookie, offsetof (ALACSpecificConfig, avgBitRate)) ; + theConfig.sampleRate = psf_get_be32 (theActualCookie, offsetof (ALACSpecificConfig, sampleRate)) ; + + p->mConfig = theConfig ; + p->mNumChannels = theConfig.numChannels ; + + RequireAction (p->mConfig.compatibleVersion <= kALACVersion, return kALAC_IncompatibleVersion ;) ; + RequireAction ((p->mConfig.bitDepth >= 8 && p->mConfig.bitDepth <= 32), return kALAC_BadBitWidth ;) ; + RequireAction ((p->mMixBufferU != NULL) && (p->mMixBufferV != NULL) && (p->u.mPredictor != NULL), + status = kALAC_MemFullError ; goto Exit ;) ; + } + else + { + status = kALAC_BadSpecificConfigSize ; + } + + // skip to Channel Layout Info + // theActualCookie += sizeof (ALACSpecificConfig) ; + + // Currently, the Channel Layout Info portion of the magic cookie (as defined in the + // ALACMagicCookieDescription.txt document) is unused by the decoder. + +Exit: + return status ; +} + +/* + Decode () + - the decoded samples are interleaved into the output buffer in the order they arrive in + the bitstream +*/ +int32_t +alac_decode (ALAC_DECODER *p, struct BitBuffer * bits, int32_t * sampleBuffer, uint32_t numSamples, uint32_t * outNumSamples) +{ + BitBuffer shiftBits ; + uint32_t bits1, bits2 ; + uint8_t tag ; + uint8_t elementInstanceTag ; + AGParamRec agParams ; + uint32_t channelIndex ; + int16_t coefsU [32] ; // max possible size is 32 although NUMCOEPAIRS is the current limit + int16_t coefsV [32] ; + uint8_t numU, numV ; + uint8_t mixBits ; + int8_t mixRes ; + uint16_t unusedHeader ; + uint8_t escapeFlag ; + uint32_t chanBits ; + uint8_t bytesShifted ; + uint32_t shift ; + uint8_t modeU, modeV ; + uint32_t denShiftU, denShiftV ; + uint16_t pbFactorU, pbFactorV ; + uint16_t pb ; + int32_t * out32 ; + uint8_t headerByte ; + uint8_t partialFrame ; + uint32_t extraBits ; + int32_t val ; + uint32_t i, j ; + int32_t status ; + uint32_t numChannels = p->mNumChannels ; + + RequireAction ((bits != NULL) && (sampleBuffer != NULL) && (outNumSamples != NULL), return kALAC_ParamError ;) ; + RequireAction (p->mNumChannels > 0, return kALAC_ZeroChannelCount ;) ; + + p->mActiveElements = 0 ; + channelIndex = 0 ; + + status = ALAC_noErr ; + *outNumSamples = numSamples ; + + while (status == ALAC_noErr) + { + // bail if we ran off the end of the buffer + RequireAction (bits->cur < bits->end, status = kALAC_ParamError ; goto Exit ;) ; + + // copy global decode params for this element + pb = p->mConfig.pb ; + + // read element tag + tag = BitBufferReadSmall (bits, 3) ; + switch (tag) + { + case ID_SCE: + case ID_LFE: + { + // mono/LFE channel + elementInstanceTag = BitBufferReadSmall (bits, 4) ; + p->mActiveElements |= (1u << elementInstanceTag) ; + + // read the 12 unused header bits + unusedHeader = (uint16_t) BitBufferRead (bits, 12) ; + RequireAction (unusedHeader == 0, status = kALAC_ParamError ; goto Exit ;) ; + + // read the 1-bit "partial frame" flag, 2-bit "shift-off" flag & 1-bit "escape" flag + headerByte = (uint8_t) BitBufferRead (bits, 4) ; + + partialFrame = headerByte >> 3 ; + + bytesShifted = (headerByte >> 1) & 0x3u ; + RequireAction (bytesShifted != 3, status = kALAC_ParamError ; goto Exit ;) ; + + shift = bytesShifted * 8 ; + + escapeFlag = headerByte & 0x1 ; + + chanBits = p->mConfig.bitDepth - (bytesShifted * 8) ; + + // check for partial frame to override requested numSamples + if (partialFrame != 0) + { + numSamples = BitBufferRead (bits, 16) << 16 ; + numSamples |= BitBufferRead (bits, 16) ; + + RequireAction (numSamples < kALACDefaultFramesPerPacket, return kALAC_NumSamplesTooBig ;) ; + } + + if (escapeFlag == 0) + { + // compressed frame, read rest of parameters + mixBits = (uint8_t) BitBufferRead (bits, 8) ; + mixRes = (int8_t) BitBufferRead (bits, 8) ; + //Assert ((mixBits == 0) && (mixRes == 0)) ; // no mixing for mono + + headerByte = (uint8_t) BitBufferRead (bits, 8) ; + modeU = headerByte >> 4 ; + denShiftU = headerByte & 0xfu ; + + headerByte = (uint8_t) BitBufferRead (bits, 8) ; + pbFactorU = headerByte >> 5 ; + numU = headerByte & 0x1fu ; + + for (i = 0 ; i < numU ; i++) + coefsU [i] = (int16_t) BitBufferRead (bits, 16) ; + + // if shift active, skip the shift buffer but remember where it starts + if (bytesShifted != 0) + { + shiftBits = *bits ; + BitBufferAdvance (bits, (bytesShifted * 8) * numSamples) ; + } + + // decompress + set_ag_params (&agParams, p->mConfig.mb, (pb * pbFactorU) / 4, p->mConfig.kb, numSamples, numSamples, p->mConfig.maxRun) ; + status = dyn_decomp (&agParams, bits, p->u.mPredictor, numSamples, chanBits, &bits1) ; + RequireNoErr (status, goto Exit ;) ; + + if (modeU == 0) + { + unpc_block (p->u.mPredictor, p->mMixBufferU, numSamples, &coefsU [0], numU, chanBits, denShiftU) ; + } + else + { + // the special "numActive == 31" mode can be done in-place + unpc_block (p->u.mPredictor, p->u.mPredictor, numSamples, NULL, 31, chanBits, 0) ; + unpc_block (p->u.mPredictor, p->mMixBufferU, numSamples, &coefsU [0], numU, chanBits, denShiftU) ; + } + } + else + { + //Assert (bytesShifted == 0) ; + + // uncompressed frame, copy data into the mix buffer to use common output code + shift = 32 - chanBits ; + if (chanBits <= 16) + { + for (i = 0 ; i < numSamples ; i++) + { + val = (int32_t) BitBufferRead (bits, (uint8_t) chanBits) ; + val = (val << shift) >> shift ; + p->mMixBufferU [i] = val ; + } + } + else + { + // BitBufferRead () can't read more than 16 bits at a time so break up the reads + extraBits = chanBits - 16 ; + for (i = 0 ; i < numSamples ; i++) + { + val = (int32_t) BitBufferRead (bits, 16) ; + val = arith_shift_left (val, 16) >> shift ; + p->mMixBufferU [i] = val | BitBufferRead (bits, (uint8_t) extraBits) ; + } + } + + mixBits = mixRes = 0 ; + bits1 = chanBits * numSamples ; + bytesShifted = 0 ; + } + + // now read the shifted values into the shift buffer + if (bytesShifted != 0) + { + shift = bytesShifted * 8 ; + //Assert (shift <= 16) ; + + for (i = 0 ; i < numSamples ; i++) + p->u.mShiftBuffer [i] = (uint16_t) BitBufferRead (&shiftBits, (uint8_t) shift) ; + } + + // convert 32-bit integers into output buffer + switch (p->mConfig.bitDepth) + { + case 16: + out32 = sampleBuffer + channelIndex ; + for (i = 0, j = 0 ; i < numSamples ; i++, j += numChannels) + out32 [j] = arith_shift_left (p->mMixBufferU [i], 16) ; + break ; + case 20: + out32 = sampleBuffer + channelIndex ; + copyPredictorTo20 (p->mMixBufferU, out32, numChannels, numSamples) ; + break ; + case 24: + out32 = sampleBuffer + channelIndex ; + if (bytesShifted != 0) + copyPredictorTo24Shift (p->mMixBufferU, p->u.mShiftBuffer, out32, numChannels, numSamples, bytesShifted) ; + else + copyPredictorTo24 (p->mMixBufferU, out32, numChannels, numSamples) ; + break ; + case 32: + out32 = sampleBuffer + channelIndex ; + if (bytesShifted != 0) + copyPredictorTo32Shift (p->mMixBufferU, p->u.mShiftBuffer, out32, numChannels, numSamples, bytesShifted) ; + else + copyPredictorTo32 (p->mMixBufferU, out32, numChannels, numSamples) ; + break ; + } + + channelIndex += 1 ; + *outNumSamples = numSamples ; + break ; + } + + case ID_CPE: + { + // if decoding this pair would take us over the max channels limit, bail + if ((channelIndex + 2) > numChannels) + goto NoMoreChannels ; + + // stereo channel pair + elementInstanceTag = BitBufferReadSmall (bits, 4) ; + p->mActiveElements |= (1u << elementInstanceTag) ; + + // read the 12 unused header bits + unusedHeader = (uint16_t) BitBufferRead (bits, 12) ; + RequireAction (unusedHeader == 0, status = kALAC_ParamError ; goto Exit ;) ; + + // read the 1-bit "partial frame" flag, 2-bit "shift-off" flag & 1-bit "escape" flag + headerByte = (uint8_t) BitBufferRead (bits, 4) ; + + partialFrame = headerByte >> 3 ; + + bytesShifted = (headerByte >> 1) & 0x3u ; + RequireAction (bytesShifted != 3, status = kALAC_ParamError ; goto Exit ;) ; + + shift = bytesShifted * 8 ; + + escapeFlag = headerByte & 0x1 ; + + chanBits = p->mConfig.bitDepth - (bytesShifted * 8) + 1 ; + + // check for partial frame length to override requested numSamples + if (partialFrame != 0) + { + numSamples = BitBufferRead (bits, 16) << 16 ; + numSamples |= BitBufferRead (bits, 16) ; + + RequireAction (numSamples < kALACDefaultFramesPerPacket, return kALAC_NumSamplesTooBig ;) ; + } + + if (escapeFlag == 0) + { + // compressed frame, read rest of parameters + mixBits = (uint8_t) BitBufferRead (bits, 8) ; + mixRes = (int8_t) BitBufferRead (bits, 8) ; + + headerByte = (uint8_t) BitBufferRead (bits, 8) ; + modeU = headerByte >> 4 ; + denShiftU = headerByte & 0xfu ; + + headerByte = (uint8_t) BitBufferRead (bits, 8) ; + pbFactorU = headerByte >> 5 ; + numU = headerByte & 0x1fu ; + for (i = 0 ; i < numU ; i++) + coefsU [i] = (int16_t) BitBufferRead (bits, 16) ; + + headerByte = (uint8_t) BitBufferRead (bits, 8) ; + modeV = headerByte >> 4 ; + denShiftV = headerByte & 0xfu ; + + headerByte = (uint8_t) BitBufferRead (bits, 8) ; + pbFactorV = headerByte >> 5 ; + numV = headerByte & 0x1fu ; + for (i = 0 ; i < numV ; i++) + coefsV [i] = (int16_t) BitBufferRead (bits, 16) ; + + // if shift active, skip the interleaved shifted values but remember where they start + if (bytesShifted != 0) + { + shiftBits = *bits ; + BitBufferAdvance (bits, (bytesShifted * 8) * 2 * numSamples) ; + } + + // decompress and run predictor for "left" channel + set_ag_params (&agParams, p->mConfig.mb, (pb * pbFactorU) / 4, p->mConfig.kb, numSamples, numSamples, p->mConfig.maxRun) ; + status = dyn_decomp (&agParams, bits, p->u.mPredictor, numSamples, chanBits, &bits1) ; + RequireNoErr (status, goto Exit ;) ; + + if (modeU == 0) + { + unpc_block (p->u.mPredictor, p->mMixBufferU, numSamples, &coefsU [0], numU, chanBits, denShiftU) ; + } + else + { + // the special "numActive == 31" mode can be done in-place + unpc_block (p->u.mPredictor, p->u.mPredictor, numSamples, NULL, 31, chanBits, 0) ; + unpc_block (p->u.mPredictor, p->mMixBufferU, numSamples, &coefsU [0], numU, chanBits, denShiftU) ; + } + + // decompress and run predictor for "right" channel + set_ag_params (&agParams, p->mConfig.mb, (pb * pbFactorV) / 4, p->mConfig.kb, numSamples, numSamples, p->mConfig.maxRun) ; + status = dyn_decomp (&agParams, bits, p->u.mPredictor, numSamples, chanBits, &bits2) ; + RequireNoErr (status, goto Exit ;) ; + + if (modeV == 0) + { + unpc_block (p->u.mPredictor, p->mMixBufferV, numSamples, &coefsV [0], numV, chanBits, denShiftV) ; + } + else + { + // the special "numActive == 31" mode can be done in-place + unpc_block (p->u.mPredictor, p->u.mPredictor, numSamples, NULL, 31, chanBits, 0) ; + unpc_block (p->u.mPredictor, p->mMixBufferV, numSamples, &coefsV [0], numV, chanBits, denShiftV) ; + } + } + else + { + //Assert (bytesShifted == 0) ; + + // uncompressed frame, copy data into the mix buffers to use common output code + chanBits = p->mConfig.bitDepth ; + shift = 32 - chanBits ; + if (chanBits <= 16) + { + for (i = 0 ; i < numSamples ; i++) + { + val = (int32_t) BitBufferRead (bits, (uint8_t) chanBits) ; + val = (val << shift) >> shift ; + p->mMixBufferU [i] = val ; + + val = (int32_t) BitBufferRead (bits, (uint8_t) chanBits) ; + val = (val << shift) >> shift ; + p->mMixBufferV [i] = val ; + } + } + else + { + // BitBufferRead () can't read more than 16 bits at a time so break up the reads + extraBits = chanBits - 16 ; + for (i = 0 ; i < numSamples ; i++) + { + val = (int32_t) BitBufferRead (bits, 16) ; + val = (((uint32_t) val) << 16) >> shift ; + p->mMixBufferU [i] = val | BitBufferRead (bits, (uint8_t) extraBits) ; + + val = (int32_t) BitBufferRead (bits, 16) ; + val = ((uint32_t) val) >> shift ; + p->mMixBufferV [i] = val | BitBufferRead (bits, (uint8_t) extraBits) ; + } + } + + bits1 = chanBits * numSamples ; + bits2 = chanBits * numSamples ; + mixBits = mixRes = 0 ; + bytesShifted = 0 ; + } + + // now read the shifted values into the shift buffer + if (bytesShifted != 0) + { + shift = bytesShifted * 8 ; + //Assert (shift <= 16) ; + + for (i = 0 ; i < (numSamples * 2) ; i += 2) + { + p->u.mShiftBuffer [i + 0] = (uint16_t) BitBufferRead (&shiftBits, (uint8_t) shift) ; + p->u.mShiftBuffer [i + 1] = (uint16_t) BitBufferRead (&shiftBits, (uint8_t) shift) ; + } + } + + // un-mix the data and convert to output format + // - note that mixRes = 0 means just interleave so we use that path for uncompressed frames + switch (p->mConfig.bitDepth) + { + case 16: + out32 = sampleBuffer + channelIndex ; + unmix16 (p->mMixBufferU, p->mMixBufferV, out32, numChannels, numSamples, mixBits, mixRes) ; + break ; + case 20: + out32 = sampleBuffer + channelIndex ; + unmix20 (p->mMixBufferU, p->mMixBufferV, out32, numChannels, numSamples, mixBits, mixRes) ; + break ; + case 24: + out32 = sampleBuffer + channelIndex ; + unmix24 (p->mMixBufferU, p->mMixBufferV, out32, numChannels, numSamples, + mixBits, mixRes, p->u.mShiftBuffer, bytesShifted) ; + break ; + case 32: + out32 = sampleBuffer + channelIndex ; + unmix32 (p->mMixBufferU, p->mMixBufferV, out32, numChannels, numSamples, + mixBits, mixRes, p->u.mShiftBuffer, bytesShifted) ; + break ; + } + + channelIndex += 2 ; + *outNumSamples = numSamples ; + break ; + } + + case ID_CCE: + case ID_PCE: + { + // unsupported element, bail + //AssertNoErr (tag) ; + status = kALAC_UnsupportedElement ; + break ; + } + + case ID_DSE: + { + // data stream element -- parse but ignore + status = alac_data_stream_element (bits) ; + break ; + } + + case ID_FIL: + { + // fill element -- parse but ignore + status = alac_fill_element (bits) ; + break ; + } + + case ID_END: + { + // frame end, all done so byte align the frame and check for overruns + BitBufferByteAlign (bits, false) ; + //Assert (bits->cur == bits->end) ; + goto Exit ; + } + } + +#if 1 // ! DEBUG + // if we've decoded all of our channels, bail (but not in debug b/c we want to know if we're seeing bad bits) + // - this also protects us if the config does not match the bitstream or crap data bits follow the audio bits + if (channelIndex >= numChannels) + break ; +#endif + } + +NoMoreChannels: + + // if we get here and haven't decoded all of the requested channels, fill the remaining channels with zeros + for ( ; channelIndex < numChannels ; channelIndex++) + { + int32_t * fill32 = sampleBuffer + channelIndex ; + Zero32 (fill32, numSamples, numChannels) ; + } + +Exit: + return status ; +} + +#if PRAGMA_MARK +#pragma mark - +#endif + +/* + FillElement () + - they're just filler so we don't need 'em +*/ +static int32_t +alac_fill_element (struct BitBuffer * bits) +{ + int16_t count ; + + // 4-bit count or (4-bit + 8-bit count) if 4-bit count == 15 + // - plus this weird -1 thing I still don't fully understand + count = BitBufferReadSmall (bits, 4) ; + if (count == 15) + count += (int16_t) BitBufferReadSmall (bits, 8) - 1 ; + + BitBufferAdvance (bits, count * 8) ; + + RequireAction (bits->cur <= bits->end, return kALAC_ParamError ;) ; + + return ALAC_noErr ; +} + +/* + DataStreamElement () + - we don't care about data stream elements so just skip them +*/ +static int32_t +alac_data_stream_element (struct BitBuffer * bits) +{ + int32_t data_byte_align_flag ; + uint16_t count ; + + // the tag associates this data stream element with a given audio element + + /* element_instance_tag = */ BitBufferReadSmall (bits, 4) ; + + data_byte_align_flag = BitBufferReadOne (bits) ; + + // 8-bit count or (8-bit + 8-bit count) if 8-bit count == 255 + count = BitBufferReadSmall (bits, 8) ; + if (count == 255) + count += BitBufferReadSmall (bits, 8) ; + + // the align flag means the bitstream should be byte-aligned before reading the following data bytes + if (data_byte_align_flag) + BitBufferByteAlign (bits, false) ; + + // skip the data bytes + BitBufferAdvance (bits, count * 8) ; + + RequireAction (bits->cur <= bits->end, return kALAC_ParamError ;) ; + + return ALAC_noErr ; +} + +/* + ZeroN () + - helper routines to clear out output channel buffers when decoding fewer channels than requested +*/ +static void Zero32 (int32_t * buffer, uint32_t numItems, uint32_t stride) +{ + if (stride == 1) + { + memset (buffer, 0, numItems * sizeof (int32_t)) ; + } + else + { + for (uint32_t indx = 0 ; indx < (numItems * stride) ; indx += stride) + buffer [indx] = 0 ; + } +} diff --git a/extern/libsndfile-modified/src/ALAC/alac_decoder.h b/extern/libsndfile-modified/src/ALAC/alac_decoder.h new file mode 100644 index 000000000..8a4359226 --- /dev/null +++ b/extern/libsndfile-modified/src/ALAC/alac_decoder.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2011 Apple Inc. All rights reserved. + * + * @APPLE_APACHE_LICENSE_HEADER_START@ + * + * Licensed under the Apache License, Version 2.0 (the "License") ; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @APPLE_APACHE_LICENSE_HEADER_END@ + */ + +/* + File: alac_decoder.h +*/ + +#ifndef ALAC_DECODER_H +#define ALAC_DECODER_H + +#include + +#include "ALACAudioTypes.h" + +typedef enum +{ + false = 0, + ALAC_TRUE = 1 +} bool ; + +struct BitBuffer ; + +typedef struct alac_decoder +{ + // decoding parameters (public for use in the analyzer) + ALACSpecificConfig mConfig ; + + uint16_t mActiveElements ; + + // decoding buffers + int32_t * mMixBufferU ; + int32_t * mMixBufferV ; + int32_t * mPredictor ; + uint16_t * mShiftBuffer ; // note: this points to mPredictor's memory but different + // variable for clarity and type difference +} alac_decoder ; + +alac_decoder * alac_decoder_new (void) ; +void alac_decoder_delete (alac_decoder *) ; + +int32_t alac_init (alac_decoder *p, void * inMagicCookie, uint32_t inMagicCookieSize) ; +int32_t alac_decode (alac_decoder *, struct BitBuffer * bits, uint8_t * sampleBuffer, uint32_t numSamples, uint32_t numChannels, uint32_t * outNumSamples) ; + +#endif /* ALAC_DECODER_H */ diff --git a/extern/libsndfile-modified/src/ALAC/alac_encoder.c b/extern/libsndfile-modified/src/ALAC/alac_encoder.c new file mode 100644 index 000000000..599399afe --- /dev/null +++ b/extern/libsndfile-modified/src/ALAC/alac_encoder.c @@ -0,0 +1,1333 @@ +/* + * Copyright (c) 2011 Apple Inc. All rights reserved. + * Copyright (C) 2012-2015 Erik de Castro Lopo + * + * @APPLE_APACHE_LICENSE_HEADER_START@ + * + * Licensed under the Apache License, Version 2.0 (the "License") ; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @APPLE_APACHE_LICENSE_HEADER_END@ + */ + +/* + File: ALACEncoder.cpp +*/ + +// build stuff +#define VERBOSE_DEBUG 0 +#define DebugMsg printf + +// headers +#include +#include +#include + +#include "sfendian.h" + +#include "alac_codec.h" + +#include "aglib.h" +#include "dplib.h" +#include "matrixlib.h" + +#include "ALACBitUtilities.h" +#include "ALACAudioTypes.h" +#include "EndianPortable.h" + +typedef enum +{ + false = 0, + true = 1 +} bool ; + +static void GetConfig (ALAC_ENCODER *p, ALACSpecificConfig * config) ; + +static int32_t EncodeStereo (ALAC_ENCODER *p, struct BitBuffer * bitstream, const int32_t * input, uint32_t stride, uint32_t channelIndex, uint32_t numSamples) ; +static int32_t EncodeStereoFast (ALAC_ENCODER *p, struct BitBuffer * bitstream, const int32_t * input, uint32_t stride, uint32_t channelIndex, uint32_t numSamples) ; +static int32_t EncodeStereoEscape (ALAC_ENCODER *p, struct BitBuffer * bitstream, const int32_t * input, uint32_t stride, uint32_t numSamples) ; +static int32_t EncodeMono (ALAC_ENCODER *p, struct BitBuffer * bitstream, const int32_t * input, uint32_t stride, uint32_t channelIndex, uint32_t numSamples) ; + + + +// Note: in C you can't typecast to a 2-dimensional array pointer but that's what we need when +// picking which coefs to use so we declare this typedef b/c we *can* typecast to this type +typedef int16_t (*SearchCoefs) [kALACMaxCoefs] ; + +// defines/constants +const uint32_t kALACEncoderMagic = MAKE_MARKER ('d', 'p', 'g', 'e') ; +const uint32_t kMaxSampleSize = 32 ; // max allowed bit width is 32 +const uint32_t kDefaultMixBits = 2 ; +const uint32_t kDefaultMixRes = 0 ; +const uint32_t kMaxRes = 4 ; +const uint32_t kDefaultNumUV = 8 ; +const uint32_t kMinUV = 4 ; +const uint32_t kMaxUV = 8 ; + +// static functions +#if VERBOSE_DEBUG +static void AddFiller (BitBuffer * bits, int32_t numBytes) ; +#endif + + +/* + Map Format: 3-bit field per channel which is the same as the "element tag" that should be placed + at the beginning of the frame for that channel. Indicates whether SCE, CPE, or LFE. + Each particular field is accessed via the current channel indx. Note that the channel + indx increments by two for channel pairs. + + For example: + + C L R 3-channel input = (ID_CPE << 3) | (ID_SCE) + indx 0 value = (map & (0x7ul << (0 * 3))) >> (0 * 3) + indx 1 value = (map & (0x7ul << (1 * 3))) >> (1 * 3) + + C L R Ls Rs LFE 5.1-channel input = (ID_LFE << 15) | (ID_CPE << 9) | (ID_CPE << 3) | (ID_SCE) + indx 0 value = (map & (0x7ul << (0 * 3))) >> (0 * 3) + indx 1 value = (map & (0x7ul << (1 * 3))) >> (1 * 3) + indx 3 value = (map & (0x7ul << (3 * 3))) >> (3 * 3) + indx 5 value = (map & (0x7ul << (5 * 3))) >> (5 * 3) + indx 7 value = (map & (0x7ul << (7 * 3))) >> (7 * 3) +*/ +static const uint32_t sChannelMaps [kALACMaxChannels] = +{ + ID_SCE, + ID_CPE, + (ID_CPE << 3) | (ID_SCE), + (ID_SCE << 9) | (ID_CPE << 3) | (ID_SCE), + (ID_CPE << 9) | (ID_CPE << 3) | (ID_SCE), + (ID_SCE << 15) | (ID_CPE << 9) | (ID_CPE << 3) | (ID_SCE), + (ID_SCE << 18) | (ID_SCE << 15) | (ID_CPE << 9) | (ID_CPE << 3) | (ID_SCE), + (ID_SCE << 21) | (ID_CPE << 15) | (ID_CPE << 9) | (ID_CPE << 3) | (ID_SCE) +} ; + +#if PRAGMA_MARK +#pragma mark - +#endif + +void +alac_set_fastmode (ALAC_ENCODER * p, int32_t fast) +{ + p->mFastMode = fast ; +} + + +/* + HEADER SPECIFICATION + + For every segment we adopt the following header: + + 1 byte reserved (always 0) + 1 byte flags (see below) + [4 byte frame length] (optional, see below) + ---Next, the per-segment ALAC parameters--- + 1 byte mixBits (middle-side parameter) + 1 byte mixRes (middle-side parameter, interpreted as signed char) + + 1 byte shiftU (4 bits modeU, 4 bits denShiftU) + 1 byte filterU (3 bits pbFactorU, 5 bits numU) + (numU) shorts (signed DP coefficients for V channel) + ---Next, 2nd-channel ALAC parameters in case of stereo mode--- + 1 byte shiftV (4 bits modeV, 4 bits denShiftV) + 1 byte filterV (3 bits pbFactorV, 5 bits numV) + (numV) shorts (signed DP coefficients for V channel) + ---After this come the shift-off bytes for (>= 24)-bit data (n-byte shift) if indicated--- + ---Then comes the AG-compressor bitstream--- + + + FLAGS + ----- + + The presence of certain flag bits changes the header format such that the parameters might + not even be sent. The currently defined flags format is: + + 0000psse + + where 0 = reserved, must be 0 + p = 1-bit field "partial frame" flag indicating 32-bit frame length follows this byte + ss = 2-bit field indicating "number of shift-off bytes ignored by compression" + e = 1-bit field indicating "escape" + + The "partial frame" flag means that the following segment is not equal to the frame length specified + in the out-of-band decoder configuration. This allows the decoder to deal with end-of-file partial + segments without incurring the 32-bit overhead for each segment. + + The "shift-off" field indicates the number of bytes at the bottom of the word that were passed through + uncompressed. The reason for this is that the entropy inherent in the LS bytes of >= 24-bit words + quite often means that the frame would have to be "escaped" b/c the compressed size would be >= the + uncompressed size. However, by shifting the input values down and running the remaining bits through + the normal compression algorithm, a net win can be achieved. If this field is non-zero, it means that + the shifted-off bytes follow after the parameter section of the header and before the compressed + bitstream. Note that doing this also allows us to use matrixing on 32-bit inputs after one or more + bytes are shifted off the bottom which helps the eventual compression ratio. For stereo channels, + the shifted off bytes are interleaved. + + The "escape" flag means that this segment was not compressed b/c the compressed size would be + >= uncompressed size. In that case, the audio data was passed through uncompressed after the header. + The other header parameter bytes will not be sent. + + + PARAMETERS + ---------- + + If the segment is not a partial or escape segment, the total header size (in bytes) is given exactly by: + + 4 + (2 + 2 * numU) (mono mode) + 4 + (2 + 2 * numV) + (2 + 2 * numV) (stereo mode) + + where the ALAC filter-lengths numU, numV are bounded by a + constant (in the current source, numU, numV <= NUMCOEPAIRS), and + this forces an absolute upper bound on header size. + + Each segment-decode process loads up these bytes from the front of the + local stream, in the above order, then follows with the entropy-encoded + bits for the given segment. + + To generalize middle-side, there are various mixing modes including middle-side, each lossless, + as embodied in the mix () and unmix () functions. These functions exploit a generalized middle-side + transformation: + + u := [(rL + (m-r)R)/m] ; + v := L - R ; + + where [ ] denotes integer floor. The (lossless) inverse is + + L = u + v - [rV/m] ; + R = L - v ; + + In the segment header, m and r are encoded in mixBits and mixRes. + Classical "middle-side" is obtained with m = 2, r = 1, but now + we have more generalized mixes. + + NOTES + ----- + The relevance of the ALAC coefficients is explained in detail + in patent documents. +*/ + +/* + EncodeStereo () + - encode a channel pair +*/ +static int32_t +EncodeStereo (ALAC_ENCODER *p, struct BitBuffer * bitstream, const int32_t * inputBuffer, uint32_t stride, uint32_t channelIndex, uint32_t numSamples) +{ + BitBuffer workBits ; + BitBuffer startBits = *bitstream ; // squirrel away copy of current state in case we need to go back and do an escape packet + AGParamRec agParams ; + uint32_t bits1, bits2 ; + uint32_t dilate ; + int32_t mixBits, mixRes, maxRes ; + uint32_t minBits, minBits1, minBits2 ; + uint32_t numU, numV ; + uint32_t mode ; + uint32_t pbFactor ; + uint32_t chanBits ; + uint8_t bytesShifted ; + SearchCoefs coefsU ; + SearchCoefs coefsV ; + uint32_t indx ; + uint8_t partialFrame ; + uint32_t escapeBits ; + bool doEscape ; + int32_t status = ALAC_noErr ; + int32_t bestRes ; + + // make sure we handle this bit-depth before we get going + RequireAction ((p->mBitDepth == 16) || (p->mBitDepth == 20) || (p->mBitDepth == 24) || (p->mBitDepth == 32), return kALAC_ParamError ;) ; + + // reload coefs pointers for this channel pair + // - note that, while you might think they should be re-initialized per block, retaining state across blocks + // actually results in better overall compression + // - strangely, re-using the same coefs for the different passes of the "mixRes" search loop instead of using + // different coefs for the different passes of "mixRes" results in even better compression + coefsU = (SearchCoefs) p->mCoefsU [channelIndex] ; + coefsV = (SearchCoefs) p->mCoefsV [channelIndex] ; + + // matrix encoding adds an extra bit but 32-bit inputs cannot be matrixed b/c 33 is too many + // so enable 16-bit "shift off" and encode in 17-bit mode + // - in addition, 24-bit mode really improves with one byte shifted off + if (p->mBitDepth == 32) + bytesShifted = 2 ; + else if (p->mBitDepth >= 24) + bytesShifted = 1 ; + else + bytesShifted = 0 ; + + chanBits = p->mBitDepth - (bytesShifted * 8) + 1 ; + + // flag whether or not this is a partial frame + partialFrame = (numSamples == p->mFrameSize) ? 0 : 1 ; + + // brute-force encode optimization loop + // - run over variations of the encoding params to find the best choice + mixBits = kDefaultMixBits ; + maxRes = kMaxRes ; + numU = numV = kDefaultNumUV ; + mode = 0 ; + pbFactor = 4 ; + dilate = 8 ; + + minBits = minBits1 = minBits2 = 1ul << 31 ; + + bestRes = p->mLastMixRes [channelIndex] ; + + for (mixRes = 0 ; mixRes <= maxRes ; mixRes++) + { + // mix the stereo inputs + switch (p->mBitDepth) + { + case 16: + mix16 (inputBuffer, stride, p->mMixBufferU, p->mMixBufferV, numSamples / dilate, mixBits, mixRes) ; + break ; + case 20: + mix20 (inputBuffer, stride, p->mMixBufferU, p->mMixBufferV, numSamples / dilate, mixBits, mixRes) ; + break ; + case 24: + // includes extraction of shifted-off bytes + mix24 (inputBuffer, stride, p->mMixBufferU, p->mMixBufferV, numSamples / dilate, + mixBits, mixRes, p->mShiftBufferUV, bytesShifted) ; + break ; + case 32: + // includes extraction of shifted-off bytes + mix32 (inputBuffer, stride, p->mMixBufferU, p->mMixBufferV, numSamples / dilate, + mixBits, mixRes, p->mShiftBufferUV, bytesShifted) ; + break ; + } + + BitBufferInit (&workBits, p->mWorkBuffer, p->mMaxOutputBytes) ; + + // run the dynamic predictors + pc_block (p->mMixBufferU, p->mPredictorU, numSamples / dilate, coefsU [numU - 1], numU, chanBits, DENSHIFT_DEFAULT) ; + pc_block (p->mMixBufferV, p->mPredictorV, numSamples / dilate, coefsV [numV - 1], numV, chanBits, DENSHIFT_DEFAULT) ; + + // run the lossless compressor on each channel + set_ag_params (&agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples / dilate, numSamples / dilate, MAX_RUN_DEFAULT) ; + status = dyn_comp (&agParams, p->mPredictorU, &workBits, numSamples / dilate, chanBits, &bits1) ; + RequireNoErr (status, goto Exit ;) ; + + set_ag_params (&agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples / dilate, numSamples / dilate, MAX_RUN_DEFAULT) ; + status = dyn_comp (&agParams, p->mPredictorV, &workBits, numSamples / dilate, chanBits, &bits2) ; + RequireNoErr (status, goto Exit ;) ; + + // look for best match + if ((bits1 + bits2) < minBits1) + { + minBits1 = bits1 + bits2 ; + bestRes = mixRes ; + } + } + + p->mLastMixRes [channelIndex] = (int16_t) bestRes ; + + // mix the stereo inputs with the current best mixRes + mixRes = p->mLastMixRes [channelIndex] ; + switch (p->mBitDepth) + { + case 16: + mix16 (inputBuffer, stride, p->mMixBufferU, p->mMixBufferV, numSamples, mixBits, mixRes) ; + break ; + case 20: + mix20 (inputBuffer, stride, p->mMixBufferU, p->mMixBufferV, numSamples, mixBits, mixRes) ; + break ; + case 24: + // also extracts the shifted off bytes into the shift buffers + mix24 (inputBuffer, stride, p->mMixBufferU, p->mMixBufferV, numSamples, + mixBits, mixRes, p->mShiftBufferUV, bytesShifted) ; + break ; + case 32: + // also extracts the shifted off bytes into the shift buffers + mix32 (inputBuffer, stride, p->mMixBufferU, p->mMixBufferV, numSamples, + mixBits, mixRes, p->mShiftBufferUV, bytesShifted) ; + break ; + } + + // now it's time for the predictor coefficient search loop + numU = numV = kMinUV ; + minBits1 = minBits2 = 1ul << 31 ; + + for (uint32_t numUV = kMinUV ; numUV <= kMaxUV ; numUV += 4) + { + BitBufferInit (&workBits, p->mWorkBuffer, p->mMaxOutputBytes) ; + + dilate = 32 ; + + // run the predictor over the same data multiple times to help it converge + for (uint32_t converge = 0 ; converge < 8 ; converge++) + { + pc_block (p->mMixBufferU, p->mPredictorU, numSamples / dilate, coefsU [numUV-1], numUV, chanBits, DENSHIFT_DEFAULT) ; + pc_block (p->mMixBufferV, p->mPredictorV, numSamples / dilate, coefsV [numUV-1], numUV, chanBits, DENSHIFT_DEFAULT) ; + } + + dilate = 8 ; + + set_ag_params (&agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples / dilate, numSamples / dilate, MAX_RUN_DEFAULT) ; + status = dyn_comp (&agParams, p->mPredictorU, &workBits, numSamples / dilate, chanBits, &bits1) ; + + if ((bits1 * dilate + 16 * numUV) < minBits1) + { + minBits1 = bits1 * dilate + 16 * numUV ; + numU = numUV ; + } + + set_ag_params (&agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples / dilate, numSamples / dilate, MAX_RUN_DEFAULT) ; + status = dyn_comp (&agParams, p->mPredictorV, &workBits, numSamples / dilate, chanBits, &bits2) ; + + if ((bits2 * dilate + 16 * numUV) < minBits2) + { + minBits2 = bits2 * dilate + 16 * numUV ; + numV = numUV ; + } + } + + // test for escape hatch if best calculated compressed size turns out to be more than the input size + minBits = minBits1 + minBits2 + (8 /* mixRes/maxRes/etc. */ * 8) + ((partialFrame == true) ? 32 : 0) ; + if (bytesShifted != 0) + minBits += (numSamples * (bytesShifted * 8) * 2) ; + + escapeBits = (numSamples * p->mBitDepth * 2) + ((partialFrame == true) ? 32 : 0) + (2 * 8) ; /* 2 common header bytes */ + + doEscape = (minBits >= escapeBits) ? true : false ; + + if (doEscape == false) + { + // write bitstream header and coefs + BitBufferWrite (bitstream, 0, 12) ; + BitBufferWrite (bitstream, (partialFrame << 3) | (bytesShifted << 1), 4) ; + if (partialFrame) + BitBufferWrite (bitstream, numSamples, 32) ; + BitBufferWrite (bitstream, mixBits, 8) ; + BitBufferWrite (bitstream, mixRes, 8) ; + + //Assert ((mode < 16) && (DENSHIFT_DEFAULT < 16)) ; + //Assert ((pbFactor < 8) && (numU < 32)) ; + //Assert ((pbFactor < 8) && (numV < 32)) ; + + BitBufferWrite (bitstream, (mode << 4) | DENSHIFT_DEFAULT, 8) ; + BitBufferWrite (bitstream, (pbFactor << 5) | numU, 8) ; + for (indx = 0 ; indx < numU ; indx++) + BitBufferWrite (bitstream, coefsU [numU - 1][indx], 16) ; + + BitBufferWrite (bitstream, (mode << 4) | DENSHIFT_DEFAULT, 8) ; + BitBufferWrite (bitstream, (pbFactor << 5) | numV, 8) ; + for (indx = 0 ; indx < numV ; indx++) + BitBufferWrite (bitstream, coefsV [numV - 1][indx], 16) ; + + // if shift active, write the interleaved shift buffers + if (bytesShifted != 0) + { + uint32_t bitShift = bytesShifted * 8 ; + + //Assert (bitShift <= 16) ; + + for (indx = 0 ; indx < (numSamples * 2) ; indx += 2) + { + uint32_t shiftedVal ; + + shiftedVal = ((uint32_t) p->mShiftBufferUV [indx + 0] << bitShift) | (uint32_t) p->mShiftBufferUV [indx + 1] ; + BitBufferWrite (bitstream, shiftedVal, bitShift * 2) ; + } + } + + // run the dynamic predictor and lossless compression for the "left" channel + // - note: to avoid allocating more buffers, we're mixing and matching between the available buffers instead + // of only using "U" buffers for the U-channel and "V" buffers for the V-channel + if (mode == 0) + { + pc_block (p->mMixBufferU, p->mPredictorU, numSamples, coefsU [numU - 1], numU, chanBits, DENSHIFT_DEFAULT) ; + } + else + { + pc_block (p->mMixBufferU, p->mPredictorV, numSamples, coefsU [numU - 1], numU, chanBits, DENSHIFT_DEFAULT) ; + pc_block (p->mPredictorV, p->mPredictorU, numSamples, NULL, 31, chanBits, 0) ; + } + + set_ag_params (&agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples, numSamples, MAX_RUN_DEFAULT) ; + status = dyn_comp (&agParams, p->mPredictorU, bitstream, numSamples, chanBits, &bits1) ; + RequireNoErr (status, goto Exit ;) ; + + // run the dynamic predictor and lossless compression for the "right" channel + if (mode == 0) + { + pc_block (p->mMixBufferV, p->mPredictorV, numSamples, coefsV [numV - 1], numV, chanBits, DENSHIFT_DEFAULT) ; + } + else + { + pc_block (p->mMixBufferV, p->mPredictorU, numSamples, coefsV [numV - 1], numV, chanBits, DENSHIFT_DEFAULT) ; + pc_block (p->mPredictorU, p->mPredictorV, numSamples, NULL, 31, chanBits, 0) ; + } + + set_ag_params (&agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples, numSamples, MAX_RUN_DEFAULT) ; + status = dyn_comp (&agParams, p->mPredictorV, bitstream, numSamples, chanBits, &bits2) ; + RequireNoErr (status, goto Exit ;) ; + + /* if we happened to create a compressed packet that was actually bigger than an escape packet would be, + chuck it and do an escape packet + */ + minBits = BitBufferGetPosition (bitstream) - BitBufferGetPosition (&startBits) ; + if (minBits >= escapeBits) + { + *bitstream = startBits ; // reset bitstream state + doEscape = true ; + printf ("compressed frame too big: %u vs. %u \n", minBits, escapeBits) ; + } + } + + if (doEscape == true) + { + /* escape */ + status = EncodeStereoEscape (p, bitstream, inputBuffer, stride, numSamples) ; + +#if VERBOSE_DEBUG + DebugMsg ("escape!: %u vs %u\n", minBits, escapeBits) ; +#endif + } + +Exit: + return status ; +} + +/* + EncodeStereoFast () + - encode a channel pair without the search loop for maximum possible speed +*/ +static int32_t +EncodeStereoFast (ALAC_ENCODER *p, struct BitBuffer * bitstream, const int32_t * inputBuffer, uint32_t stride, uint32_t channelIndex, uint32_t numSamples) +{ + BitBuffer startBits = *bitstream ; // squirrel away current bit position in case we decide to use escape hatch + AGParamRec agParams ; + uint32_t bits1, bits2 ; + int32_t mixBits, mixRes ; + uint32_t minBits, minBits1, minBits2 ; + uint32_t numU, numV ; + uint32_t mode ; + uint32_t pbFactor ; + uint32_t chanBits ; + uint8_t bytesShifted ; + SearchCoefs coefsU ; + SearchCoefs coefsV ; + uint32_t indx ; + uint8_t partialFrame ; + uint32_t escapeBits ; + bool doEscape ; + int32_t status ; + + // make sure we handle this bit-depth before we get going + RequireAction ((p->mBitDepth == 16) || (p->mBitDepth == 20) || (p->mBitDepth == 24) || (p->mBitDepth == 32), return kALAC_ParamError ;) ; + + // reload coefs pointers for this channel pair + // - note that, while you might think they should be re-initialized per block, retaining state across blocks + // actually results in better overall compression + // - strangely, re-using the same coefs for the different passes of the "mixRes" search loop instead of using + // different coefs for the different passes of "mixRes" results in even better compression + coefsU = (SearchCoefs) p->mCoefsU [channelIndex] ; + coefsV = (SearchCoefs) p->mCoefsV [channelIndex] ; + + // matrix encoding adds an extra bit but 32-bit inputs cannot be matrixed b/c 33 is too many + // so enable 16-bit "shift off" and encode in 17-bit mode + // - in addition, 24-bit mode really improves with one byte shifted off + if (p->mBitDepth == 32) + bytesShifted = 2 ; + else if (p->mBitDepth >= 24) + bytesShifted = 1 ; + else + bytesShifted = 0 ; + + chanBits = p->mBitDepth - (bytesShifted * 8) + 1 ; + + // flag whether or not this is a partial frame + partialFrame = (numSamples == p->mFrameSize) ? 0 : 1 ; + + // set up default encoding parameters for "fast" mode + mixBits = kDefaultMixBits ; + mixRes = kDefaultMixRes ; + numU = numV = kDefaultNumUV ; + mode = 0 ; + pbFactor = 4 ; + + minBits = minBits1 = minBits2 = 1ul << 31 ; + + // mix the stereo inputs with default mixBits/mixRes + switch (p->mBitDepth) + { + case 16: + mix16 (inputBuffer, stride, p->mMixBufferU, p->mMixBufferV, numSamples, mixBits, mixRes) ; + break ; + case 20: + mix20 (inputBuffer, stride, p->mMixBufferU, p->mMixBufferV, numSamples, mixBits, mixRes) ; + break ; + case 24: + // also extracts the shifted off bytes into the shift buffers + mix24 (inputBuffer, stride, p->mMixBufferU, p->mMixBufferV, numSamples, + mixBits, mixRes, p->mShiftBufferUV, bytesShifted) ; + break ; + case 32: + // also extracts the shifted off bytes into the shift buffers + mix32 (inputBuffer, stride, p->mMixBufferU, p->mMixBufferV, numSamples, + mixBits, mixRes, p->mShiftBufferUV, bytesShifted) ; + break ; + } + + /* speculatively write the bitstream assuming the compressed version will be smaller */ + + // write bitstream header and coefs + BitBufferWrite (bitstream, 0, 12) ; + BitBufferWrite (bitstream, (partialFrame << 3) | (bytesShifted << 1), 4) ; + if (partialFrame) + BitBufferWrite (bitstream, numSamples, 32) ; + BitBufferWrite (bitstream, mixBits, 8) ; + BitBufferWrite (bitstream, mixRes, 8) ; + + //Assert ((mode < 16) && (DENSHIFT_DEFAULT < 16)) ; + //Assert ((pbFactor < 8) && (numU < 32)) ; + //Assert ((pbFactor < 8) && (numV < 32)) ; + + BitBufferWrite (bitstream, (mode << 4) | DENSHIFT_DEFAULT, 8) ; + BitBufferWrite (bitstream, (pbFactor << 5) | numU, 8) ; + for (indx = 0 ; indx < numU ; indx++) + BitBufferWrite (bitstream, coefsU [numU - 1][indx], 16) ; + + BitBufferWrite (bitstream, (mode << 4) | DENSHIFT_DEFAULT, 8) ; + BitBufferWrite (bitstream, (pbFactor << 5) | numV, 8) ; + for (indx = 0 ; indx < numV ; indx++) + BitBufferWrite (bitstream, coefsV [numV - 1][indx], 16) ; + + // if shift active, write the interleaved shift buffers + if (bytesShifted != 0) + { + uint32_t bitShift = bytesShifted * 8 ; + + //Assert (bitShift <= 16) ; + + for (indx = 0 ; indx < (numSamples * 2) ; indx += 2) + { + uint32_t shiftedVal ; + + shiftedVal = ((uint32_t) p->mShiftBufferUV [indx + 0] << bitShift) | (uint32_t) p->mShiftBufferUV [indx + 1] ; + BitBufferWrite (bitstream, shiftedVal, bitShift * 2) ; + } + } + + // run the dynamic predictor and lossless compression for the "left" channel + // - note: we always use mode 0 in the "fast" path so we don't need the code for mode != 0 + pc_block (p->mMixBufferU, p->mPredictorU, numSamples, coefsU [numU - 1], numU, chanBits, DENSHIFT_DEFAULT) ; + + set_ag_params (&agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples, numSamples, MAX_RUN_DEFAULT) ; + status = dyn_comp (&agParams, p->mPredictorU, bitstream, numSamples, chanBits, &bits1) ; + RequireNoErr (status, goto Exit ;) ; + + // run the dynamic predictor and lossless compression for the "right" channel + pc_block (p->mMixBufferV, p->mPredictorV, numSamples, coefsV [numV - 1], numV, chanBits, DENSHIFT_DEFAULT) ; + + set_ag_params (&agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples, numSamples, MAX_RUN_DEFAULT) ; + status = dyn_comp (&agParams, p->mPredictorV, bitstream, numSamples, chanBits, &bits2) ; + RequireNoErr (status, goto Exit ;) ; + + // do bit requirement calculations + minBits1 = bits1 + (numU * sizeof (int16_t) * 8) ; + minBits2 = bits2 + (numV * sizeof (int16_t) * 8) ; + + // test for escape hatch if best calculated compressed size turns out to be more than the input size + minBits = minBits1 + minBits2 + (8 /* mixRes/maxRes/etc. */ * 8) + ((partialFrame == true) ? 32 : 0) ; + if (bytesShifted != 0) + minBits += (numSamples * (bytesShifted * 8) * 2) ; + + escapeBits = (numSamples * p->mBitDepth * 2) + ((partialFrame == true) ? 32 : 0) + (2 * 8) ; /* 2 common header bytes */ + + doEscape = (minBits >= escapeBits) ? true : false ; + + if (doEscape == false) + { + /* if we happened to create a compressed packet that was actually bigger than an escape packet would be, + chuck it and do an escape packet + */ + minBits = BitBufferGetPosition (bitstream) - BitBufferGetPosition (&startBits) ; + if (minBits >= escapeBits) + { + doEscape = true ; + printf ("compressed frame too big: %u vs. %u\n", minBits, escapeBits) ; + } + + } + + if (doEscape == true) + { + /* escape */ + + // reset bitstream position since we speculatively wrote the compressed version + *bitstream = startBits ; + + // write escape frame + status = EncodeStereoEscape (p, bitstream, inputBuffer, stride, numSamples) ; + +#if VERBOSE_DEBUG + DebugMsg ("escape!: %u vs %u\n", minBits, (numSamples * p->mBitDepth * 2)) ; +#endif + } + +Exit: + return status ; +} + +/* + EncodeStereoEscape () + - encode stereo escape frame +*/ +static int32_t +EncodeStereoEscape (ALAC_ENCODER *p, struct BitBuffer * bitstream, const int32_t * inputBuffer, uint32_t stride, uint32_t numSamples) +{ + uint8_t partialFrame ; + uint32_t indx ; + + // flag whether or not this is a partial frame + partialFrame = (numSamples == p->mFrameSize) ? 0 : 1 ; + + // write bitstream header + BitBufferWrite (bitstream, 0, 12) ; + BitBufferWrite (bitstream, (partialFrame << 3) | 1, 4) ; // LSB = 1 means "frame not compressed" + if (partialFrame) + BitBufferWrite (bitstream, numSamples, 32) ; + + // just copy the input data to the output buffer + switch (p->mBitDepth) + { + case 16: + for (indx = 0 ; indx < (numSamples * stride) ; indx += stride) + { + BitBufferWrite (bitstream, inputBuffer [indx + 0] >> 16, 16) ; + BitBufferWrite (bitstream, inputBuffer [indx + 1] >> 16, 16) ; + } + break ; + case 20: + for (indx = 0 ; indx < (numSamples * stride) ; indx += stride) + { + BitBufferWrite (bitstream, inputBuffer [indx + 0] >> 12, 16) ; + BitBufferWrite (bitstream, inputBuffer [indx + 1] >> 12, 16) ; + } + break ; + case 24: + // mix24 () with mixres param = 0 means de-interleave so use it to simplify things + mix24 (inputBuffer, stride, p->mMixBufferU, p->mMixBufferV, numSamples, 0, 0, p->mShiftBufferUV, 0) ; + for (indx = 0 ; indx < numSamples ; indx++) + { + BitBufferWrite (bitstream, p->mMixBufferU [indx] >> 8, 24) ; + BitBufferWrite (bitstream, p->mMixBufferV [indx] >> 8, 24) ; + } + break ; + case 32: + for (indx = 0 ; indx < (numSamples * stride) ; indx += stride) + { + BitBufferWrite (bitstream, inputBuffer [indx + 0], 32) ; + BitBufferWrite (bitstream, inputBuffer [indx + 1], 32) ; + } + break ; + } + + return ALAC_noErr ; +} + +/* + EncodeMono () + - encode a mono input buffer +*/ +static int32_t +EncodeMono (ALAC_ENCODER *p, struct BitBuffer * bitstream, const int32_t * inputBuffer, uint32_t stride, uint32_t channelIndex, uint32_t numSamples) +{ + BitBuffer startBits = *bitstream ; // squirrel away copy of current state in case we need to go back and do an escape packet + AGParamRec agParams ; + uint32_t bits1 ; + uint32_t numU ; + SearchCoefs coefsU ; + uint32_t dilate ; + uint32_t minBits, bestU ; + uint32_t minU, maxU ; + uint32_t indx, indx2 ; + uint8_t bytesShifted ; + uint32_t shift ; + uint32_t mask ; + uint32_t chanBits ; + uint8_t pbFactor ; + uint8_t partialFrame ; + uint32_t escapeBits ; + bool doEscape ; + int32_t status = ALAC_noErr ; + + + // make sure we handle this bit-depth before we get going + RequireAction ((p->mBitDepth == 16) || (p->mBitDepth == 20) || (p->mBitDepth == 24) || (p->mBitDepth == 32), return kALAC_ParamError ;) ; + + // reload coefs array from previous frame + coefsU = (SearchCoefs) p->mCoefsU [channelIndex] ; + + // pick bit depth for actual encoding + // - we lop off the lower byte (s) for 24-/32-bit encodings + if (p->mBitDepth == 32) + bytesShifted = 2 ; + else if (p->mBitDepth >= 24) + bytesShifted = 1 ; + else + bytesShifted = 0 ; + + shift = bytesShifted * 8 ; + mask = (1ul << shift) - 1 ; + chanBits = p->mBitDepth - (bytesShifted * 8) ; + + // flag whether or not this is a partial frame + partialFrame = (numSamples == p->mFrameSize) ? 0 : 1 ; + + // convert N-bit data to 32-bit for predictor + switch (p->mBitDepth) + { + case 16: + // convert 16-bit data to 32-bit for predictor + for (indx = 0, indx2 = 0 ; indx < numSamples ; indx++, indx2 += stride) + p->mMixBufferU [indx] = inputBuffer [indx2] >> 16 ; + break ; + + case 20: + // convert 20-bit data to 32-bit for predictor + for (indx = 0, indx2 = 0 ; indx < numSamples ; indx++, indx2 += stride) + p->mMixBufferU [indx] = inputBuffer [indx2] >> 12 ; + break ; + case 24: + // convert 24-bit data to 32-bit for the predictor and extract the shifted off byte (s) + for (indx = 0, indx2 = 0 ; indx < numSamples ; indx++, indx2 += stride) + { + p->mMixBufferU [indx] = inputBuffer [indx2] >> 8 ; + p->mShiftBufferUV [indx] = (uint16_t) (p->mMixBufferU [indx] & mask) ; + p->mMixBufferU [indx] >>= shift ; + } + + break ; + case 32: + // just copy the 32-bit input data for the predictor and extract the shifted off byte (s) + for (indx = 0, indx2 = 0 ; indx < numSamples ; indx++, indx2 += stride) + { + p->mShiftBufferUV [indx] = (uint16_t) (inputBuffer [indx2] & mask) ; + p->mMixBufferU [indx] = inputBuffer [indx2] >> shift ; + } + break ; + } + + // brute-force encode optimization loop (implied "encode depth" of 0 if comparing to cmd line tool) + // - run over variations of the encoding params to find the best choice + minU = 4 ; + maxU = 8 ; + minBits = 1ul << 31 ; + pbFactor = 4 ; + + bestU = minU ; + + for (numU = minU ; numU <= maxU ; numU += 4) + { + BitBuffer workBits ; + uint32_t numBits ; + + BitBufferInit (&workBits, p->mWorkBuffer, p->mMaxOutputBytes) ; + + dilate = 32 ; + for (uint32_t converge = 0 ; converge < 7 ; converge++) + pc_block (p->mMixBufferU, p->mPredictorU, numSamples / dilate, coefsU [numU - 1], numU, chanBits, DENSHIFT_DEFAULT) ; + + dilate = 8 ; + pc_block (p->mMixBufferU, p->mPredictorU, numSamples / dilate, coefsU [numU - 1], numU, chanBits, DENSHIFT_DEFAULT) ; + + set_ag_params (&agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples / dilate, numSamples / dilate, MAX_RUN_DEFAULT) ; + status = dyn_comp (&agParams, p->mPredictorU, &workBits, numSamples / dilate, chanBits, &bits1) ; + RequireNoErr (status, goto Exit ;) ; + + numBits = (dilate * bits1) + (16 * numU) ; + if (numBits < minBits) + { + bestU = numU ; + minBits = numBits ; + } + } + + // test for escape hatch if best calculated compressed size turns out to be more than the input size + // - first, add bits for the header bytes mixRes/maxRes/shiftU/filterU + minBits += (4 /* mixRes/maxRes/etc. */ * 8) + ((partialFrame == true) ? 32 : 0) ; + if (bytesShifted != 0) + minBits += (numSamples * (bytesShifted * 8)) ; + + escapeBits = (numSamples * p->mBitDepth) + ((partialFrame == true) ? 32 : 0) + (2 * 8) ; /* 2 common header bytes */ + + doEscape = (minBits >= escapeBits) ? true : false ; + + if (doEscape == false) + { + // write bitstream header + BitBufferWrite (bitstream, 0, 12) ; + BitBufferWrite (bitstream, (partialFrame << 3) | (bytesShifted << 1), 4) ; + if (partialFrame) + BitBufferWrite (bitstream, numSamples, 32) ; + BitBufferWrite (bitstream, 0, 16) ; // mixBits = mixRes = 0 + + // write the params and predictor coefs + numU = bestU ; + BitBufferWrite (bitstream, (0 << 4) | DENSHIFT_DEFAULT, 8) ; // modeU = 0 + BitBufferWrite (bitstream, (pbFactor << 5) | numU, 8) ; + for (indx = 0 ; indx < numU ; indx++) + BitBufferWrite (bitstream, coefsU [numU-1][indx], 16) ; + + // if shift active, write the interleaved shift buffers + if (bytesShifted != 0) + { + for (indx = 0 ; indx < numSamples ; indx++) + BitBufferWrite (bitstream, p->mShiftBufferUV [indx], shift) ; + } + + // run the dynamic predictor with the best result + pc_block (p->mMixBufferU, p->mPredictorU, numSamples, coefsU [numU-1], numU, chanBits, DENSHIFT_DEFAULT) ; + + // do lossless compression + set_standard_ag_params (&agParams, numSamples, numSamples) ; + status = dyn_comp (&agParams, p->mPredictorU, bitstream, numSamples, chanBits, &bits1) ; + //AssertNoErr (status) ; + + + /* if we happened to create a compressed packet that was actually bigger than an escape packet would be, + chuck it and do an escape packet + */ + minBits = BitBufferGetPosition (bitstream) - BitBufferGetPosition (&startBits) ; + if (minBits >= escapeBits) + { + *bitstream = startBits ; // reset bitstream state + doEscape = true ; + printf ("compressed frame too big: %u vs. %u\n", minBits, escapeBits) ; + } + } + + if (doEscape == true) + { + // write bitstream header and coefs + BitBufferWrite (bitstream, 0, 12) ; + BitBufferWrite (bitstream, (partialFrame << 3) | 1, 4) ; // LSB = 1 means "frame not compressed" + if (partialFrame) + BitBufferWrite (bitstream, numSamples, 32) ; + + // just copy the input data to the output buffer + switch (p->mBitDepth) + { + case 16: + for (indx = 0 ; indx < (numSamples * stride) ; indx += stride) + BitBufferWrite (bitstream, inputBuffer [indx] >> 16, 16) ; + break ; + case 20: + // convert 20-bit data to 32-bit for simplicity + for (indx = 0 ; indx < (numSamples * stride) ; indx += stride) + BitBufferWrite (bitstream, inputBuffer [indx] >> 12, 20) ; + break ; + case 24: + // convert 24-bit data to 32-bit for simplicity + for (indx = 0, indx2 = 0 ; indx < numSamples ; indx++, indx2 += stride) + { + p->mMixBufferU [indx] = inputBuffer [indx2] >> 8 ; + BitBufferWrite (bitstream, p->mMixBufferU [indx], 24) ; + } + break ; + case 32: + for (indx = 0 ; indx < (numSamples * stride) ; indx += stride) + BitBufferWrite (bitstream, inputBuffer [indx], 32) ; + break ; + } +#if VERBOSE_DEBUG + DebugMsg ("escape!: %u vs %u\n", minBits, (numSamples * p->mBitDepth)) ; +#endif + } + +Exit: + return status ; +} + +#if PRAGMA_MARK +#pragma mark - +#endif + +/* + Encode () + - encode the next block of samples +*/ +int32_t +alac_encode (ALAC_ENCODER *p, uint32_t numSamples, + const int32_t * theReadBuffer, unsigned char * theWriteBuffer, uint32_t * ioNumBytes) +{ + uint32_t outputSize ; + BitBuffer bitstream ; + int32_t status ; + uint32_t numChannels = p->mNumChannels ; + + // make sure we handle this bit-depth before we get going + RequireAction ((p->mBitDepth == 16) || (p->mBitDepth == 20) || (p->mBitDepth == 24) || (p->mBitDepth == 32), return kALAC_ParamError ;) ; + + // create a bit buffer structure pointing to our output buffer + BitBufferInit (&bitstream, theWriteBuffer, p->mMaxOutputBytes) ; + + if (numChannels == 2) + { + // add 3-bit frame start tag ID_CPE = channel pair & 4-bit element instance tag = 0 + BitBufferWrite (&bitstream, ID_CPE, 3) ; + BitBufferWrite (&bitstream, 0, 4) ; + + // encode stereo input buffer + if (p->mFastMode == false) + status = EncodeStereo (p, &bitstream, theReadBuffer, 2, 0, numSamples) ; + else + status = EncodeStereoFast (p, &bitstream, theReadBuffer, 2, 0, numSamples) ; + RequireNoErr (status, goto Exit ;) ; + } + else if (numChannels == 1) + { + // add 3-bit frame start tag ID_SCE = mono channel & 4-bit element instance tag = 0 + BitBufferWrite (&bitstream, ID_SCE, 3) ; + BitBufferWrite (&bitstream, 0, 4) ; + + // encode mono input buffer + status = EncodeMono (p, &bitstream, theReadBuffer, 1, 0, numSamples) ; + RequireNoErr (status, goto Exit ;) ; + } + else + { + const int32_t * inputBuffer ; + uint32_t tag ; + uint32_t channelIndex ; + uint8_t stereoElementTag ; + uint8_t monoElementTag ; + uint8_t lfeElementTag ; + + inputBuffer = theReadBuffer ; + + stereoElementTag = 0 ; + monoElementTag = 0 ; + lfeElementTag = 0 ; + + for (channelIndex = 0 ; channelIndex < numChannels ;) + { + tag = (sChannelMaps [numChannels - 1] & (0x7ul << (channelIndex * 3))) >> (channelIndex * 3) ; + + BitBufferWrite (&bitstream, tag, 3) ; + switch (tag) + { + case ID_SCE: + // mono + BitBufferWrite (&bitstream, monoElementTag, 4) ; + + status = EncodeMono (p, &bitstream, inputBuffer, numChannels, channelIndex, numSamples) ; + + inputBuffer += 1 ; + channelIndex++ ; + monoElementTag++ ; + break ; + + case ID_CPE: + // stereo + BitBufferWrite (&bitstream, stereoElementTag, 4) ; + + status = EncodeStereo (p, &bitstream, inputBuffer, numChannels, channelIndex, numSamples) ; + + inputBuffer += 2 ; + channelIndex += 2 ; + stereoElementTag++ ; + break ; + + case ID_LFE: + // LFE channel (subwoofer) + BitBufferWrite (&bitstream, lfeElementTag, 4) ; + + status = EncodeMono (p, &bitstream, inputBuffer, numChannels, channelIndex, numSamples) ; + + inputBuffer += 1 ; + channelIndex++ ; + lfeElementTag++ ; + break ; + + default: + printf ("That ain't right! (%u)\n", tag) ; + status = kALAC_ParamError ; + goto Exit ; + } + + RequireNoErr (status, goto Exit ;) ; + } + } + +#if VERBOSE_DEBUG +{ + // if there is room left in the output buffer, add some random fill data to test decoder + int32_t bitsLeft ; + int32_t bytesLeft ; + + bitsLeft = BitBufferGetPosition (&bitstream) - 3 ; // - 3 for ID_END tag + bytesLeft = bitstream.byteSize - ((bitsLeft + 7) / 8) ; + + if ((bytesLeft > 20) && ((bytesLeft & 0x4u) != 0)) + AddFiller (&bitstream, bytesLeft) ; +} +#endif + + // add 3-bit frame end tag: ID_END + BitBufferWrite (&bitstream, ID_END, 3) ; + + // byte-align the output data + BitBufferByteAlign (&bitstream, true) ; + + outputSize = BitBufferGetPosition (&bitstream) / 8 ; + //Assert (outputSize <= mMaxOutputBytes) ; + + + // all good, let iTunes know what happened and remember the total number of input sample frames + *ioNumBytes = outputSize ; + //mEncodedFrames += encodeMsg->numInputSamples ; + + // gather encoding stats + p->mTotalBytesGenerated += outputSize ; + p->mMaxFrameBytes = MAX (p->mMaxFrameBytes, outputSize) ; + + status = ALAC_noErr ; + +Exit: + return status ; +} + + +#if PRAGMA_MARK +#pragma mark - +#endif + +/* + GetConfig () +*/ +void +GetConfig (ALAC_ENCODER *p, ALACSpecificConfig * config) +{ + config->frameLength = Swap32NtoB (p->mFrameSize) ; + config->compatibleVersion = (uint8_t) kALACCompatibleVersion ; + config->bitDepth = (uint8_t) p->mBitDepth ; + config->pb = (uint8_t) PB0 ; + config->kb = (uint8_t) KB0 ; + config->mb = (uint8_t) MB0 ; + config->numChannels = (uint8_t) p->mNumChannels ; + config->maxRun = Swap16NtoB ((uint16_t) MAX_RUN_DEFAULT) ; + config->maxFrameBytes = Swap32NtoB (p->mMaxFrameBytes) ; + config->avgBitRate = Swap32NtoB (p->mAvgBitRate) ; + config->sampleRate = Swap32NtoB (p->mOutputSampleRate) ; +} + +uint32_t +alac_get_magic_cookie_size (uint32_t inNumChannels) +{ + if (inNumChannels > 2) + { + return sizeof (ALACSpecificConfig) + kChannelAtomSize + sizeof (ALACAudioChannelLayout) ; + } + else + { + return sizeof (ALACSpecificConfig) ; + } +} + +void +alac_get_magic_cookie (ALAC_ENCODER *p, void * outCookie, uint32_t * ioSize) +{ + ALACSpecificConfig theConfig = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } ; + ALACAudioChannelLayout theChannelLayout = { 0, 0, 0 } ; + uint8_t theChannelAtom [kChannelAtomSize] = { 0, 0, 0, 0, 'c', 'h', 'a', 'n', 0, 0, 0, 0 } ; + uint32_t theCookieSize = sizeof (ALACSpecificConfig) ; + uint8_t * theCookiePointer = (uint8_t *) outCookie ; + + GetConfig (p, &theConfig) ; + if (theConfig.numChannels > 2) + { + theChannelLayout.mChannelLayoutTag = Swap32NtoB (ALACChannelLayoutTags [theConfig.numChannels - 1]) ; + theCookieSize += (sizeof (ALACAudioChannelLayout) + kChannelAtomSize) ; + } + if (*ioSize >= theCookieSize) + { + memcpy (theCookiePointer, &theConfig, sizeof (ALACSpecificConfig)) ; + theChannelAtom [3] = (sizeof (ALACAudioChannelLayout) + kChannelAtomSize) ; + if (theConfig.numChannels > 2) + { + theCookiePointer += sizeof (ALACSpecificConfig) ; + memcpy (theCookiePointer, theChannelAtom, kChannelAtomSize) ; + theCookiePointer += kChannelAtomSize ; + memcpy (theCookiePointer, &theChannelLayout, sizeof (ALACAudioChannelLayout)) ; + } + *ioSize = theCookieSize ; + } + else + { + *ioSize = 0 ; // no incomplete cookies + } +} + +/* + alac_encoder_init () + - initialize the encoder component with the current config +*/ +int32_t +alac_encoder_init (ALAC_ENCODER *p, uint32_t samplerate, uint32_t channels, uint32_t format_flags, uint32_t frameSize) +{ + int32_t status ; + + p->mFrameSize = (frameSize > 0 && frameSize <= ALAC_FRAME_LENGTH) ? frameSize : ALAC_FRAME_LENGTH ; + + p->mOutputSampleRate = samplerate ; + p->mNumChannels = channels ; + switch (format_flags) + { + case 1: + p->mBitDepth = 16 ; + break ; + case 2: + p->mBitDepth = 20 ; + break ; + case 3: + p->mBitDepth = 24 ; + break ; + case 4: + p->mBitDepth = 32 ; + break ; + default: + break ; + } + + // set up default encoding parameters and state + // - note: mFrameSize is set in the constructor or via alac_set_frame_size () which must be called before this routine + for (uint32_t indx = 0 ; indx < kALACMaxChannels ; indx++) + p->mLastMixRes [indx] = kDefaultMixRes ; + + // the maximum output frame size can be no bigger than (samplesPerBlock * numChannels * ((10 + sampleSize)/8) + 1) + // but note that this can be bigger than the input size! + // - since we don't yet know what our input format will be, use our max allowed sample size in the calculation + p->mMaxOutputBytes = p->mFrameSize * p->mNumChannels * ((10 + kMaxSampleSize) / 8) + 1 ; + + status = ALAC_noErr ; + + // initialize coefs arrays once b/c retaining state across blocks actually improves the encode ratio + for (int32_t channel = 0 ; channel < (int32_t) p->mNumChannels ; channel++) + { + for (int32_t search = 0 ; search < kALACMaxSearches ; search++) + { + init_coefs (p->mCoefsU [channel][search], DENSHIFT_DEFAULT, kALACMaxCoefs) ; + init_coefs (p->mCoefsV [channel][search], DENSHIFT_DEFAULT, kALACMaxCoefs) ; + } + } + + return status ; +} + +/* + alac_get_source_format () + - given the input format, return one of our supported formats +*/ +void +alac_get_source_format (ALAC_ENCODER *p, const AudioFormatDescription * source, AudioFormatDescription * output) +{ + (void) output ; + // default is 16-bit native endian + // - note: for float input we assume that's coming from one of our decoders (mp3, aac) so it only makes sense + // to encode to 16-bit since the source was lossy in the first place + // - note: if not a supported bit depth, find the closest supported bit depth to the input one + if ((source->mFormatID != kALACFormatLinearPCM) || ((source->mFormatFlags & kALACFormatFlagIsFloat) != 0) || (source->mBitsPerChannel <= 16)) + p->mBitDepth = 16 ; + else if (source->mBitsPerChannel <= 20) + p->mBitDepth = 20 ; + else if (source->mBitsPerChannel <= 24) + p->mBitDepth = 24 ; + else + p->mBitDepth = 32 ; + + // we support 16/20/24/32-bit integer data at any sample rate and our target number of channels + // and sample rate were specified when we were configured + /* + MakeUncompressedAudioFormat (mNumChannels, (float) mOutputSampleRate, mBitDepth, kAudioFormatFlagsNativeIntegerPacked, output) ; + */ +} + + + +#if VERBOSE_DEBUG + +#if PRAGMA_MARK +#pragma mark - +#endif + +/* + AddFiller () + - add fill and data stream elements to the bitstream to test the decoder +*/ +static void AddFiller (BitBuffer * bits, int32_t numBytes) +{ + uint8_t tag ; + int32_t indx ; + + // out of lameness, subtract 6 bytes to deal with header + alignment as required for fill/data elements + numBytes -= 6 ; + if (numBytes <= 0) + return ; + + // randomly pick Fill or Data Stream Element based on numBytes requested + tag = (numBytes & 0x8) ? ID_FIL : ID_DSE ; + + BitBufferWrite (bits, tag, 3) ; + if (tag == ID_FIL) + { + // can't write more than 269 bytes in a fill element + numBytes = (numBytes > 269) ? 269 : numBytes ; + + // fill element = 4-bit size unless >= 15 then 4-bit size + 8-bit extension size + if (numBytes >= 15) + { + uint16_t extensionSize ; + + BitBufferWrite (bits, 15, 4) ; + + // 8-bit extension count field is "extra + 1" which is weird but I didn't define the syntax + // - otherwise, there's no way to represent 15 + // - for example, to really mean 15 bytes you must encode extensionSize = 1 + // - why it's not like data stream elements I have no idea + extensionSize = (numBytes - 15) + 1 ; + //Assert (extensionSize <= 255) ; + BitBufferWrite (bits, extensionSize, 8) ; + } + else + BitBufferWrite (bits, numBytes, 4) ; + + BitBufferWrite (bits, 0x10, 8) ; // extension_type = FILL_DATA = b0001 or'ed with fill_nibble = b0000 + for (indx = 0 ; indx < (numBytes - 1) ; indx++) + BitBufferWrite (bits, 0xa5, 8) ; // fill_byte = b10100101 = 0xa5 + } + else + { + // can't write more than 510 bytes in a data stream element + numBytes = (numBytes > 510) ? 510 : numBytes ; + + BitBufferWrite (bits, 0, 4) ; // element instance tag + BitBufferWrite (bits, 1, 1) ; // byte-align flag = true + + // data stream element = 8-bit size unless >= 255 then 8-bit size + 8-bit size + if (numBytes >= 255) + { + BitBufferWrite (bits, 255, 8) ; + BitBufferWrite (bits, numBytes - 255, 8) ; + } + else + BitBufferWrite (bits, numBytes, 8) ; + + BitBufferByteAlign (bits, true) ; // byte-align with zeros + + for (indx = 0 ; indx < numBytes ; indx++) + BitBufferWrite (bits, 0x5a, 8) ; + } +} + +#endif /* VERBOSE_DEBUG */ diff --git a/extern/libsndfile-modified/src/ALAC/dp_dec.c b/extern/libsndfile-modified/src/ALAC/dp_dec.c new file mode 100644 index 000000000..0d1c10d53 --- /dev/null +++ b/extern/libsndfile-modified/src/ALAC/dp_dec.c @@ -0,0 +1,381 @@ +/* + * Copyright (c) 2011 Apple Inc. All rights reserved. + * + * @APPLE_APACHE_LICENSE_HEADER_START@ + * + * Licensed under the Apache License, Version 2.0 (the "License") ; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @APPLE_APACHE_LICENSE_HEADER_END@ + */ + +/* + File: dp_dec.c + + Contains: Dynamic Predictor decode routines + + Copyright: (c) 2001-2011 Apple, Inc. +*/ + + +#include + +#include "dplib.h" +#include "shift.h" + +#if __GNUC__ +#define ALWAYS_INLINE __attribute__ ((always_inline)) +#elif defined _MSC_VER +#define ALWAYS_INLINE __forceinline +#else +#define ALWAYS_INLINE +#endif + +#define LOOP_ALIGN + +static inline int32_t ALWAYS_INLINE +sign_of_int (int32_t i) +{ + int32_t negishift ; + + negishift = ((uint32_t) - i) >> 31 ; + return negishift | (i >> 31) ; +} + +void +unpc_block (const int32_t * pc1, int32_t * out, int32_t num, int16_t * coefs, int32_t numactive, uint32_t chanbits, uint32_t denshift) +{ + register int16_t a0, a1, a2, a3 ; + register int32_t b0, b1, b2, b3 ; + int32_t j, k, lim ; + int32_t sum1, sg, sgn, top, dd ; + int32_t * pout ; + int32_t del, del0 ; + uint32_t chanshift = 32 - chanbits ; + int32_t denhalf = 1 << (denshift - 1) ; + + out [0] = pc1 [0] ; + if (numactive == 0) + { + // just copy if numactive == 0 (but don't bother if in/out pointers the same) + if ((num > 1) && (pc1 != out)) + memcpy (&out [1], &pc1 [1], (num - 1) * sizeof (int32_t)) ; + return ; + } + if (numactive == 31) + { + // short-circuit if numactive == 31 + int32_t prev ; + + /* this code is written such that the in/out buffers can be the same + to conserve buffer space on embedded devices like the iPod + + (original code) + for (j = 1 ; j < num ; j++) + del = pc1 [j] + out [j-1] ; + out [j] = (del << chanshift) >> chanshift ; + */ + prev = out [0] ; + for (j = 1 ; j < num ; j++) + { + del = pc1 [j] + prev ; + prev = (del << chanshift) >> chanshift ; + out [j] = prev ; + } + return ; + } + + for (j = 1 ; j <= numactive ; j++) + { + del = pc1 [j] + out [j-1] ; + out [j] = arith_shift_left (del, chanshift) >> chanshift ; + } + + lim = numactive + 1 ; + + if (numactive == 4) + { + // optimization for numactive == 4 + register int16_t ia0, ia1, ia2, ia3 ; + register int32_t ib0, ib1, ib2, ib3 ; + + ia0 = coefs [0] ; + ia1 = coefs [1] ; + ia2 = coefs [2] ; + ia3 = coefs [3] ; + + for (j = lim ; j < num ; j++) + { + LOOP_ALIGN + + top = out [j - lim] ; + pout = out + j - 1 ; + + ib0 = top - pout [0] ; + ib1 = top - pout [-1] ; + ib2 = top - pout [-2] ; + ib3 = top - pout [-3] ; + + sum1 = (denhalf - ia0 * ib0 - ia1 * ib1 - ia2 * ib2 - ia3 * ib3) >> denshift ; + + del = pc1 [j] ; + del0 = del ; + sg = sign_of_int (del) ; + del += top + sum1 ; + + out [j] = arith_shift_left (del, chanshift) >> chanshift ; + + if (sg > 0) + { + sgn = sign_of_int (ib3) ; + ia3 -= sgn ; + del0 -= (4 - 3) * ((sgn * ib3) >> denshift) ; + if (del0 <= 0) + continue ; + + sgn = sign_of_int (ib2) ; + ia2 -= sgn ; + del0 -= (4 - 2) * ((sgn * ib2) >> denshift) ; + if (del0 <= 0) + continue ; + + sgn = sign_of_int (ib1) ; + ia1 -= sgn ; + del0 -= (4 - 1) * ((sgn * ib1) >> denshift) ; + if (del0 <= 0) + continue ; + + ia0 -= sign_of_int (ib0) ; + } + else if (sg < 0) + { + // note: to avoid unnecessary negations, we flip the value of "sgn" + sgn = -sign_of_int (ib3) ; + ia3 -= sgn ; + del0 -= (4 - 3) * ((sgn * ib3) >> denshift) ; + if (del0 >= 0) + continue ; + + sgn = -sign_of_int (ib2) ; + ia2 -= sgn ; + del0 -= (4 - 2) * ((sgn * ib2) >> denshift) ; + if (del0 >= 0) + continue ; + + sgn = -sign_of_int (ib1) ; + ia1 -= sgn ; + del0 -= (4 - 1) * ((sgn * ib1) >> denshift) ; + if (del0 >= 0) + continue ; + + ia0 += sign_of_int (ib0) ; + } + } + + coefs [0] = ia0 ; + coefs [1] = ia1 ; + coefs [2] = ia2 ; + coefs [3] = ia3 ; + } + else if (numactive == 8) + { + register int16_t a4, a5, a6, a7 ; + register int32_t b4, b5, b6, b7 ; + + // optimization for numactive == 8 + a0 = coefs [0] ; + a1 = coefs [1] ; + a2 = coefs [2] ; + a3 = coefs [3] ; + a4 = coefs [4] ; + a5 = coefs [5] ; + a6 = coefs [6] ; + a7 = coefs [7] ; + + for (j = lim ; j < num ; j++) + { + LOOP_ALIGN + + top = out [j - lim] ; + pout = out + j - 1 ; + + b0 = top - (*pout--) ; + b1 = top - (*pout--) ; + b2 = top - (*pout--) ; + b3 = top - (*pout--) ; + b4 = top - (*pout--) ; + b5 = top - (*pout--) ; + b6 = top - (*pout--) ; + b7 = top - (*pout) ; + pout += 8 ; + + sum1 = (denhalf - a0 * b0 - a1 * b1 - a2 * b2 - a3 * b3 + - a4 * b4 - a5 * b5 - a6 * b6 - a7 * b7) >> denshift ; + + del = pc1 [j] ; + del0 = del ; + sg = sign_of_int (del) ; + del += top + sum1 ; + + out [j] = arith_shift_left (del, chanshift) >> chanshift ; + + if (sg > 0) + { + sgn = sign_of_int (b7) ; + a7 -= sgn ; + del0 -= 1 * ((sgn * b7) >> denshift) ; + if (del0 <= 0) + continue ; + + sgn = sign_of_int (b6) ; + a6 -= sgn ; + del0 -= 2 * ((sgn * b6) >> denshift) ; + if (del0 <= 0) + continue ; + + sgn = sign_of_int (b5) ; + a5 -= sgn ; + del0 -= 3 * ((sgn * b5) >> denshift) ; + if (del0 <= 0) + continue ; + + sgn = sign_of_int (b4) ; + a4 -= sgn ; + del0 -= 4 * ((sgn * b4) >> denshift) ; + if (del0 <= 0) + continue ; + + sgn = sign_of_int (b3) ; + a3 -= sgn ; + del0 -= 5 * ((sgn * b3) >> denshift) ; + if (del0 <= 0) + continue ; + + sgn = sign_of_int (b2) ; + a2 -= sgn ; + del0 -= 6 * ((sgn * b2) >> denshift) ; + if (del0 <= 0) + continue ; + + sgn = sign_of_int (b1) ; + a1 -= sgn ; + del0 -= 7 * ((sgn * b1) >> denshift) ; + if (del0 <= 0) + continue ; + + a0 -= sign_of_int (b0) ; + } + else if (sg < 0) + { + // note: to avoid unnecessary negations, we flip the value of "sgn" + sgn = -sign_of_int (b7) ; + a7 -= sgn ; + del0 -= 1 * ((sgn * b7) >> denshift) ; + if (del0 >= 0) + continue ; + + sgn = -sign_of_int (b6) ; + a6 -= sgn ; + del0 -= 2 * ((sgn * b6) >> denshift) ; + if (del0 >= 0) + continue ; + + sgn = -sign_of_int (b5) ; + a5 -= sgn ; + del0 -= 3 * ((sgn * b5) >> denshift) ; + if (del0 >= 0) + continue ; + + sgn = -sign_of_int (b4) ; + a4 -= sgn ; + del0 -= 4 * ((sgn * b4) >> denshift) ; + if (del0 >= 0) + continue ; + + sgn = -sign_of_int (b3) ; + a3 -= sgn ; + del0 -= 5 * ((sgn * b3) >> denshift) ; + if (del0 >= 0) + continue ; + + sgn = -sign_of_int (b2) ; + a2 -= sgn ; + del0 -= 6 * ((sgn * b2) >> denshift) ; + if (del0 >= 0) + continue ; + + sgn = -sign_of_int (b1) ; + a1 -= sgn ; + del0 -= 7 * ((sgn * b1) >> denshift) ; + if (del0 >= 0) + continue ; + + a0 += sign_of_int (b0) ; + } + } + + coefs [0] = a0 ; + coefs [1] = a1 ; + coefs [2] = a2 ; + coefs [3] = a3 ; + coefs [4] = a4 ; + coefs [5] = a5 ; + coefs [6] = a6 ; + coefs [7] = a7 ; + } + else + { + // general case + for (j = lim ; j < num ; j++) + { + LOOP_ALIGN + + sum1 = 0 ; + pout = out + j - 1 ; + top = out [j-lim] ; + + for (k = 0 ; k < numactive ; k++) + sum1 += coefs [k] * (pout [-k] - top) ; + + del = pc1 [j] ; + del0 = del ; + sg = sign_of_int (del) ; + del += top + ((sum1 + denhalf) >> denshift) ; + out [j] = (del << chanshift) >> chanshift ; + + if (sg > 0) + { + for (k = (numactive - 1) ; k >= 0 ; k--) + { + dd = top - pout [-k] ; + sgn = sign_of_int (dd) ; + coefs [k] -= sgn ; + del0 -= (numactive - k) * ((sgn * dd) >> denshift) ; + if (del0 <= 0) + break ; + } + } + else if (sg < 0) + { + for (k = (numactive - 1) ; k >= 0 ; k--) + { + dd = top - pout [-k] ; + sgn = sign_of_int (dd) ; + coefs [k] += sgn ; + del0 -= (numactive - k) * ((-sgn * dd) >> denshift) ; + if (del0 >= 0) + break ; + } + } + } + } +} diff --git a/extern/libsndfile-modified/src/ALAC/dp_enc.c b/extern/libsndfile-modified/src/ALAC/dp_enc.c new file mode 100644 index 000000000..01db8d401 --- /dev/null +++ b/extern/libsndfile-modified/src/ALAC/dp_enc.c @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2011 Apple Inc. All rights reserved. + * + * @APPLE_APACHE_LICENSE_HEADER_START@ + * + * Licensed under the Apache License, Version 2.0 (the "License") ; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @APPLE_APACHE_LICENSE_HEADER_END@ + */ + +/* + File: dp_enc.c + + Contains: Dynamic Predictor encode routines + + Copyright: (c) 2001-2011 Apple, Inc. +*/ + +#include + +#include "dplib.h" +#include "shift.h" + +#if __GNUC__ +#define ALWAYS_INLINE __attribute__ ((always_inline)) +#elif defined _MSC_VER +#define ALWAYS_INLINE __forceinline +#else +#define ALWAYS_INLINE +#endif + +#define LOOP_ALIGN + +void +init_coefs (int16_t * coefs, uint32_t denshift, int32_t numPairs) +{ + int32_t k ; + int32_t den = 1 << denshift ; + + coefs [0] = (AINIT * den) >> 4 ; + coefs [1] = (BINIT * den) >> 4 ; + coefs [2] = (CINIT * den) >> 4 ; + for (k = 3 ; k < numPairs ; k++) + coefs [k] = 0 ; +} + +void +copy_coefs (const int16_t * srcCoefs, int16_t * dstCoefs, int32_t numPairs) +{ + int32_t k ; + + for (k = 0 ; k < numPairs ; k++) + dstCoefs [k] = srcCoefs [k] ; +} + +static inline int32_t ALWAYS_INLINE sign_of_int (int32_t i) +{ + int32_t negishift ; + + negishift = ((uint32_t) - i) >> 31 ; + return negishift | (i >> 31) ; +} + +void +pc_block (int32_t * in, int32_t * pc1, int32_t num, int16_t * coefs, int32_t numactive, uint32_t chanbits, uint32_t denshift) +{ + register int16_t a0, a1, a2, a3 ; + register int32_t b0, b1, b2, b3 ; + int32_t j, k, lim ; + int32_t * pin ; + int32_t sum1, dd ; + int32_t sg, sgn ; + int32_t top ; + int32_t del, del0 ; + uint32_t chanshift = 32 - chanbits ; + int32_t denhalf = 1 << (denshift - 1) ; + + pc1 [0] = in [0] ; + if (numactive == 0) + { + // just copy if numactive == 0 (but don't bother if in/out pointers the same) + if ((num > 1) && (in != pc1)) + memcpy (&pc1 [1], &in [1], (num - 1) * sizeof (int32_t)) ; + return ; + } + if (numactive == 31) + { + // short-circuit if numactive == 31 + for (j = 1 ; j < num ; j++) + { + del = in [j] - in [j-1] ; + pc1 [j] = (del << chanshift) >> chanshift ; + } + return ; + } + + for (j = 1 ; j <= numactive ; j++) + { + del = in [j] - in [j-1] ; + pc1 [j] = arith_shift_left (del, chanshift) >> chanshift ; + } + + lim = numactive + 1 ; + + if (numactive == 4) + { + // optimization for numactive == 4 + a0 = coefs [0] ; + a1 = coefs [1] ; + a2 = coefs [2] ; + a3 = coefs [3] ; + + for (j = lim ; j < num ; j++) + { + LOOP_ALIGN + + top = in [j - lim] ; + pin = in + j - 1 ; + + b0 = top - pin [0] ; + b1 = top - pin [-1] ; + b2 = top - pin [-2] ; + b3 = top - pin [-3] ; + + sum1 = (denhalf - a0 * b0 - a1 * b1 - a2 * b2 - a3 * b3) >> denshift ; + + del = in [j] - top - sum1 ; + del = arith_shift_left (del, chanshift) >> chanshift ; + pc1 [j] = del ; + del0 = del ; + + sg = sign_of_int (del) ; + if (sg > 0) + { + sgn = sign_of_int (b3) ; + a3 -= sgn ; + del0 -= (4 - 3) * ((sgn * b3) >> denshift) ; + if (del0 <= 0) + continue ; + + sgn = sign_of_int (b2) ; + a2 -= sgn ; + del0 -= (4 - 2) * ((sgn * b2) >> denshift) ; + if (del0 <= 0) + continue ; + + sgn = sign_of_int (b1) ; + a1 -= sgn ; + del0 -= (4 - 1) * ((sgn * b1) >> denshift) ; + if (del0 <= 0) + continue ; + + a0 -= sign_of_int (b0) ; + } + else if (sg < 0) + { + // note: to avoid unnecessary negations, we flip the value of "sgn" + sgn = -sign_of_int (b3) ; + a3 -= sgn ; + del0 -= (4 - 3) * ((sgn * b3) >> denshift) ; + if (del0 >= 0) + continue ; + + sgn = -sign_of_int (b2) ; + a2 -= sgn ; + del0 -= (4 - 2) * ((sgn * b2) >> denshift) ; + if (del0 >= 0) + continue ; + + sgn = -sign_of_int (b1) ; + a1 -= sgn ; + del0 -= (4 - 1) * ((sgn * b1) >> denshift) ; + if (del0 >= 0) + continue ; + + a0 += sign_of_int (b0) ; + } + } + + coefs [0] = a0 ; + coefs [1] = a1 ; + coefs [2] = a2 ; + coefs [3] = a3 ; + } + else if (numactive == 8) + { + // optimization for numactive == 8 + register int16_t a4, a5, a6, a7 ; + register int32_t b4, b5, b6, b7 ; + + a0 = coefs [0] ; + a1 = coefs [1] ; + a2 = coefs [2] ; + a3 = coefs [3] ; + a4 = coefs [4] ; + a5 = coefs [5] ; + a6 = coefs [6] ; + a7 = coefs [7] ; + + for (j = lim ; j < num ; j++) + { + LOOP_ALIGN + + top = in [j - lim] ; + pin = in + j - 1 ; + + b0 = top - (*pin--) ; + b1 = top - (*pin--) ; + b2 = top - (*pin--) ; + b3 = top - (*pin--) ; + b4 = top - (*pin--) ; + b5 = top - (*pin--) ; + b6 = top - (*pin--) ; + b7 = top - (*pin) ; + pin += 8 ; + + sum1 = (denhalf - a0 * b0 - a1 * b1 - a2 * b2 - a3 * b3 + - a4 * b4 - a5 * b5 - a6 * b6 - a7 * b7) >> denshift ; + + del = in [j] - top - sum1 ; + del = arith_shift_left (del, chanshift) >> chanshift ; + pc1 [j] = del ; + del0 = del ; + + sg = sign_of_int (del) ; + if (sg > 0) + { + sgn = sign_of_int (b7) ; + a7 -= sgn ; + del0 -= 1 * ((sgn * b7) >> denshift) ; + if (del0 <= 0) + continue ; + + sgn = sign_of_int (b6) ; + a6 -= sgn ; + del0 -= 2 * ((sgn * b6) >> denshift) ; + if (del0 <= 0) + continue ; + + sgn = sign_of_int (b5) ; + a5 -= sgn ; + del0 -= 3 * ((sgn * b5) >> denshift) ; + if (del0 <= 0) + continue ; + + sgn = sign_of_int (b4) ; + a4 -= sgn ; + del0 -= 4 * ((sgn * b4) >> denshift) ; + if (del0 <= 0) + continue ; + + sgn = sign_of_int (b3) ; + a3 -= sgn ; + del0 -= 5 * ((sgn * b3) >> denshift) ; + if (del0 <= 0) + continue ; + + sgn = sign_of_int (b2) ; + a2 -= sgn ; + del0 -= 6 * ((sgn * b2) >> denshift) ; + if (del0 <= 0) + continue ; + + sgn = sign_of_int (b1) ; + a1 -= sgn ; + del0 -= 7 * ((sgn * b1) >> denshift) ; + if (del0 <= 0) + continue ; + + a0 -= sign_of_int (b0) ; + } + else if (sg < 0) + { + // note: to avoid unnecessary negations, we flip the value of "sgn" + sgn = -sign_of_int (b7) ; + a7 -= sgn ; + del0 -= 1 * ((sgn * b7) >> denshift) ; + if (del0 >= 0) + continue ; + + sgn = -sign_of_int (b6) ; + a6 -= sgn ; + del0 -= 2 * ((sgn * b6) >> denshift) ; + if (del0 >= 0) + continue ; + + sgn = -sign_of_int (b5) ; + a5 -= sgn ; + del0 -= 3 * ((sgn * b5) >> denshift) ; + if (del0 >= 0) + continue ; + + sgn = -sign_of_int (b4) ; + a4 -= sgn ; + del0 -= 4 * ((sgn * b4) >> denshift) ; + if (del0 >= 0) + continue ; + + sgn = -sign_of_int (b3) ; + a3 -= sgn ; + del0 -= 5 * ((sgn * b3) >> denshift) ; + if (del0 >= 0) + continue ; + + sgn = -sign_of_int (b2) ; + a2 -= sgn ; + del0 -= 6 * ((sgn * b2) >> denshift) ; + if (del0 >= 0) + continue ; + + sgn = -sign_of_int (b1) ; + a1 -= sgn ; + del0 -= 7 * ((sgn * b1) >> denshift) ; + if (del0 >= 0) + continue ; + + a0 += sign_of_int (b0) ; + } + } + + coefs [0] = a0 ; + coefs [1] = a1 ; + coefs [2] = a2 ; + coefs [3] = a3 ; + coefs [4] = a4 ; + coefs [5] = a5 ; + coefs [6] = a6 ; + coefs [7] = a7 ; + } + else + { +//pc_block_general: + // general case + for (j = lim ; j < num ; j++) + { + LOOP_ALIGN + + top = in [j - lim] ; + pin = in + j - 1 ; + + sum1 = 0 ; + for (k = 0 ; k < numactive ; k++) + sum1 -= coefs [k] * (top - pin [-k]) ; + + del = in [j] - top - ((sum1 + denhalf) >> denshift) ; + del = (del << chanshift) >> chanshift ; + pc1 [j] = del ; + del0 = del ; + + sg = sign_of_int (del) ; + if (sg > 0) + { + for (k = (numactive - 1) ; k >= 0 ; k--) + { + dd = top - pin [-k] ; + sgn = sign_of_int (dd) ; + coefs [k] -= sgn ; + del0 -= (numactive - k) * ((sgn * dd) >> denshift) ; + if (del0 <= 0) + break ; + } + } + else if (sg < 0) + { + for (k = (numactive - 1) ; k >= 0 ; k--) + { + dd = top - pin [-k] ; + sgn = sign_of_int (dd) ; + coefs [k] += sgn ; + del0 -= (numactive - k) * ((-sgn * dd) >> denshift) ; + if (del0 >= 0) + break ; + } + } + } + } +} diff --git a/extern/libsndfile-modified/src/ALAC/dplib.h b/extern/libsndfile-modified/src/ALAC/dplib.h new file mode 100644 index 000000000..43ae721d5 --- /dev/null +++ b/extern/libsndfile-modified/src/ALAC/dplib.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2011 Apple Inc. All rights reserved. + * + * @APPLE_APACHE_LICENSE_HEADER_START@ + * + * Licensed under the Apache License, Version 2.0 (the "License") ; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @APPLE_APACHE_LICENSE_HEADER_END@ + */ + +/* + File: dplib.h + + Contains: Dynamic Predictor routines + + Copyright: Copyright (C) 2001-2011 Apple, Inc. +*/ + +#ifndef __DPLIB_H__ +#define __DPLIB_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// defines + +#define DENSHIFT_MAX 15 +#define DENSHIFT_DEFAULT 9 +#define AINIT 38 +#define BINIT (-29) +#define CINIT (-2) +#define NUMCOEPAIRS 16 + +// prototypes + +void init_coefs (int16_t * coefs, uint32_t denshift, int32_t numPairs) ; +void copy_coefs (const int16_t * srcCoefs, int16_t * dstCoefs, int32_t numPairs) ; + +// NOTE: these routines read at least "numactive" samples so the i/o buffers must be at least that big + +void pc_block (int32_t * in, int32_t * pc, int32_t num, int16_t * coefs, int32_t numactive, uint32_t chanbits, uint32_t denshift) ; +void unpc_block (const int32_t * pc, int32_t * out, int32_t num, int16_t * coefs, int32_t numactive, uint32_t chanbits, uint32_t denshift) ; + +#ifdef __cplusplus +} +#endif + +#endif /* __DPLIB_H__ */ diff --git a/extern/libsndfile-modified/src/ALAC/matrix_dec.c b/extern/libsndfile-modified/src/ALAC/matrix_dec.c new file mode 100644 index 000000000..6d0b40153 --- /dev/null +++ b/extern/libsndfile-modified/src/ALAC/matrix_dec.c @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2011 Apple Inc. All rights reserved. + * Copyright (C) 2012-2014 Erik de Castro Lopo + * + * @APPLE_APACHE_LICENSE_HEADER_START@ + * + * Licensed under the Apache License, Version 2.0 (the "License") ; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @APPLE_APACHE_LICENSE_HEADER_END@ + */ + +/* + File: matrix_dec.c + + Contains: ALAC mixing/matrixing decode routines. + + Copyright: (c) 2004-2011 Apple, Inc. +*/ + +#include "matrixlib.h" +#include "ALACAudioTypes.h" +#include "shift.h" + +// up to 24-bit "offset" macros for the individual bytes of a 20/24-bit word +#if TARGET_RT_BIG_ENDIAN + #define LBYTE 2 + #define MBYTE 1 + #define HBYTE 0 +#else + #define LBYTE 0 + #define MBYTE 1 + #define HBYTE 2 +#endif + +/* + There is no plain middle-side option ; instead there are various mixing + modes including middle-side, each lossless, as embodied in the mix () + and unmix () functions. These functions exploit a generalized middle-side + transformation: + + u := [(rL + (m-r)R)/m] ; + v := L - R ; + + where [ ] denotes integer floor. The (lossless) inverse is + + L = u + v - [rV/m] ; + R = L - v ; +*/ + +// 16-bit routines + +void +unmix16 (const int32_t * u, int32_t * v, int32_t * out, uint32_t stride, int32_t numSamples, int32_t mixbits, int32_t mixres) +{ + int32_t j ; + + if (mixres != 0) + { + /* matrixed stereo */ + for (j = 0 ; j < numSamples ; j++) + { + int32_t l, r ; + + l = u [j] + v [j] - ((mixres * v [j]) >> mixbits) ; + r = l - v [j] ; + + out [0] = arith_shift_left (l, 16) ; + out [1] = arith_shift_left (r, 16) ; + out += stride ; + } + } + else + { + /* Conventional separated stereo. */ + for (j = 0 ; j < numSamples ; j++) + { + out [0] = u [j] << 16 ; + out [1] = v [j] << 16 ; + out += stride ; + } + } +} + +// 20-bit routines +// - the 20 bits of data are left-justified in 3 bytes of storage but right-aligned for input/output predictor buffers + +void +unmix20 (const int32_t * u, int32_t * v, int32_t * out, uint32_t stride, int32_t numSamples, int32_t mixbits, int32_t mixres) +{ + int32_t j ; + + if (mixres != 0) + { + /* matrixed stereo */ + for (j = 0 ; j < numSamples ; j++) + { + int32_t l, r ; + + l = u [j] + v [j] - ((mixres * v [j]) >> mixbits) ; + r = l - v [j] ; + + out [0] = arith_shift_left (l, 12) ; + out [1] = arith_shift_left (r, 12) ; + out += stride ; + } + } + else + { + /* Conventional separated stereo. */ + for (j = 0 ; j < numSamples ; j++) + { + out [0] = arith_shift_left (u [j], 12) ; + out [1] = arith_shift_left (v [j], 12) ; + out += stride ; + } + } +} + +// 24-bit routines +// - the 24 bits of data are right-justified in the input/output predictor buffers + +void +unmix24 (const int32_t * u, int32_t * v, int32_t * out, uint32_t stride, int32_t numSamples, + int32_t mixbits, int32_t mixres, uint16_t * shiftUV, int32_t bytesShifted) +{ + int32_t shift = bytesShifted * 8 ; + int32_t l, r ; + int32_t j, k ; + + if (mixres != 0) + { + /* matrixed stereo */ + if (bytesShifted != 0) + { + for (j = 0, k = 0 ; j < numSamples ; j++, k += 2) + { + l = u [j] + v [j] - ((mixres * v [j]) >> mixbits) ; + r = l - v [j] ; + + l = arith_shift_left (l, shift) | (uint32_t) shiftUV [k + 0] ; + r = arith_shift_left (r, shift) | (uint32_t) shiftUV [k + 1] ; + + out [0] = arith_shift_left (l, 8) ; + out [1] = arith_shift_left (r, 8) ; + out += stride ; + } + } + else + { + for (j = 0 ; j < numSamples ; j++) + { + l = u [j] + v [j] - ((mixres * v [j]) >> mixbits) ; + r = l - v [j] ; + + out [0] = l << 8 ; + out [1] = r << 8 ; + out += stride ; + } + } + } + else + { + /* Conventional separated stereo. */ + if (bytesShifted != 0) + { + for (j = 0, k = 0 ; j < numSamples ; j++, k += 2) + { + l = u [j] ; + r = v [j] ; + + l = (l << shift) | (uint32_t) shiftUV [k + 0] ; + r = (r << shift) | (uint32_t) shiftUV [k + 1] ; + + out [0] = l << 8 ; + out [1] = r << 8 ; + out += stride ; + } + } + else + { + for (j = 0 ; j < numSamples ; j++) + { + out [0] = u [j] << 8 ; + out [1] = v [j] << 8 ; + out += stride ; + } + } + } +} + +// 32-bit routines +// - note that these really expect the internal data width to be < 32 but the arrays are 32-bit +// - otherwise, the calculations might overflow into the 33rd bit and be lost +// - therefore, these routines deal with the specified "unused lower" bytes in the "shift" buffers + +void +unmix32 (const int32_t * u, int32_t * v, int32_t * out, uint32_t stride, int32_t numSamples, + int32_t mixbits, int32_t mixres, uint16_t * shiftUV, int32_t bytesShifted) +{ + int32_t shift = bytesShifted * 8 ; + int32_t l, r ; + int32_t j, k ; + + if (mixres != 0) + { + //Assert (bytesShifted != 0) ; + + /* matrixed stereo with shift */ + for (j = 0, k = 0 ; j < numSamples ; j++, k += 2) + { + int32_t lt, rt ; + + lt = u [j] ; + rt = v [j] ; + + l = lt + rt - ((mixres * rt) >> mixbits) ; + r = l - rt ; + + out [0] = arith_shift_left (l, shift) | (uint32_t) shiftUV [k + 0] ; + out [1] = arith_shift_left (r, shift) | (uint32_t) shiftUV [k + 1] ; + out += stride ; + } + } + else + { + if (bytesShifted == 0) + { + /* interleaving w/o shift */ + for (j = 0 ; j < numSamples ; j++) + { + out [0] = u [j] ; + out [1] = v [j] ; + out += stride ; + } + } + else + { + /* interleaving with shift */ + for (j = 0, k = 0 ; j < numSamples ; j++, k += 2) + { + out [0] = (u [j] << shift) | (uint32_t) shiftUV [k + 0] ; + out [1] = (v [j] << shift) | (uint32_t) shiftUV [k + 1] ; + out += stride ; + } + } + } +} + +// 20/24-bit <-> 32-bit helper routines (not really matrixing but convenient to put here) + +void +copyPredictorTo24 (const int32_t * in, int32_t * out, uint32_t stride, int32_t numSamples) +{ + int32_t j ; + + for (j = 0 ; j < numSamples ; j++) + { + out [0] = in [j] << 8 ; + out += stride ; + } +} + +void +copyPredictorTo24Shift (const int32_t * in, uint16_t * shift, int32_t * out, uint32_t stride, int32_t numSamples, int32_t bytesShifted) +{ + int32_t shiftVal = bytesShifted * 8 ; + int32_t j ; + + //Assert (bytesShifted != 0) ; + + for (j = 0 ; j < numSamples ; j++) + { + int32_t val = in [j] ; + + val = arith_shift_left (val, shiftVal) | (uint32_t) shift [j] ; + out [0] = arith_shift_left (val, 8) ; + out += stride ; + } +} + +void +copyPredictorTo20 (const int32_t * in, int32_t * out, uint32_t stride, int32_t numSamples) +{ + int32_t j ; + + // 32-bit predictor values are right-aligned but 20-bit output values should be left-aligned + // in the 24-bit output buffer + for (j = 0 ; j < numSamples ; j++) + { + out [0] = arith_shift_left (in [j], 12) ; + out += stride ; + } +} + +void +copyPredictorTo32 (const int32_t * in, int32_t * out, uint32_t stride, int32_t numSamples) +{ + int32_t i, j ; + + // this is only a subroutine to abstract the "iPod can only output 16-bit data" problem + for (i = 0, j = 0 ; i < numSamples ; i++, j += stride) + out [j] = arith_shift_left (in [i], 8) ; +} + +void +copyPredictorTo32Shift (const int32_t * in, uint16_t * shift, int32_t * out, uint32_t stride, int32_t numSamples, int32_t bytesShifted) +{ + int32_t * op = out ; + uint32_t shiftVal = bytesShifted * 8 ; + int32_t j ; + + //Assert (bytesShifted != 0) ; + + // this is only a subroutine to abstract the "iPod can only output 16-bit data" problem + for (j = 0 ; j < numSamples ; j++) + { + op [0] = arith_shift_left (in [j], shiftVal) | (uint32_t) shift [j] ; + op += stride ; + } +} diff --git a/extern/libsndfile-modified/src/ALAC/matrix_enc.c b/extern/libsndfile-modified/src/ALAC/matrix_enc.c new file mode 100644 index 000000000..b50f83b78 --- /dev/null +++ b/extern/libsndfile-modified/src/ALAC/matrix_enc.c @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2011 Apple Inc. All rights reserved. + * Copyright (C) 2012-2014 Erik de Castro Lopo + * + * @APPLE_APACHE_LICENSE_HEADER_START@ + * + * Licensed under the Apache License, Version 2.0 (the "License") ; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @APPLE_APACHE_LICENSE_HEADER_END@ + */ + +/* + File: matrix_enc.c + + Contains: ALAC mixing/matrixing encode routines. + + Copyright: (c) 2004-2011 Apple, Inc. +*/ + +#include "matrixlib.h" +#include "ALACAudioTypes.h" + +/* + There is no plain middle-side option ; instead there are various mixing + modes including middle-side, each lossless, as embodied in the mix () + and unmix () functions. These functions exploit a generalized middle-side + transformation: + + u := [(rL + (m-r)R)/m] ; + v := L - R ; + + where [ ] denotes integer floor. The (lossless) inverse is + + L = u + v - [rV/m] ; + R = L - v ; +*/ + +// 16-bit routines + +void +mix16 (const int32_t * in, uint32_t stride, int32_t * u, int32_t * v, int32_t numSamples, int32_t mixbits, int32_t mixres) +{ + int32_t j ; + + if (mixres != 0) + { + int32_t mod = 1 << mixbits ; + int32_t m2 ; + + /* matrixed stereo */ + m2 = mod - mixres ; + for (j = 0 ; j < numSamples ; j++) + { + int32_t l, r ; + + l = in [0] >> 16 ; + r = in [1] >> 16 ; + in += stride ; + u [j] = (mixres * l + m2 * r) >> mixbits ; + v [j] = l - r ; + } + } + else + { + /* Conventional separated stereo. */ + for (j = 0 ; j < numSamples ; j++) + { + u [j] = in [0] >> 16 ; + v [j] = in [1] >> 16 ; + in += stride ; + } + } +} + +// 20-bit routines +// - the 20 bits of data are left-justified in 3 bytes of storage but right-aligned for input/output predictor buffers + +void +mix20 (const int32_t * in, uint32_t stride, int32_t * u, int32_t * v, int32_t numSamples, int32_t mixbits, int32_t mixres) +{ + int32_t l, r ; + int32_t j ; + + if (mixres != 0) + { + /* matrixed stereo */ + int32_t mod = 1 << mixbits ; + int32_t m2 = mod - mixres ; + + for (j = 0 ; j < numSamples ; j++) + { + l = in [0] >> 12 ; + r = in [1] >> 12 ; + in += stride ; + + u [j] = (mixres * l + m2 * r) >> mixbits ; + v [j] = l - r ; + } + } + else + { + /* Conventional separated stereo. */ + for (j = 0 ; j < numSamples ; j++) + { + u [j] = in [0] >> 12 ; + v [j] = in [1] >> 12 ; + in += stride ; + } + } +} + +// 24-bit routines +// - the 24 bits of data are right-justified in the input/output predictor buffers + +void +mix24 (const int32_t * in, uint32_t stride, int32_t * u, int32_t * v, int32_t numSamples, + int32_t mixbits, int32_t mixres, uint16_t * shiftUV, int32_t bytesShifted) +{ + int32_t l, r ; + int32_t shift = bytesShifted * 8 ; + uint32_t mask = (1ul << shift) - 1 ; + int32_t j, k ; + + if (mixres != 0) + { + /* matrixed stereo */ + int32_t mod = 1 << mixbits ; + int32_t m2 = mod - mixres ; + + if (bytesShifted != 0) + { + for (j = 0, k = 0 ; j < numSamples ; j++, k += 2) + { + l = in [0] >> 8 ; + r = in [1] >> 8 ; + in += stride ; + + shiftUV [k + 0] = (uint16_t) (l & mask) ; + shiftUV [k + 1] = (uint16_t) (r & mask) ; + + l >>= shift ; + r >>= shift ; + + u [j] = (mixres * l + m2 * r) >> mixbits ; + v [j] = l - r ; + } + } + else + { + for (j = 0 ; j < numSamples ; j++) + { + l = in [0] >> 8 ; + r = in [1] >> 8 ; + in += stride ; + + u [j] = (mixres * l + m2 * r) >> mixbits ; + v [j] = l - r ; + } + } + } + else + { + /* Conventional separated stereo. */ + if (bytesShifted != 0) + { + for (j = 0, k = 0 ; j < numSamples ; j++, k += 2) + { + l = in [0] >> 8 ; + r = in [1] >> 8 ; + in += stride ; + + shiftUV [k + 0] = (uint16_t) (l & mask) ; + shiftUV [k + 1] = (uint16_t) (r & mask) ; + + l >>= shift ; + r >>= shift ; + + u [j] = l ; + v [j] = r ; + } + } + else + { + for (j = 0 ; j < numSamples ; j++) + { + l = in [0] >> 8 ; + r = in [1] >> 8 ; + in += stride ; + } + } + } +} + +// 32-bit routines +// - note that these really expect the internal data width to be < 32 but the arrays are 32-bit +// - otherwise, the calculations might overflow into the 33rd bit and be lost +// - therefore, these routines deal with the specified "unused lower" bytes in the "shift" buffers + +void +mix32 (const int32_t * in, uint32_t stride, int32_t * u, int32_t * v, int32_t numSamples, + int32_t mixbits, int32_t mixres, uint16_t * shiftUV, int32_t bytesShifted) +{ + int32_t shift = bytesShifted * 8 ; + uint32_t mask = (1ul << shift) - 1 ; + int32_t l, r ; + int32_t j, k ; + + if (mixres != 0) + { + int32_t mod = 1 << mixbits ; + int32_t m2 ; + + //Assert (bytesShifted != 0) ; + + /* matrixed stereo with shift */ + m2 = mod - mixres ; + for (j = 0, k = 0 ; j < numSamples ; j++, k += 2) + { + l = in [0] ; + r = in [1] ; + in += stride ; + + shiftUV [k + 0] = (uint16_t) (l & mask) ; + shiftUV [k + 1] = (uint16_t) (r & mask) ; + + l >>= shift ; + r >>= shift ; + + u [j] = (mixres * l + m2 * r) >> mixbits ; + v [j] = l - r ; + } + } + else + { + if (bytesShifted == 0) + { + /* de-interleaving w/o shift */ + for (j = 0 ; j < numSamples ; j++) + { + u [j] = in [0] ; + v [j] = in [1] ; + in += stride ; + } + } + else + { + /* de-interleaving with shift */ + for (j = 0, k = 0 ; j < numSamples ; j++, k += 2) + { + l = in [0] ; + r = in [1] ; + in += stride ; + + shiftUV [k + 0] = (uint16_t) (l & mask) ; + shiftUV [k + 1] = (uint16_t) (r & mask) ; + + l >>= shift ; + r >>= shift ; + + u [j] = l ; + v [j] = r ; + } + } + } +} diff --git a/extern/libsndfile-modified/src/ALAC/matrixlib.h b/extern/libsndfile-modified/src/ALAC/matrixlib.h new file mode 100644 index 000000000..d9be5feca --- /dev/null +++ b/extern/libsndfile-modified/src/ALAC/matrixlib.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2011 Apple Inc. All rights reserved. + * Copyright (C) 2012-2014 Erik de Castro Lopo + * + * @APPLE_APACHE_LICENSE_HEADER_START@ + * + * Licensed under the Apache License, Version 2.0 (the "License") ; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @APPLE_APACHE_LICENSE_HEADER_END@ + */ + +/* + File: matrixlib.h + + Contains: ALAC mixing/matrixing routines to/from 32-bit predictor buffers. + + Copyright: Copyright (C) 2004 to 2011 Apple, Inc. +*/ + +#ifndef __MATRIXLIB_H +#define __MATRIXLIB_H + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// 16-bit routines +void mix16 (const int32_t * in, uint32_t stride, int32_t * u, int32_t * v, int32_t numSamples, int32_t mixbits, int32_t mixres) ; +void unmix16 (const int32_t * u, int32_t * v, int32_t * out, uint32_t stride, int32_t numSamples, int32_t mixbits, int32_t mixres) ; + +// 20-bit routines +void mix20 (const int32_t * in, uint32_t stride, int32_t * u, int32_t * v, int32_t numSamples, int32_t mixbits, int32_t mixres) ; +void unmix20 (const int32_t * u, int32_t * v, int32_t * out, uint32_t stride, int32_t numSamples, int32_t mixbits, int32_t mixres) ; + +// 24-bit routines +// - 24-bit data sometimes compresses better by shifting off the bottom byte so these routines deal with +// the specified "unused lower bytes" in the combined "shift" buffer +void mix24 (const int32_t * in, uint32_t stride, int32_t * u, int32_t * v, int32_t numSamples, + int32_t mixbits, int32_t mixres, uint16_t * shiftUV, int32_t bytesShifted) ; +void unmix24 (const int32_t * u, int32_t * v, int32_t * out, uint32_t stride, int32_t numSamples, + int32_t mixbits, int32_t mixres, uint16_t * shiftUV, int32_t bytesShifted) ; + +// 32-bit routines +// - note that these really expect the internal data width to be < 32-bit but the arrays are 32-bit +// - otherwise, the calculations might overflow into the 33rd bit and be lost +// - therefore, these routines deal with the specified "unused lower" bytes in the combined "shift" buffer +void mix32 (const int32_t * in, uint32_t stride, int32_t * u, int32_t * v, int32_t numSamples, + int32_t mixbits, int32_t mixres, uint16_t * shiftUV, int32_t bytesShifted) ; +void unmix32 (const int32_t * u, int32_t * v, int32_t * out, uint32_t stride, int32_t numSamples, + int32_t mixbits, int32_t mixres, uint16_t * shiftUV, int32_t bytesShifted) ; + +// 20/24/32-bit <-> 32-bit helper routines (not really matrixing but convenient to put here) +void copy20ToPredictor (const int32_t * in, uint32_t stride, int32_t * out, int32_t numSamples) ; +void copy24ToPredictor (const int32_t * in, uint32_t stride, int32_t * out, int32_t numSamples) ; + +void copyPredictorTo24 (const int32_t * in, int32_t * out, uint32_t stride, int32_t numSamples) ; +void copyPredictorTo24Shift (const int32_t * in, uint16_t * shift, int32_t * out, uint32_t stride, int32_t numSamples, int32_t bytesShifted) ; +void copyPredictorTo20 (const int32_t * in, int32_t * out, uint32_t stride, int32_t numSamples) ; + +void copyPredictorTo32 (const int32_t * in, int32_t * out, uint32_t stride, int32_t numSamples) ; +void copyPredictorTo32Shift (const int32_t * in, uint16_t * shift, int32_t * out, uint32_t stride, int32_t numSamples, int32_t bytesShifted) ; + +#ifdef __cplusplus +} +#endif + +#endif /* __MATRIXLIB_H */ diff --git a/extern/libsndfile-modified/src/ALAC/shift.h b/extern/libsndfile-modified/src/ALAC/shift.h new file mode 100644 index 000000000..bce404d24 --- /dev/null +++ b/extern/libsndfile-modified/src/ALAC/shift.h @@ -0,0 +1,31 @@ +/* +** Copyright (C) 2014 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#if __GNUC__ +#define ALWAYS_INLINE __attribute__ ((always_inline)) +#elif defined _MSC_VER +#define ALWAYS_INLINE __forceinline +#else +#define ALWAYS_INLINE +#endif + + +static inline int32_t ALWAYS_INLINE +arith_shift_left (int32_t x, int shift) +{ return (int32_t) (((uint32_t) x) << shift) ; +} /* arith_shift_left */ diff --git a/extern/libsndfile-modified/src/G72x/ChangeLog b/extern/libsndfile-modified/src/G72x/ChangeLog new file mode 100644 index 000000000..aa108dff7 --- /dev/null +++ b/extern/libsndfile-modified/src/G72x/ChangeLog @@ -0,0 +1,50 @@ +2001-06-05 Erik de Castro Lopo + + * g72x.c + Added {} in function update () to prevent 'ambiguous else' warning messages. + +2000-07-14 Erik de Castro Lopo + + * g72x.c + Modified g72x_init_state () to fit in with the new structure of the code. + Implemented g72x_encode_block () and g72x_decode_block (). + +2000-07-12 Erik de Castro Lopo + + * g72x.h + Moved nearly all definitions and function prototypes from this file have been + moved to private.h. + Added an enum defining the 4 different G72x ADPCM codecs. + Added new function prototypes to define a cleaner interface to the encoder + and decoder. This new interface also allows samples to be processed in blocks + rather than on a sample by sample basis like the original code. + + * private.h + Added prototypes moved from g72x.h. + Changed struct g72x_state to a typedef struct { .. } G72x_PRIVATE. + Added fields to G72x_PRIVATE required for working on blocks of samples. + +2000-06-07 Erik de Castro Lopo + + * g72x.c + Fixed all compiler warnings. + Removed functions tandem_adjust() which is not required by libsndfile. + + * g721.c + Fixed all compiler warnings. + Removed functions tandem_adjust_alaw() and tandem_adjust_ulaw () which are not + required by libsndfile. + Removed second parameter to g721_encoder () which is not required. + + * g72x.h + Removed in_coding and out_coding parameters from all functions. These allowed + g72x encoding/decoding to/from A-law or u-law and are not required by libsndfile. + Removed unneeded defines for A-law, u-law and linear encoding. + + * g723_16.c + Removed second parameter (in_coding) for g723_16_encoder(). + Removed second parameter (out_coding) for g723_16_decoder(). + + * private.h + New file containing prototypes and tyepdefs private to G72x code. + diff --git a/extern/libsndfile-modified/src/G72x/README b/extern/libsndfile-modified/src/G72x/README new file mode 100644 index 000000000..e69de29bb diff --git a/extern/libsndfile-modified/src/G72x/README.original b/extern/libsndfile-modified/src/G72x/README.original new file mode 100644 index 000000000..23b0e7dd5 --- /dev/null +++ b/extern/libsndfile-modified/src/G72x/README.original @@ -0,0 +1,94 @@ +The files in this directory comprise ANSI-C language reference implementations +of the CCITT (International Telegraph and Telephone Consultative Committee) +G.711, G.721 and G.723 voice compressions. They have been tested on Sun +SPARCstations and passed 82 out of 84 test vectors published by CCITT +(Dec. 20, 1988) for G.721 and G.723. [The two remaining test vectors, +which the G.721 decoder implementation for u-law samples did not pass, +may be in error because they are identical to two other vectors for G.723_40.] + +This source code is released by Sun Microsystems, Inc. to the public domain. +Please give your acknowledgement in product literature if this code is used +in your product implementation. + +Sun Microsystems supports some CCITT audio formats in Solaris 2.0 system +software. However, Sun's implementations have been optimized for higher +performance on SPARCstations. + + +The source files for CCITT conversion routines in this directory are: + + g72x.h header file for g721.c, g723_24.c and g723_40.c + g711.c CCITT G.711 u-law and A-law compression + g72x.c common denominator of G.721 and G.723 ADPCM codes + g721.c CCITT G.721 32Kbps ADPCM coder (with g72x.c) + g723_24.c CCITT G.723 24Kbps ADPCM coder (with g72x.c) + g723_40.c CCITT G.723 40Kbps ADPCM coder (with g72x.c) + + +Simple conversions between u-law, A-law, and 16-bit linear PCM are invoked +as follows: + + unsigned char ucode, acode; + short pcm_val; + + ucode = linear2ulaw(pcm_val); + ucode = alaw2ulaw(acode); + + acode = linear2alaw(pcm_val); + acode = ulaw2alaw(ucode); + + pcm_val = ulaw2linear(ucode); + pcm_val = alaw2linear(acode); + + +The other CCITT compression routines are invoked as follows: + + #include "g72x.h" + + struct g72x_state state; + int sample, code; + + g72x_init_state(&state); + code = {g721,g723_24,g723_40}_encoder(sample, coding, &state); + sample = {g721,g723_24,g723_40}_decoder(code, coding, &state); + +where + coding = AUDIO_ENCODING_ULAW for 8-bit u-law samples + AUDIO_ENCODING_ALAW for 8-bit A-law samples + AUDIO_ENCODING_LINEAR for 16-bit linear PCM samples + + + +This directory also includes the following sample programs: + + encode.c CCITT ADPCM encoder + decode.c CCITT ADPCM decoder + Makefile makefile for the sample programs + + +The sample programs contain examples of how to call the various compression +routines and pack/unpack the bits. The sample programs read byte streams from +stdin and write to stdout. The input/output data is raw data (no file header +or other identifying information is embedded). The sample programs are +invoked as follows: + + encode [-3|4|5] [-a|u|l] outfile + decode [-3|4|5] [-a|u|l] outfile +where: + -3 encode to (decode from) G.723 24kbps (3-bit) data + -4 encode to (decode from) G.721 32kbps (4-bit) data [the default] + -5 encode to (decode from) G.723 40kbps (5-bit) data + -a encode from (decode to) A-law data + -u encode from (decode to) u-law data [the default] + -l encode from (decode to) 16-bit linear data + +Examples: + # Read 16-bit linear and output G.721 + encode -4 -l g721file + + # Read 40Kbps G.723 and output A-law + decode -5 -a alawfile + + # Compress and then decompress u-law data using 24Kbps G.723 + encode -3 ulawout + diff --git a/extern/libsndfile-modified/src/G72x/g721.c b/extern/libsndfile-modified/src/G72x/g721.c new file mode 100644 index 000000000..826d42c49 --- /dev/null +++ b/extern/libsndfile-modified/src/G72x/g721.c @@ -0,0 +1,155 @@ +/* + * This source code is a product of Sun Microsystems, Inc. and is provided + * for unrestricted use. Users may copy or modify this source code without + * charge. + * + * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING + * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun source code is provided with no support and without any obligation on + * the part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* + * g721.c + * + * Description: + * + * g721_encoder (), g721_decoder () + * + * These routines comprise an implementation of the CCITT G.721 ADPCM + * coding algorithm. Essentially, this implementation is identical to + * the bit level description except for a few deviations which + * take advantage of work station attributes, such as hardware 2's + * complement arithmetic and large memory. Specifically, certain time + * consuming operations such as multiplications are replaced + * with lookup tables and software 2's complement operations are + * replaced with hardware 2's complement. + * + * The deviation from the bit level specification (lookup tables) + * preserves the bit level performance specifications. + * + * As outlined in the G.721 Recommendation, the algorithm is broken + * down into modules. Each section of code below is preceded by + * the name of the module which it is implementing. + * + */ + +#include "g72x.h" +#include "g72x_priv.h" + +static short qtab_721 [7] = { -124, 80, 178, 246, 300, 349, 400 } ; +/* + * Maps G.721 code word to reconstructed scale factor normalized log + * magnitude values. + */ +static short _dqlntab [16] = { -2048, 4, 135, 213, 273, 323, 373, 425, + 425, 373, 323, 273, 213, 135, 4, -2048 } ; + +/* Maps G.721 code word to log of scale factor multiplier. */ +static short _witab [16] = { -12, 18, 41, 64, 112, 198, 355, 1122, + 1122, 355, 198, 112, 64, 41, 18, -12 } ; +/* + * Maps G.721 code words to a set of values whose long and short + * term averages are computed and then compared to give an indication + * how stationary (steady state) the signal is. + */ +static short _fitab [16] = { 0, 0, 0, 0x200, 0x200, 0x200, 0x600, 0xE00, + 0xE00, 0x600, 0x200, 0x200, 0x200, 0, 0, 0 } ; + +/* + * g721_encoder () + * + * Encodes the input vale of linear PCM, A-law or u-law data sl and returns + * the resulting code. -1 is returned for unknown input coding value. + */ +int +g721_encoder ( + int sl, + G72x_STATE *state_ptr) +{ + short sezi, se, sez ; /* ACCUM */ + short d ; /* SUBTA */ + short sr ; /* ADDB */ + short y ; /* MIX */ + short dqsez ; /* ADDC */ + short dq, i ; + + /* linearize input sample to 14-bit PCM */ + sl >>= 2 ; /* 14-bit dynamic range */ + + sezi = predictor_zero (state_ptr) ; + sez = sezi >> 1 ; + se = (sezi + predictor_pole (state_ptr)) >> 1 ; /* estimated signal */ + + d = sl - se ; /* estimation difference */ + + /* quantize the prediction difference */ + y = step_size (state_ptr) ; /* quantizer step size */ + i = quantize (d, y, qtab_721, 7) ; /* i = ADPCM code */ + + dq = reconstruct (i & 8, _dqlntab [i], y) ; /* quantized est diff */ + + sr = (dq < 0) ? se - (dq & 0x3FFF) : se + dq ; /* reconst. signal */ + + dqsez = sr + sez - se ; /* pole prediction diff. */ + + update (4, y, arith_shift_left (_witab [i], 5), _fitab [i], dq, sr, dqsez, state_ptr) ; + + return i ; +} + +/* + * g721_decoder () + * + * Description: + * + * Decodes a 4-bit code of G.721 encoded data of i and + * returns the resulting linear PCM, A-law or u-law value. + * return -1 for unknown out_coding value. + */ +int +g721_decoder ( + int i, + G72x_STATE *state_ptr) +{ + short sezi, sei, sez, se ; /* ACCUM */ + short y ; /* MIX */ + short sr ; /* ADDB */ + short dq ; + short dqsez ; + + i &= 0x0f ; /* mask to get proper bits */ + sezi = predictor_zero (state_ptr) ; + sez = sezi >> 1 ; + sei = sezi + predictor_pole (state_ptr) ; + se = sei >> 1 ; /* se = estimated signal */ + + y = step_size (state_ptr) ; /* dynamic quantizer step size */ + + dq = reconstruct (i & 0x08, _dqlntab [i], y) ; /* quantized diff. */ + + sr = (dq < 0) ? (se - (dq & 0x3FFF)) : se + dq ; /* reconst. signal */ + + dqsez = sr - se + sez ; /* pole prediction diff. */ + + update (4, y, arith_shift_left (_witab [i], 5), _fitab [i], dq, sr, dqsez, state_ptr) ; + + /* sr was 14-bit dynamic range */ + return arith_shift_left (sr, 2) ; +} + diff --git a/extern/libsndfile-modified/src/G72x/g723_16.c b/extern/libsndfile-modified/src/G72x/g723_16.c new file mode 100644 index 000000000..c377e6319 --- /dev/null +++ b/extern/libsndfile-modified/src/G72x/g723_16.c @@ -0,0 +1,162 @@ +/* + * This source code is a product of Sun Microsystems, Inc. and is provided + * for unrestricted use. Users may copy or modify this source code without + * charge. + * + * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING + * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun source code is provided with no support and without any obligation on + * the part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ +/* 16kbps version created, used 24kbps code and changing as little as possible. + * G.726 specs are available from ITU's gopher or WWW site (http://www.itu.ch) + * If any errors are found, please contact me at mrand@tamu.edu + * -Marc Randolph + */ + +/* + * g723_16.c + * + * Description: + * + * g723_16_encoder (), g723_16_decoder () + * + * These routines comprise an implementation of the CCITT G.726 16 Kbps + * ADPCM coding algorithm. Essentially, this implementation is identical to + * the bit level description except for a few deviations which take advantage + * of workstation attributes, such as hardware 2's complement arithmetic. + * + */ + +#include "g72x.h" +#include "g72x_priv.h" + +/* + * Maps G.723_16 code word to reconstructed scale factor normalized log + * magnitude values. Comes from Table 11/G.726 + */ +static short _dqlntab [4] = { 116, 365, 365, 116 } ; + +/* Maps G.723_16 code word to log of scale factor multiplier. + * + * _witab [4] is actually {-22 , 439, 439, -22}, but FILTD wants it + * as WI << 5 (multiplied by 32), so we'll do that here + */ +static short _witab [4] = { -704, 14048, 14048, -704 } ; + +/* + * Maps G.723_16 code words to a set of values whose long and short + * term averages are computed and then compared to give an indication + * how stationary (steady state) the signal is. + */ + +/* Comes from FUNCTF */ +static short _fitab [4] = { 0, 0xE00, 0xE00, 0 } ; + +/* Comes from quantizer decision level tables (Table 7/G.726) + */ +static short qtab_723_16 [1] = { 261 } ; + + +/* + * g723_16_encoder () + * + * Encodes a linear PCM, A-law or u-law input sample and returns its 2-bit code. + * Returns -1 if invalid input coding value. + */ +int +g723_16_encoder ( + int sl, + G72x_STATE *state_ptr) +{ + short sei, sezi, se, sez ; /* ACCUM */ + short d ; /* SUBTA */ + short y ; /* MIX */ + short sr ; /* ADDB */ + short dqsez ; /* ADDC */ + short dq, i ; + + /* linearize input sample to 14-bit PCM */ + sl >>= 2 ; /* sl of 14-bit dynamic range */ + + sezi = predictor_zero (state_ptr) ; + sez = sezi >> 1 ; + sei = sezi + predictor_pole (state_ptr) ; + se = sei >> 1 ; /* se = estimated signal */ + + d = sl - se ; /* d = estimation diff. */ + + /* quantize prediction difference d */ + y = step_size (state_ptr) ; /* quantizer step size */ + i = quantize (d, y, qtab_723_16, 1) ; /* i = ADPCM code */ + + /* Since quantize () only produces a three level output + * (1, 2, or 3), we must create the fourth one on our own + */ + if (i == 3) /* i code for the zero region */ + if ((d & 0x8000) == 0) /* If d > 0, i=3 isn't right... */ + i = 0 ; + + dq = reconstruct (i & 2, _dqlntab [i], y) ; /* quantized diff. */ + + sr = (dq < 0) ? se - (dq & 0x3FFF) : se + dq ; /* reconstructed signal */ + + dqsez = sr + sez - se ; /* pole prediction diff. */ + + update (2, y, _witab [i], _fitab [i], dq, sr, dqsez, state_ptr) ; + + return i ; +} + +/* + * g723_16_decoder () + * + * Decodes a 2-bit CCITT G.723_16 ADPCM code and returns + * the resulting 16-bit linear PCM, A-law or u-law sample value. + * -1 is returned if the output coding is unknown. + */ +int +g723_16_decoder ( + int i, + G72x_STATE *state_ptr) +{ + short sezi, sei, sez, se ; /* ACCUM */ + short y ; /* MIX */ + short sr ; /* ADDB */ + short dq ; + short dqsez ; + + i &= 0x03 ; /* mask to get proper bits */ + sezi = predictor_zero (state_ptr) ; + sez = sezi >> 1 ; + sei = sezi + predictor_pole (state_ptr) ; + se = sei >> 1 ; /* se = estimated signal */ + + y = step_size (state_ptr) ; /* adaptive quantizer step size */ + dq = reconstruct (i & 0x02, _dqlntab [i], y) ; /* unquantize pred diff */ + + sr = (dq < 0) ? (se - (dq & 0x3FFF)) : (se + dq) ; /* reconst. signal */ + + dqsez = sr - se + sez ; /* pole prediction diff. */ + + update (2, y, _witab [i], _fitab [i], dq, sr, dqsez, state_ptr) ; + + /* sr was of 14-bit dynamic range */ + return (sr << 2) ; +} + diff --git a/extern/libsndfile-modified/src/G72x/g723_24.c b/extern/libsndfile-modified/src/G72x/g723_24.c new file mode 100644 index 000000000..9cc2f6d50 --- /dev/null +++ b/extern/libsndfile-modified/src/G72x/g723_24.c @@ -0,0 +1,139 @@ +/* + * This source code is a product of Sun Microsystems, Inc. and is provided + * for unrestricted use. Users may copy or modify this source code without + * charge. + * + * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING + * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun source code is provided with no support and without any obligation on + * the part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* + * g723_24.c + * + * Description: + * + * g723_24_encoder (), g723_24_decoder () + * + * These routines comprise an implementation of the CCITT G.723 24 Kbps + * ADPCM coding algorithm. Essentially, this implementation is identical to + * the bit level description except for a few deviations which take advantage + * of workstation attributes, such as hardware 2's complement arithmetic. + * + */ + +#include "g72x.h" +#include "g72x_priv.h" + +/* + * Maps G.723_24 code word to reconstructed scale factor normalized log + * magnitude values. + */ +static short _dqlntab [8] = { -2048, 135, 273, 373, 373, 273, 135, -2048 } ; + +/* Maps G.723_24 code word to log of scale factor multiplier. */ +static short _witab [8] = { -128, 960, 4384, 18624, 18624, 4384, 960, -128 } ; + +/* + * Maps G.723_24 code words to a set of values whose long and short + * term averages are computed and then compared to give an indication + * how stationary (steady state) the signal is. + */ +static short _fitab [8] = { 0, 0x200, 0x400, 0xE00, 0xE00, 0x400, 0x200, 0 } ; + +static short qtab_723_24 [3] = { 8, 218, 331 } ; + +/* + * g723_24_encoder () + * + * Encodes a linear PCM, A-law or u-law input sample and returns its 3-bit code. + * Returns -1 if invalid input coding value. + */ +int +g723_24_encoder ( + int sl, + G72x_STATE *state_ptr) +{ + short sei, sezi, se, sez ; /* ACCUM */ + short d ; /* SUBTA */ + short y ; /* MIX */ + short sr ; /* ADDB */ + short dqsez ; /* ADDC */ + short dq, i ; + + /* linearize input sample to 14-bit PCM */ + sl >>= 2 ; /* sl of 14-bit dynamic range */ + + sezi = predictor_zero (state_ptr) ; + sez = sezi >> 1 ; + sei = sezi + predictor_pole (state_ptr) ; + se = sei >> 1 ; /* se = estimated signal */ + + d = sl - se ; /* d = estimation diff. */ + + /* quantize prediction difference d */ + y = step_size (state_ptr) ; /* quantizer step size */ + i = quantize (d, y, qtab_723_24, 3) ; /* i = ADPCM code */ + dq = reconstruct (i & 4, _dqlntab [i], y) ; /* quantized diff. */ + + sr = (dq < 0) ? se - (dq & 0x3FFF) : se + dq ; /* reconstructed signal */ + + dqsez = sr + sez - se ; /* pole prediction diff. */ + + update (3, y, _witab [i], _fitab [i], dq, sr, dqsez, state_ptr) ; + + return i ; +} + +/* + * g723_24_decoder () + * + * Decodes a 3-bit CCITT G.723_24 ADPCM code and returns + * the resulting 16-bit linear PCM, A-law or u-law sample value. + * -1 is returned if the output coding is unknown. + */ +int +g723_24_decoder ( + int i, + G72x_STATE *state_ptr) +{ + short sezi, sei, sez, se ; /* ACCUM */ + short y ; /* MIX */ + short sr ; /* ADDB */ + short dq ; + short dqsez ; + + i &= 0x07 ; /* mask to get proper bits */ + sezi = predictor_zero (state_ptr) ; + sez = sezi >> 1 ; + sei = sezi + predictor_pole (state_ptr) ; + se = sei >> 1 ; /* se = estimated signal */ + + y = step_size (state_ptr) ; /* adaptive quantizer step size */ + dq = reconstruct (i & 0x04, _dqlntab [i], y) ; /* unquantize pred diff */ + + sr = (dq < 0) ? (se - (dq & 0x3FFF)) : (se + dq) ; /* reconst. signal */ + + dqsez = sr - se + sez ; /* pole prediction diff. */ + + update (3, y, _witab [i], _fitab [i], dq, sr, dqsez, state_ptr) ; + + return arith_shift_left (sr, 2) ; /* sr was of 14-bit dynamic range */ +} + diff --git a/extern/libsndfile-modified/src/G72x/g723_40.c b/extern/libsndfile-modified/src/G72x/g723_40.c new file mode 100644 index 000000000..f7f8f7427 --- /dev/null +++ b/extern/libsndfile-modified/src/G72x/g723_40.c @@ -0,0 +1,153 @@ +/* + * This source code is a product of Sun Microsystems, Inc. and is provided + * for unrestricted use. Users may copy or modify this source code without + * charge. + * + * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING + * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun source code is provided with no support and without any obligation on + * the part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* + * g723_40.c + * + * Description: + * + * g723_40_encoder (), g723_40_decoder () + * + * These routines comprise an implementation of the CCITT G.723 40Kbps + * ADPCM coding algorithm. Essentially, this implementation is identical to + * the bit level description except for a few deviations which + * take advantage of workstation attributes, such as hardware 2's + * complement arithmetic. + * + * The deviation from the bit level specification (lookup tables), + * preserves the bit level performance specifications. + * + * As outlined in the G.723 Recommendation, the algorithm is broken + * down into modules. Each section of code below is preceded by + * the name of the module which it is implementing. + * + */ + +#include "g72x.h" +#include "g72x_priv.h" + +/* + * Maps G.723_40 code word to ructeconstructed scale factor normalized log + * magnitude values. + */ +static short _dqlntab [32] = { -2048, -66, 28, 104, 169, 224, 274, 318, + 358, 395, 429, 459, 488, 514, 539, 566, + 566, 539, 514, 488, 459, 429, 395, 358, + 318, 274, 224, 169, 104, 28, -66, -2048 } ; + +/* Maps G.723_40 code word to log of scale factor multiplier. */ +static short _witab [32] = { 448, 448, 768, 1248, 1280, 1312, 1856, 3200, + 4512, 5728, 7008, 8960, 11456, 14080, 16928, 22272, + 22272, 16928, 14080, 11456, 8960, 7008, 5728, 4512, + 3200, 1856, 1312, 1280, 1248, 768, 448, 448 } ; + +/* + * Maps G.723_40 code words to a set of values whose long and short + * term averages are computed and then compared to give an indication + * how stationary (steady state) the signal is. + */ +static short _fitab [32] = { 0, 0, 0, 0, 0, 0x200, 0x200, 0x200, + 0x200, 0x200, 0x400, 0x600, 0x800, 0xA00, 0xC00, 0xC00, + 0xC00, 0xC00, 0xA00, 0x800, 0x600, 0x400, 0x200, 0x200, + 0x200, 0x200, 0x200, 0, 0, 0, 0, 0 } ; + +static short qtab_723_40 [15] = { -122, -16, 68, 139, 198, 250, 298, 339, + 378, 413, 445, 475, 502, 528, 553 } ; + +/* + * g723_40_encoder () + * + * Encodes a 16-bit linear PCM, A-law or u-law input sample and retuens + * the resulting 5-bit CCITT G.723 40Kbps code. + * Returns -1 if the input coding value is invalid. + */ +int g723_40_encoder (int sl, G72x_STATE *state_ptr) +{ + short sei, sezi, se, sez ; /* ACCUM */ + short d ; /* SUBTA */ + short y ; /* MIX */ + short sr ; /* ADDB */ + short dqsez ; /* ADDC */ + short dq, i ; + + /* linearize input sample to 14-bit PCM */ + sl >>= 2 ; /* sl of 14-bit dynamic range */ + + sezi = predictor_zero (state_ptr) ; + sez = sezi >> 1 ; + sei = sezi + predictor_pole (state_ptr) ; + se = sei >> 1 ; /* se = estimated signal */ + + d = sl - se ; /* d = estimation difference */ + + /* quantize prediction difference */ + y = step_size (state_ptr) ; /* adaptive quantizer step size */ + i = quantize (d, y, qtab_723_40, 15) ; /* i = ADPCM code */ + + dq = reconstruct (i & 0x10, _dqlntab [i], y) ; /* quantized diff */ + + sr = (dq < 0) ? se - (dq & 0x7FFF) : se + dq ; /* reconstructed signal */ + + dqsez = sr + sez - se ; /* dqsez = pole prediction diff. */ + + update (5, y, _witab [i], _fitab [i], dq, sr, dqsez, state_ptr) ; + + return i ; +} + +/* + * g723_40_decoder () + * + * Decodes a 5-bit CCITT G.723 40Kbps code and returns + * the resulting 16-bit linear PCM, A-law or u-law sample value. + * -1 is returned if the output coding is unknown. + */ +int g723_40_decoder (int i, G72x_STATE *state_ptr) +{ + short sezi, sei, sez, se ; /* ACCUM */ + short y ; /* MIX */ + short sr ; /* ADDB */ + short dq ; + short dqsez ; + + i &= 0x1f ; /* mask to get proper bits */ + sezi = predictor_zero (state_ptr) ; + sez = sezi >> 1 ; + sei = sezi + predictor_pole (state_ptr) ; + se = sei >> 1 ; /* se = estimated signal */ + + y = step_size (state_ptr) ; /* adaptive quantizer step size */ + dq = reconstruct (i & 0x10, _dqlntab [i], y) ; /* estimation diff. */ + + sr = (dq < 0) ? (se - (dq & 0x7FFF)) : (se + dq) ; /* reconst. signal */ + + dqsez = sr - se + sez ; /* pole prediction diff. */ + + update (5, y, _witab [i], _fitab [i], dq, sr, dqsez, state_ptr) ; + + return arith_shift_left (sr, 2) ; /* sr was of 14-bit dynamic range */ +} + diff --git a/extern/libsndfile-modified/src/G72x/g72x.c b/extern/libsndfile-modified/src/G72x/g72x.c new file mode 100644 index 000000000..2d6469cf1 --- /dev/null +++ b/extern/libsndfile-modified/src/G72x/g72x.c @@ -0,0 +1,645 @@ +/* + * This source code is a product of Sun Microsystems, Inc. and is provided + * for unrestricted use. Users may copy or modify this source code without + * charge. + * + * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING + * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun source code is provided with no support and without any obligation on + * the part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* + * g72x.c + * + * Common routines for G.721 and G.723 conversions. + */ + +#include +#include +#include + +#include "g72x.h" +#include "g72x_priv.h" + +static G72x_STATE * g72x_state_new (void) ; +static int unpack_bytes (int bits, int blocksize, const unsigned char * block, short * samples) ; +static int pack_bytes (int bits, const short * samples, unsigned char * block) ; + +static +short power2 [15] = +{ 1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80, + 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000 +} ; + +/* + * quan () + * + * quantizes the input val against the table of size short integers. + * It returns i if table [i - 1] <= val < table [i]. + * + * Using linear search for simple coding. + */ +static +int quan (int val, short *table, int size) +{ + int i ; + + for (i = 0 ; i < size ; i++) + if (val < *table++) + break ; + return i ; +} + +/* + * fmult () + * + * returns the integer product of the 14-bit integer "an" and + * "floating point" representation (4-bit exponent, 6-bit mantessa) "srn". + */ +static +int fmult (int an, int srn) +{ + short anmag, anexp, anmant ; + short wanexp, wanmant ; + short retval ; + + anmag = (an > 0) ? an : ((-an) & 0x1FFF) ; + anexp = quan (anmag, power2, 15) - 6 ; + anmant = (anmag == 0) ? 32 : + (anexp >= 0) ? anmag >> anexp : anmag << -anexp ; + wanexp = anexp + ((srn >> 6) & 0xF) - 13 ; + + /* + ** The original was : + ** wanmant = (anmant * (srn & 0x3F) + 0x30) >> 4 ; + ** but could see no valid reason for the + 0x30. + ** Removed it and it improved the SNR of the codec. + */ + + wanmant = (anmant * (srn & 0x3F)) >> 4 ; + + retval = (wanexp >= 0) ? ((wanmant << wanexp) & 0x7FFF) : (wanmant >> -wanexp) ; + + return (((an ^ srn) < 0) ? -retval : retval) ; +} + +static G72x_STATE * g72x_state_new (void) +{ return calloc (1, sizeof (G72x_STATE)) ; +} + +/* + * private_init_state () + * + * This routine initializes and/or resets the G72x_PRIVATE structure + * pointed to by 'state_ptr'. + * All the initial state values are specified in the CCITT G.721 document. + */ +void private_init_state (G72x_STATE *state_ptr) +{ + int cnta ; + + state_ptr->yl = 34816 ; + state_ptr->yu = 544 ; + state_ptr->dms = 0 ; + state_ptr->dml = 0 ; + state_ptr->ap = 0 ; + for (cnta = 0 ; cnta < 2 ; cnta++) + { state_ptr->a [cnta] = 0 ; + state_ptr->pk [cnta] = 0 ; + state_ptr->sr [cnta] = 32 ; + } + for (cnta = 0 ; cnta < 6 ; cnta++) + { state_ptr->b [cnta] = 0 ; + state_ptr->dq [cnta] = 32 ; + } + state_ptr->td = 0 ; +} /* private_init_state */ + +struct g72x_state * g72x_reader_init (int codec, int *blocksize, int *samplesperblock) +{ G72x_STATE *pstate ; + + if ((pstate = g72x_state_new ()) == NULL) + return NULL ; + + private_init_state (pstate) ; + + pstate->encoder = NULL ; + + switch (codec) + { case G723_16_BITS_PER_SAMPLE : /* 2 bits per sample. */ + pstate->decoder = g723_16_decoder ; + *blocksize = G723_16_BYTES_PER_BLOCK ; + *samplesperblock = G723_16_SAMPLES_PER_BLOCK ; + pstate->codec_bits = 2 ; + pstate->blocksize = G723_16_BYTES_PER_BLOCK ; + pstate->samplesperblock = G723_16_SAMPLES_PER_BLOCK ; + break ; + + case G723_24_BITS_PER_SAMPLE : /* 3 bits per sample. */ + pstate->decoder = g723_24_decoder ; + *blocksize = G723_24_BYTES_PER_BLOCK ; + *samplesperblock = G723_24_SAMPLES_PER_BLOCK ; + pstate->codec_bits = 3 ; + pstate->blocksize = G723_24_BYTES_PER_BLOCK ; + pstate->samplesperblock = G723_24_SAMPLES_PER_BLOCK ; + break ; + + case G721_32_BITS_PER_SAMPLE : /* 4 bits per sample. */ + pstate->decoder = g721_decoder ; + *blocksize = G721_32_BYTES_PER_BLOCK ; + *samplesperblock = G721_32_SAMPLES_PER_BLOCK ; + pstate->codec_bits = 4 ; + pstate->blocksize = G721_32_BYTES_PER_BLOCK ; + pstate->samplesperblock = G721_32_SAMPLES_PER_BLOCK ; + break ; + + case G721_40_BITS_PER_SAMPLE : /* 5 bits per sample. */ + pstate->decoder = g723_40_decoder ; + *blocksize = G721_40_BYTES_PER_BLOCK ; + *samplesperblock = G721_40_SAMPLES_PER_BLOCK ; + pstate->codec_bits = 5 ; + pstate->blocksize = G721_40_BYTES_PER_BLOCK ; + pstate->samplesperblock = G721_40_SAMPLES_PER_BLOCK ; + break ; + + default : + free (pstate) ; + return NULL ; + } ; + + return pstate ; +} /* g72x_reader_init */ + +struct g72x_state * g72x_writer_init (int codec, int *blocksize, int *samplesperblock) +{ G72x_STATE *pstate ; + + if ((pstate = g72x_state_new ()) == NULL) + return NULL ; + + private_init_state (pstate) ; + pstate->decoder = NULL ; + + switch (codec) + { case G723_16_BITS_PER_SAMPLE : /* 2 bits per sample. */ + pstate->encoder = g723_16_encoder ; + *blocksize = G723_16_BYTES_PER_BLOCK ; + *samplesperblock = G723_16_SAMPLES_PER_BLOCK ; + pstate->codec_bits = 2 ; + pstate->blocksize = G723_16_BYTES_PER_BLOCK ; + pstate->samplesperblock = G723_16_SAMPLES_PER_BLOCK ; + break ; + + case G723_24_BITS_PER_SAMPLE : /* 3 bits per sample. */ + pstate->encoder = g723_24_encoder ; + *blocksize = G723_24_BYTES_PER_BLOCK ; + *samplesperblock = G723_24_SAMPLES_PER_BLOCK ; + pstate->codec_bits = 3 ; + pstate->blocksize = G723_24_BYTES_PER_BLOCK ; + pstate->samplesperblock = G723_24_SAMPLES_PER_BLOCK ; + break ; + + case G721_32_BITS_PER_SAMPLE : /* 4 bits per sample. */ + pstate->encoder = g721_encoder ; + *blocksize = G721_32_BYTES_PER_BLOCK ; + *samplesperblock = G721_32_SAMPLES_PER_BLOCK ; + pstate->codec_bits = 4 ; + pstate->blocksize = G721_32_BYTES_PER_BLOCK ; + pstate->samplesperblock = G721_32_SAMPLES_PER_BLOCK ; + break ; + + case G721_40_BITS_PER_SAMPLE : /* 5 bits per sample. */ + pstate->encoder = g723_40_encoder ; + *blocksize = G721_40_BYTES_PER_BLOCK ; + *samplesperblock = G721_40_SAMPLES_PER_BLOCK ; + pstate->codec_bits = 5 ; + pstate->blocksize = G721_40_BYTES_PER_BLOCK ; + pstate->samplesperblock = G721_40_SAMPLES_PER_BLOCK ; + break ; + + default : + free (pstate) ; + return NULL ; + } ; + + return pstate ; +} /* g72x_writer_init */ + +int g72x_decode_block (G72x_STATE *pstate, const unsigned char *block, short *samples) +{ int k, count ; + + count = unpack_bytes (pstate->codec_bits, pstate->blocksize, block, samples) ; + + for (k = 0 ; k < count ; k++) + samples [k] = pstate->decoder (samples [k], pstate) ; + + return 0 ; +} /* g72x_decode_block */ + +int g72x_encode_block (G72x_STATE *pstate, short *samples, unsigned char *block) +{ int k, count ; + + for (k = 0 ; k < pstate->samplesperblock ; k++) + samples [k] = pstate->encoder (samples [k], pstate) ; + + count = pack_bytes (pstate->codec_bits, samples, block) ; + + return count ; +} /* g72x_encode_block */ + +/* + * predictor_zero () + * + * computes the estimated signal from 6-zero predictor. + * + */ +int predictor_zero (G72x_STATE *state_ptr) +{ + int i ; + int sezi ; + + sezi = fmult (state_ptr->b [0] >> 2, state_ptr->dq [0]) ; + for (i = 1 ; i < 6 ; i++) /* ACCUM */ + sezi += fmult (state_ptr->b [i] >> 2, state_ptr->dq [i]) ; + return sezi ; +} +/* + * predictor_pole () + * + * computes the estimated signal from 2-pole predictor. + * + */ +int predictor_pole (G72x_STATE *state_ptr) +{ + return (fmult (state_ptr->a [1] >> 2, state_ptr->sr [1]) + + fmult (state_ptr->a [0] >> 2, state_ptr->sr [0])) ; +} +/* + * step_size () + * + * computes the quantization step size of the adaptive quantizer. + * + */ +int step_size (G72x_STATE *state_ptr) +{ + int y ; + int dif ; + int al ; + + if (state_ptr->ap >= 256) + return (state_ptr->yu) ; + else { + y = state_ptr->yl >> 6 ; + dif = state_ptr->yu - y ; + al = state_ptr->ap >> 2 ; + if (dif > 0) + y += (dif * al) >> 6 ; + else if (dif < 0) + y += (dif * al + 0x3F) >> 6 ; + return y ; + } +} + +/* + * quantize () + * + * Given a raw sample, 'd', of the difference signal and a + * quantization step size scale factor, 'y', this routine returns the + * ADPCM codeword to which that sample gets quantized. The step + * size scale factor division operation is done in the log base 2 domain + * as a subtraction. + */ +int quantize ( + int d, /* Raw difference signal sample */ + int y, /* Step size multiplier */ + short *table, /* quantization table */ + int size) /* table size of short integers */ +{ + short dqm ; /* Magnitude of 'd' */ + short expon ; /* Integer part of base 2 log of 'd' */ + short mant ; /* Fractional part of base 2 log */ + short dl ; /* Log of magnitude of 'd' */ + short dln ; /* Step size scale factor normalized log */ + int i ; + + /* + * LOG + * + * Compute base 2 log of 'd', and store in 'dl'. + */ + dqm = abs (d) ; + expon = quan (dqm >> 1, power2, 15) ; + mant = ((dqm << 7) >> expon) & 0x7F ; /* Fractional portion. */ + dl = (expon << 7) + mant ; + + /* + * SUBTB + * + * "Divide" by step size multiplier. + */ + dln = dl - (y >> 2) ; + + /* + * QUAN + * + * Obtain codword i for 'd'. + */ + i = quan (dln, table, size) ; + if (d < 0) /* take 1's complement of i */ + return ((size << 1) + 1 - i) ; + else if (i == 0) /* take 1's complement of 0 */ + return ((size << 1) + 1) ; /* new in 1988 */ + + return i ; +} +/* + * reconstruct () + * + * Returns reconstructed difference signal 'dq' obtained from + * codeword 'i' and quantization step size scale factor 'y'. + * Multiplication is performed in log base 2 domain as addition. + */ +int +reconstruct ( + int sign, /* 0 for non-negative value */ + int dqln, /* G.72x codeword */ + int y) /* Step size multiplier */ +{ + short dql ; /* Log of 'dq' magnitude */ + short dex ; /* Integer part of log */ + short dqt ; + short dq ; /* Reconstructed difference signal sample */ + + dql = dqln + (y >> 2) ; /* ADDA */ + + if (dql < 0) + return ((sign) ? -0x8000 : 0) ; + else /* ANTILOG */ + { dex = (dql >> 7) & 15 ; + dqt = 128 + (dql & 127) ; + dq = (dqt << 7) >> (14 - dex) ; + return ((sign) ? (dq - 0x8000) : dq) ; + } +} + + +/* + * update () + * + * updates the state variables for each output code + */ +void +update ( + int code_size, /* distinguish 723_40 with others */ + int y, /* quantizer step size */ + int wi, /* scale factor multiplier */ + int fi, /* for long/short term energies */ + int dq, /* quantized prediction difference */ + int sr, /* reconstructed signal */ + int dqsez, /* difference from 2-pole predictor */ + G72x_STATE *state_ptr) /* coder state pointer */ +{ + int cnt ; + short mag, expon ; /* Adaptive predictor, FLOAT A */ + short a2p = 0 ; /* LIMC */ + short a1ul ; /* UPA1 */ + short pks1 ; /* UPA2 */ + short fa1 ; + char tr ; /* tone/transition detector */ + short ylint, thr2, dqthr ; + short ylfrac, thr1 ; + short pk0 ; + + pk0 = (dqsez < 0) ? 1 : 0 ; /* needed in updating predictor poles */ + + mag = dq & 0x7FFF ; /* prediction difference magnitude */ + /* TRANS */ + ylint = state_ptr->yl >> 15 ; /* exponent part of yl */ + ylfrac = (state_ptr->yl >> 10) & 0x1F ; /* fractional part of yl */ + thr1 = (32 + ylfrac) << ylint ; /* threshold */ + thr2 = (ylint > 9) ? 31 << 10 : thr1 ; /* limit thr2 to 31 << 10 */ + dqthr = (thr2 + (thr2 >> 1)) >> 1 ; /* dqthr = 0.75 * thr2 */ + if (state_ptr->td == 0) /* signal supposed voice */ + tr = 0 ; + else if (mag <= dqthr) /* supposed data, but small mag */ + tr = 0 ; /* treated as voice */ + else /* signal is data (modem) */ + tr = 1 ; + + /* + * Quantizer scale factor adaptation. + */ + + /* FUNCTW & FILTD & DELAY */ + /* update non-steady state step size multiplier */ + state_ptr->yu = y + ((wi - y) >> 5) ; + + /* LIMB */ + if (state_ptr->yu < 544) /* 544 <= yu <= 5120 */ + state_ptr->yu = 544 ; + else if (state_ptr->yu > 5120) + state_ptr->yu = 5120 ; + + /* FILTE & DELAY */ + /* update steady state step size multiplier */ + state_ptr->yl += state_ptr->yu + ((-state_ptr->yl) >> 6) ; + + /* + * Adaptive predictor coefficients. + */ + if (tr == 1) { /* reset a's and b's for modem signal */ + state_ptr->a [0] = 0 ; + state_ptr->a [1] = 0 ; + state_ptr->b [0] = 0 ; + state_ptr->b [1] = 0 ; + state_ptr->b [2] = 0 ; + state_ptr->b [3] = 0 ; + state_ptr->b [4] = 0 ; + state_ptr->b [5] = 0 ; + } + else /* update a's and b's */ + { pks1 = pk0 ^ state_ptr->pk [0] ; /* UPA2 */ + + /* update predictor pole a [1] */ + a2p = state_ptr->a [1] - (state_ptr->a [1] >> 7) ; + if (dqsez != 0) + { fa1 = (pks1) ? state_ptr->a [0] : -state_ptr->a [0] ; + if (fa1 < -8191) /* a2p = function of fa1 */ + a2p -= 0x100 ; + else if (fa1 > 8191) + a2p += 0xFF ; + else + a2p += fa1 >> 5 ; + + if (pk0 ^ state_ptr->pk [1]) + { /* LIMC */ + if (a2p <= -12160) + a2p = -12288 ; + else if (a2p >= 12416) + a2p = 12288 ; + else + a2p -= 0x80 ; + } + else if (a2p <= -12416) + a2p = -12288 ; + else if (a2p >= 12160) + a2p = 12288 ; + else + a2p += 0x80 ; + } + + /* TRIGB & DELAY */ + state_ptr->a [1] = a2p ; + + /* UPA1 */ + /* update predictor pole a [0] */ + state_ptr->a [0] -= state_ptr->a [0] >> 8 ; + if (dqsez != 0) + { if (pks1 == 0) + state_ptr->a [0] += 192 ; + else + state_ptr->a [0] -= 192 ; + } ; + + /* LIMD */ + a1ul = 15360 - a2p ; + if (state_ptr->a [0] < -a1ul) + state_ptr->a [0] = -a1ul ; + else if (state_ptr->a [0] > a1ul) + state_ptr->a [0] = a1ul ; + + /* UPB : update predictor zeros b [6] */ + for (cnt = 0 ; cnt < 6 ; cnt++) + { if (code_size == 5) /* for 40Kbps G.723 */ + state_ptr->b [cnt] -= state_ptr->b [cnt] >> 9 ; + else /* for G.721 and 24Kbps G.723 */ + state_ptr->b [cnt] -= state_ptr->b [cnt] >> 8 ; + if (dq & 0x7FFF) /* XOR */ + { if ((dq ^ state_ptr->dq [cnt]) >= 0) + state_ptr->b [cnt] += 128 ; + else + state_ptr->b [cnt] -= 128 ; + } + } + } + + for (cnt = 5 ; cnt > 0 ; cnt--) + state_ptr->dq [cnt] = state_ptr->dq [cnt - 1] ; + /* FLOAT A : convert dq [0] to 4-bit exp, 6-bit mantissa f.p. */ + if (mag == 0) + state_ptr->dq [0] = (dq >= 0) ? 0x20 : 0xFC20 ; + else + { expon = quan (mag, power2, 15) ; + state_ptr->dq [0] = (dq >= 0) ? + (expon << 6) + ((mag << 6) >> expon) : + (expon << 6) + ((mag << 6) >> expon) - 0x400 ; + } + + state_ptr->sr [1] = state_ptr->sr [0] ; + /* FLOAT B : convert sr to 4-bit exp., 6-bit mantissa f.p. */ + if (sr == 0) + state_ptr->sr [0] = 0x20 ; + else if (sr > 0) + { expon = quan (sr, power2, 15) ; + state_ptr->sr [0] = (expon << 6) + ((sr << 6) >> expon) ; + } + else if (sr > -32768) + { mag = -sr ; + expon = quan (mag, power2, 15) ; + state_ptr->sr [0] = (expon << 6) + ((mag << 6) >> expon) - 0x400 ; + } + else + state_ptr->sr [0] = (short) 0xFC20 ; + + /* DELAY A */ + state_ptr->pk [1] = state_ptr->pk [0] ; + state_ptr->pk [0] = pk0 ; + + /* TONE */ + if (tr == 1) /* this sample has been treated as data */ + state_ptr->td = 0 ; /* next one will be treated as voice */ + else if (a2p < -11776) /* small sample-to-sample correlation */ + state_ptr->td = 1 ; /* signal may be data */ + else /* signal is voice */ + state_ptr->td = 0 ; + + /* + * Adaptation speed control. + */ + state_ptr->dms += (fi - state_ptr->dms) >> 5 ; /* FILTA */ + state_ptr->dml += (((fi << 2) - state_ptr->dml) >> 7) ; /* FILTB */ + + if (tr == 1) + state_ptr->ap = 256 ; + else if (y < 1536) /* SUBTC */ + state_ptr->ap += (0x200 - state_ptr->ap) >> 4 ; + else if (state_ptr->td == 1) + state_ptr->ap += (0x200 - state_ptr->ap) >> 4 ; + else if (abs ((state_ptr->dms << 2) - state_ptr->dml) >= (state_ptr->dml >> 3)) + state_ptr->ap += (0x200 - state_ptr->ap) >> 4 ; + else + state_ptr->ap += (-state_ptr->ap) >> 4 ; + + return ; +} /* update */ + +/*------------------------------------------------------------------------------ +*/ + +static int +unpack_bytes (int bits, int blocksize, const unsigned char * block, short * samples) +{ unsigned int in_buffer = 0 ; + unsigned char in_byte ; + int k, in_bits = 0, bindex = 0 ; + + for (k = 0 ; bindex <= blocksize && k < G72x_BLOCK_SIZE ; k++) + { if (in_bits < bits) + { in_byte = block [bindex++] ; + + in_buffer |= (in_byte << in_bits) ; + in_bits += 8 ; + } + samples [k] = in_buffer & ((1 << bits) - 1) ; + in_buffer >>= bits ; + in_bits -= bits ; + } ; + + return k ; +} /* unpack_bytes */ + +static int +pack_bytes (int bits, const short * samples, unsigned char * block) +{ + unsigned int out_buffer = 0 ; + int k, bindex = 0, out_bits = 0 ; + unsigned char out_byte ; + + for (k = 0 ; k < G72x_BLOCK_SIZE ; k++) + { out_buffer |= (samples [k] << out_bits) ; + out_bits += bits ; + if (out_bits >= 8) + { out_byte = out_buffer & 0xFF ; + out_bits -= 8 ; + out_buffer >>= 8 ; + block [bindex++] = out_byte ; + } + } ; + + return bindex ; +} /* pack_bytes */ + diff --git a/extern/libsndfile-modified/src/G72x/g72x.h b/extern/libsndfile-modified/src/G72x/g72x.h new file mode 100644 index 000000000..d7631e6d8 --- /dev/null +++ b/extern/libsndfile-modified/src/G72x/g72x.h @@ -0,0 +1,91 @@ +/* +** Copyright (C) 1999-2011 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/* +** This file is not the same as the original file from Sun Microsystems. Nearly +** all the original definitions and function prototypes that were in the file +** of this name have been moved to g72x_priv.h. +*/ + +#ifndef G72X_HEADER_FILE +#define G72X_HEADER_FILE + +/* +** Number of samples per block to process. +** Must be a common multiple of possible bits per sample : 2, 3, 4, 5 and 8. +*/ +#define G72x_BLOCK_SIZE (3 * 5 * 8) + +/* +** Identifiers for the differing kinds of G72x ADPCM codecs. +** The identifiers also define the number of encoded bits per sample. +*/ + +enum +{ G723_16_BITS_PER_SAMPLE = 2, + G723_24_BITS_PER_SAMPLE = 3, + G723_40_BITS_PER_SAMPLE = 5, + + G721_32_BITS_PER_SAMPLE = 4, + G721_40_BITS_PER_SAMPLE = 5, + + G723_16_SAMPLES_PER_BLOCK = G72x_BLOCK_SIZE, + G723_24_SAMPLES_PER_BLOCK = G723_24_BITS_PER_SAMPLE * (G72x_BLOCK_SIZE / G723_24_BITS_PER_SAMPLE), + G723_40_SAMPLES_PER_BLOCK = G723_40_BITS_PER_SAMPLE * (G72x_BLOCK_SIZE / G723_40_BITS_PER_SAMPLE), + + G721_32_SAMPLES_PER_BLOCK = G72x_BLOCK_SIZE, + G721_40_SAMPLES_PER_BLOCK = G721_40_BITS_PER_SAMPLE * (G72x_BLOCK_SIZE / G721_40_BITS_PER_SAMPLE), + + G723_16_BYTES_PER_BLOCK = (G723_16_BITS_PER_SAMPLE * G72x_BLOCK_SIZE) / 8, + G723_24_BYTES_PER_BLOCK = (G723_24_BITS_PER_SAMPLE * G72x_BLOCK_SIZE) / 8, + G723_40_BYTES_PER_BLOCK = (G723_40_BITS_PER_SAMPLE * G72x_BLOCK_SIZE) / 8, + + G721_32_BYTES_PER_BLOCK = (G721_32_BITS_PER_SAMPLE * G72x_BLOCK_SIZE) / 8, + G721_40_BYTES_PER_BLOCK = (G721_40_BITS_PER_SAMPLE * G72x_BLOCK_SIZE) / 8 +} ; + +/* Forward declaration of of g72x_state. */ + +struct g72x_state ; + +/* External function definitions. */ + +struct g72x_state * g72x_reader_init (int codec, int *blocksize, int *samplesperblock) ; +struct g72x_state * g72x_writer_init (int codec, int *blocksize, int *samplesperblock) ; +/* +** Initialize the ADPCM state table for the given codec. +** Return 0 on success, 1 on fail. +*/ + +int g72x_decode_block (struct g72x_state *pstate, const unsigned char *block, short *samples) ; +/* +** The caller fills data->block with data->bytes bytes before calling the +** function. The value data->bytes must be an integer multiple of +** data->blocksize and be <= data->max_bytes. +** When it returns, the caller can read out data->samples samples. +*/ + +int g72x_encode_block (struct g72x_state *pstate, short *samples, unsigned char *block) ; +/* +** The caller fills state->samples some integer multiple data->samples_per_block +** (up to G72x_BLOCK_SIZE) samples before calling the function. +** When it returns, the caller can read out bytes encoded bytes. +*/ + +#endif /* !G72X_HEADER_FILE */ + diff --git a/extern/libsndfile-modified/src/G72x/g72x_priv.h b/extern/libsndfile-modified/src/G72x/g72x_priv.h new file mode 100644 index 000000000..6a194ec3f --- /dev/null +++ b/extern/libsndfile-modified/src/G72x/g72x_priv.h @@ -0,0 +1,129 @@ +/* + * This source code is a product of Sun Microsystems, Inc. and is provided + * for unrestricted use. Users may copy or modify this source code without + * charge. + * + * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING + * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun source code is provided with no support and without any obligation on + * the part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +#ifndef G72X_PRIVATE_H +#define G72X_PRIVATE_H + +#ifdef __cplusplus +#error "This code is not designed to be compiled with a C++ compiler." +#endif + +/* +** The following is the definition of the state structure used by the +** G.721/G.723 encoder and decoder to preserve their internal state +** between successive calls. The meanings of the majority of the state +** structure fields are explained in detail in the CCITT Recommendation +** G.721. The field names are essentially identical to variable names +** in the bit level description of the coding algorithm included in this +** Recommendation. +*/ + +struct g72x_state +{ long yl ; /* Locked or steady state step size multiplier. */ + short yu ; /* Unlocked or non-steady state step size multiplier. */ + short dms ; /* Short term energy estimate. */ + short dml ; /* Long term energy estimate. */ + short ap ; /* Linear weighting coefficient of 'yl' and 'yu'. */ + + short a [2] ; /* Coefficients of pole portion of prediction filter. */ + short b [6] ; /* Coefficients of zero portion of prediction filter. */ + short pk [2] ; /* + ** Signs of previous two samples of a partially + ** reconstructed signal. + **/ + short dq [6] ; /* + ** Previous 6 samples of the quantized difference + ** signal represented in an internal floating point + ** format. + **/ + short sr [2] ; /* + ** Previous 2 samples of the quantized difference + ** signal represented in an internal floating point + ** format. + */ + char td ; /* delayed tone detect, new in 1988 version */ + + /* The following struct members were added for libsndfile. The original + ** code worked by calling a set of functions on a sample by sample basis + ** which is slow on architectures like Intel x86. For libsndfile, this + ** was changed so that the encoding and decoding routines could work on + ** a block of samples at a time to reduce the function call overhead. + */ + int (*encoder) (int, struct g72x_state* state) ; + int (*decoder) (int, struct g72x_state* state) ; + + int codec_bits, blocksize, samplesperblock ; +} ; + +typedef struct g72x_state G72x_STATE ; + +int predictor_zero (G72x_STATE *state_ptr) ; + +int predictor_pole (G72x_STATE *state_ptr) ; + +int step_size (G72x_STATE *state_ptr) ; + +int quantize (int d, int y, short *table, int size) ; + +int reconstruct (int sign, int dqln, int y) ; + +void update (int code_size, int y, int wi, int fi, int dq, int sr, int dqsez, G72x_STATE *state_ptr) ; + +int g721_encoder (int sample, G72x_STATE *state_ptr) ; +int g721_decoder (int code, G72x_STATE *state_ptr) ; + +int g723_16_encoder (int sample, G72x_STATE *state_ptr) ; +int g723_16_decoder (int code, G72x_STATE *state_ptr) ; + +int g723_24_encoder (int sample, G72x_STATE *state_ptr) ; +int g723_24_decoder (int code, G72x_STATE *state_ptr) ; + +int g723_40_encoder (int sample, G72x_STATE *state_ptr) ; +int g723_40_decoder (int code, G72x_STATE *state_ptr) ; + +void private_init_state (G72x_STATE *state_ptr) ; + +#if __GNUC__ +#define ALWAYS_INLINE __attribute__ ((always_inline)) +#elif defined _MSC_VER +#define ALWAYS_INLINE __forceinline +#else +#define ALWAYS_INLINE +#endif + +static inline int ALWAYS_INLINE +arith_shift_left (int x, int shift) +{ return (int) (((unsigned int) x) << shift) ; +} /* arith_shift_left */ + +static inline int ALWAYS_INLINE +arith_shift_right (int x, int shift) +{ if (x >= 0) + return x << shift ; + return ~ ((~x) << shift) ; +} /* arith_shift_right */ + +#endif /* G72X_PRIVATE_H */ diff --git a/extern/libsndfile-modified/src/G72x/g72x_test.c b/extern/libsndfile-modified/src/G72x/g72x_test.c new file mode 100644 index 000000000..e8a976773 --- /dev/null +++ b/extern/libsndfile-modified/src/G72x/g72x_test.c @@ -0,0 +1,220 @@ +/* +** Copyright (C) 1999-2017 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif +#include +#include +#include + +#include "g72x.h" +#include "g72x_priv.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846264338 +#endif + +#define BUFFER_SIZE (1 << 14) +#define SAMPLE_RATE 11025 + + +static void g721_test (void) ; +static void g723_test (double margin) ; + +static void gen_signal_double (double *data, double scale, int datalen) ; +static int error_function (double data, double orig, double margin) ; + +static int oct_save_short (short *a, short *b, int len) ; + +int +main (int argc, char *argv []) +{ int bDoAll = 0 ; + int nTests = 0 ; + + if (argc != 2) + { printf ("Usage : %s \n", argv [0]) ; + printf (" Where is one of the following:\n") ; + printf (" g721 - test G721 encoder and decoder\n") ; + printf (" g723 - test G721 encoder and decoder\n") ; + printf (" all - perform all tests\n") ; + exit (1) ; + } ; + + bDoAll = !strcmp (argv [1], "all") ; + + if (bDoAll || ! strcmp (argv [1], "g721")) + { g721_test () ; + nTests++ ; + } ; + + if (bDoAll || ! strcmp (argv [1], "g723")) + { g723_test (0.53) ; + nTests++ ; + } ; + + if (nTests == 0) + { printf ("Mono : ************************************\n") ; + printf ("Mono : * No '%s' test defined.\n", argv [1]) ; + printf ("Mono : ************************************\n") ; + return 1 ; + } ; + + return 0 ; +} /* main */ + +static void +g721_test (void) +{ + return ; +} /* g721_test */ + +static void +g723_test (double margin) +{ static double orig_buffer [BUFFER_SIZE] ; + static short orig [BUFFER_SIZE] ; + static short data [BUFFER_SIZE] ; + + G72x_STATE encoder_state, decoder_state ; + + long k ; + int code, position, max_err ; + + private_init_state (&encoder_state) ; + encoder_state.encoder = g723_24_encoder ; + encoder_state.codec_bits = 3 ; + + private_init_state (&decoder_state) ; + decoder_state.decoder = g723_24_decoder ; + decoder_state.codec_bits = 3 ; + + memset (data, 0, BUFFER_SIZE * sizeof (short)) ; + memset (orig, 0, BUFFER_SIZE * sizeof (short)) ; + + printf (" g723_test : ") ; + fflush (stdout) ; + + gen_signal_double (orig_buffer, 32000.0, BUFFER_SIZE) ; + for (k = 0 ; k < BUFFER_SIZE ; k++) + orig [k] = (short) orig_buffer [k] ; + + /* Write and read data here. */ + position = 0 ; + max_err = 0 ; + for (k = 0 ; k < BUFFER_SIZE ; k++) + { code = encoder_state.encoder (orig [k], &encoder_state) ; + data [k] = decoder_state.decoder (code, &decoder_state) ; + if (abs (orig [k] - data [k]) > max_err) + { position = k ; + max_err = abs (orig [k] - data [k]) ; + } ; + } ; + + printf ("\n\nMax error of %d at postion %d.\n", max_err, position) ; + + for (k = 0 ; k < BUFFER_SIZE ; k++) + { if (error_function (data [k], orig [k], margin)) + { printf ("Line %d: Incorrect sample A (#%ld : %d should be %d).\n", __LINE__, k, data [k], orig [k]) ; + oct_save_short (orig, data, BUFFER_SIZE) ; + exit (1) ; + } ; + } ; + + + printf ("ok\n") ; + + return ; +} /* g723_test */ + + +#define SIGNAL_MAXVAL 30000.0 +#define DECAY_COUNT 1000 + +static void +gen_signal_double (double *gendata, double scale, int gendatalen) +{ int k, ramplen ; + double amp = 0.0 ; + + ramplen = DECAY_COUNT ; + + for (k = 0 ; k < gendatalen ; k++) + { if (k <= ramplen) + amp = scale * k / ((double) ramplen) ; + else if (k > gendatalen - ramplen) + amp = scale * (gendatalen - k) / ((double) ramplen) ; + + gendata [k] = amp * (0.4 * sin (33.3 * 2.0 * M_PI * ((double) (k+1)) / ((double) SAMPLE_RATE)) + + 0.3 * cos (201.1 * 2.0 * M_PI * ((double) (k+1)) / ((double) SAMPLE_RATE))) ; + } ; + + return ; +} /* gen_signal_double */ + +static int +error_function (double data, double orig, double margin) +{ double error ; + + if (fabs (orig) <= 500.0) + error = fabs (fabs (data) - fabs (orig)) / 2000.0 ; + else if (fabs (orig) <= 1000.0) + error = fabs (data - orig) / 3000.0 ; + else + error = fabs (data - orig) / fabs (orig) ; + + if (error > margin) + { printf ("\n\n*******************\nError : %f\n", error) ; + return 1 ; + } ; + return 0 ; +} /* error_function */ + +static int +oct_save_short (short *a, short *b, int len) +{ FILE *file ; + int k ; + + if (! (file = fopen ("error.dat", "w"))) + return 1 ; + + fprintf (file, "# Not created by Octave\n") ; + + fprintf (file, "# name: a\n") ; + fprintf (file, "# type: matrix\n") ; + fprintf (file, "# rows: %d\n", len) ; + fprintf (file, "# columns: 1\n") ; + + for (k = 0 ; k < len ; k++) + fprintf (file, "% d\n", a [k]) ; + + fprintf (file, "# name: b\n") ; + fprintf (file, "# type: matrix\n") ; + fprintf (file, "# rows: %d\n", len) ; + fprintf (file, "# columns: 1\n") ; + + for (k = 0 ; k < len ; k++) + fprintf (file, "% d\n", b [k]) ; + + fclose (file) ; + return 0 ; +} /* oct_save_short */ + diff --git a/extern/libsndfile-modified/src/GSM610/COPYRIGHT b/extern/libsndfile-modified/src/GSM610/COPYRIGHT new file mode 100644 index 000000000..eba0e523b --- /dev/null +++ b/extern/libsndfile-modified/src/GSM610/COPYRIGHT @@ -0,0 +1,16 @@ +Copyright 1992, 1993, 1994 by Jutta Degener and Carsten Bormann, +Technische Universitaet Berlin + +Any use of this software is permitted provided that this notice is not +removed and that neither the authors nor the Technische Universitaet Berlin +are deemed to have made any representations as to the suitability of this +software for any purpose nor are held responsible for any defects of +this software. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + +As a matter of courtesy, the authors request to be informed about uses +this software has found, about bugs in this software, and about any +improvements that may be of general interest. + +Berlin, 28.11.1994 +Jutta Degener +Carsten Bormann diff --git a/extern/libsndfile-modified/src/GSM610/ChangeLog b/extern/libsndfile-modified/src/GSM610/ChangeLog new file mode 100644 index 000000000..24f524882 --- /dev/null +++ b/extern/libsndfile-modified/src/GSM610/ChangeLog @@ -0,0 +1,56 @@ +2004-05-12 Erik de Castro Lopo + + * gsm610_priv.h + Replace ugly macros with inline functions. + + * *.c + Remove temporary variables used by macros and other minor fixes required by + above change. + +2003-06-02 Erik de Castro Lopo + + * rpe.c + Renamed variables "exp" to "expon" to avoid shadowed parameter warnigns. + +2002-06-08 Erik de Castro Lopo + + * long_term.c + Changes tp removed compiler warnings about shadowed parameters. + +2002-06-08 Erik de Castro Lopo + + * private.h + Made declarations of gsm_A, gsm_B, gsm_MIC etc extern. This fixed a compile + problem on MacOSX. + +2002-05-10 Erik de Castro Lopo + + * *.[ch] + Removed all pre-ANSI prototype kludges. Removed proto.h and unproto.h. + Started work on making GSM 6.10 files seekable. Currently they are not. + + * code.c private.h + Function Gsm_Coder () used a statically defined array. This was obviously + not re-entrant so moved it to struct gsm_state. + +2001-09-16 Erik de Castro Lopo + + * code.c + Added #includes for string.h and stdlib.h. + +2000-10-27 Erik de Castro Lopo + + * config.h + Removed some commented out #defines (ie //*efine) which were causing problems on + the Sun cc compiler. + +2000-02-29 Erik de Castro Lopo + + * private.h + Added #defines to emulate normal compile time options. + +2000-02-28 Erik de Castro Lopo + + * everthing + Created this directory and copied files from libgsm. + http://kbs.cs.tu-berlin.de/~jutta/toast.html diff --git a/extern/libsndfile-modified/src/GSM610/README b/extern/libsndfile-modified/src/GSM610/README new file mode 100644 index 000000000..b57132b05 --- /dev/null +++ b/extern/libsndfile-modified/src/GSM610/README @@ -0,0 +1,36 @@ +GSM 06.10 13 kbit/s RPE/LTP speech codec +---------------------------------------- + +All the file in this directory were written by Jutta Degener +and Carsten Borman for The Communications and Operating Systems +Research Group (KBS) at the Technische Universitaet Berlin. + +Their work was released under the following license which is +assumed to be compatible with The GNU Lesser General Public License. + +---------------------------------------------------------------------------- + +Copyright 1992, 1993, 1994 by Jutta Degener and Carsten Bormann, +Technische Universitaet Berlin + +Any use of this software is permitted provided that this notice is not +removed and that neither the authors nor the Technische Universitaet Berlin +are deemed to have made any representations as to the suitability of this +software for any purpose nor are held responsible for any defects of +this software. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + +As a matter of courtesy, the authors request to be informed about uses +this software has found, about bugs in this software, and about any +improvements that may be of general interest. + +Berlin, 28.11.1994 +Jutta Degener (jutta@cs.tu-berlin.de) +Carsten Bormann (cabo@cs.tu-berlin.de) + +---------------------------------------------------------------------------- + +Jutta Degener and Carsten Bormann's work can be found on their homepage +at: + + http://kbs.cs.tu-berlin.de/~jutta/toast.html + diff --git a/extern/libsndfile-modified/src/GSM610/add.c b/extern/libsndfile-modified/src/GSM610/add.c new file mode 100644 index 000000000..c943eec7b --- /dev/null +++ b/extern/libsndfile-modified/src/GSM610/add.c @@ -0,0 +1,243 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +/* + * See private.h for the more commonly used macro versions. + */ + +#include +#include + +#include "gsm610_priv.h" + +#define saturate(x) \ + ((x) < MIN_WORD ? MIN_WORD : (x) > MAX_WORD ? MAX_WORD: (x)) + +int16_t gsm_add (int16_t a, int16_t b) +{ + int32_t sum = (int32_t) a + (int32_t) b ; + return saturate (sum) ; +} + +int16_t gsm_sub (int16_t a, int16_t b) +{ + int32_t diff = (int32_t) a - (int32_t) b ; + return saturate (diff) ; +} + +int16_t gsm_mult (int16_t a, int16_t b) +{ + if (a == MIN_WORD && b == MIN_WORD) + return MAX_WORD ; + + return SASR_L ((int32_t) a * (int32_t) b, 15) ; +} + +int16_t gsm_mult_r (int16_t a, int16_t b) +{ + if (b == MIN_WORD && a == MIN_WORD) + return MAX_WORD ; + else + { int32_t prod = (int32_t) a * (int32_t) b + 16384 ; + prod >>= 15 ; + return prod & 0xFFFF ; + } +} + +int16_t gsm_abs (int16_t a) +{ + return a < 0 ? (a == MIN_WORD ? MAX_WORD : -a) : a ; +} + +int32_t gsm_L_mult (int16_t a, int16_t b) +{ + assert (a != MIN_WORD || b != MIN_WORD) ; + return ((int32_t) a * (int32_t) b) << 1 ; +} + +int32_t gsm_L_add (int32_t a, int32_t b) +{ + if (a < 0) + { if (b >= 0) + return a + b ; + else + { uint32_t A = (uint32_t) - (a + 1) + (uint32_t) - (b + 1) ; + return A >= MAX_LONGWORD ? MIN_LONGWORD : - (int32_t) A - 2 ; + } + } + else if (b <= 0) + return a + b ; + else + { uint32_t A = (uint32_t) a + (uint32_t) b ; + return A > MAX_LONGWORD ? MAX_LONGWORD : A ; + } +} + +int32_t gsm_L_sub (int32_t a, int32_t b) +{ + if (a >= 0) + { if (b >= 0) + return a - b ; + else + { /* a>=0, b<0 */ + uint32_t A = (uint32_t) a + - (b + 1) ; + return A >= MAX_LONGWORD ? MAX_LONGWORD : (A + 1) ; + } + } + else if (b <= 0) + return a - b ; + else + { /* a<0, b>0 */ + uint32_t A = (uint32_t) - (a + 1) + b ; + return A >= MAX_LONGWORD ? MIN_LONGWORD : - (int32_t) A - 1 ; + } +} + +static unsigned char const bitoff [256] = { + 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 +} ; + +int16_t gsm_norm (int32_t a) +/* + * the number of left shifts needed to normalize the 32 bit + * variable L_var1 for positive values on the interval + * + * with minimum of + * minimum of 1073741824 (01000000000000000000000000000000) and + * maximum of 2147483647 (01111111111111111111111111111111) + * + * + * and for negative values on the interval with + * minimum of -2147483648 (-10000000000000000000000000000000) and + * maximum of -1073741824 (-1000000000000000000000000000000). + * + * in order to normalize the result, the following + * operation must be done: L_norm_var1 = L_var1 << norm (L_var1) ; + * + * (That's 'ffs', only from the left, not the right..) + */ +{ + assert (a != 0) ; + + if (a < 0) + { if (a <= -1073741824) return 0 ; + a = ~a ; + } + + return a & 0xffff0000 + ? (a & 0xff000000 + ? -1 + bitoff [0xFF & (a >> 24)] + : 7 + bitoff [0xFF & (a >> 16)]) + : (a & 0xff00 + ? 15 + bitoff [0xFF & (a >> 8)] + : 23 + bitoff [0xFF & a]) ; +} + +int32_t gsm_L_asl (int32_t a, int n) +{ + if (n >= 32) return 0 ; + if (n <= -32) return - (a < 0) ; + if (n < 0) return gsm_L_asr (a, -n) ; + return a << n ; +} + +int16_t gsm_asr (int16_t a, int n) +{ + if (n >= 16) return - (a < 0) ; + if (n <= -16) return 0 ; + if (n < 0) return a << -n ; + + return SASR_W (a, (int16_t) n) ; +} + +int16_t gsm_asl (int16_t a, int n) +{ + if (n >= 16) return 0 ; + if (n <= -16) return - (a < 0) ; + if (n < 0) return gsm_asr (a, -n) ; + return a << n ; +} + +int32_t gsm_L_asr (int32_t a, int n) +{ + if (n >= 32) return - (a < 0) ; + if (n <= -32) return 0 ; + if (n < 0) return a << -n ; + + return SASR_L (a, (int16_t) n) ; +} + +/* +** int16_t gsm_asr (int16_t a, int n) +** { +** if (n >= 16) return - (a < 0) ; +** if (n <= -16) return 0 ; +** if (n < 0) return a << -n ; +** +** # ifdef SASR_W +** return a >> n ; +** # else +** if (a >= 0) return a >> n ; +** else return - (int16_t) (- (uint16_t)a >> n) ; +** # endif +** } +** +*/ +/* + * (From p. 46, end of section 4.2.5) + * + * NOTE: The following lines gives [sic] one correct implementation + * of the div (num, denum) arithmetic operation. Compute div + * which is the integer division of num by denum: with denum + * >= num > 0 + */ + +int16_t gsm_div (int16_t num, int16_t denum) +{ + int32_t L_num = num ; + int32_t L_denum = denum ; + int16_t div = 0 ; + int k = 15 ; + + /* The parameter num sometimes becomes zero. + * Although this is explicitly guarded against in 4.2.5, + * we assume that the result should then be zero as well. + */ + + /* assert (num != 0) ; */ + + assert (num >= 0 && denum >= num) ; + if (num == 0) + return 0 ; + + while (k--) + { div <<= 1 ; + L_num <<= 1 ; + + if (L_num >= L_denum) + { L_num -= L_denum ; + div++ ; + } + } + + return div ; +} + diff --git a/extern/libsndfile-modified/src/GSM610/code.c b/extern/libsndfile-modified/src/GSM610/code.c new file mode 100644 index 000000000..991913bda --- /dev/null +++ b/extern/libsndfile-modified/src/GSM610/code.c @@ -0,0 +1,87 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + + +#include +#include + +#include "gsm610_priv.h" + +/* + * 4.2 FIXED POINT IMPLEMENTATION OF THE RPE-LTP CODER + */ + +void Gsm_Coder ( + + struct gsm_state * State, + + int16_t * s, /* [0..159] samples IN */ + +/* + * The RPE-LTD coder works on a frame by frame basis. The length of + * the frame is equal to 160 samples. Some computations are done + * once per frame to produce at the output of the coder the + * LARc [1..8] parameters which are the coded LAR coefficients and + * also to realize the inverse filtering operation for the entire + * frame (160 samples of signal d [0..159]). These parts produce at + * the output of the coder: + */ + + int16_t * LARc, /* [0..7] LAR coefficients OUT */ + +/* + * Procedure 4.2.11 to 4.2.18 are to be executed four times per + * frame. That means once for each sub-segment RPE-LTP analysis of + * 40 samples. These parts produce at the output of the coder: + */ + + int16_t *Nc, /* [0..3] LTP lag OUT */ + int16_t *bc, /* [0..3] coded LTP gain OUT */ + int16_t *Mc, /* [0..3] RPE grid selection OUT */ + int16_t *xmaxc, /* [0..3] Coded maximum amplitude OUT */ + int16_t *xMc /* [13*4] normalized RPE samples OUT */ +) +{ + int k ; + int16_t *dp = State->dp0 + 120 ; /* [-120...-1] */ + int16_t *dpp = dp ; /* [0...39] */ + + int16_t so [160] ; + + Gsm_Preprocess (State, s, so) ; + Gsm_LPC_Analysis (State, so, LARc) ; + Gsm_Short_Term_Analysis_Filter (State, LARc, so) ; + + for (k = 0 ; k <= 3 ; k++, xMc += 13) + { Gsm_Long_Term_Predictor (State, + so+k*40, /* d [0..39] IN */ + dp, /* dp [-120..-1] IN */ + State->e + 5, /* e [0..39] OUT */ + dpp, /* dpp [0..39] OUT */ + Nc++, + bc++) ; + + Gsm_RPE_Encoding (/*-S,-*/ + State->e + 5, /* e ][0..39][IN/OUT */ + xmaxc++, Mc++, xMc) ; + /* + * Gsm_Update_of_reconstructed_short_time_residual_signal + * (dpp, State->e + 5, dp) ; + */ + + { + register int i ; + for (i = 0 ; i <= 39 ; i++) + dp [i] = GSM_ADD (State->e [5 + i], dpp [i]) ; + } + dp += 40 ; + dpp += 40 ; + + } + memcpy ((char *) State->dp0, (char *) (State->dp0 + 160), + 120 * sizeof (*State->dp0)) ; +} + diff --git a/extern/libsndfile-modified/src/GSM610/config.h b/extern/libsndfile-modified/src/GSM610/config.h new file mode 100644 index 000000000..f3eeb82e8 --- /dev/null +++ b/extern/libsndfile-modified/src/GSM610/config.h @@ -0,0 +1,26 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +#ifndef CONFIG_H +#define CONFIG_H + +#define HAS_STDLIB_H 1 /* /usr/include/stdlib.h */ +#define HAS_FCNTL_H 1 /* /usr/include/fcntl.h */ + +#define HAS_FSTAT 1 /* fstat syscall */ +#define HAS_FCHMOD 1 /* fchmod syscall */ +#define HAS_CHMOD 1 /* chmod syscall */ +#define HAS_FCHOWN 1 /* fchown syscall */ +#define HAS_CHOWN 1 /* chown syscall */ + +#define HAS_STRING_H 1 /* /usr/include/string.h */ + +#define HAS_UNISTD_H 1 /* /usr/include/unistd.h */ +#define HAS_UTIME 1 /* POSIX utime(path, times) */ +#define HAS_UTIME_H 1 /* UTIME header file */ + +#endif /* CONFIG_H */ + diff --git a/extern/libsndfile-modified/src/GSM610/decode.c b/extern/libsndfile-modified/src/GSM610/decode.c new file mode 100644 index 000000000..2a0712f09 --- /dev/null +++ b/extern/libsndfile-modified/src/GSM610/decode.c @@ -0,0 +1,58 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +#include + +#include "gsm610_priv.h" + +/* + * 4.3 FIXED POINT IMPLEMENTATION OF THE RPE-LTP DECODER + */ + +static void Postprocessing ( + struct gsm_state * S, + register int16_t * s) +{ + register int k ; + register int16_t msr = S->msr ; + register int16_t tmp ; + + for (k = 160 ; k-- ; s++) + { tmp = GSM_MULT_R (msr, 28180) ; + msr = GSM_ADD (*s, tmp) ; /* Deemphasis */ + *s = GSM_ADD (msr, msr) & 0xFFF8 ; /* Truncation & Upscaling */ + } + S->msr = msr ; +} + +void Gsm_Decoder ( + struct gsm_state * S, + + int16_t * LARcr, /* [0..7] IN */ + + int16_t * Ncr, /* [0..3] IN */ + int16_t * bcr, /* [0..3] IN */ + int16_t * Mcr, /* [0..3] IN */ + int16_t * xmaxcr, /* [0..3] IN */ + int16_t * xMcr, /* [0..13*4] IN */ + + int16_t * s) /* [0..159] OUT */ +{ + int j, k ; + int16_t erp [40], wt [160] ; + int16_t *drp = S->dp0 + 120 ; + + for (j = 0 ; j <= 3 ; j++, xmaxcr++, bcr++, Ncr++, Mcr++, xMcr += 13) + { Gsm_RPE_Decoding (/*-S,-*/ *xmaxcr, *Mcr, xMcr, erp) ; + Gsm_Long_Term_Synthesis_Filtering (S, *Ncr, *bcr, erp, drp) ; + + for (k = 0 ; k <= 39 ; k++) wt [j * 40 + k] = drp [k] ; + } + + Gsm_Short_Term_Synthesis_Filter (S, LARcr, wt, s) ; + Postprocessing (S, s) ; +} + diff --git a/extern/libsndfile-modified/src/GSM610/gsm.h b/extern/libsndfile-modified/src/GSM610/gsm.h new file mode 100644 index 000000000..6506a6581 --- /dev/null +++ b/extern/libsndfile-modified/src/GSM610/gsm.h @@ -0,0 +1,52 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +#ifndef GSM_H +#define GSM_H + +#include /* for FILE * */ + +/* + * Interface + */ + +typedef struct gsm_state * gsm ; +typedef short gsm_signal ; /* signed 16 bit */ +typedef unsigned char gsm_byte ; +typedef gsm_byte gsm_frame [33] ; /* 33 * 8 bits */ + +#define GSM_MAGIC 0xD /* 13 kbit/s RPE-LTP */ + +#define GSM_PATCHLEVEL 10 +#define GSM_MINOR 0 +#define GSM_MAJOR 1 + +#define GSM_OPT_VERBOSE 1 +#define GSM_OPT_FAST 2 +#define GSM_OPT_LTP_CUT 3 +#define GSM_OPT_WAV49 4 +#define GSM_OPT_FRAME_INDEX 5 +#define GSM_OPT_FRAME_CHAIN 6 + +gsm gsm_create (void) ; + +/* Added for libsndfile : May 6, 2002 */ +void gsm_init (gsm) ; + +void gsm_destroy (gsm) ; + +int gsm_print (FILE *, gsm, gsm_byte *) ; +int gsm_option (gsm, int, int *) ; + +void gsm_encode (gsm, gsm_signal *, gsm_byte *) ; +int gsm_decode (gsm, gsm_byte *, gsm_signal *) ; + +int gsm_explode (gsm, gsm_byte *, gsm_signal *) ; +void gsm_implode (gsm, gsm_signal *, gsm_byte *) ; + +#endif /* GSM_H */ + + diff --git a/extern/libsndfile-modified/src/GSM610/gsm610_priv.h b/extern/libsndfile-modified/src/GSM610/gsm610_priv.h new file mode 100644 index 000000000..7ffaddc1d --- /dev/null +++ b/extern/libsndfile-modified/src/GSM610/gsm610_priv.h @@ -0,0 +1,337 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +#ifndef PRIVATE_H +#define PRIVATE_H + +#include + +/* Added by Erik de Castro Lopo */ +#define USE_FLOAT_MUL +#define FAST +#define WAV49 + +#ifdef __cplusplus +#error "This code is not designed to be compiled with a C++ compiler." +#endif +/* Added by Erik de Castro Lopo */ + +struct gsm_state +{ int16_t dp0 [280] ; + + int16_t z1 ; /* preprocessing.c, Offset_com. */ + int32_t L_z2 ; /* Offset_com. */ + int mp ; /* Preemphasis */ + + int16_t u [8] ; /* short_term_aly_filter.c */ + int16_t LARpp [2][8] ; /* */ + int16_t j ; /* */ + + int16_t ltp_cut ; /* long_term.c, LTP crosscorr. */ + int16_t nrp ; /* 40 */ /* long_term.c, synthesis */ + int16_t v [9] ; /* short_term.c, synthesis */ + int16_t msr ; /* decoder.c, Postprocessing */ + + char verbose ; /* only used if !NDEBUG */ + char fast ; /* only used if FAST */ + + char wav_fmt ; /* only used if WAV49 defined */ + unsigned char frame_index ; /* odd/even chaining */ + unsigned char frame_chain ; /* half-byte to carry forward */ + + /* Moved here from code.c where it was defined as static */ + int16_t e [50] ; +} ; + +typedef struct gsm_state GSM_STATE ; + +#define MIN_WORD (-32767 - 1) +#define MAX_WORD 32767 + +#define MIN_LONGWORD (-2147483647 - 1) +#define MAX_LONGWORD 2147483647 + +/* Signed arithmetic shift right. */ +static inline int16_t +SASR_W (int16_t x, int16_t by) +{ if (x >= 0) + return x >> by ; + return ~ ((~x) >> by) ; +} /* SASR_W */ + +static inline int32_t +SASR_L (int32_t x, int16_t by) +{ if (x >= 0) + return x >> by ; + return ~ ((~x) >> by) ; +} /* SASR_L */ + +/* Signed arithmetic shift left. */ +static inline int16_t +SASL_W (int16_t x, int16_t by) +{ if (x >= 0) + return x << by ; + return - ((-x) << by) ; +} /* SASR_W */ + +static inline int32_t +SASL_L (int32_t x, int16_t by) +{ if (x >= 0) + return x << by ; + return - ((-x) << by) ; +} /* SASR_L */ + +/* + * Prototypes from add.c + */ +int16_t gsm_mult (int16_t a, int16_t b) ; +int32_t gsm_L_mult (int16_t a, int16_t b) ; +int16_t gsm_mult_r (int16_t a, int16_t b) ; + +int16_t gsm_div (int16_t num, int16_t denum) ; + +int16_t gsm_add (int16_t a, int16_t b) ; +int32_t gsm_L_add (int32_t a, int32_t b) ; + +int16_t gsm_sub (int16_t a, int16_t b) ; +int32_t gsm_L_sub (int32_t a, int32_t b) ; + +int16_t gsm_abs (int16_t a) ; + +int16_t gsm_norm (int32_t a) ; + +int32_t gsm_L_asl (int32_t a, int n) ; +int16_t gsm_asl (int16_t a, int n) ; + +int32_t gsm_L_asr (int32_t a, int n) ; +int16_t gsm_asr (int16_t a, int n) ; + +/* + * Inlined functions from add.h + */ + +static inline int32_t +GSM_MULT_R (int16_t a, int16_t b) +{ return (((int32_t) (a)) * ((int32_t) (b)) + 16384) >> 15 ; +} /* GSM_MULT_R */ + +static inline int32_t +GSM_MULT (int16_t a, int16_t b) +{ return (((int32_t) (a)) * ((int32_t) (b))) >> 15 ; +} /* GSM_MULT */ + +static inline int32_t +GSM_L_MULT (int16_t a, int16_t b) +{ return ((int32_t) (a)) * ((int32_t) (b)) << 1 ; +} /* GSM_L_MULT */ + +static inline int32_t +GSM_L_ADD (int32_t a, int32_t b) +{ uint32_t utmp ; + + if (a < 0 && b < 0) + { utmp = (uint32_t) - ((a) + 1) + (uint32_t) - ((b) + 1) ; + return (utmp >= (uint32_t) MAX_LONGWORD) ? MIN_LONGWORD : - (int32_t) utmp - 2 ; + } ; + + if (a > 0 && b > 0) + { utmp = (uint32_t) a + (uint32_t) b ; + return (utmp >= (uint32_t) MAX_LONGWORD) ? MAX_LONGWORD : utmp ; + } ; + + return a + b ; +} /* GSM_L_ADD */ + +static inline int32_t +GSM_ADD (int16_t a, int16_t b) +{ int32_t ltmp ; + + ltmp = ((int32_t) a) + ((int32_t) b) ; + + if (ltmp >= MAX_WORD) + return MAX_WORD ; + if (ltmp <= MIN_WORD) + return MIN_WORD ; + + return ltmp ; +} /* GSM_ADD */ + +static inline int32_t +GSM_SUB (int16_t a, int16_t b) +{ int32_t ltmp ; + + ltmp = ((int32_t) a) - ((int32_t) b) ; + + if (ltmp >= MAX_WORD) + ltmp = MAX_WORD ; + else if (ltmp <= MIN_WORD) + ltmp = MIN_WORD ; + + return ltmp ; +} /* GSM_SUB */ + +static inline int16_t +GSM_ABS (int16_t a) +{ + if (a > 0) + return a ; + if (a == MIN_WORD) + return MAX_WORD ; + return -a ; +} /* GSM_ADD */ + + +/* + * More prototypes from implementations.. + */ +void Gsm_Coder ( + struct gsm_state * S, + int16_t * s, /* [0..159] samples IN */ + int16_t * LARc, /* [0..7] LAR coefficients OUT */ + int16_t * Nc, /* [0..3] LTP lag OUT */ + int16_t * bc, /* [0..3] coded LTP gain OUT */ + int16_t * Mc, /* [0..3] RPE grid selection OUT */ + int16_t * xmaxc, /* [0..3] Coded maximum amplitude OUT */ + int16_t * xMc) ; /* [13*4] normalized RPE samples OUT */ + +void Gsm_Long_Term_Predictor ( /* 4x for 160 samples */ + struct gsm_state * S, + int16_t * d, /* [0..39] residual signal IN */ + int16_t * dp, /* [-120..-1] d' IN */ + int16_t * e, /* [0..40] OUT */ + int16_t * dpp, /* [0..40] OUT */ + int16_t * Nc, /* correlation lag OUT */ + int16_t * bc) ; /* gain factor OUT */ + +void Gsm_LPC_Analysis ( + struct gsm_state * S, + int16_t * s, /* 0..159 signals IN/OUT */ + int16_t * LARc) ; /* 0..7 LARc's OUT */ + +void Gsm_Preprocess ( + struct gsm_state * S, + int16_t * s, int16_t * so) ; + +void Gsm_Encoding ( + struct gsm_state * S, + int16_t * e, + int16_t * ep, + int16_t * xmaxc, + int16_t * Mc, + int16_t * xMc) ; + +void Gsm_Short_Term_Analysis_Filter ( + struct gsm_state * S, + int16_t * LARc, /* coded log area ratio [0..7] IN */ + int16_t * d) ; /* st res. signal [0..159] IN/OUT */ + +void Gsm_Decoder ( + struct gsm_state * S, + int16_t * LARcr, /* [0..7] IN */ + int16_t * Ncr, /* [0..3] IN */ + int16_t * bcr, /* [0..3] IN */ + int16_t * Mcr, /* [0..3] IN */ + int16_t * xmaxcr, /* [0..3] IN */ + int16_t * xMcr, /* [0..13*4] IN */ + int16_t * s) ; /* [0..159] OUT */ + +void Gsm_Decoding ( + struct gsm_state * S, + int16_t xmaxcr, + int16_t Mcr, + int16_t * xMcr, /* [0..12] IN */ + int16_t * erp) ; /* [0..39] OUT */ + +void Gsm_Long_Term_Synthesis_Filtering ( + struct gsm_state* S, + int16_t Ncr, + int16_t bcr, + int16_t * erp, /* [0..39] IN */ + int16_t * drp) ; /* [-120..-1] IN, [0..40] OUT */ + +void Gsm_RPE_Decoding ( + /*-struct gsm_state *S,-*/ + int16_t xmaxcr, + int16_t Mcr, + int16_t * xMcr, /* [0..12], 3 bits IN */ + int16_t * erp) ; /* [0..39] OUT */ + +void Gsm_RPE_Encoding ( + /*-struct gsm_state * S,-*/ + int16_t * e, /* -5..-1][0..39][40..44 IN/OUT */ + int16_t * xmaxc, /* OUT */ + int16_t * Mc, /* OUT */ + int16_t * xMc) ; /* [0..12] OUT */ + +void Gsm_Short_Term_Synthesis_Filter ( + struct gsm_state * S, + int16_t * LARcr, /* log area ratios [0..7] IN */ + int16_t * drp, /* received d [0...39] IN */ + int16_t * s) ; /* signal s [0..159] OUT */ + +void Gsm_Update_of_reconstructed_short_time_residual_signal ( + int16_t * dpp, /* [0...39] IN */ + int16_t * ep, /* [0...39] IN */ + int16_t * dp) ; /* [-120...-1] IN/OUT */ + +/* + * Tables from table.c + */ +#ifndef GSM_TABLE_C + +extern int16_t gsm_A [8], gsm_B [8], gsm_MIC [8], gsm_MAC [8] ; +extern int16_t gsm_INVA [8] ; +extern int16_t gsm_DLB [4], gsm_QLB [4] ; +extern int16_t gsm_H [11] ; +extern int16_t gsm_NRFAC [8] ; +extern int16_t gsm_FAC [8] ; + +#endif /* GSM_TABLE_C */ + + +#if __GNUC__ +#define ALWAYS_INLINE __attribute__ ((always_inline)) +#elif defined _MSC_VER +#define ALWAYS_INLINE __forceinline +#else +#define ALWAYS_INLINE +#endif + + +static inline int32_t ALWAYS_INLINE +arith_shift_left (int32_t x, int shift) +{ return (int32_t) (((uint32_t) x) << shift) ; +} /* arith_shift_left */ + +static inline int32_t ALWAYS_INLINE +arith_shift_right (int32_t x, int shift) +{ if (x >= 0) + return x << shift ; + return ~ ((~x) << shift) ; +} /* arith_shift_right */ + + +/* + * Debugging + */ +#ifdef NDEBUG + +# define gsm_debug_int16_ts(a, b, c, d) /* nil */ +# define gsm_debug_int32_ts(a, b, c, d) /* nil */ +# define gsm_debug_int16_t(a, b) /* nil */ +# define gsm_debug_int32_t(a, b) /* nil */ + +#else /* !NDEBUG => DEBUG */ + + void gsm_debug_int16_ts (char * name, int, int, int16_t *) ; + void gsm_debug_int32_ts (char * name, int, int, int32_t *) ; + void gsm_debug_int32_t (char * name, int32_t) ; + void gsm_debug_int16_t (char * name, int16_t) ; + +#endif /* !NDEBUG */ + +#endif /* PRIVATE_H */ + diff --git a/extern/libsndfile-modified/src/GSM610/gsm_create.c b/extern/libsndfile-modified/src/GSM610/gsm_create.c new file mode 100644 index 000000000..05425dd7a --- /dev/null +++ b/extern/libsndfile-modified/src/GSM610/gsm_create.c @@ -0,0 +1,37 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +#include "config.h" + +#include +#include +#include + + + +#include "gsm.h" +#include "gsm610_priv.h" + +gsm gsm_create (void) +{ + gsm r ; + + r = malloc (sizeof (struct gsm_state)) ; + if (!r) return r ; + + memset ((char *) r, 0, sizeof (struct gsm_state)) ; + r->nrp = 40 ; + + return r ; +} + +/* Added for libsndfile : May 6, 2002. Not sure if it works. */ +void gsm_init (gsm state) +{ + memset (state, 0, sizeof (struct gsm_state)) ; + state->nrp = 40 ; +} + diff --git a/extern/libsndfile-modified/src/GSM610/gsm_decode.c b/extern/libsndfile-modified/src/GSM610/gsm_decode.c new file mode 100644 index 000000000..04411be3f --- /dev/null +++ b/extern/libsndfile-modified/src/GSM610/gsm_decode.c @@ -0,0 +1,357 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +#include "gsm610_priv.h" + +#include "gsm.h" + +int gsm_decode (gsm s, gsm_byte * c, gsm_signal * target) +{ + int16_t LARc [8], Nc [4], Mc [4], bc [4], xmaxc [4], xmc [13 * 4] ; + +#ifdef WAV49 + if (s->wav_fmt) + { uint16_t sr = 0 ; + + s->frame_index = !s->frame_index ; + if (s->frame_index) + { sr = *c++ ; + LARc [0] = sr & 0x3f ; sr >>= 6 ; + sr |= (uint16_t) *c++ << 2 ; + LARc [1] = sr & 0x3f ; sr >>= 6 ; + sr |= (uint16_t) *c++ << 4 ; + LARc [2] = sr & 0x1f ; sr >>= 5 ; + LARc [3] = sr & 0x1f ; sr >>= 5 ; + sr |= (uint16_t) *c++ << 2 ; + LARc [4] = sr & 0xf ; sr >>= 4 ; + LARc [5] = sr & 0xf ; sr >>= 4 ; + sr |= (uint16_t) *c++ << 2 ; /* 5 */ + LARc [6] = sr & 0x7 ; sr >>= 3 ; + LARc [7] = sr & 0x7 ; sr >>= 3 ; + sr |= (uint16_t) *c++ << 4 ; + Nc [0] = sr & 0x7f ; sr >>= 7 ; + bc [0] = sr & 0x3 ; sr >>= 2 ; + Mc [0] = sr & 0x3 ; sr >>= 2 ; + sr |= (uint16_t) *c++ << 1 ; + xmaxc [0] = sr & 0x3f ; sr >>= 6 ; + xmc [0] = sr & 0x7 ; sr >>= 3 ; + sr = *c++ ; + xmc [1] = sr & 0x7 ; sr >>= 3 ; + xmc [2] = sr & 0x7 ; sr >>= 3 ; + sr |= (uint16_t) *c++ << 2 ; + xmc [3] = sr & 0x7 ; sr >>= 3 ; + xmc [4] = sr & 0x7 ; sr >>= 3 ; + xmc [5] = sr & 0x7 ; sr >>= 3 ; + sr |= (uint16_t) *c++ << 1 ; /* 10 */ + xmc [6] = sr & 0x7 ; sr >>= 3 ; + xmc [7] = sr & 0x7 ; sr >>= 3 ; + xmc [8] = sr & 0x7 ; sr >>= 3 ; + sr = *c++ ; + xmc [9] = sr & 0x7 ; sr >>= 3 ; + xmc [10] = sr & 0x7 ; sr >>= 3 ; + sr |= (uint16_t) *c++ << 2 ; + xmc [11] = sr & 0x7 ; sr >>= 3 ; + xmc [12] = sr & 0x7 ; sr >>= 3 ; + sr |= (uint16_t) *c++ << 4 ; + Nc [1] = sr & 0x7f ; sr >>= 7 ; + bc [1] = sr & 0x3 ; sr >>= 2 ; + Mc [1] = sr & 0x3 ; sr >>= 2 ; + sr |= (uint16_t) *c++ << 1 ; + xmaxc [1] = sr & 0x3f ; sr >>= 6 ; + xmc [13] = sr & 0x7 ; sr >>= 3 ; + sr = *c++ ; /* 15 */ + xmc [14] = sr & 0x7 ; sr >>= 3 ; + xmc [15] = sr & 0x7 ; sr >>= 3 ; + sr |= (uint16_t) *c++ << 2 ; + xmc [16] = sr & 0x7 ; sr >>= 3 ; + xmc [17] = sr & 0x7 ; sr >>= 3 ; + xmc [18] = sr & 0x7 ; sr >>= 3 ; + sr |= (uint16_t) *c++ << 1 ; + xmc [19] = sr & 0x7 ; sr >>= 3 ; + xmc [20] = sr & 0x7 ; sr >>= 3 ; + xmc [21] = sr & 0x7 ; sr >>= 3 ; + sr = *c++ ; + xmc [22] = sr & 0x7 ; sr >>= 3 ; + xmc [23] = sr & 0x7 ; sr >>= 3 ; + sr |= (uint16_t) *c++ << 2 ; + xmc [24] = sr & 0x7 ; sr >>= 3 ; + xmc [25] = sr & 0x7 ; sr >>= 3 ; + sr |= (uint16_t) *c++ << 4 ; /* 20 */ + Nc [2] = sr & 0x7f ; sr >>= 7 ; + bc [2] = sr & 0x3 ; sr >>= 2 ; + Mc [2] = sr & 0x3 ; sr >>= 2 ; + sr |= (uint16_t) *c++ << 1 ; + xmaxc [2] = sr & 0x3f ; sr >>= 6 ; + xmc [26] = sr & 0x7 ; sr >>= 3 ; + sr = *c++ ; + xmc [27] = sr & 0x7 ; sr >>= 3 ; + xmc [28] = sr & 0x7 ; sr >>= 3 ; + sr |= (uint16_t) *c++ << 2 ; + xmc [29] = sr & 0x7 ; sr >>= 3 ; + xmc [30] = sr & 0x7 ; sr >>= 3 ; + xmc [31] = sr & 0x7 ; sr >>= 3 ; + sr |= (uint16_t) *c++ << 1 ; + xmc [32] = sr & 0x7 ; sr >>= 3 ; + xmc [33] = sr & 0x7 ; sr >>= 3 ; + xmc [34] = sr & 0x7 ; sr >>= 3 ; + sr = *c++ ; /* 25 */ + xmc [35] = sr & 0x7 ; sr >>= 3 ; + xmc [36] = sr & 0x7 ; sr >>= 3 ; + sr |= (uint16_t) *c++ << 2 ; + xmc [37] = sr & 0x7 ; sr >>= 3 ; + xmc [38] = sr & 0x7 ; sr >>= 3 ; + sr |= (uint16_t) *c++ << 4 ; + Nc [3] = sr & 0x7f ; sr >>= 7 ; + bc [3] = sr & 0x3 ; sr >>= 2 ; + Mc [3] = sr & 0x3 ; sr >>= 2 ; + sr |= (uint16_t) *c++ << 1 ; + xmaxc [3] = sr & 0x3f ; sr >>= 6 ; + xmc [39] = sr & 0x7 ; sr >>= 3 ; + sr = *c++ ; + xmc [40] = sr & 0x7 ; sr >>= 3 ; + xmc [41] = sr & 0x7 ; sr >>= 3 ; + sr |= (uint16_t) *c++ << 2 ; /* 30 */ + xmc [42] = sr & 0x7 ; sr >>= 3 ; + xmc [43] = sr & 0x7 ; sr >>= 3 ; + xmc [44] = sr & 0x7 ; sr >>= 3 ; + sr |= (uint16_t) *c++ << 1 ; + xmc [45] = sr & 0x7 ; sr >>= 3 ; + xmc [46] = sr & 0x7 ; sr >>= 3 ; + xmc [47] = sr & 0x7 ; sr >>= 3 ; + sr = *c++ ; + xmc [48] = sr & 0x7 ; sr >>= 3 ; + xmc [49] = sr & 0x7 ; sr >>= 3 ; + sr |= (uint16_t) *c++ << 2 ; + xmc [50] = sr & 0x7 ; sr >>= 3 ; + xmc [51] = sr & 0x7 ; sr >>= 3 ; + + s->frame_chain = sr & 0xf ; + } + else { + sr = s->frame_chain ; + sr |= (uint16_t) *c++ << 4 ; /* 1 */ + LARc [0] = sr & 0x3f ; sr >>= 6 ; + LARc [1] = sr & 0x3f ; sr >>= 6 ; + sr = *c++ ; + LARc [2] = sr & 0x1f ; sr >>= 5 ; + sr |= (uint16_t) *c++ << 3 ; + LARc [3] = sr & 0x1f ; sr >>= 5 ; + LARc [4] = sr & 0xf ; sr >>= 4 ; + sr |= (uint16_t) *c++ << 2 ; + LARc [5] = sr & 0xf ; sr >>= 4 ; + LARc [6] = sr & 0x7 ; sr >>= 3 ; + LARc [7] = sr & 0x7 ; sr >>= 3 ; + sr = *c++ ; /* 5 */ + Nc [0] = sr & 0x7f ; sr >>= 7 ; + sr |= (uint16_t) *c++ << 1 ; + bc [0] = sr & 0x3 ; sr >>= 2 ; + Mc [0] = sr & 0x3 ; sr >>= 2 ; + sr |= (uint16_t) *c++ << 5 ; + xmaxc [0] = sr & 0x3f ; sr >>= 6 ; + xmc [0] = sr & 0x7 ; sr >>= 3 ; + xmc [1] = sr & 0x7 ; sr >>= 3 ; + sr |= (uint16_t) *c++ << 1 ; + xmc [2] = sr & 0x7 ; sr >>= 3 ; + xmc [3] = sr & 0x7 ; sr >>= 3 ; + xmc [4] = sr & 0x7 ; sr >>= 3 ; + sr = *c++ ; + xmc [5] = sr & 0x7 ; sr >>= 3 ; + xmc [6] = sr & 0x7 ; sr >>= 3 ; + sr |= (uint16_t) *c++ << 2 ; /* 10 */ + xmc [7] = sr & 0x7 ; sr >>= 3 ; + xmc [8] = sr & 0x7 ; sr >>= 3 ; + xmc [9] = sr & 0x7 ; sr >>= 3 ; + sr |= (uint16_t) *c++ << 1 ; + xmc [10] = sr & 0x7 ; sr >>= 3 ; + xmc [11] = sr & 0x7 ; sr >>= 3 ; + xmc [12] = sr & 0x7 ; sr >>= 3 ; + sr = *c++ ; + Nc [1] = sr & 0x7f ; sr >>= 7 ; + sr |= (uint16_t) *c++ << 1 ; + bc [1] = sr & 0x3 ; sr >>= 2 ; + Mc [1] = sr & 0x3 ; sr >>= 2 ; + sr |= (uint16_t) *c++ << 5 ; + xmaxc [1] = sr & 0x3f ; sr >>= 6 ; + xmc [13] = sr & 0x7 ; sr >>= 3 ; + xmc [14] = sr & 0x7 ; sr >>= 3 ; + sr |= (uint16_t) *c++ << 1 ; /* 15 */ + xmc [15] = sr & 0x7 ; sr >>= 3 ; + xmc [16] = sr & 0x7 ; sr >>= 3 ; + xmc [17] = sr & 0x7 ; sr >>= 3 ; + sr = *c++ ; + xmc [18] = sr & 0x7 ; sr >>= 3 ; + xmc [19] = sr & 0x7 ; sr >>= 3 ; + sr |= (uint16_t) *c++ << 2 ; + xmc [20] = sr & 0x7 ; sr >>= 3 ; + xmc [21] = sr & 0x7 ; sr >>= 3 ; + xmc [22] = sr & 0x7 ; sr >>= 3 ; + sr |= (uint16_t) *c++ << 1 ; + xmc [23] = sr & 0x7 ; sr >>= 3 ; + xmc [24] = sr & 0x7 ; sr >>= 3 ; + xmc [25] = sr & 0x7 ; sr >>= 3 ; + sr = *c++ ; + Nc [2] = sr & 0x7f ; sr >>= 7 ; + sr |= (uint16_t) *c++ << 1 ; /* 20 */ + bc [2] = sr & 0x3 ; sr >>= 2 ; + Mc [2] = sr & 0x3 ; sr >>= 2 ; + sr |= (uint16_t) *c++ << 5 ; + xmaxc [2] = sr & 0x3f ; sr >>= 6 ; + xmc [26] = sr & 0x7 ; sr >>= 3 ; + xmc [27] = sr & 0x7 ; sr >>= 3 ; + sr |= (uint16_t) *c++ << 1 ; + xmc [28] = sr & 0x7 ; sr >>= 3 ; + xmc [29] = sr & 0x7 ; sr >>= 3 ; + xmc [30] = sr & 0x7 ; sr >>= 3 ; + sr = *c++ ; + xmc [31] = sr & 0x7 ; sr >>= 3 ; + xmc [32] = sr & 0x7 ; sr >>= 3 ; + sr |= (uint16_t) *c++ << 2 ; + xmc [33] = sr & 0x7 ; sr >>= 3 ; + xmc [34] = sr & 0x7 ; sr >>= 3 ; + xmc [35] = sr & 0x7 ; sr >>= 3 ; + sr |= (uint16_t) *c++ << 1 ; /* 25 */ + xmc [36] = sr & 0x7 ; sr >>= 3 ; + xmc [37] = sr & 0x7 ; sr >>= 3 ; + xmc [38] = sr & 0x7 ; sr >>= 3 ; + sr = *c++ ; + Nc [3] = sr & 0x7f ; sr >>= 7 ; + sr |= (uint16_t) *c++ << 1 ; + bc [3] = sr & 0x3 ; sr >>= 2 ; + Mc [3] = sr & 0x3 ; sr >>= 2 ; + sr |= (uint16_t) *c++ << 5 ; + xmaxc [3] = sr & 0x3f ; sr >>= 6 ; + xmc [39] = sr & 0x7 ; sr >>= 3 ; + xmc [40] = sr & 0x7 ; sr >>= 3 ; + sr |= (uint16_t) *c++ << 1 ; + xmc [41] = sr & 0x7 ; sr >>= 3 ; + xmc [42] = sr & 0x7 ; sr >>= 3 ; + xmc [43] = sr & 0x7 ; sr >>= 3 ; + sr = *c++ ; /* 30 */ + xmc [44] = sr & 0x7 ; sr >>= 3 ; + xmc [45] = sr & 0x7 ; sr >>= 3 ; + sr |= (uint16_t) *c++ << 2 ; + xmc [46] = sr & 0x7 ; sr >>= 3 ; + xmc [47] = sr & 0x7 ; sr >>= 3 ; + xmc [48] = sr & 0x7 ; sr >>= 3 ; + sr |= (uint16_t) *c++ << 1 ; + xmc [49] = sr & 0x7 ; sr >>= 3 ; + xmc [50] = sr & 0x7 ; sr >>= 3 ; + xmc [51] = sr & 0x7 ; sr >>= 3 ; + } + } + else +#endif + { + /* GSM_MAGIC = (*c >> 4) & 0xF ; */ + + if (((*c >> 4) & 0x0F) != GSM_MAGIC) return -1 ; + + LARc [0] = (*c++ & 0xF) << 2 ; /* 1 */ + LARc [0] |= (*c >> 6) & 0x3 ; + LARc [1] = *c++ & 0x3F ; + LARc [2] = (*c >> 3) & 0x1F ; + LARc [3] = (*c++ & 0x7) << 2 ; + LARc [3] |= (*c >> 6) & 0x3 ; + LARc [4] = (*c >> 2) & 0xF ; + LARc [5] = (*c++ & 0x3) << 2 ; + LARc [5] |= (*c >> 6) & 0x3 ; + LARc [6] = (*c >> 3) & 0x7 ; + LARc [7] = *c++ & 0x7 ; + Nc [0] = (*c >> 1) & 0x7F ; + bc [0] = (*c++ & 0x1) << 1 ; + bc [0] |= (*c >> 7) & 0x1 ; + Mc [0] = (*c >> 5) & 0x3 ; + xmaxc [0] = (*c++ & 0x1F) << 1 ; + xmaxc [0] |= (*c >> 7) & 0x1 ; + xmc [0] = (*c >> 4) & 0x7 ; + xmc [1] = (*c >> 1) & 0x7 ; + xmc [2] = (*c++ & 0x1) << 2 ; + xmc [2] |= (*c >> 6) & 0x3 ; + xmc [3] = (*c >> 3) & 0x7 ; + xmc [4] = *c++ & 0x7 ; + xmc [5] = (*c >> 5) & 0x7 ; + xmc [6] = (*c >> 2) & 0x7 ; + xmc [7] = (*c++ & 0x3) << 1 ; /* 10 */ + xmc [7] |= (*c >> 7) & 0x1 ; + xmc [8] = (*c >> 4) & 0x7 ; + xmc [9] = (*c >> 1) & 0x7 ; + xmc [10] = (*c++ & 0x1) << 2 ; + xmc [10] |= (*c >> 6) & 0x3 ; + xmc [11] = (*c >> 3) & 0x7 ; + xmc [12] = *c++ & 0x7 ; + Nc [1] = (*c >> 1) & 0x7F ; + bc [1] = (*c++ & 0x1) << 1 ; + bc [1] |= (*c >> 7) & 0x1 ; + Mc [1] = (*c >> 5) & 0x3 ; + xmaxc [1] = (*c++ & 0x1F) << 1 ; + xmaxc [1] |= (*c >> 7) & 0x1 ; + xmc [13] = (*c >> 4) & 0x7 ; + xmc [14] = (*c >> 1) & 0x7 ; + xmc [15] = (*c++ & 0x1) << 2 ; + xmc [15] |= (*c >> 6) & 0x3 ; + xmc [16] = (*c >> 3) & 0x7 ; + xmc [17] = *c++ & 0x7 ; + xmc [18] = (*c >> 5) & 0x7 ; + xmc [19] = (*c >> 2) & 0x7 ; + xmc [20] = (*c++ & 0x3) << 1 ; + xmc [20] |= (*c >> 7) & 0x1 ; + xmc [21] = (*c >> 4) & 0x7 ; + xmc [22] = (*c >> 1) & 0x7 ; + xmc [23] = (*c++ & 0x1) << 2 ; + xmc [23] |= (*c >> 6) & 0x3 ; + xmc [24] = (*c >> 3) & 0x7 ; + xmc [25] = *c++ & 0x7 ; + Nc [2] = (*c >> 1) & 0x7F ; + bc [2] = (*c++ & 0x1) << 1 ; /* 20 */ + bc [2] |= (*c >> 7) & 0x1 ; + Mc [2] = (*c >> 5) & 0x3 ; + xmaxc [2] = (*c++ & 0x1F) << 1 ; + xmaxc [2] |= (*c >> 7) & 0x1 ; + xmc [26] = (*c >> 4) & 0x7 ; + xmc [27] = (*c >> 1) & 0x7 ; + xmc [28] = (*c++ & 0x1) << 2 ; + xmc [28] |= (*c >> 6) & 0x3 ; + xmc [29] = (*c >> 3) & 0x7 ; + xmc [30] = *c++ & 0x7 ; + xmc [31] = (*c >> 5) & 0x7 ; + xmc [32] = (*c >> 2) & 0x7 ; + xmc [33] = (*c++ & 0x3) << 1 ; + xmc [33] |= (*c >> 7) & 0x1 ; + xmc [34] = (*c >> 4) & 0x7 ; + xmc [35] = (*c >> 1) & 0x7 ; + xmc [36] = (*c++ & 0x1) << 2 ; + xmc [36] |= (*c >> 6) & 0x3 ; + xmc [37] = (*c >> 3) & 0x7 ; + xmc [38] = *c++ & 0x7 ; + Nc [3] = (*c >> 1) & 0x7F ; + bc [3] = (*c++ & 0x1) << 1 ; + bc [3] |= (*c >> 7) & 0x1 ; + Mc [3] = (*c >> 5) & 0x3 ; + xmaxc [3] = (*c++ & 0x1F) << 1 ; + xmaxc [3] |= (*c >> 7) & 0x1 ; + xmc [39] = (*c >> 4) & 0x7 ; + xmc [40] = (*c >> 1) & 0x7 ; + xmc [41] = (*c++ & 0x1) << 2 ; + xmc [41] |= (*c >> 6) & 0x3 ; + xmc [42] = (*c >> 3) & 0x7 ; + xmc [43] = *c++ & 0x7 ; /* 30 */ + xmc [44] = (*c >> 5) & 0x7 ; + xmc [45] = (*c >> 2) & 0x7 ; + xmc [46] = (*c++ & 0x3) << 1 ; + xmc [46] |= (*c >> 7) & 0x1 ; + xmc [47] = (*c >> 4) & 0x7 ; + xmc [48] = (*c >> 1) & 0x7 ; + xmc [49] = (*c++ & 0x1) << 2 ; + xmc [49] |= (*c >> 6) & 0x3 ; + xmc [50] = (*c >> 3) & 0x7 ; + xmc [51] = *c & 0x7 ; /* 33 */ + } + + Gsm_Decoder (s, LARc, Nc, bc, Mc, xmaxc, xmc, target) ; + + return 0 ; +} + diff --git a/extern/libsndfile-modified/src/GSM610/gsm_destroy.c b/extern/libsndfile-modified/src/GSM610/gsm_destroy.c new file mode 100644 index 000000000..03bf7c350 --- /dev/null +++ b/extern/libsndfile-modified/src/GSM610/gsm_destroy.c @@ -0,0 +1,25 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +#include "gsm.h" +#include "config.h" + +#ifdef HAS_STDLIB_H +# include +#else +# ifdef HAS_MALLOC_H +# include +# else + extern void free () ; +# endif +#endif + +void gsm_destroy (gsm S) +{ + if (S) + free ((char *) S) ; +} + diff --git a/extern/libsndfile-modified/src/GSM610/gsm_encode.c b/extern/libsndfile-modified/src/GSM610/gsm_encode.c new file mode 100644 index 000000000..5fd535150 --- /dev/null +++ b/extern/libsndfile-modified/src/GSM610/gsm_encode.c @@ -0,0 +1,448 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +#include "gsm610_priv.h" +#include "gsm.h" + +void gsm_encode (gsm s, gsm_signal * source, gsm_byte * c) +{ + int16_t LARc [8], Nc [4], Mc [4], bc [4], xmaxc [4], xmc [13 * 4] ; + + Gsm_Coder (s, source, LARc, Nc, bc, Mc, xmaxc, xmc) ; + + + /* variable size + + GSM_MAGIC 4 + + LARc [0] 6 + LARc [1] 6 + LARc [2] 5 + LARc [3] 5 + LARc [4] 4 + LARc [5] 4 + LARc [6] 3 + LARc [7] 3 + + Nc [0] 7 + bc [0] 2 + Mc [0] 2 + xmaxc [0] 6 + xmc [0] 3 + xmc [1] 3 + xmc [2] 3 + xmc [3] 3 + xmc [4] 3 + xmc [5] 3 + xmc [6] 3 + xmc [7] 3 + xmc [8] 3 + xmc [9] 3 + xmc [10] 3 + xmc [11] 3 + xmc [12] 3 + + Nc [1] 7 + bc [1] 2 + Mc [1] 2 + xmaxc [1] 6 + xmc [13] 3 + xmc [14] 3 + xmc [15] 3 + xmc [16] 3 + xmc [17] 3 + xmc [18] 3 + xmc [19] 3 + xmc [20] 3 + xmc [21] 3 + xmc [22] 3 + xmc [23] 3 + xmc [24] 3 + xmc [25] 3 + + Nc [2] 7 + bc [2] 2 + Mc [2] 2 + xmaxc [2] 6 + xmc [26] 3 + xmc [27] 3 + xmc [28] 3 + xmc [29] 3 + xmc [30] 3 + xmc [31] 3 + xmc [32] 3 + xmc [33] 3 + xmc [34] 3 + xmc [35] 3 + xmc [36] 3 + xmc [37] 3 + xmc [38] 3 + + Nc [3] 7 + bc [3] 2 + Mc [3] 2 + xmaxc [3] 6 + xmc [39] 3 + xmc [40] 3 + xmc [41] 3 + xmc [42] 3 + xmc [43] 3 + xmc [44] 3 + xmc [45] 3 + xmc [46] 3 + xmc [47] 3 + xmc [48] 3 + xmc [49] 3 + xmc [50] 3 + xmc [51] 3 + */ + +#ifdef WAV49 + + if (s->wav_fmt) + { s->frame_index = !s->frame_index ; + if (s->frame_index) + { uint16_t sr ; + + sr = 0 ; + sr = sr >> 6 | LARc [0] << 10 ; + sr = sr >> 6 | LARc [1] << 10 ; + *c++ = sr >> 4 ; + sr = sr >> 5 | LARc [2] << 11 ; + *c++ = sr >> 7 ; + sr = sr >> 5 | LARc [3] << 11 ; + sr = sr >> 4 | LARc [4] << 12 ; + *c++ = sr >> 6 ; + sr = sr >> 4 | LARc [5] << 12 ; + sr = sr >> 3 | LARc [6] << 13 ; + *c++ = sr >> 7 ; + sr = sr >> 3 | LARc [7] << 13 ; + sr = sr >> 7 | Nc [0] << 9 ; + *c++ = sr >> 5 ; + sr = sr >> 2 | bc [0] << 14 ; + sr = sr >> 2 | Mc [0] << 14 ; + sr = sr >> 6 | xmaxc [0] << 10 ; + *c++ = sr >> 3 ; + sr = sr >> 3 | xmc [0] << 13 ; + *c++ = sr >> 8 ; + sr = sr >> 3 | xmc [1] << 13 ; + sr = sr >> 3 | xmc [2] << 13 ; + sr = sr >> 3 | xmc [3] << 13 ; + *c++ = sr >> 7 ; + sr = sr >> 3 | xmc [4] << 13 ; + sr = sr >> 3 | xmc [5] << 13 ; + sr = sr >> 3 | xmc [6] << 13 ; + *c++ = sr >> 6 ; + sr = sr >> 3 | xmc [7] << 13 ; + sr = sr >> 3 | xmc [8] << 13 ; + *c++ = sr >> 8 ; + sr = sr >> 3 | xmc [9] << 13 ; + sr = sr >> 3 | xmc [10] << 13 ; + sr = sr >> 3 | xmc [11] << 13 ; + *c++ = sr >> 7 ; + sr = sr >> 3 | xmc [12] << 13 ; + sr = sr >> 7 | Nc [1] << 9 ; + *c++ = sr >> 5 ; + sr = sr >> 2 | bc [1] << 14 ; + sr = sr >> 2 | Mc [1] << 14 ; + sr = sr >> 6 | xmaxc [1] << 10 ; + *c++ = sr >> 3 ; + sr = sr >> 3 | xmc [13] << 13 ; + *c++ = sr >> 8 ; + sr = sr >> 3 | xmc [14] << 13 ; + sr = sr >> 3 | xmc [15] << 13 ; + sr = sr >> 3 | xmc [16] << 13 ; + *c++ = sr >> 7 ; + sr = sr >> 3 | xmc [17] << 13 ; + sr = sr >> 3 | xmc [18] << 13 ; + sr = sr >> 3 | xmc [19] << 13 ; + *c++ = sr >> 6 ; + sr = sr >> 3 | xmc [20] << 13 ; + sr = sr >> 3 | xmc [21] << 13 ; + *c++ = sr >> 8 ; + sr = sr >> 3 | xmc [22] << 13 ; + sr = sr >> 3 | xmc [23] << 13 ; + sr = sr >> 3 | xmc [24] << 13 ; + *c++ = sr >> 7 ; + sr = sr >> 3 | xmc [25] << 13 ; + sr = sr >> 7 | Nc [2] << 9 ; + *c++ = sr >> 5 ; + sr = sr >> 2 | bc [2] << 14 ; + sr = sr >> 2 | Mc [2] << 14 ; + sr = sr >> 6 | xmaxc [2] << 10 ; + *c++ = sr >> 3 ; + sr = sr >> 3 | xmc [26] << 13 ; + *c++ = sr >> 8 ; + sr = sr >> 3 | xmc [27] << 13 ; + sr = sr >> 3 | xmc [28] << 13 ; + sr = sr >> 3 | xmc [29] << 13 ; + *c++ = sr >> 7 ; + sr = sr >> 3 | xmc [30] << 13 ; + sr = sr >> 3 | xmc [31] << 13 ; + sr = sr >> 3 | xmc [32] << 13 ; + *c++ = sr >> 6 ; + sr = sr >> 3 | xmc [33] << 13 ; + sr = sr >> 3 | xmc [34] << 13 ; + *c++ = sr >> 8 ; + sr = sr >> 3 | xmc [35] << 13 ; + sr = sr >> 3 | xmc [36] << 13 ; + sr = sr >> 3 | xmc [37] << 13 ; + *c++ = sr >> 7 ; + sr = sr >> 3 | xmc [38] << 13 ; + sr = sr >> 7 | Nc [3] << 9 ; + *c++ = sr >> 5 ; + sr = sr >> 2 | bc [3] << 14 ; + sr = sr >> 2 | Mc [3] << 14 ; + sr = sr >> 6 | xmaxc [3] << 10 ; + *c++ = sr >> 3 ; + sr = sr >> 3 | xmc [39] << 13 ; + *c++ = sr >> 8 ; + sr = sr >> 3 | xmc [40] << 13 ; + sr = sr >> 3 | xmc [41] << 13 ; + sr = sr >> 3 | xmc [42] << 13 ; + *c++ = sr >> 7 ; + sr = sr >> 3 | xmc [43] << 13 ; + sr = sr >> 3 | xmc [44] << 13 ; + sr = sr >> 3 | xmc [45] << 13 ; + *c++ = sr >> 6 ; + sr = sr >> 3 | xmc [46] << 13 ; + sr = sr >> 3 | xmc [47] << 13 ; + *c++ = sr >> 8 ; + sr = sr >> 3 | xmc [48] << 13 ; + sr = sr >> 3 | xmc [49] << 13 ; + sr = sr >> 3 | xmc [50] << 13 ; + *c++ = sr >> 7 ; + sr = sr >> 3 | xmc [51] << 13 ; + sr = sr >> 4 ; + *c = sr >> 8 ; + s->frame_chain = *c ; + } + else { + uint16_t sr ; + + sr = 0 ; + sr = sr >> 4 | s->frame_chain << 12 ; + sr = sr >> 6 | LARc [0] << 10 ; + *c++ = sr >> 6 ; + sr = sr >> 6 | LARc [1] << 10 ; + *c++ = sr >> 8 ; + sr = sr >> 5 | LARc [2] << 11 ; + sr = sr >> 5 | LARc [3] << 11 ; + *c++ = sr >> 6 ; + sr = sr >> 4 | LARc [4] << 12 ; + sr = sr >> 4 | LARc [5] << 12 ; + *c++ = sr >> 6 ; + sr = sr >> 3 | LARc [6] << 13 ; + sr = sr >> 3 | LARc [7] << 13 ; + *c++ = sr >> 8 ; + sr = sr >> 7 | Nc [0] << 9 ; + sr = sr >> 2 | bc [0] << 14 ; + *c++ = sr >> 7 ; + sr = sr >> 2 | Mc [0] << 14 ; + sr = sr >> 6 | xmaxc [0] << 10 ; + *c++ = sr >> 7 ; + sr = sr >> 3 | xmc [0] << 13 ; + sr = sr >> 3 | xmc [1] << 13 ; + sr = sr >> 3 | xmc [2] << 13 ; + *c++ = sr >> 6 ; + sr = sr >> 3 | xmc [3] << 13 ; + sr = sr >> 3 | xmc [4] << 13 ; + *c++ = sr >> 8 ; + sr = sr >> 3 | xmc [5] << 13 ; + sr = sr >> 3 | xmc [6] << 13 ; + sr = sr >> 3 | xmc [7] << 13 ; + *c++ = sr >> 7 ; + sr = sr >> 3 | xmc [8] << 13 ; + sr = sr >> 3 | xmc [9] << 13 ; + sr = sr >> 3 | xmc [10] << 13 ; + *c++ = sr >> 6 ; + sr = sr >> 3 | xmc [11] << 13 ; + sr = sr >> 3 | xmc [12] << 13 ; + *c++ = sr >> 8 ; + sr = sr >> 7 | Nc [1] << 9 ; + sr = sr >> 2 | bc [1] << 14 ; + *c++ = sr >> 7 ; + sr = sr >> 2 | Mc [1] << 14 ; + sr = sr >> 6 | xmaxc [1] << 10 ; + *c++ = sr >> 7 ; + sr = sr >> 3 | xmc [13] << 13 ; + sr = sr >> 3 | xmc [14] << 13 ; + sr = sr >> 3 | xmc [15] << 13 ; + *c++ = sr >> 6 ; + sr = sr >> 3 | xmc [16] << 13 ; + sr = sr >> 3 | xmc [17] << 13 ; + *c++ = sr >> 8 ; + sr = sr >> 3 | xmc [18] << 13 ; + sr = sr >> 3 | xmc [19] << 13 ; + sr = sr >> 3 | xmc [20] << 13 ; + *c++ = sr >> 7 ; + sr = sr >> 3 | xmc [21] << 13 ; + sr = sr >> 3 | xmc [22] << 13 ; + sr = sr >> 3 | xmc [23] << 13 ; + *c++ = sr >> 6 ; + sr = sr >> 3 | xmc [24] << 13 ; + sr = sr >> 3 | xmc [25] << 13 ; + *c++ = sr >> 8 ; + sr = sr >> 7 | Nc [2] << 9 ; + sr = sr >> 2 | bc [2] << 14 ; + *c++ = sr >> 7 ; + sr = sr >> 2 | Mc [2] << 14 ; + sr = sr >> 6 | xmaxc [2] << 10 ; + *c++ = sr >> 7 ; + sr = sr >> 3 | xmc [26] << 13 ; + sr = sr >> 3 | xmc [27] << 13 ; + sr = sr >> 3 | xmc [28] << 13 ; + *c++ = sr >> 6 ; + sr = sr >> 3 | xmc [29] << 13 ; + sr = sr >> 3 | xmc [30] << 13 ; + *c++ = sr >> 8 ; + sr = sr >> 3 | xmc [31] << 13 ; + sr = sr >> 3 | xmc [32] << 13 ; + sr = sr >> 3 | xmc [33] << 13 ; + *c++ = sr >> 7 ; + sr = sr >> 3 | xmc [34] << 13 ; + sr = sr >> 3 | xmc [35] << 13 ; + sr = sr >> 3 | xmc [36] << 13 ; + *c++ = sr >> 6 ; + sr = sr >> 3 | xmc [37] << 13 ; + sr = sr >> 3 | xmc [38] << 13 ; + *c++ = sr >> 8 ; + sr = sr >> 7 | Nc [3] << 9 ; + sr = sr >> 2 | bc [3] << 14 ; + *c++ = sr >> 7 ; + sr = sr >> 2 | Mc [3] << 14 ; + sr = sr >> 6 | xmaxc [3] << 10 ; + *c++ = sr >> 7 ; + sr = sr >> 3 | xmc [39] << 13 ; + sr = sr >> 3 | xmc [40] << 13 ; + sr = sr >> 3 | xmc [41] << 13 ; + *c++ = sr >> 6 ; + sr = sr >> 3 | xmc [42] << 13 ; + sr = sr >> 3 | xmc [43] << 13 ; + *c++ = sr >> 8 ; + sr = sr >> 3 | xmc [44] << 13 ; + sr = sr >> 3 | xmc [45] << 13 ; + sr = sr >> 3 | xmc [46] << 13 ; + *c++ = sr >> 7 ; + sr = sr >> 3 | xmc [47] << 13 ; + sr = sr >> 3 | xmc [48] << 13 ; + sr = sr >> 3 | xmc [49] << 13 ; + *c++ = sr >> 6 ; + sr = sr >> 3 | xmc [50] << 13 ; + sr = sr >> 3 | xmc [51] << 13 ; + *c++ = sr >> 8 ; + } + } + + else + +#endif /* WAV49 */ + { + + *c++ = ((GSM_MAGIC & 0xF) << 4) /* 1 */ + | ((LARc [0] >> 2) & 0xF) ; + *c++ = ((LARc [0] & 0x3) << 6) + | (LARc [1] & 0x3F) ; + *c++ = ((LARc [2] & 0x1F) << 3) + | ((LARc [3] >> 2) & 0x7) ; + *c++ = ((LARc [3] & 0x3) << 6) + | ((LARc [4] & 0xF) << 2) + | ((LARc [5] >> 2) & 0x3) ; + *c++ = ((LARc [5] & 0x3) << 6) + | ((LARc [6] & 0x7) << 3) + | (LARc [7] & 0x7) ; + *c++ = ((Nc [0] & 0x7F) << 1) + | ((bc [0] >> 1) & 0x1) ; + *c++ = ((bc [0] & 0x1) << 7) + | ((Mc [0] & 0x3) << 5) + | ((xmaxc [0] >> 1) & 0x1F) ; + *c++ = ((xmaxc [0] & 0x1) << 7) + | ((xmc [0] & 0x7) << 4) + | ((xmc [1] & 0x7) << 1) + | ((xmc [2] >> 2) & 0x1) ; + *c++ = ((xmc [2] & 0x3) << 6) + | ((xmc [3] & 0x7) << 3) + | (xmc [4] & 0x7) ; + *c++ = ((xmc [5] & 0x7) << 5) /* 10 */ + | ((xmc [6] & 0x7) << 2) + | ((xmc [7] >> 1) & 0x3) ; + *c++ = ((xmc [7] & 0x1) << 7) + | ((xmc [8] & 0x7) << 4) + | ((xmc [9] & 0x7) << 1) + | ((xmc [10] >> 2) & 0x1) ; + *c++ = ((xmc [10] & 0x3) << 6) + | ((xmc [11] & 0x7) << 3) + | (xmc [12] & 0x7) ; + *c++ = ((Nc [1] & 0x7F) << 1) + | ((bc [1] >> 1) & 0x1) ; + *c++ = ((bc [1] & 0x1) << 7) + | ((Mc [1] & 0x3) << 5) + | ((xmaxc [1] >> 1) & 0x1F) ; + *c++ = ((xmaxc [1] & 0x1) << 7) + | ((xmc [13] & 0x7) << 4) + | ((xmc [14] & 0x7) << 1) + | ((xmc [15] >> 2) & 0x1) ; + *c++ = ((xmc [15] & 0x3) << 6) + | ((xmc [16] & 0x7) << 3) + | (xmc [17] & 0x7) ; + *c++ = ((xmc [18] & 0x7) << 5) + | ((xmc [19] & 0x7) << 2) + | ((xmc [20] >> 1) & 0x3) ; + *c++ = ((xmc [20] & 0x1) << 7) + | ((xmc [21] & 0x7) << 4) + | ((xmc [22] & 0x7) << 1) + | ((xmc [23] >> 2) & 0x1) ; + *c++ = ((xmc [23] & 0x3) << 6) + | ((xmc [24] & 0x7) << 3) + | (xmc [25] & 0x7) ; + *c++ = ((Nc [2] & 0x7F) << 1) /* 20 */ + | ((bc [2] >> 1) & 0x1) ; + *c++ = ((bc [2] & 0x1) << 7) + | ((Mc [2] & 0x3) << 5) + | ((xmaxc [2] >> 1) & 0x1F) ; + *c++ = ((xmaxc [2] & 0x1) << 7) + | ((xmc [26] & 0x7) << 4) + | ((xmc [27] & 0x7) << 1) + | ((xmc [28] >> 2) & 0x1) ; + *c++ = ((xmc [28] & 0x3) << 6) + | ((xmc [29] & 0x7) << 3) + | (xmc [30] & 0x7) ; + *c++ = ((xmc [31] & 0x7) << 5) + | ((xmc [32] & 0x7) << 2) + | ((xmc [33] >> 1) & 0x3) ; + *c++ = ((xmc [33] & 0x1) << 7) + | ((xmc [34] & 0x7) << 4) + | ((xmc [35] & 0x7) << 1) + | ((xmc [36] >> 2) & 0x1) ; + *c++ = ((xmc [36] & 0x3) << 6) + | ((xmc [37] & 0x7) << 3) + | (xmc [38] & 0x7) ; + *c++ = ((Nc [3] & 0x7F) << 1) + | ((bc [3] >> 1) & 0x1) ; + *c++ = ((bc [3] & 0x1) << 7) + | ((Mc [3] & 0x3) << 5) + | ((xmaxc [3] >> 1) & 0x1F) ; + *c++ = ((xmaxc [3] & 0x1) << 7) + | ((xmc [39] & 0x7) << 4) + | ((xmc [40] & 0x7) << 1) + | ((xmc [41] >> 2) & 0x1) ; + *c++ = ((xmc [41] & 0x3) << 6) /* 30 */ + | ((xmc [42] & 0x7) << 3) + | (xmc [43] & 0x7) ; + *c++ = ((xmc [44] & 0x7) << 5) + | ((xmc [45] & 0x7) << 2) + | ((xmc [46] >> 1) & 0x3) ; + *c++ = ((xmc [46] & 0x1) << 7) + | ((xmc [47] & 0x7) << 4) + | ((xmc [48] & 0x7) << 1) + | ((xmc [49] >> 2) & 0x1) ; + *c++ = ((xmc [49] & 0x3) << 6) + | ((xmc [50] & 0x7) << 3) + | (xmc [51] & 0x7) ; + + } +} + diff --git a/extern/libsndfile-modified/src/GSM610/gsm_option.c b/extern/libsndfile-modified/src/GSM610/gsm_option.c new file mode 100644 index 000000000..208768338 --- /dev/null +++ b/extern/libsndfile-modified/src/GSM610/gsm_option.c @@ -0,0 +1,66 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +#include "gsm610_priv.h" + +#include "gsm.h" + +int gsm_option (gsm r, int opt, int * val) +{ + int result = -1 ; + + switch (opt) { + case GSM_OPT_LTP_CUT: +#ifdef LTP_CUT + result = r->ltp_cut ; + if (val) r->ltp_cut = *val ; +#endif + break ; + + case GSM_OPT_VERBOSE: +#ifndef NDEBUG + result = r->verbose ; + if (val) r->verbose = *val ; +#endif + break ; + + case GSM_OPT_FAST: + +#if defined (FAST) && defined (USE_FLOAT_MUL) + result = r->fast ; + if (val) r->fast = !!*val ; +#endif + break ; + + case GSM_OPT_FRAME_CHAIN: + +#ifdef WAV49 + result = r->frame_chain ; + if (val) r->frame_chain = *val ; +#endif + break ; + + case GSM_OPT_FRAME_INDEX: + +#ifdef WAV49 + result = r->frame_index ; + if (val) r->frame_index = *val ; +#endif + break ; + + case GSM_OPT_WAV49: + +#ifdef WAV49 + result = r->wav_fmt ; + if (val) r->wav_fmt = !!*val ; +#endif + break ; + + default: + break ; + } + return result ; +} diff --git a/extern/libsndfile-modified/src/GSM610/long_term.c b/extern/libsndfile-modified/src/GSM610/long_term.c new file mode 100644 index 000000000..3276a464c --- /dev/null +++ b/extern/libsndfile-modified/src/GSM610/long_term.c @@ -0,0 +1,932 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +#include +#include + +#include "gsm610_priv.h" + +/* + * 4.2.11 .. 4.2.12 LONG TERM PREDICTOR (LTP) SECTION + */ + + +/* + * This module computes the LTP gain (bc) and the LTP lag (Nc) + * for the long term analysis filter. This is done by calculating a + * maximum of the cross-correlation function between the current + * sub-segment short term residual signal d [0..39] (output of + * the short term analysis filter ; for simplification the index + * of this array begins at 0 and ends at 39 for each sub-segment of the + * RPE-LTP analysis) and the previous reconstructed short term + * residual signal dp [-120 .. -1]. A dynamic scaling must be + * performed to avoid overflow. + */ + + /* The next procedure exists in six versions. First two integer + * version (if USE_FLOAT_MUL is not defined) ; then four floating + * point versions, twice with proper scaling (USE_FLOAT_MUL defined), + * once without (USE_FLOAT_MUL and FAST defined, and fast run-time + * option used). Every pair has first a Cut version (see the -C + * option to toast or the LTP_CUT option to gsm_option ()), then the + * uncut one. (For a detailed explanation of why this is altogether + * a bad idea, see Henry Spencer and Geoff Collyer, ``#ifdef Considered + * Harmful''.) + */ + +#ifndef USE_FLOAT_MUL + +#ifdef LTP_CUT + +static void Cut_Calculation_of_the_LTP_parameters ( + + struct gsm_state * st, + + register int16_t * d, /* [0..39] IN */ + register int16_t * dp, /* [-120..-1] IN */ + int16_t * bc_out, /* OUT */ + int16_t * Nc_out /* OUT */) +{ + register int k, lambda ; + int16_t Nc, bc ; + int16_t wt [40] ; + + int32_t L_result ; + int32_t L_max, L_power ; + int16_t R, S, dmax, scal, best_k ; + int16_t ltp_cut ; + + register int16_t temp, wt_k ; + + /* Search of the optimum scaling of d [0..39]. */ + dmax = 0 ; + for (k = 0 ; k <= 39 ; k++) + { temp = d [k] ; + temp = GSM_ABS (temp) ; + if (temp > dmax) + { dmax = temp ; + best_k = k ; + } + } + temp = 0 ; + if (dmax == 0) + scal = 0 ; + else + { assert (dmax > 0) ; + temp = gsm_norm ((int32_t) dmax << 16) ; + } + if (temp > 6) scal = 0 ; + else scal = 6 - temp ; + assert (scal >= 0) ; + + /* Search for the maximum cross-correlation and coding of the LTP lag + */ + L_max = 0 ; + Nc = 40 ; /* index for the maximum cross-correlation */ + wt_k = SASR_W (d [best_k], scal) ; + + for (lambda = 40 ; lambda <= 120 ; lambda++) + { L_result = (int32_t) wt_k * dp [best_k - lambda] ; + if (L_result > L_max) + { Nc = lambda ; + L_max = L_result ; + } + } + *Nc_out = Nc ; + L_max <<= 1 ; + + /* Rescaling of L_max + */ + assert (scal <= 100 && scal >= -100) ; + L_max = L_max >> (6 - scal) ; /* sub (6, scal) */ + + assert (Nc <= 120 && Nc >= 40) ; + + /* Compute the power of the reconstructed short term residual + * signal dp [..] + */ + L_power = 0 ; + for (k = 0 ; k <= 39 ; k++) + { register int32_t L_temp ; + + L_temp = SASR_W (dp [k - Nc], 3) ; + L_power += L_temp * L_temp ; + } + L_power <<= 1 ; /* from L_MULT */ + + /* Normalization of L_max and L_power */ + + if (L_max <= 0) + { *bc_out = 0 ; + return ; + } + if (L_max >= L_power) + { *bc_out = 3 ; + return ; + } + + temp = gsm_norm (L_power) ; + + R = SASR (L_max << temp, 16) ; + S = SASR (L_power << temp, 16) ; + + /* Coding of the LTP gain + */ + + /* Table 4.3a must be used to obtain the level DLB [i] for the + * quantization of the LTP gain b to get the coded version bc. + */ + for (bc = 0 ; bc <= 2 ; bc++) if (R <= gsm_mult (S, gsm_DLB [bc])) break ; + *bc_out = bc ; +} + +#endif /* LTP_CUT */ + +static void Calculation_of_the_LTP_parameters ( + register int16_t * d, /* [0..39] IN */ + register int16_t * dp, /* [-120..-1] IN */ + int16_t * bc_out, /* OUT */ + int16_t * Nc_out /* OUT */) +{ + register int k, lambda ; + int16_t Nc, bc ; + int16_t wt [40] ; + + int32_t L_max, L_power ; + int16_t R, S, dmax, scal ; + register int16_t temp ; + + /* Search of the optimum scaling of d [0..39]. + */ + dmax = 0 ; + + for (k = 0 ; k <= 39 ; k++) + { temp = d [k] ; + temp = GSM_ABS (temp) ; + if (temp > dmax) dmax = temp ; + } + + temp = 0 ; + if (dmax == 0) + scal = 0 ; + else + { assert (dmax > 0) ; + temp = gsm_norm ((int32_t) dmax << 16) ; + } + + if (temp > 6) scal = 0 ; + else scal = 6 - temp ; + + assert (scal >= 0) ; + + /* Initialization of a working array wt + */ + + for (k = 0 ; k <= 39 ; k++) wt [k] = SASR_W (d [k], scal) ; + + /* Search for the maximum cross-correlation and coding of the LTP lag */ + L_max = 0 ; + Nc = 40 ; /* index for the maximum cross-correlation */ + + for (lambda = 40 ; lambda <= 120 ; lambda++) + { + +# undef STEP +# define STEP(k) (int32_t) wt [k] * dp [k - lambda] + + register int32_t L_result ; + + L_result = STEP (0) ; L_result += STEP (1) ; + L_result += STEP (2) ; L_result += STEP (3) ; + L_result += STEP (4) ; L_result += STEP (5) ; + L_result += STEP (6) ; L_result += STEP (7) ; + L_result += STEP (8) ; L_result += STEP (9) ; + L_result += STEP (10) ; L_result += STEP (11) ; + L_result += STEP (12) ; L_result += STEP (13) ; + L_result += STEP (14) ; L_result += STEP (15) ; + L_result += STEP (16) ; L_result += STEP (17) ; + L_result += STEP (18) ; L_result += STEP (19) ; + L_result += STEP (20) ; L_result += STEP (21) ; + L_result += STEP (22) ; L_result += STEP (23) ; + L_result += STEP (24) ; L_result += STEP (25) ; + L_result += STEP (26) ; L_result += STEP (27) ; + L_result += STEP (28) ; L_result += STEP (29) ; + L_result += STEP (30) ; L_result += STEP (31) ; + L_result += STEP (32) ; L_result += STEP (33) ; + L_result += STEP (34) ; L_result += STEP (35) ; + L_result += STEP (36) ; L_result += STEP (37) ; + L_result += STEP (38) ; L_result += STEP (39) ; + + if (L_result > L_max) + { Nc = lambda ; + L_max = L_result ; + } + } + + *Nc_out = Nc ; + + L_max <<= 1 ; + + /* Rescaling of L_max + */ + assert (scal <= 100 && scal >= -100) ; + L_max = L_max >> (6 - scal) ; /* sub (6, scal) */ + + assert (Nc <= 120 && Nc >= 40) ; + + /* Compute the power of the reconstructed short term residual + * signal dp [..] + */ + L_power = 0 ; + for (k = 0 ; k <= 39 ; k++) + { register int32_t L_temp ; + + L_temp = SASR_W (dp [k - Nc], 3) ; + L_power += L_temp * L_temp ; + } + L_power <<= 1 ; /* from L_MULT */ + + /* Normalization of L_max and L_power + */ + + if (L_max <= 0) + { *bc_out = 0 ; + return ; + } + if (L_max >= L_power) + { *bc_out = 3 ; + return ; + } + + temp = gsm_norm (L_power) ; + + R = SASR_L (L_max << temp, 16) ; + S = SASR_L (L_power << temp, 16) ; + + /* Coding of the LTP gain + */ + + /* Table 4.3a must be used to obtain the level DLB [i] for the + * quantization of the LTP gain b to get the coded version bc. + */ + for (bc = 0 ; bc <= 2 ; bc++) if (R <= gsm_mult (S, gsm_DLB [bc])) break ; + *bc_out = bc ; +} + +#else /* USE_FLOAT_MUL */ + +#ifdef LTP_CUT + +static void Cut_Calculation_of_the_LTP_parameters ( + struct gsm_state * st, /* IN */ + register int16_t * d, /* [0..39] IN */ + register int16_t * dp, /* [-120..-1] IN */ + int16_t * bc_out, /* OUT */ + int16_t * Nc_out /* OUT */) +{ + register int k, lambda ; + int16_t Nc, bc ; + int16_t ltp_cut ; + + float wt_float [40] ; + float dp_float_base [120], * dp_float = dp_float_base + 120 ; + + int32_t L_max, L_power ; + int16_t R, S, dmax, scal ; + register int16_t temp ; + + /* Search of the optimum scaling of d [0..39]. + */ + dmax = 0 ; + + for (k = 0 ; k <= 39 ; k++) + { temp = d [k] ; + temp = GSM_ABS (temp) ; + if (temp > dmax) dmax = temp ; + } + + temp = 0 ; + if (dmax == 0) scal = 0 ; + else + { assert (dmax > 0) ; + temp = gsm_norm ((int32_t) dmax << 16) ; + } + + if (temp > 6) scal = 0 ; + else scal = 6 - temp ; + + assert (scal >= 0) ; + ltp_cut = (int32_t) SASR_W (dmax, scal) * st->ltp_cut / 100 ; + + /* Initialization of a working array wt */ + + for (k = 0 ; k < 40 ; k++) + { register int16_t w = SASR_W (d [k], scal) ; + if (w < 0 ? w > -ltp_cut : w < ltp_cut) + wt_float [k] = 0.0 ; + else + wt_float [k] = w ; + } + for (k = -120 ; k < 0 ; k++) dp_float [k] = dp [k] ; + + /* Search for the maximum cross-correlation and coding of the LTP lag + */ + L_max = 0 ; + Nc = 40 ; /* index for the maximum cross-correlation */ + + for (lambda = 40 ; lambda <= 120 ; lambda += 9) + { /* Calculate L_result for l = lambda .. lambda + 9. */ + register float *lp = dp_float - lambda ; + + register float W ; + register float a = lp [-8], b = lp [-7], c = lp [-6], + d = lp [-5], e = lp [-4], f = lp [-3], + g = lp [-2], h = lp [-1] ; + register float E ; + register float S0 = 0, S1 = 0, S2 = 0, S3 = 0, S4 = 0, + S5 = 0, S6 = 0, S7 = 0, S8 = 0 ; + +# undef STEP +# define STEP(K, a, b, c, d, e, f, g, h) \ + if ((W = wt_float [K]) != 0.0) { \ + E = W * a ; S8 += E ; \ + E = W * b ; S7 += E ; \ + E = W * c ; S6 += E ; \ + E = W * d ; S5 += E ; \ + E = W * e ; S4 += E ; \ + E = W * f ; S3 += E ; \ + E = W * g ; S2 += E ; \ + E = W * h ; S1 += E ; \ + a = lp [K] ; \ + E = W * a ; S0 += E ; } else (a = lp [K]) + +# define STEP_A(K) STEP (K, a, b, c, d, e, f, g, h) +# define STEP_B(K) STEP (K, b, c, d, e, f, g, h, a) +# define STEP_C(K) STEP (K, c, d, e, f, g, h, a, b) +# define STEP_D(K) STEP (K, d, e, f, g, h, a, b, c) +# define STEP_E(K) STEP (K, e, f, g, h, a, b, c, d) +# define STEP_F(K) STEP (K, f, g, h, a, b, c, d, e) +# define STEP_G(K) STEP (K, g, h, a, b, c, d, e, f) +# define STEP_H(K) STEP (K, h, a, b, c, d, e, f, g) + + STEP_A (0) ; STEP_B (1) ; STEP_C (2) ; STEP_D (3) ; + STEP_E (4) ; STEP_F (5) ; STEP_G (6) ; STEP_H (7) ; + + STEP_A (8) ; STEP_B (9) ; STEP_C (10) ; STEP_D (11) ; + STEP_E (12) ; STEP_F (13) ; STEP_G (14) ; STEP_H (15) ; + + STEP_A (16) ; STEP_B (17) ; STEP_C (18) ; STEP_D (19) ; + STEP_E (20) ; STEP_F (21) ; STEP_G (22) ; STEP_H (23) ; + + STEP_A (24) ; STEP_B (25) ; STEP_C (26) ; STEP_D (27) ; + STEP_E (28) ; STEP_F (29) ; STEP_G (30) ; STEP_H (31) ; + + STEP_A (32) ; STEP_B (33) ; STEP_C (34) ; STEP_D (35) ; + STEP_E (36) ; STEP_F (37) ; STEP_G (38) ; STEP_H (39) ; + +# undef STEP_A +# undef STEP_B +# undef STEP_C +# undef STEP_D +# undef STEP_E +# undef STEP_F +# undef STEP_G +# undef STEP_H + + if (S0 > L_max) { L_max = S0 ; Nc = lambda ; } + if (S1 > L_max) { L_max = S1 ; Nc = lambda + 1 ; } + if (S2 > L_max) { L_max = S2 ; Nc = lambda + 2 ; } + if (S3 > L_max) { L_max = S3 ; Nc = lambda + 3 ; } + if (S4 > L_max) { L_max = S4 ; Nc = lambda + 4 ; } + if (S5 > L_max) { L_max = S5 ; Nc = lambda + 5 ; } + if (S6 > L_max) { L_max = S6 ; Nc = lambda + 6 ; } + if (S7 > L_max) { L_max = S7 ; Nc = lambda + 7 ; } + if (S8 > L_max) { L_max = S8 ; Nc = lambda + 8 ; } + + } + *Nc_out = Nc ; + + L_max <<= 1 ; + + /* Rescaling of L_max + */ + assert (scal <= 100 && scal >= -100) ; + L_max = L_max >> (6 - scal) ; /* sub (6, scal) */ + + assert (Nc <= 120 && Nc >= 40) ; + + /* Compute the power of the reconstructed short term residual + * signal dp [..] + */ + L_power = 0 ; + for (k = 0 ; k <= 39 ; k++) + { register int32_t L_temp ; + + L_temp = SASR_W (dp [k - Nc], 3) ; + L_power += L_temp * L_temp ; + } + L_power <<= 1 ; /* from L_MULT */ + + /* Normalization of L_max and L_power + */ + + if (L_max <= 0) + { *bc_out = 0 ; + return ; + } + if (L_max >= L_power) + { *bc_out = 3 ; + return ; + } + + temp = gsm_norm (L_power) ; + + R = SASR (L_max << temp, 16) ; + S = SASR (L_power << temp, 16) ; + + /* Coding of the LTP gain + */ + + /* Table 4.3a must be used to obtain the level DLB [i] for the + * quantization of the LTP gain b to get the coded version bc. + */ + for (bc = 0 ; bc <= 2 ; bc++) if (R <= gsm_mult (S, gsm_DLB [bc])) break ; + *bc_out = bc ; +} + +#endif /* LTP_CUT */ + +static void Calculation_of_the_LTP_parameters ( + register int16_t * din, /* [0..39] IN */ + register int16_t * dp, /* [-120..-1] IN */ + int16_t * bc_out, /* OUT */ + int16_t * Nc_out /* OUT */) +{ + register int k, lambda ; + int16_t Nc, bc ; + + float wt_float [40] ; + float dp_float_base [120], * dp_float = dp_float_base + 120 ; + + int32_t L_max, L_power ; + int16_t R, S, dmax, scal ; + register int16_t temp ; + + /* Search of the optimum scaling of d [0..39]. + */ + dmax = 0 ; + + for (k = 0 ; k <= 39 ; k++) + { temp = din [k] ; + temp = GSM_ABS (temp) ; + if (temp > dmax) dmax = temp ; + } + + temp = 0 ; + if (dmax == 0) scal = 0 ; + else + { assert (dmax > 0) ; + temp = gsm_norm ((int32_t) dmax << 16) ; + } + + if (temp > 6) scal = 0 ; + else scal = 6 - temp ; + + assert (scal >= 0) ; + + /* Initialization of a working array wt */ + + for (k = 0 ; k < 40 ; k++) wt_float [k] = SASR_W (din [k], scal) ; + for (k = -120 ; k < 0 ; k++) dp_float [k] = dp [k] ; + + /* Search for the maximum cross-correlation and coding of the LTP lag + */ + L_max = 0 ; + Nc = 40 ; /* index for the maximum cross-correlation */ + + for (lambda = 40 ; lambda <= 120 ; lambda += 9) + { /* Calculate L_result for l = lambda .. lambda + 9. */ + register float *lp = dp_float - lambda ; + + register float W ; + register float a = lp [-8], b = lp [-7], c = lp [-6], + d = lp [-5], e = lp [-4], f = lp [-3], + g = lp [-2], h = lp [-1] ; + register float E ; + register float S0 = 0, S1 = 0, S2 = 0, S3 = 0, S4 = 0, + S5 = 0, S6 = 0, S7 = 0, S8 = 0 ; + +# undef STEP +# define STEP(K, a, b, c, d, e, f, g, h) \ + W = wt_float [K] ; \ + E = W * a ; S8 += E ; \ + E = W * b ; S7 += E ; \ + E = W * c ; S6 += E ; \ + E = W * d ; S5 += E ; \ + E = W * e ; S4 += E ; \ + E = W * f ; S3 += E ; \ + E = W * g ; S2 += E ; \ + E = W * h ; S1 += E ; \ + a = lp [K] ; \ + E = W * a ; S0 += E + +# define STEP_A(K) STEP (K, a, b, c, d, e, f, g, h) +# define STEP_B(K) STEP (K, b, c, d, e, f, g, h, a) +# define STEP_C(K) STEP (K, c, d, e, f, g, h, a, b) +# define STEP_D(K) STEP (K, d, e, f, g, h, a, b, c) +# define STEP_E(K) STEP (K, e, f, g, h, a, b, c, d) +# define STEP_F(K) STEP (K, f, g, h, a, b, c, d, e) +# define STEP_G(K) STEP (K, g, h, a, b, c, d, e, f) +# define STEP_H(K) STEP (K, h, a, b, c, d, e, f, g) + + STEP_A (0) ; STEP_B (1) ; STEP_C (2) ; STEP_D (3) ; + STEP_E (4) ; STEP_F (5) ; STEP_G (6) ; STEP_H (7) ; + + STEP_A (8) ; STEP_B (9) ; STEP_C (10) ; STEP_D (11) ; + STEP_E (12) ; STEP_F (13) ; STEP_G (14) ; STEP_H (15) ; + + STEP_A (16) ; STEP_B (17) ; STEP_C (18) ; STEP_D (19) ; + STEP_E (20) ; STEP_F (21) ; STEP_G (22) ; STEP_H (23) ; + + STEP_A (24) ; STEP_B (25) ; STEP_C (26) ; STEP_D (27) ; + STEP_E (28) ; STEP_F (29) ; STEP_G (30) ; STEP_H (31) ; + + STEP_A (32) ; STEP_B (33) ; STEP_C (34) ; STEP_D (35) ; + STEP_E (36) ; STEP_F (37) ; STEP_G (38) ; STEP_H (39) ; + +# undef STEP_A +# undef STEP_B +# undef STEP_C +# undef STEP_D +# undef STEP_E +# undef STEP_F +# undef STEP_G +# undef STEP_H + + if (S0 > L_max) { L_max = S0 ; Nc = lambda ; } + if (S1 > L_max) { L_max = S1 ; Nc = lambda + 1 ; } + if (S2 > L_max) { L_max = S2 ; Nc = lambda + 2 ; } + if (S3 > L_max) { L_max = S3 ; Nc = lambda + 3 ; } + if (S4 > L_max) { L_max = S4 ; Nc = lambda + 4 ; } + if (S5 > L_max) { L_max = S5 ; Nc = lambda + 5 ; } + if (S6 > L_max) { L_max = S6 ; Nc = lambda + 6 ; } + if (S7 > L_max) { L_max = S7 ; Nc = lambda + 7 ; } + if (S8 > L_max) { L_max = S8 ; Nc = lambda + 8 ; } + } + *Nc_out = Nc ; + + L_max <<= 1 ; + + /* Rescaling of L_max + */ + assert (scal <= 100 && scal >= -100) ; + L_max = L_max >> (6 - scal) ; /* sub (6, scal) */ + + assert (Nc <= 120 && Nc >= 40) ; + + /* Compute the power of the reconstructed short term residual + * signal dp [..] + */ + L_power = 0 ; + for (k = 0 ; k <= 39 ; k++) + { register int32_t L_temp ; + + L_temp = SASR_W (dp [k - Nc], 3) ; + L_power += L_temp * L_temp ; + } + L_power <<= 1 ; /* from L_MULT */ + + /* Normalization of L_max and L_power + */ + + if (L_max <= 0) + { *bc_out = 0 ; + return ; + } + if (L_max >= L_power) + { *bc_out = 3 ; + return ; + } + + temp = gsm_norm (L_power) ; + + R = SASR_L (L_max << temp, 16) ; + S = SASR_L (L_power << temp, 16) ; + + /* Coding of the LTP gain + */ + + /* Table 4.3a must be used to obtain the level DLB [i] for the + * quantization of the LTP gain b to get the coded version bc. + */ + for (bc = 0 ; bc <= 2 ; bc++) if (R <= gsm_mult (S, gsm_DLB [bc])) break ; + *bc_out = bc ; +} + +#ifdef FAST +#ifdef LTP_CUT + +static void Cut_Fast_Calculation_of_the_LTP_parameters ( + struct gsm_state * st, /* IN */ + register int16_t * d, /* [0..39] IN */ + register int16_t * dp, /* [-120..-1] IN */ + int16_t * bc_out, /* OUT */ + int16_t * Nc_out /* OUT */) +{ + register int k, lambda ; + register float wt_float ; + int16_t Nc, bc ; + int16_t wt_max, best_k, ltp_cut ; + + float dp_float_base [120], * dp_float = dp_float_base + 120 ; + + register float L_result, L_max, L_power ; + + wt_max = 0 ; + + for (k = 0 ; k < 40 ; ++k) + { if (d [k] > wt_max) wt_max = d [best_k = k] ; + else if (-d [k] > wt_max) wt_max = -d [best_k = k] ; + } + + assert (wt_max >= 0) ; + wt_float = (float) wt_max ; + + for (k = -120 ; k < 0 ; ++k) dp_float [k] = (float) dp [k] ; + + /* Search for the maximum cross-correlation and coding of the LTP lag */ + L_max = 0 ; + Nc = 40 ; /* index for the maximum cross-correlation */ + + for (lambda = 40 ; lambda <= 120 ; lambda++) + { L_result = wt_float * dp_float [best_k - lambda] ; + if (L_result > L_max) + { Nc = lambda ; + L_max = L_result ; + } + } + + *Nc_out = Nc ; + if (L_max <= 0.) + { *bc_out = 0 ; + return ; + } + + /* Compute the power of the reconstructed short term residual + * signal dp [..] + */ + dp_float -= Nc ; + L_power = 0 ; + for (k = 0 ; k < 40 ; ++k) + { register float f = dp_float [k] ; + L_power += f * f ; + } + + if (L_max >= L_power) + { *bc_out = 3 ; + return ; + } + + /* Coding of the LTP gain + * Table 4.3a must be used to obtain the level DLB [i] for the + * quantization of the LTP gain b to get the coded version bc. + */ + lambda = L_max / L_power * 32768.0 ; + for (bc = 0 ; bc <= 2 ; ++bc) if (lambda <= gsm_DLB [bc]) break ; + *bc_out = bc ; +} + +#endif /* LTP_CUT */ + +static void Fast_Calculation_of_the_LTP_parameters ( + register int16_t * din, /* [0..39] IN */ + register int16_t * dp, /* [-120..-1] IN */ + int16_t * bc_out, /* OUT */ + int16_t * Nc_out /* OUT */) +{ + register int k, lambda ; + int16_t Nc, bc ; + + float wt_float [40] ; + float dp_float_base [120], * dp_float = dp_float_base + 120 ; + + register float L_max, L_power ; + + for (k = 0 ; k < 40 ; ++k) wt_float [k] = (float) din [k] ; + for (k = -120 ; k < 0 ; ++k) dp_float [k] = (float) dp [k] ; + + /* Search for the maximum cross-correlation and coding of the LTP lag */ + L_max = 0 ; + Nc = 40 ; /* index for the maximum cross-correlation */ + + for (lambda = 40 ; lambda <= 120 ; lambda += 9) + { /* Calculate L_result for l = lambda .. lambda + 9. */ + register float *lp = dp_float - lambda ; + + register float W ; + register float a = lp [-8], b = lp [-7], c = lp [-6], + d = lp [-5], e = lp [-4], f = lp [-3], + g = lp [-2], h = lp [-1] ; + register float E ; + register float S0 = 0, S1 = 0, S2 = 0, S3 = 0, S4 = 0, + S5 = 0, S6 = 0, S7 = 0, S8 = 0 ; + +# undef STEP +# define STEP(K, a, b, c, d, e, f, g, h) \ + W = wt_float [K] ; \ + E = W * a ; S8 += E ; \ + E = W * b ; S7 += E ; \ + E = W * c ; S6 += E ; \ + E = W * d ; S5 += E ; \ + E = W * e ; S4 += E ; \ + E = W * f ; S3 += E ; \ + E = W * g ; S2 += E ; \ + E = W * h ; S1 += E ; \ + a = lp [K] ; \ + E = W * a ; S0 += E + +# define STEP_A(K) STEP (K, a, b, c, d, e, f, g, h) +# define STEP_B(K) STEP (K, b, c, d, e, f, g, h, a) +# define STEP_C(K) STEP (K, c, d, e, f, g, h, a, b) +# define STEP_D(K) STEP (K, d, e, f, g, h, a, b, c) +# define STEP_E(K) STEP (K, e, f, g, h, a, b, c, d) +# define STEP_F(K) STEP (K, f, g, h, a, b, c, d, e) +# define STEP_G(K) STEP (K, g, h, a, b, c, d, e, f) +# define STEP_H(K) STEP (K, h, a, b, c, d, e, f, g) + + STEP_A (0) ; STEP_B (1) ; STEP_C (2) ; STEP_D (3) ; + STEP_E (4) ; STEP_F (5) ; STEP_G (6) ; STEP_H (7) ; + + STEP_A (8) ; STEP_B (9) ; STEP_C (10) ; STEP_D (11) ; + STEP_E (12) ; STEP_F (13) ; STEP_G (14) ; STEP_H (15) ; + + STEP_A (16) ; STEP_B (17) ; STEP_C (18) ; STEP_D (19) ; + STEP_E (20) ; STEP_F (21) ; STEP_G (22) ; STEP_H (23) ; + + STEP_A (24) ; STEP_B (25) ; STEP_C (26) ; STEP_D (27) ; + STEP_E (28) ; STEP_F (29) ; STEP_G (30) ; STEP_H (31) ; + + STEP_A (32) ; STEP_B (33) ; STEP_C (34) ; STEP_D (35) ; + STEP_E (36) ; STEP_F (37) ; STEP_G (38) ; STEP_H (39) ; + + if (S0 > L_max) { L_max = S0 ; Nc = lambda ; } + if (S1 > L_max) { L_max = S1 ; Nc = lambda + 1 ; } + if (S2 > L_max) { L_max = S2 ; Nc = lambda + 2 ; } + if (S3 > L_max) { L_max = S3 ; Nc = lambda + 3 ; } + if (S4 > L_max) { L_max = S4 ; Nc = lambda + 4 ; } + if (S5 > L_max) { L_max = S5 ; Nc = lambda + 5 ; } + if (S6 > L_max) { L_max = S6 ; Nc = lambda + 6 ; } + if (S7 > L_max) { L_max = S7 ; Nc = lambda + 7 ; } + if (S8 > L_max) { L_max = S8 ; Nc = lambda + 8 ; } + } + *Nc_out = Nc ; + + if (L_max <= 0.0) + { *bc_out = 0 ; + return ; + } + + /* Compute the power of the reconstructed short term residual + * signal dp [..] + */ + dp_float -= Nc ; + L_power = 0 ; + for (k = 0 ; k < 40 ; ++k) + { register float f = dp_float [k] ; + L_power += f * f ; + } + + if (L_max >= L_power) + { *bc_out = 3 ; + return ; + } + + /* Coding of the LTP gain + * Table 4.3a must be used to obtain the level DLB [i] for the + * quantization of the LTP gain b to get the coded version bc. + */ + lambda = L_max / L_power * 32768.0 ; + for (bc = 0 ; bc <= 2 ; ++bc) if (lambda <= gsm_DLB [bc]) break ; + *bc_out = bc ; +} + +#endif /* FAST */ +#endif /* USE_FLOAT_MUL */ + + +/* 4.2.12 */ + +static void Long_term_analysis_filtering ( + int16_t bc, /* IN */ + int16_t Nc, /* IN */ + register int16_t * dp, /* previous d [-120..-1] IN */ + register int16_t * d, /* d [0..39] IN */ + register int16_t * dpp, /* estimate [0..39] OUT */ + register int16_t * e /* long term res. signal [0..39] OUT */) +/* + * In this part, we have to decode the bc parameter to compute + * the samples of the estimate dpp [0..39]. The decoding of bc needs the + * use of table 4.3b. The long term residual signal e [0..39] + * is then calculated to be fed to the RPE encoding section. + */ +{ + register int k ; + +# undef STEP +# define STEP(BP) \ + for (k = 0 ; k <= 39 ; k++) \ + { dpp [k] = GSM_MULT_R (BP, dp [k - Nc]) ; \ + e [k] = GSM_SUB (d [k], dpp [k]) ; \ + } + + switch (bc) + { case 0: STEP (3277) ; break ; + case 1: STEP (11469) ; break ; + case 2: STEP (21299) ; break ; + case 3: STEP (32767) ; break ; + } +} + +void Gsm_Long_Term_Predictor ( /* 4x for 160 samples */ + + struct gsm_state * S, + + int16_t * d, /* [0..39] residual signal IN */ + int16_t * dp, /* [-120..-1] d' IN */ + + int16_t * e, /* [0..39] OUT */ + int16_t * dpp, /* [0..39] OUT */ + int16_t * Nc, /* correlation lag OUT */ + int16_t * bc /* gain factor OUT */) +{ + assert (d) ; assert (dp) ; assert (e) ; + assert (dpp) ; assert (Nc) ; assert (bc) ; + +#if defined (FAST) && defined (USE_FLOAT_MUL) + if (S->fast) +#if defined (LTP_CUT) + if (S->ltp_cut) + Cut_Fast_Calculation_of_the_LTP_parameters (S, + d, dp, bc, Nc) ; + else +#endif /* LTP_CUT */ + Fast_Calculation_of_the_LTP_parameters (d, dp, bc, Nc) ; + else +#endif /* FAST & USE_FLOAT_MUL */ +#ifdef LTP_CUT + if (S->ltp_cut) + Cut_Calculation_of_the_LTP_parameters (S, d, dp, bc, Nc) ; + else +#endif + Calculation_of_the_LTP_parameters (d, dp, bc, Nc) ; + + Long_term_analysis_filtering (*bc, *Nc, dp, d, dpp, e) ; +} + +/* 4.3.2 */ +void Gsm_Long_Term_Synthesis_Filtering ( + struct gsm_state * S, + + int16_t Ncr, + int16_t bcr, + register int16_t * erp, /* [0..39] IN */ + register int16_t * drp /* [-120..-1] IN, [-120..40] OUT */) +/* + * This procedure uses the bcr and Ncr parameter to realize the + * long term synthesis filtering. The decoding of bcr needs + * table 4.3b. + */ +{ + register int k ; + int16_t brp, drpp, Nr ; + + /* Check the limits of Nr. + */ + Nr = Ncr < 40 || Ncr > 120 ? S->nrp : Ncr ; + S->nrp = Nr ; + assert (Nr >= 40 && Nr <= 120) ; + + /* Decoding of the LTP gain bcr + */ + brp = gsm_QLB [bcr] ; + + /* Computation of the reconstructed short term residual + * signal drp [0..39] + */ + assert (brp != MIN_WORD) ; + + for (k = 0 ; k <= 39 ; k++) + { drpp = GSM_MULT_R (brp, drp [k - Nr]) ; + drp [k] = GSM_ADD (erp [k], drpp) ; + } + + /* + * Update of the reconstructed short term residual signal + * drp [-1..-120] + */ + + for (k = 0 ; k <= 119 ; k++) drp [-120 + k] = drp [-80 + k] ; +} diff --git a/extern/libsndfile-modified/src/GSM610/lpc.c b/extern/libsndfile-modified/src/GSM610/lpc.c new file mode 100644 index 000000000..922421e15 --- /dev/null +++ b/extern/libsndfile-modified/src/GSM610/lpc.c @@ -0,0 +1,333 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +#include +#include +#include + +#include "gsm610_priv.h" + +/* + * 4.2.4 .. 4.2.7 LPC ANALYSIS SECTION + */ + +/* 4.2.4 */ + + +static void Autocorrelation ( + int16_t * s, /* [0..159] IN/OUT */ + int32_t * L_ACF) /* [0..8] OUT */ +/* + * The goal is to compute the array L_ACF [k]. The signal s [i] must + * be scaled in order to avoid an overflow situation. + */ +{ + register int k, i ; + + int16_t temp, smax, scalauto ; + +#ifdef USE_FLOAT_MUL + float float_s [160] ; +#endif + + /* Dynamic scaling of the array s [0..159] */ + + /* Search for the maximum. */ + smax = 0 ; + for (k = 0 ; k <= 159 ; k++) + { temp = GSM_ABS (s [k]) ; + if (temp > smax) smax = temp ; + } + + /* Computation of the scaling factor. + */ + if (smax == 0) + scalauto = 0 ; + else + { assert (smax > 0) ; + scalauto = 4 - gsm_norm ((int32_t) smax << 16) ; /* sub (4,..) */ + } + + /* Scaling of the array s [0...159] + */ + + if (scalauto > 0) + { + +# ifdef USE_FLOAT_MUL +# define SCALE(n) \ + case n: for (k = 0 ; k <= 159 ; k++) \ + float_s [k] = (float) \ + (s [k] = GSM_MULT_R (s [k], 16384 >> (n-1))) ;\ + break ; +# else +# define SCALE(n) \ + case n: for (k = 0 ; k <= 159 ; k++) \ + s [k] = GSM_MULT_R (s [k], 16384 >> (n-1)) ;\ + break ; +# endif /* USE_FLOAT_MUL */ + + switch (scalauto) { + SCALE (1) + SCALE (2) + SCALE (3) + SCALE (4) + } +# undef SCALE + } +# ifdef USE_FLOAT_MUL + else for (k = 0 ; k <= 159 ; k++) float_s [k] = (float) s [k] ; +# endif + + /* Compute the L_ACF [..]. + */ + { +# ifdef USE_FLOAT_MUL + register float *sp = float_s ; + register float sl = *sp ; + +# define STEP(k) L_ACF [k] += (int32_t) (sl * sp [- (k)]) ; +# else + int16_t *sp = s ; + int16_t sl = *sp ; + +# define STEP(k) L_ACF [k] += ((int32_t) sl * sp [- (k)]) ; +# endif + +# define NEXTI sl = *++sp + + + for (k = 9 ; k-- ; L_ACF [k] = 0) ; + + STEP (0) ; + NEXTI ; + STEP (0) ; STEP (1) ; + NEXTI ; + STEP (0) ; STEP (1) ; STEP (2) ; + NEXTI ; + STEP (0) ; STEP (1) ; STEP (2) ; STEP (3) ; + NEXTI ; + STEP (0) ; STEP (1) ; STEP (2) ; STEP (3) ; STEP (4) ; + NEXTI ; + STEP (0) ; STEP (1) ; STEP (2) ; STEP (3) ; STEP (4) ; STEP (5) ; + NEXTI ; + STEP (0) ; STEP (1) ; STEP (2) ; STEP (3) ; STEP (4) ; STEP (5) ; STEP (6) ; + NEXTI ; + STEP (0) ; STEP (1) ; STEP (2) ; STEP (3) ; STEP (4) ; STEP (5) ; STEP (6) ; STEP (7) ; + + for (i = 8 ; i <= 159 ; i++) + { NEXTI ; + + STEP (0) ; + STEP (1) ; STEP (2) ; STEP (3) ; STEP (4) ; + STEP (5) ; STEP (6) ; STEP (7) ; STEP (8) ; + } + + for (k = 9 ; k-- ; ) + L_ACF [k] = SASL_L (L_ACF [k], 1) ; + + } + /* Rescaling of the array s [0..159] + */ + if (scalauto > 0) + { assert (scalauto <= 4) ; + for (k = 160 ; k-- ; s++) + *s = SASL_W (*s, scalauto) ; + } +} + +#if defined (USE_FLOAT_MUL) && defined (FAST) + +static void Fast_Autocorrelation ( + int16_t * s, /* [0..159] IN/OUT */ + int32_t * L_ACF) /* [0..8] OUT */ +{ + register int k, i ; + float f_L_ACF [9] ; + float scale ; + + float s_f [160] ; + register float *sf = s_f ; + + for (i = 0 ; i < 160 ; ++i) sf [i] = s [i] ; + for (k = 0 ; k <= 8 ; k++) + { register float L_temp2 = 0 ; + register float *sfl = sf - k ; + for (i = k ; i < 160 ; ++i) L_temp2 += sf [i] * sfl [i] ; + f_L_ACF [k] = L_temp2 ; + } + scale = 2147483648.0f / f_L_ACF [0] ; + + for (k = 0 ; k <= 8 ; k++) + L_ACF [k] = f_L_ACF [k] * scale ; +} +#endif /* defined (USE_FLOAT_MUL) && defined (FAST) */ + +/* 4.2.5 */ + +static void Reflection_coefficients ( + int32_t * L_ACF, /* 0...8 IN */ + register int16_t * r /* 0...7 OUT */ +) +{ + register int i, m, n ; + register int16_t temp ; + int16_t ACF [9] ; /* 0..8 */ + int16_t P [9] ; /* 0..8 */ + int16_t K [9] ; /* 2..8 */ + + /* Schur recursion with 16 bits arithmetic. + */ + + if (L_ACF [0] == 0) + { memset (r, 0, 8 * sizeof (r [0])) ; + return ; + } + + assert (L_ACF [0] != 0) ; + temp = gsm_norm (L_ACF [0]) ; + + assert (temp >= 0 && temp < 32) ; + + /* ? overflow ? */ + for (i = 0 ; i <= 8 ; i++) ACF [i] = SASR_L (SASL_L (L_ACF [i], temp), 16) ; + + /* Initialize array P [..] and K [..] for the recursion. + */ + + for (i = 1 ; i <= 7 ; i++) K [i] = ACF [i] ; + for (i = 0 ; i <= 8 ; i++) P [i] = ACF [i] ; + + /* Compute reflection coefficients + */ + for (n = 1 ; n <= 8 ; n++, r++) + { temp = P [1] ; + temp = GSM_ABS (temp) ; + if (P [0] < temp) + { for (i = n ; i <= 8 ; i++) *r++ = 0 ; + return ; + } + + *r = gsm_div (temp, P [0]) ; + + assert (*r >= 0) ; + if (P [1] > 0) *r = -*r ; /* r [n] = sub (0, r [n]) */ + assert (*r != MIN_WORD) ; + if (n == 8) return ; + + /* Schur recursion + */ + temp = GSM_MULT_R (P [1], *r) ; + P [0] = GSM_ADD (P [0], temp) ; + + for (m = 1 ; m <= 8 - n ; m++) + { temp = GSM_MULT_R (K [m], *r) ; + P [m] = GSM_ADD (P [m + 1], temp) ; + + temp = GSM_MULT_R (P [m + 1], *r) ; + K [m] = GSM_ADD (K [m], temp) ; + } + } +} + +/* 4.2.6 */ + +static void Transformation_to_Log_Area_Ratios ( + register int16_t * r /* 0..7 IN/OUT */ +) +/* + * The following scaling for r [..] and LAR [..] has been used: + * + * r [..] = integer (real_r [..]*32768.) ; -1 <= real_r < 1. + * LAR [..] = integer (real_LAR [..] * 16384) ; + * with -1.625 <= real_LAR <= 1.625 + */ +{ + register int16_t temp ; + register int i ; + + + /* Computation of the LAR [0..7] from the r [0..7] + */ + for (i = 1 ; i <= 8 ; i++, r++) + { temp = *r ; + temp = GSM_ABS (temp) ; + assert (temp >= 0) ; + + if (temp < 22118) + { temp >>= 1 ; + } + else if (temp < 31130) + { assert (temp >= 11059) ; + temp -= 11059 ; + } + else + { assert (temp >= 26112) ; + temp -= 26112 ; + temp <<= 2 ; + } + + *r = *r < 0 ? -temp : temp ; + assert (*r != MIN_WORD) ; + } +} + +/* 4.2.7 */ + +static void Quantization_and_coding ( + register int16_t * LAR /* [0..7] IN/OUT */ +) +{ + register int16_t temp ; + + /* This procedure needs four tables ; the following equations + * give the optimum scaling for the constants: + * + * A [0..7] = integer (real_A [0..7] * 1024) + * B [0..7] = integer (real_B [0..7] * 512) + * MAC [0..7] = maximum of the LARc [0..7] + * MIC [0..7] = minimum of the LARc [0..7] + */ + +# undef STEP +# define STEP(A, B, MAC, MIC) \ + temp = GSM_MULT (A, *LAR) ; \ + temp = GSM_ADD (temp, B) ; \ + temp = GSM_ADD (temp, 256) ; \ + temp = SASR_W (temp, 9) ; \ + *LAR = temp > MAC ? MAC - MIC : (temp < MIC ? 0 : temp - MIC) ; \ + LAR++ ; + + STEP (20480, 0, 31, -32) ; + STEP (20480, 0, 31, -32) ; + STEP (20480, 2048, 15, -16) ; + STEP (20480, -2560, 15, -16) ; + + STEP (13964, 94, 7, -8) ; + STEP (15360, -1792, 7, -8) ; + STEP (8534, -341, 3, -4) ; + STEP (9036, -1144, 3, -4) ; + +# undef STEP +} + +void Gsm_LPC_Analysis ( + struct gsm_state *S, + int16_t * s, /* 0..159 signals IN/OUT */ + int16_t *LARc) /* 0..7 LARc's OUT */ +{ + int32_t L_ACF [9] ; + +#if defined (USE_FLOAT_MUL) && defined (FAST) + if (S->fast) + Fast_Autocorrelation (s, L_ACF) ; + else +#endif + Autocorrelation (s, L_ACF ) ; + Reflection_coefficients (L_ACF, LARc ) ; + Transformation_to_Log_Area_Ratios (LARc) ; + Quantization_and_coding (LARc) ; +} diff --git a/extern/libsndfile-modified/src/GSM610/preprocess.c b/extern/libsndfile-modified/src/GSM610/preprocess.c new file mode 100644 index 000000000..82f4fe296 --- /dev/null +++ b/extern/libsndfile-modified/src/GSM610/preprocess.c @@ -0,0 +1,101 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +#include +#include + +#include "gsm610_priv.h" + +/* 4.2.0 .. 4.2.3 PREPROCESSING SECTION + * + * After A-law to linear conversion (or directly from the + * Ato D converter) the following scaling is assumed for + * input to the RPE-LTP algorithm: + * + * in: 0.1.....................12 + * S.v.v.v.v.v.v.v.v.v.v.v.v.*.*.* + * + * Where S is the sign bit, v a valid bit, and * a "don't care" bit. + * The original signal is called sop[..] + * + * out: 0.1................... 12 + * S.S.v.v.v.v.v.v.v.v.v.v.v.v.0.0 + */ + + +void Gsm_Preprocess ( + struct gsm_state * S, + int16_t * s, + int16_t * so) /* [0..159] IN/OUT */ +{ + + int16_t z1 = S->z1 ; + int32_t L_z2 = S->L_z2 ; + int16_t mp = S->mp ; + + int16_t s1 ; + int32_t L_s2 ; + + int32_t L_temp ; + + int16_t msp, lsp ; + int16_t SO ; + + register int k = 160 ; + + while (k--) + { + + /* 4.2.1 Downscaling of the input signal */ + SO = arith_shift_left (SASR_W (*s, 3), 2) ; + s++ ; + + assert (SO >= -0x4000) ; /* downscaled by */ + assert (SO <= 0x3FFC) ; /* previous routine. */ + + + /* 4.2.2 Offset compensation + * + * This part implements a high-pass filter and requires extended + * arithmetic precision for the recursive part of this filter. + * The input of this procedure is the array so[0...159] and the + * output the array sof[ 0...159 ]. + */ + + /* Compute the non-recursive part */ + + s1 = SO - z1 ; /* s1 = gsm_sub (*so, z1) ; */ + z1 = SO ; + + assert (s1 != MIN_WORD) ; + + /* Compute the recursive part */ + L_s2 = s1 ; + L_s2 = arith_shift_left (L_s2, 15) ; + + /* Execution of a 31 bv 16 bits multiplication */ + + msp = SASR_L (L_z2, 15) ; + lsp = L_z2 - arith_shift_left ((int32_t) msp, 15) ; /* gsm_L_sub (L_z2,(msp<<15)) ; */ + + L_s2 += GSM_MULT_R (lsp, 32735) ; + L_temp = (int32_t) msp * 32735 ; /* GSM_L_MULT (msp,32735) >> 1 ;*/ + L_z2 = GSM_L_ADD (L_temp, L_s2) ; + + /* Compute sof[k] with rounding */ + L_temp = GSM_L_ADD (L_z2, 16384) ; + + /* 4.2.3 Preemphasis */ + + msp = GSM_MULT_R (mp, -28180) ; + mp = SASR_L (L_temp, 15) ; + *so++ = GSM_ADD (mp, msp) ; + } + + S->z1 = z1 ; + S->L_z2 = L_z2 ; + S->mp = mp ; +} diff --git a/extern/libsndfile-modified/src/GSM610/rpe.c b/extern/libsndfile-modified/src/GSM610/rpe.c new file mode 100644 index 000000000..d9e90f29c --- /dev/null +++ b/extern/libsndfile-modified/src/GSM610/rpe.c @@ -0,0 +1,460 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +#include +#include + +#include "gsm610_priv.h" + +/* 4.2.13 .. 4.2.17 RPE ENCODING SECTION + */ + +/* 4.2.13 */ + +static void Weighting_filter ( + register int16_t * e, /* signal [-5..0.39.44] IN */ + int16_t * x /* signal [0..39] OUT */ +) +/* + * The coefficients of the weighting filter are stored in a table + * (see table 4.4). The following scaling is used: + * + * H[0..10] = integer(real_H [0..10] * 8192) ; + */ +{ + /* int16_t wt [50] ; */ + + register int32_t L_result ; + register int k /* , i */ ; + + /* Initialization of a temporary working array wt[0...49] + */ + + /* for (k = 0 ; k <= 4 ; k++) wt[k] = 0 ; + * for (k = 5 ; k <= 44 ; k++) wt[k] = *e++; + * for (k = 45 ; k <= 49 ; k++) wt[k] = 0 ; + * + * (e[-5..-1] and e[40..44] are allocated by the caller, + * are initially zero and are not written anywhere.) + */ + e -= 5 ; + + /* Compute the signal x[0..39] + */ + for (k = 0 ; k <= 39 ; k++) + { L_result = 8192 >> 1 ; + + /* for (i = 0 ; i <= 10 ; i++) { + * L_temp = GSM_L_MULT(wt[k+i], gsm_H[i]) ; + * L_result = GSM_L_ADD(L_result, L_temp) ; + * } + */ + +#undef STEP +#define STEP(i, H) (e [k + i] * (int32_t) H) + + /* Every one of these multiplications is done twice -- + * but I don't see an elegant way to optimize this. + * Do you? + */ + +#ifdef STUPID_COMPILER + L_result += STEP (0, -134) ; + L_result += STEP (1, -374) ; + /* + STEP (2, 0) */ + L_result += STEP (3, 2054) ; + L_result += STEP (4, 5741) ; + L_result += STEP (5, 8192) ; + L_result += STEP (6, 5741) ; + L_result += STEP (7, 2054) ; + /* + STEP (8, 0) */ + L_result += STEP (9, -374) ; + L_result += STEP (10, -134) ; +#else + L_result += STEP (0, -134) + + STEP (1, -374) + /* + STEP (2, 0) */ + + STEP (3, 2054) + + STEP (4, 5741) + + STEP (5, 8192) + + STEP (6, 5741) + + STEP (7, 2054) + /* + STEP (8, 0) */ + + STEP (9, -374) + + STEP (10, -134) ; +#endif + + /* L_result = GSM_L_ADD(L_result, L_result) ; (* scaling(x2) *) + * L_result = GSM_L_ADD(L_result, L_result) ; (* scaling(x4) *) + * + * x[k] = SASR(L_result, 16) ; + */ + + /* 2 adds vs. >>16 => 14, minus one shift to compensate for + * those we lost when replacing L_MULT by '*'. + */ + + L_result = SASR_L (L_result, 13) ; + x [k] = (L_result < MIN_WORD ? MIN_WORD + : (L_result > MAX_WORD ? MAX_WORD : L_result)) ; + } +} + +/* 4.2.14 */ + +static void RPE_grid_selection ( + int16_t * x, /* [0..39] IN */ + int16_t * xM, /* [0..12] OUT */ + int16_t * Mc_out /* OUT */ +) +/* + * The signal x[0..39] is used to select the RPE grid which is + * represented by Mc. + */ +{ + register int i ; + register int32_t L_result, L_temp ; + int32_t EM ; /* xxx should be L_EM? */ + int16_t Mc ; + + int32_t L_common_0_3 ; + + EM = 0 ; + Mc = 0 ; + + /* for (m = 0 ; m <= 3 ; m++) { + * L_result = 0 ; + * + * + * for (i = 0 ; i <= 12 ; i++) { + * + * temp1 = SASR_W (x[m + 3*i], 2) ; + * + * assert (temp1 != MIN_WORD) ; + * + * L_temp = GSM_L_MULT(temp1, temp1) ; + * L_result = GSM_L_ADD(L_temp, L_result) ; + * } + * + * if (L_result > EM) { + * Mc = m ; + * EM = L_result ; + * } + * } + */ + +#undef STEP +#define STEP(m, i) L_temp = SASR_W (x [m + 3 * i], 2) ; \ + L_result += L_temp * L_temp ; + + /* common part of 0 and 3 */ + + L_result = 0 ; + STEP (0, 1) ; STEP (0, 2) ; STEP (0, 3) ; STEP (0, 4) ; + STEP (0, 5) ; STEP (0, 6) ; STEP (0, 7) ; STEP (0, 8) ; + STEP (0, 9) ; STEP (0, 10) ; STEP (0, 11) ; STEP (0, 12) ; + L_common_0_3 = L_result ; + + /* i = 0 */ + + STEP (0, 0) ; + L_result <<= 1 ; /* implicit in L_MULT */ + EM = L_result ; + + /* i = 1 */ + + L_result = 0 ; + STEP (1, 0) ; + STEP (1, 1) ; STEP (1, 2) ; STEP (1, 3) ; STEP (1, 4) ; + STEP (1, 5) ; STEP (1, 6) ; STEP (1, 7) ; STEP (1, 8) ; + STEP (1, 9) ; STEP (1, 10) ; STEP (1, 11) ; STEP (1, 12) ; + L_result <<= 1 ; + if (L_result > EM) + { Mc = 1 ; + EM = L_result ; + } + + /* i = 2 */ + + L_result = 0 ; + STEP (2, 0) ; + STEP (2, 1) ; STEP (2, 2) ; STEP (2, 3) ; STEP (2, 4) ; + STEP (2, 5) ; STEP (2, 6) ; STEP (2, 7) ; STEP (2, 8) ; + STEP (2, 9) ; STEP (2, 10) ; STEP (2, 11) ; STEP (2, 12) ; + L_result <<= 1 ; + if (L_result > EM) + { Mc = 2 ; + EM = L_result ; + } + + /* i = 3 */ + + L_result = L_common_0_3 ; + STEP (3, 12) ; + L_result <<= 1 ; + if (L_result > EM) + { Mc = 3 ; + EM = L_result ; + } + + /* Down-sampling by a factor 3 to get the selected xM [0..12] + * RPE sequence. + */ + for (i = 0 ; i <= 12 ; i ++) xM [i] = x [Mc + 3 * i] ; + *Mc_out = Mc ; +} + +/* 4.12.15 */ + +static void APCM_quantization_xmaxc_to_exp_mant ( + int16_t xmaxc, /* IN */ + int16_t * expon_out, /* OUT */ + int16_t * mant_out) /* OUT */ +{ + int16_t expon, mant ; + + /* Compute expononent and mantissa of the decoded version of xmaxc + */ + + expon = 0 ; + if (xmaxc > 15) expon = SASR_W (xmaxc, 3) - 1 ; + mant = xmaxc - (expon << 3) ; + + if (mant == 0) + { expon = -4 ; + mant = 7 ; + } + else + { while (mant <= 7) + { mant = mant << 1 | 1 ; + expon-- ; + } + mant -= 8 ; + } + + assert (expon >= -4 && expon <= 6) ; + assert (mant >= 0 && mant <= 7) ; + + *expon_out = expon ; + *mant_out = mant ; +} + +static void APCM_quantization ( + int16_t * xM, /* [0..12] IN */ + int16_t * xMc, /* [0..12] OUT */ + int16_t * mant_out, /* OUT */ + int16_t * expon_out, /* OUT */ + int16_t * xmaxc_out /* OUT */ +) +{ + int i, itest ; + + int16_t xmax, xmaxc, temp, temp1, temp2 ; + int16_t expon, mant ; + + + /* Find the maximum absolute value xmax of xM [0..12]. + */ + + xmax = 0 ; + for (i = 0 ; i <= 12 ; i++) + { temp = xM [i] ; + temp = GSM_ABS (temp) ; + if (temp > xmax) xmax = temp ; + } + + /* Qantizing and coding of xmax to get xmaxc. + */ + + expon = 0 ; + temp = SASR_W (xmax, 9) ; + itest = 0 ; + + for (i = 0 ; i <= 5 ; i++) + { itest |= (temp <= 0) ; + temp = SASR_W (temp, 1) ; + + assert (expon <= 5) ; + if (itest == 0) expon++ ; /* expon = add (expon, 1) */ + } + + assert (expon <= 6 && expon >= 0) ; + temp = expon + 5 ; + + assert (temp <= 11 && temp >= 0) ; + xmaxc = gsm_add (SASR_W (xmax, temp), (int16_t) (expon << 3)) ; + + /* Quantizing and coding of the xM [0..12] RPE sequence + * to get the xMc [0..12] + */ + + APCM_quantization_xmaxc_to_exp_mant (xmaxc, &expon, &mant) ; + + /* This computation uses the fact that the decoded version of xmaxc + * can be calculated by using the expononent and the mantissa part of + * xmaxc (logarithmic table). + * So, this method avoids any division and uses only a scaling + * of the RPE samples by a function of the expononent. A direct + * multiplication by the inverse of the mantissa (NRFAC[0..7] + * found in table 4.5) gives the 3 bit coded version xMc [0..12] + * of the RPE samples. + */ + + + /* Direct computation of xMc [0..12] using table 4.5 + */ + + assert (expon <= 4096 && expon >= -4096) ; + assert (mant >= 0 && mant <= 7) ; + + temp1 = 6 - expon ; /* normalization by the expononent */ + temp2 = gsm_NRFAC [mant] ; /* inverse mantissa */ + + for (i = 0 ; i <= 12 ; i++) + { assert (temp1 >= 0 && temp1 < 16) ; + + temp = arith_shift_left (xM [i], temp1) ; + temp = GSM_MULT (temp, temp2) ; + temp = SASR_W (temp, 12) ; + xMc [i] = temp + 4 ; /* see note below */ + } + + /* NOTE: This equation is used to make all the xMc [i] positive. + */ + + *mant_out = mant ; + *expon_out = expon ; + *xmaxc_out = xmaxc ; +} + +/* 4.2.16 */ + +static void APCM_inverse_quantization ( + register int16_t * xMc, /* [0..12] IN */ + int16_t mant, + int16_t expon, + register int16_t * xMp) /* [0..12] OUT */ +/* + * This part is for decoding the RPE sequence of coded xMc [0..12] + * samples to obtain the xMp[0..12] array. Table 4.6 is used to get + * the mantissa of xmaxc (FAC[0..7]). + */ +{ + int i ; + int16_t temp, temp1, temp2, temp3 ; + + assert (mant >= 0 && mant <= 7) ; + + temp1 = gsm_FAC [mant] ; /* see 4.2-15 for mant */ + temp2 = gsm_sub (6, expon) ; /* see 4.2-15 for exp */ + temp3 = gsm_asl (1, gsm_sub (temp2, 1)) ; + + for (i = 13 ; i-- ;) + { assert (*xMc <= 7 && *xMc >= 0) ; /* 3 bit unsigned */ + + /* temp = gsm_sub (*xMc++ << 1, 7) ; */ + temp = (*xMc++ << 1) - 7 ; /* restore sign */ + assert (temp <= 7 && temp >= -7) ; /* 4 bit signed */ + + temp = arith_shift_left (temp, 12) ; /* 16 bit signed */ + temp = GSM_MULT_R (temp1, temp) ; + temp = GSM_ADD (temp, temp3) ; + *xMp++ = gsm_asr (temp, temp2) ; + } +} + +/* 4.2.17 */ + +static void RPE_grid_positioning ( + int16_t Mc, /* grid position IN */ + register int16_t * xMp, /* [0..12] IN */ + register int16_t * ep /* [0..39] OUT */ +) +/* + * This procedure computes the reconstructed long term residual signal + * ep[0..39] for the LTP analysis filter. The inputs are the Mc + * which is the grid position selection and the xMp[0..12] decoded + * RPE samples which are upsampled by a factor of 3 by inserting zero + * values. + */ +{ + int i = 13 ; + + assert (0 <= Mc && Mc <= 3) ; + + switch (Mc) + { case 3: *ep++ = 0 ; + /* Falls through. */ + case 2: do + { *ep++ = 0 ; + /* Falls through. */ + case 1: *ep++ = 0 ; + /* Falls through. */ + case 0: *ep++ = *xMp++ ; + } while (--i) ; + } + while (++Mc < 4) *ep++ = 0 ; +} + +/* 4.2.18 */ + +/* This procedure adds the reconstructed long term residual signal + * ep[0..39] to the estimated signal dpp[0..39] from the long term + * analysis filter to compute the reconstructed short term residual + * signal dp[-40..-1] ; also the reconstructed short term residual + * array dp[-120..-41] is updated. + */ + +#if 0 /* Has been inlined in code.c */ +void Gsm_Update_of_reconstructed_short_time_residual_signal ( + int16_t * dpp, /* [0...39] IN */ + int16_t * ep, /* [0...39] IN */ + int16_t * dp) /* [-120...-1] IN/OUT */ +{ + int k ; + + for (k = 0 ; k <= 79 ; k++) + dp [-120 + k] = dp [-80 + k] ; + + for (k = 0 ; k <= 39 ; k++) + dp [-40 + k] = gsm_add (ep [k], dpp [k]) ; +} +#endif /* Has been inlined in code.c */ + +void Gsm_RPE_Encoding ( + int16_t * e, /* -5..-1][0..39][40..44 IN/OUT */ + int16_t * xmaxc, /* OUT */ + int16_t * Mc, /* OUT */ + int16_t * xMc) /* [0..12] OUT */ +{ + int16_t x [40] ; + int16_t xM [13], xMp [13] ; + int16_t mant, expon ; + + Weighting_filter (e, x) ; + RPE_grid_selection (x, xM, Mc) ; + + APCM_quantization (xM, xMc, &mant, &expon, xmaxc) ; + APCM_inverse_quantization (xMc, mant, expon, xMp) ; + + RPE_grid_positioning (*Mc, xMp, e) ; + +} + +void Gsm_RPE_Decoding ( + int16_t xmaxcr, + int16_t Mcr, + int16_t * xMcr, /* [0..12], 3 bits IN */ + int16_t * erp /* [0..39] OUT */ +) +{ + int16_t expon, mant ; + int16_t xMp [13] ; + + APCM_quantization_xmaxc_to_exp_mant (xmaxcr, &expon, &mant) ; + APCM_inverse_quantization (xMcr, mant, expon, xMp) ; + RPE_grid_positioning (Mcr, xMp, erp) ; +} diff --git a/extern/libsndfile-modified/src/GSM610/short_term.c b/extern/libsndfile-modified/src/GSM610/short_term.c new file mode 100644 index 000000000..e8cdac3b8 --- /dev/null +++ b/extern/libsndfile-modified/src/GSM610/short_term.c @@ -0,0 +1,412 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +#include +#include + +#include "gsm610_priv.h" + +/* + * SHORT TERM ANALYSIS FILTERING SECTION + */ + +/* 4.2.8 */ + +static void Decoding_of_the_coded_Log_Area_Ratios ( + int16_t * LARc, /* coded log area ratio [0..7] IN */ + int16_t * LARpp) /* out: decoded .. */ +{ + register int16_t temp1 ; + + /* This procedure requires for efficient implementation + * two tables. + * + * INVA[1..8] = integer((32768 * 8) / real_A[1..8]) + * MIC[1..8] = minimum value of the LARc[1..8] + */ + + /* Compute the LARpp[1..8] + */ + + /* for (i = 1; i <= 8; i++, B++, MIC++, INVA++, LARc++, LARpp++) { + * + * temp1 = GSM_ADD (*LARc, *MIC) << 10; + * temp2 = *B << 1; + * temp1 = GSM_SUB(temp1, temp2) ; + * + * assert(*INVA != MIN_WORD) ; + * + * temp1 = GSM_MULT_R (*INVA, temp1) ; + * *LARpp = GSM_ADD (temp1, temp1) ; + * } + */ + +#undef STEP +#define STEP(B, MIC, INVA) \ + temp1 = arith_shift_left (GSM_ADD (*LARc++, MIC), 10) ; \ + temp1 = GSM_SUB (temp1, B * 2) ; \ + temp1 = GSM_MULT_R (INVA, temp1) ; \ + *LARpp++ = GSM_ADD (temp1, temp1) ; + + STEP (0, -32, 13107) ; + STEP (0, -32, 13107) ; + STEP (2048, -16, 13107) ; + STEP (-2560, -16, 13107) ; + + STEP (94, -8, 19223) ; + STEP (-1792, -8, 17476) ; + STEP (-341, -4, 31454) ; + STEP (-1144, -4, 29708) ; + + /* NOTE: the addition of *MIC is used to restore + * the sign of *LARc. + */ +} + +/* 4.2.9 */ +/* Computation of the quantized reflection coefficients + */ + +/* 4.2.9.1 Interpolation of the LARpp[1..8] to get the LARp[1..8] + */ + +/* + * Within each frame of 160 analyzed speech samples the short term + * analysis and synthesis filters operate with four different sets of + * coefficients, derived from the previous set of decoded LARs(LARpp(j-1)) + * and the actual set of decoded LARs (LARpp(j)) + * + * (Initial value: LARpp(j-1)[1..8] = 0.) + */ + +static void Coefficients_0_12 ( + register int16_t * LARpp_j_1, + register int16_t * LARpp_j, + register int16_t * LARp) +{ + register int i ; + + for (i = 1 ; i <= 8 ; i++, LARp++, LARpp_j_1++, LARpp_j++) + { *LARp = GSM_ADD (SASR_W (*LARpp_j_1, 2), SASR_W (*LARpp_j, 2)) ; + *LARp = GSM_ADD (*LARp, SASR_W (*LARpp_j_1, 1)) ; + } +} + +static void Coefficients_13_26 ( + register int16_t * LARpp_j_1, + register int16_t * LARpp_j, + register int16_t * LARp) +{ + register int i ; + for (i = 1 ; i <= 8 ; i++, LARpp_j_1++, LARpp_j++, LARp++) + *LARp = GSM_ADD (SASR_W (*LARpp_j_1, 1), SASR_W (*LARpp_j, 1)) ; +} + +static void Coefficients_27_39 ( + register int16_t * LARpp_j_1, + register int16_t * LARpp_j, + register int16_t * LARp) +{ + register int i ; + + for (i = 1 ; i <= 8 ; i++, LARpp_j_1++, LARpp_j++, LARp++) + { *LARp = GSM_ADD (SASR_W (*LARpp_j_1, 2), SASR_W (*LARpp_j, 2)) ; + *LARp = GSM_ADD (*LARp, SASR_W (*LARpp_j, 1)) ; + } +} + + +static void Coefficients_40_159 ( + register int16_t * LARpp_j, + register int16_t * LARp) +{ + register int i ; + + for (i = 1 ; i <= 8 ; i++, LARp++, LARpp_j++) + *LARp = *LARpp_j ; +} + +/* 4.2.9.2 */ + +static void LARp_to_rp ( + register int16_t * LARp) /* [0..7] IN/OUT */ +/* + * The input of this procedure is the interpolated LARp[0..7] array. + * The reflection coefficients, rp[i], are used in the analysis + * filter and in the synthesis filter. + */ +{ + register int i ; + register int16_t temp ; + + for (i = 1 ; i <= 8 ; i++, LARp++) + { /* temp = GSM_ABS(*LARp) ; + * + * if (temp < 11059) temp <<= 1; + * else if (temp < 20070) temp += 11059; + * else temp = GSM_ADD (temp >> 2, 26112) ; + * + * *LARp = *LARp < 0 ? -temp : temp; + */ + + if (*LARp < 0) + { temp = *LARp == MIN_WORD ? MAX_WORD : - (*LARp) ; + *LARp = - ((temp < 11059) ? temp << 1 + : ((temp < 20070) ? temp + 11059 + : GSM_ADD ((int16_t) (temp >> 2), (int16_t) 26112))) ; + } + else + { temp = *LARp ; + *LARp = (temp < 11059) ? temp << 1 + : ((temp < 20070) ? temp + 11059 + : GSM_ADD ((int16_t) (temp >> 2), (int16_t) 26112)) ; + } + } +} + + +/* 4.2.10 */ +static void Short_term_analysis_filtering ( + struct gsm_state * S, + register int16_t * rp, /* [0..7] IN */ + register int k_n, /* k_end - k_start */ + register int16_t * s /* [0..n-1] IN/OUT */ +) +/* + * This procedure computes the short term residual signal d[..] to be fed + * to the RPE-LTP loop from the s[..] signal and from the local rp[..] + * array (quantized reflection coefficients). As the call of this + * procedure can be done in many ways (see the interpolation of the LAR + * coefficient), it is assumed that the computation begins with index + * k_start (for arrays d[..] and s[..]) and stops with index k_end + * (k_start and k_end are defined in 4.2.9.1). This procedure also + * needs to keep the array u [0..7] in memory for each call. + */ +{ + register int16_t * u = S->u ; + register int i ; + register int16_t di, zzz, ui, sav, rpi ; + + for ( ; k_n-- ; s++) + { di = sav = *s ; + + for (i = 0 ; i < 8 ; i++) + { /* YYY */ + ui = u [i] ; + rpi = rp [i] ; + u [i] = sav ; + + zzz = GSM_MULT_R (rpi, di) ; + sav = GSM_ADD (ui, zzz) ; + + zzz = GSM_MULT_R (rpi, ui) ; + di = GSM_ADD (di, zzz) ; + } + + *s = di ; + } +} + +#if defined (USE_FLOAT_MUL) && defined (FAST) + +static void Fast_Short_term_analysis_filtering ( + struct gsm_state * S, + register int16_t * rp, /* [0..7] IN */ + register int k_n, /* k_end - k_start */ + register int16_t * s /* [0..n-1] IN/OUT */ +) +{ + register int16_t * u = S->u ; + register int i ; + + float uf [8], rpf [8] ; + + register float scalef = 3.0517578125e-5 ; + register float sav, di, temp ; + + for (i = 0 ; i < 8 ; ++i) + { uf [i] = u [i] ; + rpf [i] = rp [i] * scalef ; + } + for ( ; k_n-- ; s++) + { sav = di = *s ; + for (i = 0 ; i < 8 ; i++) + { register float rpfi = rpf [i] ; + register float ufi = uf [i] ; + + uf [i] = sav ; + temp = rpfi * di + ufi ; + di += rpfi * ufi ; + sav = temp ; + } + *s = di ; + } + for (i = 0 ; i < 8 ; i++) u [i] = uf [i] ; +} +#endif /* ! (defined (USE_FLOAT_MUL) && defined (FAST)) */ + +static void Short_term_synthesis_filtering ( + struct gsm_state * S, + register int16_t * rrp, /* [0..7] IN */ + register int k, /* k_end - k_start */ + register int16_t * wt, /* [0..k-1] IN */ + register int16_t * sr /* [0..k-1] OUT */ +) +{ + register int16_t * v = S->v ; + register int i ; + register int16_t sri, tmp1, tmp2 ; + + while (k--) + { sri = *wt++ ; + for (i = 8 ; i-- ; ) + { /* sri = GSM_SUB(sri, gsm_mult_r(rrp[i], v [i])) ; + */ + tmp1 = rrp [i] ; + tmp2 = v [i] ; + tmp2 = (tmp1 == MIN_WORD && tmp2 == MIN_WORD + ? MAX_WORD + : 0x0FFFF & (((int32_t) tmp1 * (int32_t) tmp2 + + 16384) >> 15)) ; + + sri = GSM_SUB (sri, tmp2) ; + + /* v [i+1] = GSM_ADD (v [i], gsm_mult_r(rrp[i], sri)) ; + */ + tmp1 = (tmp1 == MIN_WORD && sri == MIN_WORD + ? MAX_WORD + : 0x0FFFF & (((int32_t) tmp1 * (int32_t) sri + + 16384) >> 15)) ; + + v [i + 1] = GSM_ADD (v [i], tmp1) ; + } + *sr++ = v [0] = sri ; + } +} + + +#if defined (FAST) && defined (USE_FLOAT_MUL) + +static void Fast_Short_term_synthesis_filtering ( + struct gsm_state * S, + register int16_t * rrp, /* [0..7] IN */ + register int k, /* k_end - k_start */ + register int16_t * wt, /* [0..k-1] IN */ + register int16_t * sr /* [0..k-1] OUT */ +) +{ + register int16_t * v = S->v ; + register int i ; + + float va [9], rrpa [8] ; + register float scalef = 3.0517578125e-5, temp ; + + for (i = 0 ; i < 8 ; ++i) + { va [i] = v [i] ; + rrpa [i] = (float) rrp [i] * scalef ; + } + while (k--) { + register float sri = *wt++ ; + for (i = 8 ; i-- ; ) + { sri -= rrpa [i] * va [i] ; + if (sri < -32768.0) sri = -32768.0 ; + else if (sri > 32767.0) sri = 32767.0 ; + + temp = va [i] + rrpa [i] * sri ; + if (temp < -32768.0) temp = -32768.0 ; + else if (temp > 32767.0) temp = 32767.0 ; + va [i+1] = temp ; + } + *sr++ = va [0] = sri ; + } + for (i = 0 ; i < 9 ; ++i) v [i] = va [i] ; +} + +#endif /* defined(FAST) && defined(USE_FLOAT_MUL) */ + +void Gsm_Short_Term_Analysis_Filter ( + struct gsm_state * S, + + int16_t * LARc, /* coded log area ratio [0..7] IN */ + int16_t * s /* signal [0..159] IN/OUT */ +) +{ + int16_t * LARpp_j = S->LARpp [S->j] ; + int16_t * LARpp_j_1 = S->LARpp [S->j ^= 1] ; + + int16_t LARp [8] ; + +#undef FILTER +#if defined (FAST) && defined (USE_FLOAT_MUL) +# define FILTER (* (S->fast \ + ? Fast_Short_term_analysis_filtering \ + : Short_term_analysis_filtering)) + +#else +# define FILTER Short_term_analysis_filtering +#endif + + Decoding_of_the_coded_Log_Area_Ratios (LARc, LARpp_j) ; + + Coefficients_0_12 (LARpp_j_1, LARpp_j, LARp) ; + LARp_to_rp (LARp) ; + FILTER (S, LARp, 13, s) ; + + Coefficients_13_26 (LARpp_j_1, LARpp_j, LARp) ; + LARp_to_rp (LARp) ; + FILTER (S, LARp, 14, s + 13) ; + + Coefficients_27_39 (LARpp_j_1, LARpp_j, LARp) ; + LARp_to_rp (LARp) ; + FILTER (S, LARp, 13, s + 27) ; + + Coefficients_40_159 (LARpp_j, LARp) ; + LARp_to_rp (LARp) ; + FILTER (S, LARp, 120, s + 40) ; +} + +void Gsm_Short_Term_Synthesis_Filter ( + struct gsm_state * S, + + int16_t * LARcr, /* received log area ratios [0..7] IN */ + int16_t * wt, /* received d [0..159] IN */ + + int16_t * s /* signal s [0..159] OUT */ +) +{ + int16_t * LARpp_j = S->LARpp [S->j] ; + int16_t * LARpp_j_1 = S->LARpp [S->j ^= 1] ; + + int16_t LARp [8] ; + +#undef FILTER +#if defined (FAST) && defined (USE_FLOAT_MUL) + +# define FILTER (* (S->fast \ + ? Fast_Short_term_synthesis_filtering \ + : Short_term_synthesis_filtering)) +#else +# define FILTER Short_term_synthesis_filtering +#endif + + Decoding_of_the_coded_Log_Area_Ratios (LARcr, LARpp_j) ; + + Coefficients_0_12 (LARpp_j_1, LARpp_j, LARp) ; + LARp_to_rp (LARp) ; + FILTER (S, LARp, 13, wt, s) ; + + Coefficients_13_26 (LARpp_j_1, LARpp_j, LARp) ; + LARp_to_rp (LARp) ; + FILTER (S, LARp, 14, wt + 13, s + 13) ; + + Coefficients_27_39 (LARpp_j_1, LARpp_j, LARp) ; + LARp_to_rp (LARp) ; + FILTER (S, LARp, 13, wt + 27, s + 27) ; + + Coefficients_40_159 (LARpp_j, LARp) ; + LARp_to_rp (LARp) ; + FILTER (S, LARp, 120, wt + 40, s + 40) ; +} diff --git a/extern/libsndfile-modified/src/GSM610/table.c b/extern/libsndfile-modified/src/GSM610/table.c new file mode 100644 index 000000000..30590aff3 --- /dev/null +++ b/extern/libsndfile-modified/src/GSM610/table.c @@ -0,0 +1,60 @@ +/* + * Copyright 1992 by Jutta Degener and Carsten Bormann, Technische + * Universitaet Berlin. See the accompanying file "COPYRIGHT" for + * details. THERE IS ABSOLUTELY NO WARRANTY FOR THIS SOFTWARE. + */ + +/* Most of these tables are inlined at their point of use. + */ + +/* 4.4 TABLES USED IN THE FIXED POINT IMPLEMENTATION OF THE RPE-LTP + * CODER AND DECODER + * + * (Most of them inlined, so watch out.) + */ + +#define GSM_TABLE_C +#include "gsm610_priv.h" + +/* Table 4.1 Quantization of the Log.-Area Ratios + */ +/* i 1 2 3 4 5 6 7 8 */ +int16_t gsm_A [8] = { 20480, 20480, 20480, 20480, 13964, 15360, 8534, 9036 } ; +int16_t gsm_B [8] = { 0, 0, 2048, -2560, 94, -1792, -341, -1144 } ; +int16_t gsm_MIC [8] = { -32, -32, -16, -16, -8, -8, -4, -4 } ; +int16_t gsm_MAC [8] = { 31, 31, 15, 15, 7, 7, 3, 3 } ; + + +/* Table 4.2 Tabulation of 1/A[1..8] + */ +int16_t gsm_INVA [8] = { 13107, 13107, 13107, 13107, 19223, 17476, 31454, 29708 } ; + + +/* Table 4.3a Decision level of the LTP gain quantizer + */ +/* bc 0 1 2 3 */ +int16_t gsm_DLB [4] = { 6554, 16384, 26214, 32767 } ; + + +/* Table 4.3b Quantization levels of the LTP gain quantizer + */ +/* bc 0 1 2 3 */ +int16_t gsm_QLB [4] = { 3277, 11469, 21299, 32767 } ; + + +/* Table 4.4 Coefficients of the weighting filter + */ +/* i 0 1 2 3 4 5 6 7 8 9 10 */ +int16_t gsm_H [11] = { -134, -374, 0, 2054, 5741, 8192, 5741, 2054, 0, -374, -134 } ; + + +/* Table 4.5 Normalized inverse mantissa used to compute xM/xmax + */ +/* i 0 1 2 3 4 5 6 7 */ +int16_t gsm_NRFAC [8] = { 29128, 26215, 23832, 21846, 20165, 18725, 17476, 16384 } ; + + +/* Table 4.6 Normalized direct mantissa used to compute xM/xmax + */ +/* i 0 1 2 3 4 5 6 7 */ +int16_t gsm_FAC [8] = { 18431, 20479, 22527, 24575, 26623, 28671, 30719, 32767 } ; diff --git a/extern/libsndfile-modified/src/aiff.c b/extern/libsndfile-modified/src/aiff.c new file mode 100644 index 000000000..a2bda8f4f --- /dev/null +++ b/extern/libsndfile-modified/src/aiff.c @@ -0,0 +1,1851 @@ +/* +** Copyright (C) 1999-2018 Erik de Castro Lopo +** Copyright (C) 2005 David Viens +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" +#include "chanmap.h" + +/*------------------------------------------------------------------------------ + * Macros to handle big/little endian issues. + */ + +#define FORM_MARKER (MAKE_MARKER ('F', 'O', 'R', 'M')) +#define AIFF_MARKER (MAKE_MARKER ('A', 'I', 'F', 'F')) +#define AIFC_MARKER (MAKE_MARKER ('A', 'I', 'F', 'C')) +#define COMM_MARKER (MAKE_MARKER ('C', 'O', 'M', 'M')) +#define SSND_MARKER (MAKE_MARKER ('S', 'S', 'N', 'D')) +#define MARK_MARKER (MAKE_MARKER ('M', 'A', 'R', 'K')) +#define INST_MARKER (MAKE_MARKER ('I', 'N', 'S', 'T')) +#define APPL_MARKER (MAKE_MARKER ('A', 'P', 'P', 'L')) +#define CHAN_MARKER (MAKE_MARKER ('C', 'H', 'A', 'N')) + +#define c_MARKER (MAKE_MARKER ('(', 'c', ')', ' ')) +#define NAME_MARKER (MAKE_MARKER ('N', 'A', 'M', 'E')) +#define AUTH_MARKER (MAKE_MARKER ('A', 'U', 'T', 'H')) +#define ANNO_MARKER (MAKE_MARKER ('A', 'N', 'N', 'O')) +#define COMT_MARKER (MAKE_MARKER ('C', 'O', 'M', 'T')) +#define FVER_MARKER (MAKE_MARKER ('F', 'V', 'E', 'R')) +#define SFX_MARKER (MAKE_MARKER ('S', 'F', 'X', '!')) + +#define PEAK_MARKER (MAKE_MARKER ('P', 'E', 'A', 'K')) +#define basc_MARKER (MAKE_MARKER ('b', 'a', 's', 'c')) + +/* Supported AIFC encodings.*/ +#define NONE_MARKER (MAKE_MARKER ('N', 'O', 'N', 'E')) +#define sowt_MARKER (MAKE_MARKER ('s', 'o', 'w', 't')) +#define twos_MARKER (MAKE_MARKER ('t', 'w', 'o', 's')) +#define raw_MARKER (MAKE_MARKER ('r', 'a', 'w', ' ')) +#define in24_MARKER (MAKE_MARKER ('i', 'n', '2', '4')) +#define ni24_MARKER (MAKE_MARKER ('4', '2', 'n', '1')) +#define in32_MARKER (MAKE_MARKER ('i', 'n', '3', '2')) +#define ni32_MARKER (MAKE_MARKER ('2', '3', 'n', 'i')) + +#define fl32_MARKER (MAKE_MARKER ('f', 'l', '3', '2')) +#define FL32_MARKER (MAKE_MARKER ('F', 'L', '3', '2')) +#define fl64_MARKER (MAKE_MARKER ('f', 'l', '6', '4')) +#define FL64_MARKER (MAKE_MARKER ('F', 'L', '6', '4')) + +#define ulaw_MARKER (MAKE_MARKER ('u', 'l', 'a', 'w')) +#define ULAW_MARKER (MAKE_MARKER ('U', 'L', 'A', 'W')) +#define alaw_MARKER (MAKE_MARKER ('a', 'l', 'a', 'w')) +#define ALAW_MARKER (MAKE_MARKER ('A', 'L', 'A', 'W')) + +#define DWVW_MARKER (MAKE_MARKER ('D', 'W', 'V', 'W')) +#define GSM_MARKER (MAKE_MARKER ('G', 'S', 'M', ' ')) +#define ima4_MARKER (MAKE_MARKER ('i', 'm', 'a', '4')) + +/* +** This value is officially assigned to Mega Nerd Pty Ltd by Apple +** Corportation as the Application marker for libsndfile. +** +** See : http://developer.apple.com/faq/datatype.html +*/ +#define m3ga_MARKER (MAKE_MARKER ('m', '3', 'g', 'a')) + +/* Unsupported AIFC encodings.*/ + +#define MAC3_MARKER (MAKE_MARKER ('M', 'A', 'C', '3')) +#define MAC6_MARKER (MAKE_MARKER ('M', 'A', 'C', '6')) +#define ADP4_MARKER (MAKE_MARKER ('A', 'D', 'P', '4')) + +/* Predfined chunk sizes. */ +#define SIZEOF_AIFF_COMM 18 +#define SIZEOF_AIFC_COMM_MIN 22 +#define SIZEOF_AIFC_COMM 24 +#define SIZEOF_SSND_CHUNK 8 +#define SIZEOF_INST_CHUNK 20 + +/* Is it constant? */ + +/* AIFC/IMA4 defines. */ +#define AIFC_IMA4_BLOCK_LEN 34 +#define AIFC_IMA4_SAMPLES_PER_BLOCK 64 + +#define AIFF_PEAK_CHUNK_SIZE(ch) (2 * sizeof (int) + ch * (sizeof (float) + sizeof (int))) + +/*------------------------------------------------------------------------------ + * Typedefs for file chunks. + */ + +enum +{ HAVE_FORM = 0x01, + HAVE_AIFF = 0x02, + HAVE_AIFC = 0x04, + HAVE_FVER = 0x08, + HAVE_COMM = 0x10, + HAVE_SSND = 0x20 +} ; + +typedef struct +{ uint32_t size ; + int16_t numChannels ; + uint32_t numSampleFrames ; + int16_t sampleSize ; + uint8_t sampleRate [10] ; + uint32_t encoding ; + char zero_bytes [2] ; +} COMM_CHUNK ; + +typedef struct +{ uint32_t offset ; + uint32_t blocksize ; +} SSND_CHUNK ; + +typedef struct +{ int16_t playMode ; + uint16_t beginLoop ; + uint16_t endLoop ; +} INST_LOOP ; + +typedef struct +{ int8_t baseNote ; /* all notes are MIDI note numbers */ + int8_t detune ; /* cents off, only -50 to +50 are significant */ + int8_t lowNote ; + int8_t highNote ; + int8_t lowVelocity ; /* 1 to 127 */ + int8_t highVelocity ; /* 1 to 127 */ + int16_t gain ; /* in dB, 0 is normal */ + INST_LOOP sustain_loop ; + INST_LOOP release_loop ; +} INST_CHUNK ; + + +enum +{ basc_SCALE_MINOR = 1, + basc_SCALE_MAJOR, + basc_SCALE_NEITHER, + basc_SCALE_BOTH +} ; + +enum +{ basc_TYPE_LOOP = 0, + basc_TYPE_ONE_SHOT +} ; + + +typedef struct +{ uint32_t version ; + uint32_t numBeats ; + uint16_t rootNote ; + uint16_t scaleType ; + uint16_t sigNumerator ; + uint16_t sigDenominator ; + uint16_t loopType ; +} basc_CHUNK ; + +typedef struct +{ uint16_t markerID ; + uint32_t position ; +} MARK_ID_POS ; + +typedef struct +{ sf_count_t comm_offset ; + sf_count_t ssnd_offset ; + + int32_t chanmap_tag ; + + MARK_ID_POS *markstr ; +} AIFF_PRIVATE ; + +/*------------------------------------------------------------------------------ + * Private static functions. + */ + +static int aiff_close (SF_PRIVATE *psf) ; + +static int tenbytefloat2int (uint8_t *bytes) ; +static void uint2tenbytefloat (uint32_t num, uint8_t *bytes) ; + +static int aiff_read_comm_chunk (SF_PRIVATE *psf, COMM_CHUNK *comm_fmt) ; + +static int aiff_read_header (SF_PRIVATE *psf, COMM_CHUNK *comm_fmt) ; + +static int aiff_write_header (SF_PRIVATE *psf, int calc_length) ; +static int aiff_write_tailer (SF_PRIVATE *psf) ; +static void aiff_write_strings (SF_PRIVATE *psf, int location) ; + +static int aiff_command (SF_PRIVATE *psf, int command, void *data, int datasize) ; + +static const char *get_loop_mode_str (int16_t mode) ; + +static int16_t get_loop_mode (int16_t mode) ; + +static int aiff_read_basc_chunk (SF_PRIVATE * psf, int) ; + +static int aiff_read_chanmap (SF_PRIVATE * psf, unsigned dword) ; + +static uint32_t marker_to_position (const MARK_ID_POS *m, uint16_t n, int marksize) ; + +static int aiff_set_chunk (SF_PRIVATE *psf, const SF_CHUNK_INFO * chunk_info) ; +static SF_CHUNK_ITERATOR * aiff_next_chunk_iterator (SF_PRIVATE *psf, SF_CHUNK_ITERATOR * iterator) ; +static int aiff_get_chunk_size (SF_PRIVATE *psf, const SF_CHUNK_ITERATOR * iterator, SF_CHUNK_INFO * chunk_info) ; +static int aiff_get_chunk_data (SF_PRIVATE *psf, const SF_CHUNK_ITERATOR * iterator, SF_CHUNK_INFO * chunk_info) ; + +/*------------------------------------------------------------------------------ +** Public function. +*/ + +int +aiff_open (SF_PRIVATE *psf) +{ COMM_CHUNK comm_fmt ; + int error = 0, subformat ; + + memset (&comm_fmt, 0, sizeof (comm_fmt)) ; + + subformat = SF_CODEC (psf->sf.format) ; + + if ((psf->container_data = calloc (1, sizeof (AIFF_PRIVATE))) == NULL) + return SFE_MALLOC_FAILED ; + + psf->container_close = aiff_close ; + + if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0)) + { if ((error = aiff_read_header (psf, &comm_fmt))) + return error ; + + psf->next_chunk_iterator = aiff_next_chunk_iterator ; + psf->get_chunk_size = aiff_get_chunk_size ; + psf->get_chunk_data = aiff_get_chunk_data ; + + psf_fseek (psf, psf->dataoffset, SEEK_SET) ; + } ; + + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { if (psf->is_pipe) + return SFE_NO_PIPE_WRITE ; + + if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_AIFF) + return SFE_BAD_OPEN_FORMAT ; + + if (psf->file.mode == SFM_WRITE && (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE)) + { if ((psf->peak_info = peak_info_calloc (psf->sf.channels)) == NULL) + return SFE_MALLOC_FAILED ; + psf->peak_info->peak_loc = SF_PEAK_START ; + } ; + + if (psf->file.mode != SFM_RDWR || psf->filelength < 40) + { psf->filelength = 0 ; + psf->datalength = 0 ; + psf->dataoffset = 0 ; + psf->sf.frames = 0 ; + } ; + + psf->strings.flags = SF_STR_ALLOW_START | SF_STR_ALLOW_END ; + + if ((error = aiff_write_header (psf, SF_FALSE))) + return error ; + + psf->write_header = aiff_write_header ; + psf->set_chunk = aiff_set_chunk ; + } ; + + psf->command = aiff_command ; + + switch (SF_CODEC (psf->sf.format)) + { case SF_FORMAT_PCM_U8 : + error = pcm_init (psf) ; + break ; + + case SF_FORMAT_PCM_S8 : + error = pcm_init (psf) ; + break ; + + case SF_FORMAT_PCM_16 : + case SF_FORMAT_PCM_24 : + case SF_FORMAT_PCM_32 : + error = pcm_init (psf) ; + break ; + + case SF_FORMAT_ULAW : + error = ulaw_init (psf) ; + break ; + + case SF_FORMAT_ALAW : + error = alaw_init (psf) ; + break ; + + /* Lite remove start */ + case SF_FORMAT_FLOAT : + error = float32_init (psf) ; + break ; + + case SF_FORMAT_DOUBLE : + error = double64_init (psf) ; + break ; + + case SF_FORMAT_DWVW_12 : + if (psf->sf.frames > comm_fmt.numSampleFrames) + psf->sf.frames = comm_fmt.numSampleFrames ; + break ; + + case SF_FORMAT_DWVW_16 : + error = dwvw_init (psf, 16) ; + if (psf->sf.frames > comm_fmt.numSampleFrames) + psf->sf.frames = comm_fmt.numSampleFrames ; + break ; + + case SF_FORMAT_DWVW_24 : + error = dwvw_init (psf, 24) ; + if (psf->sf.frames > comm_fmt.numSampleFrames) + psf->sf.frames = comm_fmt.numSampleFrames ; + break ; + + case SF_FORMAT_DWVW_N : + if (psf->file.mode != SFM_READ) + { error = SFE_DWVW_BAD_BITWIDTH ; + break ; + } ; + if (comm_fmt.sampleSize >= 8 && comm_fmt.sampleSize < 24) + { error = dwvw_init (psf, comm_fmt.sampleSize) ; + if (psf->sf.frames > comm_fmt.numSampleFrames) + psf->sf.frames = comm_fmt.numSampleFrames ; + break ; + } ; + psf_log_printf (psf, "AIFC/DWVW : Bad bitwidth %d\n", comm_fmt.sampleSize) ; + error = SFE_DWVW_BAD_BITWIDTH ; + break ; + + case SF_FORMAT_IMA_ADPCM : + /* + ** IMA ADPCM encoded AIFF files always have a block length + ** of 34 which decodes to 64 samples. + */ + error = aiff_ima_init (psf, AIFC_IMA4_BLOCK_LEN, AIFC_IMA4_SAMPLES_PER_BLOCK) ; + break ; + /* Lite remove end */ + + case SF_FORMAT_GSM610 : + error = gsm610_init (psf) ; + if (psf->sf.frames > comm_fmt.numSampleFrames) + psf->sf.frames = comm_fmt.numSampleFrames ; + break ; + + default : return SFE_UNIMPLEMENTED ; + } ; + + if (psf->file.mode != SFM_WRITE && psf->sf.frames - comm_fmt.numSampleFrames != 0) + { psf_log_printf (psf, + "*** Frame count read from 'COMM' chunk (%u) not equal to frame count\n" + "*** calculated from length of 'SSND' chunk (%u).\n", + comm_fmt.numSampleFrames, (uint32_t) psf->sf.frames) ; + } ; + + return error ; +} /* aiff_open */ + +/*========================================================================================== +** Private functions. +*/ + +/* This function ought to check size */ +static uint32_t +marker_to_position (const MARK_ID_POS *m, uint16_t n, int marksize) +{ int i ; + + for (i = 0 ; i < marksize ; i++) + if (m [i].markerID == n) + return m [i].position ; + return 0 ; +} /* marker_to_position */ + +static int +aiff_read_header (SF_PRIVATE *psf, COMM_CHUNK *comm_fmt) +{ SSND_CHUNK ssnd_fmt ; + AIFF_PRIVATE *paiff ; + BUF_UNION ubuf ; + uint32_t chunk_size = 0, FORMsize, SSNDsize, bytesread, mark_count = 0 ; + int k, found_chunk = 0, done = 0, error = 0 ; + char *cptr ; + int instr_found = 0, mark_found = 0 ; + + if (psf->filelength > 0xFFFFFFFFLL) + psf_log_printf (psf, "Warning : filelength > 0xffffffff. This is bad!!!!\n") ; + + if ((paiff = psf->container_data) == NULL) + return SFE_INTERNAL ; + + paiff->comm_offset = 0 ; + paiff->ssnd_offset = 0 ; + + /* Set position to start of file to begin reading header. */ + psf_binheader_readf (psf, "p", 0) ; + + memset (comm_fmt, 0, sizeof (COMM_CHUNK)) ; + + /* Until recently AIF* file were all BIG endian. */ + psf->endian = SF_ENDIAN_BIG ; + + /* AIFF files can apparently have their chunks in any order. However, they + ** must have a FORM chunk. Approach here is to read all the chunks one by + ** one and then check for the mandatory chunks at the end. + */ + while (! done) + { unsigned marker ; + size_t jump = chunk_size & 1 ; + + marker = chunk_size = 0 ; + psf_binheader_readf (psf, "Ejm4", jump, &marker, &chunk_size) ; + if (marker == 0) + { sf_count_t pos = psf_ftell (psf) ; + psf_log_printf (psf, "Have 0 marker at position %D (0x%x).\n", pos, pos) ; + break ; + } ; + + if (psf->file.mode == SFM_RDWR && (found_chunk & HAVE_SSND)) + return SFE_AIFF_RW_SSND_NOT_LAST ; + + psf_store_read_chunk_u32 (&psf->rchunks, marker, psf_ftell (psf), chunk_size) ; + + switch (marker) + { case FORM_MARKER : + if (found_chunk) + return SFE_AIFF_NO_FORM ; + + FORMsize = chunk_size ; + + found_chunk |= HAVE_FORM ; + psf_binheader_readf (psf, "m", &marker) ; + switch (marker) + { case AIFC_MARKER : + case AIFF_MARKER : + found_chunk |= (marker == AIFC_MARKER) ? (HAVE_AIFC | HAVE_AIFF) : HAVE_AIFF ; + break ; + default : + break ; + } ; + + if (psf->fileoffset > 0 && psf->filelength > FORMsize + 8) + { /* Set file length. */ + psf->filelength = FORMsize + 8 ; + psf_log_printf (psf, "FORM : %u\n %M\n", FORMsize, marker) ; + } + else if (FORMsize != psf->filelength - 2 * SIGNED_SIZEOF (chunk_size)) + { chunk_size = psf->filelength - 2 * sizeof (chunk_size) ; + psf_log_printf (psf, "FORM : %u (should be %u)\n %M\n", FORMsize, chunk_size, marker) ; + FORMsize = chunk_size ; + } + else + psf_log_printf (psf, "FORM : %u\n %M\n", FORMsize, marker) ; + /* Set this to 0, so we don't jump a byte when parsing the next marker. */ + chunk_size = 0 ; + break ; + + + case COMM_MARKER : + paiff->comm_offset = psf_ftell (psf) - 8 ; + chunk_size += chunk_size & 1 ; + comm_fmt->size = chunk_size ; + if ((error = aiff_read_comm_chunk (psf, comm_fmt)) != 0) + return error ; + + found_chunk |= HAVE_COMM ; + break ; + + case PEAK_MARKER : + /* Must have COMM chunk before PEAK chunk. */ + if ((found_chunk & (HAVE_FORM | HAVE_AIFF | HAVE_COMM)) != (HAVE_FORM | HAVE_AIFF | HAVE_COMM)) + return SFE_AIFF_PEAK_B4_COMM ; + + psf_log_printf (psf, "%M : %d\n", marker, chunk_size) ; + if (chunk_size != AIFF_PEAK_CHUNK_SIZE (psf->sf.channels)) + { psf_binheader_readf (psf, "j", chunk_size) ; + psf_log_printf (psf, "*** File PEAK chunk too big.\n") ; + return SFE_WAV_BAD_PEAK ; + } ; + + if (psf->peak_info) + { psf_log_printf (psf, "*** Found existing peak info, using last one.\n") ; + free (psf->peak_info) ; + psf->peak_info = NULL ; + } ; + if ((psf->peak_info = peak_info_calloc (psf->sf.channels)) == NULL) + return SFE_MALLOC_FAILED ; + + /* Read in rest of PEAK chunk. */ + psf_binheader_readf (psf, "E44", &(psf->peak_info->version), &(psf->peak_info->timestamp)) ; + + if (psf->peak_info->version != 1) + psf_log_printf (psf, " version : %d *** (should be version 1)\n", psf->peak_info->version) ; + else + psf_log_printf (psf, " version : %d\n", psf->peak_info->version) ; + + psf_log_printf (psf, " time stamp : %d\n", psf->peak_info->timestamp) ; + psf_log_printf (psf, " Ch Position Value\n") ; + + cptr = ubuf.cbuf ; + for (k = 0 ; k < psf->sf.channels ; k++) + { float value ; + uint32_t position ; + + psf_binheader_readf (psf, "Ef4", &value, &position) ; + psf->peak_info->peaks [k].value = value ; + psf->peak_info->peaks [k].position = position ; + + snprintf (cptr, sizeof (ubuf.scbuf), " %2d %-12" PRId64 " %g\n", + k, psf->peak_info->peaks [k].position, psf->peak_info->peaks [k].value) ; + cptr [sizeof (ubuf.scbuf) - 1] = 0 ; + psf_log_printf (psf, "%s", cptr) ; + } ; + + psf->peak_info->peak_loc = ((found_chunk & HAVE_SSND) == 0) ? SF_PEAK_START : SF_PEAK_END ; + break ; + + case SSND_MARKER : + if ((found_chunk & HAVE_AIFC) && (found_chunk & HAVE_FVER) == 0) + psf_log_printf (psf, "*** Valid AIFC files should have an FVER chunk.\n") ; + + paiff->ssnd_offset = psf_ftell (psf) - 8 ; + SSNDsize = chunk_size ; + psf_binheader_readf (psf, "E44", &(ssnd_fmt.offset), &(ssnd_fmt.blocksize)) ; + + psf->datalength = SSNDsize - sizeof (ssnd_fmt) ; + psf->dataoffset = psf_ftell (psf) ; + + if (psf->datalength > psf->filelength - psf->dataoffset || psf->datalength < 0) + { psf_log_printf (psf, " SSND : %u (should be %D)\n", SSNDsize, psf->filelength - psf->dataoffset + sizeof (SSND_CHUNK)) ; + psf->datalength = psf->filelength - psf->dataoffset ; + } + else + psf_log_printf (psf, " SSND : %u\n", SSNDsize) ; + + if (ssnd_fmt.offset == 0 || psf->dataoffset + ssnd_fmt.offset == ssnd_fmt.blocksize) + { psf_log_printf (psf, " Offset : %u\n", ssnd_fmt.offset) ; + psf_log_printf (psf, " Block Size : %u\n", ssnd_fmt.blocksize) ; + + psf->dataoffset += ssnd_fmt.offset ; + psf->datalength -= ssnd_fmt.offset ; + } + else + { psf_log_printf (psf, " Offset : %u\n", ssnd_fmt.offset) ; + psf_log_printf (psf, " Block Size : %u ???\n", ssnd_fmt.blocksize) ; + psf->dataoffset += ssnd_fmt.offset ; + psf->datalength -= ssnd_fmt.offset ; + } ; + + /* Only set dataend if there really is data at the end. */ + if (psf->datalength + psf->dataoffset < psf->filelength) + psf->dataend = psf->datalength + psf->dataoffset ; + + found_chunk |= HAVE_SSND ; + + if (! psf->sf.seekable) + break ; + + /* Seek to end of SSND chunk. */ + psf_fseek (psf, psf->dataoffset + psf->datalength, SEEK_SET) ; + break ; + + case c_MARKER : + if (chunk_size == 0) + break ; + if (chunk_size >= SIGNED_SIZEOF (ubuf.scbuf)) + { psf_log_printf (psf, " %M : %d (too big)\n", marker, chunk_size) ; + return SFE_INTERNAL ; + } ; + + cptr = ubuf.cbuf ; + psf_binheader_readf (psf, "b", cptr, chunk_size + (chunk_size & 1)) ; + cptr [chunk_size] = 0 ; + + psf_sanitize_string (cptr, chunk_size) ; + + psf_log_printf (psf, " %M : %s\n", marker, cptr) ; + psf_store_string (psf, SF_STR_COPYRIGHT, cptr) ; + chunk_size += chunk_size & 1 ; + break ; + + case AUTH_MARKER : + if (chunk_size == 0) + break ; + if (chunk_size >= SIGNED_SIZEOF (ubuf.scbuf) - 1) + { psf_log_printf (psf, " %M : %d (too big)\n", marker, chunk_size) ; + return SFE_INTERNAL ; + } ; + + cptr = ubuf.cbuf ; + psf_binheader_readf (psf, "b", cptr, chunk_size + (chunk_size & 1)) ; + cptr [chunk_size] = 0 ; + psf_log_printf (psf, " %M : %s\n", marker, cptr) ; + psf_store_string (psf, SF_STR_ARTIST, cptr) ; + chunk_size += chunk_size & 1 ; + break ; + + case COMT_MARKER : + { uint16_t count, id, len ; + uint32_t timestamp, bytes ; + + if (chunk_size == 0) + break ; + bytes = chunk_size ; + bytes -= psf_binheader_readf (psf, "E2", &count) ; + psf_log_printf (psf, " %M : %d\n count : %d\n", marker, chunk_size, count) ; + + for (k = 0 ; k < count ; k++) + { bytes -= psf_binheader_readf (psf, "E422", ×tamp, &id, &len) ; + psf_log_printf (psf, " time : 0x%x\n marker : %x\n length : %d\n", timestamp, id, len) ; + + if (len + 1 > SIGNED_SIZEOF (ubuf.scbuf)) + { psf_log_printf (psf, "\nError : string length (%d) too big.\n", len) ; + return SFE_INTERNAL ; + } ; + + cptr = ubuf.cbuf ; + bytes -= psf_binheader_readf (psf, "b", cptr, len) ; + cptr [len] = 0 ; + psf_log_printf (psf, " string : %s\n", cptr) ; + } ; + + if (bytes > 0) + psf_binheader_readf (psf, "j", bytes) ; + } ; + break ; + + case APPL_MARKER : + { unsigned appl_marker ; + + if (chunk_size == 0) + break ; + if (chunk_size >= SIGNED_SIZEOF (ubuf.scbuf) - 1) + { psf_log_printf (psf, " %M : %u (too big, skipping)\n", marker, chunk_size) ; + psf_binheader_readf (psf, "j", chunk_size + (chunk_size & 1)) ; + break ; + } ; + + if (chunk_size < 4) + { psf_log_printf (psf, " %M : %d (too small, skipping)\n", marker, chunk_size) ; + psf_binheader_readf (psf, "j", chunk_size + (chunk_size & 1)) ; + break ; + } ; + + cptr = ubuf.cbuf ; + psf_binheader_readf (psf, "mb", &appl_marker, cptr, chunk_size + (chunk_size & 1) - 4) ; + cptr [chunk_size] = 0 ; + + for (k = 0 ; k < (int) chunk_size ; k++) + if (! psf_isprint (cptr [k])) + { cptr [k] = 0 ; + break ; + } ; + + psf_log_printf (psf, " %M : %d\n AppSig : %M\n Name : %s\n", marker, chunk_size, appl_marker, cptr) ; + psf_store_string (psf, SF_STR_SOFTWARE, cptr) ; + chunk_size += chunk_size & 1 ; + } ; + break ; + + case NAME_MARKER : + if (chunk_size == 0) + break ; + if (chunk_size >= SIGNED_SIZEOF (ubuf.scbuf) - 2) + { psf_log_printf (psf, " %M : %d (too big)\n", marker, chunk_size) ; + return SFE_INTERNAL ; + } ; + + cptr = ubuf.cbuf ; + psf_binheader_readf (psf, "b", cptr, chunk_size + (chunk_size & 1)) ; + cptr [chunk_size] = 0 ; + psf_log_printf (psf, " %M : %s\n", marker, cptr) ; + psf_store_string (psf, SF_STR_TITLE, cptr) ; + chunk_size += chunk_size & 1 ; + break ; + + case ANNO_MARKER : + if (chunk_size == 0) + break ; + if (chunk_size >= SIGNED_SIZEOF (ubuf.scbuf) - 2) + { psf_log_printf (psf, " %M : %d (too big)\n", marker, chunk_size) ; + return SFE_INTERNAL ; + } ; + + cptr = ubuf.cbuf ; + psf_binheader_readf (psf, "b", cptr, chunk_size + (chunk_size & 1)) ; + cptr [chunk_size] = 0 ; + psf_log_printf (psf, " %M : %s\n", marker, cptr) ; + psf_store_string (psf, SF_STR_COMMENT, cptr) ; + chunk_size += chunk_size & 1 ; + break ; + + case INST_MARKER : + if (chunk_size != SIZEOF_INST_CHUNK) + { psf_log_printf (psf, " %M : %d (should be %d)\n", marker, chunk_size, SIZEOF_INST_CHUNK) ; + psf_binheader_readf (psf, "j", chunk_size) ; + break ; + } ; + psf_log_printf (psf, " %M : %d\n", marker, chunk_size) ; + { uint8_t bytes [6] ; + int16_t gain ; + + if (psf->instrument == NULL && (psf->instrument = psf_instrument_alloc ()) == NULL) + return SFE_MALLOC_FAILED ; + + psf_binheader_readf (psf, "b", bytes, 6) ; + psf_log_printf (psf, " Base Note : %u\n Detune : %u\n" + " Low Note : %u\n High Note : %u\n" + " Low Vel. : %u\n High Vel. : %u\n", + bytes [0], bytes [1], bytes [2], bytes [3], bytes [4], bytes [5]) ; + psf->instrument->basenote = bytes [0] ; + psf->instrument->detune = bytes [1] ; + psf->instrument->key_lo = bytes [2] ; + psf->instrument->key_hi = bytes [3] ; + psf->instrument->velocity_lo = bytes [4] ; + psf->instrument->velocity_hi = bytes [5] ; + psf_binheader_readf (psf, "E2", &gain) ; + psf->instrument->gain = gain ; + psf_log_printf (psf, " Gain (dB) : %d\n", gain) ; + } ; + { int16_t mode ; /* 0 - no loop, 1 - forward looping, 2 - backward looping */ + const char *loop_mode ; + uint16_t begin, end ; + + psf_binheader_readf (psf, "E222", &mode, &begin, &end) ; + loop_mode = get_loop_mode_str (mode) ; + mode = get_loop_mode (mode) ; + if (mode == SF_LOOP_NONE) + { psf->instrument->loop_count = 0 ; + psf->instrument->loops [0].mode = SF_LOOP_NONE ; + } + else + { psf->instrument->loop_count = 1 ; + psf->instrument->loops [0].mode = SF_LOOP_FORWARD ; + psf->instrument->loops [0].start = begin ; + psf->instrument->loops [0].end = end ; + psf->instrument->loops [0].count = 0 ; + } ; + psf_log_printf (psf, " Sustain\n mode : %d => %s\n begin : %u\n end : %u\n", + mode, loop_mode, begin, end) ; + psf_binheader_readf (psf, "E222", &mode, &begin, &end) ; + loop_mode = get_loop_mode_str (mode) ; + mode = get_loop_mode (mode) ; + if (mode == SF_LOOP_NONE) + psf->instrument->loops [1].mode = SF_LOOP_NONE ; + else + { psf->instrument->loop_count += 1 ; + psf->instrument->loops [1].mode = SF_LOOP_FORWARD ; + psf->instrument->loops [1].start = begin ; + psf->instrument->loops [1].end = end ; + psf->instrument->loops [1].count = 0 ; + } ; + psf_log_printf (psf, " Release\n mode : %d => %s\n begin : %u\n end : %u\n", + mode, loop_mode, begin, end) ; + } ; + instr_found++ ; + break ; + + case basc_MARKER : + psf_log_printf (psf, " basc : %u\n", chunk_size) ; + + if ((error = aiff_read_basc_chunk (psf, chunk_size))) + return error ; + break ; + + case MARK_MARKER : + psf_log_printf (psf, " %M : %d\n", marker, chunk_size) ; + { uint16_t mark_id, n = 0 ; + uint32_t position ; + + bytesread = psf_binheader_readf (psf, "E2", &n) ; + mark_count = n ; + psf_log_printf (psf, " Count : %u\n", mark_count) ; + if (paiff->markstr != NULL) + { psf_log_printf (psf, "*** Second MARK chunk found. Throwing away the first.\n") ; + free (paiff->markstr) ; + } ; + paiff->markstr = calloc (mark_count, sizeof (MARK_ID_POS)) ; + if (paiff->markstr == NULL) + return SFE_MALLOC_FAILED ; + + if (mark_count > 2500) /* 2500 is close to the largest number of cues possible because of block sizes */ + { psf_log_printf (psf, " More than 2500 markers, skipping!\n") ; + psf_binheader_readf (psf, "j", chunk_size - bytesread) ; + break ; + } ; + + if (psf->cues) + { free (psf->cues) ; + psf->cues = NULL ; + } ; + if ((psf->cues = psf_cues_alloc (mark_count)) == NULL) + return SFE_MALLOC_FAILED ; + + for (n = 0 ; n < mark_count && bytesread < chunk_size ; n++) + { uint32_t pstr_len ; + uint8_t ch ; + + bytesread += psf_binheader_readf (psf, "E241", &mark_id, &position, &ch) ; + psf_log_printf (psf, " Mark ID : %u\n Position : %u\n", mark_id, position) ; + + psf->cues->cue_points [n].indx = mark_id ; + psf->cues->cue_points [n].position = 0 ; + psf->cues->cue_points [n].fcc_chunk = MAKE_MARKER ('d', 'a', 't', 'a') ; /* always data */ + psf->cues->cue_points [n].chunk_start = 0 ; + psf->cues->cue_points [n].block_start = 0 ; + psf->cues->cue_points [n].sample_offset = position ; + + pstr_len = (ch & 1) ? ch : ch + 1 ; + + if (pstr_len < sizeof (ubuf.scbuf) - 1) + { bytesread += psf_binheader_readf (psf, "b", ubuf.scbuf, pstr_len) ; + ubuf.scbuf [pstr_len] = 0 ; + } + else + { uint32_t read_len = pstr_len - (sizeof (ubuf.scbuf) - 1) ; + bytesread += psf_binheader_readf (psf, "bj", ubuf.scbuf, read_len, pstr_len - read_len) ; + ubuf.scbuf [sizeof (ubuf.scbuf) - 1] = 0 ; + } + + psf_log_printf (psf, " Name : %s\n", ubuf.scbuf) ; + + psf_strlcpy (psf->cues->cue_points [n].name, sizeof (psf->cues->cue_points [n].name), ubuf.cbuf) ; + + paiff->markstr [n].markerID = mark_id ; + paiff->markstr [n].position = position ; + /* + ** TODO if ubuf.scbuf is equal to + ** either Beg_loop, Beg loop or beg loop and spam + ** if (psf->instrument == NULL && (psf->instrument = psf_instrument_alloc ()) == NULL) + ** return SFE_MALLOC_FAILED ; + */ + } ; + } ; + mark_found++ ; + psf_binheader_readf (psf, "j", chunk_size - bytesread) ; + break ; + + case FVER_MARKER : + found_chunk |= HAVE_FVER ; + /* Falls through. */ + + case SFX_MARKER : + psf_log_printf (psf, " %M : %d\n", marker, chunk_size) ; + psf_binheader_readf (psf, "j", chunk_size) ; + break ; + + case NONE_MARKER : + /* Fix for broken AIFC files with incorrect COMM chunk length. */ + chunk_size = (chunk_size >> 24) - 3 ; + psf_log_printf (psf, " %M : %d\n", marker, chunk_size) ; + psf_binheader_readf (psf, "j", make_size_t (chunk_size)) ; + break ; + + case CHAN_MARKER : + if (chunk_size < 12) + { psf_log_printf (psf, " %M : %d (should be >= 12)\n", marker, chunk_size) ; + psf_binheader_readf (psf, "j", chunk_size) ; + break ; + } + + psf_log_printf (psf, " %M : %d\n", marker, chunk_size) ; + + if ((error = aiff_read_chanmap (psf, chunk_size))) + return error ; + break ; + + default : + if (chunk_size >= 0xffff0000) + { done = SF_TRUE ; + psf_log_printf (psf, "*** Unknown chunk marker (%X) at position %D with length %u. Exiting parser.\n", marker, psf_ftell (psf) - 8, chunk_size) ; + break ; + } ; + + if (psf_isprint ((marker >> 24) & 0xFF) && psf_isprint ((marker >> 16) & 0xFF) + && psf_isprint ((marker >> 8) & 0xFF) && psf_isprint (marker & 0xFF)) + { psf_log_printf (psf, " %M : %u (unknown marker)\n", marker, chunk_size) ; + + psf_binheader_readf (psf, "j", chunk_size) ; + break ; + } ; + + if (psf_ftell (psf) & 0x03) + { psf_log_printf (psf, " Unknown chunk marker at position %D. Resynching.\n", psf_ftell (psf) - 8) ; + psf_binheader_readf (psf, "j", -3) ; + break ; + } ; + psf_log_printf (psf, "*** Unknown chunk marker %X at position %D. Exiting parser.\n", marker, psf_ftell (psf)) ; + done = SF_TRUE ; + break ; + } ; /* switch (marker) */ + + if (chunk_size >= psf->filelength) + { psf_log_printf (psf, "*** Chunk size %u > file length %D. Exiting parser.\n", chunk_size, psf->filelength) ; + break ; + } ; + + if ((! psf->sf.seekable) && (found_chunk & HAVE_SSND)) + break ; + + if (psf_ftell (psf) >= psf->filelength - (2 * SIGNED_SIZEOF (int32_t))) + break ; + } ; /* while (1) */ + + if (instr_found && mark_found) + { int ji, str_index ; + /* Next loop will convert markers to loop positions for internal handling */ + for (ji = 0 ; ji < psf->instrument->loop_count ; ji ++) + { if (ji < ARRAY_LEN (psf->instrument->loops)) + { psf->instrument->loops [ji].start = marker_to_position (paiff->markstr, psf->instrument->loops [ji].start, mark_count) ; + psf->instrument->loops [ji].end = marker_to_position (paiff->markstr, psf->instrument->loops [ji].end, mark_count) ; + psf->instrument->loops [ji].mode = SF_LOOP_FORWARD ; + } ; + } ; + + /* The markers that correspond to loop positions can now be removed from cues struct */ + if (psf->cues->cue_count > (uint32_t) (psf->instrument->loop_count * 2)) + { uint32_t j ; + + for (j = 0 ; j < psf->cues->cue_count - (uint32_t) (psf->instrument->loop_count * 2) ; j ++) + { /* This simply copies the information in cues above loop positions and writes it at current count instead */ + psf->cues->cue_points [j].indx = psf->cues->cue_points [j + psf->instrument->loop_count * 2].indx ; + psf->cues->cue_points [j].position = psf->cues->cue_points [j + psf->instrument->loop_count * 2].position ; + psf->cues->cue_points [j].fcc_chunk = psf->cues->cue_points [j + psf->instrument->loop_count * 2].fcc_chunk ; + psf->cues->cue_points [j].chunk_start = psf->cues->cue_points [j + psf->instrument->loop_count * 2].chunk_start ; + psf->cues->cue_points [j].block_start = psf->cues->cue_points [j + psf->instrument->loop_count * 2].block_start ; + psf->cues->cue_points [j].sample_offset = psf->cues->cue_points [j + psf->instrument->loop_count * 2].sample_offset ; + for (str_index = 0 ; str_index < 256 ; str_index++) + psf->cues->cue_points [j].name [str_index] = psf->cues->cue_points [j + psf->instrument->loop_count * 2].name [str_index] ; + } ; + psf->cues->cue_count -= psf->instrument->loop_count * 2 ; + } else + { /* All the cues were in fact loop positions so we can actually remove the cues altogether */ + free (psf->cues) ; + psf->cues = NULL ; + } + } ; + + if (psf->sf.channels < 1) + return SFE_CHANNEL_COUNT_ZERO ; + + if (psf->sf.channels > SF_MAX_CHANNELS) + return SFE_CHANNEL_COUNT ; + + if (! (found_chunk & HAVE_FORM)) + return SFE_AIFF_NO_FORM ; + + if (! (found_chunk & HAVE_AIFF)) + return SFE_AIFF_COMM_NO_FORM ; + + if (! (found_chunk & HAVE_COMM)) + return SFE_AIFF_SSND_NO_COMM ; + + if (! psf->dataoffset) + return SFE_AIFF_NO_DATA ; + + return 0 ; +} /* aiff_read_header */ + +static int +aiff_close (SF_PRIVATE *psf) +{ AIFF_PRIVATE *paiff = psf->container_data ; + + if (paiff != NULL && paiff->markstr != NULL) + { free (paiff->markstr) ; + paiff->markstr = NULL ; + } ; + + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { aiff_write_tailer (psf) ; + aiff_write_header (psf, SF_TRUE) ; + } ; + + return 0 ; +} /* aiff_close */ + +static int +aiff_read_comm_chunk (SF_PRIVATE *psf, COMM_CHUNK *comm_fmt) +{ BUF_UNION ubuf ; + int subformat, samplerate ; + + ubuf.scbuf [0] = 0 ; + + /* The COMM chunk has an int aligned to an odd word boundary. Some + ** processors are not able to deal with this (ie bus fault) so we have + ** to take special care. + */ + + psf_binheader_readf (psf, "E242b", &(comm_fmt->numChannels), &(comm_fmt->numSampleFrames), + &(comm_fmt->sampleSize), &(comm_fmt->sampleRate), SIGNED_SIZEOF (comm_fmt->sampleRate)) ; + + if (comm_fmt->size > 0x10000 && (comm_fmt->size & 0xffff) == 0) + { psf_log_printf (psf, " COMM : %d (0x%x) *** should be ", comm_fmt->size, comm_fmt->size) ; + comm_fmt->size = ENDSWAP_32 (comm_fmt->size) ; + psf_log_printf (psf, "%d (0x%x)\n", comm_fmt->size, comm_fmt->size) ; + } + else + psf_log_printf (psf, " COMM : %d\n", comm_fmt->size) ; + + if (comm_fmt->size == SIZEOF_AIFF_COMM) + comm_fmt->encoding = NONE_MARKER ; + else if (comm_fmt->size == SIZEOF_AIFC_COMM_MIN) + psf_binheader_readf (psf, "Em", &(comm_fmt->encoding)) ; + else if (comm_fmt->size >= SIZEOF_AIFC_COMM) + { uint8_t encoding_len ; + unsigned read_len ; + + psf_binheader_readf (psf, "Em1", &(comm_fmt->encoding), &encoding_len) ; + + comm_fmt->size = SF_MIN (sizeof (ubuf.scbuf), make_size_t (comm_fmt->size)) ; + memset (ubuf.scbuf, 0, comm_fmt->size) ; + read_len = comm_fmt->size - SIZEOF_AIFC_COMM + 1 ; + psf_binheader_readf (psf, "b", ubuf.scbuf, read_len) ; + ubuf.scbuf [read_len + 1] = 0 ; + } ; + + samplerate = tenbytefloat2int (comm_fmt->sampleRate) ; + + psf_log_printf (psf, " Sample Rate : %d\n", samplerate) ; + psf_log_printf (psf, " Frames : %u%s\n", comm_fmt->numSampleFrames, (comm_fmt->numSampleFrames == 0 && psf->filelength > 104) ? " (Should not be 0)" : "") ; + + if (comm_fmt->numChannels < 1 || comm_fmt->numChannels > SF_MAX_CHANNELS) + { psf_log_printf (psf, " Channels : %d (should be >= 1 and < %d)\n", comm_fmt->numChannels, SF_MAX_CHANNELS) ; + return SFE_CHANNEL_COUNT_BAD ; + } ; + + psf_log_printf (psf, " Channels : %d\n", comm_fmt->numChannels) ; + + /* Found some broken 'fl32' files with comm.samplesize == 16. Fix it here. */ + if ((comm_fmt->encoding == fl32_MARKER || comm_fmt->encoding == FL32_MARKER) && comm_fmt->sampleSize != 32) + { psf_log_printf (psf, " Sample Size : %d (should be 32)\n", comm_fmt->sampleSize) ; + comm_fmt->sampleSize = 32 ; + } + else if ((comm_fmt->encoding == fl64_MARKER || comm_fmt->encoding == FL64_MARKER) && comm_fmt->sampleSize != 64) + { psf_log_printf (psf, " Sample Size : %d (should be 64)\n", comm_fmt->sampleSize) ; + comm_fmt->sampleSize = 64 ; + } + else + psf_log_printf (psf, " Sample Size : %d\n", comm_fmt->sampleSize) ; + + + if ((psf->sf.channels != comm_fmt->numChannels) && psf->peak_info) + { psf_log_printf (psf, " *** channel count changed, discarding existing PEAK chunk\n") ; + free (psf->peak_info) ; + psf->peak_info = NULL ; + } ; + + subformat = s_bitwidth_to_subformat (comm_fmt->sampleSize) ; + + psf->sf.samplerate = samplerate ; + psf->sf.frames = comm_fmt->numSampleFrames ; + psf->sf.channels = comm_fmt->numChannels ; + psf->bytewidth = BITWIDTH2BYTES (comm_fmt->sampleSize) ; + + psf->endian = SF_ENDIAN_BIG ; + + switch (comm_fmt->encoding) + { case NONE_MARKER : + psf->sf.format = (SF_FORMAT_AIFF | subformat) ; + break ; + + case twos_MARKER : + case in24_MARKER : + case in32_MARKER : + psf->sf.format = (SF_ENDIAN_BIG | SF_FORMAT_AIFF | subformat) ; + break ; + + case sowt_MARKER : + case ni24_MARKER : + case ni32_MARKER : + psf->endian = SF_ENDIAN_LITTLE ; + psf->sf.format = (SF_ENDIAN_LITTLE | SF_FORMAT_AIFF | subformat) ; + break ; + + case fl32_MARKER : + case FL32_MARKER : + psf->sf.format = (SF_FORMAT_AIFF | SF_FORMAT_FLOAT) ; + break ; + + case ulaw_MARKER : + case ULAW_MARKER : + psf->sf.format = (SF_FORMAT_AIFF | SF_FORMAT_ULAW) ; + break ; + + case alaw_MARKER : + case ALAW_MARKER : + psf->sf.format = (SF_FORMAT_AIFF | SF_FORMAT_ALAW) ; + break ; + + case fl64_MARKER : + case FL64_MARKER : + psf->sf.format = (SF_FORMAT_AIFF | SF_FORMAT_DOUBLE) ; + break ; + + case raw_MARKER : + psf->sf.format = (SF_FORMAT_AIFF | SF_FORMAT_PCM_U8) ; + break ; + + case DWVW_MARKER : + psf->sf.format = SF_FORMAT_AIFF ; + switch (comm_fmt->sampleSize) + { case 12 : + psf->sf.format |= SF_FORMAT_DWVW_12 ; + break ; + case 16 : + psf->sf.format |= SF_FORMAT_DWVW_16 ; + break ; + case 24 : + psf->sf.format |= SF_FORMAT_DWVW_24 ; + break ; + + default : + psf->sf.format |= SF_FORMAT_DWVW_N ; + break ; + } ; + break ; + + case GSM_MARKER : + psf->sf.format = (SF_FORMAT_AIFF | SF_FORMAT_GSM610) ; + break ; + + + case ima4_MARKER : + psf->endian = SF_ENDIAN_BIG ; + psf->sf.format = (SF_FORMAT_AIFF | SF_FORMAT_IMA_ADPCM) ; + break ; + + default : + psf_log_printf (psf, "AIFC : Unimplemented format : %M\n", comm_fmt->encoding) ; + return SFE_UNIMPLEMENTED ; + } ; + + if (! ubuf.scbuf [0]) + psf_log_printf (psf, " Encoding : %M\n", comm_fmt->encoding) ; + else + psf_log_printf (psf, " Encoding : %M => %s\n", comm_fmt->encoding, ubuf.scbuf) ; + + return 0 ; +} /* aiff_read_comm_chunk */ + + +/*========================================================================================== +*/ + +static int +aiff_rewrite_header (SF_PRIVATE *psf) +{ AIFF_PRIVATE *paiff = psf->container_data ; + + /* Assuming here that the header has already been written and just + ** needs to be corrected for new data length. That means that we + ** only change the length fields of the FORM and SSND chunks ; + ** everything else can be skipped over. + */ + int k, ch, comm_size, comm_frames ; + sf_count_t header_len ; + + /* Calculate the header length rather than use dataoffset, as AIFF files + ** can have additional padding offset bytes which aren't usefully a part of + ** the header. + */ + header_len = paiff->ssnd_offset + 8 + SIZEOF_SSND_CHUNK ; + if (psf->header.len < header_len || header_len > psf->dataoffset) + return SFE_INTERNAL ; + psf_fseek (psf, 0, SEEK_SET) ; + psf_fread (psf->header.ptr, header_len, 1, psf) ; + + psf->header.indx = 0 ; + + /* FORM chunk. */ + psf_binheader_writef (psf, "Etm8", BHWm (FORM_MARKER), BHW8 (psf->filelength - 8)) ; + + /* COMM chunk. */ + if ((k = psf_find_read_chunk_m32 (&psf->rchunks, COMM_MARKER)) >= 0) + { psf->header.indx = psf->rchunks.chunks [k].offset - 8 ; + comm_frames = psf->sf.frames ; + comm_size = psf->rchunks.chunks [k].len ; + psf_binheader_writef (psf, "Em42t4", BHWm (COMM_MARKER), BHW4 (comm_size), BHW2 (psf->sf.channels), BHW4 (comm_frames)) ; + } ; + + /* PEAK chunk. */ + if ((k = psf_find_read_chunk_m32 (&psf->rchunks, PEAK_MARKER)) >= 0) + { psf->header.indx = psf->rchunks.chunks [k].offset - 8 ; + psf_binheader_writef (psf, "Em4", BHWm (PEAK_MARKER), BHW4 (AIFF_PEAK_CHUNK_SIZE (psf->sf.channels))) ; + psf_binheader_writef (psf, "E44", BHW4 (1), BHW4 (time (NULL))) ; + for (ch = 0 ; ch < psf->sf.channels ; ch++) + psf_binheader_writef (psf, "Eft8", BHWf ((float) psf->peak_info->peaks [ch].value), BHW8 (psf->peak_info->peaks [ch].position)) ; + } ; + + + /* SSND chunk. */ + if ((k = psf_find_read_chunk_m32 (&psf->rchunks, SSND_MARKER)) >= 0) + { psf->header.indx = psf->rchunks.chunks [k].offset - 8 ; + psf_binheader_writef (psf, "Etm8", BHWm (SSND_MARKER), BHW8 (psf->datalength + SIZEOF_SSND_CHUNK)) ; + } ; + + /* Header mangling complete so write it out. */ + psf_fseek (psf, 0, SEEK_SET) ; + psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ; + + return 0 ; +} /* aiff_rewrite_header */ + +static int +aiff_write_header (SF_PRIVATE *psf, int calc_length) +{ sf_count_t current ; + AIFF_PRIVATE *paiff ; + uint8_t comm_sample_rate [10], comm_zero_bytes [2] = { 0, 0 } ; + uint32_t comm_type, comm_size, comm_encoding, comm_frames = 0, uk ; + int ret, k, endian, has_data = SF_FALSE ; + int16_t bit_width ; + + if ((paiff = psf->container_data) == NULL) + return SFE_INTERNAL ; + + current = psf_ftell (psf) ; + + if (current > psf->dataoffset) + has_data = SF_TRUE ; + + if (calc_length) + { psf->filelength = psf_get_filelen (psf) ; + + psf->datalength = psf->filelength - psf->dataoffset ; + if (psf->dataend) + psf->datalength -= psf->filelength - psf->dataend ; + + if (psf->bytewidth > 0) + psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ; + } ; + + if (psf->file.mode == SFM_RDWR && psf->dataoffset > 0 && psf->rchunks.count > 0) + { if ((ret = aiff_rewrite_header (psf)) != 0) + return ret ; + if (current > 0) + psf_fseek (psf, current, SEEK_SET) ; + return 0 ; + } ; + + endian = SF_ENDIAN (psf->sf.format) ; + if (CPU_IS_LITTLE_ENDIAN && endian == SF_ENDIAN_CPU) + endian = SF_ENDIAN_LITTLE ; + + /* Standard value here. */ + bit_width = psf->bytewidth * 8 ; + comm_frames = (psf->sf.frames > 0xFFFFFFFF) ? 0xFFFFFFFF : psf->sf.frames ; + + switch (SF_CODEC (psf->sf.format) | endian) + { case SF_FORMAT_PCM_S8 | SF_ENDIAN_BIG : + psf->endian = SF_ENDIAN_BIG ; + comm_type = AIFC_MARKER ; + comm_size = SIZEOF_AIFC_COMM ; + comm_encoding = twos_MARKER ; + break ; + + case SF_FORMAT_PCM_S8 | SF_ENDIAN_LITTLE : + psf->endian = SF_ENDIAN_LITTLE ; + comm_type = AIFC_MARKER ; + comm_size = SIZEOF_AIFC_COMM ; + comm_encoding = sowt_MARKER ; + break ; + + case SF_FORMAT_PCM_16 | SF_ENDIAN_BIG : + psf->endian = SF_ENDIAN_BIG ; + comm_type = AIFC_MARKER ; + comm_size = SIZEOF_AIFC_COMM ; + comm_encoding = twos_MARKER ; + break ; + + case SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE : + psf->endian = SF_ENDIAN_LITTLE ; + comm_type = AIFC_MARKER ; + comm_size = SIZEOF_AIFC_COMM ; + comm_encoding = sowt_MARKER ; + break ; + + case SF_FORMAT_PCM_24 | SF_ENDIAN_BIG : + psf->endian = SF_ENDIAN_BIG ; + comm_type = AIFC_MARKER ; + comm_size = SIZEOF_AIFC_COMM ; + comm_encoding = in24_MARKER ; + break ; + + case SF_FORMAT_PCM_24 | SF_ENDIAN_LITTLE : + psf->endian = SF_ENDIAN_LITTLE ; + comm_type = AIFC_MARKER ; + comm_size = SIZEOF_AIFC_COMM ; + comm_encoding = ni24_MARKER ; + break ; + + case SF_FORMAT_PCM_32 | SF_ENDIAN_BIG : + psf->endian = SF_ENDIAN_BIG ; + comm_type = AIFC_MARKER ; + comm_size = SIZEOF_AIFC_COMM ; + comm_encoding = in32_MARKER ; + break ; + + case SF_FORMAT_PCM_32 | SF_ENDIAN_LITTLE : + psf->endian = SF_ENDIAN_LITTLE ; + comm_type = AIFC_MARKER ; + comm_size = SIZEOF_AIFC_COMM ; + comm_encoding = ni32_MARKER ; + break ; + + case SF_FORMAT_PCM_S8 : /* SF_ENDIAN_FILE */ + case SF_FORMAT_PCM_16 : + case SF_FORMAT_PCM_24 : + case SF_FORMAT_PCM_32 : + psf->endian = SF_ENDIAN_BIG ; + comm_type = AIFF_MARKER ; + comm_size = SIZEOF_AIFF_COMM ; + comm_encoding = 0 ; + break ; + + case SF_FORMAT_FLOAT : /* Big endian floating point. */ + psf->endian = SF_ENDIAN_BIG ; + comm_type = AIFC_MARKER ; + comm_size = SIZEOF_AIFC_COMM ; + comm_encoding = FL32_MARKER ; /* Use 'FL32' because its easier to read. */ + break ; + + case SF_FORMAT_DOUBLE : /* Big endian double precision floating point. */ + psf->endian = SF_ENDIAN_BIG ; + comm_type = AIFC_MARKER ; + comm_size = SIZEOF_AIFC_COMM ; + comm_encoding = FL64_MARKER ; /* Use 'FL64' because its easier to read. */ + break ; + + case SF_FORMAT_ULAW : + psf->endian = SF_ENDIAN_BIG ; + comm_type = AIFC_MARKER ; + comm_size = SIZEOF_AIFC_COMM ; + comm_encoding = ulaw_MARKER ; + break ; + + case SF_FORMAT_ALAW : + psf->endian = SF_ENDIAN_BIG ; + comm_type = AIFC_MARKER ; + comm_size = SIZEOF_AIFC_COMM ; + comm_encoding = alaw_MARKER ; + break ; + + case SF_FORMAT_PCM_U8 : + psf->endian = SF_ENDIAN_BIG ; + comm_type = AIFC_MARKER ; + comm_size = SIZEOF_AIFC_COMM ; + comm_encoding = raw_MARKER ; + break ; + + case SF_FORMAT_DWVW_12 : + psf->endian = SF_ENDIAN_BIG ; + comm_type = AIFC_MARKER ; + comm_size = SIZEOF_AIFC_COMM ; + comm_encoding = DWVW_MARKER ; + + /* Override standard value here.*/ + bit_width = 12 ; + break ; + + case SF_FORMAT_DWVW_16 : + psf->endian = SF_ENDIAN_BIG ; + comm_type = AIFC_MARKER ; + comm_size = SIZEOF_AIFC_COMM ; + comm_encoding = DWVW_MARKER ; + + /* Override standard value here.*/ + bit_width = 16 ; + break ; + + case SF_FORMAT_DWVW_24 : + psf->endian = SF_ENDIAN_BIG ; + comm_type = AIFC_MARKER ; + comm_size = SIZEOF_AIFC_COMM ; + comm_encoding = DWVW_MARKER ; + + /* Override standard value here.*/ + bit_width = 24 ; + break ; + + case SF_FORMAT_GSM610 : + psf->endian = SF_ENDIAN_BIG ; + comm_type = AIFC_MARKER ; + comm_size = SIZEOF_AIFC_COMM ; + comm_encoding = GSM_MARKER ; + + /* Override standard value here.*/ + bit_width = 16 ; + break ; + + case SF_FORMAT_IMA_ADPCM : + psf->endian = SF_ENDIAN_BIG ; + comm_type = AIFC_MARKER ; + comm_size = SIZEOF_AIFC_COMM ; + comm_encoding = ima4_MARKER ; + + /* Override standard value here.*/ + bit_width = 16 ; + comm_frames = psf->sf.frames / AIFC_IMA4_SAMPLES_PER_BLOCK ; + break ; + + default : return SFE_BAD_OPEN_FORMAT ; + } ; + + /* Reset the current header length to zero. */ + psf->header.ptr [0] = 0 ; + psf->header.indx = 0 ; + psf_fseek (psf, 0, SEEK_SET) ; + + psf_binheader_writef (psf, "Etm8", BHWm (FORM_MARKER), BHW8 (psf->filelength - 8)) ; + + /* Write AIFF/AIFC marker and COM chunk. */ + if (comm_type == AIFC_MARKER) + /* AIFC must have an FVER chunk. */ + psf_binheader_writef (psf, "Emm44", BHWm (comm_type), BHWm (FVER_MARKER), BHW4 (4), BHW4 (0xA2805140)) ; + else + psf_binheader_writef (psf, "Em", BHWm (comm_type)) ; + + paiff->comm_offset = psf->header.indx - 8 ; + + memset (comm_sample_rate, 0, sizeof (comm_sample_rate)) ; + uint2tenbytefloat (psf->sf.samplerate, comm_sample_rate) ; + + psf_binheader_writef (psf, "Em42t42", BHWm (COMM_MARKER), BHW4 (comm_size), BHW2 (psf->sf.channels), BHW4 (comm_frames), BHW2 (bit_width)) ; + psf_binheader_writef (psf, "b", BHWv (comm_sample_rate), BHWz (sizeof (comm_sample_rate))) ; + + /* AIFC chunks have some extra data. */ + if (comm_type == AIFC_MARKER) + psf_binheader_writef (psf, "mb", BHWm (comm_encoding), BHWv (comm_zero_bytes), BHWz (sizeof (comm_zero_bytes))) ; + + if (psf->channel_map && paiff->chanmap_tag) + psf_binheader_writef (psf, "Em4444", BHWm (CHAN_MARKER), BHW4 (12), BHW4 (paiff->chanmap_tag), BHW4 (0), BHW4 (0)) ; + + /* Check if there's a INST chunk to write */ + if (psf->instrument != NULL && psf->cues != NULL) + { /* Huge chunk of code removed here because it had egregious errors that were + ** not detected by either the compiler or the tests. It was found when updating + ** the way psf_binheader_writef works. + */ + } + else if (psf->instrument == NULL && psf->cues != NULL) + { /* There are cues but no loops */ + uint32_t idx ; + int totalStringLength = 0, stringLength ; + + /* Here we count how many bytes will the pascal strings need */ + for (idx = 0 ; idx < psf->cues->cue_count ; idx++) + { stringLength = strlen (psf->cues->cue_points [idx].name) + 1 ; /* We'll count the first byte also of every pascal string */ + totalStringLength += stringLength + (stringLength % 2 == 0 ? 0 : 1) ; + } ; + + psf_binheader_writef (psf, "Em42", + BHWm (MARK_MARKER), BHW4 (2 + psf->cues->cue_count * (2 + 4) + totalStringLength), BHW2 (psf->cues->cue_count)) ; + + for (idx = 0 ; idx < psf->cues->cue_count ; idx++) + psf_binheader_writef (psf, "E24p", BHW2 (psf->cues->cue_points [idx].indx), BHW4 (psf->cues->cue_points [idx].sample_offset), BHWp (psf->cues->cue_points [idx].name)) ; + } ; + + if (psf->strings.flags & SF_STR_LOCATE_START) + aiff_write_strings (psf, SF_STR_LOCATE_START) ; + + if (psf->peak_info != NULL && psf->peak_info->peak_loc == SF_PEAK_START) + { psf_binheader_writef (psf, "Em4", BHWm (PEAK_MARKER), BHW4 (AIFF_PEAK_CHUNK_SIZE (psf->sf.channels))) ; + psf_binheader_writef (psf, "E44", BHW4 (1), BHW4 (time (NULL))) ; + for (k = 0 ; k < psf->sf.channels ; k++) + psf_binheader_writef (psf, "Eft8", BHWf ((float) psf->peak_info->peaks [k].value), BHW8 (psf->peak_info->peaks [k].position)) ; + } ; + + /* Write custom headers. */ + for (uk = 0 ; uk < psf->wchunks.used ; uk++) + psf_binheader_writef (psf, "Em4b", BHWm (psf->wchunks.chunks [uk].mark32), BHW4 (psf->wchunks.chunks [uk].len), BHWv (psf->wchunks.chunks [uk].data), BHWz (psf->wchunks.chunks [uk].len)) ; + + /* Write SSND chunk. */ + paiff->ssnd_offset = psf->header.indx ; + psf_binheader_writef (psf, "Etm844", BHWm (SSND_MARKER), BHW8 (psf->datalength + SIZEOF_SSND_CHUNK), BHW4 (0), BHW4 (0)) ; + + /* Header construction complete so write it out. */ + psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ; + + if (psf->error) + return psf->error ; + + if (has_data && psf->dataoffset != psf->header.indx) + return psf->error = SFE_INTERNAL ; + + psf->dataoffset = psf->header.indx ; + + if (! has_data) + psf_fseek (psf, psf->dataoffset, SEEK_SET) ; + else if (current > 0) + psf_fseek (psf, current, SEEK_SET) ; + + return psf->error ; +} /* aiff_write_header */ + +static int +aiff_write_tailer (SF_PRIVATE *psf) +{ int k ; + + /* Reset the current header length to zero. */ + psf->header.ptr [0] = 0 ; + psf->header.indx = 0 ; + + psf->dataend = psf_fseek (psf, 0, SEEK_END) ; + + /* Make sure tailer data starts at even byte offset. Pad if necessary. */ + if (psf->dataend % 2 == 1) + { psf_fwrite (psf->header.ptr, 1, 1, psf) ; + psf->dataend ++ ; + } ; + + if (psf->peak_info != NULL && psf->peak_info->peak_loc == SF_PEAK_END) + { psf_binheader_writef (psf, "Em4", BHWm (PEAK_MARKER), BHW4 (AIFF_PEAK_CHUNK_SIZE (psf->sf.channels))) ; + psf_binheader_writef (psf, "E44", BHW4 (1), BHW4 (time (NULL))) ; + for (k = 0 ; k < psf->sf.channels ; k++) + psf_binheader_writef (psf, "Eft8", BHWf ((float) psf->peak_info->peaks [k].value), BHW8 (psf->peak_info->peaks [k].position)) ; + } ; + + if (psf->strings.flags & SF_STR_LOCATE_END) + aiff_write_strings (psf, SF_STR_LOCATE_END) ; + + /* Write the tailer. */ + if (psf->header.indx > 0) + psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ; + + return 0 ; +} /* aiff_write_tailer */ + +static void +aiff_write_strings (SF_PRIVATE *psf, int location) +{ int k, slen ; + + for (k = 0 ; k < SF_MAX_STRINGS ; k++) + { if (psf->strings.data [k].type == 0) + break ; + + if (psf->strings.data [k].flags != location) + continue ; + + switch (psf->strings.data [k].type) + { case SF_STR_SOFTWARE : + slen = strlen (psf->strings.storage + psf->strings.data [k].offset) ; + psf_binheader_writef (psf, "Em4mb", BHWm (APPL_MARKER), BHW4 (slen + 4), BHWm (m3ga_MARKER), BHWv (psf->strings.storage + psf->strings.data [k].offset), BHWz (slen + (slen & 1))) ; + break ; + + case SF_STR_TITLE : + psf_binheader_writef (psf, "EmS", BHWm (NAME_MARKER), BHWS (psf->strings.storage + psf->strings.data [k].offset)) ; + break ; + + case SF_STR_COPYRIGHT : + psf_binheader_writef (psf, "EmS", BHWm (c_MARKER), BHWS (psf->strings.storage + psf->strings.data [k].offset)) ; + break ; + + case SF_STR_ARTIST : + psf_binheader_writef (psf, "EmS", BHWm (AUTH_MARKER), BHWS (psf->strings.storage + psf->strings.data [k].offset)) ; + break ; + + case SF_STR_COMMENT : + psf_binheader_writef (psf, "EmS", BHWm (ANNO_MARKER), BHWS (psf->strings.storage + psf->strings.data [k].offset)) ; + break ; + + /* + case SF_STR_DATE : + psf_binheader_writef (psf, "Ems", BHWm (ICRD_MARKER), BHWs (psf->strings.data [k].str)) ; + break ; + */ + } ; + } ; + + return ; +} /* aiff_write_strings */ + +static int +aiff_command (SF_PRIVATE * psf, int command, void * UNUSED (data), int UNUSED (datasize)) +{ AIFF_PRIVATE *paiff ; + + if ((paiff = psf->container_data) == NULL) + return SFE_INTERNAL ; + + switch (command) + { case SFC_SET_CHANNEL_MAP_INFO : + paiff->chanmap_tag = aiff_caf_find_channel_layout_tag (psf->channel_map, psf->sf.channels) ; + return (paiff->chanmap_tag != 0) ; + + default : + break ; + } ; + + return 0 ; +} /* aiff_command */ + +static const char* +get_loop_mode_str (int16_t mode) +{ switch (mode) + { case 0 : return "none" ; + case 1 : return "forward" ; + case 2 : return "backward" ; + } ; + + return "*** unknown" ; +} /* get_loop_mode_str */ + +static int16_t +get_loop_mode (int16_t mode) +{ switch (mode) + { case 0 : return SF_LOOP_NONE ; + case 1 : return SF_LOOP_FORWARD ; + case 2 : return SF_LOOP_BACKWARD ; + } ; + + return SF_LOOP_NONE ; +} /* get_loop_mode */ + +/*========================================================================================== +** Rough hack at converting from 80 bit IEEE float in AIFF header to an int and +** back again. It assumes that all sample rates are between 1 and 800MHz, which +** should be OK as other sound file formats use a 32 bit integer to store sample +** rate. +** There is another (probably better) version in the source code to the SoX but it +** has a copyright which probably prevents it from being allowable as GPL/LGPL. +*/ + +static int +tenbytefloat2int (uint8_t *bytes) +{ int val = 3 ; + + if (bytes [0] & 0x80) /* Negative number. */ + return 0 ; + + if (bytes [0] <= 0x3F) /* Less than 1. */ + return 1 ; + + if (bytes [0] > 0x40) /* Way too big. */ + return 0x4000000 ; + + if (bytes [0] == 0x40 && bytes [1] > 0x1C) /* Too big. */ + return 800000000 ; + + /* Ok, can handle it. */ + + val = (bytes [2] << 23) | (bytes [3] << 15) | (bytes [4] << 7) | (bytes [5] >> 1) ; + + val >>= (29 - bytes [1]) ; + + return val ; +} /* tenbytefloat2int */ + +static void +uint2tenbytefloat (uint32_t num, uint8_t *bytes) +{ uint32_t mask = 0x40000000 ; + int count ; + + if (num <= 1) + { bytes [0] = 0x3F ; + bytes [1] = 0xFF ; + bytes [2] = 0x80 ; + return ; + } ; + + bytes [0] = 0x40 ; + + if (num >= mask) + { bytes [1] = 0x1D ; + return ; + } ; + + for (count = 0 ; count < 32 ; count ++) + { if (num & mask) + break ; + mask >>= 1 ; + } ; + + num = count < 31 ? num << (count + 1) : 0 ; + bytes [1] = 29 - count ; + bytes [2] = (num >> 24) & 0xFF ; + bytes [3] = (num >> 16) & 0xFF ; + bytes [4] = (num >> 8) & 0xFF ; + bytes [5] = num & 0xFF ; + +} /* uint2tenbytefloat */ + +static int +aiff_read_basc_chunk (SF_PRIVATE * psf, int datasize) +{ const char * type_str ; + basc_CHUNK bc ; + int count ; + + count = psf_binheader_readf (psf, "E442", &bc.version, &bc.numBeats, &bc.rootNote) ; + count += psf_binheader_readf (psf, "E222", &bc.scaleType, &bc.sigNumerator, &bc.sigDenominator) ; + count += psf_binheader_readf (psf, "E2j", &bc.loopType, datasize - sizeof (bc)) ; + + psf_log_printf (psf, " Version ? : %u\n Num Beats : %u\n Root Note : 0x%x\n", + bc.version, bc.numBeats, bc.rootNote) ; + + switch (bc.scaleType) + { case basc_SCALE_MINOR : + type_str = "MINOR" ; + break ; + case basc_SCALE_MAJOR : + type_str = "MAJOR" ; + break ; + case basc_SCALE_NEITHER : + type_str = "NEITHER" ; + break ; + case basc_SCALE_BOTH : + type_str = "BOTH" ; + break ; + default : + type_str = "!!WRONG!!" ; + break ; + } ; + + psf_log_printf (psf, " ScaleType : 0x%x (%s)\n", bc.scaleType, type_str) ; + psf_log_printf (psf, " Time Sig : %d/%d\n", bc.sigNumerator, bc.sigDenominator) ; + + switch (bc.loopType) + { case basc_TYPE_ONE_SHOT : + type_str = "One Shot" ; + break ; + case basc_TYPE_LOOP : + type_str = "Loop" ; + break ; + default: + type_str = "!!WRONG!!" ; + break ; + } ; + + psf_log_printf (psf, " Loop Type : 0x%x (%s)\n", bc.loopType, type_str) ; + + if (psf->loop_info) + { psf_log_printf (psf, " Found existing loop info, using last one.\n") ; + free (psf->loop_info) ; + psf->loop_info = NULL ; + } ; + if ((psf->loop_info = calloc (1, sizeof (SF_LOOP_INFO))) == NULL) + return SFE_MALLOC_FAILED ; + + psf->loop_info->time_sig_num = bc.sigNumerator ; + psf->loop_info->time_sig_den = bc.sigDenominator ; + psf->loop_info->loop_mode = (bc.loopType == basc_TYPE_ONE_SHOT) ? SF_LOOP_NONE : SF_LOOP_FORWARD ; + psf->loop_info->num_beats = bc.numBeats ; + + /* Can always be recalculated from other known fields. */ + psf->loop_info->bpm = (1.0 / psf->sf.frames) * psf->sf.samplerate + * ((bc.numBeats * 4.0) / bc.sigDenominator) * 60.0 ; + psf->loop_info->root_key = bc.rootNote ; + + if (count < datasize) + psf_binheader_readf (psf, "j", datasize - count) ; + + return 0 ; +} /* aiff_read_basc_chunk */ + + +static int +aiff_read_chanmap (SF_PRIVATE * psf, unsigned dword) +{ const AIFF_CAF_CHANNEL_MAP * map_info ; + unsigned channel_bitmap, channel_decriptions, bytesread ; + int layout_tag ; + + bytesread = psf_binheader_readf (psf, "444", &layout_tag, &channel_bitmap, &channel_decriptions) ; + + if ((map_info = aiff_caf_of_channel_layout_tag (layout_tag)) == NULL) + return 0 ; + + psf_log_printf (psf, " Tag : %x\n", layout_tag) ; + if (map_info) + psf_log_printf (psf, " Layout : %s\n", map_info->name) ; + + if (bytesread < dword) + psf_binheader_readf (psf, "j", dword - bytesread) ; + + if (map_info->channel_map != NULL) + { size_t chanmap_size = SF_MIN (psf->sf.channels, layout_tag & 0xffff) * sizeof (psf->channel_map [0]) ; + + free (psf->channel_map) ; + + if ((psf->channel_map = malloc (chanmap_size)) == NULL) + return SFE_MALLOC_FAILED ; + + memcpy (psf->channel_map, map_info->channel_map, chanmap_size) ; + } ; + + return 0 ; +} /* aiff_read_chanmap */ + +/*============================================================================== +*/ + +static int +aiff_set_chunk (SF_PRIVATE *psf, const SF_CHUNK_INFO * chunk_info) +{ return psf_save_write_chunk (&psf->wchunks, chunk_info) ; +} /* aiff_set_chunk */ + +static SF_CHUNK_ITERATOR * +aiff_next_chunk_iterator (SF_PRIVATE *psf, SF_CHUNK_ITERATOR * iterator) +{ return psf_next_chunk_iterator (&psf->rchunks, iterator) ; +} /* aiff_next_chunk_iterator */ + +static int +aiff_get_chunk_size (SF_PRIVATE *psf, const SF_CHUNK_ITERATOR * iterator, SF_CHUNK_INFO * chunk_info) +{ int indx ; + + if ((indx = psf_find_read_chunk_iterator (&psf->rchunks, iterator)) < 0) + return SFE_UNKNOWN_CHUNK ; + + chunk_info->datalen = psf->rchunks.chunks [indx].len ; + + return SFE_NO_ERROR ; +} /* aiff_get_chunk_size */ + +static int +aiff_get_chunk_data (SF_PRIVATE *psf, const SF_CHUNK_ITERATOR * iterator, SF_CHUNK_INFO * chunk_info) +{ sf_count_t pos ; + int indx ; + + if ((indx = psf_find_read_chunk_iterator (&psf->rchunks, iterator)) < 0) + return SFE_UNKNOWN_CHUNK ; + + if (chunk_info->data == NULL) + return SFE_BAD_CHUNK_DATA_PTR ; + + chunk_info->id_size = psf->rchunks.chunks [indx].id_size ; + memcpy (chunk_info->id, psf->rchunks.chunks [indx].id, sizeof (chunk_info->id) / sizeof (*chunk_info->id)) ; + + pos = psf_ftell (psf) ; + psf_fseek (psf, psf->rchunks.chunks [indx].offset, SEEK_SET) ; + psf_fread (chunk_info->data, SF_MIN (chunk_info->datalen, psf->rchunks.chunks [indx].len), 1, psf) ; + psf_fseek (psf, pos, SEEK_SET) ; + + return SFE_NO_ERROR ; +} /* aiff_get_chunk_data */ diff --git a/extern/libsndfile-modified/src/alac.c b/extern/libsndfile-modified/src/alac.c new file mode 100644 index 000000000..a6668f367 --- /dev/null +++ b/extern/libsndfile-modified/src/alac.c @@ -0,0 +1,999 @@ +/* +** Copyright (C) 2011-2016 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" +#include "ALAC/alac_codec.h" +#include "ALAC/ALACBitUtilities.h" + +#define ALAC_MAX_FRAME_SIZE 8192 +#define ALAC_BYTE_BUFFER_SIZE 0x20000 +#define ALAC_MAX_CHANNEL_COUNT 8 // Same as kALACMaxChannels in /ALACAudioTypes.h + +typedef struct +{ uint32_t current, count, allocated ; + uint32_t packet_size [] ; +} PAKT_INFO ; + +typedef struct +{ sf_count_t input_data_pos ; + + PAKT_INFO * pakt_info ; + + int channels, final_write_block ; + + uint32_t frames_this_block, partial_block_frames, frames_per_block ; + uint32_t bits_per_sample, kuki_size ; + + + /* Can't have a decoder and an encoder at the same time so stick + ** them in a union. + */ + union + { ALAC_DECODER decoder ; + ALAC_ENCODER encoder ; + } u ; + + char enctmpname [512] ; + FILE *enctmp ; + + uint8_t byte_buffer [ALAC_MAX_CHANNEL_COUNT * ALAC_BYTE_BUFFER_SIZE] ; + + int buffer [] ; + +} ALAC_PRIVATE ; + +/*============================================================================================ +*/ + +static int alac_reader_init (SF_PRIVATE *psf, const ALAC_DECODER_INFO * info) ; +static int alac_writer_init (SF_PRIVATE *psf) ; + +static sf_count_t alac_reader_calc_frames (SF_PRIVATE *psf, ALAC_PRIVATE *plac) ; + +static sf_count_t alac_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; +static sf_count_t alac_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; +static sf_count_t alac_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; +static sf_count_t alac_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; + +static sf_count_t alac_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; +static sf_count_t alac_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; +static sf_count_t alac_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; +static sf_count_t alac_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; + +static sf_count_t alac_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ; + +static int alac_close (SF_PRIVATE *psf) ; +static int alac_byterate (SF_PRIVATE *psf) ; + +static int alac_decode_block (SF_PRIVATE *psf, ALAC_PRIVATE *plac) ; +static int alac_encode_block (ALAC_PRIVATE *plac) ; + +static uint32_t alac_kuki_read (SF_PRIVATE * psf, uint32_t kuki_offset, uint8_t * kuki, size_t kuki_maxlen) ; + +static PAKT_INFO * alac_pakt_alloc (uint32_t initial_count) ; +static PAKT_INFO * alac_pakt_read_decode (SF_PRIVATE * psf, uint32_t pakt_offset) ; +static PAKT_INFO * alac_pakt_append (PAKT_INFO * info, uint32_t value) ; +static uint8_t * alac_pakt_encode (const SF_PRIVATE *psf, uint32_t * pakt_size) ; +static sf_count_t alac_pakt_block_offset (const PAKT_INFO *info, uint32_t block) ; + +static const char * alac_error_string (int error) ; + +/*============================================================================================ +** ALAC Reader initialisation function. +*/ + +int +alac_init (SF_PRIVATE *psf, const ALAC_DECODER_INFO * info) +{ int error ; + + if ((psf->codec_data = calloc (1, sizeof (ALAC_PRIVATE) + psf->sf.channels * sizeof (int) * ALAC_MAX_FRAME_SIZE)) == NULL) + return SFE_MALLOC_FAILED ; + + psf->codec_close = alac_close ; + + switch (psf->file.mode) + { case SFM_RDWR : + return SFE_BAD_MODE_RW ; + + case SFM_READ : + if ((error = alac_reader_init (psf, info))) + return error ; + break ; + + case SFM_WRITE : + if ((error = alac_writer_init (psf))) + return error ; + break ; + + default : + psf_log_printf (psf, "%s : Bad psf->file.mode.\n", __func__) ; + return SFE_INTERNAL ; + } ; + + psf->byterate = alac_byterate ; + + return 0 ; +} /* aiff_alac_init */ + +void +alac_get_desc_chunk_items (int subformat, uint32_t *fmt_flags, uint32_t *frames_per_packet) +{ switch (subformat) + { case SF_FORMAT_ALAC_16 : + *fmt_flags = 1 ; + break ; + case SF_FORMAT_ALAC_20 : + *fmt_flags = 2 ; + break ; + case SF_FORMAT_ALAC_24 : + *fmt_flags = 3 ; + break ; + case SF_FORMAT_ALAC_32 : + *fmt_flags = 4 ; + break ; + default : + break ; + } ; + *frames_per_packet = ALAC_FRAME_LENGTH ; +} /* alac_get_desc_chunk_items */ + +static int +alac_close (SF_PRIVATE *psf) +{ ALAC_PRIVATE *plac ; + BUF_UNION ubuf ; + + plac = psf->codec_data ; + + if (psf->file.mode == SFM_WRITE) + { ALAC_ENCODER *penc = &plac->u.encoder ; + SF_CHUNK_INFO chunk_info ; + sf_count_t readcount ; + uint8_t kuki_data [1024] ; + uint32_t pakt_size = 0, saved_partial_block_frames ; + + plac->final_write_block = 1 ; + saved_partial_block_frames = plac->partial_block_frames ; + + /* If a block has been partially assembled, write it out as the final block. */ + if (plac->partial_block_frames && plac->partial_block_frames < plac->frames_per_block) + alac_encode_block (plac) ; + + plac->partial_block_frames = saved_partial_block_frames ; + + alac_get_magic_cookie (penc, kuki_data, &plac->kuki_size) ; + + memset (&chunk_info, 0, sizeof (chunk_info)) ; + chunk_info.id_size = snprintf (chunk_info.id, sizeof (chunk_info.id), "kuki") ; + chunk_info.data = kuki_data ; + chunk_info.datalen = plac->kuki_size ; + psf_save_write_chunk (&psf->wchunks, &chunk_info) ; + + memset (&chunk_info, 0, sizeof (chunk_info)) ; + chunk_info.id_size = snprintf (chunk_info.id, sizeof (chunk_info.id), "pakt") ; + chunk_info.data = alac_pakt_encode (psf, &pakt_size) ; + chunk_info.datalen = pakt_size ; + psf_save_write_chunk (&psf->wchunks, &chunk_info) ; + + free (chunk_info.data) ; + chunk_info.data = NULL ; + + psf->write_header (psf, 1) ; + + if (plac->enctmp != NULL) + { fseek (plac->enctmp, 0, SEEK_SET) ; + + while ((readcount = fread (ubuf.ucbuf, 1, sizeof (ubuf.ucbuf), plac->enctmp)) > 0) + psf_fwrite (ubuf.ucbuf, 1, readcount, psf) ; + fclose (plac->enctmp) ; + remove (plac->enctmpname) ; + } ; + } ; + + if (plac->pakt_info) + free (plac->pakt_info) ; + plac->pakt_info = NULL ; + + return 0 ; +} /* alac_close */ + +static int +alac_byterate (SF_PRIVATE *psf) +{ + if (psf->file.mode == SFM_READ) + return (psf->datalength * psf->sf.samplerate) / psf->sf.frames ; + + return -1 ; +} /* alac_byterate */ + +/*============================================================================================ +** ALAC initialisation Functions. +*/ + +static int +alac_reader_init (SF_PRIVATE *psf, const ALAC_DECODER_INFO * info) +{ ALAC_PRIVATE *plac ; + uint32_t kuki_size ; + int error ; + union { uint8_t kuki [512] ; uint32_t alignment ; } u ; + + if (info == NULL) + { psf_log_printf (psf, "%s : ALAC_DECODER_INFO is NULL.\n", __func__) ; + return SFE_INTERNAL ; + } ; + + if (info->frames_per_packet > ALAC_FRAME_LENGTH) + { psf_log_printf (psf, "*** Error : frames_per_packet (%u) is too big. ***\n", info->frames_per_packet) ; + return SFE_INTERNAL ; + } ; + + plac = psf->codec_data ; + + plac->channels = psf->sf.channels ; + plac->frames_per_block = info->frames_per_packet ; + plac->bits_per_sample = info->bits_per_sample ; + + if (plac->pakt_info != NULL) + free (plac->pakt_info) ; + plac->pakt_info = alac_pakt_read_decode (psf, info->pakt_offset) ; + + if (plac->pakt_info == NULL) + { psf_log_printf (psf, "%s : alac_pkt_read() returns NULL.\n", __func__) ; + return SFE_INTERNAL ; + } ; + + /* Read in the ALAC cookie data and pass it to the init function. */ + kuki_size = alac_kuki_read (psf, info->kuki_offset, u.kuki, sizeof (u.kuki)) ; + + if ((error = alac_decoder_init (&plac->u.decoder, u.kuki, kuki_size)) != ALAC_noErr) + { psf_log_printf (psf, "*** alac_decoder_init() returned %s. ***\n", alac_error_string (error)) ; + return SFE_INTERNAL ; + } ; + + + if (plac->u.decoder.mNumChannels != (unsigned) psf->sf.channels) + { psf_log_printf (psf, "*** Initialized decoder has %u channels, but it should be %d. ***\n", plac->u.decoder.mNumChannels, psf->sf.channels) ; + return SFE_INTERNAL ; + } ; + + switch (info->bits_per_sample) + { case 16 : + case 20 : + case 24 : + case 32 : + psf->read_short = alac_read_s ; + psf->read_int = alac_read_i ; + psf->read_float = alac_read_f ; + psf->read_double = alac_read_d ; + break ; + + default : + printf ("%s : info->bits_per_sample %u\n", __func__, info->bits_per_sample) ; + return SFE_UNSUPPORTED_ENCODING ; + } ; + + psf->codec_close = alac_close ; + psf->seek = alac_seek ; + + psf->sf.frames = alac_reader_calc_frames (psf, plac) ; + alac_seek (psf, SFM_READ, 0) ; + + return 0 ; +} /* alac_reader_init */ + +static int +alac_writer_init (SF_PRIVATE *psf) +{ ALAC_PRIVATE *plac ; + uint32_t alac_format_flags = 0 ; + + plac = psf->codec_data ; + + if (psf->file.mode != SFM_WRITE) + return SFE_BAD_MODE_RW ; + + plac->channels = psf->sf.channels ; + plac->kuki_size = alac_get_magic_cookie_size (psf->sf.channels) ; + + psf->write_short = alac_write_s ; + psf->write_int = alac_write_i ; + psf->write_float = alac_write_f ; + psf->write_double = alac_write_d ; + + switch (SF_CODEC (psf->sf.format)) + { case SF_FORMAT_ALAC_16 : + alac_format_flags = 1 ; + plac->bits_per_sample = 16 ; + break ; + + case SF_FORMAT_ALAC_20 : + alac_format_flags = 2 ; + plac->bits_per_sample = 20 ; + break ; + + case SF_FORMAT_ALAC_24 : + alac_format_flags = 3 ; + plac->bits_per_sample = 24 ; + break ; + + case SF_FORMAT_ALAC_32 : + alac_format_flags = 4 ; + plac->bits_per_sample = 32 ; + break ; + + default : + psf_log_printf (psf, "%s : Can't figure out bits per sample.\n", __func__) ; + return SFE_UNIMPLEMENTED ; + } ; + + plac->frames_per_block = ALAC_FRAME_LENGTH ; + + plac->pakt_info = alac_pakt_alloc (2000) ; + + if ((plac->enctmp = psf_open_tmpfile (plac->enctmpname, sizeof (plac->enctmpname))) == NULL) + { psf_log_printf (psf, "Error : Failed to open temp file '%s' : \n", plac->enctmpname, strerror (errno)) ; + return SFE_ALAC_FAIL_TMPFILE ; + } ; + + alac_encoder_init (&plac->u.encoder, psf->sf.samplerate, psf->sf.channels, alac_format_flags, ALAC_FRAME_LENGTH) ; + + return 0 ; +} /* alac_writer_init */ + +/*============================================================================================ +** ALAC block decoder and encoder. +*/ + +static inline uint32_t +alac_reader_next_packet_size (PAKT_INFO * info) +{ if (info->current >= info->count) + return 0 ; + return info->packet_size [info->current++] ; +} /* alac_reader_next_packet_size */ + +static sf_count_t +alac_reader_calc_frames (SF_PRIVATE *psf, ALAC_PRIVATE *plac) +{ sf_count_t frames = 0 ; + uint32_t current_pos = 1, blocks = 0 ; + + plac->pakt_info->current = 0 ; + + while (current_pos < psf->filelength && current_pos > 0) + { current_pos = alac_reader_next_packet_size (plac->pakt_info) ; + blocks = current_pos > 0 ? blocks + 1 : blocks ; + } ; + + if (blocks == 0) + return 0 ; + + /* Only count full blocks. */ + frames = plac->frames_per_block * (blocks - 1) ; + + alac_seek (psf, SFM_READ, frames) ; + alac_decode_block (psf, plac) ; + frames += plac->frames_this_block ; + + plac->pakt_info->current = 0 ; + + return frames ; +} /* alac_reader_calc_frames */ + +static int +alac_decode_block (SF_PRIVATE *psf, ALAC_PRIVATE *plac) +{ ALAC_DECODER *pdec = &plac->u.decoder ; + uint32_t packet_size ; + BitBuffer bit_buffer ; + + packet_size = alac_reader_next_packet_size (plac->pakt_info) ; + if (packet_size == 0) + { if (plac->pakt_info->current < plac->pakt_info->count) + psf_log_printf (psf, "packet_size is 0 (%d of %d)\n", plac->pakt_info->current, plac->pakt_info->count) ; + return 0 ; + } ; + + psf_fseek (psf, plac->input_data_pos, SEEK_SET) ; + + if (packet_size > sizeof (plac->byte_buffer)) + { psf_log_printf (psf, "%s : bad packet_size (%u)\n", __func__, packet_size) ; + return 0 ; + } ; + + if ((packet_size != psf_fread (plac->byte_buffer, 1, packet_size, psf))) + return 0 ; + + BitBufferInit (&bit_buffer, plac->byte_buffer, packet_size) ; + + plac->input_data_pos += packet_size ; + plac->frames_this_block = 0 ; + alac_decode (pdec, &bit_buffer, plac->buffer, plac->frames_per_block, &plac->frames_this_block) ; + + plac->partial_block_frames = 0 ; + + return 1 ; +} /* alac_decode_block */ + + +static int +alac_encode_block (ALAC_PRIVATE *plac) +{ ALAC_ENCODER *penc = &plac->u.encoder ; + uint32_t num_bytes = 0 ; + + alac_encode (penc, plac->partial_block_frames, plac->buffer, plac->byte_buffer, &num_bytes) ; + + if (fwrite (plac->byte_buffer, 1, num_bytes, plac->enctmp) != num_bytes) + return 0 ; + if ((plac->pakt_info = alac_pakt_append (plac->pakt_info, num_bytes)) == NULL) + return 0 ; + + plac->partial_block_frames = 0 ; + + return 1 ; +} /* alac_encode_block */ + +/*============================================================================================ +** ALAC read functions. +*/ + +static sf_count_t +alac_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) +{ ALAC_PRIVATE *plac ; + int *iptr ; + int k, readcount ; + sf_count_t total = 0 ; + + if ((plac = (ALAC_PRIVATE*) psf->codec_data) == NULL) + return 0 ; + + while (len > 0) + { if (plac->partial_block_frames >= plac->frames_this_block && alac_decode_block (psf, plac) == 0) + break ; + + readcount = (plac->frames_this_block - plac->partial_block_frames) * plac->channels ; + readcount = readcount > len ? (int) len : readcount ; + + iptr = plac->buffer + plac->partial_block_frames * plac->channels ; + + for (k = 0 ; k < readcount ; k++) + ptr [total + k] = iptr [k] >> 16 ; + + plac->partial_block_frames += readcount / plac->channels ; + total += readcount ; + len -= readcount ; + } ; + + return total ; +} /* alac_read_s */ + +static sf_count_t +alac_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) +{ ALAC_PRIVATE *plac ; + int *iptr ; + int k, readcount ; + sf_count_t total = 0 ; + + if ((plac = (ALAC_PRIVATE*) psf->codec_data) == NULL) + return 0 ; + + while (len > 0) + { if (plac->partial_block_frames >= plac->frames_this_block && alac_decode_block (psf, plac) == 0) + break ; + + readcount = (plac->frames_this_block - plac->partial_block_frames) * plac->channels ; + readcount = readcount > len ? (int) len : readcount ; + + iptr = plac->buffer + plac->partial_block_frames * plac->channels ; + + for (k = 0 ; k < readcount ; k++) + ptr [total + k] = iptr [k] ; + + plac->partial_block_frames += readcount / plac->channels ; + total += readcount ; + len -= readcount ; + } ; + + return total ; +} /* alac_read_i */ + +static sf_count_t +alac_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) +{ ALAC_PRIVATE *plac ; + int *iptr ; + int k, readcount ; + sf_count_t total = 0 ; + float normfact ; + + if ((plac = (ALAC_PRIVATE*) psf->codec_data) == NULL) + return 0 ; + + normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x80000000) : 1.0 ; + + while (len > 0) + { if (plac->partial_block_frames >= plac->frames_this_block && alac_decode_block (psf, plac) == 0) + break ; + + readcount = (plac->frames_this_block - plac->partial_block_frames) * plac->channels ; + readcount = readcount > len ? (int) len : readcount ; + + iptr = plac->buffer + plac->partial_block_frames * plac->channels ; + + for (k = 0 ; k < readcount ; k++) + ptr [total + k] = normfact * iptr [k] ; + + plac->partial_block_frames += readcount / plac->channels ; + total += readcount ; + len -= readcount ; + } ; + + return total ; +} /* alac_read_f */ + +static sf_count_t +alac_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) +{ ALAC_PRIVATE *plac ; + int *iptr ; + int k, readcount ; + sf_count_t total = 0 ; + double normfact ; + + if ((plac = (ALAC_PRIVATE*) psf->codec_data) == NULL) + return 0 ; + + normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((float) 0x80000000) : 1.0 ; + + while (len > 0) + { if (plac->partial_block_frames >= plac->frames_this_block && alac_decode_block (psf, plac) == 0) + break ; + + readcount = (plac->frames_this_block - plac->partial_block_frames) * plac->channels ; + readcount = readcount > len ? (int) len : readcount ; + + iptr = plac->buffer + plac->partial_block_frames * plac->channels ; + + for (k = 0 ; k < readcount ; k++) + ptr [total + k] = normfact * iptr [k] ; + + plac->partial_block_frames += readcount / plac->channels ; + total += readcount ; + len -= readcount ; + } ; + + return total ; +} /* alac_read_d */ + +/*============================================================================================ +*/ + +static sf_count_t +alac_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) +{ ALAC_PRIVATE *plac ; + int newblock, newsample ; + + if (! psf->codec_data) + return 0 ; + plac = (ALAC_PRIVATE*) psf->codec_data ; + + if (psf->datalength < 0 || psf->dataoffset < 0) + { psf->error = SFE_BAD_SEEK ; + return PSF_SEEK_ERROR ; + } ; + + if (offset == 0) + { psf_fseek (psf, psf->dataoffset, SEEK_SET) ; + + plac->frames_this_block = 0 ; + plac->input_data_pos = psf->dataoffset ; + plac->pakt_info->current = 0 ; + return 0 ; + } ; + + if (offset < 0 || offset > plac->pakt_info->count * plac->frames_per_block) + { psf->error = SFE_BAD_SEEK ; + return PSF_SEEK_ERROR ; + } ; + + newblock = offset / plac->frames_per_block ; + newsample = offset % plac->frames_per_block ; + + if (mode == SFM_READ) + { plac->input_data_pos = psf->dataoffset + alac_pakt_block_offset (plac->pakt_info, newblock) ; + + plac->pakt_info->current = newblock ; + alac_decode_block (psf, plac) ; + plac->partial_block_frames = newsample ; + } + else + { /* What to do about write??? */ + psf->error = SFE_BAD_SEEK ; + return PSF_SEEK_ERROR ; + } ; + + return newblock * plac->frames_per_block + newsample ; +} /* alac_seek */ + +/*========================================================================================== +** ALAC Write Functions. +*/ + +static sf_count_t +alac_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) +{ ALAC_PRIVATE *plac ; + int *iptr ; + int k, writecount ; + sf_count_t total = 0 ; + + if ((plac = (ALAC_PRIVATE*) psf->codec_data) == NULL) + return 0 ; + + while (len > 0) + { writecount = (plac->frames_per_block - plac->partial_block_frames) * plac->channels ; + writecount = (writecount == 0 || writecount > len) ? (int) len : writecount ; + + iptr = plac->buffer + plac->partial_block_frames * plac->channels ; + + for (k = 0 ; k < writecount ; k++) + iptr [k] = arith_shift_left (ptr [k], 16) ; + + plac->partial_block_frames += writecount / plac->channels ; + total += writecount ; + len -= writecount ; + ptr += writecount ; + + if (plac->partial_block_frames >= plac->frames_per_block) + alac_encode_block (plac) ; + } ; + + return total ; +} /* alac_write_s */ + +static sf_count_t +alac_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) +{ ALAC_PRIVATE *plac ; + int *iptr ; + int k, writecount ; + sf_count_t total = 0 ; + + if ((plac = (ALAC_PRIVATE*) psf->codec_data) == NULL) + return 0 ; + + while (len > 0) + { writecount = (plac->frames_per_block - plac->partial_block_frames) * plac->channels ; + writecount = (writecount == 0 || writecount > len) ? (int) len : writecount ; + + iptr = plac->buffer + plac->partial_block_frames * plac->channels ; + + for (k = 0 ; k < writecount ; k++) + iptr [k] = ptr [k] ; + + plac->partial_block_frames += writecount / plac->channels ; + total += writecount ; + len -= writecount ; + ptr += writecount ; + + if (plac->partial_block_frames >= plac->frames_per_block) + alac_encode_block (plac) ; + } ; + + return total ; +} /* alac_write_i */ + +static sf_count_t +alac_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) +{ ALAC_PRIVATE *plac ; + void (*convert) (const float *, int *t, int, int) ; + int *iptr ; + int writecount ; + sf_count_t total = 0 ; + + if ((plac = (ALAC_PRIVATE*) psf->codec_data) == NULL) + return 0 ; + + convert = (psf->add_clipping) ? psf_f2i_clip_array : psf_f2i_array ; + + while (len > 0) + { writecount = (plac->frames_per_block - plac->partial_block_frames) * plac->channels ; + writecount = (writecount == 0 || writecount > len) ? (int) len : writecount ; + + iptr = plac->buffer + plac->partial_block_frames * plac->channels ; + + convert (ptr, iptr, writecount, psf->norm_float) ; + + plac->partial_block_frames += writecount / plac->channels ; + total += writecount ; + len -= writecount ; + ptr += writecount ; + + if (plac->partial_block_frames >= plac->frames_per_block) + alac_encode_block (plac) ; + } ; + + return total ; +} /* alac_write_f */ + +static sf_count_t +alac_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) +{ ALAC_PRIVATE *plac ; + void (*convert) (const double *, int *t, int, int) ; + int *iptr ; + int writecount ; + sf_count_t total = 0 ; + + if ((plac = (ALAC_PRIVATE*) psf->codec_data) == NULL) + return 0 ; + + convert = (psf->add_clipping) ? psf_d2i_clip_array : psf_d2i_array ; + + while (len > 0) + { writecount = (plac->frames_per_block - plac->partial_block_frames) * plac->channels ; + writecount = (writecount == 0 || writecount > len) ? (int) len : writecount ; + + iptr = plac->buffer + plac->partial_block_frames * plac->channels ; + + convert (ptr, iptr, writecount, psf->norm_float) ; + + plac->partial_block_frames += writecount / plac->channels ; + total += writecount ; + len -= writecount ; + ptr += writecount ; + + if (plac->partial_block_frames >= plac->frames_per_block) + alac_encode_block (plac) ; + } ; + + return total ; +} /* alac_write_d */ + +/*============================================================================== +** PAKT_INFO handling. +*/ + +static PAKT_INFO * +alac_pakt_alloc (uint32_t initial_count) +{ PAKT_INFO * info ; + + if ((info = calloc (1, sizeof (PAKT_INFO) + initial_count * sizeof (info->packet_size [0]))) == NULL) + return NULL ; + + info->allocated = initial_count ; + info->current = 0 ; + info->count = 0 ; + + return info ; +} /* alac_pakt_alloc */ + +static PAKT_INFO * +alac_pakt_append (PAKT_INFO * info, uint32_t value) +{ + if (info->count >= info->allocated) + { PAKT_INFO * temp ; + uint32_t newcount = info->allocated + info->allocated / 2 ; + + if ((temp = realloc (info, sizeof (PAKT_INFO) + newcount * sizeof (info->packet_size [0]))) == NULL) + return NULL ; + + info = temp ; + info->allocated = newcount ; + } ; + + info->packet_size [info->count++] = value ; + return info ; +} /* alac_pakt_append */ + +static PAKT_INFO * +alac_pakt_read_decode (SF_PRIVATE * psf, uint32_t UNUSED (pakt_offset)) +{ SF_CHUNK_INFO chunk_info ; + PAKT_INFO * info = NULL ; + uint8_t *pakt_data = NULL ; + uint32_t bcount, value = 1, pakt_size ; + SF_CHUNK_ITERATOR * chunk_iterator ; + + + memset (&chunk_info, 0, sizeof (chunk_info)) ; + snprintf (chunk_info.id, sizeof (chunk_info.id), "pakt") ; + chunk_info.id_size = 4 ; + + if ((chunk_iterator = psf_get_chunk_iterator (psf, chunk_info.id)) == NULL) + { psf_log_printf (psf, "%s : no chunk iterator found\n", __func__) ; + free (chunk_info.data) ; + chunk_info.data = NULL ; + return NULL ; + } ; + + psf->get_chunk_size (psf, chunk_iterator, &chunk_info) ; + + pakt_size = chunk_info.datalen ; + chunk_info.data = pakt_data = malloc (pakt_size + 5) ; + if (!chunk_info.data) + return NULL ; + + if ((bcount = psf->get_chunk_data (psf, chunk_iterator, &chunk_info)) != SF_ERR_NO_ERROR) + { while (chunk_iterator) + chunk_iterator = psf->next_chunk_iterator (psf, chunk_iterator) ; + free (chunk_info.data) ; + chunk_info.data = NULL ; + return NULL ; + } ; + + while (chunk_iterator) + chunk_iterator = psf->next_chunk_iterator (psf, chunk_iterator) ; + + info = alac_pakt_alloc (pakt_size / 4) ; + + /* Start at 24 bytes in, skipping over the 'pakt' chunks header. */ + for (bcount = 24 ; bcount < pakt_size && value != 0 ; ) + { uint8_t byte ; + int32_t count = 0 ; + + value = 0 ; + do + { byte = pakt_data [bcount + count] ; + value = (value << 7) + (byte & 0x7F) ; + + count ++ ; + if (count > 5 || bcount + count > pakt_size) + { printf ("%s %d : Ooops! count %" PRIi32 " bcount %" PRIu32 "\n", __func__, __LINE__, count, bcount) ; + value = 0 ; + break ; + } ; + } + while (byte & 0x80) ; + + bcount += count ; + + if ((info = alac_pakt_append (info, value)) == NULL) + goto FreeExit ; + } ; + + free (pakt_data) ; + + return info ; + +FreeExit : + free (pakt_data) ; + free (info) ; + return NULL ; +} /* alac_pakt_read_decode */ + +static uint8_t * +alac_pakt_encode (const SF_PRIVATE *psf, uint32_t * pakt_size_out) +{ const ALAC_PRIVATE *plac ; + const PAKT_INFO *info ; + uint8_t *data ; + uint32_t k, allocated, pakt_size ; + + plac = psf->codec_data ; + info = plac->pakt_info ; + + allocated = 100 + 2 * info->count ; + if ((data = calloc (1, allocated)) == NULL) + return NULL ; + + psf_put_be64 (data, 0, info->count) ; + psf_put_be64 (data, 8, psf->sf.frames) ; + psf_put_be32 (data, 20, kALACDefaultFramesPerPacket - plac->partial_block_frames) ; + + /* Real 'pakt' data starts after 24 byte header. */ + pakt_size = 24 ; + + for (k = 0 ; k < info->count ; k++) + { int32_t value = info->packet_size [k] ; + + if ((value & 0x7f) == value) + { data [pakt_size++] = value ; + continue ; + } ; + + if ((value & 0x3fff) == value) + { data [pakt_size++] = (value >> 7) | 0x80 ; + data [pakt_size++] = value & 0x7f ; + continue ; + } ; + + if ((value & 0x1fffff) == value) + { data [pakt_size++] = (value >> 14) | 0x80 ; + data [pakt_size++] = ((value >> 7) & 0x7f) | 0x80 ; + data [pakt_size++] = value & 0x7f ; + continue ; + } ; + + if ((value & 0x0fffffff) == value) + { data [pakt_size++] = (value >> 21) | 0x80 ; + data [pakt_size++] = ((value >> 14) & 0x7f) | 0x80 ; + data [pakt_size++] = ((value >> 7) & 0x7f) | 0x80 ; + data [pakt_size++] = value & 0x7f ; + continue ; + } ; + + *pakt_size_out = 0 ; + free (data) ; + return NULL ; + } ; + + *pakt_size_out = pakt_size ; + return data ; +} /* alac_pakt_encode */ + +static sf_count_t +alac_pakt_block_offset (const PAKT_INFO *info, uint32_t block) +{ sf_count_t offset = 0 ; + uint32_t k ; + + for (k = 0 ; k < block ; k++) + offset += info->packet_size [k] ; + + return offset ; +} /* alac_pakt_block_offset */ + +static uint32_t +alac_kuki_read (SF_PRIVATE * psf, uint32_t kuki_offset, uint8_t * kuki, size_t kuki_maxlen) +{ uint32_t marker ; + uint64_t kuki_size ; + + if (psf_fseek (psf, kuki_offset, SEEK_SET) != kuki_offset) + return 0 ; + + psf_fread (&marker, 1, sizeof (marker), psf) ; + if (marker != MAKE_MARKER ('k', 'u', 'k', 'i')) + return 0 ; + + psf_fread (&kuki_size, 1, sizeof (kuki_size), psf) ; + kuki_size = BE2H_64 (kuki_size) ; + + if (kuki_size == 0 || kuki_size > kuki_maxlen) + { psf_log_printf (psf, "%s : Bad size (%D) of 'kuki' chunk.\n", __func__, kuki_size) ; + return 0 ; + } ; + + psf_fread (kuki, 1, kuki_size, psf) ; + + return kuki_size ; +} /* alac_kuki_read */ + +#define CASE_NAME(x) case x : return #x ; break ; + +static const char * +alac_error_string (int error) +{ static char errstr [128] ; + switch (error) + { CASE_NAME (kALAC_UnimplementedError) ; + CASE_NAME (kALAC_FileNotFoundError) ; + CASE_NAME (kALAC_ParamError) ; + CASE_NAME (kALAC_MemFullError) ; + CASE_NAME (fALAC_FrameLengthError) ; + + /* Added for libsndfile */ + CASE_NAME (kALAC_BadBitWidth) ; + CASE_NAME (kALAC_IncompatibleVersion) ; + CASE_NAME (kALAC_BadSpecificConfigSize) ; + CASE_NAME (kALAC_ZeroChannelCount) ; + CASE_NAME (kALAC_NumSamplesTooBig) ; + CASE_NAME (kALAC_UnsupportedElement) ; + default : + break ; + } ; + + snprintf (errstr, sizeof (errstr), "Unknown error %d", error) ; + return errstr ; +} /* alac_error_string */ + diff --git a/extern/libsndfile-modified/src/alaw.c b/extern/libsndfile-modified/src/alaw.c new file mode 100644 index 000000000..4be642e59 --- /dev/null +++ b/extern/libsndfile-modified/src/alaw.c @@ -0,0 +1,553 @@ +/* +** Copyright (C) 1999-2013 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include + +#include "sndfile.h" +#include "common.h" + +static sf_count_t alaw_read_alaw2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; +static sf_count_t alaw_read_alaw2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; +static sf_count_t alaw_read_alaw2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; +static sf_count_t alaw_read_alaw2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; + +static sf_count_t alaw_write_s2alaw (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; +static sf_count_t alaw_write_i2alaw (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; +static sf_count_t alaw_write_f2alaw (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; +static sf_count_t alaw_write_d2alaw (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; + +static void alaw2s_array (unsigned char *buffer, int count, short *ptr) ; +static void alaw2i_array (unsigned char *buffer, int count, int *ptr) ; +static void alaw2f_array (unsigned char *buffer, int count, float *ptr, float normfact) ; +static void alaw2d_array (unsigned char *buffer, int count, double *ptr, double normfact) ; + +static void s2alaw_array (const short *buffer, int count, unsigned char *ptr) ; +static void i2alaw_array (const int *buffer, int count, unsigned char *ptr) ; +static void f2alaw_array (const float *buffer, int count, unsigned char *ptr, float normfact) ; +static void d2alaw_array (const double *buffer, int count, unsigned char *ptr, double normfact) ; + + +int +alaw_init (SF_PRIVATE *psf) +{ + if (psf->file.mode == SFM_READ || psf->file.mode == SFM_RDWR) + { psf->read_short = alaw_read_alaw2s ; + psf->read_int = alaw_read_alaw2i ; + psf->read_float = alaw_read_alaw2f ; + psf->read_double = alaw_read_alaw2d ; + } ; + + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { psf->write_short = alaw_write_s2alaw ; + psf->write_int = alaw_write_i2alaw ; + psf->write_float = alaw_write_f2alaw ; + psf->write_double = alaw_write_d2alaw ; + } ; + + psf->bytewidth = 1 ; + psf->blockwidth = psf->sf.channels ; + + if (psf->filelength > psf->dataoffset) + psf->datalength = (psf->dataend) ? psf->dataend - psf->dataoffset : psf->filelength - psf->dataoffset ; + else + psf->datalength = 0 ; + + psf->sf.frames = psf->blockwidth > 0 ? psf->datalength / psf->blockwidth : 0 ; + + return 0 ; +} /* alaw_init */ + +/*============================================================================== + * Private static functions and data. + */ + +static +short alaw_decode [256] = +{ -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, + -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, + -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, + -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, + -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944, + -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136, + -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472, + -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568, + -344, -328, -376, -360, -280, -264, -312, -296, + -472, -456, -504, -488, -408, -392, -440, -424, + -88, -72, -120, -104, -24, -8, -56, -40, + -216, -200, -248, -232, -152, -136, -184, -168, + -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184, + -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, + -688, -656, -752, -720, -560, -528, -624, -592, + -944, -912, -1008, -976, -816, -784, -880, -848, + 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, + 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, + 2752, 2624, 3008, 2880, 2240, 2112, 2496, 2368, + 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, + 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, + 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, + 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, + 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, + 344, 328, 376, 360, 280, 264, 312, 296, + 472, 456, 504, 488, 408, 392, 440, 424, + 88, 72, 120, 104, 24, 8, 56, 40, + 216, 200, 248, 232, 152, 136, 184, 168, + 1376, 1312, 1504, 1440, 1120, 1056, 1248, 1184, + 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, + 688, 656, 752, 720, 560, 528, 624, 592, + 944, 912, 1008, 976, 816, 784, 880, 848 +} ; /* alaw_decode */ + +static +unsigned char alaw_encode [2048 + 1] = +{ 0xd5, 0xd4, 0xd7, 0xd6, 0xd1, 0xd0, 0xd3, 0xd2, 0xdd, 0xdc, 0xdf, 0xde, + 0xd9, 0xd8, 0xdb, 0xda, 0xc5, 0xc4, 0xc7, 0xc6, 0xc1, 0xc0, 0xc3, 0xc2, + 0xcd, 0xcc, 0xcf, 0xce, 0xc9, 0xc8, 0xcb, 0xca, 0xf5, 0xf5, 0xf4, 0xf4, + 0xf7, 0xf7, 0xf6, 0xf6, 0xf1, 0xf1, 0xf0, 0xf0, 0xf3, 0xf3, 0xf2, 0xf2, + 0xfd, 0xfd, 0xfc, 0xfc, 0xff, 0xff, 0xfe, 0xfe, 0xf9, 0xf9, 0xf8, 0xf8, + 0xfb, 0xfb, 0xfa, 0xfa, 0xe5, 0xe5, 0xe5, 0xe5, 0xe4, 0xe4, 0xe4, 0xe4, + 0xe7, 0xe7, 0xe7, 0xe7, 0xe6, 0xe6, 0xe6, 0xe6, 0xe1, 0xe1, 0xe1, 0xe1, + 0xe0, 0xe0, 0xe0, 0xe0, 0xe3, 0xe3, 0xe3, 0xe3, 0xe2, 0xe2, 0xe2, 0xe2, + 0xed, 0xed, 0xed, 0xed, 0xec, 0xec, 0xec, 0xec, 0xef, 0xef, 0xef, 0xef, + 0xee, 0xee, 0xee, 0xee, 0xe9, 0xe9, 0xe9, 0xe9, 0xe8, 0xe8, 0xe8, 0xe8, + 0xeb, 0xeb, 0xeb, 0xeb, 0xea, 0xea, 0xea, 0xea, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa +} ; /* alaw_encode */ + +static inline void +alaw2s_array (unsigned char *buffer, int count, short *ptr) +{ for (int i = 0 ; i < count ; i++) + ptr [i] = alaw_decode [(int) buffer [i]] ; +} /* alaw2s_array */ + +static inline void +alaw2i_array (unsigned char *buffer, int count, int *ptr) +{ for (int i = 0 ; i < count ; i++) + ptr [i] = ((uint32_t) alaw_decode [(int) buffer [i]]) << 16 ; +} /* alaw2i_array */ + +static inline void +alaw2f_array (unsigned char *buffer, int count, float *ptr, float normfact) +{ for (int i = 0 ; i < count ; i++) + ptr [i] = normfact * alaw_decode [(int) buffer [i]] ; +} /* alaw2f_array */ + +static inline void +alaw2d_array (unsigned char *buffer, int count, double *ptr, double normfact) +{ for (int i = 0 ; i < count ; i++) + ptr [i] = normfact * alaw_decode [(int) buffer [i]] ; +} /* alaw2d_array */ + +static inline void +s2alaw_array (const short *ptr, int count, unsigned char *buffer) +{ for (int i = 0 ; i < count ; i++) + { if (ptr [i] >= 0) + buffer [i] = alaw_encode [ptr [i] / 16] ; + else + buffer [i] = 0x7F & alaw_encode [ptr [i] / -16] ; + } ; +} /* s2alaw_array */ + +static inline void +i2alaw_array (const int *ptr, int count, unsigned char *buffer) +{ for (int i = 0 ; i < count ; i++) + { if (ptr [i] == INT_MIN) + buffer [i] = alaw_encode [INT_MAX >> (16 + 4)] ; + else if (ptr [i] >= 0) + buffer [i] = alaw_encode [ptr [i] >> (16 + 4)] ; + else + buffer [i] = 0x7F & alaw_encode [- ptr [i] >> (16 + 4)] ; + } ; +} /* i2alaw_array */ + +static inline void +f2alaw_array (const float *ptr, int count, unsigned char *buffer, float normfact) +{ for (int i = 0 ; i < count ; i++) + { if (ptr [i] >= 0) + buffer [i] = alaw_encode [psf_lrintf (normfact * ptr [i])] ; + else + buffer [i] = 0x7F & alaw_encode [- psf_lrintf (normfact * ptr [i])] ; + } ; +} /* f2alaw_array */ + +static inline void +d2alaw_array (const double *ptr, int count, unsigned char *buffer, double normfact) +{ for (int i = 0 ; i < count ; i++) + { if (!isfinite (ptr [i])) + buffer [i] = 0 ; + else if (ptr [i] >= 0) + buffer [i] = alaw_encode [psf_lrint (normfact * ptr [i])] ; + else + buffer [i] = 0x7F & alaw_encode [- psf_lrint (normfact * ptr [i])] ; + } ; +} /* d2alaw_array */ + +/*============================================================================== +*/ + +static sf_count_t +alaw_read_alaw2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + + bufferlen = ARRAY_LEN (ubuf.ucbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.ucbuf, 1, bufferlen, psf) ; + alaw2s_array (ubuf.ucbuf, readcount, ptr + total) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* alaw_read_alaw2s */ + +static sf_count_t +alaw_read_alaw2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + + bufferlen = ARRAY_LEN (ubuf.ucbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.ucbuf, 1, bufferlen, psf) ; + alaw2i_array (ubuf.ucbuf, readcount, ptr + total) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* alaw_read_alaw2i */ + +static sf_count_t +alaw_read_alaw2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + float normfact ; + + normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x8000) : 1.0 ; + + bufferlen = ARRAY_LEN (ubuf.ucbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.ucbuf, 1, bufferlen, psf) ; + alaw2f_array (ubuf.ucbuf, readcount, ptr + total, normfact) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* alaw_read_alaw2f */ + +static sf_count_t +alaw_read_alaw2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + double normfact ; + + normfact = (psf->norm_double) ? 1.0 / ((double) 0x8000) : 1.0 ; + bufferlen = ARRAY_LEN (ubuf.ucbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.ucbuf, 1, bufferlen, psf) ; + alaw2d_array (ubuf.ucbuf, readcount, ptr + total, normfact) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* alaw_read_alaw2d */ + +/*============================================================================================= +*/ + +static sf_count_t +alaw_write_s2alaw (SF_PRIVATE *psf, const short *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + bufferlen = ARRAY_LEN (ubuf.ucbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + s2alaw_array (ptr + total, bufferlen, ubuf.ucbuf) ; + writecount = (int) psf_fwrite (ubuf.ucbuf, 1, bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* alaw_write_s2alaw */ + +static sf_count_t +alaw_write_i2alaw (SF_PRIVATE *psf, const int *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + bufferlen = ARRAY_LEN (ubuf.ucbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + i2alaw_array (ptr + total, bufferlen, ubuf.ucbuf) ; + writecount = (int) psf_fwrite (ubuf.ucbuf, 1, bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* alaw_write_i2alaw */ + +static sf_count_t +alaw_write_f2alaw (SF_PRIVATE *psf, const float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + float normfact ; + + normfact = (psf->norm_float == SF_TRUE) ? (1.0 * 0x7FFF) / 16.0 : 1.0 / 16 ; + + bufferlen = ARRAY_LEN (ubuf.ucbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + f2alaw_array (ptr + total, bufferlen, ubuf.ucbuf, normfact) ; + writecount = (int) psf_fwrite (ubuf.ucbuf, 1, bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* alaw_write_f2alaw */ + +static sf_count_t +alaw_write_d2alaw (SF_PRIVATE *psf, const double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + double normfact ; + + normfact = (psf->norm_double) ? (1.0 * 0x7FFF) / 16.0 : 1.0 / 16.0 ; + + bufferlen = ARRAY_LEN (ubuf.ucbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + d2alaw_array (ptr + total, bufferlen, ubuf.ucbuf, normfact) ; + writecount = (int) psf_fwrite (ubuf.ucbuf, 1, bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* alaw_write_d2alaw */ + diff --git a/extern/libsndfile-modified/src/au.c b/extern/libsndfile-modified/src/au.c new file mode 100644 index 000000000..62bd691d6 --- /dev/null +++ b/extern/libsndfile-modified/src/au.c @@ -0,0 +1,454 @@ +/* +** Copyright (C) 1999-2017 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + +/*------------------------------------------------------------------------------ +** Macros to handle big/little endian issues. +*/ + +#define DOTSND_MARKER (MAKE_MARKER ('.', 's', 'n', 'd')) +#define DNSDOT_MARKER (MAKE_MARKER ('d', 'n', 's', '.')) + +#define AU_DATA_OFFSET 24 + +/*------------------------------------------------------------------------------ +** Known AU file encoding types. +*/ + +enum +{ AU_ENCODING_ULAW_8 = 1, /* 8-bit u-law samples */ + AU_ENCODING_PCM_8 = 2, /* 8-bit linear samples */ + AU_ENCODING_PCM_16 = 3, /* 16-bit linear samples */ + AU_ENCODING_PCM_24 = 4, /* 24-bit linear samples */ + AU_ENCODING_PCM_32 = 5, /* 32-bit linear samples */ + + AU_ENCODING_FLOAT = 6, /* floating-point samples */ + AU_ENCODING_DOUBLE = 7, /* double-precision float samples */ + AU_ENCODING_INDIRECT = 8, /* fragmented sampled data */ + AU_ENCODING_NESTED = 9, /* ? */ + AU_ENCODING_DSP_CORE = 10, /* DSP program */ + AU_ENCODING_DSP_DATA_8 = 11, /* 8-bit fixed-point samples */ + AU_ENCODING_DSP_DATA_16 = 12, /* 16-bit fixed-point samples */ + AU_ENCODING_DSP_DATA_24 = 13, /* 24-bit fixed-point samples */ + AU_ENCODING_DSP_DATA_32 = 14, /* 32-bit fixed-point samples */ + + AU_ENCODING_DISPLAY = 16, /* non-audio display data */ + AU_ENCODING_MULAW_SQUELCH = 17, /* ? */ + AU_ENCODING_EMPHASIZED = 18, /* 16-bit linear with emphasis */ + AU_ENCODING_NEXT = 19, /* 16-bit linear with compression (NEXT) */ + AU_ENCODING_COMPRESSED_EMPHASIZED = 20, /* A combination of the two above */ + AU_ENCODING_DSP_COMMANDS = 21, /* Music Kit DSP commands */ + AU_ENCODING_DSP_COMMANDS_SAMPLES = 22, /* ? */ + + AU_ENCODING_ADPCM_G721_32 = 23, /* G721 32 kbs ADPCM - 4 bits per sample. */ + AU_ENCODING_ADPCM_G722 = 24, /* G722 64 kbs ADPCM */ + AU_ENCODING_ADPCM_G723_24 = 25, /* G723 24 kbs ADPCM - 3 bits per sample. */ + AU_ENCODING_ADPCM_G723_40 = 26, /* G723 40 kbs ADPCM - 5 bits per sample. */ + + AU_ENCODING_ALAW_8 = 27 +} ; + +/*------------------------------------------------------------------------------ +** Typedefs. +*/ + +typedef struct +{ int dataoffset ; + int datasize ; + int encoding ; + int samplerate ; + int channels ; +} AU_FMT ; + + +/*------------------------------------------------------------------------------ +** Private static functions. +*/ + +static int au_close (SF_PRIVATE *psf) ; + +static int au_format_to_encoding (int format) ; + +static int au_write_header (SF_PRIVATE *psf, int calc_length) ; +static int au_read_header (SF_PRIVATE *psf) ; + +/*------------------------------------------------------------------------------ +** Public function. +*/ + +int +au_open (SF_PRIVATE *psf) +{ int subformat ; + int error = 0 ; + + if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0)) + { if ((error = au_read_header (psf))) + return error ; + } ; + + if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_AU) + return SFE_BAD_OPEN_FORMAT ; + + subformat = SF_CODEC (psf->sf.format) ; + + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { psf->endian = SF_ENDIAN (psf->sf.format) ; + if (CPU_IS_LITTLE_ENDIAN && psf->endian == SF_ENDIAN_CPU) + psf->endian = SF_ENDIAN_LITTLE ; + else if (psf->endian != SF_ENDIAN_LITTLE) + psf->endian = SF_ENDIAN_BIG ; + + if (au_write_header (psf, SF_FALSE)) + return psf->error ; + + psf->write_header = au_write_header ; + } ; + + psf->container_close = au_close ; + + psf->blockwidth = psf->bytewidth * psf->sf.channels ; + + switch (subformat) + { case SF_FORMAT_ULAW : /* 8-bit Ulaw encoding. */ + ulaw_init (psf) ; + break ; + + case SF_FORMAT_PCM_S8 : /* 8-bit linear PCM. */ + error = pcm_init (psf) ; + break ; + + case SF_FORMAT_PCM_16 : /* 16-bit linear PCM. */ + case SF_FORMAT_PCM_24 : /* 24-bit linear PCM */ + case SF_FORMAT_PCM_32 : /* 32-bit linear PCM. */ + error = pcm_init (psf) ; + break ; + + case SF_FORMAT_ALAW : /* 8-bit Alaw encoding. */ + alaw_init (psf) ; + break ; + + /* Lite remove start */ + case SF_FORMAT_FLOAT : /* 32-bit floats. */ + error = float32_init (psf) ; + break ; + + case SF_FORMAT_DOUBLE : /* 64-bit double precision floats. */ + error = double64_init (psf) ; + break ; + + case SF_FORMAT_G721_32 : + error = g72x_init (psf) ; + psf->sf.seekable = SF_FALSE ; + break ; + + case SF_FORMAT_G723_24 : + error = g72x_init (psf) ; + psf->sf.seekable = SF_FALSE ; + break ; + + case SF_FORMAT_G723_40 : + error = g72x_init (psf) ; + psf->sf.seekable = SF_FALSE ; + break ; + /* Lite remove end */ + + default : break ; + } ; + + return error ; +} /* au_open */ + +/*------------------------------------------------------------------------------ +*/ + +static int +au_close (SF_PRIVATE *psf) +{ + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + au_write_header (psf, SF_TRUE) ; + + return 0 ; +} /* au_close */ + +static int +au_write_header (SF_PRIVATE *psf, int calc_length) +{ sf_count_t current ; + int encoding, datalength ; + + if (psf->pipeoffset > 0) + return 0 ; + + current = psf_ftell (psf) ; + + if (calc_length) + { psf->filelength = psf_get_filelen (psf) ; + + psf->datalength = psf->filelength - psf->dataoffset ; + if (psf->dataend) + psf->datalength -= psf->filelength - psf->dataend ; + } ; + + encoding = au_format_to_encoding (SF_CODEC (psf->sf.format)) ; + if (! encoding) + return (psf->error = SFE_BAD_OPEN_FORMAT) ; + + /* Reset the current header length to zero. */ + psf->header.ptr [0] = 0 ; + psf->header.indx = 0 ; + + /* + ** Only attempt to seek if we are not writng to a pipe. If we are + ** writing to a pipe we shouldn't be here anyway. + */ + if (psf->is_pipe == SF_FALSE) + psf_fseek (psf, 0, SEEK_SET) ; + + /* + ** AU format files allow a datalength value of -1 if the datalength + ** is not know at the time the header is written. + ** Also use this value of -1 if the datalength > 2 gigabytes. + */ + if (psf->datalength < 0 || psf->datalength > 0x7FFFFFFF) + datalength = -1 ; + else + datalength = (int) (psf->datalength & 0x7FFFFFFF) ; + + if (psf->endian == SF_ENDIAN_BIG) + { psf_binheader_writef (psf, "Em4", BHWm (DOTSND_MARKER), BHW4 (AU_DATA_OFFSET)) ; + psf_binheader_writef (psf, "E4444", BHW4 (datalength), BHW4 (encoding), BHW4 (psf->sf.samplerate), BHW4 (psf->sf.channels)) ; + } + else if (psf->endian == SF_ENDIAN_LITTLE) + { psf_binheader_writef (psf, "em4", BHWm (DNSDOT_MARKER), BHW4 (AU_DATA_OFFSET)) ; + psf_binheader_writef (psf, "e4444", BHW4 (datalength), BHW4 (encoding), BHW4 (psf->sf.samplerate), BHW4 (psf->sf.channels)) ; + } + else + return (psf->error = SFE_BAD_OPEN_FORMAT) ; + + /* Header construction complete so write it out. */ + psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ; + + if (psf->error) + return psf->error ; + + psf->dataoffset = psf->header.indx ; + + if (current > 0) + psf_fseek (psf, current, SEEK_SET) ; + + return psf->error ; +} /* au_write_header */ + +static int +au_format_to_encoding (int format) +{ + switch (format) + { case SF_FORMAT_PCM_S8 : return AU_ENCODING_PCM_8 ; + case SF_FORMAT_PCM_16 : return AU_ENCODING_PCM_16 ; + case SF_FORMAT_PCM_24 : return AU_ENCODING_PCM_24 ; + case SF_FORMAT_PCM_32 : return AU_ENCODING_PCM_32 ; + + case SF_FORMAT_FLOAT : return AU_ENCODING_FLOAT ; + case SF_FORMAT_DOUBLE : return AU_ENCODING_DOUBLE ; + + case SF_FORMAT_ULAW : return AU_ENCODING_ULAW_8 ; + case SF_FORMAT_ALAW : return AU_ENCODING_ALAW_8 ; + + case SF_FORMAT_G721_32 : return AU_ENCODING_ADPCM_G721_32 ; + case SF_FORMAT_G723_24 : return AU_ENCODING_ADPCM_G723_24 ; + case SF_FORMAT_G723_40 : return AU_ENCODING_ADPCM_G723_40 ; + + default : break ; + } ; + return 0 ; +} /* au_format_to_encoding */ + +static int +au_read_header (SF_PRIVATE *psf) +{ AU_FMT au_fmt ; + int marker, dword ; + + memset (&au_fmt, 0, sizeof (au_fmt)) ; + psf_binheader_readf (psf, "pm", 0, &marker) ; + psf_log_printf (psf, "%M\n", marker) ; + + if (marker == DOTSND_MARKER) + { psf->endian = SF_ENDIAN_BIG ; + + psf_binheader_readf (psf, "E44444", &(au_fmt.dataoffset), &(au_fmt.datasize), + &(au_fmt.encoding), &(au_fmt.samplerate), &(au_fmt.channels)) ; + } + else if (marker == DNSDOT_MARKER) + { psf->endian = SF_ENDIAN_LITTLE ; + psf_binheader_readf (psf, "e44444", &(au_fmt.dataoffset), &(au_fmt.datasize), + &(au_fmt.encoding), &(au_fmt.samplerate), &(au_fmt.channels)) ; + } + else + return SFE_AU_NO_DOTSND ; + + psf_log_printf (psf, " Data Offset : %d\n", au_fmt.dataoffset) ; + + if (psf->fileoffset > 0 && au_fmt.datasize == -1) + { psf_log_printf (psf, " Data Size : -1\n") ; + return SFE_AU_EMBED_BAD_LEN ; + } ; + + if (psf->fileoffset > 0) + { psf->filelength = au_fmt.dataoffset + au_fmt.datasize ; + psf_log_printf (psf, " Data Size : %d\n", au_fmt.datasize) ; + } + else if (au_fmt.datasize == -1 || au_fmt.dataoffset + au_fmt.datasize == psf->filelength) + psf_log_printf (psf, " Data Size : %d\n", au_fmt.datasize) ; + else if (au_fmt.dataoffset + au_fmt.datasize < psf->filelength) + { psf->filelength = au_fmt.dataoffset + au_fmt.datasize ; + psf_log_printf (psf, " Data Size : %d\n", au_fmt.datasize) ; + } + else + { dword = psf->filelength - au_fmt.dataoffset ; + psf_log_printf (psf, " Data Size : %d (should be %d)\n", au_fmt.datasize, dword) ; + au_fmt.datasize = dword ; + } ; + + psf->dataoffset = au_fmt.dataoffset ; + psf->datalength = psf->filelength - psf->dataoffset ; + + if (psf_ftell (psf) < psf->dataoffset) + psf_binheader_readf (psf, "j", psf->dataoffset - psf_ftell (psf)) ; + + psf->sf.samplerate = au_fmt.samplerate ; + psf->sf.channels = au_fmt.channels ; + + /* Only fill in type major. */ + if (psf->endian == SF_ENDIAN_BIG) + psf->sf.format = SF_FORMAT_AU ; + else if (psf->endian == SF_ENDIAN_LITTLE) + psf->sf.format = SF_ENDIAN_LITTLE | SF_FORMAT_AU ; + + psf_log_printf (psf, " Encoding : %d => ", au_fmt.encoding) ; + + psf->sf.format = SF_ENDIAN (psf->sf.format) ; + + switch (au_fmt.encoding) + { case AU_ENCODING_ULAW_8 : + psf->sf.format |= SF_FORMAT_AU | SF_FORMAT_ULAW ; + psf->bytewidth = 1 ; /* Before decoding */ + psf_log_printf (psf, "8-bit ISDN u-law\n") ; + break ; + + case AU_ENCODING_PCM_8 : + psf->sf.format |= SF_FORMAT_AU | SF_FORMAT_PCM_S8 ; + psf->bytewidth = 1 ; + psf_log_printf (psf, "8-bit linear PCM\n") ; + break ; + + case AU_ENCODING_PCM_16 : + psf->sf.format |= SF_FORMAT_AU | SF_FORMAT_PCM_16 ; + psf->bytewidth = 2 ; + psf_log_printf (psf, "16-bit linear PCM\n") ; + break ; + + case AU_ENCODING_PCM_24 : + psf->sf.format |= SF_FORMAT_AU | SF_FORMAT_PCM_24 ; + psf->bytewidth = 3 ; + psf_log_printf (psf, "24-bit linear PCM\n") ; + break ; + + case AU_ENCODING_PCM_32 : + psf->sf.format |= SF_FORMAT_AU | SF_FORMAT_PCM_32 ; + psf->bytewidth = 4 ; + psf_log_printf (psf, "32-bit linear PCM\n") ; + break ; + + case AU_ENCODING_FLOAT : + psf->sf.format |= SF_FORMAT_AU | SF_FORMAT_FLOAT ; + psf->bytewidth = 4 ; + psf_log_printf (psf, "32-bit float\n") ; + break ; + + case AU_ENCODING_DOUBLE : + psf->sf.format |= SF_FORMAT_AU | SF_FORMAT_DOUBLE ; + psf->bytewidth = 8 ; + psf_log_printf (psf, "64-bit double precision float\n") ; + break ; + + case AU_ENCODING_ALAW_8 : + psf->sf.format |= SF_FORMAT_AU | SF_FORMAT_ALAW ; + psf->bytewidth = 1 ; /* Before decoding */ + psf_log_printf (psf, "8-bit ISDN A-law\n") ; + break ; + + case AU_ENCODING_ADPCM_G721_32 : + psf->sf.format |= SF_FORMAT_AU | SF_FORMAT_G721_32 ; + psf->bytewidth = 0 ; + psf_log_printf (psf, "G721 32kbs ADPCM\n") ; + break ; + + case AU_ENCODING_ADPCM_G723_24 : + psf->sf.format |= SF_FORMAT_AU | SF_FORMAT_G723_24 ; + psf->bytewidth = 0 ; + psf_log_printf (psf, "G723 24kbs ADPCM\n") ; + break ; + + case AU_ENCODING_ADPCM_G723_40 : + psf->sf.format |= SF_FORMAT_AU | SF_FORMAT_G723_40 ; + psf->bytewidth = 0 ; + psf_log_printf (psf, "G723 40kbs ADPCM\n") ; + break ; + + case AU_ENCODING_ADPCM_G722 : + psf_log_printf (psf, "G722 64 kbs ADPCM (unsupported)\n") ; + break ; + + case AU_ENCODING_NEXT : + psf_log_printf (psf, "Weird NeXT encoding format (unsupported)\n") ; + break ; + + default : + psf_log_printf (psf, "Unknown!!\n") ; + break ; + } ; + + psf_log_printf (psf, " Sample Rate : %d\n", au_fmt.samplerate) ; + if (au_fmt.channels < 1) + { psf_log_printf (psf, " Channels : %d **** should be >= 1\n", au_fmt.channels) ; + return SFE_CHANNEL_COUNT_ZERO ; + } + else if (au_fmt.channels > SF_MAX_CHANNELS) + { psf_log_printf (psf, " Channels : %d **** should be <= %d\n", au_fmt.channels, SF_MAX_CHANNELS) ; + return SFE_CHANNEL_COUNT ; + } ; + + psf_log_printf (psf, " Channels : %d\n", au_fmt.channels) ; + + psf->blockwidth = psf->sf.channels * psf->bytewidth ; + + if (! psf->sf.frames && psf->blockwidth) + psf->sf.frames = (psf->filelength - psf->dataoffset) / psf->blockwidth ; + + return 0 ; +} /* au_read_header */ + diff --git a/extern/libsndfile-modified/src/audio_detect.c b/extern/libsndfile-modified/src/audio_detect.c new file mode 100644 index 000000000..b2671e8d8 --- /dev/null +++ b/extern/libsndfile-modified/src/audio_detect.c @@ -0,0 +1,107 @@ +/* +** Copyright (C) 1999-2012 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + + +#include "sfconfig.h" + +#include +#include + +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include +#include + +#include "common.h" + +typedef struct +{ int le_float ; + int be_float ; + int le_int_24_32 ; + int be_int_24_32 ; +} VOTE ; + + +static void vote_for_format (VOTE * vote, const unsigned char * data, int datalen) ; + +int +audio_detect (SF_PRIVATE * psf, AUDIO_DETECT *ad, const unsigned char * data, int datalen) +{ VOTE vote ; + + if (psf == NULL) + return 0 ; + + if (ad == NULL || datalen < 256) + return 0 ; + + vote_for_format (&vote, data, datalen) ; + + psf_log_printf (psf, "audio_detect :\n" + " le_float : %d\n" + " be_float : %d\n" + " le_int_24_32 : %d\n" + " be_int_24_32 : %d\n", + vote.le_float, vote.be_float, vote.le_int_24_32, vote.be_int_24_32) ; + + if (0) puts (psf->parselog.buf) ; + + if (ad->endianness == SF_ENDIAN_LITTLE && vote.le_float > (3 * datalen) / 4) + { /* Almost certainly 32 bit floats. */ + return SF_FORMAT_FLOAT ; + } ; + + if (ad->endianness == SF_ENDIAN_LITTLE && vote.le_int_24_32 > (3 * datalen) / 4) + { /* Almost certainly 24 bit data stored in 32 bit ints. */ + return SF_FORMAT_PCM_32 ; + } ; + + return 0 ; +} /* data_detect */ + +static void +vote_for_format (VOTE * vote, const unsigned char * data, int datalen) +{ + int k ; + + memset (vote, 0, sizeof (VOTE)) ; + + datalen -= datalen % 4 ; + + for (k = 0 ; k < datalen ; k ++) + { if ((k % 4) == 0) + { if (data [k] == 0 && data [k + 1] != 0) + vote->le_int_24_32 += 4 ; + + if (data [2] != 0 && data [3] == 0) + vote->le_int_24_32 += 4 ; + + if (data [0] != 0 && data [3] > 0x43 && data [3] < 0x4B) + vote->le_float += 4 ; + + if (data [3] != 0 && data [0] > 0x43 && data [0] < 0x4B) + vote->be_float += 4 ; + } ; + } ; + + return ; +} /* vote_for_format */ + diff --git a/extern/libsndfile-modified/src/avr.c b/extern/libsndfile-modified/src/avr.c new file mode 100644 index 000000000..6c78ff69b --- /dev/null +++ b/extern/libsndfile-modified/src/avr.c @@ -0,0 +1,244 @@ +/* +** Copyright (C) 2004-2017 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + +#define TWOBIT_MARKER (MAKE_MARKER ('2', 'B', 'I', 'T')) +#define AVR_HDR_SIZE 128 + +/* +** From: hyc@hanauma.Jpl.Nasa.Gov (Howard Chu) +** +** A lot of PD software exists to play Mac .snd files on the ST. One other +** format that seems pretty popular (used by a number of commercial packages) +** is the AVR format (from Audio Visual Research). This format has a 128 byte +** header that looks like this (its actually packed, but thats not portable): +*/ + +typedef struct +{ int marker ; /* 2BIT */ + char name [8] ; /* null-padded sample name */ + short mono ; /* 0 = mono, 0xffff = stereo */ + short rez ; /* 8 = 8 bit, 16 = 16 bit */ + short sign ; /* 0 = unsigned, 0xffff = signed */ + + short loop ; /* 0 = no loop, 0xffff = looping sample */ + short midi ; /* 0xffff = no MIDI note assigned, */ + /* 0xffXX = single key note assignment */ + /* 0xLLHH = key split, low/hi note */ + int srate ; /* sample frequency in hertz */ + int frames ; /* sample length in bytes or words (see rez) */ + int lbeg ; /* offset to start of loop in bytes or words. */ + /* set to zero if unused */ + int lend ; /* offset to end of loop in bytes or words. */ + /* set to sample length if unused */ + short res1 ; /* Reserved, MIDI keyboard split */ + short res2 ; /* Reserved, sample compression */ + short res3 ; /* Reserved */ + char ext [20] ; /* Additional filename space, used if (name[7] != 0) */ + char user [64] ; /* User defined. Typically ASCII message */ +} AVR_HEADER ; + +/*------------------------------------------------------------------------------ +** Private static functions. +*/ + +static int avr_close (SF_PRIVATE *psf) ; + +static int avr_read_header (SF_PRIVATE *psf) ; +static int avr_write_header (SF_PRIVATE *psf, int calc_length) ; + +/*------------------------------------------------------------------------------ +** Public function. +*/ + +int +avr_open (SF_PRIVATE *psf) +{ int error = 0 ; + + if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0)) + { if ((error = avr_read_header (psf))) + return error ; + } ; + + if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_AVR) + return SFE_BAD_OPEN_FORMAT ; + + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { psf->endian = SF_ENDIAN_BIG ; + + if (avr_write_header (psf, SF_FALSE)) + return psf->error ; + + psf->write_header = avr_write_header ; + } ; + + psf->container_close = avr_close ; + + psf->blockwidth = psf->bytewidth * psf->sf.channels ; + + error = pcm_init (psf) ; + + return error ; +} /* avr_open */ + +static int +avr_read_header (SF_PRIVATE *psf) +{ AVR_HEADER hdr ; + + memset (&hdr, 0, sizeof (hdr)) ; + + psf_binheader_readf (psf, "pmb", 0, &hdr.marker, &hdr.name, sizeof (hdr.name)) ; + psf_log_printf (psf, "%M\n", hdr.marker) ; + + if (hdr.marker != TWOBIT_MARKER) + return SFE_AVR_NOT_AVR ; + + psf_log_printf (psf, " Name : %s\n", hdr.name) ; + + psf_binheader_readf (psf, "E22222", &hdr.mono, &hdr.rez, &hdr.sign, &hdr.loop, &hdr.midi) ; + + psf->sf.channels = (hdr.mono & 1) + 1 ; + + psf_log_printf (psf, " Channels : %d\n Bit width : %d\n Signed : %s\n", + (hdr.mono & 1) + 1, hdr.rez, hdr.sign ? "yes" : "no") ; + + switch (arith_shift_left (hdr.rez, 16) + (hdr.sign & 1)) + { case ((8 << 16) + 0) : + psf->sf.format = SF_FORMAT_AVR | SF_FORMAT_PCM_U8 ; + psf->bytewidth = 1 ; + break ; + + case ((8 << 16) + 1) : + psf->sf.format = SF_FORMAT_AVR | SF_FORMAT_PCM_S8 ; + psf->bytewidth = 1 ; + break ; + + case ((16 << 16) + 1) : + psf->sf.format = SF_FORMAT_AVR | SF_FORMAT_PCM_16 ; + psf->bytewidth = 2 ; + break ; + + default : + psf_log_printf (psf, "Error : bad rez/sign combination.\n") ; + return SFE_AVR_BAD_REZ_SIGN ; + } ; + + psf_binheader_readf (psf, "E4444", &hdr.srate, &hdr.frames, &hdr.lbeg, &hdr.lend) ; + + psf->sf.frames = hdr.frames ; + psf->sf.samplerate = hdr.srate ; + + psf_log_printf (psf, " Frames : %D\n", psf->sf.frames) ; + psf_log_printf (psf, " Sample rate : %d\n", psf->sf.samplerate) ; + + psf_binheader_readf (psf, "E222", &hdr.res1, &hdr.res2, &hdr.res3) ; + psf_binheader_readf (psf, "bb", hdr.ext, sizeof (hdr.ext), hdr.user, sizeof (hdr.user)) ; + + psf_log_printf (psf, " Ext : %s\n User : %s\n", hdr.ext, hdr.user) ; + + psf->endian = SF_ENDIAN_BIG ; + + psf->dataoffset = AVR_HDR_SIZE ; + psf->datalength = hdr.frames * (hdr.rez / 8) ; + + if (psf->fileoffset > 0) + psf->filelength = AVR_HDR_SIZE + psf->datalength ; + + if (psf_ftell (psf) != psf->dataoffset) + psf_binheader_readf (psf, "j", psf->dataoffset - psf_ftell (psf)) ; + + psf->blockwidth = psf->sf.channels * psf->bytewidth ; + + if (psf->sf.frames == 0 && psf->blockwidth) + psf->sf.frames = (psf->filelength - psf->dataoffset) / psf->blockwidth ; + + return 0 ; +} /* avr_read_header */ + +static int +avr_write_header (SF_PRIVATE *psf, int calc_length) +{ sf_count_t current ; + int sign ; + + if (psf->pipeoffset > 0) + return 0 ; + + current = psf_ftell (psf) ; + + if (calc_length) + { psf->filelength = psf_get_filelen (psf) ; + + psf->datalength = psf->filelength - psf->dataoffset ; + if (psf->dataend) + psf->datalength -= psf->filelength - psf->dataend ; + + psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ; + } ; + + /* Reset the current header length to zero. */ + psf->header.ptr [0] = 0 ; + psf->header.indx = 0 ; + + /* + ** Only attempt to seek if we are not writng to a pipe. If we are + ** writing to a pipe we shouldn't be here anyway. + */ + if (psf->is_pipe == SF_FALSE) + psf_fseek (psf, 0, SEEK_SET) ; + + psf_binheader_writef (psf, "Emz22", BHWm (TWOBIT_MARKER), BHWz (8), + BHW2 (psf->sf.channels == 2 ? 0xFFFF : 0), BHW2 (psf->bytewidth * 8)) ; + + sign = ((SF_CODEC (psf->sf.format)) == SF_FORMAT_PCM_U8) ? 0 : 0xFFFF ; + + psf_binheader_writef (psf, "E222", BHW2 (sign), BHW2 (0), BHW2 (0xFFFF)) ; + psf_binheader_writef (psf, "E4444", BHW4 (psf->sf.samplerate), BHW4 (psf->sf.frames), BHW4 (0), BHW4 (0)) ; + + psf_binheader_writef (psf, "E222zz", BHW2 (0), BHW2 (0), BHW2 (0), BHWz (20), BHWz (64)) ; + + /* Header construction complete so write it out. */ + psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ; + + if (psf->error) + return psf->error ; + + psf->dataoffset = psf->header.indx ; + + if (current > 0) + psf_fseek (psf, current, SEEK_SET) ; + + return psf->error ; +} /* avr_write_header */ + +static int +avr_close (SF_PRIVATE *psf) +{ + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + avr_write_header (psf, SF_TRUE) ; + + return 0 ; +} /* avr_close */ + diff --git a/extern/libsndfile-modified/src/binheader_writef_check.py b/extern/libsndfile-modified/src/binheader_writef_check.py new file mode 100755 index 000000000..09ebc92e0 --- /dev/null +++ b/extern/libsndfile-modified/src/binheader_writef_check.py @@ -0,0 +1,114 @@ +#!/usr/bin/python + +# Copyright (C) 2006-2017 Erik de Castro Lopo +# +# All rights reserved. +# +# 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 author nor the names of any 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 COPYRIGHT OWNER 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 parses C code using regexes (yes, thats horrible) and makes sure +# that calling conventions to the function psf_binheader_writef are +# correct. + + + +import re, string, sys + +_whitespace_re = re.compile ("\s+", re.MULTILINE) + +def find_binheader_writefs (data): + lst = re.findall ('psf_binheader_writef\s*\(\s*[a-zA-Z_]+\s*,\s*\"[^;]+;', data, re.MULTILINE) + return [_whitespace_re.sub (" ", x) for x in lst] + +def find_format_string (s): + fmt = re.search ('"([^"]+)"', s) + if not fmt: + print ("Bad format in :\n\n\t%s\n\n" % s) + sys.exit (1) + fmt = fmt.groups () + if len (fmt) != 1: + print ("Bad format in :\n\n\t%s\n\n" % s) + sys.exit (1) + return _whitespace_re.sub ("", fmt [0]) + +def get_param_list (data): + dlist = re.search ("\((.+)\)\s*;", data) + dlist = dlist.groups ()[0] + dlist = dlist.split(",") + dlist = [x.strip() for x in dlist] + return dlist [2:] + +def handle_file (fname): + errors = 0 + data = open (fname, "r").read () + + # return errors + + writefs = find_binheader_writefs (data) + for item in writefs: + fmt = find_format_string (item) + params = get_param_list (item) + param_index = 0 + + # print item + + for ch in fmt: + if ch in 'Eet ': + continue + + if ch == 'b': + if params [param_index][:4] == "BHWv" and params [param_index + 1][:4] == "BHWz": + param_index += 2 + continue + + if "BHW" + ch == params [param_index][:4]: + param_index += 1 + continue + + if errors == 0: sys.stdout.write ("\n") + print ("\n%s: error for format specifier '%c' (index %d) in:\n %s\n" % (fname, ch, param_index, item)) + errors += 1 + # Break out of 'for ch in fmt' loop + break + + return errors + +#=============================================================================== + +if len (sys.argv) > 1: + sys.stdout.write ("\n binheader_writef_check : ") + sys.stdout.flush () + errors = 0 + for fname in sys.argv [1:]: + errors += handle_file (fname) + if errors > 0: + print ("\nErrors : %d\n" % errors) + sys.exit (1) + +print ("ok\n") + diff --git a/extern/libsndfile-modified/src/broadcast.c b/extern/libsndfile-modified/src/broadcast.c new file mode 100644 index 000000000..aad5f880d --- /dev/null +++ b/extern/libsndfile-modified/src/broadcast.c @@ -0,0 +1,190 @@ +/* +** Copyright (C) 2006-2016 Erik de Castro Lopo +** Copyright (C) 2006 Paul Davis +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include + +#include "common.h" + + +static int gen_coding_history (char * added_history, int added_history_max, const SF_INFO * psfinfo) ; + +static inline size_t +bc_min_size (const SF_BROADCAST_INFO* info) +{ if (info == NULL) + return 0 ; + + return offsetof (SF_BROADCAST_INFO, coding_history) + info->coding_history_size ; +} /* bc_min_size */ + +SF_BROADCAST_INFO_16K* +broadcast_var_alloc (void) +{ return calloc (1, sizeof (SF_BROADCAST_INFO_16K)) ; +} /* broadcast_var_alloc */ + +int +broadcast_var_set (SF_PRIVATE *psf, const SF_BROADCAST_INFO * info, size_t datasize) +{ size_t len ; + + if (info == NULL) + return SF_FALSE ; + + if (bc_min_size (info) > datasize) + { psf->error = SFE_BAD_BROADCAST_INFO_SIZE ; + return SF_FALSE ; + } ; + + if (datasize >= sizeof (SF_BROADCAST_INFO_16K)) + { psf->error = SFE_BAD_BROADCAST_INFO_TOO_BIG ; + return SF_FALSE ; + } ; + + if (psf->broadcast_16k == NULL) + { if ((psf->broadcast_16k = broadcast_var_alloc ()) == NULL) + { psf->error = SFE_MALLOC_FAILED ; + return SF_FALSE ; + } ; + } ; + + /* Only copy the first part of the struct. */ + memcpy (psf->broadcast_16k, info, offsetof (SF_BROADCAST_INFO, coding_history)) ; + + psf_strlcpy_crlf (psf->broadcast_16k->coding_history, info->coding_history, sizeof (psf->broadcast_16k->coding_history), datasize - offsetof (SF_BROADCAST_INFO, coding_history)) ; + len = strlen (psf->broadcast_16k->coding_history) ; + + if (len > 0 && psf->broadcast_16k->coding_history [len - 1] != '\n') + psf_strlcat (psf->broadcast_16k->coding_history, sizeof (psf->broadcast_16k->coding_history), "\r\n") ; + + if (psf->file.mode == SFM_WRITE) + { char added_history [256] ; + + gen_coding_history (added_history, sizeof (added_history), &(psf->sf)) ; + psf_strlcat (psf->broadcast_16k->coding_history, sizeof (psf->broadcast_16k->coding_history), added_history) ; + } ; + + /* Force coding_history_size to be even. */ + len = strlen (psf->broadcast_16k->coding_history) ; + len += (len & 1) ? 1 : 0 ; + psf->broadcast_16k->coding_history_size = (uint32_t) len ; + + /* Currently writing this version. */ + psf->broadcast_16k->version = 2 ; + + return SF_TRUE ; +} /* broadcast_var_set */ + + +int +broadcast_var_get (SF_PRIVATE *psf, SF_BROADCAST_INFO * data, size_t datasize) +{ size_t size ; + + if (psf->broadcast_16k == NULL) + return SF_FALSE ; + + size = SF_MIN (datasize, bc_min_size ((const SF_BROADCAST_INFO *) psf->broadcast_16k)) ; + + memcpy (data, psf->broadcast_16k, size) ; + + return SF_TRUE ; +} /* broadcast_var_get */ + +/*------------------------------------------------------------------------------ +*/ + +static int +gen_coding_history (char * added_history, int added_history_max, const SF_INFO * psfinfo) +{ char chnstr [16] ; + int count, width ; + + /* + ** From : http://www.sr.se/utveckling/tu/bwf/docs/codhist2.htm + ** + ** Parameter Variable string Unit + ** ========================================================================================== + ** Coding Algorithm A= + ** Sampling frequency F=<11000,22050,24000,32000,44100,48000> [Hz] + ** Bit-rate B= + ** Word Length W=<8, 12, 14, 16, 18, 20, 22, 24> [bits] + ** Mode M= + ** Text, free string T= + */ + + switch (psfinfo->channels) + { case 0 : + return SF_FALSE ; + + case 1 : + psf_strlcpy (chnstr, sizeof (chnstr), "mono") ; + break ; + + case 2 : + psf_strlcpy (chnstr, sizeof (chnstr), "stereo") ; + break ; + + default : + snprintf (chnstr, sizeof (chnstr), "%dchn", psfinfo->channels) ; + break ; + } ; + + switch (SF_CODEC (psfinfo->format)) + { case SF_FORMAT_PCM_U8 : + case SF_FORMAT_PCM_S8 : + width = 8 ; + break ; + case SF_FORMAT_PCM_16 : + width = 16 ; + break ; + case SF_FORMAT_PCM_24 : + width = 24 ; + break ; + case SF_FORMAT_PCM_32 : + width = 32 ; + break ; + case SF_FORMAT_FLOAT : + width = 24 ; /* Bits in the mantissa + 1 */ + break ; + case SF_FORMAT_DOUBLE : + width = 53 ; /* Bits in the mantissa + 1 */ + break ; + case SF_FORMAT_ULAW : + case SF_FORMAT_ALAW : + width = 12 ; + break ; + default : + width = 42 ; + break ; + } ; + + count = snprintf (added_history, added_history_max, + "A=PCM,F=%d,W=%d,M=%s,T=%s-%s\r\n", + psfinfo->samplerate, width, chnstr, PACKAGE_NAME, PACKAGE_VERSION) ; + + if (count >= added_history_max) + return 0 ; + + return count ; +} /* gen_coding_history */ diff --git a/extern/libsndfile-modified/src/caf.c b/extern/libsndfile-modified/src/caf.c new file mode 100644 index 000000000..a886bf562 --- /dev/null +++ b/extern/libsndfile-modified/src/caf.c @@ -0,0 +1,1034 @@ +/* +** Copyright (C) 2005-2017 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" +#include "chanmap.h" + +/*------------------------------------------------------------------------------ +** Macros to handle big/little endian issues. +*/ + +#define aac_MARKER MAKE_MARKER ('a', 'a', 'c', ' ') +#define alac_MARKER MAKE_MARKER ('a', 'l', 'a', 'c') +#define alaw_MARKER MAKE_MARKER ('a', 'l', 'a', 'w') +#define caff_MARKER MAKE_MARKER ('c', 'a', 'f', 'f') +#define chan_MARKER MAKE_MARKER ('c', 'h', 'a', 'n') +#define data_MARKER MAKE_MARKER ('d', 'a', 't', 'a') +#define desc_MARKER MAKE_MARKER ('d', 'e', 's', 'c') +#define edct_MARKER MAKE_MARKER ('e', 'd', 'c', 't') +#define free_MARKER MAKE_MARKER ('f', 'r', 'e', 'e') +#define ima4_MARKER MAKE_MARKER ('i', 'm', 'a', '4') +#define info_MARKER MAKE_MARKER ('i', 'n', 'f', 'o') +#define inst_MARKER MAKE_MARKER ('i', 'n', 's', 't') +#define kuki_MARKER MAKE_MARKER ('k', 'u', 'k', 'i') +#define lpcm_MARKER MAKE_MARKER ('l', 'p', 'c', 'm') +#define mark_MARKER MAKE_MARKER ('m', 'a', 'r', 'k') +#define midi_MARKER MAKE_MARKER ('m', 'i', 'd', 'i') +#define mp1_MARKER MAKE_MARKER ('.', 'm', 'p', '1') +#define mp2_MARKER MAKE_MARKER ('.', 'm', 'p', '2') +#define mp3_MARKER MAKE_MARKER ('.', 'm', 'p', '3') +#define ovvw_MARKER MAKE_MARKER ('o', 'v', 'v', 'w') +#define pakt_MARKER MAKE_MARKER ('p', 'a', 'k', 't') +#define peak_MARKER MAKE_MARKER ('p', 'e', 'a', 'k') +#define regn_MARKER MAKE_MARKER ('r', 'e', 'g', 'n') +#define strg_MARKER MAKE_MARKER ('s', 't', 'r', 'g') +#define umid_MARKER MAKE_MARKER ('u', 'm', 'i', 'd') +#define uuid_MARKER MAKE_MARKER ('u', 'u', 'i', 'd') +#define ulaw_MARKER MAKE_MARKER ('u', 'l', 'a', 'w') +#define MAC3_MARKER MAKE_MARKER ('M', 'A', 'C', '3') +#define MAC6_MARKER MAKE_MARKER ('M', 'A', 'C', '6') + +#define CAF_PEAK_CHUNK_SIZE(ch) ((int) (sizeof (int) + ch * (sizeof (float) + 8))) + +/*------------------------------------------------------------------------------ +** Typedefs. +*/ + +typedef struct +{ uint8_t srate [8] ; + uint32_t fmt_id ; + uint32_t fmt_flags ; + uint32_t pkt_bytes ; + uint32_t frames_per_packet ; + uint32_t channels_per_frame ; + uint32_t bits_per_chan ; +} DESC_CHUNK ; + +typedef struct +{ int chanmap_tag ; + + ALAC_DECODER_INFO alac ; +} CAF_PRIVATE ; + +/*------------------------------------------------------------------------------ +** Private static functions. +*/ + +static int caf_close (SF_PRIVATE *psf) ; +static int caf_read_header (SF_PRIVATE *psf) ; +static int caf_write_header (SF_PRIVATE *psf, int calc_length) ; +static int caf_write_tailer (SF_PRIVATE *psf) ; +static int caf_command (SF_PRIVATE *psf, int command, void *data, int datasize) ; +static int caf_read_chanmap (SF_PRIVATE * psf, sf_count_t chunk_size) ; +static int caf_read_strings (SF_PRIVATE * psf, sf_count_t chunk_size) ; +static void caf_write_strings (SF_PRIVATE * psf, int location) ; + + +static int caf_set_chunk (SF_PRIVATE *psf, const SF_CHUNK_INFO * chunk_info) ; +static SF_CHUNK_ITERATOR * caf_next_chunk_iterator (SF_PRIVATE *psf, SF_CHUNK_ITERATOR * iterator) ; +static int caf_get_chunk_size (SF_PRIVATE *psf, const SF_CHUNK_ITERATOR * iterator, SF_CHUNK_INFO * chunk_info) ; +static int caf_get_chunk_data (SF_PRIVATE *psf, const SF_CHUNK_ITERATOR * iterator, SF_CHUNK_INFO * chunk_info) ; + +/*------------------------------------------------------------------------------ +** Public function. +*/ + +int +caf_open (SF_PRIVATE *psf) +{ CAF_PRIVATE * pcaf ; + int subformat, format, error = 0 ; + + if ((psf->container_data = calloc (1, sizeof (CAF_PRIVATE))) == NULL) + return SFE_MALLOC_FAILED ; + + pcaf = psf->container_data ; + + if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0)) + { if ((error = caf_read_header (psf))) + return error ; + + psf->next_chunk_iterator = caf_next_chunk_iterator ; + psf->get_chunk_size = caf_get_chunk_size ; + psf->get_chunk_data = caf_get_chunk_data ; + } ; + + subformat = SF_CODEC (psf->sf.format) ; + + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { if (psf->is_pipe) + return SFE_NO_PIPE_WRITE ; + + format = SF_CONTAINER (psf->sf.format) ; + if (format != SF_FORMAT_CAF) + return SFE_BAD_OPEN_FORMAT ; + + psf->blockwidth = psf->bytewidth * psf->sf.channels ; + + if (psf->file.mode != SFM_RDWR || psf->filelength < 44) + { psf->filelength = 0 ; + psf->datalength = 0 ; + psf->dataoffset = 0 ; + psf->sf.frames = 0 ; + } ; + + psf->strings.flags = SF_STR_ALLOW_START | SF_STR_ALLOW_END ; + + /* + ** By default, add the peak chunk to floating point files. Default behaviour + ** can be switched off using sf_command (SFC_SET_PEAK_CHUNK, SF_FALSE). + */ + if (psf->file.mode == SFM_WRITE && (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE)) + { if ((psf->peak_info = peak_info_calloc (psf->sf.channels)) == NULL) + return SFE_MALLOC_FAILED ; + psf->peak_info->peak_loc = SF_PEAK_START ; + } ; + + if ((error = caf_write_header (psf, SF_FALSE)) != 0) + return error ; + + psf->write_header = caf_write_header ; + psf->set_chunk = caf_set_chunk ; + } ; + + psf->container_close = caf_close ; + psf->command = caf_command ; + + switch (subformat) + { case SF_FORMAT_PCM_S8 : + case SF_FORMAT_PCM_16 : + case SF_FORMAT_PCM_24 : + case SF_FORMAT_PCM_32 : + error = pcm_init (psf) ; + break ; + + case SF_FORMAT_ULAW : + error = ulaw_init (psf) ; + break ; + + case SF_FORMAT_ALAW : + error = alaw_init (psf) ; + break ; + + /* Lite remove start */ + case SF_FORMAT_FLOAT : + error = float32_init (psf) ; + break ; + + case SF_FORMAT_DOUBLE : + error = double64_init (psf) ; + break ; + + case SF_FORMAT_ALAC_16 : + case SF_FORMAT_ALAC_20 : + case SF_FORMAT_ALAC_24 : + case SF_FORMAT_ALAC_32 : + if (psf->file.mode == SFM_READ) + /* Only pass the ALAC_DECODER_INFO in read mode. */ + error = alac_init (psf, &pcaf->alac) ; + else + error = alac_init (psf, NULL) ; + break ; + + /* Lite remove end */ + + default : + return SFE_UNSUPPORTED_ENCODING ; + } ; + + return error ; +} /* caf_open */ + +static int +caf_close (SF_PRIVATE *psf) +{ + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { caf_write_tailer (psf) ; + caf_write_header (psf, SF_TRUE) ; + } ; + + return 0 ; +} /* caf_close */ + +static int +caf_command (SF_PRIVATE * psf, int command, void * UNUSED (data), int UNUSED (datasize)) +{ CAF_PRIVATE *pcaf ; + + if ((pcaf = psf->container_data) == NULL) + return SFE_INTERNAL ; + + switch (command) + { case SFC_SET_CHANNEL_MAP_INFO : + pcaf->chanmap_tag = aiff_caf_find_channel_layout_tag (psf->channel_map, psf->sf.channels) ; + return (pcaf->chanmap_tag != 0) ; + + default : + break ; + } ; + + return 0 ; +} /* caf_command */ + +/*------------------------------------------------------------------------------ +*/ + +static int +decode_desc_chunk (SF_PRIVATE *psf, const DESC_CHUNK *desc) +{ int format = SF_FORMAT_CAF ; + + psf->sf.channels = desc->channels_per_frame ; + + if (desc->fmt_id == alac_MARKER) + { CAF_PRIVATE *pcaf ; + + if ((pcaf = psf->container_data) != NULL) + { switch (desc->fmt_flags) + { case 1 : + pcaf->alac.bits_per_sample = 16 ; + format |= SF_FORMAT_ALAC_16 ; + break ; + case 2 : + pcaf->alac.bits_per_sample = 20 ; + format |= SF_FORMAT_ALAC_20 ; + break ; + case 3 : + pcaf->alac.bits_per_sample = 24 ; + format |= SF_FORMAT_ALAC_24 ; + break ; + case 4 : + pcaf->alac.bits_per_sample = 32 ; + format |= SF_FORMAT_ALAC_32 ; + break ; + default : + psf_log_printf (psf, "Bad ALAC format flag value of %d\n", desc->fmt_flags) ; + } ; + + pcaf->alac.frames_per_packet = desc->frames_per_packet ; + } ; + + return format ; + } ; + + format |= psf->endian == SF_ENDIAN_LITTLE ? SF_ENDIAN_LITTLE : 0 ; + + if (desc->fmt_id == lpcm_MARKER && desc->fmt_flags & 1) + { /* Floating point data. */ + if (desc->bits_per_chan == 32 && desc->pkt_bytes == 4 * desc->channels_per_frame) + { psf->bytewidth = 4 ; + return format | SF_FORMAT_FLOAT ; + } ; + if (desc->bits_per_chan == 64 && desc->pkt_bytes == 8 * desc->channels_per_frame) + { psf->bytewidth = 8 ; + return format | SF_FORMAT_DOUBLE ; + } ; + } ; + + if (desc->fmt_id == lpcm_MARKER && (desc->fmt_flags & 1) == 0) + { /* Integer data. */ + if (desc->bits_per_chan == 32 && desc->pkt_bytes == 4 * desc->channels_per_frame) + { psf->bytewidth = 4 ; + return format | SF_FORMAT_PCM_32 ; + } ; + if (desc->bits_per_chan == 24 && desc->pkt_bytes == 3 * desc->channels_per_frame) + { psf->bytewidth = 3 ; + return format | SF_FORMAT_PCM_24 ; + } ; + if (desc->bits_per_chan == 16 && desc->pkt_bytes == 2 * desc->channels_per_frame) + { psf->bytewidth = 2 ; + return format | SF_FORMAT_PCM_16 ; + } ; + if (desc->bits_per_chan == 8 && desc->pkt_bytes == 1 * desc->channels_per_frame) + { psf->bytewidth = 1 ; + return format | SF_FORMAT_PCM_S8 ; + } ; + } ; + + if (desc->fmt_id == alaw_MARKER && desc->bits_per_chan == 8) + { psf->bytewidth = 1 ; + return format | SF_FORMAT_ALAW ; + } ; + + if (desc->fmt_id == ulaw_MARKER && desc->bits_per_chan == 8) + { psf->bytewidth = 1 ; + return format | SF_FORMAT_ULAW ; + } ; + + psf_log_printf (psf, "**** Unknown format identifier.\n") ; + + return 0 ; +} /* decode_desc_chunk */ + +static int +caf_read_header (SF_PRIVATE *psf) +{ CAF_PRIVATE *pcaf ; + BUF_UNION ubuf ; + DESC_CHUNK desc ; + sf_count_t chunk_size ; + double srate ; + short version, flags ; + int marker, k, have_data = 0, error ; + + if ((pcaf = psf->container_data) == NULL) + return SFE_INTERNAL ; + + memset (&desc, 0, sizeof (desc)) ; + + /* Set position to start of file to begin reading header. */ + psf_binheader_readf (psf, "pmE2E2", 0, &marker, &version, &flags) ; + psf_log_printf (psf, "%M\n Version : %d\n Flags : %x\n", marker, version, flags) ; + if (marker != caff_MARKER) + return SFE_CAF_NOT_CAF ; + + psf_binheader_readf (psf, "mE8b", &marker, &chunk_size, ubuf.ucbuf, 8) ; + srate = double64_be_read (ubuf.ucbuf) ; + snprintf (ubuf.cbuf, sizeof (ubuf.cbuf), "%5.3f", srate) ; + psf_log_printf (psf, "%M : %D\n Sample rate : %s\n", marker, chunk_size, ubuf.cbuf) ; + if (marker != desc_MARKER) + return SFE_CAF_NO_DESC ; + + if (chunk_size < SIGNED_SIZEOF (DESC_CHUNK)) + { psf_log_printf (psf, "**** Chunk size too small. Should be > 32 bytes.\n") ; + return SFE_MALFORMED_FILE ; + } ; + + psf->sf.samplerate = psf_lrint (srate) ; + + psf_binheader_readf (psf, "mE44444", &desc.fmt_id, &desc.fmt_flags, &desc.pkt_bytes, &desc.frames_per_packet, + &desc.channels_per_frame, &desc.bits_per_chan) ; + psf_log_printf (psf, " Format id : %M\n Format flags : %x\n Bytes / packet : %u\n" + " Frames / packet : %u\n Channels / frame : %u\n Bits / channel : %u\n", + desc.fmt_id, desc.fmt_flags, desc.pkt_bytes, desc.frames_per_packet, desc.channels_per_frame, desc.bits_per_chan) ; + + if (desc.channels_per_frame > SF_MAX_CHANNELS) + { psf_log_printf (psf, "**** Bad channels per frame value %u.\n", desc.channels_per_frame) ; + return SFE_MALFORMED_FILE ; + } ; + + if (chunk_size > SIGNED_SIZEOF (DESC_CHUNK)) + psf_binheader_readf (psf, "j", (int) (chunk_size - sizeof (DESC_CHUNK))) ; + + psf->sf.channels = desc.channels_per_frame ; + + while (1) + { marker = 0 ; + chunk_size = 0 ; + + psf_binheader_readf (psf, "mE8", &marker, &chunk_size) ; + if (marker == 0) + { sf_count_t pos = psf_ftell (psf) ; + psf_log_printf (psf, "Have 0 marker at position %D (0x%x).\n", pos, pos) ; + break ; + } ; + if (chunk_size < 0) + { psf_log_printf (psf, "%M : %D *** Should be >= 0 ***\n", marker, chunk_size) ; + break ; + } ; + if (chunk_size > psf->filelength) + break ; + + psf_store_read_chunk_u32 (&psf->rchunks, marker, psf_ftell (psf), chunk_size) ; + + switch (marker) + { case peak_MARKER : + psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ; + if (chunk_size != CAF_PEAK_CHUNK_SIZE (psf->sf.channels)) + { psf_binheader_readf (psf, "j", (size_t) chunk_size) ; + psf_log_printf (psf, "*** File PEAK chunk %D should be %d.\n", chunk_size, CAF_PEAK_CHUNK_SIZE (psf->sf.channels)) ; + return SFE_CAF_BAD_PEAK ; + } ; + + if (psf->peak_info) + { psf_log_printf (psf, "*** Found existing peak info, using last one.\n") ; + free (psf->peak_info) ; + psf->peak_info = NULL ; + } ; + if ((psf->peak_info = peak_info_calloc (psf->sf.channels)) == NULL) + return SFE_MALLOC_FAILED ; + + /* read in rest of PEAK chunk. */ + psf_binheader_readf (psf, "E4", & (psf->peak_info->edit_number)) ; + psf_log_printf (psf, " edit count : %d\n", psf->peak_info->edit_number) ; + + psf_log_printf (psf, " Ch Position Value\n") ; + for (k = 0 ; k < psf->sf.channels ; k++) + { sf_count_t position ; + float value ; + + psf_binheader_readf (psf, "Ef8", &value, &position) ; + psf->peak_info->peaks [k].value = value ; + psf->peak_info->peaks [k].position = position ; + + snprintf (ubuf.cbuf, sizeof (ubuf.cbuf), " %2d %-12" PRId64 " %g\n", k, position, value) ; + psf_log_printf (psf, ubuf.cbuf) ; + } ; + + psf->peak_info->peak_loc = SF_PEAK_START ; + break ; + + case chan_MARKER : + if (chunk_size < 12) + { psf_log_printf (psf, "%M : %D (should be >= 12)\n", marker, chunk_size) ; + psf_binheader_readf (psf, "j", (size_t) chunk_size) ; + break ; + } + + psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ; + + if ((error = caf_read_chanmap (psf, chunk_size))) + return error ; + break ; + + case free_MARKER : + psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ; + psf_binheader_readf (psf, "j", (size_t) chunk_size) ; + break ; + + case data_MARKER : + psf_binheader_readf (psf, "E4", &k) ; + if (chunk_size == -1) + { psf_log_printf (psf, "%M : -1\n") ; + chunk_size = psf->filelength - psf->header.indx ; + } + else if (psf->filelength > 0 && chunk_size > psf->filelength - psf->header.indx + 10) + { psf_log_printf (psf, "%M : %D (should be %D)\n", marker, chunk_size, psf->filelength - psf->header.indx - 8) ; + psf->datalength = psf->filelength - psf->header.indx - 8 ; + } + else + { psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ; + /* Subtract the 4 bytes of the 'edit' field above. */ + psf->datalength = chunk_size - 4 ; + } ; + + psf_log_printf (psf, " edit : %u\n", k) ; + + psf->dataoffset = psf->header.indx ; + if (psf->datalength + psf->dataoffset < psf->filelength) + psf->dataend = psf->datalength + psf->dataoffset ; + + psf_binheader_readf (psf, "j", (size_t) psf->datalength) ; + have_data = 1 ; + break ; + + case kuki_MARKER : + psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ; + pcaf->alac.kuki_offset = psf_ftell (psf) - 12 ; + psf_binheader_readf (psf, "j", (size_t) chunk_size) ; + break ; + + case pakt_MARKER : + if (chunk_size < 24) + { psf_log_printf (psf, "%M : %D (should be > 24)\n", marker, chunk_size) ; + return SFE_MALFORMED_FILE ; + } + else if (chunk_size > psf->filelength - psf->header.indx) + { psf_log_printf (psf, "%M : %D (should be < %D)\n", marker, chunk_size, psf->filelength - psf->header.indx) ; + return SFE_MALFORMED_FILE ; + } + else + psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ; + + psf_binheader_readf (psf, "E8844", &pcaf->alac.packets, &pcaf->alac.valid_frames, + &pcaf->alac.priming_frames, &pcaf->alac.remainder_frames) ; + + psf_log_printf (psf, + " Packets : %D\n" + " Valid frames : %D\n" + " Priming frames : %d\n" + " Remainder frames : %d\n", + pcaf->alac.packets, pcaf->alac.valid_frames, pcaf->alac.priming_frames, + pcaf->alac.remainder_frames + ) ; + + if (pcaf->alac.packets == 0 && pcaf->alac.valid_frames == 0 + && pcaf->alac.priming_frames == 0 && pcaf->alac.remainder_frames == 0) + psf_log_printf (psf, "*** 'pakt' chunk header is all zero.\n") ; + + pcaf->alac.pakt_offset = psf_ftell (psf) - 12 ; + psf_binheader_readf (psf, "j", (size_t) chunk_size - 24) ; + break ; + + case info_MARKER : + if (chunk_size < 4) + { psf_log_printf (psf, "%M : %D (should be > 4)\n", marker, chunk_size) ; + return SFE_MALFORMED_FILE ; + } + else if (chunk_size > psf->filelength - psf->header.indx) + { psf_log_printf (psf, "%M : %D (should be < %D)\n", marker, chunk_size, psf->filelength - psf->header.indx) ; + return SFE_MALFORMED_FILE ; + } ; + psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ; + if (chunk_size > 4) + caf_read_strings (psf, chunk_size - 4) ; + break ; + + default : + psf_log_printf (psf, "%M : %D (skipped)\n", marker, chunk_size) ; + psf_binheader_readf (psf, "j", (size_t) chunk_size) ; + break ; + } ; + + if (marker != data_MARKER && chunk_size >= 0xffffff00) + break ; + + if (! psf->sf.seekable && have_data) + break ; + + if (psf_ftell (psf) >= psf->filelength - SIGNED_SIZEOF (chunk_size)) + { psf_log_printf (psf, "End\n") ; + break ; + } ; + } ; + + if (have_data == 0) + { psf_log_printf (psf, "**** Error, could not find 'data' chunk.\n") ; + return SFE_MALFORMED_FILE ; + } ; + + psf->endian = (desc.fmt_flags & 2) ? SF_ENDIAN_LITTLE : SF_ENDIAN_BIG ; + + psf_fseek (psf, psf->dataoffset, SEEK_SET) ; + + if ((psf->sf.format = decode_desc_chunk (psf, &desc)) == 0) + return SFE_UNSUPPORTED_ENCODING ; + + if (psf->bytewidth > 0) + psf->sf.frames = psf->datalength / psf->bytewidth ; + + return 0 ; +} /* caf_read_header */ + +/*------------------------------------------------------------------------------ +*/ + +static int +caf_write_header (SF_PRIVATE *psf, int calc_length) +{ BUF_UNION ubuf ; + CAF_PRIVATE *pcaf ; + DESC_CHUNK desc ; + sf_count_t current ; + uint32_t uk ; + int subformat, append_free_block = SF_TRUE ; + + if ((pcaf = psf->container_data) == NULL) + return SFE_INTERNAL ; + + memset (&desc, 0, sizeof (desc)) ; + + current = psf_ftell (psf) ; + + if (calc_length) + { psf->filelength = psf_get_filelen (psf) ; + + psf->datalength = psf->filelength - psf->dataoffset ; + + if (psf->dataend) + psf->datalength -= psf->filelength - psf->dataend ; + + if (psf->bytewidth > 0) + psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ; + } ; + + /* Reset the current header length to zero. */ + psf->header.ptr [0] = 0 ; + psf->header.indx = 0 ; + psf_fseek (psf, 0, SEEK_SET) ; + + /* 'caff' marker, version and flags. */ + psf_binheader_writef (psf, "Em22", BHWm (caff_MARKER), BHW2 (1), BHW2 (0)) ; + + /* 'desc' marker and chunk size. */ + psf_binheader_writef (psf, "Em8", BHWm (desc_MARKER), BHW8 ((sf_count_t) (sizeof (DESC_CHUNK)))) ; + + double64_be_write (1.0 * psf->sf.samplerate, ubuf.ucbuf) ; + psf_binheader_writef (psf, "b", BHWv (ubuf.ucbuf), BHWz (8)) ; + + subformat = SF_CODEC (psf->sf.format) ; + + psf->endian = SF_ENDIAN (psf->sf.format) ; + + if (CPU_IS_BIG_ENDIAN && (psf->endian == 0 || psf->endian == SF_ENDIAN_CPU)) + psf->endian = SF_ENDIAN_BIG ; + else if (CPU_IS_LITTLE_ENDIAN && (psf->endian == SF_ENDIAN_LITTLE || psf->endian == SF_ENDIAN_CPU)) + psf->endian = SF_ENDIAN_LITTLE ; + + if (psf->endian == SF_ENDIAN_LITTLE) + desc.fmt_flags = 2 ; + else + psf->endian = SF_ENDIAN_BIG ; + + /* initial section (same for all, it appears) */ + switch (subformat) + { case SF_FORMAT_PCM_S8 : + desc.fmt_id = lpcm_MARKER ; + psf->bytewidth = 1 ; + desc.pkt_bytes = psf->bytewidth * psf->sf.channels ; + desc.frames_per_packet = 1 ; + desc.channels_per_frame = psf->sf.channels ; + desc.bits_per_chan = 8 ; + break ; + + case SF_FORMAT_PCM_16 : + desc.fmt_id = lpcm_MARKER ; + psf->bytewidth = 2 ; + desc.pkt_bytes = psf->bytewidth * psf->sf.channels ; + desc.frames_per_packet = 1 ; + desc.channels_per_frame = psf->sf.channels ; + desc.bits_per_chan = 16 ; + break ; + + case SF_FORMAT_PCM_24 : + psf->bytewidth = 3 ; + desc.pkt_bytes = psf->bytewidth * psf->sf.channels ; + desc.frames_per_packet = 1 ; + desc.channels_per_frame = psf->sf.channels ; + desc.bits_per_chan = 24 ; + desc.fmt_id = lpcm_MARKER ; + break ; + + case SF_FORMAT_PCM_32 : + desc.fmt_id = lpcm_MARKER ; + psf->bytewidth = 4 ; + desc.pkt_bytes = psf->bytewidth * psf->sf.channels ; + desc.frames_per_packet = 1 ; + desc.channels_per_frame = psf->sf.channels ; + desc.bits_per_chan = 32 ; + break ; + + case SF_FORMAT_FLOAT : + desc.fmt_id = lpcm_MARKER ; + desc.fmt_flags |= 1 ; + psf->bytewidth = 4 ; + desc.pkt_bytes = psf->bytewidth * psf->sf.channels ; + desc.frames_per_packet = 1 ; + desc.channels_per_frame = psf->sf.channels ; + desc.bits_per_chan = 32 ; + break ; + + case SF_FORMAT_DOUBLE : + desc.fmt_id = lpcm_MARKER ; + desc.fmt_flags |= 1 ; + psf->bytewidth = 8 ; + desc.pkt_bytes = psf->bytewidth * psf->sf.channels ; + desc.frames_per_packet = 1 ; + desc.channels_per_frame = psf->sf.channels ; + desc.bits_per_chan = 64 ; + break ; + + case SF_FORMAT_ALAW : + desc.fmt_id = alaw_MARKER ; + psf->bytewidth = 1 ; + desc.pkt_bytes = psf->bytewidth * psf->sf.channels ; + desc.frames_per_packet = 1 ; + desc.channels_per_frame = psf->sf.channels ; + desc.bits_per_chan = 8 ; + break ; + + case SF_FORMAT_ULAW : + desc.fmt_id = ulaw_MARKER ; + psf->bytewidth = 1 ; + desc.pkt_bytes = psf->bytewidth * psf->sf.channels ; + desc.frames_per_packet = 1 ; + desc.channels_per_frame = psf->sf.channels ; + desc.bits_per_chan = 8 ; + break ; + + case SF_FORMAT_ALAC_16 : + case SF_FORMAT_ALAC_20 : + case SF_FORMAT_ALAC_24 : + case SF_FORMAT_ALAC_32 : + desc.fmt_id = alac_MARKER ; + desc.pkt_bytes = psf->bytewidth * psf->sf.channels ; + desc.channels_per_frame = psf->sf.channels ; + alac_get_desc_chunk_items (subformat, &desc.fmt_flags, &desc.frames_per_packet) ; + append_free_block = SF_FALSE ; + break ; + + default : + return SFE_UNIMPLEMENTED ; + } ; + + psf_binheader_writef (psf, "mE44444", BHWm (desc.fmt_id), BHW4 (desc.fmt_flags), BHW4 (desc.pkt_bytes), BHW4 (desc.frames_per_packet), BHW4 (desc.channels_per_frame), BHW4 (desc.bits_per_chan)) ; + + caf_write_strings (psf, SF_STR_LOCATE_START) ; + + if (psf->peak_info != NULL) + { int k ; + psf_binheader_writef (psf, "Em84", BHWm (peak_MARKER), BHW8 ((sf_count_t) CAF_PEAK_CHUNK_SIZE (psf->sf.channels)), BHW4 (psf->peak_info->edit_number)) ; + for (k = 0 ; k < psf->sf.channels ; k++) + psf_binheader_writef (psf, "Ef8", BHWf ((float) psf->peak_info->peaks [k].value), BHW8 (psf->peak_info->peaks [k].position)) ; + } ; + + if (psf->channel_map && pcaf->chanmap_tag) + psf_binheader_writef (psf, "Em8444", BHWm (chan_MARKER), BHW8 ((sf_count_t) 12), BHW4 (pcaf->chanmap_tag), BHW4 (0), BHW4 (0)) ; + + /* Write custom headers. */ + for (uk = 0 ; uk < psf->wchunks.used ; uk++) + psf_binheader_writef (psf, "m44b", BHWm ((int) psf->wchunks.chunks [uk].mark32), BHW4 (0), BHW4 (psf->wchunks.chunks [uk].len), BHWv (psf->wchunks.chunks [uk].data), BHWz (psf->wchunks.chunks [uk].len)) ; + + if (append_free_block) + { /* Add free chunk so that the actual audio data starts at a multiple 0x1000. */ + sf_count_t free_len = 0x1000 - psf->header.indx - 16 - 12 ; + while (free_len < 0) + free_len += 0x1000 ; + psf_binheader_writef (psf, "Em8z", BHWm (free_MARKER), BHW8 (free_len), BHWz (free_len)) ; + } ; + + psf_binheader_writef (psf, "Em84", BHWm (data_MARKER), BHW8 (psf->datalength + 4), BHW4 (0)) ; + + psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ; + if (psf->error) + return psf->error ; + + psf->dataoffset = psf->header.indx ; + if (current < psf->dataoffset) + psf_fseek (psf, psf->dataoffset, SEEK_SET) ; + else if (current > 0) + psf_fseek (psf, current, SEEK_SET) ; + + return psf->error ; +} /* caf_write_header */ + +static int +caf_write_tailer (SF_PRIVATE *psf) +{ + /* Reset the current header buffer length to zero. */ + psf->header.ptr [0] = 0 ; + psf->header.indx = 0 ; + + if (psf->bytewidth > 0 && psf->sf.seekable == SF_TRUE) + { psf->datalength = psf->sf.frames * psf->bytewidth * psf->sf.channels ; + psf->dataend = psf->dataoffset + psf->datalength ; + } ; + + if (psf->dataend > 0) + psf_fseek (psf, psf->dataend, SEEK_SET) ; + else + psf->dataend = psf_fseek (psf, 0, SEEK_END) ; + + if (psf->dataend & 1) + psf_binheader_writef (psf, "z", BHWz (1)) ; + + if (psf->strings.flags & SF_STR_LOCATE_END) + caf_write_strings (psf, SF_STR_LOCATE_END) ; + + /* Write the tailer. */ + if (psf->header.indx > 0) + psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ; + + return 0 ; +} /* caf_write_tailer */ + +static int +caf_read_chanmap (SF_PRIVATE * psf, sf_count_t chunk_size) +{ const AIFF_CAF_CHANNEL_MAP * map_info ; + unsigned channel_bitmap, channel_decriptions, bytesread ; + int layout_tag ; + + bytesread = psf_binheader_readf (psf, "E444", &layout_tag, &channel_bitmap, &channel_decriptions) ; + + map_info = aiff_caf_of_channel_layout_tag (layout_tag) ; + + psf_log_printf (psf, " Tag : %x\n", layout_tag) ; + if (map_info) + psf_log_printf (psf, " Layout : %s\n", map_info->name) ; + + if (bytesread < chunk_size) + psf_binheader_readf (psf, "j", chunk_size - bytesread) ; + + if (map_info && map_info->channel_map != NULL) + { size_t chanmap_size = SF_MIN (psf->sf.channels, layout_tag & 0xff) * sizeof (psf->channel_map [0]) ; + + free (psf->channel_map) ; + + if ((psf->channel_map = malloc (chanmap_size)) == NULL) + return SFE_MALLOC_FAILED ; + + memcpy (psf->channel_map, map_info->channel_map, chanmap_size) ; + } ; + + return 0 ; +} /* caf_read_chanmap */ + + +static uint32_t +string_hash32 (const char * str) +{ uint32_t hash = 0x87654321 ; + + while (str [0]) + { hash = hash * 333 + str [0] ; + str ++ ; + } ; + + return hash ; +} /* string_hash32 */ + +static int +caf_read_strings (SF_PRIVATE * psf, sf_count_t chunk_size) +{ char *buf ; + char *key, *value ; + uint32_t count, hash ; + + if ((buf = malloc (chunk_size + 1)) == NULL) + return (psf->error = SFE_MALLOC_FAILED) ; + + psf_binheader_readf (psf, "E4b", &count, buf, (size_t) chunk_size) ; + psf_log_printf (psf, " count: %u\n", count) ; + + /* Force terminate `buf` to make sure. */ + buf [chunk_size] = 0 ; + + for (key = buf ; key < buf + chunk_size ; ) + { value = key + strlen (key) + 1 ; + if (value > buf + chunk_size) + break ; + psf_log_printf (psf, " %-12s : %s\n", key, value) ; + + hash = string_hash32 (key) ; + switch (hash) + { case 0xC4861943 : /* 'title' */ + psf_store_string (psf, SF_STR_TITLE, value) ; + break ; + case 0xAD47A394 : /* 'software' */ + psf_store_string (psf, SF_STR_SOFTWARE, value) ; + break ; + case 0x5D178E2A : /* 'copyright' */ + psf_store_string (psf, SF_STR_COPYRIGHT, value) ; + break ; + case 0x60E4D0C8 : /* 'artist' */ + psf_store_string (psf, SF_STR_ARTIST, value) ; + break ; + case 0x83B5D16A : /* 'genre' */ + psf_store_string (psf, SF_STR_GENRE, value) ; + break ; + case 0x15E5FC88 : /* 'comment' */ + case 0x7C297D5B : /* 'comments' */ + psf_store_string (psf, SF_STR_COMMENT, value) ; + break ; + case 0x24A7C347 : /* 'tracknumber' */ + psf_store_string (psf, SF_STR_TRACKNUMBER, value) ; + break ; + case 0x50A31EB7 : /* 'date' */ + psf_store_string (psf, SF_STR_DATE, value) ; + break ; + case 0x6583545A : /* 'album' */ + psf_store_string (psf, SF_STR_ALBUM, value) ; + break ; + case 0xE7C64B6C : /* 'license' */ + psf_store_string (psf, SF_STR_LICENSE, value) ; + break ; + default : + psf_log_printf (psf, " Unhandled hash 0x%x : /* '%s' */\n", hash, key) ; + break ; + } ; + + key = value + strlen (value) + 1 ; + } ; + + free (buf) ; + + return 0 ; +} /* caf_read_strings */ + +struct put_buffer +{ uint32_t index ; + char s [16 * 1024] ; +} ; + +static uint32_t +put_key_value (struct put_buffer * buf, const char * key, const char * value) +{ uint32_t written ; + + if (buf->index + strlen (key) + strlen (value) + 2 > sizeof (buf->s)) + return 0 ; + + written = snprintf (buf->s + buf->index, sizeof (buf->s) - buf->index, "%s%c%s%c", key, 0, value, 0) ; + + if (buf->index + written >= sizeof (buf->s)) + return 0 ; + + buf->index += written ; + return 1 ; +} /* put_key_value */ + +static void +caf_write_strings (SF_PRIVATE * psf, int location) +{ struct put_buffer buf ; + const char * cptr ; + uint32_t k, string_count = 0 ; + + memset (&buf, 0, sizeof (buf)) ; + + for (k = 0 ; k < SF_MAX_STRINGS ; k++) + { if (psf->strings.data [k].type == 0) + break ; + + if (psf->strings.data [k].flags != location) + continue ; + + if ((cptr = psf_get_string (psf, psf->strings.data [k].type)) == NULL) + continue ; + + switch (psf->strings.data [k].type) + { case SF_STR_TITLE : + string_count += put_key_value (&buf, "title", cptr) ; + break ; + case SF_STR_COPYRIGHT : + string_count += put_key_value (&buf, "copyright", cptr) ; + break ; + case SF_STR_SOFTWARE : + string_count += put_key_value (&buf, "software", cptr) ; + break ; + case SF_STR_ARTIST : + string_count += put_key_value (&buf, "artist", cptr) ; + break ; + case SF_STR_COMMENT : + string_count += put_key_value (&buf, "comment", cptr) ; + break ; + case SF_STR_DATE : + string_count += put_key_value (&buf, "date", cptr) ; + break ; + case SF_STR_ALBUM : + string_count += put_key_value (&buf, "album", cptr) ; + break ; + case SF_STR_LICENSE : + string_count += put_key_value (&buf, "license", cptr) ; + break ; + case SF_STR_TRACKNUMBER : + string_count += put_key_value (&buf, "tracknumber", cptr) ; + break ; + case SF_STR_GENRE : + string_count += put_key_value (&buf, "genre", cptr) ; + break ; + + default : + break ; + } ; + } ; + + if (string_count == 0 || buf.index == 0) + return ; + + psf_binheader_writef (psf, "Em84b", BHWm (info_MARKER), BHW8 (buf.index + 4), BHW4 (string_count), BHWv (buf.s), BHWz (buf.index)) ; +} /* caf_write_strings */ + +/*============================================================================== +*/ + +static int +caf_set_chunk (SF_PRIVATE *psf, const SF_CHUNK_INFO * chunk_info) +{ return psf_save_write_chunk (&psf->wchunks, chunk_info) ; +} /* caf_set_chunk */ + +static SF_CHUNK_ITERATOR * +caf_next_chunk_iterator (SF_PRIVATE *psf, SF_CHUNK_ITERATOR * iterator) +{ return psf_next_chunk_iterator (&psf->rchunks, iterator) ; +} /* caf_next_chunk_iterator */ + +static int +caf_get_chunk_size (SF_PRIVATE *psf, const SF_CHUNK_ITERATOR * iterator, SF_CHUNK_INFO * chunk_info) +{ int indx ; + + if ((indx = psf_find_read_chunk_iterator (&psf->rchunks, iterator)) < 0) + return SFE_UNKNOWN_CHUNK ; + + chunk_info->datalen = psf->rchunks.chunks [indx].len ; + + return SFE_NO_ERROR ; +} /* caf_get_chunk_size */ + +static int +caf_get_chunk_data (SF_PRIVATE *psf, const SF_CHUNK_ITERATOR * iterator, SF_CHUNK_INFO * chunk_info) +{ int indx ; + sf_count_t pos ; + + if ((indx = psf_find_read_chunk_iterator (&psf->rchunks, iterator)) < 0) + return SFE_UNKNOWN_CHUNK ; + + if (chunk_info->data == NULL) + return SFE_BAD_CHUNK_DATA_PTR ; + + chunk_info->id_size = psf->rchunks.chunks [indx].id_size ; + memcpy (chunk_info->id, psf->rchunks.chunks [indx].id, sizeof (chunk_info->id) / sizeof (*chunk_info->id)) ; + + pos = psf_ftell (psf) ; + psf_fseek (psf, psf->rchunks.chunks [indx].offset, SEEK_SET) ; + psf_fread (chunk_info->data, SF_MIN (chunk_info->datalen, psf->rchunks.chunks [indx].len), 1, psf) ; + psf_fseek (psf, pos, SEEK_SET) ; + + return SFE_NO_ERROR ; +} /* caf_get_chunk_data */ diff --git a/extern/libsndfile-modified/src/cart.c b/extern/libsndfile-modified/src/cart.c new file mode 100644 index 000000000..8b00eab16 --- /dev/null +++ b/extern/libsndfile-modified/src/cart.c @@ -0,0 +1,101 @@ +/* +** Copyright (C) 2012 Chris Roberts +** Copyright (C) 2006-2013 Erik de Castro Lopo +** Copyright (C) 2006 Paul Davis +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include +#include "common.h" + + + +static inline size_t +cart_min_size (const SF_CART_INFO* info) +{ if (info == NULL) + return 0 ; + + return offsetof (SF_CART_INFO, tag_text) + info->tag_text_size ; +} /* cart_min_size */ + +SF_CART_INFO_16K* +cart_var_alloc (void) +{ SF_CART_INFO_16K* thing ; + thing = malloc (sizeof (SF_CART_INFO_16K)) ; + return thing ; +} /* cart_var_alloc */ + +int +cart_var_set (SF_PRIVATE *psf, const SF_CART_INFO * info, size_t datasize) +{ size_t len ; + + if (info == NULL) + return SF_FALSE ; + + if (cart_min_size (info) > datasize) + { psf->error = SFE_BAD_CART_INFO_SIZE ; + return SF_FALSE ; + } ; + + if (datasize >= sizeof (SF_CART_INFO_16K)) + { psf->error = SFE_BAD_CART_INFO_TOO_BIG ; + return SF_FALSE ; + } ; + + if (psf->cart_16k == NULL) + { if ((psf->cart_16k = cart_var_alloc ()) == NULL) + { psf->error = SFE_MALLOC_FAILED ; + return SF_FALSE ; + } ; + } ; + + memcpy (psf->cart_16k, info, offsetof (SF_CART_INFO, tag_text)) ; + psf_strlcpy_crlf (psf->cart_16k->tag_text, info->tag_text, sizeof (psf->cart_16k->tag_text), datasize - offsetof (SF_CART_INFO, tag_text)) ; + + len = strlen (psf->cart_16k->tag_text) ; + + if (len > 0 && psf->cart_16k->tag_text [len - 1] != '\n') + psf_strlcat (psf->cart_16k->tag_text, sizeof (psf->cart_16k->tag_text), "\r\n") ; + + /* Force tag_text_size to be even. */ + len = strlen (psf->cart_16k->tag_text) ; + len += (len & 1) ? 1 : 2 ; + + psf->cart_16k->tag_text_size = (uint32_t) len ; + + return SF_TRUE ; +} /* cart_var_set */ + + +int +cart_var_get (SF_PRIVATE *psf, SF_CART_INFO * data, size_t datasize) +{ size_t size ; + if (psf->cart_16k == NULL) + return SF_FALSE ; + + size = SF_MIN (datasize, cart_min_size ((const SF_CART_INFO *) psf->cart_16k)) ; + + memcpy (data, psf->cart_16k, size) ; + + return SF_TRUE ; +} /* cart_var_get */ + + diff --git a/extern/libsndfile-modified/src/chanmap.c b/extern/libsndfile-modified/src/chanmap.c new file mode 100644 index 000000000..c06702ca0 --- /dev/null +++ b/extern/libsndfile-modified/src/chanmap.c @@ -0,0 +1,262 @@ +/* +** Copyright (C) 2009-2014 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/* +** Mostly from "Apple Core Audio Format Specification 1.0": +** +** http://developer.apple.com/documentation/MusicAudio/Reference/CAFSpec/CAFSpec.pdf +*/ + +#include "sfconfig.h" + +#include +#include +#include + +#include "sndfile.h" +#include "common.h" +#include "chanmap.h" + + +static const AIFF_CAF_CHANNEL_MAP zero_chan [] = +{ { (0 << 16) | 0, NULL, "Use channel descriptions." }, + { (1 << 16) | 0, NULL, "Use channel bitmap." } +} ; /* zero_chan */ + + +static const int one_chan_mono [1] = { SF_CHANNEL_MAP_MONO } ; + +static const AIFF_CAF_CHANNEL_MAP one_chan [] = +{ { (100 << 16) | 1, one_chan_mono, "mono" } +} ; /* one_chan */ + + +static const int two_channel_stereo [2] = { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT } ; + +static const AIFF_CAF_CHANNEL_MAP two_chan [] = +{ { (101 << 16) | 2, two_channel_stereo, "stereo (L, R)" }, + { (102 << 16) | 2, two_channel_stereo, "stereo headphones (L, R)" }, +#if 0 + { (103 << 16) | 2, NULL, "matrix stereo (Lt, Rt)" }, + { (104 << 16) | 2, NULL, "2 channels (mid, side)" }, + { (105 << 16) | 2, NULL, "coincident mic pair" }, + { (106 << 16) | 2, NULL, "binaural stereo (L, R)" + } +#endif +} ; /* two_chan */ + + +static const int three_channel_mpeg_30a [3] = + { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_CENTER } ; +static const int three_channel_mpeg_30b [3] = + { SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT } ; +static const int three_channel_itu_21 [3] = + { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_CENTER } ; +static const int three_channel_dvd_4 [3] = + { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_LFE } ; + +static const AIFF_CAF_CHANNEL_MAP three_chan [] = +{ { (113 << 16) | 3, three_channel_mpeg_30a, "MPEG 3 0 A (L, R, C)" }, + { (114 << 16) | 3, three_channel_mpeg_30b, "MPEG 3 0 B (C, L, R)" }, + { (131 << 16) | 3, three_channel_itu_21, "ITU 2.1 (L, R, Cs)" }, + { (133 << 16) | 3, three_channel_dvd_4, "DVD 4 (L, R, LFE)" } +} ; /* three_chan */ + + +static const int four_channel_ambisonc_b [4] = + { SF_CHANNEL_MAP_AMBISONIC_B_W, SF_CHANNEL_MAP_AMBISONIC_B_X, SF_CHANNEL_MAP_AMBISONIC_B_Y, SF_CHANNEL_MAP_AMBISONIC_B_Z } ; +static const int four_channel_quad [4] = + { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT } ; +static const int four_channel_mpeg_40a [4] = + { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_REAR_CENTER } ; +static const int four_channel_mpeg_40b [4] = + { SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_CENTER } ; +static const int four_channel_itu_23 [4] = + { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT } ; +static const int four_channel_dvd_5 [4] = + { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_LFE, SF_CHANNEL_MAP_REAR_CENTER } ; +static const int four_channel_dvd_10 [4] = + { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LFE } ; + +static const AIFF_CAF_CHANNEL_MAP four_chan [] = +{ { (107 << 16) | 4, four_channel_ambisonc_b, "ambisonic B (W, X, Y, Z)" }, + { (108 << 16) | 4, four_channel_quad, "quad (Lfront, Rfront, Lrear, Rrear)" }, + { (115 << 16) | 4, four_channel_mpeg_40a, "MPEG 4.0 A (L, R, C, Cs)" }, + { (116 << 16) | 4, four_channel_mpeg_40b, "MPEG 4.0 B (C, L, R, Cs)" }, + { (132 << 16) | 4, four_channel_itu_23, "ITU 2.3 (L, R, Ls, Rs)" }, + { (134 << 16) | 4, four_channel_dvd_5, "DVD 5 (L, R, LFE, Cs)" }, + { (136 << 16) | 4, four_channel_dvd_10, "DVD 10 (L, R, C, LFE)" } +} ; /* four_chan */ + + +static const int five_channel_pentagonal [5] = + { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT, SF_CHANNEL_MAP_CENTER } ; +static const int five_channel_mpeg_50_a [5] = + { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT } ; +static const int five_channel_mpeg_50_b [5] = + { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT, SF_CHANNEL_MAP_CENTER } ; +static const int five_channel_mpeg_50_c [5] = + { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT } ; +static const int five_channel_mpeg_50_d [5] = + { SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT } ; +static const int five_channel_dvd_6 [5] = + { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_LFE, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT } ; +static const int five_channel_dvd_11 [5] = + { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LFE, SF_CHANNEL_MAP_REAR_CENTER } ; +static const int five_channel_dvd_18 [5] = + { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT, SF_CHANNEL_MAP_LFE } ; + +static const AIFF_CAF_CHANNEL_MAP five_chan [] = +{ { (109 << 16) | 5, five_channel_pentagonal, "pentagonal (L, R, Lrear, Rrear, C)" }, + { (117 << 16) | 5, five_channel_mpeg_50_a, "MPEG 5.0 A (L, R, C, Ls, Rs)" }, + { (118 << 16) | 5, five_channel_mpeg_50_b, "MPEG 5.0 B (L, R, Ls, Rs, C)" }, + { (119 << 16) | 5, five_channel_mpeg_50_c, "MPEG 5.0 C (L, C, R, Ls, Rs,)" }, + { (120 << 16) | 5, five_channel_mpeg_50_d, "MPEG 5.0 D (C, L, R, Ls, Rs)" }, + { (135 << 16) | 5, five_channel_dvd_6, "DVD 6 (L, R, LFE, Ls, Rs)" }, + { (137 << 16) | 5, five_channel_dvd_11, "DVD 11 (L, R, C, LFE, Cs)" }, + { (138 << 16) | 5, five_channel_dvd_18, "DVD 18 (L, R, Ls, Rs, LFE)" } +} ; /* five_chan */ + + +static const int six_channel_mpeg_51_a [6] = + { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LFE, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT } ; +static const int six_channel_mpeg_51_b [6] = + { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT, SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LFE } ; +static const int six_channel_mpeg_51_c [6] = + { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT, SF_CHANNEL_MAP_LFE } ; +static const int six_channel_mpeg_51_d [6] = + { SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT, SF_CHANNEL_MAP_LFE } ; +static const int six_channel_audio_unit_60 [6] = + { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT, SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_REAR_CENTER } ; +static const int six_channel_aac_60 [6] = + { SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT, SF_CHANNEL_MAP_REAR_CENTER } ; + +static const AIFF_CAF_CHANNEL_MAP six_chan [] = +{ { (110 << 16) | 6, NULL, "hexagonal (L, R, Lr, Rr, C, Rear)" }, + { (121 << 16) | 6, six_channel_mpeg_51_a, "MPEG 5.1 A (L, R, C, LFE, Ls, Rs)" }, + { (122 << 16) | 6, six_channel_mpeg_51_b, "MPEG 5.1 B (L, R, Ls, Rs, C, LFE)" }, + { (123 << 16) | 6, six_channel_mpeg_51_c, "MPEG 5.1 C (L, C, R, Ls, Rs, LFE)" }, + { (124 << 16) | 6, six_channel_mpeg_51_d, "MPEG 5.1 D (C, L, R, Ls, Rs, LFE)" }, + { (139 << 16) | 6, six_channel_audio_unit_60, "AudioUnit 6.0 (L, R, Ls, Rs, C, Cs)" }, + { (141 << 16) | 6, six_channel_aac_60, "AAC 6.0 (C, L, R, Ls, Rs, Cs)" } +} ; /* six_chan */ + + +static const int six_channel_mpeg_61a [7] = + { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LFE, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT, SF_CHANNEL_MAP_REAR_CENTER } ; +static const int six_channel_aac_61 [7] = + { SF_CHANNEL_MAP_CENTER, SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT, SF_CHANNEL_MAP_REAR_CENTER, SF_CHANNEL_MAP_LFE } ; + +static const AIFF_CAF_CHANNEL_MAP seven_chan [] = +{ { (125 << 16) | 7, six_channel_mpeg_61a, "MPEG 6.1 A (L, R, C, LFE, Ls, Rs, Cs)" }, + { (140 << 16) | 7, NULL, "AudioUnit 7.0 (L, R, Ls, Rs, C, Rls, Rrs)" }, + { (142 << 16) | 7, six_channel_aac_61, "AAC 6.1 (C, L, R, Ls, Rs, Cs, Lfe)" }, + { (143 << 16) | 7, NULL, "AAC 7.0 (C, L, R, Ls, Rs, Rls, Rrs,)" } +} ; /* seven_chan */ + + +static const AIFF_CAF_CHANNEL_MAP eight_chan [] = +{ { (111 << 16) | 8, NULL, + // front left, front right, rear left, rear right, + // front center, rear center, side left, side right + "octagonal (Lf, Rf, Lr, Rr, Cf, Cr, Ls, Rs)" + }, + { (112 << 16) | 8, NULL, + // left, right, rear left, rear right + // top left, top right, top rear left, top rear right + "cube (L, R, Lrear, Rrear, Ltop, Rtop, Ltoprear, Rtoprear)" + }, + { (126 << 16) | 8, NULL, "MPEG 7.1 A (L, R, C, LFE, Ls, Rs, Lc, Rc)" }, + { (127 << 16) | 8, NULL, "MPEG 7.1 B (C, Lc, Rc, L, R, Ls, Rs, LFE)" }, + { (128 << 16) | 8, NULL, "MPEG 7.1 C (L, R, C, LFE, Ls, R, Rls, Rrs)" }, + { (129 << 16) | 8, NULL, "Emagic Default 7.1 (L, R, Ls, Rs, C, LFE, Lc, Rc)" }, + { (130 << 16) | 8, NULL, + // (ITU_5_1 plus a matrix encoded stereo mix) + "SMPTE DTV (L, R, C, LFE, Ls, Rs, Lt, Rt)" + }, + { (144 << 16) | 8, NULL, "AAC octagonal (C, L, R, Ls, Rs, Rls, Rrs, Cs)" } +} ; /* eight_chan */ + + + +#if 0 + +TMH_10_2_std = (145 << 16) | 16, +// L R C Vhc Lsd Rsd Ls Rs Vhl Vhr Lw Rw Csd Cs LFE1 LFE2 + +TMH_10_2_full = (146 << 16) | 21, +// TMH_10_2_std plus: Lc Rc HI VI Haptic + +#endif + + +typedef struct +{ const AIFF_CAF_CHANNEL_MAP * map ; + int len ; +} MAP_MAP ; + +static const MAP_MAP map [] = +{ { zero_chan, ARRAY_LEN (zero_chan) }, + { one_chan, ARRAY_LEN (one_chan) }, + { two_chan, ARRAY_LEN (two_chan) }, + { three_chan, ARRAY_LEN (three_chan) }, + { four_chan, ARRAY_LEN (four_chan) }, + { five_chan, ARRAY_LEN (five_chan) }, + { six_chan, ARRAY_LEN (six_chan) }, + { seven_chan, ARRAY_LEN (seven_chan) }, + { eight_chan, ARRAY_LEN (eight_chan) } +} ; /* map */ + + +int +aiff_caf_find_channel_layout_tag (const int *chan_map, int channels) +{ const AIFF_CAF_CHANNEL_MAP * curr_map ; + unsigned k, len ; + + if (channels < 1 || channels >= ARRAY_LEN (map)) + return 0 ; + + curr_map = map [channels].map ; + len = map [channels].len ; + + for (k = 0 ; k < len ; k++) + if (curr_map [k].channel_map != NULL) + if (memcmp (chan_map, curr_map [k].channel_map, channels * sizeof (chan_map [0])) == 0) + return curr_map [k].channel_layout_tag ; + + return 0 ; +} /* aiff_caf_find_channel_layout_tag */ + +const AIFF_CAF_CHANNEL_MAP * +aiff_caf_of_channel_layout_tag (int tag) +{ const AIFF_CAF_CHANNEL_MAP * curr_map ; + unsigned k, len ; + int channels = tag & 0xffff ; + + if (channels < 0 || channels >= ARRAY_LEN (map)) + return NULL ; + + curr_map = map [channels].map ; + len = map [channels].len ; + + for (k = 0 ; k < len ; k++) + if (curr_map [k].channel_layout_tag == tag) + return curr_map + k ; + + return NULL ; +} /* aiff_caf_of_channel_layout_tag */ diff --git a/extern/libsndfile-modified/src/chanmap.h b/extern/libsndfile-modified/src/chanmap.h new file mode 100644 index 000000000..8af409dba --- /dev/null +++ b/extern/libsndfile-modified/src/chanmap.h @@ -0,0 +1,32 @@ +/* +** Copyright (C) 2009-2011 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +typedef struct +{ /* The tag in the AIFF or CAF file. */ + int channel_layout_tag ; + + /* The equivalent array of SF_CHANNEL_MAP_* entries. */ + const int * channel_map ; + + const char * name ; +} AIFF_CAF_CHANNEL_MAP ; + + +int aiff_caf_find_channel_layout_tag (const int *chan_map, int channels) ; + +const AIFF_CAF_CHANNEL_MAP * aiff_caf_of_channel_layout_tag (int tag) ; diff --git a/extern/libsndfile-modified/src/chunk.c b/extern/libsndfile-modified/src/chunk.c new file mode 100644 index 000000000..9b181fc74 --- /dev/null +++ b/extern/libsndfile-modified/src/chunk.c @@ -0,0 +1,266 @@ +/* +** Copyright (C) 2008-2016 Erik de Castro Lopo +** Copyright (C) 2012 IOhannes m zmoelnig, IEM +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + +static int64_t +hash_of_str (const char * str) +{ int64_t marker = 0 ; + int k ; + + for (k = 0 ; str [k] ; k++) + marker = marker * 0x7f + ((const uint8_t *) str) [k] ; + + return marker ; +} /* hash_of_str */ + +SF_CHUNK_ITERATOR * +psf_get_chunk_iterator (SF_PRIVATE * psf, const char * marker_str) +{ const READ_CHUNKS * pchk = &psf->rchunks ; + int idx ; + + if (marker_str) + idx = psf_find_read_chunk_str (pchk, marker_str) ; + else + idx = pchk->used > 0 ? 0 : -1 ; + + if (idx < 0) + return NULL ; + + if (psf->iterator == NULL) + { psf->iterator = calloc (1, sizeof (SF_CHUNK_ITERATOR)) ; + if (psf->iterator == NULL) + return NULL ; + } ; + + psf->iterator->sndfile = (SNDFILE *) psf ; + + if (marker_str) + { int64_t hash ; + size_t marker_len ; + union + { uint32_t marker ; + char str [5] ; + } u ; + + snprintf (u.str, sizeof (u.str), "%s", marker_str) ; + + marker_len = strlen (marker_str) ; + if (marker_len > 64) + marker_len = 64 ; + + hash = marker_len > 4 ? hash_of_str (marker_str) : u.marker ; + + memcpy (psf->iterator->id, marker_str, marker_len) ; + psf->iterator->id_size = (unsigned) marker_len ; + psf->iterator->hash = hash ; + } + + psf->iterator->current = idx ; + + return psf->iterator ; +} /* psf_get_chunk_iterator */ + +SF_CHUNK_ITERATOR * +psf_next_chunk_iterator (const READ_CHUNKS * pchk , SF_CHUNK_ITERATOR * iterator) +{ uint64_t hash = iterator->hash ; + uint32_t k ; + + iterator->current++ ; + + if (hash) + { for (k = iterator->current ; k < pchk->used ; k++) + if (pchk->chunks [k].hash == hash) + { iterator->current = k ; + return iterator ; + } + } + else if (iterator->current < pchk->used) + return iterator ; + + /* No match, clear iterator and return NULL */ + memset (iterator, 0, sizeof (*iterator)) ; + return NULL ; +} /* psf_next_chunk_iterator */ + +static int +psf_store_read_chunk (READ_CHUNKS * pchk, const READ_CHUNK * rchunk) +{ if (pchk->count == 0) + { pchk->used = 0 ; + pchk->count = 20 ; + pchk->chunks = calloc (pchk->count, sizeof (READ_CHUNK)) ; + if (!pchk->chunks) + { return SFE_MALLOC_FAILED ; + } ; + } + else if (pchk->used > pchk->count) + return SFE_INTERNAL ; + else if (pchk->used == pchk->count) + { READ_CHUNK * old_ptr = pchk->chunks ; + int new_count = 3 * (pchk->count + 1) / 2 ; + + READ_CHUNK * new_chunks = realloc (old_ptr, new_count * sizeof (READ_CHUNK)) ; + if (new_chunks == NULL) + { + return SFE_MALLOC_FAILED ; + } else { + pchk->chunks = new_chunks; + } ; + pchk->count = new_count ; + } ; + + pchk->chunks [pchk->used] = *rchunk ; + + pchk->used ++ ; + + return SFE_NO_ERROR ; +} /* psf_store_read_chunk */ + +int +psf_store_read_chunk_u32 (READ_CHUNKS * pchk, uint32_t marker, sf_count_t offset, uint32_t len) +{ READ_CHUNK rchunk ; + + memset (&rchunk, 0, sizeof (rchunk)) ; + + rchunk.hash = marker ; + rchunk.mark32 = marker ; + rchunk.offset = offset ; + rchunk.len = len ; + + rchunk.id_size = 4 ; + memcpy (rchunk.id, &marker, rchunk.id_size) ; + + return psf_store_read_chunk (pchk, &rchunk) ; +} /* psf_store_read_chunk_u32 */ + +int +psf_find_read_chunk_str (const READ_CHUNKS * pchk, const char * marker_str) +{ uint64_t hash ; + uint32_t k ; + union + { uint32_t marker ; + char str [5] ; + } u ; + + snprintf (u.str, sizeof (u.str), "%s", marker_str) ; + + hash = strlen (marker_str) > 4 ? hash_of_str (marker_str) : u.marker ; + + for (k = 0 ; k < pchk->used ; k++) + if (pchk->chunks [k].hash == hash) + return k ; + + return -1 ; +} /* psf_find_read_chunk_str */ + +int +psf_find_read_chunk_m32 (const READ_CHUNKS * pchk, uint32_t marker) +{ uint32_t k ; + + for (k = 0 ; k < pchk->used ; k++) + if (pchk->chunks [k].mark32 == marker) + return k ; + + return -1 ; +} /* psf_find_read_chunk_m32 */ +int +psf_find_read_chunk_iterator (const READ_CHUNKS * pchk, const SF_CHUNK_ITERATOR * marker) +{ if (marker->current < pchk->used) + return marker->current ; + + return -1 ; +} /* psf_find_read_chunk_iterator */ + +int +psf_store_read_chunk_str (READ_CHUNKS * pchk, const char * marker_str, sf_count_t offset, uint32_t len) +{ READ_CHUNK rchunk ; + union + { uint32_t marker ; + char str [5] ; + } u ; + size_t marker_len ; + + memset (&rchunk, 0, sizeof (rchunk)) ; + snprintf (u.str, sizeof (u.str), "%s", marker_str) ; + + marker_len = strlen (marker_str) ; + + rchunk.hash = marker_len > 4 ? hash_of_str (marker_str) : u.marker ; + rchunk.mark32 = u.marker ; + rchunk.offset = offset ; + rchunk.len = len ; + + rchunk.id_size = marker_len > 64 ? 64 : (unsigned) marker_len ; + memcpy (rchunk.id, marker_str, rchunk.id_size) ; + + return psf_store_read_chunk (pchk, &rchunk) ; +} /* psf_store_read_chunk_str */ + +int +psf_save_write_chunk (WRITE_CHUNKS * pchk, const SF_CHUNK_INFO * chunk_info) +{ union + { uint32_t marker ; + char str [5] ; + /* Update snprintf() format string below when changing this */ + } u ; + uint32_t len ; + + if (pchk->count == 0) + { pchk->used = 0 ; + pchk->count = 20 ; + pchk->chunks = calloc (pchk->count, sizeof (WRITE_CHUNK)) ; + if (!pchk->chunks) + { return SFE_MALLOC_FAILED ; + } ; + } + else if (pchk->used >= pchk->count) + { WRITE_CHUNK * old_ptr = pchk->chunks ; + int new_count = 3 * (pchk->count + 1) / 2 ; + + WRITE_CHUNK * new_chunks = realloc (old_ptr, new_count * sizeof (WRITE_CHUNK)) ; + if (new_chunks == NULL) + { + return SFE_MALLOC_FAILED ; + } else { + pchk->chunks = new_chunks; + } ; + } ; + + len = chunk_info->datalen ; + while (len & 3) len ++ ; + + snprintf (u.str, sizeof (u.str), "%.4s", chunk_info->id) ; + + pchk->chunks [pchk->used].hash = strlen (chunk_info->id) > 4 ? hash_of_str (chunk_info->id) : u.marker ; + pchk->chunks [pchk->used].mark32 = u.marker ; + pchk->chunks [pchk->used].len = len ; + pchk->chunks [pchk->used].data = psf_memdup (chunk_info->data, chunk_info->datalen) ; + + pchk->used ++ ; + + return SFE_NO_ERROR ; +} /* psf_save_write_chunk */ + diff --git a/extern/libsndfile-modified/src/command.c b/extern/libsndfile-modified/src/command.c new file mode 100644 index 000000000..d4837dab6 --- /dev/null +++ b/extern/libsndfile-modified/src/command.c @@ -0,0 +1,415 @@ +/* +** Copyright (C) 2001-2016 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include + +#include "sndfile.h" +#include "common.h" + +static SF_FORMAT_INFO const simple_formats [] = +{ + { SF_FORMAT_AIFF | SF_FORMAT_PCM_16, + "AIFF (Apple/SGI 16 bit PCM)", "aiff" + }, + + { SF_FORMAT_AIFF | SF_FORMAT_FLOAT, + "AIFF (Apple/SGI 32 bit float)", "aifc" + }, + + { SF_FORMAT_AIFF | SF_FORMAT_PCM_S8, + "AIFF (Apple/SGI 8 bit PCM)", "aiff" + }, + + { SF_FORMAT_AU | SF_FORMAT_PCM_16, + "AU (Sun/Next 16 bit PCM)", "au" + }, + + { SF_FORMAT_AU | SF_FORMAT_ULAW, + "AU (Sun/Next 8-bit u-law)", "au" + }, + + { SF_FORMAT_CAF | SF_FORMAT_ALAC_16, + "CAF (Apple 16 bit ALAC)", "caf" + }, + + { SF_FORMAT_CAF | SF_FORMAT_PCM_16, + "CAF (Apple 16 bit PCM)", "caf" + }, + +#if HAVE_EXTERNAL_XIPH_LIBS + { SF_FORMAT_FLAC | SF_FORMAT_PCM_16, + "FLAC 16 bit", "flac" + }, +#endif + +#if HAVE_MPEG + { SF_FORMAT_MPEG | SF_FORMAT_MPEG_LAYER_III, + "MPEG Layer 3", "mp3" + }, +#endif + + { SF_FORMAT_RAW | SF_FORMAT_VOX_ADPCM, + "OKI Dialogic VOX ADPCM", "vox" + }, + +#if HAVE_EXTERNAL_XIPH_LIBS + { SF_FORMAT_OGG | SF_FORMAT_OPUS, + "Ogg Opus (Xiph Foundation)", "opus" + }, + + { SF_FORMAT_OGG | SF_FORMAT_VORBIS, + "Ogg Vorbis (Xiph Foundation)", "ogg" + }, +#endif + + { SF_FORMAT_WAV | SF_FORMAT_PCM_16, + "WAV (Microsoft 16 bit PCM)", "wav" + }, + + { SF_FORMAT_WAV | SF_FORMAT_FLOAT, + "WAV (Microsoft 32 bit float)", "wav" + }, + + { SF_FORMAT_WAV | SF_FORMAT_IMA_ADPCM, + "WAV (Microsoft 4 bit IMA ADPCM)", "wav" + }, + + { SF_FORMAT_WAV | SF_FORMAT_MS_ADPCM, + "WAV (Microsoft 4 bit MS ADPCM)", "wav" + }, + + { SF_FORMAT_WAV | SF_FORMAT_PCM_U8, + "WAV (Microsoft 8 bit PCM)", "wav" + }, + +} ; /* simple_formats */ + +int +psf_get_format_simple_count (void) +{ return (sizeof (simple_formats) / sizeof (SF_FORMAT_INFO)) ; +} /* psf_get_format_simple_count */ + +int +psf_get_format_simple (SF_FORMAT_INFO *data) +{ int indx ; + + if (data->format < 0 || data->format >= (SIGNED_SIZEOF (simple_formats) / SIGNED_SIZEOF (SF_FORMAT_INFO))) + return SFE_BAD_COMMAND_PARAM ; + + indx = data->format ; + memcpy (data, &(simple_formats [indx]), SIGNED_SIZEOF (SF_FORMAT_INFO)) ; + + return 0 ; +} /* psf_get_format_simple */ + +/*============================================================================ +** Major format info. +*/ + +static SF_FORMAT_INFO const major_formats [] = +{ + { SF_FORMAT_AIFF, "AIFF (Apple/SGI)", "aiff" }, + { SF_FORMAT_AU, "AU (Sun/NeXT)", "au" }, + { SF_FORMAT_AVR, "AVR (Audio Visual Research)", "avr" }, + { SF_FORMAT_CAF, "CAF (Apple Core Audio File)", "caf" }, +#if HAVE_EXTERNAL_XIPH_LIBS + { SF_FORMAT_FLAC, "FLAC (Free Lossless Audio Codec)", "flac" }, +#endif + { SF_FORMAT_HTK, "HTK (HMM Tool Kit)", "htk" }, + { SF_FORMAT_SVX, "IFF (Amiga IFF/SVX8/SV16)", "iff" }, + { SF_FORMAT_MAT4, "MAT4 (GNU Octave 2.0 / Matlab 4.2)", "mat" }, + { SF_FORMAT_MAT5, "MAT5 (GNU Octave 2.1 / Matlab 5.0)", "mat" }, + { SF_FORMAT_MPC2K, "MPC (Akai MPC 2k)", "mpc" }, +#if HAVE_MPEG + { SF_FORMAT_MPEG, "MPEG-1/2 Audio", "m1a" }, +#endif +#if HAVE_EXTERNAL_XIPH_LIBS + { SF_FORMAT_OGG, "OGG (OGG Container format)", "oga" }, +#endif + { SF_FORMAT_PAF, "PAF (Ensoniq PARIS)", "paf" }, + { SF_FORMAT_PVF, "PVF (Portable Voice Format)", "pvf" }, + { SF_FORMAT_RAW, "RAW (header-less)", "raw" }, + { SF_FORMAT_RF64, "RF64 (RIFF 64)", "rf64" }, + { SF_FORMAT_SD2, "SD2 (Sound Designer II)", "sd2" }, + { SF_FORMAT_SDS, "SDS (Midi Sample Dump Standard)", "sds" }, + { SF_FORMAT_IRCAM, "SF (Berkeley/IRCAM/CARL)", "sf" }, + { SF_FORMAT_VOC, "VOC (Creative Labs)", "voc" }, + { SF_FORMAT_W64, "W64 (SoundFoundry WAVE 64)", "w64" }, + { SF_FORMAT_WAV, "WAV (Microsoft)", "wav" }, + { SF_FORMAT_NIST, "WAV (NIST Sphere)", "wav" }, + { SF_FORMAT_WAVEX, "WAVEX (Microsoft)", "wav" }, + { SF_FORMAT_WVE, "WVE (Psion Series 3)", "wve" }, + { SF_FORMAT_XI, "XI (FastTracker 2)", "xi" }, + +} ; /* major_formats */ + +int +psf_get_format_major_count (void) +{ return (sizeof (major_formats) / sizeof (SF_FORMAT_INFO)) ; +} /* psf_get_format_major_count */ + +int +psf_get_format_major (SF_FORMAT_INFO *data) +{ int indx ; + + if (data->format < 0 || data->format >= (SIGNED_SIZEOF (major_formats) / SIGNED_SIZEOF (SF_FORMAT_INFO))) + return SFE_BAD_COMMAND_PARAM ; + + indx = data->format ; + memcpy (data, &(major_formats [indx]), SIGNED_SIZEOF (SF_FORMAT_INFO)) ; + + return 0 ; +} /* psf_get_format_major */ + +/*============================================================================ +** Subtype format info. +*/ + +static SF_FORMAT_INFO subtype_formats [] = +{ + { SF_FORMAT_PCM_S8, "Signed 8 bit PCM", NULL }, + { SF_FORMAT_PCM_16, "Signed 16 bit PCM", NULL }, + { SF_FORMAT_PCM_24, "Signed 24 bit PCM", NULL }, + { SF_FORMAT_PCM_32, "Signed 32 bit PCM", NULL }, + + { SF_FORMAT_PCM_U8, "Unsigned 8 bit PCM", NULL }, + + { SF_FORMAT_FLOAT, "32 bit float", NULL }, + { SF_FORMAT_DOUBLE, "64 bit float", NULL }, + + { SF_FORMAT_ULAW, "U-Law", NULL }, + { SF_FORMAT_ALAW, "A-Law", NULL }, + { SF_FORMAT_IMA_ADPCM, "IMA ADPCM", NULL }, + { SF_FORMAT_MS_ADPCM, "Microsoft ADPCM", NULL }, + + { SF_FORMAT_GSM610, "GSM 6.10", NULL }, + + { SF_FORMAT_G721_32, "32kbs G721 ADPCM", NULL }, + { SF_FORMAT_G723_24, "24kbs G723 ADPCM", NULL }, + { SF_FORMAT_G723_40, "40kbs G723 ADPCM", NULL }, + + { SF_FORMAT_DWVW_12, "12 bit DWVW", NULL }, + { SF_FORMAT_DWVW_16, "16 bit DWVW", NULL }, + { SF_FORMAT_DWVW_24, "24 bit DWVW", NULL }, + { SF_FORMAT_VOX_ADPCM, "VOX ADPCM", "vox" }, + + { SF_FORMAT_NMS_ADPCM_16, "16kbs NMS ADPCM", NULL }, + { SF_FORMAT_NMS_ADPCM_24, "24kbs NMS ADPCM", NULL }, + { SF_FORMAT_NMS_ADPCM_32, "32kbs NMS ADPCM", NULL }, + + { SF_FORMAT_DPCM_16, "16 bit DPCM", NULL }, + { SF_FORMAT_DPCM_8, "8 bit DPCM", NULL }, + +#if HAVE_EXTERNAL_XIPH_LIBS + { SF_FORMAT_VORBIS, "Vorbis", NULL }, + { SF_FORMAT_OPUS, "Opus", NULL }, +#endif + +#if HAVE_MPEG + { SF_FORMAT_MPEG_LAYER_I, "MPEG Layer I", "mp1" }, + { SF_FORMAT_MPEG_LAYER_II, "MPEG Layer II", "mp2" }, + { SF_FORMAT_MPEG_LAYER_III, "MPEG Layer III", "mp3" }, +#endif + + { SF_FORMAT_ALAC_16, "16 bit ALAC", NULL }, + { SF_FORMAT_ALAC_20, "20 bit ALAC", NULL }, + { SF_FORMAT_ALAC_24, "24 bit ALAC", NULL }, + { SF_FORMAT_ALAC_32, "32 bit ALAC", NULL }, +} ; /* subtype_formats */ + +int +psf_get_format_subtype_count (void) +{ return (sizeof (subtype_formats) / sizeof (SF_FORMAT_INFO)) ; +} /* psf_get_format_subtype_count */ + +int +psf_get_format_subtype (SF_FORMAT_INFO *data) +{ int indx ; + + if (data->format < 0 || data->format >= (SIGNED_SIZEOF (subtype_formats) / SIGNED_SIZEOF (SF_FORMAT_INFO))) + { data->format = 0 ; + return SFE_BAD_COMMAND_PARAM ; + } ; + + indx = data->format ; + memcpy (data, &(subtype_formats [indx]), sizeof (SF_FORMAT_INFO)) ; + + return 0 ; +} /* psf_get_format_subtype */ + +/*============================================================================== +*/ + +int +psf_get_format_info (SF_FORMAT_INFO *data) +{ int k, format ; + + if (SF_CONTAINER (data->format)) + { format = SF_CONTAINER (data->format) ; + + for (k = 0 ; k < (SIGNED_SIZEOF (major_formats) / SIGNED_SIZEOF (SF_FORMAT_INFO)) ; k++) + { if (format == major_formats [k].format) + { memcpy (data, &(major_formats [k]), sizeof (SF_FORMAT_INFO)) ; + return 0 ; + } ; + } ; + } + else if (SF_CODEC (data->format)) + { format = SF_CODEC (data->format) ; + + for (k = 0 ; k < (SIGNED_SIZEOF (subtype_formats) / SIGNED_SIZEOF (SF_FORMAT_INFO)) ; k++) + { if (format == subtype_formats [k].format) + { memcpy (data, &(subtype_formats [k]), sizeof (SF_FORMAT_INFO)) ; + return 0 ; + } ; + } ; + } ; + + memset (data, 0, sizeof (SF_FORMAT_INFO)) ; + + return SFE_BAD_COMMAND_PARAM ; +} /* psf_get_format_info */ + +/*============================================================================== +*/ + +double +psf_calc_signal_max (SF_PRIVATE *psf, int normalize) +{ BUF_UNION ubuf ; + sf_count_t position ; + double max_val, temp, *data ; + int k, len, readcount, save_state ; + + /* If the file is not seekable, there is nothing we can do. */ + if (! psf->sf.seekable) + { psf->error = SFE_NOT_SEEKABLE ; + return 0.0 ; + } ; + + if (! psf->read_double) + { psf->error = SFE_UNIMPLEMENTED ; + return 0.0 ; + } ; + + save_state = sf_command ((SNDFILE*) psf, SFC_GET_NORM_DOUBLE, NULL, 0) ; + sf_command ((SNDFILE*) psf, SFC_SET_NORM_DOUBLE, NULL, normalize) ; + + /* Brute force. Read the whole file and find the biggest sample. */ + /* Get current position in file */ + position = sf_seek ((SNDFILE*) psf, 0, SEEK_CUR) ; + /* Go to start of file. */ + sf_seek ((SNDFILE*) psf, 0, SEEK_SET) ; + + data = ubuf.dbuf ; + /* Make sure len is an integer multiple of the channel count. */ + len = ARRAY_LEN (ubuf.dbuf) - (ARRAY_LEN (ubuf.dbuf) % psf->sf.channels) ; + + for (readcount = 1, max_val = 0.0 ; readcount > 0 ; /* nothing */) + { readcount = (int) sf_read_double ((SNDFILE*) psf, data, len) ; + for (k = 0 ; k < readcount ; k++) + { temp = fabs (data [k]) ; + max_val = temp > max_val ? temp : max_val ; + } ; + } ; + + /* Return to SNDFILE to original state. */ + sf_seek ((SNDFILE*) psf, position, SEEK_SET) ; + sf_command ((SNDFILE*) psf, SFC_SET_NORM_DOUBLE, NULL, save_state) ; + + return max_val ; +} /* psf_calc_signal_max */ + +int +psf_calc_max_all_channels (SF_PRIVATE *psf, double *peaks, int normalize) +{ BUF_UNION ubuf ; + sf_count_t position ; + double temp, *data ; + int k, len, readcount, save_state ; + int chan ; + + /* If the file is not seekable, there is nothing we can do. */ + if (! psf->sf.seekable) + return (psf->error = SFE_NOT_SEEKABLE) ; + + if (! psf->read_double) + return (psf->error = SFE_UNIMPLEMENTED) ; + + save_state = sf_command ((SNDFILE*) psf, SFC_GET_NORM_DOUBLE, NULL, 0) ; + sf_command ((SNDFILE*) psf, SFC_SET_NORM_DOUBLE, NULL, normalize) ; + + memset (peaks, 0, sizeof (double) * psf->sf.channels) ; + + /* Brute force. Read the whole file and find the biggest sample for each channel. */ + position = sf_seek ((SNDFILE*) psf, 0, SEEK_CUR) ; /* Get current position in file */ + sf_seek ((SNDFILE*) psf, 0, SEEK_SET) ; /* Go to start of file. */ + + len = ARRAY_LEN (ubuf.dbuf) - (ARRAY_LEN (ubuf.dbuf) % psf->sf.channels) ; + + data = ubuf.dbuf ; + + chan = 0 ; + readcount = len ; + while (readcount > 0) + { readcount = (int) sf_read_double ((SNDFILE*) psf, data, len) ; + for (k = 0 ; k < readcount ; k++) + { temp = fabs (data [k]) ; + peaks [chan] = temp > peaks [chan] ? temp : peaks [chan] ; + chan = (chan + 1) % psf->sf.channels ; + } ; + } ; + + sf_seek ((SNDFILE*) psf, position, SEEK_SET) ; /* Return to original position. */ + + sf_command ((SNDFILE*) psf, SFC_SET_NORM_DOUBLE, NULL, save_state) ; + + return 0 ; +} /* psf_calc_max_all_channels */ + +int +psf_get_signal_max (SF_PRIVATE *psf, double *peak) +{ int k ; + + if (psf->peak_info == NULL) + return SF_FALSE ; + + peak [0] = psf->peak_info->peaks [0].value ; + + for (k = 1 ; k < psf->sf.channels ; k++) + peak [0] = SF_MAX (peak [0], psf->peak_info->peaks [k].value) ; + + return SF_TRUE ; +} /* psf_get_signal_max */ + +int +psf_get_max_all_channels (SF_PRIVATE *psf, double *peaks) +{ int k ; + + if (psf->peak_info == NULL) + return SF_FALSE ; + + for (k = 0 ; k < psf->sf.channels ; k++) + peaks [k] = psf->peak_info->peaks [k].value ; + + return SF_TRUE ; +} /* psf_get_max_all_channels */ + + diff --git a/extern/libsndfile-modified/src/common.c b/extern/libsndfile-modified/src/common.c new file mode 100644 index 000000000..1c3d951db --- /dev/null +++ b/extern/libsndfile-modified/src/common.c @@ -0,0 +1,1845 @@ +/* +** Copyright (C) 1999-2019 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include + +#include +#include +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif +#include +#include +#include +#if HAVE_SYS_TIME_H +#include +#endif +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + +#define INITIAL_HEADER_SIZE 256 + +/* Allocate and initialize the SF_PRIVATE struct. */ +SF_PRIVATE * +psf_allocate (void) +{ SF_PRIVATE * psf ; + + if ((psf = calloc (1, sizeof (SF_PRIVATE))) == NULL) + return NULL ; + + if ((psf->header.ptr = calloc (1, INITIAL_HEADER_SIZE)) == NULL) + { free (psf) ; + return NULL ; + } ; + psf->header.len = INITIAL_HEADER_SIZE ; + + return psf ; +} /* psf_allocate */ + +static int +psf_bump_header_allocation (SF_PRIVATE * psf, sf_count_t needed) +{ + sf_count_t newlen, smallest = INITIAL_HEADER_SIZE ; + void * ptr ; + + newlen = (needed > psf->header.len) ? 2 * SF_MAX (needed, smallest) : 2 * psf->header.len ; + + if (newlen > 100 * 1024) + { psf_log_printf (psf, "Request for header allocation of %D denied.\n", newlen) ; + return 1 ; + } + + if ((ptr = realloc (psf->header.ptr, newlen)) == NULL) + { psf_log_printf (psf, "realloc (%p, %D) failed\n", psf->header.ptr, newlen) ; + psf->error = SFE_MALLOC_FAILED ; + return 1 ; + } ; + + /* Always zero-out new header memory to avoid un-initializer memory accesses. */ + if (newlen > psf->header.len) + memset ((char *) ptr + psf->header.len, 0, newlen - psf->header.len) ; + + psf->header.ptr = ptr ; + psf->header.len = newlen ; + return 0 ; +} /* psf_bump_header_allocation */ + +/*----------------------------------------------------------------------------------------------- +** psf_log_printf allows libsndfile internal functions to print to an internal parselog which +** can later be displayed. +** The format specifiers are as for printf but without the field width and other modifiers. +** Printing is performed to the parselog char array of the SF_PRIVATE struct. +** Printing is done in such a way as to guarantee that the log never overflows the end of the +** parselog array. +*/ + +static inline void +log_putchar (SF_PRIVATE *psf, char ch) +{ if (psf->parselog.indx < SIGNED_SIZEOF (psf->parselog.buf) - 1) + { psf->parselog.buf [psf->parselog.indx++] = ch ; + psf->parselog.buf [psf->parselog.indx] = 0 ; + } ; + return ; +} /* log_putchar */ + +void +psf_log_printf (SF_PRIVATE *psf, const char *format, ...) +{ va_list ap ; + uint32_t u, tens ; + int d, shift, width, width_specifier, left_align, slen, precision ; + char c, *strptr, istr [5], lead_char, sign_char ; + + va_start (ap, format) ; + + while ((c = *format++)) + { if (c != '%') + { log_putchar (psf, c) ; + continue ; + } ; + + if (format [0] == '%') /* Handle %% */ + { log_putchar (psf, '%') ; + format ++ ; + continue ; + } ; + + sign_char = 0 ; + left_align = SF_FALSE ; + while (1) + { switch (format [0]) + { case ' ' : + case '+' : + sign_char = format [0] ; + format ++ ; + continue ; + + case '-' : + left_align = SF_TRUE ; + format ++ ; + continue ; + + default : break ; + } ; + + break ; + } ; + + if (format [0] == 0) + break ; + + lead_char = ' ' ; + if (format [0] == '0') + lead_char = '0' ; + + width_specifier = 0 ; + while ((c = *format++) && isdigit (c)) + width_specifier = width_specifier * 10 + (c - '0') ; + + precision = 0 ; + if (c == '.') + { while ((c = *format++) && isdigit (c)) + precision = precision * 10 + (c - '0') ; + } ; + + switch (c) + { case 0 : /* NULL character. */ + va_end (ap) ; + return ; + + case 's': /* string */ + strptr = va_arg (ap, char *) ; + if (strptr == NULL) + break ; + if (precision > 0) + slen = strnlen (strptr, precision) ; + else + slen = strlen (strptr) ; + width_specifier = width_specifier >= slen ? width_specifier - slen : 0 ; + if (left_align == SF_FALSE) + while (width_specifier -- > 0) + log_putchar (psf, ' ') ; + while (slen--) + log_putchar (psf, *strptr++) ; + while (width_specifier -- > 0) + log_putchar (psf, ' ') ; + break ; + + case 'd': /* int */ + d = va_arg (ap, int) ; + + if (d < 0) + { sign_char = '-' ; + if (lead_char != '0' && left_align == SF_FALSE) + width_specifier -- ; + + u = - ((unsigned) d) ; + } + else + { u = (unsigned) d ; + } + + tens = 1 ; + width = 1 ; + while (u / tens >= 10) + { tens *= 10 ; + width ++ ; + } ; + + width_specifier -= width ; + + if (sign_char == ' ') + { log_putchar (psf, ' ') ; + width_specifier -- ; + } ; + + if (left_align == SF_FALSE && lead_char != '0') + { if (sign_char == '+') + width_specifier -- ; + + while (width_specifier -- > 0) + log_putchar (psf, lead_char) ; + } ; + + if (sign_char == '+' || sign_char == '-') + { log_putchar (psf, sign_char) ; + width_specifier -- ; + } ; + + if (left_align == SF_FALSE) + while (width_specifier -- > 0) + log_putchar (psf, lead_char) ; + + while (tens > 0) + { log_putchar (psf, '0' + u / tens) ; + u %= tens ; + tens /= 10 ; + } ; + + while (width_specifier -- > 0) + log_putchar (psf, lead_char) ; + break ; + + case 'D': /* sf_count_t */ + { sf_count_t D ; + uint64_t U, Tens ; + + D = va_arg (ap, sf_count_t) ; + + if (D == 0) + { while (-- width_specifier > 0) + log_putchar (psf, lead_char) ; + log_putchar (psf, '0') ; + break ; + } + else + { if (D < 0) + { log_putchar (psf, '-') ; + U = - ((uint64_t) D) ; + } + else + { U = (uint64_t) D ; + } + } + + Tens = 1 ; + width = 1 ; + while (U / Tens >= 10) + { Tens *= 10 ; + width ++ ; + } ; + + while (width_specifier > width) + { log_putchar (psf, lead_char) ; + width_specifier-- ; + } ; + + while (Tens > 0) + { log_putchar (psf, '0' + U / Tens) ; + U %= Tens ; + Tens /= 10 ; + } ; + } ; + break ; + + case 'u': /* unsigned int */ + u = va_arg (ap, unsigned int) ; + + tens = 1 ; + width = 1 ; + while (u / tens >= 10) + { tens *= 10 ; + width ++ ; + } ; + + width_specifier -= width ; + + if (sign_char == ' ') + { log_putchar (psf, ' ') ; + width_specifier -- ; + } ; + + if (left_align == SF_FALSE && lead_char != '0') + { if (sign_char == '+') + width_specifier -- ; + + while (width_specifier -- > 0) + log_putchar (psf, lead_char) ; + } ; + + if (sign_char == '+' || sign_char == '-') + { log_putchar (psf, sign_char) ; + width_specifier -- ; + } ; + + if (left_align == SF_FALSE) + while (width_specifier -- > 0) + log_putchar (psf, lead_char) ; + + while (tens > 0) + { log_putchar (psf, '0' + u / tens) ; + u %= tens ; + tens /= 10 ; + } ; + + while (width_specifier -- > 0) + log_putchar (psf, lead_char) ; + break ; + + case 'c': /* char */ + c = va_arg (ap, int) & 0xFF ; + log_putchar (psf, c) ; + break ; + + case 'x': /* hex */ + case 'X': /* hex */ + d = va_arg (ap, int) ; + + if (d == 0) + { while (--width_specifier > 0) + log_putchar (psf, lead_char) ; + log_putchar (psf, '0') ; + break ; + } ; + shift = 28 ; + width = (width_specifier < 8) ? 8 : width_specifier ; + while (! ((((uint32_t) 0xF) << shift) & d)) + { shift -= 4 ; + width -- ; + } ; + + while (width > 0 && width_specifier > width) + { log_putchar (psf, lead_char) ; + width_specifier-- ; + } ; + + while (shift >= 0) + { c = (d >> shift) & 0xF ; + log_putchar (psf, (c > 9) ? c + 'A' - 10 : c + '0') ; + shift -= 4 ; + } ; + break ; + + case 'M': /* int2str */ + d = va_arg (ap, int) ; + if (CPU_IS_LITTLE_ENDIAN) + { istr [0] = d & 0xFF ; + istr [1] = (d >> 8) & 0xFF ; + istr [2] = (d >> 16) & 0xFF ; + istr [3] = (d >> 24) & 0xFF ; + } + else + { istr [3] = d & 0xFF ; + istr [2] = (d >> 8) & 0xFF ; + istr [1] = (d >> 16) & 0xFF ; + istr [0] = (d >> 24) & 0xFF ; + } ; + istr [4] = 0 ; + strptr = istr ; + while (*strptr) + { c = *strptr++ ; + log_putchar (psf, psf_isprint (c) ? c : '.') ; + } ; + break ; + + default : + log_putchar (psf, '*') ; + log_putchar (psf, c) ; + log_putchar (psf, '*') ; + break ; + } /* switch */ + } /* while */ + + va_end (ap) ; + return ; +} /* psf_log_printf */ + +/*----------------------------------------------------------------------------------------------- +** ASCII header printf functions. +** Some formats (ie NIST) use ascii text in their headers. +** Format specifiers are the same as the standard printf specifiers (uses vsnprintf). +** If this generates a compile error on any system, the author should be notified +** so an alternative vsnprintf can be provided. +*/ + +void +psf_asciiheader_printf (SF_PRIVATE *psf, const char *format, ...) +{ va_list argptr ; + int maxlen ; + char *start ; + + if (! format) + return ; + + maxlen = strlen ((char*) psf->header.ptr) ; + start = ((char*) psf->header.ptr) + maxlen ; + maxlen = psf->header.len - maxlen ; + + va_start (argptr, format) ; + vsnprintf (start, maxlen, format, argptr) ; + va_end (argptr) ; + + /* Make sure the string is properly terminated. */ + start [maxlen - 1] = 0 ; + + psf->header.indx = strlen ((char*) psf->header.ptr) ; + + return ; +} /* psf_asciiheader_printf */ + +/*----------------------------------------------------------------------------------------------- +** Binary header writing functions. Returns number of bytes written. +** +** Format specifiers for psf_binheader_writef are as follows +** m - marker - four bytes - no endian manipulation +** +** e - all following numerical values will be little endian +** E - all following numerical values will be big endian +** +** t - all following O types will be truncated to 4 bytes +** T - switch off truncation of all following O types +** +** 1 - single byte value +** 2 - two byte value +** 3 - three byte value +** 4 - four byte value +** 8 - eight byte value (sometimes written as 4 bytes) +** +** s - string preceded by a four byte length +** S - string including null terminator +** p - a Pascal string +** +** f - floating point data +** d - double precision floating point data +** h - 16 binary bytes value +** +** b - binary data (see below) +** z - zero bytes (ses below) +** j - jump forwards or backwards +** +** To write a word followed by an int (both little endian) use: +** psf_binheader_writef ("e24", wordval, longval) ; +** +** To write binary data use: +** psf_binheader_writef ("b", &bindata, sizeof (bindata)) ; +** +** To write N zero bytes use: +** NOTE: due to platform issues (ie x86-64) you should cast the +** argument to size_t or ensure the variable type is size_t. +** psf_binheader_writef ("z", N) ; +*/ + +/* These macros may seem a bit messy but do prevent problems with processors which +** seg. fault when asked to write an int or short to a non-int/short aligned address. +*/ + +static inline void +header_put_byte (SF_PRIVATE *psf, char x) +{ psf->header.ptr [psf->header.indx++] = x ; +} /* header_put_byte */ + +#if (CPU_IS_BIG_ENDIAN == 1) +static inline void +header_put_marker (SF_PRIVATE *psf, int x) +{ psf->header.ptr [psf->header.indx++] = (x >> 24) ; + psf->header.ptr [psf->header.indx++] = (x >> 16) ; + psf->header.ptr [psf->header.indx++] = (x >> 8) ; + psf->header.ptr [psf->header.indx++] = x ; +} /* header_put_marker */ + +#elif (CPU_IS_LITTLE_ENDIAN == 1) +static inline void +header_put_marker (SF_PRIVATE *psf, int x) +{ psf->header.ptr [psf->header.indx++] = x ; + psf->header.ptr [psf->header.indx++] = (x >> 8) ; + psf->header.ptr [psf->header.indx++] = (x >> 16) ; + psf->header.ptr [psf->header.indx++] = (x >> 24) ; +} /* header_put_marker */ + +#else +# error "Cannot determine endian-ness of processor." +#endif + + +static inline void +header_put_be_short (SF_PRIVATE *psf, int x) +{ psf->header.ptr [psf->header.indx++] = (x >> 8) ; + psf->header.ptr [psf->header.indx++] = x ; +} /* header_put_be_short */ + +static inline void +header_put_le_short (SF_PRIVATE *psf, int x) +{ psf->header.ptr [psf->header.indx++] = x ; + psf->header.ptr [psf->header.indx++] = (x >> 8) ; +} /* header_put_le_short */ + +static inline void +header_put_be_3byte (SF_PRIVATE *psf, int x) +{ psf->header.ptr [psf->header.indx++] = (x >> 16) ; + psf->header.ptr [psf->header.indx++] = (x >> 8) ; + psf->header.ptr [psf->header.indx++] = x ; +} /* header_put_be_3byte */ + +static inline void +header_put_le_3byte (SF_PRIVATE *psf, int x) +{ psf->header.ptr [psf->header.indx++] = x ; + psf->header.ptr [psf->header.indx++] = (x >> 8) ; + psf->header.ptr [psf->header.indx++] = (x >> 16) ; +} /* header_put_le_3byte */ + +static inline void +header_put_be_int (SF_PRIVATE *psf, int x) +{ psf->header.ptr [psf->header.indx++] = (x >> 24) ; + psf->header.ptr [psf->header.indx++] = (x >> 16) ; + psf->header.ptr [psf->header.indx++] = (x >> 8) ; + psf->header.ptr [psf->header.indx++] = x ; +} /* header_put_be_int */ + +static inline void +header_put_le_int (SF_PRIVATE *psf, int x) +{ psf->header.ptr [psf->header.indx++] = x ; + psf->header.ptr [psf->header.indx++] = (x >> 8) ; + psf->header.ptr [psf->header.indx++] = (x >> 16) ; + psf->header.ptr [psf->header.indx++] = (x >> 24) ; +} /* header_put_le_int */ + +static inline void +header_put_be_8byte (SF_PRIVATE *psf, sf_count_t x) +{ psf->header.ptr [psf->header.indx++] = (x >> 56) ; + psf->header.ptr [psf->header.indx++] = (unsigned char) (x >> 48) ; + psf->header.ptr [psf->header.indx++] = (unsigned char) (x >> 40) ; + psf->header.ptr [psf->header.indx++] = (unsigned char) (x >> 32) ; + psf->header.ptr [psf->header.indx++] = (unsigned char) (x >> 24) ; + psf->header.ptr [psf->header.indx++] = (unsigned char) (x >> 16) ; + psf->header.ptr [psf->header.indx++] = (unsigned char) (x >> 8) ; + psf->header.ptr [psf->header.indx++] = (unsigned char) x ; +} /* header_put_be_8byte */ + +static inline void +header_put_le_8byte (SF_PRIVATE *psf, sf_count_t x) +{ psf->header.ptr [psf->header.indx++] = (unsigned char) x ; + psf->header.ptr [psf->header.indx++] = (unsigned char) (x >> 8) ; + psf->header.ptr [psf->header.indx++] = (unsigned char) (x >> 16) ; + psf->header.ptr [psf->header.indx++] = (unsigned char) (x >> 24) ; + psf->header.ptr [psf->header.indx++] = (unsigned char) (x >> 32) ; + psf->header.ptr [psf->header.indx++] = (unsigned char) (x >> 40) ; + psf->header.ptr [psf->header.indx++] = (unsigned char) (x >> 48) ; + psf->header.ptr [psf->header.indx++] = (x >> 56) ; +} /* header_put_le_8byte */ + +int +psf_binheader_writef (SF_PRIVATE *psf, const char *format, ...) +{ va_list argptr ; + sf_count_t countdata ; + unsigned long longdata ; + unsigned int data ; + float floatdata ; + double doubledata ; + void *bindata ; + size_t size ; + char c, *strptr ; + int count = 0, trunc_8to4 = SF_FALSE ; + + if (! format) + return psf_ftell (psf) ; + + va_start (argptr, format) ; + + while ((c = *format++)) + { + if (psf->header.indx + 16 >= psf->header.len && psf_bump_header_allocation (psf, 16)) + break ; + + switch (c) + { case ' ' : /* Do nothing. Just used to space out format string. */ + break ; + + case 'e' : /* All conversions are now from LE to host. */ + psf->rwf_endian = SF_ENDIAN_LITTLE ; + break ; + + case 'E' : /* All conversions are now from BE to host. */ + psf->rwf_endian = SF_ENDIAN_BIG ; + break ; + + case 't' : /* All 8 byte values now get written as 4 bytes. */ + trunc_8to4 = SF_TRUE ; + break ; + + case 'T' : /* All 8 byte values now get written as 8 bytes. */ + trunc_8to4 = SF_FALSE ; + break ; + + case 'm' : + data = va_arg (argptr, unsigned int) ; + header_put_marker (psf, data) ; + count += 4 ; + break ; + + case '1' : + data = va_arg (argptr, unsigned int) ; + header_put_byte (psf, data) ; + count += 1 ; + break ; + + case '2' : + data = va_arg (argptr, unsigned int) ; + if (psf->rwf_endian == SF_ENDIAN_BIG) + { header_put_be_short (psf, data) ; + } + else + { header_put_le_short (psf, data) ; + } ; + count += 2 ; + break ; + + case '3' : /* tribyte */ + data = va_arg (argptr, unsigned int) ; + if (psf->rwf_endian == SF_ENDIAN_BIG) + { header_put_be_3byte (psf, data) ; + } + else + { header_put_le_3byte (psf, data) ; + } ; + count += 3 ; + break ; + + case '4' : + data = va_arg (argptr, unsigned int) ; + if (psf->rwf_endian == SF_ENDIAN_BIG) + { header_put_be_int (psf, data) ; + } + else + { header_put_le_int (psf, data) ; + } ; + count += 4 ; + break ; + + case '8' : + countdata = va_arg (argptr, sf_count_t) ; + if (psf->rwf_endian == SF_ENDIAN_BIG && trunc_8to4 == SF_FALSE) + { header_put_be_8byte (psf, countdata) ; + count += 8 ; + } + else if (psf->rwf_endian == SF_ENDIAN_LITTLE && trunc_8to4 == SF_FALSE) + { header_put_le_8byte (psf, countdata) ; + count += 8 ; + } + else if (psf->rwf_endian == SF_ENDIAN_BIG && trunc_8to4 == SF_TRUE) + { longdata = countdata & 0xFFFFFFFF ; + header_put_be_int (psf, longdata) ; + count += 4 ; + } + else if (psf->rwf_endian == SF_ENDIAN_LITTLE && trunc_8to4 == SF_TRUE) + { longdata = countdata & 0xFFFFFFFF ; + header_put_le_int (psf, longdata) ; + count += 4 ; + } + break ; + + case 'f' : + /* Floats are passed as doubles. Is this always true? */ + floatdata = (float) va_arg (argptr, double) ; + if (psf->rwf_endian == SF_ENDIAN_BIG) + float32_be_write (floatdata, psf->header.ptr + psf->header.indx) ; + else + float32_le_write (floatdata, psf->header.ptr + psf->header.indx) ; + psf->header.indx += 4 ; + count += 4 ; + break ; + + case 'd' : + doubledata = va_arg (argptr, double) ; + if (psf->rwf_endian == SF_ENDIAN_BIG) + double64_be_write (doubledata, psf->header.ptr + psf->header.indx) ; + else + double64_le_write (doubledata, psf->header.ptr + psf->header.indx) ; + psf->header.indx += 8 ; + count += 8 ; + break ; + + case 's' : + /* Write a C string (guaranteed to have a zero terminator). */ + strptr = va_arg (argptr, char *) ; + size = strlen (strptr) + 1 ; + + if (psf->header.indx + 4 + (sf_count_t) size + (sf_count_t) (size & 1) > psf->header.len && psf_bump_header_allocation (psf, 4 + size + (size & 1))) + break ; + + if (psf->rwf_endian == SF_ENDIAN_BIG) + header_put_be_int (psf, size + (size & 1)) ; + else + header_put_le_int (psf, size + (size & 1)) ; + memcpy (&(psf->header.ptr [psf->header.indx]), strptr, size) ; + size += (size & 1) ; + psf->header.indx += size ; + psf->header.ptr [psf->header.indx - 1] = 0 ; + count += 4 + size ; + break ; + + case 'S' : + /* + ** Write an AIFF style string (no zero terminator but possibly + ** an extra pad byte if the string length is odd). + */ + strptr = va_arg (argptr, char *) ; + size = strlen (strptr) ; + if (psf->header.indx + 4 + (sf_count_t) size + (sf_count_t) (size & 1) > psf->header.len && psf_bump_header_allocation (psf, 4 + size + (size & 1))) + break ; + if (psf->rwf_endian == SF_ENDIAN_BIG) + header_put_be_int (psf, size) ; + else + header_put_le_int (psf, size) ; + memcpy (&(psf->header.ptr [psf->header.indx]), strptr, size + (size & 1)) ; + size += (size & 1) ; + psf->header.indx += size ; + count += 4 + size ; + break ; + + case 'p' : + /* Write a PASCAL string (as used by AIFF files). + */ + strptr = va_arg (argptr, char *) ; + size = strlen (strptr) ; + size = (size & 1) ? size : size + 1 ; + size = (size > 254) ? 254 : size ; + + if (psf->header.indx + 1 + (sf_count_t) size > psf->header.len && psf_bump_header_allocation (psf, 1 + size)) + break ; + + header_put_byte (psf, size) ; + memcpy (&(psf->header.ptr [psf->header.indx]), strptr, size) ; + psf->header.indx += size ; + count += 1 + size ; + break ; + + case 'b' : + bindata = va_arg (argptr, void *) ; + size = va_arg (argptr, size_t) ; + + if (psf->header.indx + (sf_count_t) size > psf->header.len && psf_bump_header_allocation (psf, size)) + break ; + + memcpy (&(psf->header.ptr [psf->header.indx]), bindata, size) ; + psf->header.indx += size ; + count += size ; + break ; + + case 'z' : + size = va_arg (argptr, size_t) ; + + if (psf->header.indx + (sf_count_t) size > psf->header.len && psf_bump_header_allocation (psf, size)) + break ; + + count += size ; + while (size) + { psf->header.ptr [psf->header.indx] = 0 ; + psf->header.indx ++ ; + size -- ; + } ; + break ; + + case 'h' : + bindata = va_arg (argptr, void *) ; + memcpy (&(psf->header.ptr [psf->header.indx]), bindata, 16) ; + psf->header.indx += 16 ; + count += 16 ; + break ; + + case 'j' : /* Jump forwards/backwards by specified amount. */ + size = va_arg (argptr, size_t) ; + + if (psf->header.indx + (sf_count_t) size > psf->header.len && psf_bump_header_allocation (psf, size)) + break ; + + psf->header.indx += size ; + count += size ; + break ; + + case 'o' : /* Jump to specified offset. */ + size = va_arg (argptr, size_t) ; + + if ((sf_count_t) size >= psf->header.len && psf_bump_header_allocation (psf, size)) + break ; + + psf->header.indx = size ; + break ; + + default : + psf_log_printf (psf, "*** Invalid format specifier `%c'\n", c) ; + psf->error = SFE_INTERNAL ; + break ; + } ; + } ; + + va_end (argptr) ; + return count ; +} /* psf_binheader_writef */ + +/*----------------------------------------------------------------------------------------------- +** Binary header reading functions. Returns number of bytes read. +** +** Format specifiers are the same as for header write function above with the following +** additions: +** +** p - jump a given number of position from start of file. +** +** If format is NULL, psf_binheader_readf returns the current offset. +*/ + +#if (CPU_IS_BIG_ENDIAN == 1) +#define GET_MARKER(ptr) ( (((uint32_t) (ptr) [0]) << 24) | ((ptr) [1] << 16) | \ + ((ptr) [2] << 8) | ((ptr) [3])) + +#elif (CPU_IS_LITTLE_ENDIAN == 1) +#define GET_MARKER(ptr) ( ((ptr) [0]) | ((ptr) [1] << 8) | \ + ((ptr) [2] << 16) | (((uint32_t) (ptr) [3]) << 24)) + +#else +# error "Cannot determine endian-ness of processor." +#endif + +#define GET_LE_SHORT(ptr) (((ptr) [1] << 8) | ((ptr) [0])) +#define GET_BE_SHORT(ptr) (((ptr) [0] << 8) | ((ptr) [1])) + +#define GET_LE_3BYTE(ptr) ( ((ptr) [2] << 16) | ((ptr) [1] << 8) | ((ptr) [0])) +#define GET_BE_3BYTE(ptr) ( ((ptr) [0] << 16) | ((ptr) [1] << 8) | ((ptr) [2])) + +#define GET_LE_INT(ptr) ( ((ptr) [3] << 24) | ((ptr) [2] << 16) | \ + ((ptr) [1] << 8) | ((ptr) [0])) + +#define GET_BE_INT(ptr) ( ((ptr) [0] << 24) | ((ptr) [1] << 16) | \ + ((ptr) [2] << 8) | ((ptr) [3])) + +#define GET_LE_8BYTE(ptr) ( (((sf_count_t) (ptr) [7]) << 56) | (((sf_count_t) (ptr) [6]) << 48) | \ + (((sf_count_t) (ptr) [5]) << 40) | (((sf_count_t) (ptr) [4]) << 32) | \ + (((sf_count_t) (ptr) [3]) << 24) | (((sf_count_t) (ptr) [2]) << 16) | \ + (((sf_count_t) (ptr) [1]) << 8) | ((ptr) [0])) + +#define GET_BE_8BYTE(ptr) ( (((sf_count_t) (ptr) [0]) << 56) | (((sf_count_t) (ptr) [1]) << 48) | \ + (((sf_count_t) (ptr) [2]) << 40) | (((sf_count_t) (ptr) [3]) << 32) | \ + (((sf_count_t) (ptr) [4]) << 24) | (((sf_count_t) (ptr) [5]) << 16) | \ + (((sf_count_t) (ptr) [6]) << 8) | ((ptr) [7])) + + + +static int +header_read (SF_PRIVATE *psf, void *ptr, int bytes) +{ int count = 0 ; + + if (psf->header.indx + bytes >= psf->header.len && psf_bump_header_allocation (psf, bytes)) + return count ; + + if (psf->header.indx + bytes > psf->header.end) + { count = psf_fread (psf->header.ptr + psf->header.end, 1, bytes - (psf->header.end - psf->header.indx), psf) ; + if (count != bytes - (int) (psf->header.end - psf->header.indx)) + { psf_log_printf (psf, "Error : psf_fread returned short count.\n") ; + return count ; + } ; + psf->header.end += count ; + } ; + + memcpy (ptr, psf->header.ptr + psf->header.indx, bytes) ; + psf->header.indx += bytes ; + + return bytes ; +} /* header_read */ + +static void +header_seek (SF_PRIVATE *psf, sf_count_t position, int whence) +{ + switch (whence) + { case SEEK_SET : + if (psf->header.indx + position >= psf->header.len) + psf_bump_header_allocation (psf, position) ; + if (position > psf->header.len) + { /* Too much header to cache so just seek instead. */ + psf->header.indx = psf->header.end = 0 ; + psf_fseek (psf, position, whence) ; + return ; + } ; + if (position > psf->header.end) + psf->header.end += psf_fread (psf->header.ptr + psf->header.end, 1, position - psf->header.end, psf) ; + psf->header.indx = position ; + break ; + + case SEEK_CUR : + if (psf->header.indx + position >= psf->header.len) + psf_bump_header_allocation (psf, position) ; + + if (psf->header.indx + position < 0) + break ; + + if (psf->header.indx >= psf->header.len) + { psf_fseek (psf, position, whence) ; + return ; + } ; + + if (psf->header.indx + position <= psf->header.end) + { psf->header.indx += position ; + break ; + } ; + + 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 ; + 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 ; + } ; + + psf->header.end += psf_fread (psf->header.ptr + psf->header.end, 1, position - (psf->header.end - psf->header.indx), psf) ; + psf->header.indx = psf->header.end ; + break ; + + case SEEK_END : + default : + psf_log_printf (psf, "Bad whence param in header_seek().\n") ; + break ; + } ; + + return ; +} /* header_seek */ + +static int +header_gets (SF_PRIVATE *psf, char *ptr, int bufsize) +{ int k ; + + if (psf->header.indx + bufsize >= psf->header.len && psf_bump_header_allocation (psf, bufsize)) + return 0 ; + + for (k = 0 ; k < bufsize - 1 ; k++) + { if (psf->header.indx < psf->header.end) + { ptr [k] = psf->header.ptr [psf->header.indx] ; + psf->header.indx ++ ; + } + else + { psf->header.end += psf_fread (psf->header.ptr + psf->header.end, 1, 1, psf) ; + ptr [k] = psf->header.ptr [psf->header.indx] ; + psf->header.indx = psf->header.end ; + } ; + + if (ptr [k] == '\n') + break ; + } ; + + ptr [k] = 0 ; + + return k ; +} /* header_gets */ + +int +psf_binheader_readf (SF_PRIVATE *psf, char const *format, ...) +{ va_list argptr ; + sf_count_t *countptr, countdata ; + unsigned char *ucptr, sixteen_bytes [16] = { 0 } ; + unsigned int *intptr, intdata ; + unsigned short *shortptr ; + char *charptr ; + float *floatptr ; + double *doubleptr ; + char c ; + int byte_count = 0, count = 0 ; + + if (! format) + return psf_ftell (psf) ; + + va_start (argptr, format) ; + + while ((c = *format++)) + { + if (psf->header.indx + 16 >= psf->header.len && psf_bump_header_allocation (psf, 16)) + break ; + + switch (c) + { case 'e' : /* All conversions are now from LE to host. */ + psf->rwf_endian = SF_ENDIAN_LITTLE ; + break ; + + case 'E' : /* All conversions are now from BE to host. */ + psf->rwf_endian = SF_ENDIAN_BIG ; + break ; + + case 'm' : /* 4 byte marker value eg 'RIFF' */ + intptr = va_arg (argptr, unsigned int*) ; + *intptr = 0 ; + ucptr = (unsigned char*) intptr ; + byte_count += header_read (psf, ucptr, sizeof (int)) ; + *intptr = GET_MARKER (ucptr) ; + break ; + + case 'h' : + intptr = va_arg (argptr, unsigned int*) ; + *intptr = 0 ; + ucptr = (unsigned char*) intptr ; + byte_count += header_read (psf, sixteen_bytes, sizeof (sixteen_bytes)) ; + { int k ; + intdata = 0 ; + for (k = 0 ; k < 16 ; k++) + intdata ^= sixteen_bytes [k] << k ; + } + *intptr = intdata ; + break ; + + case '1' : + charptr = va_arg (argptr, char*) ; + *charptr = 0 ; + byte_count += header_read (psf, charptr, sizeof (char)) ; + break ; + + case '2' : /* 2 byte value with the current endian-ness */ + shortptr = va_arg (argptr, unsigned short*) ; + *shortptr = 0 ; + ucptr = (unsigned char*) shortptr ; + byte_count += header_read (psf, ucptr, sizeof (short)) ; + if (psf->rwf_endian == SF_ENDIAN_BIG) + *shortptr = GET_BE_SHORT (ucptr) ; + else + *shortptr = GET_LE_SHORT (ucptr) ; + break ; + + case '3' : /* 3 byte value with the current endian-ness */ + intptr = va_arg (argptr, unsigned int*) ; + *intptr = 0 ; + byte_count += header_read (psf, sixteen_bytes, 3) ; + if (psf->rwf_endian == SF_ENDIAN_BIG) + *intptr = GET_BE_3BYTE (sixteen_bytes) ; + else + *intptr = GET_LE_3BYTE (sixteen_bytes) ; + break ; + + case '4' : /* 4 byte value with the current endian-ness */ + intptr = va_arg (argptr, unsigned int*) ; + *intptr = 0 ; + ucptr = (unsigned char*) intptr ; + byte_count += header_read (psf, ucptr, sizeof (int)) ; + if (psf->rwf_endian == SF_ENDIAN_BIG) + *intptr = psf_get_be32 (ucptr, 0) ; + else + *intptr = psf_get_le32 (ucptr, 0) ; + break ; + + case '8' : /* 8 byte value with the current endian-ness */ + countptr = va_arg (argptr, sf_count_t *) ; + *countptr = 0 ; + byte_count += header_read (psf, sixteen_bytes, 8) ; + if (psf->rwf_endian == SF_ENDIAN_BIG) + countdata = psf_get_be64 (sixteen_bytes, 0) ; + else + countdata = psf_get_le64 (sixteen_bytes, 0) ; + *countptr = countdata ; + break ; + + case 'f' : /* Float conversion */ + floatptr = va_arg (argptr, float *) ; + *floatptr = 0.0 ; + byte_count += header_read (psf, floatptr, sizeof (float)) ; + if (psf->rwf_endian == SF_ENDIAN_BIG) + *floatptr = float32_be_read ((unsigned char*) floatptr) ; + else + *floatptr = float32_le_read ((unsigned char*) floatptr) ; + break ; + + case 'd' : /* double conversion */ + doubleptr = va_arg (argptr, double *) ; + *doubleptr = 0.0 ; + byte_count += header_read (psf, doubleptr, sizeof (double)) ; + if (psf->rwf_endian == SF_ENDIAN_BIG) + *doubleptr = double64_be_read ((unsigned char*) doubleptr) ; + else + *doubleptr = double64_le_read ((unsigned char*) doubleptr) ; + break ; + + case 's' : + psf_log_printf (psf, "Format conversion 's' not implemented yet.\n") ; + /* + strptr = va_arg (argptr, char *) ; + size = strlen (strptr) + 1 ; + size += (size & 1) ; + longdata = H2LE_32 (size) ; + get_int (psf, longdata) ; + memcpy (&(psf->header.ptr [psf->header.indx]), strptr, size) ; + psf->header.indx += size ; + */ + break ; + + case 'b' : /* Raw bytes */ + charptr = va_arg (argptr, char*) ; + count = va_arg (argptr, size_t) ; + memset (charptr, 0, count) ; + byte_count += header_read (psf, charptr, count) ; + break ; + + case 'G' : + charptr = va_arg (argptr, char*) ; + count = va_arg (argptr, size_t) ; + memset (charptr, 0, count) ; + + if (psf->header.indx + count >= psf->header.len && psf_bump_header_allocation (psf, count)) + break ; + + byte_count += header_gets (psf, charptr, count) ; + break ; + + case 'z' : + psf_log_printf (psf, "Format conversion 'z' not implemented yet.\n") ; + /* + size = va_arg (argptr, size_t) ; + while (size) + { psf->header.ptr [psf->header.indx] = 0 ; + psf->header.indx ++ ; + size -- ; + } ; + */ + break ; + + case 'p' : /* Seek to position from start. */ + count = va_arg (argptr, size_t) ; + header_seek (psf, count, SEEK_SET) ; + byte_count = count ; + break ; + + case 'j' : /* Seek to position from current position. */ + count = va_arg (argptr, size_t) ; + header_seek (psf, count, SEEK_CUR) ; + byte_count += count ; + break ; + + case '!' : /* Clear buffer, forcing re-read. */ + psf->header.end = psf->header.indx = 0 ; + break ; + + default : + psf_log_printf (psf, "*** Invalid format specifier `%c'\n", c) ; + psf->error = SFE_INTERNAL ; + break ; + } ; + } ; + + va_end (argptr) ; + + return byte_count ; +} /* psf_binheader_readf */ + +/*----------------------------------------------------------------------------------------------- +*/ + +sf_count_t +psf_default_seek (SF_PRIVATE *psf, int UNUSED (mode), sf_count_t samples_from_start) +{ sf_count_t position, retval ; + + if (! (psf->blockwidth && psf->dataoffset >= 0)) + { psf->error = SFE_BAD_SEEK ; + return PSF_SEEK_ERROR ; + } ; + + if (! psf->sf.seekable) + { psf->error = SFE_NOT_SEEKABLE ; + return PSF_SEEK_ERROR ; + } ; + + position = psf->dataoffset + psf->blockwidth * samples_from_start ; + + if ((retval = psf_fseek (psf, position, SEEK_SET)) != position) + { psf->error = SFE_SEEK_FAILED ; + return PSF_SEEK_ERROR ; + } ; + + return samples_from_start ; +} /* psf_default_seek */ + +/*----------------------------------------------------------------------------------------------- +*/ + +void +psf_hexdump (const void *ptr, int len) +{ const char *data ; + char ascii [17] ; + int k, m ; + + if ((data = ptr) == NULL) + return ; + if (len <= 0) + return ; + + puts ("") ; + for (k = 0 ; k < len ; k += 16) + { memset (ascii, ' ', sizeof (ascii)) ; + + printf ("%08X: ", k) ; + for (m = 0 ; m < 16 && k + m < len ; m++) + { printf (m == 8 ? " %02X " : "%02X ", data [k + m] & 0xFF) ; + ascii [m] = psf_isprint (data [k + m]) ? data [k + m] : '.' ; + } ; + + if (m <= 8) printf (" ") ; + for ( ; m < 16 ; m++) printf (" ") ; + + ascii [16] = 0 ; + printf (" %s\n", ascii) ; + } ; + + puts ("") ; +} /* psf_hexdump */ + +void +psf_log_SF_INFO (SF_PRIVATE *psf) +{ psf_log_printf (psf, "---------------------------------\n") ; + + psf_log_printf (psf, " Sample rate : %d\n", psf->sf.samplerate) ; + if (psf->sf.frames == SF_COUNT_MAX) + psf_log_printf (psf, " Frames : unknown\n") ; + else + psf_log_printf (psf, " Frames : %D\n", psf->sf.frames) ; + psf_log_printf (psf, " Channels : %d\n", psf->sf.channels) ; + + psf_log_printf (psf, " Format : 0x%X\n", psf->sf.format) ; + psf_log_printf (psf, " Sections : %d\n", psf->sf.sections) ; + psf_log_printf (psf, " Seekable : %s\n", psf->sf.seekable ? "TRUE" : "FALSE") ; + + psf_log_printf (psf, "---------------------------------\n") ; +} /* psf_dump_SFINFO */ + +/*======================================================================================== +*/ + +int +psf_isprint (int ch) +{ return (ch >= ' ' && ch <= '~') ; +} /* psf_isprint */ + +void +psf_strlcat (char *dest, size_t n, const char *src) +{ strncat (dest, src, n - strlen (dest) - 1) ; + dest [n - 1] = 0 ; +} /* psf_strlcat */ + +void +psf_strlcpy (char *dest, size_t n, const char *src) +{ strncpy (dest, src, n - 1) ; + dest [n - 1] = 0 ; +} /* psf_strlcpy */ + +/*======================================================================================== +*/ + +void * +psf_memdup (const void *src, size_t n) +{ if (src == NULL) + return NULL ; + + void * mem = calloc (1, n & 3 ? n + 4 - (n & 3) : n) ; + if (mem != NULL) + memcpy (mem, src, n) ; + return mem ; +} /* psf_memdup */ + +void* +psf_memset (void *s, int c, sf_count_t len) +{ char *ptr ; + int setcount ; + + ptr = (char *) s ; + + while (len > 0) + { setcount = (len > 0x10000000) ? 0x10000000 : (int) len ; + + memset (ptr, c, setcount) ; + + ptr += setcount ; + len -= setcount ; + } ; + + return s ; +} /* psf_memset */ + + +/* +** Clang refuses to do sizeof (SF_CUES_VAR (cue_count)) so we have to manually +** bodgy something up instead. +*/ + +#ifdef _MSC_VER +typedef SF_CUES_VAR (0) SF_CUES_0 ; +#else +typedef SF_CUES_VAR () SF_CUES_0 ; +#endif + +/* calculate size of SF_CUES struct given number of cues */ +#define SF_CUES_VAR_SIZE(count) (sizeof (SF_CUES_0) + count * sizeof (SF_CUE_POINT)) + +/* calculate number of cues in SF_CUES struct given data size */ +#define SF_CUES_COUNT(datasize) (((datasize) - sizeof (uint32_t)) / sizeof (SF_CUE_POINT)) + +SF_CUES * +psf_cues_alloc (uint32_t cue_count) +{ SF_CUES *pcues = calloc (1, SF_CUES_VAR_SIZE (cue_count)) ; + if (pcues) + { pcues->cue_count = cue_count ; + } ; + return pcues ; +} /* psf_cues_alloc */ + +SF_CUES * +psf_cues_dup (const void * ptr, size_t datasize) +{ const SF_CUES *pcues = ptr ; + SF_CUES *pnew = NULL ; + + if (pcues->cue_count <= SF_CUES_COUNT (datasize)) + { /* check that passed-in datasize is consistent with cue_count in passed-in SF_CUES struct */ + pnew = psf_cues_alloc (pcues->cue_count) ; + memcpy (pnew, pcues, SF_CUES_VAR_SIZE (pcues->cue_count)) ; + } + + return pnew ; +} /* psf_cues_dup */ + +void +psf_get_cues (SF_PRIVATE * psf, void * data, size_t datasize) +{ + if (psf->cues) + { uint32_t cue_count = SF_CUES_COUNT (datasize) ; + + cue_count = SF_MIN (cue_count, psf->cues->cue_count) ; + memcpy (data, psf->cues, SF_CUES_VAR_SIZE (cue_count)) ; + ((SF_CUES*) data)->cue_count = cue_count ; + } ; + + return ; +} /* psf_get_cues */ + + +SF_INSTRUMENT * +psf_instrument_alloc (void) +{ SF_INSTRUMENT *instr ; + + instr = calloc (1, sizeof (SF_INSTRUMENT)) ; + + if (instr == NULL) + return NULL ; + + /* Set non-zero default values. */ + instr->basenote = -1 ; + instr->velocity_lo = -1 ; + instr->velocity_hi = -1 ; + instr->key_lo = -1 ; + instr->key_hi = -1 ; + + return instr ; +} /* psf_instrument_alloc */ + +void +psf_sanitize_string (char * cptr, int len) +{ + do + { + len -- ; + cptr [len] = psf_isprint (cptr [len]) ? cptr [len] : '.' ; + } + while (len > 0) ; +} /* psf_sanitize_string */ + +void +psf_get_date_str (char *str, int maxlen) +{ time_t current ; + struct tm timedata, *tmptr ; + + time (¤t) ; + +#if defined (HAVE_GMTIME_R) + /* If the re-entrant version is available, use it. */ + tmptr = gmtime_r (¤t, &timedata) ; +#elif defined (HAVE_GMTIME) + /* Otherwise use the standard one and copy the data to local storage. */ + tmptr = gmtime (¤t) ; + memcpy (&timedata, tmptr, sizeof (timedata)) ; +#else + tmptr = NULL ; +#endif + + if (tmptr) + snprintf (str, maxlen, "%4d-%02d-%02d %02d:%02d:%02d UTC", + 1900 + timedata.tm_year, timedata.tm_mon, timedata.tm_mday, + timedata.tm_hour, timedata.tm_min, timedata.tm_sec) ; + else + snprintf (str, maxlen, "Unknown date") ; + + return ; +} /* psf_get_date_str */ + +int +subformat_to_bytewidth (int format) +{ + switch (format) + { case SF_FORMAT_PCM_U8 : + case SF_FORMAT_PCM_S8 : + return 1 ; + case SF_FORMAT_PCM_16 : + return 2 ; + case SF_FORMAT_PCM_24 : + return 3 ; + case SF_FORMAT_PCM_32 : + case SF_FORMAT_FLOAT : + return 4 ; + case SF_FORMAT_DOUBLE : + return 8 ; + } ; + + return 0 ; +} /* subformat_to_bytewidth */ + +int +s_bitwidth_to_subformat (int bits) +{ static int array [] = + { SF_FORMAT_PCM_S8, SF_FORMAT_PCM_16, SF_FORMAT_PCM_24, SF_FORMAT_PCM_32 + } ; + + if (bits < 8 || bits > 32) + return 0 ; + + return array [((bits + 7) / 8) - 1] ; +} /* bitwidth_to_subformat */ + +int +u_bitwidth_to_subformat (int bits) +{ static int array [] = + { SF_FORMAT_PCM_U8, SF_FORMAT_PCM_16, SF_FORMAT_PCM_24, SF_FORMAT_PCM_32 + } ; + + if (bits < 8 || bits > 32) + return 0 ; + + return array [((bits + 7) / 8) - 1] ; +} /* bitwidth_to_subformat */ + +/* +** psf_rand_int32 : Not crypto quality, but more than adequate for things +** like stream serial numbers in Ogg files or the unique_id field of the +** SF_PRIVATE struct. +*/ + +int32_t +psf_rand_int32 (void) +{ static uint64_t value = 0 ; + int k, count ; + + if (value == 0) + { +#if HAVE_GETTIMEOFDAY + struct timeval tv ; + gettimeofday (&tv, NULL) ; + value = tv.tv_sec + tv.tv_usec ; +#else + value = time (NULL) ; +#endif + } ; + + count = 4 + (value & 7) ; + for (k = 0 ; k < count ; k++) + value = (11117 * value + 211231) & 0x7fffffff ; + + return (int32_t) value ; +} /* psf_rand_int32 */ + +void +append_snprintf (char * dest, size_t maxlen, const char * fmt, ...) +{ size_t len = strlen (dest) ; + + if (len < maxlen) + { va_list ap ; + + va_start (ap, fmt) ; + vsnprintf (dest + len, maxlen - len, fmt, ap) ; + va_end (ap) ; + } ; + + return ; +} /* append_snprintf */ + + +void +psf_strlcpy_crlf (char *dest, const char *src, size_t destmax, size_t srcmax) +{ /* Must be minus 2 so it can still expand a single trailing '\n' or '\r'. */ + char * destend = dest + destmax - 2 ; + const char * srcend = src + srcmax ; + + while (dest < destend && src < srcend) + { if ((src [0] == '\r' && src [1] == '\n') || (src [0] == '\n' && src [1] == '\r')) + { *dest++ = '\r' ; + *dest++ = '\n' ; + src += 2 ; + continue ; + } ; + + if (src [0] == '\r') + { *dest++ = '\r' ; + *dest++ = '\n' ; + src += 1 ; + continue ; + } ; + + if (src [0] == '\n') + { *dest++ = '\r' ; + *dest++ = '\n' ; + src += 1 ; + continue ; + } ; + + *dest++ = *src++ ; + } ; + + /* Make sure dest is terminated. */ + *dest = 0 ; +} /* psf_strlcpy_crlf */ + +sf_count_t +psf_decode_frame_count (SF_PRIVATE *psf) +{ sf_count_t count, readlen, total = 0 ; + BUF_UNION ubuf ; + + /* If we're reading from a pipe or the file is too long, just return SF_COUNT_MAX. */ + if (psf_is_pipe (psf) || psf->datalength > 0x1000000) + return SF_COUNT_MAX ; + + psf_fseek (psf, psf->dataoffset, SEEK_SET) ; + + readlen = ARRAY_LEN (ubuf.ibuf) / psf->sf.channels ; + readlen *= psf->sf.channels ; + + while ((count = psf->read_int (psf, ubuf.ibuf, readlen)) > 0) + total += count ; + + psf_fseek (psf, psf->dataoffset, SEEK_SET) ; + + return total / psf->sf.channels ; +} /* psf_decode_frame_count */ + +/*============================================================================== +*/ + +#define CASE_NAME(x) case x : return #x ; break ; + +const char * +str_of_major_format (int format) +{ switch (SF_CONTAINER (format)) + { CASE_NAME (SF_FORMAT_WAV) ; + CASE_NAME (SF_FORMAT_AIFF) ; + CASE_NAME (SF_FORMAT_AU) ; + CASE_NAME (SF_FORMAT_RAW) ; + CASE_NAME (SF_FORMAT_PAF) ; + CASE_NAME (SF_FORMAT_SVX) ; + CASE_NAME (SF_FORMAT_NIST) ; + CASE_NAME (SF_FORMAT_VOC) ; + CASE_NAME (SF_FORMAT_IRCAM) ; + CASE_NAME (SF_FORMAT_W64) ; + CASE_NAME (SF_FORMAT_MAT4) ; + CASE_NAME (SF_FORMAT_MAT5) ; + CASE_NAME (SF_FORMAT_PVF) ; + CASE_NAME (SF_FORMAT_XI) ; + CASE_NAME (SF_FORMAT_HTK) ; + CASE_NAME (SF_FORMAT_SDS) ; + CASE_NAME (SF_FORMAT_AVR) ; + CASE_NAME (SF_FORMAT_WAVEX) ; + CASE_NAME (SF_FORMAT_SD2) ; + CASE_NAME (SF_FORMAT_FLAC) ; + CASE_NAME (SF_FORMAT_CAF) ; + CASE_NAME (SF_FORMAT_WVE) ; + CASE_NAME (SF_FORMAT_OGG) ; + CASE_NAME (SF_FORMAT_MPEG) ; + default : + break ; + } ; + + return "BAD_MAJOR_FORMAT" ; +} /* str_of_major_format */ + +const char * +str_of_minor_format (int format) +{ switch (SF_CODEC (format)) + { CASE_NAME (SF_FORMAT_PCM_S8) ; + CASE_NAME (SF_FORMAT_PCM_16) ; + CASE_NAME (SF_FORMAT_PCM_24) ; + CASE_NAME (SF_FORMAT_PCM_32) ; + CASE_NAME (SF_FORMAT_PCM_U8) ; + CASE_NAME (SF_FORMAT_FLOAT) ; + CASE_NAME (SF_FORMAT_DOUBLE) ; + CASE_NAME (SF_FORMAT_ULAW) ; + CASE_NAME (SF_FORMAT_ALAW) ; + CASE_NAME (SF_FORMAT_IMA_ADPCM) ; + CASE_NAME (SF_FORMAT_MS_ADPCM) ; + CASE_NAME (SF_FORMAT_GSM610) ; + CASE_NAME (SF_FORMAT_VOX_ADPCM) ; + CASE_NAME (SF_FORMAT_NMS_ADPCM_16) ; + CASE_NAME (SF_FORMAT_NMS_ADPCM_24) ; + CASE_NAME (SF_FORMAT_NMS_ADPCM_32) ; + CASE_NAME (SF_FORMAT_G721_32) ; + CASE_NAME (SF_FORMAT_G723_24) ; + CASE_NAME (SF_FORMAT_G723_40) ; + CASE_NAME (SF_FORMAT_DWVW_12) ; + CASE_NAME (SF_FORMAT_DWVW_16) ; + CASE_NAME (SF_FORMAT_DWVW_24) ; + CASE_NAME (SF_FORMAT_DWVW_N) ; + CASE_NAME (SF_FORMAT_DPCM_8) ; + CASE_NAME (SF_FORMAT_DPCM_16) ; + CASE_NAME (SF_FORMAT_VORBIS) ; + CASE_NAME (SF_FORMAT_MPEG_LAYER_I) ; + CASE_NAME (SF_FORMAT_MPEG_LAYER_II) ; + CASE_NAME (SF_FORMAT_MPEG_LAYER_III) ; + default : + break ; + } ; + + return "BAD_MINOR_FORMAT" ; +} /* str_of_minor_format */ + +const char * +str_of_open_mode (int mode) +{ switch (mode) + { CASE_NAME (SFM_READ) ; + CASE_NAME (SFM_WRITE) ; + CASE_NAME (SFM_RDWR) ; + + default : + break ; + } ; + + return "BAD_MODE" ; +} /* str_of_open_mode */ + +const char * +str_of_endianness (int end) +{ switch (end) + { CASE_NAME (SF_ENDIAN_BIG) ; + CASE_NAME (SF_ENDIAN_LITTLE) ; + CASE_NAME (SF_ENDIAN_CPU) ; + default : + break ; + } ; + + /* Zero length string for SF_ENDIAN_FILE. */ + return "" ; +} /* str_of_endianness */ + +/*============================================================================== +*/ + +void +psf_f2s_array (const float *src, short *dest, int count, int normalize) +{ float normfact ; + + normfact = normalize ? (1.0 * 0x7FFF) : 1.0 ; + for (int i = 0 ; i < count ; i++) + dest [i] = psf_lrintf (src [i] * normfact) ; + + return ; +} /* psf_f2s_array */ + +void +psf_f2s_clip_array (const float *src, short *dest, int count, int normalize) +{ float normfact, scaled_value ; + + normfact = normalize ? (1.0 * 0x8000) : 1.0 ; + + for (int i = 0 ; i < count ; i++) + { scaled_value = src [i] * normfact ; + if (scaled_value >= (1.0 * 0x7FFF)) + { dest [i] = 0x7FFF ; + continue ; + } ; + if (scaled_value <= (-8.0 * 0x1000)) + { dest [i] = -0x7FFF - 1 ; + continue ; + } ; + + dest [i] = psf_lrintf (scaled_value) ; + } ; + + return ; +} /* psf_f2s_clip_array */ + +void +psf_d2s_array (const double *src, short *dest, int count, int normalize) +{ double normfact ; + + normfact = normalize ? (1.0 * 0x7FFF) : 1.0 ; + for (int i = 0 ; i < count ; i++) + dest [i] = psf_lrint (src [i] * normfact) ; + + return ; +} /* psf_f2s_array */ + +void +psf_d2s_clip_array (const double *src, short *dest, int count, int normalize) +{ double normfact, scaled_value ; + + normfact = normalize ? (1.0 * 0x8000) : 1.0 ; + + for (int i = 0 ; i < count ; i++) + { scaled_value = src [i] * normfact ; + if (scaled_value >= (1.0 * 0x7FFF)) + { dest [i] = 0x7FFF ; + continue ; + } ; + if (scaled_value <= (-8.0 * 0x1000)) + { dest [i] = -0x7FFF - 1 ; + continue ; + } ; + + dest [i] = psf_lrint (scaled_value) ; + } ; + + return ; +} /* psf_d2s_clip_array */ + + +void +psf_f2i_array (const float *src, int *dest, int count, int normalize) +{ float normfact ; + + normfact = normalize ? (1.0 * 0x7FFFFFFF) : 1.0 ; + for (int i = 0 ; i < count ; i++) + dest [i] = psf_lrintf (src [i] * normfact) ; + + return ; +} /* psf_f2i_array */ + +void +psf_f2i_clip_array (const float *src, int *dest, int count, int normalize) +{ float normfact, scaled_value ; + + normfact = normalize ? (8.0 * 0x10000000) : 1.0 ; + + for (int i = 0 ; i < count ; i++) + { scaled_value = src [i] * normfact ; +#if CPU_CLIPS_POSITIVE == 0 + if (scaled_value >= (1.0 * 0x7FFFFFFF)) + { dest [i] = 0x7FFFFFFF ; + continue ; + } ; +#endif +#if CPU_CLIPS_NEGATIVE == 0 + if (scaled_value <= (-8.0 * 0x10000000)) + { dest [i] = 0x80000000 ; + continue ; + } ; +#endif + + dest [i] = psf_lrintf (scaled_value) ; + } ; + + return ; +} /* psf_f2i_clip_array */ + +void +psf_d2i_array (const double *src, int *dest, int count, int normalize) +{ double normfact ; + + normfact = normalize ? (1.0 * 0x7FFFFFFF) : 1.0 ; + for (int i = 0 ; i < count ; i++) + dest [i] = psf_lrint (src [i] * normfact) ; + + return ; +} /* psf_f2i_array */ + +void +psf_d2i_clip_array (const double *src, int *dest, int count, int normalize) +{ double normfact, scaled_value ; + + normfact = normalize ? (8.0 * 0x10000000) : 1.0 ; + + for (int i = 0 ; i < count ; i++) + { scaled_value = src [i] * normfact ; +#if CPU_CLIPS_POSITIVE == 0 + if (scaled_value >= (1.0 * 0x7FFFFFFF)) + { dest [i] = 0x7FFFFFFF ; + continue ; + } ; +#endif +#if CPU_CLIPS_NEGATIVE == 0 + if (scaled_value <= (-8.0 * 0x10000000)) + { dest [i] = 0x80000000 ; + continue ; + } ; +#endif + + dest [i] = psf_lrint (scaled_value) ; + } ; + + return ; +} /* psf_d2i_clip_array */ + +FILE * +psf_open_tmpfile (char * fname, size_t fnamelen) +{ const char * tmpdir ; + FILE * file ; + + if (OS_IS_WIN32) + tmpdir = getenv ("TEMP") ; + else + { tmpdir = getenv ("TMPDIR") ; + tmpdir = tmpdir == NULL ? "/tmp" : tmpdir ; + } ; + + if (tmpdir && access (tmpdir, R_OK | W_OK | X_OK) == 0) + { snprintf (fname, fnamelen, "%s/%x%x-alac.tmp", tmpdir, psf_rand_int32 (), psf_rand_int32 ()) ; + if ((file = fopen (fname, "wb+")) != NULL) + return file ; + } ; + + snprintf (fname, fnamelen, "%x%x-alac.tmp", psf_rand_int32 (), psf_rand_int32 ()) ; + if ((file = fopen (fname, "wb+")) != NULL) + return file ; + + memset (fname, 0, fnamelen) ; + return NULL ; +} /* psf_open_tmpfile */ diff --git a/extern/libsndfile-modified/src/common.h b/extern/libsndfile-modified/src/common.h new file mode 100644 index 000000000..d92eabde9 --- /dev/null +++ b/extern/libsndfile-modified/src/common.h @@ -0,0 +1,1096 @@ +/* +** Copyright (C) 1999-2018 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef SNDFILE_COMMON_H +#define SNDFILE_COMMON_H + +#include "sfconfig.h" + +#include +#include +#if HAVE_STDBOOL_H +#include +#endif + +#if HAVE_INTTYPES_H +#include +#elif HAVE_STDINT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#ifndef SNDFILE_H +#include "sndfile.h" +#endif + +#include + +#ifdef USE_SSE2 +# ifdef _MSC_VER +# include +# else +# include +# endif +#endif + +#ifdef __cplusplus +#error "This code is not designed to be compiled with a C++ compiler." +#endif + + + +/* +** Inspiration : http://sourcefrog.net/weblog/software/languages/C/unused.html +*/ +#ifdef UNUSED +#elif defined (__GNUC__) +# define UNUSED(x) UNUSED_ ## x __attribute__ ((unused)) +#elif defined (__LCLINT__) +# define UNUSED(x) /*@unused@*/ x +#else +# define UNUSED(x) x +#endif + +#ifdef __GNUC__ +# define WARN_UNUSED __attribute__ ((warn_unused_result)) +#else +# define WARN_UNUSED +#endif + +#define SF_BUFFER_LEN (8192) +#define SF_FILENAME_LEN (1024) +#define SF_SYSERR_LEN (256) +#define SF_MAX_STRINGS (32) +#define SF_PARSELOG_LEN (2048) + +#define PSF_SEEK_ERROR ((sf_count_t) -1) + +#define BITWIDTH2BYTES(x) (((x) + 7) / 8) + +/* For some reason sizeof returns an unsigned value which causes +** a warning when that value is added or subtracted from a signed +** value. Use SIGNED_SIZEOF instead. +*/ +#define SIGNED_SIZEOF(x) ((int) sizeof (x)) + +#define ARRAY_LEN(x) ((int) (sizeof (x) / sizeof ((x) [0]))) + +#define SF_MAX(a, b) ((a) > (b) ? (a) : (b)) +#define SF_MIN(a, b) ((a) < (b) ? (a) : (b)) + + +#define COMPILE_TIME_ASSERT(e) (sizeof (struct { int : - !! (e) ; })) + + +#define SF_MAX_CHANNELS 1024 + +/* +* Macros for spliting the format file of SF_INFO into container type, +** codec type and endian-ness. +*/ +#define SF_CONTAINER(x) ((x) & SF_FORMAT_TYPEMASK) +#define SF_CODEC(x) ((x) & SF_FORMAT_SUBMASK) +#define SF_ENDIAN(x) ((x) & SF_FORMAT_ENDMASK) + +/* +** Binheader cast macros. +*/ + +#define BHW1(x) ((uint8_t) (x)) +#define BHW2(x) ((uint16_t) (x)) +#define BHW3(x) ((uint32_t) (x)) +#define BHW4(x) ((uint32_t) (x)) +#define BHW8(x) ((uint64_t) (x)) + +#define BHWm(x) ((uint32_t) (x)) +#define BHWS(x) ((char *) (x)) + +#define BHWf(x) ((double) (x)) +#define BHWd(x) ((double) (x)) + +#define BHWh(x) ((void *) (x)) +#define BHWj(x) ((size_t) (x)) +#define BHWp(x) ((char *) (x)) +#define BHWo(x) ((size_t) (x)) +#define BHWs(x) ((char *) (x)) +#define BHWv(x) ((const void *) (x)) +#define BHWz(x) ((size_t) (x)) + +/*------------------------------------------------------------------------------ +*/ + +enum +{ /* PEAK chunk location. */ + SF_PEAK_START = 42, + SF_PEAK_END = 43, + + /* PEAK chunk location. */ + SF_SCALE_MAX = 52, + SF_SCALE_MIN = 53, + + /* str_flags values. */ + SF_STR_ALLOW_START = 0x0100, + SF_STR_ALLOW_END = 0x0200, + + /* Location of strings. */ + SF_STR_LOCATE_START = 0x0400, + SF_STR_LOCATE_END = 0x0800, + + SFD_TYPEMASK = 0x0FFFFFFF +} ; + +#define SFM_MASK (SFM_READ | SFM_WRITE | SFM_RDWR) +#define SFM_UNMASK (~SFM_MASK) + +/*--------------------------------------------------------------------------------------- +** Formats that may be supported at some time in the future. +** When support is finalised, these values move to src/sndfile.h. +*/ + +enum +{ /* Work in progress. */ + SF_FORMAT_SPEEX = 0x5000000, + SF_FORMAT_OGGFLAC = 0x5000001, + + /* Formats supported read only. */ + SF_FORMAT_TXW = 0x4030000, /* Yamaha TX16 sampler file */ + SF_FORMAT_DWD = 0x4040000, /* DiamondWare Digirized */ + + /* Following are detected but not supported. */ + SF_FORMAT_REX = 0x40A0000, /* Propellorheads Rex/Rcy */ + SF_FORMAT_REX2 = 0x40D0000, /* Propellorheads Rex2 */ + SF_FORMAT_KRZ = 0x40E0000, /* Kurzweil sampler file */ + SF_FORMAT_WMA = 0x4100000, /* Windows Media Audio. */ + SF_FORMAT_SHN = 0x4110000, /* Shorten. */ + + /* Unsupported encodings. */ + SF_FORMAT_SVX_FIB = 0x1020, /* SVX Fibonacci Delta encoding. */ + SF_FORMAT_SVX_EXP = 0x1021, /* SVX Exponential Delta encoding. */ + + SF_FORMAT_PCM_N = 0x1030 +} ; + +/*--------------------------------------------------------------------------------------- +*/ + +typedef struct +{ unsigned kuki_offset ; + unsigned pakt_offset ; + + unsigned bits_per_sample ; + unsigned frames_per_packet ; + + int64_t packets ; + int64_t valid_frames ; + int32_t priming_frames ; + int32_t remainder_frames ; +} ALAC_DECODER_INFO ; + +/*--------------------------------------------------------------------------------------- +** PEAK_CHUNK - This chunk type is common to both AIFF and WAVE files although their +** endian encodings are different. +*/ + +typedef struct +{ double value ; /* signed value of peak */ + sf_count_t position ; /* the sample frame for the peak */ +} PEAK_POS ; + +typedef struct +{ /* libsndfile internal : write a PEAK chunk at the start or end of the file? */ + int peak_loc ; + + /* WAV/AIFF */ + unsigned int version ; /* version of the PEAK chunk */ + unsigned int timestamp ; /* secs since 1/1/1970 */ + + /* CAF */ + unsigned int edit_number ; + + /* the per channel peak info */ + PEAK_POS peaks [] ; +} PEAK_INFO ; + +static inline PEAK_INFO * +peak_info_calloc (int channels) +{ return calloc (1, sizeof (PEAK_INFO) + channels * sizeof (PEAK_POS)) ; +} /* peak_info_calloc */ + +typedef struct +{ int type ; + int flags ; + size_t offset ; +} STR_DATA ; + +typedef struct +{ uint64_t hash ; + char id [64] ; + unsigned id_size ; + uint32_t mark32 ; + sf_count_t offset ; + uint32_t len ; +} READ_CHUNK ; + +typedef struct +{ uint64_t hash ; + uint32_t mark32 ; + uint32_t len ; + void *data ; +} WRITE_CHUNK ; + +typedef struct +{ uint32_t count ; + uint32_t used ; + READ_CHUNK *chunks ; +} READ_CHUNKS ; +typedef struct +{ uint32_t count ; + uint32_t used ; + WRITE_CHUNK *chunks ; +} WRITE_CHUNKS ; + +struct SF_CHUNK_ITERATOR +{ uint32_t current ; + int64_t hash ; + char id [64] ; + unsigned id_size ; + SNDFILE *sndfile ; +} ; + +static inline size_t +make_size_t (int x) +{ return (size_t) x ; +} /* make_size_t */ + +typedef SF_BROADCAST_INFO_VAR (16 * 1024) SF_BROADCAST_INFO_16K ; + +typedef SF_CART_INFO_VAR (16 * 1024) SF_CART_INFO_16K ; + +typedef struct +{ sf_count_t offset ; + sf_count_t len ; + unsigned minor_version ; +} ID3V2_HEADER_INFO ; + +#if SIZEOF_WCHAR_T == 2 +typedef wchar_t sfwchar_t ; +#else +typedef int16_t sfwchar_t ; +#endif + + +void *psf_memdup (const void *src, size_t n) ; + +/* +** This version of isprint specifically ignores any locale info. Its used for +** determining which characters can be printed in things like hexdumps. +*/ +int psf_isprint (int ch) ; + +/*======================================================================================= +** SF_PRIVATE stuct - a pointer to this struct is passed back to the caller of the +** sf_open_XXXX functions. The caller however has no knowledge of the struct's +** contents. +*/ + +typedef struct +{ + char path [SF_FILENAME_LEN] ; + char dir [SF_FILENAME_LEN] ; + char name [SF_FILENAME_LEN / 4] ; + +#if USE_WINDOWS_API + /* + ** These fields can only be used in src/file_io.c. + ** They are basically the same as a windows file HANDLE. + */ + void *handle, *hsaved ; +#else + /* These fields can only be used in src/file_io.c. */ + int filedes, savedes ; +#endif + + int do_not_close_descriptor ; + int mode ; /* Open mode : SFM_READ, SFM_WRITE or SFM_RDWR. */ +} PSF_FILE ; + + + +typedef union +{ double dbuf [SF_BUFFER_LEN / sizeof (double)] ; +#if (defined (SIZEOF_INT64_T) && (SIZEOF_INT64_T == 8)) + int64_t lbuf [SF_BUFFER_LEN / sizeof (int64_t)] ; +#else + long lbuf [SF_BUFFER_LEN / sizeof (double)] ; +#endif + float fbuf [SF_BUFFER_LEN / sizeof (float)] ; + int ibuf [SF_BUFFER_LEN / sizeof (int)] ; + short sbuf [SF_BUFFER_LEN / sizeof (short)] ; + char cbuf [SF_BUFFER_LEN / sizeof (char)] ; + signed char scbuf [SF_BUFFER_LEN / sizeof (signed char)] ; + unsigned char ucbuf [SF_BUFFER_LEN / sizeof (signed char)] ; +} BUF_UNION ; + + + +typedef struct sf_private_tag +{ + PSF_FILE file, rsrc ; + + char syserr [SF_SYSERR_LEN] ; + + /* parselog and indx should only be changed within the logging functions + ** of common.c + */ + struct + { char buf [SF_PARSELOG_LEN] ; + int indx ; + } parselog ; + + + struct + { unsigned char * ptr ; + sf_count_t indx, end, len ; + } header ; + + int rwf_endian ; /* Header endian-ness flag. */ + + /* Storage and housekeeping data for adding/reading strings from + ** sound files. + */ + struct + { STR_DATA data [SF_MAX_STRINGS] ; + char *storage ; + size_t storage_len ; + size_t storage_used ; + uint32_t flags ; + } strings ; + + /* Guard value. If this changes the buffers above have overflowed. */ + int Magick ; + + unsigned unique_id ; + + int error ; + + int endian ; /* File endianness : SF_ENDIAN_LITTLE or SF_ENDIAN_BIG. */ + int data_endswap ; /* Need to endswap data? */ + + /* + ** Maximum float value for calculating the multiplier for + ** float/double to short/int conversions. + */ + int float_int_mult ; + float float_max ; + + int scale_int_float ; + + /* Vairables for handling pipes. */ + int is_pipe ; /* True if file is a pipe. */ + sf_count_t pipeoffset ; /* Number of bytes read from a pipe. */ + + /* True if clipping must be performed on float->int conversions. */ + int add_clipping ; + + SF_INFO sf ; + + int have_written ; /* Has a single write been done to the file? */ + PEAK_INFO *peak_info ; + + /* Cue Marker Info */ + SF_CUES *cues ; + + /* Loop Info */ + SF_LOOP_INFO *loop_info ; + SF_INSTRUMENT *instrument ; + + /* Broadcast (EBU) Info */ + SF_BROADCAST_INFO_16K *broadcast_16k ; + + /* Cart (AES46) Info */ + SF_CART_INFO_16K *cart_16k ; + + /* Channel map data (if present) : an array of ints. */ + int *channel_map ; + + sf_count_t filelength ; /* Overall length of (embedded) file. */ + sf_count_t fileoffset ; /* Offset in number of bytes from beginning of file. */ + + sf_count_t rsrclength ; /* Length of the resource fork (if it exists). */ + + sf_count_t dataoffset ; /* Offset in number of bytes from beginning of file. */ + sf_count_t datalength ; /* Length in bytes of the audio data. */ + sf_count_t dataend ; /* Offset to file tailer. */ + + int blockwidth ; /* Size in bytes of one set of interleaved samples. */ + int bytewidth ; /* Size in bytes of one sample (one channel). */ + + void *dither ; + void *interleave ; + + int last_op ; /* Last operation; either SFM_READ or SFM_WRITE */ + sf_count_t read_current ; + sf_count_t write_current ; + + void *container_data ; /* This is a pointer to dynamically allocated file + ** container format specific data. + */ + + void *codec_data ; /* This is a pointer to dynamically allocated file + ** codec format specific data. + */ + + SF_DITHER_INFO write_dither ; + SF_DITHER_INFO read_dither ; + + int norm_double ; + int norm_float ; + + int auto_header ; + + int ieee_replace ; + + /* A set of file specific function pointers */ + sf_count_t (*read_short) (struct sf_private_tag*, short *ptr, sf_count_t len) ; + sf_count_t (*read_int) (struct sf_private_tag*, int *ptr, sf_count_t len) ; + sf_count_t (*read_float) (struct sf_private_tag*, float *ptr, sf_count_t len) ; + sf_count_t (*read_double) (struct sf_private_tag*, double *ptr, sf_count_t len) ; + + sf_count_t (*write_short) (struct sf_private_tag*, const short *ptr, sf_count_t len) ; + sf_count_t (*write_int) (struct sf_private_tag*, const int *ptr, sf_count_t len) ; + sf_count_t (*write_float) (struct sf_private_tag*, const float *ptr, sf_count_t len) ; + sf_count_t (*write_double) (struct sf_private_tag*, const double *ptr, sf_count_t len) ; + + sf_count_t (*seek) (struct sf_private_tag*, int mode, sf_count_t samples_from_start) ; + int (*write_header) (struct sf_private_tag*, int calc_length) ; + int (*command) (struct sf_private_tag*, int command, void *data, int datasize) ; + int (*byterate) (struct sf_private_tag*) ; + + /* + ** Separate close functions for the codec and the container. + ** The codec close function is always called first. + */ + int (*codec_close) (struct sf_private_tag*) ; + int (*container_close) (struct sf_private_tag*) ; + + char *format_desc ; + + /* Virtual I/O functions. */ + int virtual_io ; + SF_VIRTUAL_IO vio ; + void *vio_user_data ; + + /* Chunk get/set. */ + SF_CHUNK_ITERATOR *iterator ; + + READ_CHUNKS rchunks ; + WRITE_CHUNKS wchunks ; + + int (*set_chunk) (struct sf_private_tag*, const SF_CHUNK_INFO * chunk_info) ; + SF_CHUNK_ITERATOR * (*next_chunk_iterator) (struct sf_private_tag*, SF_CHUNK_ITERATOR * iterator) ; + int (*get_chunk_size) (struct sf_private_tag*, const SF_CHUNK_ITERATOR * iterator, SF_CHUNK_INFO * chunk_info) ; + int (*get_chunk_data) (struct sf_private_tag*, const SF_CHUNK_ITERATOR * iterator, SF_CHUNK_INFO * chunk_info) ; + + int cpu_flags ; + + ID3V2_HEADER_INFO id3_header ; +} SF_PRIVATE ; + + + +enum +{ SFE_NO_ERROR = SF_ERR_NO_ERROR, + SFE_BAD_OPEN_FORMAT = SF_ERR_UNRECOGNISED_FORMAT, + SFE_SYSTEM = SF_ERR_SYSTEM, + SFE_MALFORMED_FILE = SF_ERR_MALFORMED_FILE, + SFE_UNSUPPORTED_ENCODING = SF_ERR_UNSUPPORTED_ENCODING, + + SFE_ZERO_MAJOR_FORMAT, + SFE_ZERO_MINOR_FORMAT, + SFE_BAD_FILE, + SFE_BAD_FILE_READ, + SFE_OPEN_FAILED, + SFE_BAD_SNDFILE_PTR, + SFE_BAD_SF_INFO_PTR, + SFE_BAD_SF_INCOMPLETE, + SFE_BAD_FILE_PTR, + SFE_BAD_INT_PTR, + SFE_BAD_STAT_SIZE, + SFE_NO_TEMP_DIR, + SFE_MALLOC_FAILED, + SFE_UNIMPLEMENTED, + SFE_BAD_READ_ALIGN, + SFE_BAD_WRITE_ALIGN, + SFE_NOT_READMODE, + SFE_NOT_WRITEMODE, + SFE_BAD_MODE_RW, + SFE_BAD_SF_INFO, + SFE_BAD_OFFSET, + SFE_NO_EMBED_SUPPORT, + SFE_NO_EMBEDDED_RDWR, + SFE_NO_PIPE_WRITE, + + SFE_INTERNAL, + SFE_BAD_COMMAND_PARAM, + SFE_BAD_ENDIAN, + SFE_CHANNEL_COUNT_ZERO, + SFE_CHANNEL_COUNT, + SFE_CHANNEL_COUNT_BAD, + + SFE_BAD_VIRTUAL_IO, + + SFE_INTERLEAVE_MODE, + SFE_INTERLEAVE_SEEK, + SFE_INTERLEAVE_READ, + + SFE_BAD_SEEK, + SFE_NOT_SEEKABLE, + SFE_AMBIGUOUS_SEEK, + SFE_WRONG_SEEK, + SFE_SEEK_FAILED, + + SFE_BAD_OPEN_MODE, + SFE_OPEN_PIPE_RDWR, + SFE_RDWR_POSITION, + SFE_RDWR_BAD_HEADER, + SFE_CMD_HAS_DATA, + SFE_BAD_BROADCAST_INFO_SIZE, + SFE_BAD_BROADCAST_INFO_TOO_BIG, + SFE_BAD_CART_INFO_SIZE, + SFE_BAD_CART_INFO_TOO_BIG, + + SFE_STR_NO_SUPPORT, + SFE_STR_NOT_WRITE, + SFE_STR_MAX_DATA, + SFE_STR_MAX_COUNT, + SFE_STR_BAD_TYPE, + SFE_STR_NO_ADD_END, + SFE_STR_BAD_STRING, + SFE_STR_WEIRD, + + SFE_WAV_NO_RIFF, + SFE_WAV_NO_WAVE, + SFE_WAV_NO_FMT, + SFE_WAV_BAD_FMT, + SFE_WAV_FMT_SHORT, + SFE_WAV_BAD_FACT, + SFE_WAV_BAD_PEAK, + SFE_WAV_PEAK_B4_FMT, + SFE_WAV_BAD_FORMAT, + SFE_WAV_BAD_BLOCKALIGN, + SFE_WAV_NO_DATA, + SFE_WAV_BAD_LIST, + SFE_WAV_ADPCM_NOT4BIT, + SFE_WAV_ADPCM_CHANNELS, + SFE_WAV_ADPCM_SAMPLES, + SFE_WAV_GSM610_FORMAT, + SFE_WAV_UNKNOWN_CHUNK, + SFE_WAV_WVPK_DATA, + SFE_WAV_NMS_FORMAT, + + SFE_AIFF_NO_FORM, + SFE_AIFF_AIFF_NO_FORM, + SFE_AIFF_COMM_NO_FORM, + SFE_AIFF_SSND_NO_COMM, + SFE_AIFF_UNKNOWN_CHUNK, + SFE_AIFF_COMM_CHUNK_SIZE, + SFE_AIFF_BAD_COMM_CHUNK, + SFE_AIFF_PEAK_B4_COMM, + SFE_AIFF_BAD_PEAK, + SFE_AIFF_NO_SSND, + SFE_AIFF_NO_DATA, + SFE_AIFF_RW_SSND_NOT_LAST, + + SFE_AU_UNKNOWN_FORMAT, + SFE_AU_NO_DOTSND, + SFE_AU_EMBED_BAD_LEN, + + SFE_RAW_READ_BAD_SPEC, + SFE_RAW_BAD_BITWIDTH, + SFE_RAW_BAD_FORMAT, + + SFE_PAF_NO_MARKER, + SFE_PAF_VERSION, + SFE_PAF_UNKNOWN_FORMAT, + SFE_PAF_SHORT_HEADER, + SFE_PAF_BAD_CHANNELS, + + SFE_SVX_NO_FORM, + SFE_SVX_NO_BODY, + SFE_SVX_NO_DATA, + SFE_SVX_BAD_COMP, + SFE_SVX_BAD_NAME_LENGTH, + + SFE_NIST_BAD_HEADER, + SFE_NIST_CRLF_CONVERISON, + SFE_NIST_BAD_ENCODING, + + SFE_VOC_NO_CREATIVE, + SFE_VOC_BAD_FORMAT, + SFE_VOC_BAD_VERSION, + SFE_VOC_BAD_MARKER, + SFE_VOC_BAD_SECTIONS, + SFE_VOC_MULTI_SAMPLERATE, + SFE_VOC_MULTI_SECTION, + SFE_VOC_MULTI_PARAM, + SFE_VOC_SECTION_COUNT, + SFE_VOC_NO_PIPE, + + SFE_IRCAM_NO_MARKER, + SFE_IRCAM_BAD_CHANNELS, + SFE_IRCAM_UNKNOWN_FORMAT, + + SFE_W64_64_BIT, + SFE_W64_NO_RIFF, + SFE_W64_NO_WAVE, + SFE_W64_NO_DATA, + SFE_W64_ADPCM_NOT4BIT, + SFE_W64_ADPCM_CHANNELS, + SFE_W64_GSM610_FORMAT, + + SFE_MAT4_BAD_NAME, + SFE_MAT4_NO_SAMPLERATE, + + SFE_MAT5_BAD_ENDIAN, + SFE_MAT5_NO_BLOCK, + SFE_MAT5_SAMPLE_RATE, + + SFE_PVF_NO_PVF1, + SFE_PVF_BAD_HEADER, + SFE_PVF_BAD_BITWIDTH, + + SFE_DWVW_BAD_BITWIDTH, + SFE_G72X_NOT_MONO, + SFE_NMS_ADPCM_NOT_MONO, + + SFE_XI_BAD_HEADER, + SFE_XI_EXCESS_SAMPLES, + SFE_XI_NO_PIPE, + + SFE_HTK_NO_PIPE, + + SFE_SDS_NOT_SDS, + SFE_SDS_BAD_BIT_WIDTH, + + SFE_SD2_FD_DISALLOWED, + SFE_SD2_BAD_DATA_OFFSET, + SFE_SD2_BAD_MAP_OFFSET, + SFE_SD2_BAD_DATA_LENGTH, + SFE_SD2_BAD_MAP_LENGTH, + SFE_SD2_BAD_RSRC, + SFE_SD2_BAD_SAMPLE_SIZE, + + SFE_FLAC_BAD_HEADER, + SFE_FLAC_NEW_DECODER, + SFE_FLAC_INIT_DECODER, + SFE_FLAC_LOST_SYNC, + SFE_FLAC_BAD_SAMPLE_RATE, + SFE_FLAC_CHANNEL_COUNT_CHANGED, + SFE_FLAC_UNKOWN_ERROR, + + SFE_WVE_NOT_WVE, + SFE_WVE_NO_PIPE, + + SFE_VORBIS_ENCODER_BUG, + + SFE_RF64_NOT_RF64, + SFE_RF64_PEAK_B4_FMT, + SFE_RF64_NO_DATA, + + SFE_BAD_CHUNK_PTR, + SFE_UNKNOWN_CHUNK, + SFE_BAD_CHUNK_FORMAT, + SFE_BAD_CHUNK_MARKER, + SFE_BAD_CHUNK_DATA_PTR, + SFE_ALAC_FAIL_TMPFILE, + SFE_FILENAME_TOO_LONG, + SFE_NEGATIVE_RW_LEN, + + SFE_OPUS_BAD_SAMPLERATE, + + SFE_CAF_NOT_CAF, + SFE_CAF_NO_DESC, + SFE_CAF_BAD_PEAK, + + SFE_AVR_NOT_AVR, + SFE_AVR_BAD_REZ_SIGN, + + SFE_MPC_NO_MARKER, + + SFE_MPEG_BAD_SAMPLERATE, + + SFE_MAX_ERROR /* This must be last in list. */ +} ; + +/* Allocate and initialize the SF_PRIVATE struct. */ +SF_PRIVATE * psf_allocate (void) ; + +int subformat_to_bytewidth (int format) ; +int s_bitwidth_to_subformat (int bits) ; +int u_bitwidth_to_subformat (int bits) ; + +/* Functions for reading and writing floats and doubles on processors +** with non-IEEE floats/doubles. +*/ +float float32_be_read (const unsigned char *cptr) ; +float float32_le_read (const unsigned char *cptr) ; +void float32_be_write (float in, unsigned char *out) ; +void float32_le_write (float in, unsigned char *out) ; + +double double64_be_read (const unsigned char *cptr) ; +double double64_le_read (const unsigned char *cptr) ; +void double64_be_write (double in, unsigned char *out) ; +void double64_le_write (double in, unsigned char *out) ; + +/* Functions for writing to the internal logging buffer. */ + +void psf_log_printf (SF_PRIVATE *psf, const char *format, ...) ; +void psf_log_SF_INFO (SF_PRIVATE *psf) ; + +int32_t psf_rand_int32 (void) ; + +void append_snprintf (char * dest, size_t maxlen, const char * fmt, ...) ; +void psf_strlcpy_crlf (char *dest, const char *src, size_t destmax, size_t srcmax) ; + +sf_count_t psf_decode_frame_count (SF_PRIVATE *psf) ; + +/* Functions used when writing file headers. */ + +int psf_binheader_writef (SF_PRIVATE *psf, const char *format, ...) ; +void psf_asciiheader_printf (SF_PRIVATE *psf, const char *format, ...) ; + +/* Functions used when reading file headers. */ + +int psf_binheader_readf (SF_PRIVATE *psf, char const *format, ...) ; + +/* Functions used in the write function for updating the peak chunk. */ + +void peak_update_short (SF_PRIVATE *psf, short *ptr, size_t items) ; +void peak_update_int (SF_PRIVATE *psf, int *ptr, size_t items) ; +void peak_update_double (SF_PRIVATE *psf, double *ptr, size_t items) ; + +/* Functions defined in command.c. */ + +int psf_get_format_simple_count (void) ; +int psf_get_format_simple (SF_FORMAT_INFO *data) ; + +int psf_get_format_info (SF_FORMAT_INFO *data) ; + +int psf_get_format_major_count (void) ; +int psf_get_format_major (SF_FORMAT_INFO *data) ; + +int psf_get_format_subtype_count (void) ; +int psf_get_format_subtype (SF_FORMAT_INFO *data) ; + +void psf_generate_format_desc (SF_PRIVATE *psf) ; + +double psf_calc_signal_max (SF_PRIVATE *psf, int normalize) ; +int psf_calc_max_all_channels (SF_PRIVATE *psf, double *peaks, int normalize) ; + +int psf_get_signal_max (SF_PRIVATE *psf, double *peak) ; +int psf_get_max_all_channels (SF_PRIVATE *psf, double *peaks) ; + +/* Functions in strings.c. */ + +const char* psf_get_string (SF_PRIVATE *psf, int str_type) ; +int psf_set_string (SF_PRIVATE *psf, int str_type, const char *str) ; +int psf_store_string (SF_PRIVATE *psf, int str_type, const char *str) ; +int psf_location_string_count (const SF_PRIVATE * psf, int location) ; + +/* Default seek function. Use for PCM and float encoded data. */ +sf_count_t psf_default_seek (SF_PRIVATE *psf, int mode, sf_count_t samples_from_start) ; + +int macos_guess_file_type (SF_PRIVATE *psf, const char *filename) ; + +/*------------------------------------------------------------------------------------ +** File I/O functions which will allow access to large files (> 2 Gig) on +** some 32 bit OSes. Implementation in file_io.c. +*/ + +int psf_fopen (SF_PRIVATE *psf) ; +int psf_set_stdio (SF_PRIVATE *psf) ; +int psf_file_valid (SF_PRIVATE *psf) ; +void psf_set_file (SF_PRIVATE *psf, int fd) ; +void psf_init_files (SF_PRIVATE *psf) ; +void psf_use_rsrc (SF_PRIVATE *psf, int on_off) ; + +SNDFILE * psf_open_file (SF_PRIVATE *psf, SF_INFO *sfinfo) ; + +sf_count_t psf_fseek (SF_PRIVATE *psf, sf_count_t offset, int whence) ; +sf_count_t psf_fread (void *ptr, sf_count_t bytes, sf_count_t count, SF_PRIVATE *psf) ; +sf_count_t psf_fwrite (const void *ptr, sf_count_t bytes, sf_count_t count, SF_PRIVATE *psf) ; +sf_count_t psf_fgets (char *buffer, sf_count_t bufsize, SF_PRIVATE *psf) ; +sf_count_t psf_ftell (SF_PRIVATE *psf) ; +sf_count_t psf_get_filelen (SF_PRIVATE *psf) ; + +void psf_fsync (SF_PRIVATE *psf) ; + +int psf_is_pipe (SF_PRIVATE *psf) ; + +int psf_ftruncate (SF_PRIVATE *psf, sf_count_t len) ; +int psf_fclose (SF_PRIVATE *psf) ; + +/* Open and close the resource fork of a file. */ +int psf_open_rsrc (SF_PRIVATE *psf) ; +int psf_close_rsrc (SF_PRIVATE *psf) ; + +int psf_copy_filename (SF_PRIVATE *psf, const char *path) ; + +/* +void psf_fclearerr (SF_PRIVATE *psf) ; +int psf_ferror (SF_PRIVATE *psf) ; +*/ + +/*------------------------------------------------------------------------------------ +** Functions for reading and writing different file formats. +*/ + +int aiff_open (SF_PRIVATE *psf) ; +int au_open (SF_PRIVATE *psf) ; +int avr_open (SF_PRIVATE *psf) ; +int htk_open (SF_PRIVATE *psf) ; +int ircam_open (SF_PRIVATE *psf) ; +int mat4_open (SF_PRIVATE *psf) ; +int mat5_open (SF_PRIVATE *psf) ; +int nist_open (SF_PRIVATE *psf) ; +int paf_open (SF_PRIVATE *psf) ; +int pvf_open (SF_PRIVATE *psf) ; +int raw_open (SF_PRIVATE *psf) ; +int sd2_open (SF_PRIVATE *psf) ; +int sds_open (SF_PRIVATE *psf) ; +int svx_open (SF_PRIVATE *psf) ; +int voc_open (SF_PRIVATE *psf) ; +int w64_open (SF_PRIVATE *psf) ; +int wav_open (SF_PRIVATE *psf) ; +int xi_open (SF_PRIVATE *psf) ; +int flac_open (SF_PRIVATE *psf) ; +int caf_open (SF_PRIVATE *psf) ; +int mpc2k_open (SF_PRIVATE *psf) ; +int rf64_open (SF_PRIVATE *psf) ; + +int ogg_vorbis_open (SF_PRIVATE *psf) ; +int ogg_speex_open (SF_PRIVATE *psf) ; +int ogg_pcm_open (SF_PRIVATE *psf) ; +int ogg_opus_open (SF_PRIVATE *psf) ; +int ogg_open (SF_PRIVATE *psf) ; + +int mpeg_open (SF_PRIVATE *psf) ; + +/* In progress. Do not currently work. */ + +int rx2_open (SF_PRIVATE *psf) ; +int txw_open (SF_PRIVATE *psf) ; +int wve_open (SF_PRIVATE *psf) ; +int dwd_open (SF_PRIVATE *psf) ; + +/*------------------------------------------------------------------------------------ +** Init functions for a number of common data encodings. +*/ + +int pcm_init (SF_PRIVATE *psf) ; +int ulaw_init (SF_PRIVATE *psf) ; +int alaw_init (SF_PRIVATE *psf) ; +int float32_init (SF_PRIVATE *psf) ; +int double64_init (SF_PRIVATE *psf) ; +int dwvw_init (SF_PRIVATE *psf, int bitwidth) ; +int gsm610_init (SF_PRIVATE *psf) ; +int nms_adpcm_init (SF_PRIVATE *psf) ; +int vox_adpcm_init (SF_PRIVATE *psf) ; +int flac_init (SF_PRIVATE *psf) ; +int g72x_init (SF_PRIVATE * psf) ; +int alac_init (SF_PRIVATE *psf, const ALAC_DECODER_INFO * info) ; +int mpeg_init (SF_PRIVATE *psf, int bitrate_mode, int write_metadata) ; + +int dither_init (SF_PRIVATE *psf, int mode) ; + +int wavlike_ima_init (SF_PRIVATE *psf, int blockalign, int samplesperblock) ; +int wavlike_msadpcm_init (SF_PRIVATE *psf, int blockalign, int samplesperblock) ; + +int aiff_ima_init (SF_PRIVATE *psf, int blockalign, int samplesperblock) ; + +int interleave_init (SF_PRIVATE *psf) ; + +/*------------------------------------------------------------------------------------ +** Chunk logging functions. +*/ + +SF_CHUNK_ITERATOR * psf_get_chunk_iterator (SF_PRIVATE * psf, const char * marker_str) ; +SF_CHUNK_ITERATOR * psf_next_chunk_iterator (const READ_CHUNKS * pchk , SF_CHUNK_ITERATOR *iterator) ; +int psf_store_read_chunk_u32 (READ_CHUNKS * pchk, uint32_t marker, sf_count_t offset, uint32_t len) ; +int psf_store_read_chunk_str (READ_CHUNKS * pchk, const char * marker, sf_count_t offset, uint32_t len) ; +int psf_save_write_chunk (WRITE_CHUNKS * pchk, const SF_CHUNK_INFO * chunk_info) ; +int psf_find_read_chunk_str (const READ_CHUNKS * pchk, const char * marker) ; +int psf_find_read_chunk_m32 (const READ_CHUNKS * pchk, uint32_t marker) ; +int psf_find_read_chunk_iterator (const READ_CHUNKS * pchk, const SF_CHUNK_ITERATOR * marker) ; + +int psf_find_write_chunk (WRITE_CHUNKS * pchk, const char * marker) ; + +/*------------------------------------------------------------------------------------ +** Functions that work like OpenBSD's strlcpy/strlcat to replace strncpy/strncat. +** +** See : http://www.gratisoft.us/todd/papers/strlcpy.html +** +** These functions are available on *BSD, but are not avaialble everywhere so we +** implement them here. +** +** The argument order has been changed to that of strncpy/strncat to cause +** compiler errors if code is carelessly converted from one to the other. +*/ + +void psf_strlcat (char *dest, size_t n, const char *src) ; +void psf_strlcpy (char *dest, size_t n, const char *src) ; + +/*------------------------------------------------------------------------------------ +** SIMD optimized math functions. +*/ + +static inline int psf_lrintf (float x) +{ + #ifdef USE_SSE2 + return _mm_cvtss_si32 (_mm_load_ss (&x)) ; + #else + return lrintf (x) ; + #endif +} /* psf_lrintf */ + +static inline int psf_lrint (double x) +{ + #ifdef USE_SSE2 + return _mm_cvtsd_si32 (_mm_load_sd (&x)) ; + #else + return lrint (x) ; + #endif +} /* psf_lrintf */ + +/*------------------------------------------------------------------------------------ +** Other helper functions. +*/ + +void *psf_memset (void *s, int c, sf_count_t n) ; + +SF_CUES * psf_cues_dup (const void * ptr, size_t datasize) ; +SF_CUES * psf_cues_alloc (uint32_t cue_count) ; +void psf_get_cues (SF_PRIVATE * psf, void * data, size_t datasize) ; + +SF_INSTRUMENT * psf_instrument_alloc (void) ; + +void psf_sanitize_string (char * cptr, int len) ; + +/* Generate the current date as a string. */ +void psf_get_date_str (char *str, int maxlen) ; + +SF_BROADCAST_INFO_16K * broadcast_var_alloc (void) ; +int broadcast_var_set (SF_PRIVATE *psf, const SF_BROADCAST_INFO * data, size_t datasize) ; +int broadcast_var_get (SF_PRIVATE *psf, SF_BROADCAST_INFO * data, size_t datasize) ; + + +SF_CART_INFO_16K * cart_var_alloc (void) ; +int cart_var_set (SF_PRIVATE *psf, const SF_CART_INFO * date, size_t datasize) ; +int cart_var_get (SF_PRIVATE *psf, SF_CART_INFO * data, size_t datasize) ; + +typedef struct +{ int channels ; + int endianness ; +} AUDIO_DETECT ; + +int audio_detect (SF_PRIVATE * psf, AUDIO_DETECT *ad, const unsigned char * data, int datalen) ; +int id3_skip (SF_PRIVATE * psf) ; +const char *id3_lookup_v1_genre (int number) ; + +void alac_get_desc_chunk_items (int subformat, uint32_t *fmt_flags, uint32_t *frames_per_packet) ; + +FILE * psf_open_tmpfile (char * fname, size_t fnamelen) ; + +/*------------------------------------------------------------------------------------ +** Helper/debug functions. +*/ + +void psf_hexdump (const void *ptr, int len) ; + +const char * str_of_major_format (int format) ; +const char * str_of_minor_format (int format) ; +const char * str_of_open_mode (int mode) ; +const char * str_of_endianness (int end) ; + +/*------------------------------------------------------------------------------------ +** Extra commands for sf_command(). Not for public use yet. +*/ + +enum +{ SFC_TEST_AIFF_ADD_INST_CHUNK = 0x2000, + SFC_TEST_WAV_ADD_INFO_CHUNK = 0x2010 +} ; + +/* +** Maybe, one day, make these functions or something like them, public. +** +** Buffer to buffer dithering. Pointer in and out are allowed to point +** to the same buffer for in-place dithering. +*/ + +#if 0 +int sf_dither_short (const SF_DITHER_INFO *dither, const short *in, short *out, int count) ; +int sf_dither_int (const SF_DITHER_INFO *dither, const int *in, int *out, int count) ; +int sf_dither_float (const SF_DITHER_INFO *dither, const float *in, float *out, int count) ; +int sf_dither_double (const SF_DITHER_INFO *dither, const double *in, double *out, int count) ; +#endif + +/*------------------------------------------------------------------------------------ +** Data conversion functions. +*/ + +void psf_f2s_array (const float *src, short *dest, int count, int normalize) ; +void psf_f2s_clip_array (const float *src, short *dest, int count, int normalize) ; + +void psf_d2s_array (const double *src, short *dest, int count, int normalize) ; +void psf_d2s_clip_array (const double *src, short *dest, int count, int normalize) ; + +void psf_f2i_array (const float *src, int *dest, int count, int normalize) ; +void psf_f2i_clip_array (const float *src, int *dest, int count, int normalize) ; + +void psf_d2i_array (const double *src, int *dest, int count, int normalize) ; +void psf_d2i_clip_array (const double *src, int *dest, int count, int normalize) ; + + +/*------------------------------------------------------------------------------------ +** Left and right shift on int. According to the C standard, the left and right +** shift operations applied to a negative integer results in undefined behavior. +** These twp functions work around that. +*/ + +#if __GNUC__ +#define ALWAYS_INLINE __attribute__ ((always_inline)) +#else +#define ALWAYS_INLINE +#endif + +static inline int32_t ALWAYS_INLINE +arith_shift_left (int32_t x, int shift) +{ return (int32_t) (((uint32_t) x) << shift) ; +} /* arith_shift_left */ + +static inline int32_t ALWAYS_INLINE +arith_shift_right (int32_t x, int shift) +{ if (x >= 0) + return x >> shift ; + return ~ ((~x) >> shift) ; +} /* arith_shift_right */ + +#endif /* SNDFILE_COMMON_H */ diff --git a/extern/libsndfile-modified/src/config.h.cmake b/extern/libsndfile-modified/src/config.h.cmake new file mode 100644 index 000000000..e8d81453d --- /dev/null +++ b/extern/libsndfile-modified/src/config.h.cmake @@ -0,0 +1,315 @@ +/* Set to 1 if the compile is GNU GCC. */ +#cmakedefine01 COMPILER_IS_GCC + +/* Target processor clips on negative float to int conversion. */ +#cmakedefine01 CPU_CLIPS_NEGATIVE + +/* Target processor clips on positive float to int conversion. */ +#cmakedefine01 CPU_CLIPS_POSITIVE + +/* Target processor is big endian. */ +#cmakedefine01 CPU_IS_BIG_ENDIAN + +/* Target processor is little endian. */ +#cmakedefine01 CPU_IS_LITTLE_ENDIAN + +/* Set to 1 to enable experimental code. */ +#cmakedefine01 ENABLE_EXPERIMENTAL_CODE + +/* Define to 1 if you have the header file. */ +#cmakedefine01 HAVE_ALSA_ASOUNDLIB_H + +/* Define to 1 if you have the header file. */ +#cmakedefine01 HAVE_BYTESWAP_H + +/* Define to 1 if you have the `calloc' function. */ +#cmakedefine01 HAVE_CALLOC + +/* Define to 1 if you have the `ceil' function. */ +#cmakedefine01 HAVE_CEIL + +/* Set to 1 if S_IRGRP is defined. */ +#cmakedefine01 HAVE_DECL_S_IRGRP + +/* Define to 1 if you have the header file. */ +#cmakedefine01 HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_DIRECT_H + +/* Define to 1 if you have the header file. */ +#cmakedefine01 HAVE_ENDIAN_H + +/* Will be set to 1 if flac, ogg and vorbis are available. */ +#cmakedefine01 HAVE_EXTERNAL_XIPH_LIBS + +/* Will be set to 1 if lame and mpg123 are available. */ +#cmakedefine01 HAVE_MPEG + +/* Define to 1 if you have the `floor' function. */ +#cmakedefine01 HAVE_FLOOR + +/* Define to 1 if you have the `fmod' function. */ +#cmakedefine01 HAVE_FMOD + +/* Define to 1 if you have the `free' function. */ +#cmakedefine01 HAVE_FREE + +/* Define to 1 if you have the `fstat' function. */ +#cmakedefine01 HAVE_FSTAT + +/* Define to 1 if you have the `fstat64' function. */ +#cmakedefine01 HAVE_FSTAT64 + +/* Define to 1 if you have the `fsync' function. */ +#cmakedefine01 HAVE_FSYNC + +/* Define to 1 if you have the `ftruncate' function. */ +#cmakedefine01 HAVE_FTRUNCATE + +/* Define to 1 if you have the `getpagesize' function. */ +#cmakedefine01 HAVE_GETPAGESIZE + +/* Define to 1 if you have the `gettimeofday' function. */ +#cmakedefine01 HAVE_GETTIMEOFDAY + +/* Define if you have the `gmtime' function. */ +#cmakedefine HAVE_GMTIME + +/* Define if you have the `gmtime_r' function. */ +#cmakedefine HAVE_GMTIME_R + +/* Define to 1 if you have the header file. */ +#cmakedefine01 HAVE_INTTYPES_H + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_IO_H + +/* Define to 1 if you have the `m' library (-lm). */ +#cmakedefine01 HAVE_LIBM + +/* Define to 1 if you have the header file. */ +#cmakedefine01 HAVE_LOCALE_H + +/* Define if you have the `localtime' function. */ +#cmakedefine HAVE_LOCALTIME + +/* Define if you have the `localtime_r' function. */ +#cmakedefine HAVE_LOCALTIME_R + +/* Define if you have C99's lrint function. */ +#cmakedefine01 HAVE_LRINT + +/* Define if you have C99's lrintf function. */ +#cmakedefine01 HAVE_LRINTF + +/* Define to 1 if you have the `lround' function. */ +#cmakedefine01 HAVE_LROUND + +/* Define to 1 if you have the `lseek' function. */ +#cmakedefine01 HAVE_LSEEK + +/* Define to 1 if you have the `lseek64' function. */ +#cmakedefine01 HAVE_LSEEK64 + +/* Define to 1 if you have the `malloc' function. */ +#cmakedefine01 HAVE_MALLOC + +/* Define to 1 if you have the header file. */ +#cmakedefine01 HAVE_MEMORY_H + +/* Define to 1 if you have the `mmap' function. */ +#cmakedefine01 HAVE_MMAP + +/* Define to 1 if you have the `open' function. */ +#cmakedefine01 HAVE_OPEN + +/* Define to 1 if you have the `pipe' function. */ +#cmakedefine01 HAVE_PIPE + +/* Define to 1 if you have the `read' function. */ +#cmakedefine01 HAVE_READ + +/* Define to 1 if you have the `realloc' function. */ +#cmakedefine01 HAVE_REALLOC + +/* Define to 1 if you have the `setlocale' function. */ +#cmakedefine01 HAVE_SETLOCALE + +/* Set to 1 if is available. */ +#cmakedefine01 HAVE_SNDIO_H + +/* Define to 1 if you have the `snprintf' function. */ +#cmakedefine01 HAVE_SNPRINTF + +/* Set to 1 if you have libsqlite3. */ +#cmakedefine01 HAVE_SQLITE3 + +/* Define to 1 if the system has the type `ssize_t'. */ +#cmakedefine01 HAVE_SSIZE_T + +#if (HAVE_SSIZE_T == 0) +#define ssize_t intptr_t +#endif + +/* Define to 1 if you have the header file. */ +#cmakedefine01 HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#cmakedefine01 HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#cmakedefine01 HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#cmakedefine01 HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#cmakedefine01 HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#cmakedefine01 HAVE_SYS_TIME_H + +/* Define to 1 if you have the header file. */ +#cmakedefine01 HAVE_SYS_TYPES_H + +/* Define to 1 if you have that is POSIX.1 compatible. */ +#cmakedefine01 HAVE_SYS_WAIT_H + +/* Define to 1 if you have the header file. */ +#cmakedefine01 HAVE_UNISTD_H + +/* Define to 1 if you have the header file. */ +#cmakedefine01 HAVE_IMMINTRIN_H + +/* Define to 1 if you have the header file. */ +#cmakedefine01 HAVE_STDBOOL_H + +/* Define to 1 if you have the `vsnprintf' function. */ +#cmakedefine01 HAVE_VSNPRINTF + +/* Define to 1 if you have the `waitpid' function. */ +#cmakedefine01 HAVE_WAITPID + +/* Define to 1 if you have the `write' function. */ +#cmakedefine01 HAVE_WRITE + +/* The darwin version, no-zero is valid */ +#cmakedefine01 OSX_DARWIN_VERSION + +/* Set to 1 if compiling for OpenBSD */ +#cmakedefine01 OS_IS_OPENBSD + +/* Set to 1 if compiling for Win32 */ +#cmakedefine01 OS_IS_WIN32 + +/* Set to 1 if SSE2 is enabled */ +#cmakedefine USE_SSE2 + +/* Name of package */ +#define PACKAGE "@PACKAGE_NAME@" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "@PACKAGE_BUGREPORT@" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "@PACKAGE_NAME@" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "@PACKAGE_NAME@ @CPACK_PACKAGE_VERSION_FULL@" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "@PACKAGE_NAME@" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "@PACKAGE_URL@" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "@CPACK_PACKAGE_VERSION_FULL@" + +/* The size of `double', as computed by sizeof. */ +@SIZEOF_DOUBLE_CODE@ + +/* The size of `float', as computed by sizeof. */ +@SIZEOF_FLOAT_CODE@ + +/* The size of `int', as computed by sizeof. */ +@SIZEOF_INT_CODE@ + +/* The size of `int64_t', as computed by sizeof. */ +@SIZEOF_INT64_T_CODE@ + +/* The size of `loff_t', as computed by sizeof. */ +@SIZEOF_LOFF_T_CODE@ + +/* The size of `long', as computed by sizeof. */ +@SIZEOF_LONG_CODE@ + +/* The size of `long long', as computed by sizeof. */ +@SIZEOF_LONG_LONG_CODE@ + +/* The size of `off64_t', as computed by sizeof. */ +@SIZEOF_OFF64_T_CODE@ + +/* The size of `off_t', as computed by sizeof. */ +@SIZEOF_OFF_T_CODE@ + +/* The size of `short', as computed by sizeof. */ +@SIZEOF_SHORT_CODE@ + +/* The size of `size_t', as computed by sizeof. */ +@SIZEOF_SIZE_T_CODE@ + +/* The size of `ssize_t', as computed by sizeof. */ +@SIZEOF_SSIZE_T_CODE@ + +/* The size of `void*', as computed by sizeof. */ +@SIZEOF_VOIDP_CODE@ + +/* The size of `wchar_t', as computed by sizeof. */ +@SIZEOF_WCHAR_T_CODE@ + +/* Enable extensions on AIX 3, Interix. */ +#ifndef _ALL_SOURCE +# undef _ALL_SOURCE +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# undef _GNU_SOURCE +#endif +/* Enable threading extensions on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# undef _POSIX_PTHREAD_SEMANTICS +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# undef _TANDEM_SOURCE +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# undef __EXTENSIONS__ +#endif + + +/* Set to 1 to use the native windows API */ +#cmakedefine01 USE_WINDOWS_API + +/* Version number of package */ +#define VERSION "@PROJECT_VERSION@" + +/* Set to 1 if windows DLL is being built. */ +#cmakedefine01 WIN32_TARGET_DLL + +/* Target processor is big endian. */ +#cmakedefine01 WORDS_BIGENDIAN + +/* Enable large inode numbers on Mac OS X 10.5. */ +#ifndef _DARWIN_USE_64_BIT_INODE +# define _DARWIN_USE_64_BIT_INODE 1 +#endif + +/* Define to 1 if on MINIX. */ +#cmakedefine01 _MINIX + +/* Define as `__inline' or '__inline__' if that's what the C compiler calls it, or to nothing if it is not supported. */ +@INLINE_CODE@ diff --git a/extern/libsndfile-modified/src/create_symbols_file.py b/extern/libsndfile-modified/src/create_symbols_file.py new file mode 100644 index 000000000..c0debce1d --- /dev/null +++ b/extern/libsndfile-modified/src/create_symbols_file.py @@ -0,0 +1,181 @@ +#!/usr/bin/python + +# Copyright (C) 2003-2017 Erik de Castro Lopo +# +# All rights reserved. +# +# 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 author nor the names of any 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 COPYRIGHT OWNER 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. + +import re, sys + +#---------------------------------------------------------------- +# These are all of the public functions exported from libsndfile. +# +# Its important not to change the order they are listed in or +# the ordinal values in the second column. + +ALL_SYMBOLS = ( + ( "sf_command", 1 ), + ( "sf_open", 2 ), + ( "sf_close", 3 ), + ( "sf_seek", 4 ), + ( "sf_error", 7 ), + ( "sf_perror", 8 ), + ( "sf_error_str", 9 ), + ( "sf_error_number", 10 ), + ( "sf_format_check", 11 ), + ( "sf_read_raw", 16 ), + ( "sf_readf_short", 17 ), + ( "sf_readf_int", 18 ), + ( "sf_readf_float", 19 ), + ( "sf_readf_double", 20 ), + ( "sf_read_short", 21 ), + ( "sf_read_int", 22 ), + ( "sf_read_float", 23 ), + ( "sf_read_double", 24 ), + ( "sf_write_raw", 32 ), + ( "sf_writef_short", 33 ), + ( "sf_writef_int", 34 ), + ( "sf_writef_float", 35 ), + ( "sf_writef_double", 36 ), + ( "sf_write_short", 37 ), + ( "sf_write_int", 38 ), + ( "sf_write_float", 39 ), + ( "sf_write_double", 40 ), + ( "sf_strerror", 50 ), + ( "sf_get_string", 60 ), + ( "sf_set_string", 61 ), + ( "sf_version_string", 68 ), + ( "sf_open_fd", 70 ), + ( "sf_wchar_open", 71 ), + ( "sf_open_virtual", 80 ), + ( "sf_write_sync", 90 ), + ( "sf_set_chunk", 100 ), + ( "sf_get_chunk_size", 101 ), + ( "sf_get_chunk_data", 102 ), + ( "sf_get_chunk_iterator", 103 ), + ( "sf_next_chunk_iterator", 104 ), + ( "sf_current_byterate", 110 ) + ) + +#------------------------------------------------------------------------------- + +def linux_symbols (progname, version): + print ("# Auto-generated by %s\n" %progname) + print ("libsndfile.so.%s" % version) + print ("{") + print (" global:") + for name, ordinal in ALL_SYMBOLS: + if name == "sf_wchar_open": + continue + print (" %s ;" % name) + print (" local:") + print (" * ;") + print ("} ;") + sys.stdout.write ("\n") + return + +def darwin_symbols (progname, version): + print ("# Auto-generated by %s\n" %progname) + for name, ordinal in ALL_SYMBOLS: + if name == "sf_wchar_open": + continue + print ("_%s" % name) + sys.stdout.write ("\n") + return + +def win32_symbols (progname, version, name): + print ("; Auto-generated by %s\n" %progname) + print ("EXPORTS\n") + for name, ordinal in ALL_SYMBOLS: + print ("%-20s @%s" % (name, ordinal)) + sys.stdout.write ("\n") + return + +def os2_symbols (progname, version, name): + print ("; Auto-generated by %s\n" %progname) + print ("LIBRARY %s%s" % (name, re.sub (r"\..*", "", version))) + print ("INITINSTANCE TERMINSTANCE") + print ("CODE PRELOAD MOVEABLE DISCARDABLE") + print ("DATA PRELOAD MOVEABLE MULTIPLE NONSHARED") + print ("EXPORTS\n") + for name, ordinal in ALL_SYMBOLS: + if name == "sf_wchar_open": + continue + print ("_%-20s @%s" % (name, ordinal)) + sys.stdout.write ("\n") + return + +def plain_symbols (progname, version, name): + for name, ordinal in ALL_SYMBOLS: + print (name) + +def no_symbols (os_name): + sys.stdout.write ("\n") + print ("No known way of restricting exported symbols on '%s'." % os_name) + print ("If you know a way, please contact the author.") + sys.stdout.write ("\n") + return + +#------------------------------------------------------------------------------- + +progname = re.sub (".*[\\/]", "", sys.argv [0]) + +if len (sys.argv) != 3: + sys.stdout.write ("\n") + print ("Usage : %s ." % progname) + sys.stdout.write ("\n") + print (" Currently supported values for target OS are:") + print (" linux") + print (" darwin (ie MacOSX)") + print (" win32 (ie wintendo)") + print (" cygwin (Cygwin on wintendo)") + print (" os2 (OS/2)") + print (" plain (plain list of symbols)") + sys.stdout.write ("\n") + sys.exit (1) + +os_name = sys.argv [1] +version = re.sub (r"\.[a-z0-9]+$", "", sys.argv [2]) + +if os_name == "linux" or os_name == "gnu" or os_name == "binutils": + linux_symbols (progname, version) +elif os_name == "darwin": + darwin_symbols (progname, version) +elif os_name == "win32": + win32_symbols (progname, version, "libsndfile") +elif os_name == "cygwin": + win32_symbols (progname, version, "cygsndfile") +elif os_name == "os2": + os2_symbols (progname, version, "sndfile") +elif os_name == "static": + plain_symbols (progname, version, "") +else: + no_symbols (os_name) + +sys.exit (0) + diff --git a/extern/libsndfile-modified/src/dither.c b/extern/libsndfile-modified/src/dither.c new file mode 100644 index 000000000..b0ef7311a --- /dev/null +++ b/extern/libsndfile-modified/src/dither.c @@ -0,0 +1,534 @@ +/* +** Copyright (C) 2003-2011 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + +/*============================================================================ +** Rule number 1 is to only apply dither when going from a larger bitwidth +** to a smaller bitwidth. This can happen on both read and write. +** +** Need to apply dither on all conversions marked X below. +** +** Dither on write: +** +** Input +** | short int float double +** --------+----------------------------------------------- +** O 8 bit | X X X X +** u 16 bit | none X X X +** t 24 bit | none X X X +** p 32 bit | none none X X +** u float | none none none none +** t double | none none none none +** +** Dither on read: +** +** Input +** O | 8 bit 16 bit 24 bit 32 bit float double +** u --------+------------------------------------------------- +** t short | none none X X X X +** p int | none none none X X X +** u float | none none none none none none +** t double | none none none none none none +*/ + +#define SFE_DITHER_BAD_PTR 666 +#define SFE_DITHER_BAD_TYPE 667 + +typedef struct +{ int read_short_dither_bits, read_int_dither_bits ; + int write_short_dither_bits, write_int_dither_bits ; + double read_float_dither_scale, read_double_dither_bits ; + double write_float_dither_scale, write_double_dither_bits ; + + sf_count_t (*read_short) (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; + sf_count_t (*read_int) (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; + sf_count_t (*read_float) (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; + sf_count_t (*read_double) (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; + + sf_count_t (*write_short) (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; + sf_count_t (*write_int) (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; + sf_count_t (*write_float) (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; + sf_count_t (*write_double) (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; + + double buffer [SF_BUFFER_LEN / sizeof (double)] ; +} DITHER_DATA ; + +static sf_count_t dither_read_short (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; +static sf_count_t dither_read_int (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; + +static sf_count_t dither_write_short (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; +static sf_count_t dither_write_int (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; +static sf_count_t dither_write_float (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; +static sf_count_t dither_write_double (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; + +int +dither_init (SF_PRIVATE *psf, int mode) +{ DITHER_DATA *pdither ; + + pdither = psf->dither ; /* This may be NULL. */ + + /* Turn off dither on read. */ + if (mode == SFM_READ && psf->read_dither.type == SFD_NO_DITHER) + { if (pdither == NULL) + return 0 ; /* Dither is already off, so just return. */ + + if (pdither->read_short) + psf->read_short = pdither->read_short ; + if (pdither->read_int) + psf->read_int = pdither->read_int ; + if (pdither->read_float) + psf->read_float = pdither->read_float ; + if (pdither->read_double) + psf->read_double = pdither->read_double ; + return 0 ; + } ; + + /* Turn off dither on write. */ + if (mode == SFM_WRITE && psf->write_dither.type == SFD_NO_DITHER) + { if (pdither == NULL) + return 0 ; /* Dither is already off, so just return. */ + + if (pdither->write_short) + psf->write_short = pdither->write_short ; + if (pdither->write_int) + psf->write_int = pdither->write_int ; + if (pdither->write_float) + psf->write_float = pdither->write_float ; + if (pdither->write_double) + psf->write_double = pdither->write_double ; + return 0 ; + } ; + + /* Turn on dither on read if asked. */ + if (mode == SFM_READ && psf->read_dither.type != 0) + { if (pdither == NULL) + pdither = psf->dither = calloc (1, sizeof (DITHER_DATA)) ; + if (pdither == NULL) + return SFE_MALLOC_FAILED ; + + switch (SF_CODEC (psf->sf.format)) + { case SF_FORMAT_DOUBLE : + case SF_FORMAT_FLOAT : + pdither->read_int = psf->read_int ; + psf->read_int = dither_read_int ; + break ; + + case SF_FORMAT_PCM_32 : + case SF_FORMAT_PCM_24 : + case SF_FORMAT_PCM_16 : + case SF_FORMAT_PCM_S8 : + case SF_FORMAT_PCM_U8 : + pdither->read_short = psf->read_short ; + psf->read_short = dither_read_short ; + break ; + + default : break ; + } ; + } ; + + /* Turn on dither on write if asked. */ + if (mode == SFM_WRITE && psf->write_dither.type != 0) + { if (pdither == NULL) + pdither = psf->dither = calloc (1, sizeof (DITHER_DATA)) ; + if (pdither == NULL) + return SFE_MALLOC_FAILED ; + + switch (SF_CODEC (psf->sf.format)) + { case SF_FORMAT_DOUBLE : + case SF_FORMAT_FLOAT : + pdither->write_int = psf->write_int ; + psf->write_int = dither_write_int ; + break ; + + case SF_FORMAT_PCM_32 : + case SF_FORMAT_PCM_24 : + case SF_FORMAT_PCM_16 : + case SF_FORMAT_PCM_S8 : + case SF_FORMAT_PCM_U8 : + break ; + + default : break ; + } ; + + pdither->write_short = psf->write_short ; + psf->write_short = dither_write_short ; + + pdither->write_int = psf->write_int ; + psf->write_int = dither_write_int ; + + pdither->write_float = psf->write_float ; + psf->write_float = dither_write_float ; + + pdither->write_double = psf->write_double ; + psf->write_double = dither_write_double ; + } ; + + return 0 ; +} /* dither_init */ + +/*============================================================================== +*/ + +static void dither_short (const short *in, short *out, int frames, int channels) ; +static void dither_int (const int *in, int *out, int frames, int channels) ; + +static void dither_float (const float *in, float *out, int frames, int channels) ; +static void dither_double (const double *in, double *out, int frames, int channels) ; + +static sf_count_t +dither_read_short (SF_PRIVATE * UNUSED (psf), short * UNUSED (ptr), sf_count_t len) +{ + return len ; +} /* dither_read_short */ + +static sf_count_t +dither_read_int (SF_PRIVATE * UNUSED (psf), int * UNUSED (ptr), sf_count_t len) +{ + return len ; +} /* dither_read_int */ + +/*------------------------------------------------------------------------------ +*/ + +static sf_count_t +dither_write_short (SF_PRIVATE *psf, const short *ptr, sf_count_t len) +{ DITHER_DATA *pdither ; + int bufferlen, writecount, thiswrite ; + sf_count_t total = 0 ; + + if ((pdither = psf->dither) == NULL) + { psf->error = SFE_DITHER_BAD_PTR ; + return 0 ; + } ; + + switch (SF_CODEC (psf->sf.format)) + { case SF_FORMAT_PCM_S8 : + case SF_FORMAT_PCM_U8 : + case SF_FORMAT_DPCM_8 : + break ; + + default : + return pdither->write_short (psf, ptr, len) ; + } ; + + bufferlen = sizeof (pdither->buffer) / (sizeof (short)) ; + + while (len > 0) + { writecount = (len >= bufferlen) ? bufferlen : (int) len ; + writecount /= psf->sf.channels ; + writecount *= psf->sf.channels ; + + dither_short (ptr, (short*) pdither->buffer, writecount / psf->sf.channels, psf->sf.channels) ; + + thiswrite = (int) pdither->write_short (psf, (short*) pdither->buffer, writecount) ; + total += thiswrite ; + len -= thiswrite ; + if (thiswrite < writecount) + break ; + } ; + + return total ; +} /* dither_write_short */ + +static sf_count_t +dither_write_int (SF_PRIVATE *psf, const int *ptr, sf_count_t len) +{ DITHER_DATA *pdither ; + int bufferlen, writecount, thiswrite ; + sf_count_t total = 0 ; + + if ((pdither = psf->dither) == NULL) + { psf->error = SFE_DITHER_BAD_PTR ; + return 0 ; + } ; + + switch (SF_CODEC (psf->sf.format)) + { case SF_FORMAT_PCM_S8 : + case SF_FORMAT_PCM_U8 : + case SF_FORMAT_PCM_16 : + case SF_FORMAT_PCM_24 : + break ; + + case SF_FORMAT_DPCM_8 : + case SF_FORMAT_DPCM_16 : + break ; + + default : + return pdither->write_int (psf, ptr, len) ; + } ; + + + bufferlen = sizeof (pdither->buffer) / (sizeof (int)) ; + + while (len > 0) + { writecount = (len >= bufferlen) ? bufferlen : (int) len ; + writecount /= psf->sf.channels ; + writecount *= psf->sf.channels ; + + dither_int (ptr, (int*) pdither->buffer, writecount / psf->sf.channels, psf->sf.channels) ; + + thiswrite = (int) pdither->write_int (psf, (int*) pdither->buffer, writecount) ; + total += thiswrite ; + len -= thiswrite ; + if (thiswrite < writecount) + break ; + } ; + + return total ; +} /* dither_write_int */ + +static sf_count_t +dither_write_float (SF_PRIVATE *psf, const float *ptr, sf_count_t len) +{ DITHER_DATA *pdither ; + int bufferlen, writecount, thiswrite ; + sf_count_t total = 0 ; + + if ((pdither = psf->dither) == NULL) + { psf->error = SFE_DITHER_BAD_PTR ; + return 0 ; + } ; + + switch (SF_CODEC (psf->sf.format)) + { case SF_FORMAT_PCM_S8 : + case SF_FORMAT_PCM_U8 : + case SF_FORMAT_PCM_16 : + case SF_FORMAT_PCM_24 : + break ; + + case SF_FORMAT_DPCM_8 : + case SF_FORMAT_DPCM_16 : + break ; + + default : + return pdither->write_float (psf, ptr, len) ; + } ; + + bufferlen = sizeof (pdither->buffer) / (sizeof (float)) ; + + while (len > 0) + { writecount = (len >= bufferlen) ? bufferlen : (int) len ; + writecount /= psf->sf.channels ; + writecount *= psf->sf.channels ; + + dither_float (ptr, (float*) pdither->buffer, writecount / psf->sf.channels, psf->sf.channels) ; + + thiswrite = (int) pdither->write_float (psf, (float*) pdither->buffer, writecount) ; + total += thiswrite ; + len -= thiswrite ; + if (thiswrite < writecount) + break ; + } ; + + return total ; +} /* dither_write_float */ + +static sf_count_t +dither_write_double (SF_PRIVATE *psf, const double *ptr, sf_count_t len) +{ DITHER_DATA *pdither ; + int bufferlen, writecount, thiswrite ; + sf_count_t total = 0 ; + + if ((pdither = psf->dither) == NULL) + { psf->error = SFE_DITHER_BAD_PTR ; + return 0 ; + } ; + + switch (SF_CODEC (psf->sf.format)) + { case SF_FORMAT_PCM_S8 : + case SF_FORMAT_PCM_U8 : + case SF_FORMAT_PCM_16 : + case SF_FORMAT_PCM_24 : + break ; + + case SF_FORMAT_DPCM_8 : + case SF_FORMAT_DPCM_16 : + break ; + + default : + return pdither->write_double (psf, ptr, len) ; + } ; + + + bufferlen = sizeof (pdither->buffer) / sizeof (double) ; + + while (len > 0) + { writecount = (len >= bufferlen) ? bufferlen : (int) len ; + writecount /= psf->sf.channels ; + writecount *= psf->sf.channels ; + + dither_double (ptr, (double*) pdither->buffer, writecount / psf->sf.channels, psf->sf.channels) ; + + thiswrite = (int) pdither->write_double (psf, (double*) pdither->buffer, writecount) ; + total += thiswrite ; + len -= thiswrite ; + if (thiswrite < writecount) + break ; + } ; + + return total ; +} /* dither_write_double */ + +/*============================================================================== +*/ + +static void +dither_short (const short *in, short *out, int frames, int channels) +{ int ch, k ; + + for (ch = 0 ; ch < channels ; ch++) + for (k = ch ; k < channels * frames ; k += channels) + out [k] = in [k] ; + +} /* dither_short */ + +static void +dither_int (const int *in, int *out, int frames, int channels) +{ int ch, k ; + + for (ch = 0 ; ch < channels ; ch++) + for (k = ch ; k < channels * frames ; k += channels) + out [k] = in [k] ; + +} /* dither_int */ + +static void +dither_float (const float *in, float *out, int frames, int channels) +{ int ch, k ; + + for (ch = 0 ; ch < channels ; ch++) + for (k = ch ; k < channels * frames ; k += channels) + out [k] = in [k] ; + +} /* dither_float */ + +static void +dither_double (const double *in, double *out, int frames, int channels) +{ int ch, k ; + + for (ch = 0 ; ch < channels ; ch++) + for (k = ch ; k < channels * frames ; k += channels) + out [k] = in [k] ; + +} /* dither_double */ + +/*============================================================================== +*/ +#if 0 + +/* +** Not made public because this (maybe) requires storage of state information. +** +** Also maybe need separate state info for each channel!!!! +*/ + +int +DO_NOT_USE_sf_dither_short (const SF_DITHER_INFO *dither, const short *in, short *out, int frames, int channels) +{ int ch, k ; + + if (! dither) + return SFE_DITHER_BAD_PTR ; + + switch (dither->type & SFD_TYPEMASK) + { case SFD_WHITE : + case SFD_TRIANGULAR_PDF : + for (ch = 0 ; ch < channels ; ch++) + for (k = ch ; k < channels * frames ; k += channels) + out [k] = in [k] ; + break ; + + default : + return SFE_DITHER_BAD_TYPE ; + } ; + + return 0 ; +} /* DO_NOT_USE_sf_dither_short */ + +int +DO_NOT_USE_sf_dither_int (const SF_DITHER_INFO *dither, const int *in, int *out, int frames, int channels) +{ int ch, k ; + + if (! dither) + return SFE_DITHER_BAD_PTR ; + + switch (dither->type & SFD_TYPEMASK) + { case SFD_WHITE : + case SFD_TRIANGULAR_PDF : + for (ch = 0 ; ch < channels ; ch++) + for (k = ch ; k < channels * frames ; k += channels) + out [k] = in [k] ; + break ; + + default : + return SFE_DITHER_BAD_TYPE ; + } ; + + return 0 ; +} /* DO_NOT_USE_sf_dither_int */ + +int +DO_NOT_USE_sf_dither_float (const SF_DITHER_INFO *dither, const float *in, float *out, int frames, int channels) +{ int ch, k ; + + if (! dither) + return SFE_DITHER_BAD_PTR ; + + switch (dither->type & SFD_TYPEMASK) + { case SFD_WHITE : + case SFD_TRIANGULAR_PDF : + for (ch = 0 ; ch < channels ; ch++) + for (k = ch ; k < channels * frames ; k += channels) + out [k] = in [k] ; + break ; + + default : + return SFE_DITHER_BAD_TYPE ; + } ; + + return 0 ; +} /* DO_NOT_USE_sf_dither_float */ + +int +DO_NOT_USE_sf_dither_double (const SF_DITHER_INFO *dither, const double *in, double *out, int frames, int channels) +{ int ch, k ; + + if (! dither) + return SFE_DITHER_BAD_PTR ; + + switch (dither->type & SFD_TYPEMASK) + { case SFD_WHITE : + case SFD_TRIANGULAR_PDF : + for (ch = 0 ; ch < channels ; ch++) + for (k = ch ; k < channels * frames ; k += channels) + out [k] = in [k] ; + break ; + + default : + return SFE_DITHER_BAD_TYPE ; + } ; + + return 0 ; +} /* DO_NOT_USE_sf_dither_double */ + +#endif + diff --git a/extern/libsndfile-modified/src/double64.c b/extern/libsndfile-modified/src/double64.c new file mode 100644 index 000000000..0c79cd58f --- /dev/null +++ b/extern/libsndfile-modified/src/double64.c @@ -0,0 +1,1063 @@ +/* +** Copyright (C) 1999-2015 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + +#if CPU_IS_LITTLE_ENDIAN + #define DOUBLE64_READ double64_le_read + #define DOUBLE64_WRITE double64_le_write +#elif CPU_IS_BIG_ENDIAN + #define DOUBLE64_READ double64_be_read + #define DOUBLE64_WRITE double64_be_write +#endif + +/* A 32 number which will not overflow when multiplied by sizeof (double). */ +#define SENSIBLE_LEN (0x8000000) + +/*-------------------------------------------------------------------------------------------- +** Processor floating point capabilities. double64_get_capability () returns one of the +** latter three values. +*/ + +enum +{ DOUBLE_UNKNOWN = 0x00, + DOUBLE_CAN_RW_LE = 0x23, + DOUBLE_CAN_RW_BE = 0x34, + DOUBLE_BROKEN_LE = 0x45, + DOUBLE_BROKEN_BE = 0x56 +} ; + +/*-------------------------------------------------------------------------------------------- +** Prototypes for private functions. +*/ + +static sf_count_t host_read_d2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; +static sf_count_t host_read_d2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; +static sf_count_t host_read_d2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; +static sf_count_t host_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; + +static sf_count_t host_write_s2d (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; +static sf_count_t host_write_i2d (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; +static sf_count_t host_write_f2d (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; +static sf_count_t host_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; + +static void double64_peak_update (SF_PRIVATE *psf, const double *buffer, int count, sf_count_t indx) ; + +static int double64_get_capability (SF_PRIVATE *psf) ; + +static sf_count_t replace_read_d2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; +static sf_count_t replace_read_d2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; +static sf_count_t replace_read_d2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; +static sf_count_t replace_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; + +static sf_count_t replace_write_s2d (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; +static sf_count_t replace_write_i2d (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; +static sf_count_t replace_write_f2d (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; +static sf_count_t replace_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; + +static void d2bd_read (double *buffer, int count) ; +static void bd2d_write (double *buffer, int count) ; + +/*-------------------------------------------------------------------------------------------- +** Exported functions. +*/ + +int +double64_init (SF_PRIVATE *psf) +{ static int double64_caps ; + + if (psf->sf.channels < 1 || psf->sf.channels > SF_MAX_CHANNELS) + { psf_log_printf (psf, "double64_init : internal error : channels = %d\n", psf->sf.channels) ; + return SFE_INTERNAL ; + } ; + + double64_caps = double64_get_capability (psf) ; + + psf->blockwidth = sizeof (double) * psf->sf.channels ; + + if (psf->file.mode == SFM_READ || psf->file.mode == SFM_RDWR) + { switch (psf->endian + double64_caps) + { case (SF_ENDIAN_BIG + DOUBLE_CAN_RW_BE) : + psf->data_endswap = SF_FALSE ; + psf->read_short = host_read_d2s ; + psf->read_int = host_read_d2i ; + psf->read_float = host_read_d2f ; + psf->read_double = host_read_d ; + break ; + + case (SF_ENDIAN_LITTLE + DOUBLE_CAN_RW_LE) : + psf->data_endswap = SF_FALSE ; + psf->read_short = host_read_d2s ; + psf->read_int = host_read_d2i ; + psf->read_float = host_read_d2f ; + psf->read_double = host_read_d ; + break ; + + case (SF_ENDIAN_BIG + DOUBLE_CAN_RW_LE) : + psf->data_endswap = SF_TRUE ; + psf->read_short = host_read_d2s ; + psf->read_int = host_read_d2i ; + psf->read_float = host_read_d2f ; + psf->read_double = host_read_d ; + break ; + + case (SF_ENDIAN_LITTLE + DOUBLE_CAN_RW_BE) : + psf->data_endswap = SF_TRUE ; + psf->read_short = host_read_d2s ; + psf->read_int = host_read_d2i ; + psf->read_float = host_read_d2f ; + psf->read_double = host_read_d ; + break ; + + /* When the CPU is not IEEE compatible. */ + case (SF_ENDIAN_BIG + DOUBLE_BROKEN_BE) : + psf->data_endswap = SF_FALSE ; + psf->read_short = replace_read_d2s ; + psf->read_int = replace_read_d2i ; + psf->read_float = replace_read_d2f ; + psf->read_double = replace_read_d ; + break ; + + case (SF_ENDIAN_LITTLE + DOUBLE_BROKEN_LE) : + psf->data_endswap = SF_FALSE ; + psf->read_short = replace_read_d2s ; + psf->read_int = replace_read_d2i ; + psf->read_float = replace_read_d2f ; + psf->read_double = replace_read_d ; + break ; + + case (SF_ENDIAN_BIG + DOUBLE_BROKEN_LE) : + psf->data_endswap = SF_TRUE ; + psf->read_short = replace_read_d2s ; + psf->read_int = replace_read_d2i ; + psf->read_float = replace_read_d2f ; + psf->read_double = replace_read_d ; + break ; + + case (SF_ENDIAN_LITTLE + DOUBLE_BROKEN_BE) : + psf->data_endswap = SF_TRUE ; + psf->read_short = replace_read_d2s ; + psf->read_int = replace_read_d2i ; + psf->read_float = replace_read_d2f ; + psf->read_double = replace_read_d ; + break ; + + default : break ; + } ; + } ; + + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { switch (psf->endian + double64_caps) + { case (SF_ENDIAN_LITTLE + DOUBLE_CAN_RW_LE) : + psf->data_endswap = SF_FALSE ; + psf->write_short = host_write_s2d ; + psf->write_int = host_write_i2d ; + psf->write_float = host_write_f2d ; + psf->write_double = host_write_d ; + break ; + + case (SF_ENDIAN_BIG + DOUBLE_CAN_RW_BE) : + psf->data_endswap = SF_FALSE ; + psf->write_short = host_write_s2d ; + psf->write_int = host_write_i2d ; + psf->write_float = host_write_f2d ; + psf->write_double = host_write_d ; + break ; + + case (SF_ENDIAN_BIG + DOUBLE_CAN_RW_LE) : + psf->data_endswap = SF_TRUE ; + psf->write_short = host_write_s2d ; + psf->write_int = host_write_i2d ; + psf->write_float = host_write_f2d ; + psf->write_double = host_write_d ; + break ; + + case (SF_ENDIAN_LITTLE + DOUBLE_CAN_RW_BE) : + psf->data_endswap = SF_TRUE ; + psf->write_short = host_write_s2d ; + psf->write_int = host_write_i2d ; + psf->write_float = host_write_f2d ; + psf->write_double = host_write_d ; + break ; + + /* When the CPU is not IEEE compatible. */ + case (SF_ENDIAN_LITTLE + DOUBLE_BROKEN_LE) : + psf->data_endswap = SF_FALSE ; + psf->write_short = replace_write_s2d ; + psf->write_int = replace_write_i2d ; + psf->write_float = replace_write_f2d ; + psf->write_double = replace_write_d ; + break ; + + case (SF_ENDIAN_BIG + DOUBLE_BROKEN_BE) : + psf->data_endswap = SF_FALSE ; + psf->write_short = replace_write_s2d ; + psf->write_int = replace_write_i2d ; + psf->write_float = replace_write_f2d ; + psf->write_double = replace_write_d ; + break ; + + case (SF_ENDIAN_BIG + DOUBLE_BROKEN_LE) : + psf->data_endswap = SF_TRUE ; + psf->write_short = replace_write_s2d ; + psf->write_int = replace_write_i2d ; + psf->write_float = replace_write_f2d ; + psf->write_double = replace_write_d ; + break ; + + case (SF_ENDIAN_LITTLE + DOUBLE_BROKEN_BE) : + psf->data_endswap = SF_TRUE ; + psf->write_short = replace_write_s2d ; + psf->write_int = replace_write_i2d ; + psf->write_float = replace_write_f2d ; + psf->write_double = replace_write_d ; + break ; + + default : break ; + } ; + } ; + + if (psf->filelength > psf->dataoffset) + { psf->datalength = (psf->dataend > 0) ? psf->dataend - psf->dataoffset : + psf->filelength - psf->dataoffset ; + } + else + psf->datalength = 0 ; + + psf->sf.frames = psf->datalength / psf->blockwidth ; + + return 0 ; +} /* double64_init */ + +/*---------------------------------------------------------------------------- +** From : http://www.hpcf.cam.ac.uk/fp_formats.html +** +** 64 bit double precision layout (big endian) +** Sign bit 0 +** Exponent bits 1-11 +** Mantissa bits 12-63 +** Exponent Offset 1023 +** +** double single +** +** +INF 7FF0000000000000 7F800000 +** -INF FFF0000000000000 FF800000 +** NaN 7FF0000000000001 7F800001 +** to to +** 7FFFFFFFFFFFFFFF 7FFFFFFF +** and and +** FFF0000000000001 FF800001 +** to to +** FFFFFFFFFFFFFFFF FFFFFFFF +** +OVER 7FEFFFFFFFFFFFFF 7F7FFFFF +** -OVER FFEFFFFFFFFFFFFF FF7FFFFF +** +UNDER 0010000000000000 00800000 +** -UNDER 8010000000000000 80800000 +*/ + +double +double64_be_read (const unsigned char *cptr) +{ int exponent, negative, upper, lower ; + double dvalue ; + + negative = (cptr [0] & 0x80) ? 1 : 0 ; + exponent = ((cptr [0] & 0x7F) << 4) | ((cptr [1] >> 4) & 0xF) ; + + /* Might not have a 64 bit long, so load the mantissa into a double. */ + upper = (((cptr [1] & 0xF) << 24) | (cptr [2] << 16) | (cptr [3] << 8) | cptr [4]) ; + lower = (cptr [5] << 16) | (cptr [6] << 8) | cptr [7] ; + + if (exponent == 0 && upper == 0 && lower == 0) + return 0.0 ; + + dvalue = upper + lower / ((double) 0x1000000) ; + dvalue += 0x10000000 ; + + exponent = exponent - 0x3FF ; + + dvalue = dvalue / ((double) 0x10000000) ; + + if (negative) + dvalue *= -1 ; + + if (exponent > 0) + dvalue *= pow (2.0, exponent) ; + else if (exponent < 0) + dvalue /= pow (2.0, abs (exponent)) ; + + return dvalue ; +} /* double64_be_read */ + +double +double64_le_read (const unsigned char *cptr) +{ int exponent, negative, upper, lower ; + double dvalue ; + + negative = (cptr [7] & 0x80) ? 1 : 0 ; + exponent = ((cptr [7] & 0x7F) << 4) | ((cptr [6] >> 4) & 0xF) ; + + /* Might not have a 64 bit long, so load the mantissa into a double. */ + upper = ((cptr [6] & 0xF) << 24) | (cptr [5] << 16) | (cptr [4] << 8) | cptr [3] ; + lower = (cptr [2] << 16) | (cptr [1] << 8) | cptr [0] ; + + if (exponent == 0 && upper == 0 && lower == 0) + return 0.0 ; + + dvalue = upper + lower / ((double) 0x1000000) ; + dvalue += 0x10000000 ; + + exponent = exponent - 0x3FF ; + + dvalue = dvalue / ((double) 0x10000000) ; + + if (negative) + dvalue *= -1 ; + + if (exponent > 0) + dvalue *= pow (2.0, exponent) ; + else if (exponent < 0) + dvalue /= pow (2.0, abs (exponent)) ; + + return dvalue ; +} /* double64_le_read */ + +void +double64_be_write (double in, unsigned char *out) +{ int exponent, mantissa ; + + memset (out, 0, sizeof (double)) ; + + if (fabs (in) < 1e-30) + return ; + + if (in < 0.0) + { in *= -1.0 ; + out [0] |= 0x80 ; + } ; + + in = frexp (in, &exponent) ; + + exponent += 1022 ; + + out [0] |= (exponent >> 4) & 0x7F ; + out [1] |= (exponent << 4) & 0xF0 ; + + in *= 0x20000000 ; + mantissa = psf_lrint (floor (in)) ; + + out [1] |= (mantissa >> 24) & 0xF ; + out [2] = (mantissa >> 16) & 0xFF ; + out [3] = (mantissa >> 8) & 0xFF ; + out [4] = mantissa & 0xFF ; + + in = fmod (in, 1.0) ; + in *= 0x1000000 ; + mantissa = psf_lrint (floor (in)) ; + + out [5] = (mantissa >> 16) & 0xFF ; + out [6] = (mantissa >> 8) & 0xFF ; + out [7] = mantissa & 0xFF ; + + return ; +} /* double64_be_write */ + +void +double64_le_write (double in, unsigned char *out) +{ int exponent, mantissa ; + + memset (out, 0, sizeof (double)) ; + + if (fabs (in) < 1e-30) + return ; + + if (in < 0.0) + { in *= -1.0 ; + out [7] |= 0x80 ; + } ; + + in = frexp (in, &exponent) ; + + exponent += 1022 ; + + out [7] |= (exponent >> 4) & 0x7F ; + out [6] |= (exponent << 4) & 0xF0 ; + + in *= 0x20000000 ; + mantissa = psf_lrint (floor (in)) ; + + out [6] |= (mantissa >> 24) & 0xF ; + out [5] = (mantissa >> 16) & 0xFF ; + out [4] = (mantissa >> 8) & 0xFF ; + out [3] = mantissa & 0xFF ; + + in = fmod (in, 1.0) ; + in *= 0x1000000 ; + mantissa = psf_lrint (floor (in)) ; + + out [2] = (mantissa >> 16) & 0xFF ; + out [1] = (mantissa >> 8) & 0xFF ; + out [0] = mantissa & 0xFF ; + + return ; +} /* double64_le_write */ + +/*============================================================================================== +** Private functions. +*/ + +static void +double64_peak_update (SF_PRIVATE *psf, const double *buffer, int count, sf_count_t indx) +{ int chan ; + int k, position ; + float fmaxval ; + + for (chan = 0 ; chan < psf->sf.channels ; chan++) + { fmaxval = fabs (buffer [chan]) ; + position = 0 ; + for (k = chan ; k < count ; k += psf->sf.channels) + if (fmaxval < fabs (buffer [k])) + { fmaxval = fabs (buffer [k]) ; + position = k ; + } ; + + if (fmaxval > psf->peak_info->peaks [chan].value) + { psf->peak_info->peaks [chan].value = fmaxval ; + psf->peak_info->peaks [chan].position = psf->write_current + indx + (position / psf->sf.channels) ; + } ; + } ; + + return ; +} /* double64_peak_update */ + +static int +double64_get_capability (SF_PRIVATE *psf) +{ union + { double d ; + unsigned char c [8] ; + } data ; + + data.d = 1.234567890123456789 ; /* Some abitrary value. */ + + if (! psf->ieee_replace) + { /* If this test is true ints and floats are compatible and little endian. */ + if (data.c [0] == 0xfb && data.c [1] == 0x59 && data.c [2] == 0x8c && data.c [3] == 0x42 && + data.c [4] == 0xca && data.c [5] == 0xc0 && data.c [6] == 0xf3 && data.c [7] == 0x3f) + return DOUBLE_CAN_RW_LE ; + + /* If this test is true ints and floats are compatible and big endian. */ + if (data.c [0] == 0x3f && data.c [1] == 0xf3 && data.c [2] == 0xc0 && data.c [3] == 0xca && + data.c [4] == 0x42 && data.c [5] == 0x8c && data.c [6] == 0x59 && data.c [7] == 0xfb) + return DOUBLE_CAN_RW_BE ; + } ; + + /* Doubles are broken. Don't expect reading or writing to be fast. */ + psf_log_printf (psf, "Using IEEE replacement code for double.\n") ; + + return (CPU_IS_LITTLE_ENDIAN) ? DOUBLE_BROKEN_LE : DOUBLE_BROKEN_BE ; +} /* double64_get_capability */ + +/*======================================================================================= +*/ + +static void +d2s_array (const double *src, int count, short *dest, double scale) +{ for (int i = 0 ; i < count ; i++) + { dest [i] = psf_lrint (scale * src [i]) ; + } ; +} /* d2s_array */ + +static void +d2s_clip_array (const double *src, int count, short *dest, double scale) +{ for (int i = 0 ; i < count ; i++) + { double tmp = scale * src [i] ; + + if (tmp > 32767.0) + dest [i] = SHRT_MAX ; + else if (tmp < -32768.0) + dest [i] = SHRT_MIN ; + else + dest [i] = psf_lrint (tmp) ; + } ; +} /* d2s_clip_array */ + +static void +d2i_array (const double *src, int count, int *dest, double scale) +{ for (int i = 0 ; i < count ; i++) + { dest [i] = psf_lrint (scale * src [i]) ; + } ; +} /* d2i_array */ + +static void +d2i_clip_array (const double *src, int count, int *dest, double scale) +{ for (int i = 0 ; i < count ; i++) + { float tmp = scale * src [i] ; + + if (CPU_CLIPS_POSITIVE == 0 && tmp > (1.0 * INT_MAX)) + dest [i] = INT_MAX ; + else if (CPU_CLIPS_NEGATIVE == 0 && tmp < (-1.0 * INT_MAX)) + dest [i] = INT_MIN ; + else + dest [i] = psf_lrint (tmp) ; + } ; +} /* d2i_clip_array */ + +static inline void +d2f_array (const double *src, int count, float *dest) +{ for (int i = 0 ; i < count ; i++) + { dest [i] = src [i] ; + } ; +} /* d2f_array */ + +static inline void +s2d_array (const short *src, double *dest, int count, double scale) +{ for (int i = 0 ; i < count ; i++) + { dest [i] = scale * src [i] ; + } ; +} /* s2d_array */ + +static inline void +i2d_array (const int *src, double *dest, int count, double scale) +{ for (int i = 0 ; i < count ; i++) + { dest [i] = scale * src [i] ; + } ; +} /* i2d_array */ + +static inline void +f2d_array (const float *src, double *dest, int count) +{ for (int i = 0 ; i < count ; i++) + { dest [i] = src [i] ; + } ; +} /* f2d_array */ + +/*---------------------------------------------------------------------------------------------- +*/ + +static sf_count_t +host_read_d2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + void (*convert) (const double *, int, short *, double) ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + double scale ; + + convert = (psf->add_clipping) ? d2s_clip_array : d2s_array ; + bufferlen = ARRAY_LEN (ubuf.dbuf) ; + scale = (psf->float_int_mult == 0) ? 1.0 : 0x7FFF / psf->float_max ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.dbuf, sizeof (double), bufferlen, psf) ; + + if (psf->data_endswap == SF_TRUE) + endswap_double_array (ubuf.dbuf, readcount) ; + + convert (ubuf.dbuf, readcount, ptr + total, scale) ; + total += readcount ; + len -= readcount ; + if (readcount < bufferlen) + break ; + } ; + + return total ; +} /* host_read_d2s */ + +static sf_count_t +host_read_d2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + void (*convert) (const double *, int, int *, double) ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + double scale ; + + convert = (psf->add_clipping) ? d2i_clip_array : d2i_array ; + bufferlen = ARRAY_LEN (ubuf.dbuf) ; + scale = (psf->float_int_mult == 0) ? 1.0 : 2147483648.0f / psf->float_max ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.dbuf, sizeof (double), bufferlen, psf) ; + + if (psf->data_endswap == SF_TRUE) + endswap_double_array (ubuf.dbuf, bufferlen) ; + + convert (ubuf.dbuf, readcount, ptr + total, scale) ; + total += readcount ; + len -= readcount ; + if (readcount < bufferlen) + break ; + } ; + + return total ; +} /* host_read_d2i */ + +static sf_count_t +host_read_d2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + + bufferlen = ARRAY_LEN (ubuf.dbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.dbuf, sizeof (double), bufferlen, psf) ; + + if (psf->data_endswap == SF_TRUE) + endswap_double_array (ubuf.dbuf, readcount) ; + + d2f_array (ubuf.dbuf, readcount, ptr + total) ; + total += readcount ; + len -= readcount ; + if (readcount < bufferlen) + break ; + } ; + + return total ; +} /* host_read_d2f */ + +static sf_count_t +host_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) +{ int bufferlen ; + sf_count_t readcount, total = 0 ; + + readcount = psf_fread (ptr, sizeof (double), len, psf) ; + + if (psf->data_endswap != SF_TRUE) + return readcount ; + + /* If the read length was sensible, endswap output in one go. */ + if (readcount < SENSIBLE_LEN) + { endswap_double_array (ptr, readcount) ; + return readcount ; + } ; + + bufferlen = SENSIBLE_LEN ; + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + + endswap_double_array (ptr + total, bufferlen) ; + + total += bufferlen ; + len -= bufferlen ; + } ; + + return total ; +} /* host_read_d */ + +static sf_count_t +host_write_s2d (SF_PRIVATE *psf, const short *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + double scale ; + + scale = (psf->scale_int_float == 0) ? 1.0 : 1.0 / 0x8000 ; + bufferlen = ARRAY_LEN (ubuf.dbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + + s2d_array (ptr + total, ubuf.dbuf, bufferlen, scale) ; + + if (psf->peak_info) + double64_peak_update (psf, ubuf.dbuf, bufferlen, total / psf->sf.channels) ; + + if (psf->data_endswap == SF_TRUE) + endswap_double_array (ubuf.dbuf, bufferlen) ; + + writecount = (int) psf_fwrite (ubuf.dbuf, sizeof (double), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* host_write_s2d */ + +static sf_count_t +host_write_i2d (SF_PRIVATE *psf, const int *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + double scale ; + + scale = (psf->scale_int_float == 0) ? 1.0 : 1.0 / (8.0 * 0x10000000) ; + bufferlen = ARRAY_LEN (ubuf.dbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + i2d_array (ptr + total, ubuf.dbuf, bufferlen, scale) ; + + if (psf->peak_info) + double64_peak_update (psf, ubuf.dbuf, bufferlen, total / psf->sf.channels) ; + + if (psf->data_endswap == SF_TRUE) + endswap_double_array (ubuf.dbuf, bufferlen) ; + + writecount = (int) psf_fwrite (ubuf.dbuf, sizeof (double), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* host_write_i2d */ + +static sf_count_t +host_write_f2d (SF_PRIVATE *psf, const float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + bufferlen = ARRAY_LEN (ubuf.dbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + f2d_array (ptr + total, ubuf.dbuf, bufferlen) ; + + if (psf->peak_info) + double64_peak_update (psf, ubuf.dbuf, bufferlen, total / psf->sf.channels) ; + + if (psf->data_endswap == SF_TRUE) + endswap_double_array (ubuf.dbuf, bufferlen) ; + + writecount = (int) psf_fwrite (ubuf.dbuf, sizeof (double), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* host_write_f2d */ + +static sf_count_t +host_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + if (psf->peak_info) + double64_peak_update (psf, ptr, len, 0) ; + + if (psf->data_endswap != SF_TRUE) + return psf_fwrite (ptr, sizeof (double), len, psf) ; + + bufferlen = ARRAY_LEN (ubuf.dbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + + endswap_double_copy (ubuf.dbuf, ptr + total, bufferlen) ; + + writecount = (int) psf_fwrite (ubuf.dbuf, sizeof (double), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* host_write_d */ + +/*======================================================================================= +*/ + +static sf_count_t +replace_read_d2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + double scale ; + + bufferlen = ARRAY_LEN (ubuf.dbuf) ; + scale = (psf->float_int_mult == 0) ? 1.0 : 0x7FFF / psf->float_max ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.dbuf, sizeof (double), bufferlen, psf) ; + + if (psf->data_endswap == SF_TRUE) + endswap_double_array (ubuf.dbuf, bufferlen) ; + + d2bd_read (ubuf.dbuf, bufferlen) ; + + d2s_array (ubuf.dbuf, readcount, ptr + total, scale) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* replace_read_d2s */ + +static sf_count_t +replace_read_d2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + double scale ; + + bufferlen = ARRAY_LEN (ubuf.dbuf) ; + scale = (psf->float_int_mult == 0) ? 1.0 : 2147483648.0f / psf->float_max ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.dbuf, sizeof (double), bufferlen, psf) ; + + if (psf->data_endswap == SF_TRUE) + endswap_double_array (ubuf.dbuf, bufferlen) ; + + d2bd_read (ubuf.dbuf, bufferlen) ; + + d2i_array (ubuf.dbuf, readcount, ptr + total, scale) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* replace_read_d2i */ + +static sf_count_t +replace_read_d2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + + bufferlen = ARRAY_LEN (ubuf.dbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.dbuf, sizeof (double), bufferlen, psf) ; + + if (psf->data_endswap == SF_TRUE) + endswap_double_array (ubuf.dbuf, bufferlen) ; + + d2bd_read (ubuf.dbuf, bufferlen) ; + + memcpy (ptr + total, ubuf.dbuf, bufferlen * sizeof (double)) ; + + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* replace_read_d2f */ + +static sf_count_t +replace_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + + /* FIXME : This is probably nowhere near optimal. */ + bufferlen = ARRAY_LEN (ubuf.dbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.dbuf, sizeof (double), bufferlen, psf) ; + + if (psf->data_endswap == SF_TRUE) + endswap_double_array (ubuf.dbuf, readcount) ; + + d2bd_read (ubuf.dbuf, readcount) ; + + memcpy (ptr + total, ubuf.dbuf, readcount * sizeof (double)) ; + + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* replace_read_d */ + +static sf_count_t +replace_write_s2d (SF_PRIVATE *psf, const short *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + double scale ; + + scale = (psf->scale_int_float == 0) ? 1.0 : 1.0 / 0x8000 ; + bufferlen = ARRAY_LEN (ubuf.dbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + s2d_array (ptr + total, ubuf.dbuf, bufferlen, scale) ; + + if (psf->peak_info) + double64_peak_update (psf, ubuf.dbuf, bufferlen, total / psf->sf.channels) ; + + bd2d_write (ubuf.dbuf, bufferlen) ; + + if (psf->data_endswap == SF_TRUE) + endswap_double_array (ubuf.dbuf, bufferlen) ; + + writecount = (int) psf_fwrite (ubuf.dbuf, sizeof (double), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* replace_write_s2d */ + +static sf_count_t +replace_write_i2d (SF_PRIVATE *psf, const int *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + double scale ; + + scale = (psf->scale_int_float == 0) ? 1.0 : 1.0 / (8.0 * 0x10000000) ; + bufferlen = ARRAY_LEN (ubuf.dbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + i2d_array (ptr + total, ubuf.dbuf, bufferlen, scale) ; + + if (psf->peak_info) + double64_peak_update (psf, ubuf.dbuf, bufferlen, total / psf->sf.channels) ; + + bd2d_write (ubuf.dbuf, bufferlen) ; + + if (psf->data_endswap == SF_TRUE) + endswap_double_array (ubuf.dbuf, bufferlen) ; + + writecount = (int) psf_fwrite (ubuf.dbuf, sizeof (double), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* replace_write_i2d */ + +static sf_count_t +replace_write_f2d (SF_PRIVATE *psf, const float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + bufferlen = ARRAY_LEN (ubuf.dbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + f2d_array (ptr + total, ubuf.dbuf, bufferlen) ; + + bd2d_write (ubuf.dbuf, bufferlen) ; + + if (psf->data_endswap == SF_TRUE) + endswap_double_array (ubuf.dbuf, bufferlen) ; + + writecount = (int) psf_fwrite (ubuf.dbuf, sizeof (double), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* replace_write_f2d */ + +static sf_count_t +replace_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + /* FIXME : This is probably nowhere near optimal. */ + if (psf->peak_info) + double64_peak_update (psf, ptr, len, 0) ; + + bufferlen = ARRAY_LEN (ubuf.dbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + + memcpy (ubuf.dbuf, ptr + total, bufferlen * sizeof (double)) ; + + bd2d_write (ubuf.dbuf, bufferlen) ; + + if (psf->data_endswap == SF_TRUE) + endswap_double_array (ubuf.dbuf, bufferlen) ; + + writecount = (int) psf_fwrite (ubuf.dbuf, sizeof (double), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* replace_write_d */ + +/*---------------------------------------------------------------------------------------------- +*/ + +static void +d2bd_read (double *buffer, int count) +{ for (int i = 0 ; i < count ; i++) + { buffer [i] = DOUBLE64_READ ((unsigned char *) &buffer [i]) ; + } ; +} /* d2bd_read */ + +static void +bd2d_write (double *buffer, int count) +{ for (int i = 0 ; i < count ; i++) + { DOUBLE64_WRITE (buffer [i], (unsigned char*) &buffer [i]) ; + } ; +} /* bd2d_write */ + diff --git a/extern/libsndfile-modified/src/dwd.c b/extern/libsndfile-modified/src/dwd.c new file mode 100644 index 000000000..a15750d4f --- /dev/null +++ b/extern/libsndfile-modified/src/dwd.c @@ -0,0 +1,201 @@ +/* +** Copyright (C) 2002-2012 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + +#if (ENABLE_EXPERIMENTAL_CODE == 0) + +int +dwd_open (SF_PRIVATE *psf) +{ if (psf) + return SFE_UNIMPLEMENTED ; + return 0 ; +} /* dwd_open */ + +#else + +/*------------------------------------------------------------------------------ +** Macros to handle big/little endian issues. +*/ + +#define SFE_DWD_NO_DWD 1666 +#define SFE_DWD_BAND_BIT_WIDTH 1667 +#define SFE_DWD_COMPRESSION 1668 + +#define DWD_IDENTIFIER "DiamondWare Digitized\n\0\x1a" +#define DWD_IDENTIFIER_LEN 24 + +#define DWD_HEADER_LEN 57 + +/*------------------------------------------------------------------------------ +** Typedefs. +*/ + +/*------------------------------------------------------------------------------ +** Private static functions. +*/ + +static int dwd_read_header (SF_PRIVATE *psf) ; + +static int dwd_close (SF_PRIVATE *psf) ; + +/*------------------------------------------------------------------------------ +** Public function. +*/ + +int +dwd_open (SF_PRIVATE *psf) +{ int error = 0 ; + + if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0)) + { if ((error = dwd_read_header (psf))) + return error ; + } ; + + if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_DWD) + return SFE_BAD_OPEN_FORMAT ; + + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { + /*-psf->endian = SF_ENDIAN (psf->sf.format) ; + if (CPU_IS_LITTLE_ENDIAN && psf->endian == SF_ENDIAN_CPU) + psf->endian = SF_ENDIAN_LITTLE ; + else if (psf->endian != SF_ENDIAN_LITTLE) + psf->endian = SF_ENDIAN_BIG ; + + if (! (encoding = dwd_write_header (psf, SF_FALSE))) + return psf->error ; + + psf->write_header = dwd_write_header ; + -*/ + } ; + + psf->container_close = dwd_close ; + + /*-psf->blockwidth = psf->bytewidth * psf->sf.channels ;-*/ + + return error ; +} /* dwd_open */ + +/*------------------------------------------------------------------------------ +*/ + +static int +dwd_close (SF_PRIVATE * UNUSED (psf)) +{ + return 0 ; +} /* dwd_close */ + +/* This struct contains all the fields of interest om the DWD header, but does not +** do so in the same order and layout as the actual file, header. +** No assumptions are made about the packing of this struct. +*/ +typedef struct +{ uint8_t major, minor, compression, channels, bitwidth ; + uint16_t srate, maxval ; + uint32_t id, datalen, frames, offset ; +} DWD_HEADER ; + +static int +dwd_read_header (SF_PRIVATE *psf) +{ BUF_UNION ubuf ; + DWD_HEADER dwdh ; + + memset (ubuf.cbuf, 0, sizeof (ubuf.cbuf)) ; + /* Set position to start of file to begin reading header. */ + psf_binheader_readf (psf, "pb", 0, ubuf.cbuf, DWD_IDENTIFIER_LEN) ; + + if (memcmp (ubuf.cbuf, DWD_IDENTIFIER, DWD_IDENTIFIER_LEN) != 0) + return SFE_DWD_NO_DWD ; + + psf_log_printf (psf, "Read only : DiamondWare Digitized (.dwd)\n", ubuf.cbuf) ; + + psf_binheader_readf (psf, "11", &dwdh.major, &dwdh.minor) ; + psf_binheader_readf (psf, "e4j1", &dwdh.id, 1, &dwdh.compression) ; + psf_binheader_readf (psf, "e211", &dwdh.srate, &dwdh.channels, &dwdh.bitwidth) ; + psf_binheader_readf (psf, "e24", &dwdh.maxval, &dwdh.datalen) ; + psf_binheader_readf (psf, "e44", &dwdh.frames, &dwdh.offset) ; + + psf_log_printf (psf, " Version Major : %d\n Version Minor : %d\n Unique ID : %08X\n", + dwdh.major, dwdh.minor, dwdh.id) ; + psf_log_printf (psf, " Compression : %d => ", dwdh.compression) ; + + if (dwdh.compression != 0) + { psf_log_printf (psf, "Unsupported compression\n") ; + return SFE_DWD_COMPRESSION ; + } + else + psf_log_printf (psf, "None\n") ; + + psf_log_printf (psf, " Sample Rate : %d\n Channels : %d\n" + " Bit Width : %d\n", + dwdh.srate, dwdh.channels, dwdh.bitwidth) ; + + switch (dwdh.bitwidth) + { case 8 : + psf->sf.format = SF_FORMAT_DWD | SF_FORMAT_PCM_S8 ; + psf->bytewidth = 1 ; + break ; + + case 16 : + psf->sf.format = SF_FORMAT_DWD | SF_FORMAT_PCM_16 ; + psf->bytewidth = 2 ; + break ; + + default : + psf_log_printf (psf, "*** Bad bit width %d\n", dwdh.bitwidth) ; + return SFE_DWD_BAND_BIT_WIDTH ; + } ; + + if (psf->filelength != dwdh.offset + dwdh.datalen) + { psf_log_printf (psf, " Data Length : %d (should be %D)\n", dwdh.datalen, psf->filelength - dwdh.offset) ; + dwdh.datalen = (uint32_t) (psf->filelength - dwdh.offset) ; + } + else + psf_log_printf (psf, " Data Length : %d\n", dwdh.datalen) ; + + psf_log_printf (psf, " Max Value : %d\n", dwdh.maxval) ; + psf_log_printf (psf, " Frames : %d\n", dwdh.frames) ; + psf_log_printf (psf, " Data Offset : %d\n", dwdh.offset) ; + + psf->datalength = dwdh.datalen ; + psf->dataoffset = dwdh.offset ; + + psf->endian = SF_ENDIAN_LITTLE ; + + psf->sf.samplerate = dwdh.srate ; + psf->sf.channels = dwdh.channels ; + psf->sf.sections = 1 ; + + return pcm_init (psf) ; +} /* dwd_read_header */ + +/*------------------------------------------------------------------------------ +*/ + +#endif + diff --git a/extern/libsndfile-modified/src/dwvw.c b/extern/libsndfile-modified/src/dwvw.c new file mode 100644 index 000000000..a015fceb0 --- /dev/null +++ b/extern/libsndfile-modified/src/dwvw.c @@ -0,0 +1,674 @@ +/* +** Copyright (C) 2002-2014 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/*=========================================================================== +** Delta Word Variable Width +** +** This decoder and encoder were implemented using information found in this +** document : http://home.swbell.net/rubywand/R011SNDFMTS.TXT +** +** According to the document, the algorithm "was invented 1991 by Magnus +** Lidstrom and is copyright 1993 by NuEdge Development". +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + +typedef struct +{ int bit_width, dwm_maxsize, max_delta, span ; + int samplecount ; + int bit_count, bits, last_delta_width, last_sample ; + struct + { int index, end ; + unsigned char buffer [256] ; + } b ; +} DWVW_PRIVATE ; + +/*============================================================================================ +*/ + +static sf_count_t dwvw_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; +static sf_count_t dwvw_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; +static sf_count_t dwvw_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; +static sf_count_t dwvw_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; + +static sf_count_t dwvw_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; +static sf_count_t dwvw_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; +static sf_count_t dwvw_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; +static sf_count_t dwvw_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; + +static sf_count_t dwvw_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ; +static int dwvw_close (SF_PRIVATE *psf) ; +static int dwvw_byterate (SF_PRIVATE *psf) ; + +static int dwvw_decode_data (SF_PRIVATE *psf, DWVW_PRIVATE *pdwvw, int *ptr, int len) ; +static int dwvw_decode_load_bits (SF_PRIVATE *psf, DWVW_PRIVATE *pdwvw, int bit_count) ; + +static int dwvw_encode_data (SF_PRIVATE *psf, DWVW_PRIVATE *pdwvw, const int *ptr, int len) ; +static void dwvw_encode_store_bits (SF_PRIVATE *psf, DWVW_PRIVATE *pdwvw, int data, int new_bits) ; +static void dwvw_read_reset (DWVW_PRIVATE *pdwvw) ; + +/*============================================================================================ +** DWVW initialisation function. +*/ + +int +dwvw_init (SF_PRIVATE *psf, int bitwidth) +{ DWVW_PRIVATE *pdwvw ; + + if (psf->codec_data != NULL) + { psf_log_printf (psf, "*** psf->codec_data is not NULL.\n") ; + return SFE_INTERNAL ; + } ; + + if (bitwidth > 24) + return SFE_DWVW_BAD_BITWIDTH ; + + if (psf->file.mode == SFM_RDWR) + return SFE_BAD_MODE_RW ; + + if ((pdwvw = calloc (1, sizeof (DWVW_PRIVATE))) == NULL) + return SFE_MALLOC_FAILED ; + + psf->codec_data = (void*) pdwvw ; + pdwvw->bit_width = bitwidth ; + dwvw_read_reset (pdwvw) ; + + if (psf->file.mode == SFM_READ) + { psf->read_short = dwvw_read_s ; + psf->read_int = dwvw_read_i ; + psf->read_float = dwvw_read_f ; + psf->read_double = dwvw_read_d ; + } ; + + if (psf->file.mode == SFM_WRITE) + { psf->write_short = dwvw_write_s ; + psf->write_int = dwvw_write_i ; + psf->write_float = dwvw_write_f ; + psf->write_double = dwvw_write_d ; + } ; + + psf->codec_close = dwvw_close ; + psf->seek = dwvw_seek ; + psf->byterate = dwvw_byterate ; + + if (psf->file.mode == SFM_READ) + { psf->sf.frames = psf_decode_frame_count (psf) ; + dwvw_read_reset (pdwvw) ; + } ; + + return 0 ; +} /* dwvw_init */ + +/*-------------------------------------------------------------------------------------------- +*/ + +static int +dwvw_close (SF_PRIVATE *psf) +{ DWVW_PRIVATE *pdwvw ; + + if (psf->codec_data == NULL) + return 0 ; + pdwvw = (DWVW_PRIVATE*) psf->codec_data ; + + if (psf->file.mode == SFM_WRITE) + { static int last_values [12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } ; + + /* Write 8 zero samples to fully flush output. */ + dwvw_encode_data (psf, pdwvw, last_values, 12) ; + + /* Write the last buffer worth of data to disk. */ + psf_fwrite (pdwvw->b.buffer, 1, pdwvw->b.index, psf) ; + + if (psf->write_header) + psf->write_header (psf, SF_TRUE) ; + } ; + + return 0 ; +} /* dwvw_close */ + +static sf_count_t +dwvw_seek (SF_PRIVATE *psf, int UNUSED (mode), sf_count_t offset) +{ DWVW_PRIVATE *pdwvw ; + + if (! psf->codec_data) + { psf->error = SFE_INTERNAL ; + return PSF_SEEK_ERROR ; + } ; + + pdwvw = (DWVW_PRIVATE*) psf->codec_data ; + + if (offset == 0) + { psf_fseek (psf, psf->dataoffset, SEEK_SET) ; + dwvw_read_reset (pdwvw) ; + return 0 ; + } ; + + psf->error = SFE_BAD_SEEK ; + return PSF_SEEK_ERROR ; +} /* dwvw_seek */ + +static int +dwvw_byterate (SF_PRIVATE *psf) +{ + if (psf->file.mode == SFM_READ) + return (psf->datalength * psf->sf.samplerate) / psf->sf.frames ; + + return -1 ; +} /* dwvw_byterate */ + +/*============================================================================== +*/ + +static sf_count_t +dwvw_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) +{ DWVW_PRIVATE *pdwvw ; + BUF_UNION ubuf ; + int *iptr ; + int k, bufferlen, readcount = 0, count ; + sf_count_t total = 0 ; + + if (! psf->codec_data) + return 0 ; + pdwvw = (DWVW_PRIVATE*) psf->codec_data ; + + iptr = ubuf.ibuf ; + bufferlen = ARRAY_LEN (ubuf.ibuf) ; + while (len > 0) + { readcount = (len >= bufferlen) ? bufferlen : (int) len ; + count = dwvw_decode_data (psf, pdwvw, iptr, readcount) ; + for (k = 0 ; k < readcount ; k++) + ptr [total + k] = iptr [k] >> 16 ; + + total += count ; + len -= readcount ; + if (count != readcount) + break ; + } ; + + return total ; +} /* dwvw_read_s */ + +static sf_count_t +dwvw_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) +{ DWVW_PRIVATE *pdwvw ; + int readcount, count ; + sf_count_t total = 0 ; + + if (! psf->codec_data) + return 0 ; + pdwvw = (DWVW_PRIVATE*) psf->codec_data ; + + while (len > 0) + { readcount = (len > 0x10000000) ? 0x10000000 : (int) len ; + + count = dwvw_decode_data (psf, pdwvw, ptr, readcount) ; + + total += count ; + len -= count ; + + if (count != readcount) + break ; + } ; + + return total ; +} /* dwvw_read_i */ + +static sf_count_t +dwvw_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) +{ DWVW_PRIVATE *pdwvw ; + BUF_UNION ubuf ; + int *iptr ; + int k, bufferlen, readcount = 0, count ; + sf_count_t total = 0 ; + float normfact ; + + if (! psf->codec_data) + return 0 ; + pdwvw = (DWVW_PRIVATE*) psf->codec_data ; + + normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x80000000) : 1.0 ; + + iptr = ubuf.ibuf ; + bufferlen = ARRAY_LEN (ubuf.ibuf) ; + while (len > 0) + { readcount = (len >= bufferlen) ? bufferlen : (int) len ; + count = dwvw_decode_data (psf, pdwvw, iptr, readcount) ; + for (k = 0 ; k < readcount ; k++) + ptr [total + k] = normfact * (float) (iptr [k]) ; + + total += count ; + len -= readcount ; + if (count != readcount) + break ; + } ; + + return total ; +} /* dwvw_read_f */ + +static sf_count_t +dwvw_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) +{ DWVW_PRIVATE *pdwvw ; + BUF_UNION ubuf ; + int *iptr ; + int k, bufferlen, readcount = 0, count ; + sf_count_t total = 0 ; + double normfact ; + + if (! psf->codec_data) + return 0 ; + pdwvw = (DWVW_PRIVATE*) psf->codec_data ; + + normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x80000000) : 1.0 ; + + iptr = ubuf.ibuf ; + bufferlen = ARRAY_LEN (ubuf.ibuf) ; + while (len > 0) + { readcount = (len >= bufferlen) ? bufferlen : (int) len ; + count = dwvw_decode_data (psf, pdwvw, iptr, readcount) ; + for (k = 0 ; k < readcount ; k++) + ptr [total + k] = normfact * (double) (iptr [k]) ; + + total += count ; + len -= readcount ; + if (count != readcount) + break ; + } ; + + return total ; +} /* dwvw_read_d */ + +static int +dwvw_decode_data (SF_PRIVATE *psf, DWVW_PRIVATE *pdwvw, int *ptr, int len) +{ int count ; + int delta_width_modifier, delta_width, delta_negative, delta, sample ; + + /* Restore state from last decode call. */ + delta_width = pdwvw->last_delta_width ; + sample = pdwvw->last_sample ; + + for (count = 0 ; count < len ; count++) + { /* If bit_count parameter is zero get the delta_width_modifier. */ + delta_width_modifier = dwvw_decode_load_bits (psf, pdwvw, -1) ; + + /* Check for end of input bit stream. Break loop if end. */ + if (delta_width_modifier < 0 || (pdwvw->b.end == 0 && count == 0)) + break ; + + if (delta_width_modifier && dwvw_decode_load_bits (psf, pdwvw, 1)) + delta_width_modifier = - delta_width_modifier ; + + /* Calculate the current word width. */ + delta_width = (delta_width + delta_width_modifier + pdwvw->bit_width) % pdwvw->bit_width ; + + /* Load the delta. */ + delta = 0 ; + if (delta_width) + { delta = dwvw_decode_load_bits (psf, pdwvw, delta_width - 1) | (1 << (delta_width - 1)) ; + delta_negative = dwvw_decode_load_bits (psf, pdwvw, 1) ; + if (delta == pdwvw->max_delta - 1) + delta += dwvw_decode_load_bits (psf, pdwvw, 1) ; + if (delta_negative) + delta = -delta ; + } ; + + /* Calculate the sample */ + sample += delta ; + + if (sample >= pdwvw->max_delta) + sample -= pdwvw->span ; + else if (sample < - pdwvw->max_delta) + sample += pdwvw->span ; + + /* Store the sample justifying to the most significant bit. */ + ptr [count] = arith_shift_left (sample, 32 - pdwvw->bit_width) ; + + if (pdwvw->b.end == 0 && pdwvw->bit_count == 0) + break ; + } ; + + pdwvw->last_delta_width = delta_width ; + pdwvw->last_sample = sample ; + + pdwvw->samplecount += count ; + + return count ; +} /* dwvw_decode_data */ + +static int +dwvw_decode_load_bits (SF_PRIVATE *psf, DWVW_PRIVATE *pdwvw, int bit_count) +{ int output = 0, get_dwm = SF_FALSE ; + + /* + ** Depending on the value of parameter bit_count, either get the + ** required number of bits (ie bit_count > 0) or the + ** delta_width_modifier (otherwise). + */ + + if (bit_count < 0) + { get_dwm = SF_TRUE ; + /* modify bit_count to ensure we have enought bits for finding dwm. */ + bit_count = pdwvw->dwm_maxsize ; + } ; + + /* Load bits in bit reseviour. */ + while (pdwvw->bit_count < bit_count) + { if (pdwvw->b.index >= pdwvw->b.end) + { pdwvw->b.end = (int) psf_fread (pdwvw->b.buffer, 1, sizeof (pdwvw->b.buffer), psf) ; + pdwvw->b.index = 0 ; + } ; + + /* Check for end of input stream. */ + if (bit_count < 8 && pdwvw->b.end == 0) + return -1 ; + + pdwvw->bits = arith_shift_left (pdwvw->bits, 8) ; + + if (pdwvw->b.index < pdwvw->b.end) + { pdwvw->bits |= pdwvw->b.buffer [pdwvw->b.index] ; + pdwvw->b.index ++ ; + } ; + pdwvw->bit_count += 8 ; + } ; + + /* If asked to get bits do so. */ + if (! get_dwm) + { output = (pdwvw->bits >> (pdwvw->bit_count - bit_count)) & ((1 << bit_count) - 1) ; + pdwvw->bit_count -= bit_count ; + return output ; + } ; + + /* Otherwise must have been asked to get delta_width_modifier. */ + while (output < (pdwvw->dwm_maxsize)) + { pdwvw->bit_count -= 1 ; + if (pdwvw->bits & (1 << pdwvw->bit_count)) + break ; + output += 1 ; + } ; + + return output ; +} /* dwvw_decode_load_bits */ + +static void +dwvw_read_reset (DWVW_PRIVATE *pdwvw) +{ int bitwidth = pdwvw->bit_width ; + + memset (pdwvw, 0, sizeof (DWVW_PRIVATE)) ; + + pdwvw->bit_width = bitwidth ; + pdwvw->dwm_maxsize = bitwidth / 2 ; + pdwvw->max_delta = 1 << (bitwidth - 1) ; + pdwvw->span = 1 << bitwidth ; +} /* dwvw_read_reset */ + +static void +dwvw_encode_store_bits (SF_PRIVATE *psf, DWVW_PRIVATE *pdwvw, int data, int new_bits) +{ int byte ; + + /* Shift the bits into the resevoir. */ + pdwvw->bits = arith_shift_left (pdwvw->bits, new_bits) | (data & (arith_shift_left (1, new_bits) - 1)) ; + pdwvw->bit_count += new_bits ; + + /* Transfer bit to buffer. */ + while (pdwvw->bit_count >= 8) + { byte = pdwvw->bits >> (pdwvw->bit_count - 8) ; + pdwvw->bit_count -= 8 ; + pdwvw->b.buffer [pdwvw->b.index] = byte & 0xFF ; + pdwvw->b.index ++ ; + } ; + + if (pdwvw->b.index > SIGNED_SIZEOF (pdwvw->b.buffer) - 4) + { psf_fwrite (pdwvw->b.buffer, 1, pdwvw->b.index, psf) ; + pdwvw->b.index = 0 ; + } ; + + return ; +} /* dwvw_encode_store_bits */ + +#if 0 +/* Debigging routine. */ +static void +dump_bits (DWVW_PRIVATE *pdwvw) +{ int k, mask ; + + for (k = 0 ; k < 10 && k < pdwvw->b.index ; k++) + { mask = 0x80 ; + while (mask) + { putchar (mask & pdwvw->b.buffer [k] ? '1' : '0') ; + mask >>= 1 ; + } ; + putchar (' ') ; + } + + for (k = pdwvw->bit_count - 1 ; k >= 0 ; k --) + putchar (pdwvw->bits & (1 << k) ? '1' : '0') ; + + putchar ('\n') ; +} /* dump_bits */ +#endif + +#define HIGHEST_BIT(x, count) \ + { int y = x ; \ + (count) = 0 ; \ + while (y) \ + { (count) ++ ; \ + y >>= 1 ; \ + } ; \ + } ; + +static int +dwvw_encode_data (SF_PRIVATE *psf, DWVW_PRIVATE *pdwvw, const int *ptr, int len) +{ int count ; + int delta_width_modifier, delta, delta_negative, delta_width, extra_bit ; + + for (count = 0 ; count < len ; count++) + { delta = (ptr [count] >> (32 - pdwvw->bit_width)) - pdwvw->last_sample ; + + /* Calculate extra_bit if needed. */ + extra_bit = -1 ; + delta_negative = 0 ; + if (delta < -pdwvw->max_delta) + delta = pdwvw->max_delta + (delta % pdwvw->max_delta) ; + else if (delta == -pdwvw->max_delta) + { extra_bit = 1 ; + delta_negative = 1 ; + delta = pdwvw->max_delta - 1 ; + } + else if (delta > pdwvw->max_delta) + { delta_negative = 1 ; + delta = pdwvw->span - delta ; + delta = abs (delta) ; + } + else if (delta == pdwvw->max_delta) + { extra_bit = 1 ; + delta = pdwvw->max_delta - 1 ; + } + else if (delta < 0) + { delta_negative = 1 ; + delta = abs (delta) ; + } ; + + if (delta == pdwvw->max_delta - 1 && extra_bit == -1) + extra_bit = 0 ; + + /* Find width in bits of delta */ + HIGHEST_BIT (delta, delta_width) ; + + /* Calculate the delta_width_modifier */ + delta_width_modifier = (delta_width - pdwvw->last_delta_width) % pdwvw->bit_width ; + if (delta_width_modifier > pdwvw->dwm_maxsize) + delta_width_modifier -= pdwvw->bit_width ; + if (delta_width_modifier < -pdwvw->dwm_maxsize) + delta_width_modifier += pdwvw->bit_width ; + + /* Write delta_width_modifier zeros, followed by terminating '1'. */ + dwvw_encode_store_bits (psf, pdwvw, 0, abs (delta_width_modifier)) ; + if (abs (delta_width_modifier) != pdwvw->dwm_maxsize) + dwvw_encode_store_bits (psf, pdwvw, 1, 1) ; + + /* Write delta_width_modifier sign. */ + if (delta_width_modifier < 0) + dwvw_encode_store_bits (psf, pdwvw, 1, 1) ; + if (delta_width_modifier > 0) + dwvw_encode_store_bits (psf, pdwvw, 0, 1) ; + + /* Write delta and delta sign bit. */ + if (delta_width) + { dwvw_encode_store_bits (psf, pdwvw, delta, abs (delta_width) - 1) ; + dwvw_encode_store_bits (psf, pdwvw, (delta_negative ? 1 : 0), 1) ; + } ; + + /* Write extra bit!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ + if (extra_bit >= 0) + dwvw_encode_store_bits (psf, pdwvw, extra_bit, 1) ; + + pdwvw->last_sample = ptr [count] >> (32 - pdwvw->bit_width) ; + pdwvw->last_delta_width = delta_width ; + } ; + + pdwvw->samplecount += count ; + + return count ; +} /* dwvw_encode_data */ + +static sf_count_t +dwvw_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) +{ DWVW_PRIVATE *pdwvw ; + BUF_UNION ubuf ; + int *iptr ; + int k, bufferlen, writecount = 0, count ; + sf_count_t total = 0 ; + + if (! psf->codec_data) + return 0 ; + pdwvw = (DWVW_PRIVATE*) psf->codec_data ; + + iptr = ubuf.ibuf ; + bufferlen = ARRAY_LEN (ubuf.ibuf) ; + while (len > 0) + { writecount = (len >= bufferlen) ? bufferlen : (int) len ; + for (k = 0 ; k < writecount ; k++) + iptr [k] = arith_shift_left (ptr [total + k], 16) ; + count = dwvw_encode_data (psf, pdwvw, iptr, writecount) ; + + total += count ; + len -= writecount ; + if (count != writecount) + break ; + } ; + + return total ; +} /* dwvw_write_s */ + +static sf_count_t +dwvw_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) +{ DWVW_PRIVATE *pdwvw ; + int writecount, count ; + sf_count_t total = 0 ; + + if (! psf->codec_data) + return 0 ; + pdwvw = (DWVW_PRIVATE*) psf->codec_data ; + + while (len > 0) + { writecount = (len > 0x10000000) ? 0x10000000 : (int) len ; + + count = dwvw_encode_data (psf, pdwvw, ptr, writecount) ; + + total += count ; + len -= count ; + + if (count != writecount) + break ; + } ; + + return total ; +} /* dwvw_write_i */ + +static sf_count_t +dwvw_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) +{ DWVW_PRIVATE *pdwvw ; + BUF_UNION ubuf ; + int *iptr ; + int k, bufferlen, writecount = 0, count ; + sf_count_t total = 0 ; + float normfact ; + + if (! psf->codec_data) + return 0 ; + pdwvw = (DWVW_PRIVATE*) psf->codec_data ; + + normfact = (psf->norm_float == SF_TRUE) ? (1.0 * 0x7FFFFFFF) : 1.0 ; + + iptr = ubuf.ibuf ; + bufferlen = ARRAY_LEN (ubuf.ibuf) ; + while (len > 0) + { writecount = (len >= bufferlen) ? bufferlen : (int) len ; + for (k = 0 ; k < writecount ; k++) + iptr [k] = psf_lrintf (normfact * ptr [total + k]) ; + count = dwvw_encode_data (psf, pdwvw, iptr, writecount) ; + + total += count ; + len -= writecount ; + if (count != writecount) + break ; + } ; + + return total ; +} /* dwvw_write_f */ + +static sf_count_t +dwvw_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) +{ DWVW_PRIVATE *pdwvw ; + BUF_UNION ubuf ; + int *iptr ; + int k, bufferlen, writecount = 0, count ; + sf_count_t total = 0 ; + double normfact ; + + if (! psf->codec_data) + return 0 ; + pdwvw = (DWVW_PRIVATE*) psf->codec_data ; + + normfact = (psf->norm_double == SF_TRUE) ? (1.0 * 0x7FFFFFFF) : 1.0 ; + + iptr = ubuf.ibuf ; + bufferlen = ARRAY_LEN (ubuf.ibuf) ; + while (len > 0) + { writecount = (len >= bufferlen) ? bufferlen : (int) len ; + for (k = 0 ; k < writecount ; k++) + iptr [k] = psf_lrint (normfact * ptr [total + k]) ; + count = dwvw_encode_data (psf, pdwvw, iptr, writecount) ; + + total += count ; + len -= writecount ; + if (count != writecount) + break ; + } ; + + return total ; +} /* dwvw_write_d */ + diff --git a/extern/libsndfile-modified/src/file_io.c b/extern/libsndfile-modified/src/file_io.c new file mode 100644 index 000000000..b7f7ed77f --- /dev/null +++ b/extern/libsndfile-modified/src/file_io.c @@ -0,0 +1,1206 @@ +/* +** Copyright (C) 2002-2014 Erik de Castro Lopo +** Copyright (C) 2003 Ross Bencina +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/* +** The file is split into three sections as follows: +** - The top section (USE_WINDOWS_API == 0) for Linux, Unix and MacOSX +** systems (including Cygwin). +** - The middle section (USE_WINDOWS_API == 1) for microsoft windows +** (including MinGW) using the native windows API. +** - A legacy windows section which attempted to work around grevious +** bugs in microsoft's POSIX implementation. +*/ + +/* +** The header file sfconfig.h MUST be included before the others to ensure +** that large file support is enabled correctly on Unix systems. +*/ + +#include "sfconfig.h" + +#if USE_WINDOWS_API + +/* Don't include rarely used headers, speed up build */ +#define WIN32_LEAN_AND_MEAN + +#include +#endif + +#include +#include + +#if HAVE_UNISTD_H +#include +#else +#include +#endif + +#if (HAVE_DECL_S_IRGRP == 0) +#include +#endif + +#include +#include +#include +#include + +#include "sndfile.h" +#include "common.h" + +#define SENSIBLE_SIZE (0x40000000) + +/* +** Neat solution to the Win32/OS2 binary file flage requirement. +** If O_BINARY isn't already defined by the inclusion of the system +** headers, set it to zero. +*/ +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +static void psf_log_syserr (SF_PRIVATE *psf, int error) ; + +int +psf_copy_filename (SF_PRIVATE *psf, const char *path) +{ const char *ccptr ; + char *cptr ; + + if (strlen (path) > 1 && strlen (path) - 1 >= sizeof (psf->file.path)) + { psf->error = SFE_FILENAME_TOO_LONG ; + return psf->error ; + } ; + + snprintf (psf->file.path, sizeof (psf->file.path), "%s", path) ; + if ((ccptr = strrchr (path, '/')) || (ccptr = strrchr (path, '\\'))) + ccptr ++ ; + else + ccptr = path ; + + snprintf (psf->file.name, sizeof (psf->file.name), "%s", ccptr) ; + + /* Now grab the directory. */ + snprintf (psf->file.dir, sizeof (psf->file.dir), "%s", path) ; + if ((cptr = strrchr (psf->file.dir, '/')) || (cptr = strrchr (psf->file.dir, '\\'))) + cptr [1] = 0 ; + else + psf->file.dir [0] = 0 ; + + return 0 ; +} /* psf_copy_filename */ + +#if (USE_WINDOWS_API == 0) + +/*------------------------------------------------------------------------------ +** Win32 stuff at the bottom of the file. Unix and other sensible OSes here. +*/ + +static int psf_close_fd (int fd) ; +static int psf_open_fd (PSF_FILE * pfile) ; +static sf_count_t psf_get_filelen_fd (int fd) ; + +int +psf_fopen (SF_PRIVATE *psf) +{ + psf->error = 0 ; + psf->file.filedes = psf_open_fd (&psf->file) ; + + if (psf->file.filedes == - SFE_BAD_OPEN_MODE) + { psf->error = SFE_BAD_OPEN_MODE ; + psf->file.filedes = -1 ; + return psf->error ; + } ; + + if (psf->file.filedes == -1) + psf_log_syserr (psf, errno) ; + + return psf->error ; +} /* psf_fopen */ + +int +psf_fclose (SF_PRIVATE *psf) +{ int retval ; + + if (psf->virtual_io) + return 0 ; + + if (psf->file.do_not_close_descriptor) + { psf->file.filedes = -1 ; + return 0 ; + } ; + + if ((retval = psf_close_fd (psf->file.filedes)) == -1) + psf_log_syserr (psf, errno) ; + + psf->file.filedes = -1 ; + + return retval ; +} /* psf_fclose */ + +int +psf_open_rsrc (SF_PRIVATE *psf) +{ size_t count ; + + if (psf->rsrc.filedes > 0) + return 0 ; + + /* Test for MacOSX style resource fork on HPFS or HPFS+ filesystems. */ + count = snprintf (psf->rsrc.path, sizeof (psf->rsrc.path), "%s/..namedfork/rsrc", psf->file.path) ; + psf->error = SFE_NO_ERROR ; + if (count < sizeof (psf->rsrc.path)) + { if ((psf->rsrc.filedes = psf_open_fd (&psf->rsrc)) >= 0) + { psf->rsrclength = psf_get_filelen_fd (psf->rsrc.filedes) ; + if (psf->rsrclength > 0 || (psf->rsrc.mode & SFM_WRITE)) + return SFE_NO_ERROR ; + psf_close_fd (psf->rsrc.filedes) ; + psf->rsrc.filedes = -1 ; + } ; + + if (psf->rsrc.filedes == - SFE_BAD_OPEN_MODE) + { psf->error = SFE_BAD_OPEN_MODE ; + return psf->error ; + } ; + } ; + + /* + ** Now try for a resource fork stored as a separate file in the same + ** directory, but preceded with a dot underscore. + */ + count = snprintf (psf->rsrc.path, sizeof (psf->rsrc.path), "%s._%s", psf->file.dir, psf->file.name) ; + psf->error = SFE_NO_ERROR ; + if (count < sizeof (psf->rsrc.path) && (psf->rsrc.filedes = psf_open_fd (&psf->rsrc)) >= 0) + { psf->rsrclength = psf_get_filelen_fd (psf->rsrc.filedes) ; + return SFE_NO_ERROR ; + } ; + + /* + ** Now try for a resource fork stored in a separate file in the + ** .AppleDouble/ directory. + */ + count = snprintf (psf->rsrc.path, sizeof (psf->rsrc.path), "%s.AppleDouble/%s", psf->file.dir, psf->file.name) ; + psf->error = SFE_NO_ERROR ; + if (count < sizeof (psf->rsrc.path)) + { if ((psf->rsrc.filedes = psf_open_fd (&psf->rsrc)) >= 0) + { psf->rsrclength = psf_get_filelen_fd (psf->rsrc.filedes) ; + return SFE_NO_ERROR ; + } ; + + /* No resource file found. */ + if (psf->rsrc.filedes == -1) + psf_log_syserr (psf, errno) ; + } + else + { psf->error = SFE_OPEN_FAILED ; + } ; + + psf->rsrc.filedes = -1 ; + + return psf->error ; +} /* psf_open_rsrc */ + +sf_count_t +psf_get_filelen (SF_PRIVATE *psf) +{ sf_count_t filelen ; + + if (psf->virtual_io) + return psf->vio.get_filelen (psf->vio_user_data) ; + + filelen = psf_get_filelen_fd (psf->file.filedes) ; + + if (filelen == -1) + { psf_log_syserr (psf, errno) ; + return (sf_count_t) -1 ; + } ; + + if (filelen == -SFE_BAD_STAT_SIZE) + { psf->error = SFE_BAD_STAT_SIZE ; + return (sf_count_t) -1 ; + } ; + + switch (psf->file.mode) + { case SFM_WRITE : + filelen = filelen - psf->fileoffset ; + break ; + + case SFM_READ : + if (psf->fileoffset > 0 && psf->filelength > 0) + filelen = psf->filelength ; + break ; + + case SFM_RDWR : + /* + ** Cannot open embedded files SFM_RDWR so we don't need to + ** subtract psf->fileoffset. We already have the answer we + ** need. + */ + break ; + + default : + /* Shouldn't be here, so return error. */ + filelen = -1 ; + } ; + + return filelen ; +} /* psf_get_filelen */ + +int +psf_close_rsrc (SF_PRIVATE *psf) +{ psf_close_fd (psf->rsrc.filedes) ; + psf->rsrc.filedes = -1 ; + return 0 ; +} /* psf_close_rsrc */ + +int +psf_set_stdio (SF_PRIVATE *psf) +{ int error = 0 ; + + switch (psf->file.mode) + { case SFM_RDWR : + error = SFE_OPEN_PIPE_RDWR ; + break ; + + case SFM_READ : + psf->file.filedes = 0 ; + break ; + + case SFM_WRITE : + psf->file.filedes = 1 ; + break ; + + default : + error = SFE_BAD_OPEN_MODE ; + break ; + } ; + psf->filelength = 0 ; + + return error ; +} /* psf_set_stdio */ + +void +psf_set_file (SF_PRIVATE *psf, int fd) +{ psf->file.filedes = fd ; +} /* psf_set_file */ + +int +psf_file_valid (SF_PRIVATE *psf) +{ return (psf->file.filedes >= 0) ? SF_TRUE : SF_FALSE ; +} /* psf_set_file */ + +sf_count_t +psf_fseek (SF_PRIVATE *psf, sf_count_t offset, int whence) +{ sf_count_t absolute_position ; + + if (psf->virtual_io) + return psf->vio.seek (offset, whence, psf->vio_user_data) ; + + /* When decoding from pipes sometimes see seeks to the pipeoffset, which appears to mean do nothing. */ + if (psf->is_pipe) + { if (whence != SEEK_SET || offset != psf->pipeoffset) + psf_log_printf (psf, "psf_fseek : pipe seek to value other than pipeoffset\n") ; + return offset ; + } + + switch (whence) + { case SEEK_SET : + offset += psf->fileoffset ; + break ; + + case SEEK_END : + break ; + + case SEEK_CUR : + break ; + + default : + /* We really should not be here. */ + psf_log_printf (psf, "psf_fseek : whence is %d *****.\n", whence) ; + return 0 ; + } ; + + absolute_position = lseek (psf->file.filedes, offset, whence) ; + + if (absolute_position < 0) + psf_log_syserr (psf, errno) ; + + return absolute_position - psf->fileoffset ; +} /* psf_fseek */ + +sf_count_t +psf_fread (void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf) +{ sf_count_t total = 0 ; + ssize_t count ; + + if (psf->virtual_io) + return psf->vio.read (ptr, bytes*items, psf->vio_user_data) / bytes ; + + items *= bytes ; + + /* Do this check after the multiplication above. */ + if (items <= 0) + return 0 ; + + while (items > 0) + { /* Break the read down to a sensible size. */ + count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : (ssize_t) items ; + + count = read (psf->file.filedes, ((char*) ptr) + total, (size_t) count) ; + + if (count == -1) + { if (errno == EINTR) + continue ; + + psf_log_syserr (psf, errno) ; + break ; + } ; + + if (count == 0) + break ; + + total += count ; + items -= count ; + } ; + + if (psf->is_pipe) + psf->pipeoffset += total ; + + return total / bytes ; +} /* psf_fread */ + +sf_count_t +psf_fwrite (const void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf) +{ sf_count_t total = 0 ; + ssize_t count ; + + if (bytes == 0 || items == 0) + return 0 ; + + if (psf->virtual_io) + return psf->vio.write (ptr, bytes*items, psf->vio_user_data) / bytes ; + + items *= bytes ; + + /* Do this check after the multiplication above. */ + if (items <= 0) + return 0 ; + + while (items > 0) + { /* Break the writes down to a sensible size. */ + count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : items ; + + count = write (psf->file.filedes, ((const char*) ptr) + total, count) ; + + if (count == -1) + { if (errno == EINTR) + continue ; + + psf_log_syserr (psf, errno) ; + break ; + } ; + + if (count == 0) + break ; + + total += count ; + items -= count ; + } ; + + if (psf->is_pipe) + psf->pipeoffset += total ; + + return total / bytes ; +} /* psf_fwrite */ + +sf_count_t +psf_ftell (SF_PRIVATE *psf) +{ sf_count_t pos ; + + if (psf->virtual_io) + return psf->vio.tell (psf->vio_user_data) ; + + if (psf->is_pipe) + return psf->pipeoffset ; + + pos = lseek (psf->file.filedes, 0, SEEK_CUR) ; + + if (pos == ((sf_count_t) -1)) + { psf_log_syserr (psf, errno) ; + return -1 ; + } ; + + return pos - psf->fileoffset ; +} /* psf_ftell */ + +static int +psf_close_fd (int fd) +{ int retval ; + + if (fd < 0) + return 0 ; + + while ((retval = close (fd)) == -1 && errno == EINTR) + /* Do nothing. */ ; + + return retval ; +} /* psf_close_fd */ + +sf_count_t +psf_fgets (char *buffer, sf_count_t bufsize, SF_PRIVATE *psf) +{ sf_count_t k = 0 ; + sf_count_t count ; + + while (k < bufsize - 1) + { count = read (psf->file.filedes, &(buffer [k]), 1) ; + + if (count == -1) + { if (errno == EINTR) + continue ; + + psf_log_syserr (psf, errno) ; + break ; + } ; + + if (count == 0 || buffer [k++] == '\n') + break ; + } ; + + buffer [k] = 0 ; + + return k ; +} /* psf_fgets */ + +int +psf_is_pipe (SF_PRIVATE *psf) +{ struct stat statbuf ; + + if (psf->virtual_io) + return SF_FALSE ; + + if (fstat (psf->file.filedes, &statbuf) == -1) + { psf_log_syserr (psf, errno) ; + /* Default to maximum safety. */ + return SF_TRUE ; + } ; + + if (S_ISFIFO (statbuf.st_mode) || S_ISSOCK (statbuf.st_mode)) + return SF_TRUE ; + + return SF_FALSE ; +} /* psf_is_pipe */ + +static sf_count_t +psf_get_filelen_fd (int fd) +{ +#if (SIZEOF_OFF_T == 4 && HAVE_FSTAT64) + struct stat64 statbuf ; + + if (fstat64 (fd, &statbuf) == -1) + return (sf_count_t) -1 ; + + return statbuf.st_size ; +#else + struct stat statbuf ; + + if (fstat (fd, &statbuf) == -1) + return (sf_count_t) -1 ; + + return statbuf.st_size ; +#endif +} /* psf_get_filelen_fd */ + +int +psf_ftruncate (SF_PRIVATE *psf, sf_count_t len) +{ int retval ; + + /* Returns 0 on success, non-zero on failure. */ + if (len < 0) + return -1 ; + + if ((sizeof (off_t) < sizeof (sf_count_t)) && len > 0x7FFFFFFF) + return -1 ; + + retval = ftruncate (psf->file.filedes, len) ; + + if (retval == -1) + psf_log_syserr (psf, errno) ; + + return retval ; +} /* psf_ftruncate */ + +void +psf_init_files (SF_PRIVATE *psf) +{ psf->file.filedes = -1 ; + psf->rsrc.filedes = -1 ; + psf->file.savedes = -1 ; +} /* psf_init_files */ + +void +psf_use_rsrc (SF_PRIVATE *psf, int on_off) +{ + if (on_off) + { if (psf->file.filedes != psf->rsrc.filedes) + { psf->file.savedes = psf->file.filedes ; + psf->file.filedes = psf->rsrc.filedes ; + } ; + } + else if (psf->file.filedes == psf->rsrc.filedes) + psf->file.filedes = psf->file.savedes ; + + return ; +} /* psf_use_rsrc */ + +static int +psf_open_fd (PSF_FILE * pfile) +{ int fd, oflag, mode ; + + /* + ** Sanity check. If everything is OK, this test and the printfs will + ** be optimised out. This is meant to catch the problems caused by + ** "sfconfig.h" being included after . + */ + if (sizeof (sf_count_t) != 8) + { puts ("\n\n*** Fatal error : sizeof (sf_count_t) != 8") ; + puts ("*** This means that libsndfile was not configured correctly.\n") ; + exit (1) ; + } ; + + switch (pfile->mode) + { case SFM_READ : + oflag = O_RDONLY | O_BINARY ; + mode = 0 ; + break ; + + case SFM_WRITE : + oflag = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY ; + mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ; + break ; + + case SFM_RDWR : + oflag = O_RDWR | O_CREAT | O_BINARY ; + mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH ; + break ; + + default : + return - SFE_BAD_OPEN_MODE ; + break ; + } ; + + if (mode == 0) + fd = open (pfile->path, oflag) ; + else + fd = open (pfile->path, oflag, mode) ; + + return fd ; +} /* psf_open_fd */ + +static void +psf_log_syserr (SF_PRIVATE *psf, int error) +{ + /* Only log an error if no error has been set yet. */ + if (psf->error == 0) + { psf->error = SFE_SYSTEM ; + snprintf (psf->syserr, sizeof (psf->syserr), "System error : %s.", strerror (error)) ; + } ; + + return ; +} /* psf_log_syserr */ + +void +psf_fsync (SF_PRIVATE *psf) +{ +#if HAVE_FSYNC + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + fsync (psf->file.filedes) ; +#else + psf = NULL ; +#endif +} /* psf_fsync */ + +#else + +/* Win32 file i/o functions implemented using native Win32 API */ + +#ifndef WINAPI_PARTITION_SYSTEM +#define WINAPI_PARTITION_SYSTEM 0 +#endif + +static int psf_close_handle (HANDLE handle) ; +static HANDLE psf_open_handle (PSF_FILE * pfile) ; +static sf_count_t psf_get_filelen_handle (HANDLE handle) ; + +/* USE_WINDOWS_API */ int +psf_fopen (SF_PRIVATE *psf) +{ + psf->error = 0 ; + psf->file.handle = psf_open_handle (&psf->file) ; + + if (psf->file.handle == INVALID_HANDLE_VALUE) + psf_log_syserr (psf, GetLastError ()) ; + + return psf->error ; +} /* psf_fopen */ + +/* USE_WINDOWS_API */ int +psf_fclose (SF_PRIVATE *psf) +{ int retval ; + + if (psf->virtual_io) + return 0 ; + + if (psf->file.do_not_close_descriptor) + { psf->file.handle = INVALID_HANDLE_VALUE ; + return 0 ; + } ; + + if ((retval = psf_close_handle (psf->file.handle)) == -1) + psf_log_syserr (psf, GetLastError ()) ; + + psf->file.handle = INVALID_HANDLE_VALUE ; + + return retval ; +} /* psf_fclose */ + +/* USE_WINDOWS_API */ int +psf_open_rsrc (SF_PRIVATE *psf) +{ + if (psf->rsrc.handle != INVALID_HANDLE_VALUE) + return 0 ; + + /* Test for MacOSX style resource fork on HPFS or HPFS+ filesystems. */ + snprintf (psf->rsrc.path, sizeof (psf->rsrc.path), "%s/rsrc", psf->file.path) ; + psf->error = SFE_NO_ERROR ; + if ((psf->rsrc.handle = psf_open_handle (&psf->rsrc)) != INVALID_HANDLE_VALUE) + { psf->rsrclength = psf_get_filelen_handle (psf->rsrc.handle) ; + return SFE_NO_ERROR ; + } ; + + /* + ** Now try for a resource fork stored as a separate file in the same + ** directory, but preceded with a dot underscore. + */ + snprintf (psf->rsrc.path, sizeof (psf->rsrc.path), "%s._%s", psf->file.dir, psf->file.name) ; + psf->error = SFE_NO_ERROR ; + if ((psf->rsrc.handle = psf_open_handle (&psf->rsrc)) != INVALID_HANDLE_VALUE) + { psf->rsrclength = psf_get_filelen_handle (psf->rsrc.handle) ; + return SFE_NO_ERROR ; + } ; + + /* + ** Now try for a resource fork stored in a separate file in the + ** .AppleDouble/ directory. + */ + snprintf (psf->rsrc.path, sizeof (psf->rsrc.path), "%s.AppleDouble/%s", psf->file.dir, psf->file.name) ; + psf->error = SFE_NO_ERROR ; + if ((psf->rsrc.handle = psf_open_handle (&psf->rsrc)) != INVALID_HANDLE_VALUE) + { psf->rsrclength = psf_get_filelen_handle (psf->rsrc.handle) ; + return SFE_NO_ERROR ; + } ; + + /* No resource file found. */ + if (psf->rsrc.handle == INVALID_HANDLE_VALUE) + psf_log_syserr (psf, GetLastError ()) ; + + return psf->error ; +} /* psf_open_rsrc */ + +/* USE_WINDOWS_API */ sf_count_t +psf_get_filelen (SF_PRIVATE *psf) +{ sf_count_t filelen ; + + if (psf->virtual_io) + return psf->vio.get_filelen (psf->vio_user_data) ; + + filelen = psf_get_filelen_handle (psf->file.handle) ; + + if (filelen == -1) + { psf_log_syserr (psf, errno) ; + return (sf_count_t) -1 ; + } ; + + if (filelen == -SFE_BAD_STAT_SIZE) + { psf->error = SFE_BAD_STAT_SIZE ; + return (sf_count_t) -1 ; + } ; + + switch (psf->file.mode) + { case SFM_WRITE : + filelen = filelen - psf->fileoffset ; + break ; + + case SFM_READ : + if (psf->fileoffset > 0 && psf->filelength > 0) + filelen = psf->filelength ; + break ; + + case SFM_RDWR : + /* + ** Cannot open embedded files SFM_RDWR so we don't need to + ** subtract psf->fileoffset. We already have the answer we + ** need. + */ + break ; + + default : + /* Shouldn't be here, so return error. */ + filelen = -1 ; + } ; + + return filelen ; +} /* psf_get_filelen */ + +/* USE_WINDOWS_API */ void +psf_init_files (SF_PRIVATE *psf) +{ psf->file.handle = INVALID_HANDLE_VALUE ; + psf->rsrc.handle = INVALID_HANDLE_VALUE ; + psf->file.hsaved = INVALID_HANDLE_VALUE ; +} /* psf_init_files */ + +/* USE_WINDOWS_API */ void +psf_use_rsrc (SF_PRIVATE *psf, int on_off) +{ + if (on_off) + { if (psf->file.handle != psf->rsrc.handle) + { psf->file.hsaved = psf->file.handle ; + psf->file.handle = psf->rsrc.handle ; + } ; + } + else if (psf->file.handle == psf->rsrc.handle) + psf->file.handle = psf->file.hsaved ; + + return ; +} /* psf_use_rsrc */ + +/* USE_WINDOWS_API */ static HANDLE +psf_open_handle (PSF_FILE * pfile) +{ DWORD dwDesiredAccess ; + DWORD dwShareMode ; + DWORD dwCreationDistribution ; + HANDLE handle ; + LPWSTR pwszPath = NULL ; + + switch (pfile->mode) + { case SFM_READ : + dwDesiredAccess = GENERIC_READ ; + dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE ; + dwCreationDistribution = OPEN_EXISTING ; + break ; + + case SFM_WRITE : + dwDesiredAccess = GENERIC_WRITE ; + dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE ; + dwCreationDistribution = CREATE_ALWAYS ; + break ; + + case SFM_RDWR : + dwDesiredAccess = GENERIC_READ | GENERIC_WRITE ; + dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE ; + dwCreationDistribution = OPEN_ALWAYS ; + break ; + + default : + return INVALID_HANDLE_VALUE ; + } ; + + int nResult = MultiByteToWideChar (CP_UTF8, 0, pfile->path, -1, NULL, 0) ; + pwszPath = malloc (nResult * sizeof (WCHAR)) ; + if (!pwszPath) + return INVALID_HANDLE_VALUE ; + + int nResult2 = MultiByteToWideChar (CP_UTF8, 0, pfile->path, -1, pwszPath, nResult) ; + if (nResult != nResult2) + { free (pwszPath) ; + return INVALID_HANDLE_VALUE ; + } ; + +#if defined (WINAPI_FAMILY_PARTITION) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) + CREATEFILE2_EXTENDED_PARAMETERS cfParams = { 0 } ; + cfParams.dwSize = sizeof (CREATEFILE2_EXTENDED_PARAMETERS) ; + cfParams.dwFileAttributes = FILE_ATTRIBUTE_NORMAL ; + + handle = CreateFile2 (pwszPath, dwDesiredAccess, dwShareMode, dwCreationDistribution, &cfParams) ; +#else + handle = CreateFileW ( + pwszPath, /* pointer to name of the file */ + dwDesiredAccess, /* access (read-write) mode */ + dwShareMode, /* share mode */ + 0, /* pointer to security attributes */ + dwCreationDistribution, /* how to create */ + FILE_ATTRIBUTE_NORMAL, /* file attributes (could use FILE_FLAG_SEQUENTIAL_SCAN) */ + NULL /* handle to file with attributes to copy */ + ) ; +#endif + free (pwszPath) ; + + return handle ; +} /* psf_open_handle */ + +/* USE_WINDOWS_API */ static void +psf_log_syserr (SF_PRIVATE *psf, int error) +{ LPVOID lpMsgBuf ; + + /* Only log an error if no error has been set yet. */ + if (psf->error == 0) + { psf->error = SFE_SYSTEM ; + + FormatMessage ( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + error, + MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpMsgBuf, + 0, + NULL + ) ; + + snprintf (psf->syserr, sizeof (psf->syserr), "System error : %s", (char*) lpMsgBuf) ; + LocalFree (lpMsgBuf) ; + } ; + + return ; +} /* psf_log_syserr */ + + +/* USE_WINDOWS_API */ int +psf_close_rsrc (SF_PRIVATE *psf) +{ psf_close_handle (psf->rsrc.handle) ; + psf->rsrc.handle = INVALID_HANDLE_VALUE ; + return 0 ; +} /* psf_close_rsrc */ + + +/* USE_WINDOWS_API */ int +psf_set_stdio (SF_PRIVATE *psf) +{ HANDLE handle = INVALID_HANDLE_VALUE ; + int error = 0 ; + + switch (psf->file.mode) + { case SFM_RDWR : + error = SFE_OPEN_PIPE_RDWR ; + break ; + + case SFM_READ : + handle = GetStdHandle (STD_INPUT_HANDLE) ; + psf->file.do_not_close_descriptor = 1 ; + break ; + + case SFM_WRITE : + handle = GetStdHandle (STD_OUTPUT_HANDLE) ; + psf->file.do_not_close_descriptor = 1 ; + break ; + + default : + error = SFE_BAD_OPEN_MODE ; + break ; + } ; + + psf->file.handle = handle ; + psf->filelength = 0 ; + + return error ; +} /* psf_set_stdio */ + +/* USE_WINDOWS_API */ void +psf_set_file (SF_PRIVATE *psf, int fd) +{ HANDLE handle ; + intptr_t osfhandle ; + + osfhandle = _get_osfhandle (fd) ; + handle = (HANDLE) osfhandle ; + + psf->file.handle = handle ; +} /* psf_set_file */ + +/* USE_WINDOWS_API */ int +psf_file_valid (SF_PRIVATE *psf) +{ if (psf->file.handle == INVALID_HANDLE_VALUE) + return SF_FALSE ; + return SF_TRUE ; +} /* psf_set_file */ + +/* USE_WINDOWS_API */ sf_count_t +psf_fseek (SF_PRIVATE *psf, sf_count_t offset, int whence) +{ sf_count_t new_position ; + LARGE_INTEGER liDistanceToMove, liNewFilePointer ; + DWORD dwMoveMethod ; + BOOL fResult ; + DWORD dwError ; + + if (psf->virtual_io) + return psf->vio.seek (offset, whence, psf->vio_user_data) ; + + switch (whence) + { case SEEK_SET : + offset += psf->fileoffset ; + dwMoveMethod = FILE_BEGIN ; + break ; + + case SEEK_END : + dwMoveMethod = FILE_END ; + break ; + + default : + dwMoveMethod = FILE_CURRENT ; + break ; + } ; + + liDistanceToMove.QuadPart = offset ; + + fResult = SetFilePointerEx (psf->file.handle, liDistanceToMove, &liNewFilePointer, dwMoveMethod) ; + + if (fResult == FALSE) + dwError = GetLastError () ; + else + dwError = NO_ERROR ; + + if (dwError != NO_ERROR) + { psf_log_syserr (psf, dwError) ; + return -1 ; + } ; + + new_position = liNewFilePointer.QuadPart - psf->fileoffset ; + + return new_position ; +} /* psf_fseek */ + +/* USE_WINDOWS_API */ sf_count_t +psf_fread (void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf) +{ sf_count_t total = 0 ; + ssize_t count ; + DWORD dwNumberOfBytesRead ; + + if (psf->virtual_io) + return psf->vio.read (ptr, bytes*items, psf->vio_user_data) / bytes ; + + items *= bytes ; + + /* Do this check after the multiplication above. */ + if (items <= 0) + return 0 ; + + while (items > 0) + { /* Break the writes down to a sensible size. */ + count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : (ssize_t) items ; + + if (ReadFile (psf->file.handle, ((char*) ptr) + total, count, &dwNumberOfBytesRead, 0) == 0) + { psf_log_syserr (psf, GetLastError ()) ; + break ; + } + else + count = dwNumberOfBytesRead ; + + if (count == 0) + break ; + + total += count ; + items -= count ; + } ; + + if (psf->is_pipe) + psf->pipeoffset += total ; + + return total / bytes ; +} /* psf_fread */ + +/* USE_WINDOWS_API */ sf_count_t +psf_fwrite (const void *ptr, sf_count_t bytes, sf_count_t items, SF_PRIVATE *psf) +{ sf_count_t total = 0 ; + ssize_t count ; + DWORD dwNumberOfBytesWritten ; + + if (psf->virtual_io) + return psf->vio.write (ptr, bytes * items, psf->vio_user_data) / bytes ; + + items *= bytes ; + + /* Do this check after the multiplication above. */ + if (items <= 0) + return 0 ; + + while (items > 0) + { /* Break the writes down to a sensible size. */ + count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : (ssize_t) items ; + + if (WriteFile (psf->file.handle, ((const char*) ptr) + total, count, &dwNumberOfBytesWritten, 0) == 0) + { psf_log_syserr (psf, GetLastError ()) ; + break ; + } + else + count = dwNumberOfBytesWritten ; + + if (count == 0) + break ; + + total += count ; + items -= count ; + } ; + + if (psf->is_pipe) + psf->pipeoffset += total ; + + return total / bytes ; +} /* psf_fwrite */ + +/* USE_WINDOWS_API */ sf_count_t +psf_ftell (SF_PRIVATE *psf) +{ sf_count_t pos ; + LARGE_INTEGER liDistanceToMove, liNewFilePointer ; + BOOL fResult ; + DWORD dwError ; + + if (psf->virtual_io) + return psf->vio.tell (psf->vio_user_data) ; + + if (psf->is_pipe) + return psf->pipeoffset ; + + liDistanceToMove.QuadPart = 0 ; + + fResult = SetFilePointerEx (psf->file.handle, liDistanceToMove, &liNewFilePointer, FILE_CURRENT) ; + + if (fResult == FALSE) + dwError = GetLastError () ; + else + dwError = NO_ERROR ; + + if (dwError != NO_ERROR) + { psf_log_syserr (psf, dwError) ; + return -1 ; + } ; + + pos = liNewFilePointer.QuadPart ; + + return pos - psf->fileoffset ; +} /* psf_ftell */ + +/* USE_WINDOWS_API */ static int +psf_close_handle (HANDLE handle) +{ if (handle == INVALID_HANDLE_VALUE) + return 0 ; + + if (CloseHandle (handle) == 0) + return -1 ; + + return 0 ; +} /* psf_close_handle */ + +/* USE_WINDOWS_API */ sf_count_t +psf_fgets (char *buffer, sf_count_t bufsize, SF_PRIVATE *psf) +{ sf_count_t k = 0 ; + sf_count_t count ; + DWORD dwNumberOfBytesRead ; + + while (k < bufsize - 1) + { if (ReadFile (psf->file.handle, &(buffer [k]), 1, &dwNumberOfBytesRead, 0) == 0) + { psf_log_syserr (psf, GetLastError ()) ; + break ; + } + else + { count = dwNumberOfBytesRead ; + /* note that we only check for '\n' not other line endings such as CRLF */ + if (count == 0 || buffer [k++] == '\n') + break ; + } ; + } ; + + buffer [k] = 0 ; + + return k ; +} /* psf_fgets */ + +/* USE_WINDOWS_API */ int +psf_is_pipe (SF_PRIVATE *psf) +{ + if (psf->virtual_io) + return SF_FALSE ; + + if (GetFileType (psf->file.handle) == FILE_TYPE_DISK) + return SF_FALSE ; + + /* Default to maximum safety. */ + return SF_TRUE ; +} /* psf_is_pipe */ + +/* USE_WINDOWS_API */ sf_count_t +psf_get_filelen_handle (HANDLE handle) +{ sf_count_t filelen ; + LARGE_INTEGER liFileSize ; + BOOL fResult ; + DWORD dwError = NO_ERROR ; + + fResult = GetFileSizeEx (handle, &liFileSize) ; + + if (fResult == FALSE) + dwError = GetLastError () ; + + if (dwError != NO_ERROR) + return (sf_count_t) -1 ; + + filelen = liFileSize.QuadPart ; + + return filelen ; +} /* psf_get_filelen_handle */ + +/* USE_WINDOWS_API */ void +psf_fsync (SF_PRIVATE *psf) +{ FlushFileBuffers (psf->file.handle) ; +} /* psf_fsync */ + + +/* USE_WINDOWS_API */ int +psf_ftruncate (SF_PRIVATE *psf, sf_count_t len) +{ int retval = 0 ; + LARGE_INTEGER liDistanceToMove ; + BOOL fResult ; + DWORD dwError = NO_ERROR ; + + /* This implementation trashes the current file position. + ** should it save and restore it? what if the current position is past + ** the new end of file? + */ + + /* Returns 0 on success, non-zero on failure. */ + if (len < 0) + return 1 ; + + liDistanceToMove.QuadPart = (sf_count_t) len ; + + fResult = SetFilePointerEx (psf->file.handle, liDistanceToMove, NULL, FILE_BEGIN) ; + + if (fResult == FALSE) + dwError = GetLastError () ; + + if (dwError != NO_ERROR) + { retval = -1 ; + psf_log_syserr (psf, dwError) ; + } + else + { /* Note: when SetEndOfFile is used to extend a file, the contents of the + ** new portion of the file is undefined. This is unlike chsize(), + ** which guarantees that the new portion of the file will be zeroed. + ** Not sure if this is important or not. + */ + if (SetEndOfFile (psf->file.handle) == 0) + { retval = -1 ; + psf_log_syserr (psf, GetLastError ()) ; + } ; + } ; + + return retval ; +} /* psf_ftruncate */ + +#endif + diff --git a/extern/libsndfile-modified/src/flac.c b/extern/libsndfile-modified/src/flac.c new file mode 100644 index 000000000..073ce553d --- /dev/null +++ b/extern/libsndfile-modified/src/flac.c @@ -0,0 +1,1463 @@ +/* +** Copyright (C) 2004-2017 Erik de Castro Lopo +** Copyright (C) 2004 Tobias Gehrig +** +** This program is free software ; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation ; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY ; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program ; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include +#include +#include + +#include "sndfile.h" +#include "common.h" + +#if HAVE_EXTERNAL_XIPH_LIBS + +#include +#include +#include + +/*------------------------------------------------------------------------------ +** Private static functions. +*/ + +#define FLAC_DEFAULT_COMPRESSION_LEVEL 5 + +#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, + PFLAC_PCM_FLOAT = 52, + PFLAC_PCM_DOUBLE = 53 +} PFLAC_PCM ; + +typedef struct +{ + FLAC__StreamDecoder *fsd ; + FLAC__StreamEncoder *fse ; + + PFLAC_PCM pcmtype ; + void* ptr ; + unsigned pos, len, remain ; + + FLAC__StreamMetadata *metadata ; + + const int32_t * const * wbuffer ; + int32_t * rbuffer [FLAC__MAX_CHANNELS] ; + + int32_t* encbuffer ; + unsigned bufferpos ; + + const FLAC__Frame *frame ; + + unsigned compression ; + +} FLAC_PRIVATE ; + +typedef struct +{ const char *tag ; + int type ; +} FLAC_TAG ; + +static sf_count_t flac_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ; +static int flac_byterate (SF_PRIVATE *psf) ; +static int flac_close (SF_PRIVATE *psf) ; + +static int flac_enc_init (SF_PRIVATE *psf) ; +static int flac_read_header (SF_PRIVATE *psf) ; + +static sf_count_t flac_read_flac2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; +static sf_count_t flac_read_flac2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; +static sf_count_t flac_read_flac2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; +static sf_count_t flac_read_flac2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; + +static sf_count_t flac_write_s2flac (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; +static sf_count_t flac_write_i2flac (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; +static sf_count_t flac_write_f2flac (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; +static sf_count_t flac_write_d2flac (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; + +static void f2flac8_array (const float *src, int32_t *dest, int count, int normalize) ; +static void f2flac16_array (const float *src, int32_t *dest, int count, int normalize) ; +static void f2flac24_array (const float *src, int32_t *dest, int count, int normalize) ; +static void f2flac8_clip_array (const float *src, int32_t *dest, int count, int normalize) ; +static void f2flac16_clip_array (const float *src, int32_t *dest, int count, int normalize) ; +static void f2flac24_clip_array (const float *src, int32_t *dest, int count, int normalize) ; +static void d2flac8_array (const double *src, int32_t *dest, int count, int normalize) ; +static void d2flac16_array (const double *src, int32_t *dest, int count, int normalize) ; +static void d2flac24_array (const double *src, int32_t *dest, int count, int normalize) ; +static void d2flac8_clip_array (const double *src, int32_t *dest, int count, int normalize) ; +static void d2flac16_clip_array (const double *src, int32_t *dest, int count, int normalize) ; +static void d2flac24_clip_array (const double *src, int32_t *dest, int count, int normalize) ; + +static int flac_command (SF_PRIVATE *psf, int command, void *data, int datasize) ; + +/* Decoder Callbacks */ +static FLAC__StreamDecoderReadStatus sf_flac_read_callback (const FLAC__StreamDecoder *decoder, FLAC__byte buffer [], size_t *bytes, void *client_data) ; +static FLAC__StreamDecoderSeekStatus sf_flac_seek_callback (const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data) ; +static FLAC__StreamDecoderTellStatus sf_flac_tell_callback (const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data) ; +static FLAC__StreamDecoderLengthStatus sf_flac_length_callback (const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data) ; +static FLAC__bool sf_flac_eof_callback (const FLAC__StreamDecoder *decoder, void *client_data) ; +static FLAC__StreamDecoderWriteStatus sf_flac_write_callback (const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const int32_t * const buffer [], void *client_data) ; +static void sf_flac_meta_callback (const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data) ; +static void sf_flac_error_callback (const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data) ; + +/* Encoder Callbacks */ +static FLAC__StreamEncoderSeekStatus sf_flac_enc_seek_callback (const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data) ; +static FLAC__StreamEncoderTellStatus sf_flac_enc_tell_callback (const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data) ; +static FLAC__StreamEncoderWriteStatus sf_flac_enc_write_callback (const FLAC__StreamEncoder *encoder, const FLAC__byte buffer [], size_t bytes, unsigned samples, unsigned current_frame, void *client_data) ; + +static void +s2flac8_array (const short *src, int32_t *dest, int count) +{ for (int i = 0 ; i < count ; i++) + dest [i] = src [i] >> 8 ; +} /* s2flac8_array */ + +static void +s2flac16_array (const short *src, int32_t *dest, int count) +{ for (int i = 0 ; i < count ; i++) + dest [i] = src [i] ; +} /* s2flac16_array */ + +static void +s2flac24_array (const short *src, int32_t *dest, int count) +{ for (int i = 0 ; i < count ; i++) + dest [i] = src [i] << 8 ; +} /* s2flac24_array */ + +static void +i2flac8_array (const int *src, int32_t *dest, int count) +{ for (int i = 0 ; i < count ; i++) + dest [i] = src [i] >> 24 ; +} /* i2flac8_array */ + +static void +i2flac16_array (const int *src, int32_t *dest, int count) +{ + for (int i = 0 ; i < count ; i++) + dest [i] = src [i] >> 16 ; +} /* i2flac16_array */ + +static void +i2flac24_array (const int *src, int32_t *dest, int count) +{ for (int i = 0 ; i < count ; i++) + dest [i] = src [i] >> 8 ; +} /* i2flac24_array */ + +static sf_count_t +flac_buffer_copy (SF_PRIVATE *psf) +{ FLAC_PRIVATE* pflac = (FLAC_PRIVATE*) psf->codec_data ; + const FLAC__Frame *frame = pflac->frame ; + const int32_t* const *buffer = pflac->wbuffer ; + unsigned i = 0, j, offset, channels, len ; + + if (psf->sf.channels != (int) frame->header.channels) + { psf_log_printf (psf, "Error: FLAC frame changed from %d to %d channels\n" + "Nothing to do but to error out.\n" , + psf->sf.channels, frame->header.channels) ; + psf->error = SFE_FLAC_CHANNEL_COUNT_CHANGED ; + return 0 ; + } ; + + /* + ** frame->header.blocksize is variable and we're using a constant blocksize + ** of FLAC__MAX_BLOCK_SIZE. + ** Check our assumptions here. + */ + if (frame->header.blocksize > FLAC__MAX_BLOCK_SIZE) + { psf_log_printf (psf, "Ooops : frame->header.blocksize (%d) > FLAC__MAX_BLOCK_SIZE (%d)\n", __func__, __LINE__, frame->header.blocksize, FLAC__MAX_BLOCK_SIZE) ; + psf->error = SFE_INTERNAL ; + return 0 ; + } ; + + if (frame->header.channels > FLAC__MAX_CHANNELS) + psf_log_printf (psf, "Ooops : frame->header.channels (%d) > FLAC__MAX_BLOCK_SIZE (%d)\n", __func__, __LINE__, frame->header.channels, FLAC__MAX_CHANNELS) ; + + channels = SF_MIN (frame->header.channels, FLAC__MAX_CHANNELS) ; + + if (pflac->ptr == NULL) + { /* + ** This pointer is reset to NULL each time the current frame has been + ** decoded. Somehow its used during encoding and decoding. + */ + for (i = 0 ; i < channels ; i++) + { + if (pflac->rbuffer [i] == NULL) + pflac->rbuffer [i] = calloc (FLAC__MAX_BLOCK_SIZE, sizeof (int32_t)) ; + + memcpy (pflac->rbuffer [i], buffer [i], frame->header.blocksize * sizeof (int32_t)) ; + } ; + pflac->wbuffer = (const int32_t* const*) pflac->rbuffer ; + + return 0 ; + } ; + + len = SF_MIN (pflac->len, frame->header.blocksize) ; + + if (pflac->remain % channels != 0) + { psf_log_printf (psf, "Error: pflac->remain %u channels %u\n", pflac->remain, channels) ; + return 0 ; + } ; + + switch (pflac->pcmtype) + { case PFLAC_PCM_SHORT : + { short *retpcm = (short*) pflac->ptr ; + int shift = 16 - frame->header.bits_per_sample ; + if (shift < 0) + { shift = abs (shift) ; + for (i = 0 ; i < len && pflac->remain > 0 ; i++) + { offset = pflac->pos + i * channels ; + + if (pflac->bufferpos >= frame->header.blocksize) + break ; + + if (offset + channels > pflac->len) + break ; + + for (j = 0 ; j < channels ; j++) + retpcm [offset + j] = buffer [j][pflac->bufferpos] >> shift ; + pflac->remain -= channels ; + pflac->bufferpos ++ ; + } + } + else + { for (i = 0 ; i < len && pflac->remain > 0 ; i++) + { offset = pflac->pos + i * channels ; + + if (pflac->bufferpos >= frame->header.blocksize) + break ; + + if (offset + channels > pflac->len) + break ; + + for (j = 0 ; j < channels ; j++) + retpcm [offset + j] = ((uint16_t) buffer [j][pflac->bufferpos]) << shift ; + + pflac->remain -= channels ; + pflac->bufferpos ++ ; + } ; + } ; + } ; + break ; + + case PFLAC_PCM_INT : + { int *retpcm = (int*) pflac->ptr ; + int shift = 32 - frame->header.bits_per_sample ; + for (i = 0 ; i < len && pflac->remain > 0 ; i++) + { offset = pflac->pos + i * channels ; + + if (pflac->bufferpos >= frame->header.blocksize) + break ; + + if (offset + channels > pflac->len) + break ; + + for (j = 0 ; j < channels ; j++) + retpcm [offset + j] = ((uint32_t) buffer [j][pflac->bufferpos]) << shift ; + pflac->remain -= channels ; + pflac->bufferpos++ ; + } ; + } ; + break ; + + case PFLAC_PCM_FLOAT : + { float *retpcm = (float*) pflac->ptr ; + float norm = (psf->norm_float == SF_TRUE) ? 1.0 / (1 << (frame->header.bits_per_sample - 1)) : 1.0 ; + + for (i = 0 ; i < len && pflac->remain > 0 ; i++) + { offset = pflac->pos + i * channels ; + + if (pflac->bufferpos >= frame->header.blocksize) + break ; + + if (offset + channels > pflac->len) + break ; + + for (j = 0 ; j < channels ; j++) + retpcm [offset + j] = buffer [j][pflac->bufferpos] * norm ; + pflac->remain -= channels ; + pflac->bufferpos++ ; + } ; + } ; + break ; + + case PFLAC_PCM_DOUBLE : + { double *retpcm = (double*) pflac->ptr ; + double norm = (psf->norm_double == SF_TRUE) ? 1.0 / (1 << (frame->header.bits_per_sample - 1)) : 1.0 ; + + for (i = 0 ; i < len && pflac->remain > 0 ; i++) + { offset = pflac->pos + i * channels ; + + if (pflac->bufferpos >= frame->header.blocksize) + break ; + + if (offset + channels > pflac->len) + break ; + + for (j = 0 ; j < channels ; j++) + retpcm [offset + j] = buffer [j][pflac->bufferpos] * norm ; + pflac->remain -= channels ; + pflac->bufferpos++ ; + } ; + } ; + break ; + + default : + return 0 ; + } ; + + offset = i * channels ; + pflac->pos += i * channels ; + + return offset ; +} /* flac_buffer_copy */ + + +static FLAC__StreamDecoderReadStatus +sf_flac_read_callback (const FLAC__StreamDecoder * UNUSED (decoder), FLAC__byte buffer [], size_t *bytes, void *client_data) +{ SF_PRIVATE *psf = (SF_PRIVATE*) client_data ; + + *bytes = psf_fread (buffer, 1, *bytes, psf) ; + if (*bytes > 0 && psf->error == 0) + return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE ; + + return FLAC__STREAM_DECODER_READ_STATUS_ABORT ; +} /* sf_flac_read_callback */ + +static FLAC__StreamDecoderSeekStatus +sf_flac_seek_callback (const FLAC__StreamDecoder * UNUSED (decoder), FLAC__uint64 absolute_byte_offset, void *client_data) +{ SF_PRIVATE *psf = (SF_PRIVATE*) client_data ; + + psf_fseek (psf, absolute_byte_offset, SEEK_SET) ; + if (psf->error) + return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR ; + + return FLAC__STREAM_DECODER_SEEK_STATUS_OK ; +} /* sf_flac_seek_callback */ + +static FLAC__StreamDecoderTellStatus +sf_flac_tell_callback (const FLAC__StreamDecoder * UNUSED (decoder), FLAC__uint64 *absolute_byte_offset, void *client_data) +{ SF_PRIVATE *psf = (SF_PRIVATE*) client_data ; + + *absolute_byte_offset = psf_ftell (psf) ; + if (psf->error) + return FLAC__STREAM_DECODER_TELL_STATUS_ERROR ; + + return FLAC__STREAM_DECODER_TELL_STATUS_OK ; +} /* sf_flac_tell_callback */ + +static FLAC__StreamDecoderLengthStatus +sf_flac_length_callback (const FLAC__StreamDecoder * UNUSED (decoder), FLAC__uint64 *stream_length, void *client_data) +{ SF_PRIVATE *psf = (SF_PRIVATE*) client_data ; + + if ((*stream_length = psf->filelength) == 0) + return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR ; + + return FLAC__STREAM_DECODER_LENGTH_STATUS_OK ; +} /* sf_flac_length_callback */ + +static FLAC__bool +sf_flac_eof_callback (const FLAC__StreamDecoder *UNUSED (decoder), void *client_data) +{ SF_PRIVATE *psf = (SF_PRIVATE*) client_data ; + + if (psf_ftell (psf) == psf->filelength) + return SF_TRUE ; + + return SF_FALSE ; +} /* sf_flac_eof_callback */ + +static FLAC__StreamDecoderWriteStatus +sf_flac_write_callback (const FLAC__StreamDecoder * UNUSED (decoder), const FLAC__Frame *frame, const int32_t * const buffer [], void *client_data) +{ SF_PRIVATE *psf = (SF_PRIVATE*) client_data ; + FLAC_PRIVATE* pflac = (FLAC_PRIVATE*) psf->codec_data ; + + pflac->frame = frame ; + pflac->bufferpos = 0 ; + + pflac->wbuffer = buffer ; + + flac_buffer_copy (psf) ; + + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE ; +} /* sf_flac_write_callback */ + +static void +sf_flac_meta_get_vorbiscomments (SF_PRIVATE *psf, const FLAC__StreamMetadata *metadata) +{ static FLAC_TAG tags [] = + { { "title", SF_STR_TITLE }, + { "copyright", SF_STR_COPYRIGHT }, + { "software", SF_STR_SOFTWARE }, + { "artist", SF_STR_ARTIST }, + { "comment", SF_STR_COMMENT }, + { "date", SF_STR_DATE }, + { "album", SF_STR_ALBUM }, + { "license", SF_STR_LICENSE }, + { "tracknumber", SF_STR_TRACKNUMBER }, + { "genre", SF_STR_GENRE } + } ; + + const char *value, *cptr ; + int k, tag_num ; + + for (k = 0 ; k < ARRAY_LEN (tags) ; k++) + { tag_num = FLAC__metadata_object_vorbiscomment_find_entry_from (metadata, 0, tags [k].tag) ; + + if (tag_num < 0) + continue ; + + value = (const char*) metadata->data.vorbis_comment.comments [tag_num].entry ; + if ((cptr = strchr (value, '=')) != NULL) + value = cptr + 1 ; + + psf_log_printf (psf, " %-12s : %s\n", tags [k].tag, value) ; + psf_store_string (psf, tags [k].type, value) ; + } ; + + return ; +} /* sf_flac_meta_get_vorbiscomments */ + +static void +sf_flac_meta_callback (const FLAC__StreamDecoder * UNUSED (decoder), const FLAC__StreamMetadata *metadata, void *client_data) +{ SF_PRIVATE *psf = (SF_PRIVATE*) client_data ; + int bitwidth = 0 ; + + switch (metadata->type) + { case FLAC__METADATA_TYPE_STREAMINFO : + if (psf->sf.channels > 0 && psf->sf.channels != (int) metadata->data.stream_info.channels) + { psf_log_printf (psf, "Error: FLAC stream changed from %d to %d channels\n" + "Nothing to do but to error out.\n" , + psf->sf.channels, metadata->data.stream_info.channels) ; + psf->error = SFE_FLAC_CHANNEL_COUNT_CHANGED ; + return ; + } ; + + if (psf->sf.channels > 0 && psf->sf.samplerate != (int) metadata->data.stream_info.sample_rate) + { psf_log_printf (psf, "Warning: FLAC stream changed sample rates from %d to %d.\n" + "Carrying on as if nothing happened.", + psf->sf.samplerate, metadata->data.stream_info.sample_rate) ; + } ; + psf->sf.channels = metadata->data.stream_info.channels ; + psf->sf.samplerate = metadata->data.stream_info.sample_rate ; + psf->sf.frames = metadata->data.stream_info.total_samples ; + + psf_log_printf (psf, "FLAC Stream Metadata\n Channels : %d\n Sample rate : %d\n", psf->sf.channels, psf->sf.samplerate) ; + + if (psf->sf.frames == 0) + { psf_log_printf (psf, " Frames : 0 (bumping to SF_COUNT_MAX)\n") ; + psf->sf.frames = SF_COUNT_MAX ; + } + else + psf_log_printf (psf, " Frames : %D\n", psf->sf.frames) ; + + switch (metadata->data.stream_info.bits_per_sample) + { case 8 : + psf->sf.format |= SF_FORMAT_PCM_S8 ; + bitwidth = 8 ; + break ; + case 16 : + psf->sf.format |= SF_FORMAT_PCM_16 ; + bitwidth = 16 ; + break ; + case 24 : + psf->sf.format |= SF_FORMAT_PCM_24 ; + bitwidth = 24 ; + break ; + default : + psf_log_printf (psf, "sf_flac_meta_callback : bits_per_sample %d not yet implemented.\n", metadata->data.stream_info.bits_per_sample) ; + break ; + } ; + + if (bitwidth > 0) + psf_log_printf (psf, " Bit width : %d\n", bitwidth) ; + break ; + + case FLAC__METADATA_TYPE_VORBIS_COMMENT : + psf_log_printf (psf, "Vorbis Comment Metadata\n") ; + sf_flac_meta_get_vorbiscomments (psf, metadata) ; + break ; + + case FLAC__METADATA_TYPE_PADDING : + psf_log_printf (psf, "Padding Metadata\n") ; + break ; + + case FLAC__METADATA_TYPE_APPLICATION : + psf_log_printf (psf, "Application Metadata\n") ; + break ; + + case FLAC__METADATA_TYPE_SEEKTABLE : + psf_log_printf (psf, "Seektable Metadata\n") ; + break ; + + case FLAC__METADATA_TYPE_CUESHEET : + psf_log_printf (psf, "Cuesheet Metadata\n") ; + break ; + + case FLAC__METADATA_TYPE_PICTURE : + psf_log_printf (psf, "Picture Metadata\n") ; + break ; + + case FLAC__METADATA_TYPE_UNDEFINED : + psf_log_printf (psf, "Undefined Metadata\n") ; + break ; + + default : + psf_log_printf (psf, "sf_flac_meta_callback : metadata-type %d not yet implemented.\n", metadata->type) ; + break ; + } ; + + return ; +} /* sf_flac_meta_callback */ + +static void +sf_flac_error_callback (const FLAC__StreamDecoder * UNUSED (decoder), FLAC__StreamDecoderErrorStatus status, void *client_data) +{ SF_PRIVATE *psf = (SF_PRIVATE*) client_data ; + + psf_log_printf (psf, "ERROR : %s\n", FLAC__StreamDecoderErrorStatusString [status]) ; + + switch (status) + { case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC : + psf->error = SFE_FLAC_LOST_SYNC ; + break ; + case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER : + psf->error = SFE_FLAC_BAD_HEADER ; + break ; + default : + psf->error = SFE_FLAC_UNKOWN_ERROR ; + break ; + } ; + + return ; +} /* sf_flac_error_callback */ + +static FLAC__StreamEncoderSeekStatus +sf_flac_enc_seek_callback (const FLAC__StreamEncoder * UNUSED (encoder), FLAC__uint64 absolute_byte_offset, void *client_data) +{ SF_PRIVATE *psf = (SF_PRIVATE*) client_data ; + + psf_fseek (psf, absolute_byte_offset, SEEK_SET) ; + if (psf->error) + return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR ; + + return FLAC__STREAM_ENCODER_SEEK_STATUS_OK ; +} /* sf_flac_enc_seek_callback */ + +static FLAC__StreamEncoderTellStatus +sf_flac_enc_tell_callback (const FLAC__StreamEncoder *UNUSED (encoder), FLAC__uint64 *absolute_byte_offset, void *client_data) +{ SF_PRIVATE *psf = (SF_PRIVATE*) client_data ; + + *absolute_byte_offset = psf_ftell (psf) ; + if (psf->error) + return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR ; + + return FLAC__STREAM_ENCODER_TELL_STATUS_OK ; +} /* sf_flac_enc_tell_callback */ + +static FLAC__StreamEncoderWriteStatus +sf_flac_enc_write_callback (const FLAC__StreamEncoder * UNUSED (encoder), const FLAC__byte buffer [], size_t bytes, unsigned UNUSED (samples), unsigned UNUSED (current_frame), void *client_data) +{ SF_PRIVATE *psf = (SF_PRIVATE*) client_data ; + + if (psf_fwrite (buffer, 1, bytes, psf) == (sf_count_t) bytes && psf->error == 0) + return FLAC__STREAM_ENCODER_WRITE_STATUS_OK ; + + return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR ; +} /* sf_flac_enc_write_callback */ + +static void +flac_write_strings (SF_PRIVATE *psf, FLAC_PRIVATE* pflac) +{ FLAC__StreamMetadata_VorbisComment_Entry entry ; + int k, string_count = 0 ; + + for (k = 0 ; k < SF_MAX_STRINGS ; k++) + { if (psf->strings.data [k].type != 0) + string_count ++ ; + } ; + + if (string_count == 0) + return ; + + if (pflac->metadata == NULL && (pflac->metadata = FLAC__metadata_object_new (FLAC__METADATA_TYPE_VORBIS_COMMENT)) == NULL) + { psf_log_printf (psf, "FLAC__metadata_object_new returned NULL\n") ; + return ; + } ; + + for (k = 0 ; k < SF_MAX_STRINGS && psf->strings.data [k].type != 0 ; k++) + { const char * key, * value ; + + switch (psf->strings.data [k].type) + { case SF_STR_SOFTWARE : + key = "software" ; + break ; + case SF_STR_TITLE : + key = "title" ; + break ; + case SF_STR_COPYRIGHT : + key = "copyright" ; + break ; + case SF_STR_ARTIST : + key = "artist" ; + break ; + case SF_STR_COMMENT : + key = "comment" ; + break ; + case SF_STR_DATE : + key = "date" ; + break ; + case SF_STR_ALBUM : + key = "album" ; + break ; + case SF_STR_LICENSE : + key = "license" ; + break ; + case SF_STR_TRACKNUMBER : + key = "tracknumber" ; + break ; + case SF_STR_GENRE : + key = "genre" ; + break ; + default : + continue ; + } ; + + value = psf->strings.storage + psf->strings.data [k].offset ; + + FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair (&entry, key, value) ; + FLAC__metadata_object_vorbiscomment_append_comment (pflac->metadata, entry, /* copy */ SF_FALSE) ; + } ; + + if (! FLAC__stream_encoder_set_metadata (pflac->fse, &pflac->metadata, 1)) + { printf ("%s %d : fail\n", __func__, __LINE__) ; + return ; + } ; + + return ; +} /* flac_write_strings */ + +static int +flac_write_header (SF_PRIVATE *psf, int UNUSED (calc_length)) +{ FLAC_PRIVATE* pflac = (FLAC_PRIVATE*) psf->codec_data ; + int err ; + + flac_write_strings (psf, pflac) ; + + if ((err = FLAC__stream_encoder_init_stream (pflac->fse, sf_flac_enc_write_callback, sf_flac_enc_seek_callback, sf_flac_enc_tell_callback, NULL, psf)) != FLAC__STREAM_DECODER_INIT_STATUS_OK) + { psf_log_printf (psf, "Error : FLAC encoder init returned error : %s\n", FLAC__StreamEncoderInitStatusString [err]) ; + return SFE_FLAC_INIT_DECODER ; + } ; + + if (psf->error == 0) + psf->dataoffset = psf_ftell (psf) ; + pflac->encbuffer = calloc (ENC_BUFFER_SIZE, sizeof (int32_t)) ; + + /* can only call init_stream once */ + psf->write_header = NULL ; + + return psf->error ; +} /* flac_write_header */ + +/*------------------------------------------------------------------------------ +** Public function. +*/ + +int +flac_open (SF_PRIVATE *psf) +{ int subformat ; + int error = 0 ; + + FLAC_PRIVATE* pflac = calloc (1, sizeof (FLAC_PRIVATE)) ; + psf->codec_data = pflac ; + + /* Set the default value here. Over-ridden later if necessary. */ + pflac->compression = FLAC_DEFAULT_COMPRESSION_LEVEL ; + + if (psf->file.mode == SFM_RDWR) + return SFE_BAD_MODE_RW ; + + if (psf->file.mode == SFM_READ) + { if ((error = flac_read_header (psf))) + return error ; + } ; + + subformat = SF_CODEC (psf->sf.format) ; + + if (psf->file.mode == SFM_WRITE) + { if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_FLAC) + return SFE_BAD_OPEN_FORMAT ; + + psf->endian = SF_ENDIAN_BIG ; + psf->sf.seekable = 0 ; + + psf->strings.flags = SF_STR_ALLOW_START ; + + if ((error = flac_enc_init (psf))) + return error ; + + /* In an ideal world we would write the header at this point. Unfortunately + ** that would prevent string metadata being added so we have to hold off. + */ + + psf->write_header = flac_write_header ; + } ; + + psf->datalength = psf->filelength ; + psf->dataoffset = 0 ; + + psf->container_close = flac_close ; + psf->seek = flac_seek ; + psf->byterate = flac_byterate ; + + psf->command = flac_command ; + + switch (subformat) + { case SF_FORMAT_PCM_S8 : /* 8-bit FLAC. */ + case SF_FORMAT_PCM_16 : /* 16-bit FLAC. */ + case SF_FORMAT_PCM_24 : /* 24-bit FLAC. */ + error = flac_init (psf) ; + break ; + + default : return SFE_UNIMPLEMENTED ; + } ; + + return error ; +} /* flac_open */ + +/*------------------------------------------------------------------------------ +*/ + +static int +flac_close (SF_PRIVATE *psf) +{ FLAC_PRIVATE* pflac ; + int k ; + + if ((pflac = (FLAC_PRIVATE*) psf->codec_data) == NULL) + return 0 ; + + if (pflac->metadata != NULL) + FLAC__metadata_object_delete (pflac->metadata) ; + + if (psf->file.mode == SFM_WRITE) + { FLAC__stream_encoder_finish (pflac->fse) ; + FLAC__stream_encoder_delete (pflac->fse) ; + free (pflac->encbuffer) ; + } ; + + if (psf->file.mode == SFM_READ) + { FLAC__stream_decoder_finish (pflac->fsd) ; + FLAC__stream_decoder_delete (pflac->fsd) ; + } ; + + for (k = 0 ; k < ARRAY_LEN (pflac->rbuffer) ; k++) + free (pflac->rbuffer [k]) ; + + free (pflac) ; + psf->codec_data = NULL ; + + return 0 ; +} /* flac_close */ + +static int +flac_enc_init (SF_PRIVATE *psf) +{ FLAC_PRIVATE* pflac = (FLAC_PRIVATE*) psf->codec_data ; + unsigned bps ; + + /* To cite the flac FAQ at + ** http://flac.sourceforge.net/faq.html#general__samples + ** "FLAC supports linear sample rates from 1Hz - 655350Hz in 1Hz + ** increments." + */ + if (psf->sf.samplerate < 1 || psf->sf.samplerate > 655350) + { psf_log_printf (psf, "flac sample rate out of range.\n", psf->sf.samplerate) ; + return SFE_FLAC_BAD_SAMPLE_RATE ; + } ; + + psf_fseek (psf, 0, SEEK_SET) ; + + switch (SF_CODEC (psf->sf.format)) + { case SF_FORMAT_PCM_S8 : + bps = 8 ; + break ; + case SF_FORMAT_PCM_16 : + bps = 16 ; + break ; + case SF_FORMAT_PCM_24 : + bps = 24 ; + break ; + + default : + bps = 0 ; + break ; + } ; + + if (pflac->fse) + FLAC__stream_encoder_delete (pflac->fse) ; + if ((pflac->fse = FLAC__stream_encoder_new ()) == NULL) + return SFE_FLAC_NEW_DECODER ; + + if (! FLAC__stream_encoder_set_channels (pflac->fse, psf->sf.channels)) + { psf_log_printf (psf, "FLAC__stream_encoder_set_channels (%d) return false.\n", psf->sf.channels) ; + return SFE_FLAC_INIT_DECODER ; + } ; + + if (! FLAC__stream_encoder_set_sample_rate (pflac->fse, psf->sf.samplerate)) + { psf_log_printf (psf, "FLAC__stream_encoder_set_sample_rate (%d) returned false.\n", psf->sf.samplerate) ; + return SFE_FLAC_BAD_SAMPLE_RATE ; + } ; + + if (! FLAC__stream_encoder_set_bits_per_sample (pflac->fse, bps)) + { psf_log_printf (psf, "FLAC__stream_encoder_set_bits_per_sample (%d) return false.\n", bps) ; + return SFE_FLAC_INIT_DECODER ; + } ; + + if (! FLAC__stream_encoder_set_compression_level (pflac->fse, pflac->compression)) + { psf_log_printf (psf, "FLAC__stream_encoder_set_compression_level (%d) return false.\n", pflac->compression) ; + return SFE_FLAC_INIT_DECODER ; + } ; + + return 0 ; +} /* flac_enc_init */ + +static int +flac_read_header (SF_PRIVATE *psf) +{ FLAC_PRIVATE* pflac = (FLAC_PRIVATE*) psf->codec_data ; + + psf_fseek (psf, 0, SEEK_SET) ; + if (pflac->fsd) + FLAC__stream_decoder_delete (pflac->fsd) ; + if ((pflac->fsd = FLAC__stream_decoder_new ()) == NULL) + return SFE_FLAC_NEW_DECODER ; + + FLAC__stream_decoder_set_metadata_respond_all (pflac->fsd) ; + + if (FLAC__stream_decoder_init_stream (pflac->fsd, sf_flac_read_callback, sf_flac_seek_callback, sf_flac_tell_callback, sf_flac_length_callback, sf_flac_eof_callback, sf_flac_write_callback, sf_flac_meta_callback, sf_flac_error_callback, psf) != FLAC__STREAM_DECODER_INIT_STATUS_OK) + return SFE_FLAC_INIT_DECODER ; + + FLAC__stream_decoder_process_until_end_of_metadata (pflac->fsd) ; + + psf_log_printf (psf, "End\n") ; + + if (psf->error != 0) + FLAC__stream_decoder_delete (pflac->fsd) ; + else + { FLAC__uint64 position ; + + FLAC__stream_decoder_get_decode_position (pflac->fsd, &position) ; + psf->dataoffset = position ; + } ; + + return psf->error ; +} /* flac_read_header */ + +static int +flac_command (SF_PRIVATE * psf, int command, void * data, int datasize) +{ FLAC_PRIVATE* pflac = (FLAC_PRIVATE*) psf->codec_data ; + double quality ; + + switch (command) + { case SFC_SET_COMPRESSION_LEVEL : + if (data == NULL || datasize != sizeof (double)) + return SF_FALSE ; + + if (psf->have_written) + return SF_FALSE ; + + /* FLAC compression level is in the range [0, 8] while libsndfile takes + ** values in the range [0.0, 1.0]. Massage the libsndfile value here. + */ + quality = (*((double *) data)) * 8.0 ; + /* Clip range. */ + pflac->compression = psf_lrint (SF_MAX (0.0, SF_MIN (8.0, quality))) ; + + psf_log_printf (psf, "%s : Setting SFC_SET_COMPRESSION_LEVEL to %u.\n", __func__, pflac->compression) ; + + if (flac_enc_init (psf)) + return SF_FALSE ; + + return SF_TRUE ; + + default : + return SF_FALSE ; + } ; + + return SF_FALSE ; +} /* flac_command */ + +int +flac_init (SF_PRIVATE *psf) +{ + if (psf->file.mode == SFM_RDWR) + return SFE_BAD_MODE_RW ; + + if (psf->file.mode == SFM_READ) + { psf->read_short = flac_read_flac2s ; + psf->read_int = flac_read_flac2i ; + psf->read_float = flac_read_flac2f ; + psf->read_double = flac_read_flac2d ; + } ; + + if (psf->file.mode == SFM_WRITE) + { psf->write_short = flac_write_s2flac ; + psf->write_int = flac_write_i2flac ; + psf->write_float = flac_write_f2flac ; + psf->write_double = flac_write_d2flac ; + } ; + + if (psf->filelength > psf->dataoffset) + psf->datalength = (psf->dataend) ? psf->dataend - psf->dataoffset : psf->filelength - psf->dataoffset ; + else + psf->datalength = 0 ; + + return 0 ; +} /* flac_init */ + +static unsigned +flac_read_loop (SF_PRIVATE *psf, unsigned len) +{ FLAC_PRIVATE* pflac = (FLAC_PRIVATE*) psf->codec_data ; + FLAC__StreamDecoderState state ; + + pflac->pos = 0 ; + pflac->len = len ; + pflac->remain = len ; + + state = FLAC__stream_decoder_get_state (pflac->fsd) ; + if (state > FLAC__STREAM_DECODER_END_OF_STREAM) + { psf_log_printf (psf, "FLAC__stream_decoder_get_state returned %s\n", FLAC__StreamDecoderStateString [state]) ; + /* Current frame is busted, so NULL the pointer. */ + pflac->frame = NULL ; + } ; + + /* First copy data that has already been decoded and buffered. */ + if (pflac->frame != NULL && pflac->bufferpos < pflac->frame->header.blocksize) + flac_buffer_copy (psf) ; + + /* Decode some more. */ + while (pflac->pos < pflac->len) + { if (FLAC__stream_decoder_process_single (pflac->fsd) == 0) + { psf_log_printf (psf, "FLAC__stream_decoder_process_single returned false\n") ; + /* Current frame is busted, so NULL the pointer. */ + pflac->frame = NULL ; + break ; + } ; + state = FLAC__stream_decoder_get_state (pflac->fsd) ; + if (state >= FLAC__STREAM_DECODER_END_OF_STREAM) + { psf_log_printf (psf, "FLAC__stream_decoder_get_state returned %s\n", FLAC__StreamDecoderStateString [state]) ; + /* Current frame is busted, so NULL the pointer. */ + pflac->frame = NULL ; + break ; + } ; + } ; + + pflac->ptr = NULL ; + + return pflac->pos ; +} /* flac_read_loop */ + +static sf_count_t +flac_read_flac2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) +{ FLAC_PRIVATE* pflac = (FLAC_PRIVATE*) psf->codec_data ; + sf_count_t total = 0, current ; + unsigned readlen ; + + pflac->pcmtype = PFLAC_PCM_SHORT ; + + while (total < len) + { pflac->ptr = ptr + 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 ; + total += current ; + } ; + + return total ; +} /* flac_read_flac2s */ + +static sf_count_t +flac_read_flac2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) +{ FLAC_PRIVATE* pflac = (FLAC_PRIVATE*) psf->codec_data ; + sf_count_t total = 0, current ; + unsigned readlen ; + + pflac->pcmtype = PFLAC_PCM_INT ; + + while (total < len) + { pflac->ptr = ptr + 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 ; + total += current ; + } ; + + return total ; +} /* flac_read_flac2i */ + +static sf_count_t +flac_read_flac2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) +{ FLAC_PRIVATE* pflac = (FLAC_PRIVATE*) psf->codec_data ; + sf_count_t total = 0, current ; + unsigned readlen ; + + pflac->pcmtype = PFLAC_PCM_FLOAT ; + + while (total < len) + { pflac->ptr = ptr + 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 ; + total += current ; + } ; + + return total ; +} /* flac_read_flac2f */ + +static sf_count_t +flac_read_flac2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) +{ FLAC_PRIVATE* pflac = (FLAC_PRIVATE*) psf->codec_data ; + sf_count_t total = 0, current ; + unsigned readlen ; + + pflac->pcmtype = PFLAC_PCM_DOUBLE ; + + while (total < len) + { pflac->ptr = ptr + 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 ; + total += current ; + } ; + + return total ; +} /* flac_read_flac2d */ + +static sf_count_t +flac_write_s2flac (SF_PRIVATE *psf, const short *ptr, sf_count_t len) +{ FLAC_PRIVATE* pflac = (FLAC_PRIVATE*) psf->codec_data ; + void (*convert) (const short *, int32_t *, int) ; + int bufferlen, writecount, thiswrite ; + sf_count_t total = 0 ; + int32_t* buffer = pflac->encbuffer ; + + switch (SF_CODEC (psf->sf.format)) + { case SF_FORMAT_PCM_S8 : + convert = s2flac8_array ; + break ; + case SF_FORMAT_PCM_16 : + convert = s2flac16_array ; + break ; + case SF_FORMAT_PCM_24 : + convert = s2flac24_array ; + break ; + default : + return -1 ; + } ; + + bufferlen = ENC_BUFFER_SIZE / (sizeof (int32_t) * psf->sf.channels) ; + bufferlen *= psf->sf.channels ; + + while (len > 0) + { writecount = (len >= bufferlen) ? bufferlen : (int) len ; + convert (ptr + total, buffer, writecount) ; + if (FLAC__stream_encoder_process_interleaved (pflac->fse, buffer, writecount / psf->sf.channels)) + thiswrite = writecount ; + else + break ; + total += thiswrite ; + if (thiswrite < writecount) + break ; + + len -= thiswrite ; + } ; + + return total ; +} /* flac_write_s2flac */ + +static sf_count_t +flac_write_i2flac (SF_PRIVATE *psf, const int *ptr, sf_count_t len) +{ FLAC_PRIVATE* pflac = (FLAC_PRIVATE*) psf->codec_data ; + void (*convert) (const int *, int32_t *, int) ; + int bufferlen, writecount, thiswrite ; + sf_count_t total = 0 ; + int32_t* buffer = pflac->encbuffer ; + + switch (SF_CODEC (psf->sf.format)) + { case SF_FORMAT_PCM_S8 : + convert = i2flac8_array ; + break ; + case SF_FORMAT_PCM_16 : + convert = i2flac16_array ; + break ; + case SF_FORMAT_PCM_24 : + convert = i2flac24_array ; + break ; + default : + return -1 ; + } ; + + bufferlen = ENC_BUFFER_SIZE / (sizeof (int32_t) * psf->sf.channels) ; + bufferlen *= psf->sf.channels ; + + while (len > 0) + { writecount = (len >= bufferlen) ? bufferlen : (int) len ; + convert (ptr + total, buffer, writecount) ; + if (FLAC__stream_encoder_process_interleaved (pflac->fse, buffer, writecount / psf->sf.channels)) + thiswrite = writecount ; + else + break ; + total += thiswrite ; + if (thiswrite < writecount) + break ; + + len -= thiswrite ; + } ; + + return total ; +} /* flac_write_i2flac */ + +static sf_count_t +flac_write_f2flac (SF_PRIVATE *psf, const float *ptr, sf_count_t len) +{ FLAC_PRIVATE* pflac = (FLAC_PRIVATE*) psf->codec_data ; + void (*convert) (const float *, int32_t *, int, int) ; + int bufferlen, writecount, thiswrite ; + sf_count_t total = 0 ; + int32_t* buffer = pflac->encbuffer ; + + switch (SF_CODEC (psf->sf.format)) + { case SF_FORMAT_PCM_S8 : + convert = (psf->add_clipping) ? f2flac8_clip_array : f2flac8_array ; + break ; + case SF_FORMAT_PCM_16 : + convert = (psf->add_clipping) ? f2flac16_clip_array : f2flac16_array ; + break ; + case SF_FORMAT_PCM_24 : + convert = (psf->add_clipping) ? f2flac24_clip_array : f2flac24_array ; + break ; + default : + return -1 ; + } ; + + bufferlen = ENC_BUFFER_SIZE / (sizeof (int32_t) * psf->sf.channels) ; + bufferlen *= psf->sf.channels ; + + while (len > 0) + { writecount = (len >= bufferlen) ? bufferlen : (int) len ; + convert (ptr + total, buffer, writecount, psf->norm_float) ; + if (FLAC__stream_encoder_process_interleaved (pflac->fse, buffer, writecount / psf->sf.channels)) + thiswrite = writecount ; + else + break ; + total += thiswrite ; + if (thiswrite < writecount) + break ; + + len -= thiswrite ; + } ; + + return total ; +} /* flac_write_f2flac */ + +static void +f2flac8_clip_array (const float *src, int32_t *dest, int count, int normalize) +{ float normfact, scaled_value ; + + normfact = normalize ? (8.0 * 0x10) : 1.0 ; + + for (int i = 0 ; i < count ; i++) + { scaled_value = src [i] * normfact ; + if (scaled_value >= (1.0 * 0x7F)) + { dest [i] = 0x7F ; + continue ; + } ; + if (scaled_value <= (-8.0 * 0x10)) + { dest [i] = -0x80 ; + continue ; + } ; + dest [i] = psf_lrintf (scaled_value) ; + } ; + + return ; +} /* f2flac8_clip_array */ + +static void +f2flac16_clip_array (const float *src, int32_t *dest, int count, int normalize) +{ float normfact, scaled_value ; + + normfact = normalize ? (8.0 * 0x1000) : 1.0 ; + + for (int i = 0 ; i < count ; i++) + { scaled_value = src [i] * normfact ; + if (scaled_value >= (1.0 * 0x7FFF)) + { dest [i] = 0x7FFF ; + continue ; + } ; + if (scaled_value <= (-8.0 * 0x1000)) + { dest [i] = -0x8000 ; + continue ; + } ; + dest [i] = psf_lrintf (scaled_value) ; + } ; +} /* f2flac16_clip_array */ + +static void +f2flac24_clip_array (const float *src, int32_t *dest, int count, int normalize) +{ float normfact, scaled_value ; + + normfact = normalize ? (8.0 * 0x100000) : 1.0 ; + + for (int i = 0 ; i < count ; i++) + { scaled_value = src [i] * normfact ; + if (scaled_value >= (1.0 * 0x7FFFFF)) + { dest [i] = 0x7FFFFF ; + continue ; + } ; + + if (scaled_value <= (-8.0 * 0x100000)) + { dest [i] = -0x800000 ; + continue ; + } + dest [i] = psf_lrintf (scaled_value) ; + } ; + + return ; +} /* f2flac24_clip_array */ + +static void +f2flac8_array (const float *src, int32_t *dest, int count, int normalize) +{ float normfact = normalize ? (1.0 * 0x7F) : 1.0 ; + + for (int i = 0 ; i < count ; i++) + dest [i] = psf_lrintf (src [i] * normfact) ; +} /* f2flac8_array */ + +static void +f2flac16_array (const float *src, int32_t *dest, int count, int normalize) +{ float normfact = normalize ? (1.0 * 0x7FFF) : 1.0 ; + + for (int i = 0 ; i < count ; i++) + dest [i] = psf_lrintf (src [i] * normfact) ; +} /* f2flac16_array */ + +static void +f2flac24_array (const float *src, int32_t *dest, int count, int normalize) +{ float normfact = normalize ? (1.0 * 0x7FFFFF) : 1.0 ; + + for (int i = 0 ; i < count ; i++) + dest [i] = psf_lrintf (src [i] * normfact) ; +} /* f2flac24_array */ + +static sf_count_t +flac_write_d2flac (SF_PRIVATE *psf, const double *ptr, sf_count_t len) +{ FLAC_PRIVATE* pflac = (FLAC_PRIVATE*) psf->codec_data ; + void (*convert) (const double *, int32_t *, int, int) ; + int bufferlen, writecount, thiswrite ; + sf_count_t total = 0 ; + int32_t* buffer = pflac->encbuffer ; + + switch (SF_CODEC (psf->sf.format)) + { case SF_FORMAT_PCM_S8 : + convert = (psf->add_clipping) ? d2flac8_clip_array : d2flac8_array ; + break ; + case SF_FORMAT_PCM_16 : + convert = (psf->add_clipping) ? d2flac16_clip_array : d2flac16_array ; + break ; + case SF_FORMAT_PCM_24 : + convert = (psf->add_clipping) ? d2flac24_clip_array : d2flac24_array ; + break ; + default : + return -1 ; + } ; + + bufferlen = ENC_BUFFER_SIZE / (sizeof (int32_t) * psf->sf.channels) ; + bufferlen *= psf->sf.channels ; + + while (len > 0) + { writecount = (len >= bufferlen) ? bufferlen : (int) len ; + convert (ptr + total, buffer, writecount, psf->norm_double) ; + if (FLAC__stream_encoder_process_interleaved (pflac->fse, buffer, writecount / psf->sf.channels)) + thiswrite = writecount ; + else + break ; + total += thiswrite ; + if (thiswrite < writecount) + break ; + + len -= thiswrite ; + } ; + + return total ; +} /* flac_write_d2flac */ + +static void +d2flac8_clip_array (const double *src, int32_t *dest, int count, int normalize) +{ double normfact, scaled_value ; + + normfact = normalize ? (8.0 * 0x10) : 1.0 ; + + for (int i = 0 ; i < count ; i++) + { scaled_value = src [i] * normfact ; + if (scaled_value >= (1.0 * 0x7F)) + { dest [i] = 0x7F ; + continue ; + } ; + if (scaled_value <= (-8.0 * 0x10)) + { dest [i] = -0x80 ; + continue ; + } ; + dest [i] = psf_lrint (scaled_value) ; + } ; + + return ; +} /* d2flac8_clip_array */ + +static void +d2flac16_clip_array (const double *src, int32_t *dest, int count, int normalize) +{ double normfact, scaled_value ; + + normfact = normalize ? (8.0 * 0x1000) : 1.0 ; + + for (int i = 0 ; i < count ; i++) + { scaled_value = src [i] * normfact ; + if (scaled_value >= (1.0 * 0x7FFF)) + { dest [i] = 0x7FFF ; + continue ; + } ; + if (scaled_value <= (-8.0 * 0x1000)) + { dest [i] = -0x8000 ; + continue ; + } ; + dest [i] = psf_lrint (scaled_value) ; + } ; + + return ; +} /* d2flac16_clip_array */ + +static void +d2flac24_clip_array (const double *src, int32_t *dest, int count, int normalize) +{ double normfact, scaled_value ; + + normfact = normalize ? (8.0 * 0x100000) : 1.0 ; + + for (int i = 0 ; i < count ; i++) + { scaled_value = src [i] * normfact ; + if (scaled_value >= (1.0 * 0x7FFFFF)) + { dest [i] = 0x7FFFFF ; + continue ; + } ; + if (scaled_value <= (-8.0 * 0x100000)) + { dest [i] = -0x800000 ; + continue ; + } ; + dest [i] = psf_lrint (scaled_value) ; + } ; + + return ; +} /* d2flac24_clip_array */ + +static void +d2flac8_array (const double *src, int32_t *dest, int count, int normalize) +{ double normfact = normalize ? (1.0 * 0x7F) : 1.0 ; + + for (int i = 0 ; i < count ; i++) + dest [i] = psf_lrint (src [i] * normfact) ; +} /* d2flac8_array */ + +static void +d2flac16_array (const double *src, int32_t *dest, int count, int normalize) +{ double normfact = normalize ? (1.0 * 0x7FFF) : 1.0 ; + + for (int i = 0 ; i < count ; i++) + dest [i] = psf_lrint (src [i] * normfact) ; +} /* d2flac16_array */ + +static void +d2flac24_array (const double *src, int32_t *dest, int count, int normalize) +{ double normfact = normalize ? (1.0 * 0x7FFFFF) : 1.0 ; + + for (int i = 0 ; i < count ; i++) + dest [i] = psf_lrint (src [i] * normfact) ; +} /* d2flac24_array */ + +static sf_count_t +flac_seek (SF_PRIVATE *psf, int UNUSED (mode), sf_count_t offset) +{ FLAC_PRIVATE* pflac = (FLAC_PRIVATE*) psf->codec_data ; + + if (pflac == NULL) + return 0 ; + + if (psf->dataoffset < 0) + { psf->error = SFE_BAD_SEEK ; + return ((sf_count_t) -1) ; + } ; + + pflac->frame = NULL ; + + if (psf->file.mode == SFM_READ) + { if (FLAC__stream_decoder_seek_absolute (pflac->fsd, offset)) + return offset ; + + if (offset == psf->sf.frames) + { /* + ** If we've been asked to seek to the very end of the file, libFLAC + ** will return an error. However, we know the length of the file so + ** instead of returning an error, we can return the offset. + */ + return offset ; + } ; + + psf->error = SFE_BAD_SEEK ; + return ((sf_count_t) -1) ; + } ; + + /* Seeking in write mode not yet supported. */ + psf->error = SFE_BAD_SEEK ; + + return ((sf_count_t) -1) ; +} /* flac_seek */ + +static int +flac_byterate (SF_PRIVATE *psf) +{ + if (psf->file.mode == SFM_READ) + return (psf->datalength * psf->sf.samplerate) / psf->sf.frames ; + + return -1 ; +} /* flac_byterate */ + + +#else /* HAVE_EXTERNAL_XIPH_LIBS */ + +int +flac_open (SF_PRIVATE *psf) +{ + psf_log_printf (psf, "This version of libsndfile was compiled without FLAC support.\n") ; + return SFE_UNIMPLEMENTED ; +} /* flac_open */ + +#endif diff --git a/extern/libsndfile-modified/src/float32.c b/extern/libsndfile-modified/src/float32.c new file mode 100644 index 000000000..431e39bb3 --- /dev/null +++ b/extern/libsndfile-modified/src/float32.c @@ -0,0 +1,1017 @@ +/* +** Copyright (C) 1999-2017 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + +#if CPU_IS_LITTLE_ENDIAN + #define FLOAT32_READ float32_le_read + #define FLOAT32_WRITE float32_le_write +#elif CPU_IS_BIG_ENDIAN + #define FLOAT32_READ float32_be_read + #define FLOAT32_WRITE float32_be_write +#endif + +/*-------------------------------------------------------------------------------------------- +** Processor floating point capabilities. float32_get_capability () returns one of the +** latter four values. +*/ + +enum +{ FLOAT_UNKNOWN = 0x00, + FLOAT_CAN_RW_LE = 0x12, + FLOAT_CAN_RW_BE = 0x23, + FLOAT_BROKEN_LE = 0x34, + FLOAT_BROKEN_BE = 0x45 +} ; + +/*-------------------------------------------------------------------------------------------- +** Prototypes for private functions. +*/ + +static sf_count_t host_read_f2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; +static sf_count_t host_read_f2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; +static sf_count_t host_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; +static sf_count_t host_read_f2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; + +static sf_count_t host_write_s2f (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; +static sf_count_t host_write_i2f (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; +static sf_count_t host_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; +static sf_count_t host_write_d2f (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; + +static void float32_peak_update (SF_PRIVATE *psf, const float *buffer, int count, sf_count_t indx) ; + +static sf_count_t replace_read_f2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; +static sf_count_t replace_read_f2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; +static sf_count_t replace_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; +static sf_count_t replace_read_f2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; + +static sf_count_t replace_write_s2f (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; +static sf_count_t replace_write_i2f (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; +static sf_count_t replace_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; +static sf_count_t replace_write_d2f (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; + +static void bf2f_array (float *buffer, int count) ; +static void f2bf_array (float *buffer, int count) ; + +static int float32_get_capability (SF_PRIVATE *psf) ; + +/*-------------------------------------------------------------------------------------------- +** Exported functions. +*/ + +int +float32_init (SF_PRIVATE *psf) +{ static int float_caps ; + + if (psf->sf.channels < 1) + { psf_log_printf (psf, "float32_init : internal error : channels = %d\n", psf->sf.channels) ; + return SFE_INTERNAL ; + } ; + + float_caps = float32_get_capability (psf) ; + + psf->blockwidth = sizeof (float) * psf->sf.channels ; + + if (psf->file.mode == SFM_READ || psf->file.mode == SFM_RDWR) + { switch (psf->endian + float_caps) + { case (SF_ENDIAN_BIG + FLOAT_CAN_RW_BE) : + psf->data_endswap = SF_FALSE ; + psf->read_short = host_read_f2s ; + psf->read_int = host_read_f2i ; + psf->read_float = host_read_f ; + psf->read_double = host_read_f2d ; + break ; + + case (SF_ENDIAN_LITTLE + FLOAT_CAN_RW_LE) : + psf->data_endswap = SF_FALSE ; + psf->read_short = host_read_f2s ; + psf->read_int = host_read_f2i ; + psf->read_float = host_read_f ; + psf->read_double = host_read_f2d ; + break ; + + case (SF_ENDIAN_BIG + FLOAT_CAN_RW_LE) : + psf->data_endswap = SF_TRUE ; + psf->read_short = host_read_f2s ; + psf->read_int = host_read_f2i ; + psf->read_float = host_read_f ; + psf->read_double = host_read_f2d ; + break ; + + case (SF_ENDIAN_LITTLE + FLOAT_CAN_RW_BE) : + psf->data_endswap = SF_TRUE ; + psf->read_short = host_read_f2s ; + psf->read_int = host_read_f2i ; + psf->read_float = host_read_f ; + psf->read_double = host_read_f2d ; + break ; + + /* When the CPU is not IEEE compatible. */ + case (SF_ENDIAN_BIG + FLOAT_BROKEN_LE) : + psf->data_endswap = SF_TRUE ; + psf->read_short = replace_read_f2s ; + psf->read_int = replace_read_f2i ; + psf->read_float = replace_read_f ; + psf->read_double = replace_read_f2d ; + break ; + + case (SF_ENDIAN_LITTLE + FLOAT_BROKEN_LE) : + psf->data_endswap = SF_FALSE ; + psf->read_short = replace_read_f2s ; + psf->read_int = replace_read_f2i ; + psf->read_float = replace_read_f ; + psf->read_double = replace_read_f2d ; + break ; + + case (SF_ENDIAN_BIG + FLOAT_BROKEN_BE) : + psf->data_endswap = SF_FALSE ; + psf->read_short = replace_read_f2s ; + psf->read_int = replace_read_f2i ; + psf->read_float = replace_read_f ; + psf->read_double = replace_read_f2d ; + break ; + + case (SF_ENDIAN_LITTLE + FLOAT_BROKEN_BE) : + psf->data_endswap = SF_TRUE ; + psf->read_short = replace_read_f2s ; + psf->read_int = replace_read_f2i ; + psf->read_float = replace_read_f ; + psf->read_double = replace_read_f2d ; + break ; + + default : break ; + } ; + } ; + + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { switch (psf->endian + float_caps) + { case (SF_ENDIAN_LITTLE + FLOAT_CAN_RW_LE) : + psf->data_endswap = SF_FALSE ; + psf->write_short = host_write_s2f ; + psf->write_int = host_write_i2f ; + psf->write_float = host_write_f ; + psf->write_double = host_write_d2f ; + break ; + + case (SF_ENDIAN_BIG + FLOAT_CAN_RW_BE) : + psf->data_endswap = SF_FALSE ; + psf->write_short = host_write_s2f ; + psf->write_int = host_write_i2f ; + psf->write_float = host_write_f ; + psf->write_double = host_write_d2f ; + break ; + + case (SF_ENDIAN_BIG + FLOAT_CAN_RW_LE) : + psf->data_endswap = SF_TRUE ; + psf->write_short = host_write_s2f ; + psf->write_int = host_write_i2f ; + psf->write_float = host_write_f ; + psf->write_double = host_write_d2f ; + break ; + + case (SF_ENDIAN_LITTLE + FLOAT_CAN_RW_BE) : + psf->data_endswap = SF_TRUE ; + psf->write_short = host_write_s2f ; + psf->write_int = host_write_i2f ; + psf->write_float = host_write_f ; + psf->write_double = host_write_d2f ; + break ; + + /* When the CPU is not IEEE compatible. */ + case (SF_ENDIAN_BIG + FLOAT_BROKEN_LE) : + psf->data_endswap = SF_TRUE ; + psf->write_short = replace_write_s2f ; + psf->write_int = replace_write_i2f ; + psf->write_float = replace_write_f ; + psf->write_double = replace_write_d2f ; + break ; + + case (SF_ENDIAN_LITTLE + FLOAT_BROKEN_LE) : + psf->data_endswap = SF_FALSE ; + psf->write_short = replace_write_s2f ; + psf->write_int = replace_write_i2f ; + psf->write_float = replace_write_f ; + psf->write_double = replace_write_d2f ; + break ; + + case (SF_ENDIAN_BIG + FLOAT_BROKEN_BE) : + psf->data_endswap = SF_FALSE ; + psf->write_short = replace_write_s2f ; + psf->write_int = replace_write_i2f ; + psf->write_float = replace_write_f ; + psf->write_double = replace_write_d2f ; + break ; + + case (SF_ENDIAN_LITTLE + FLOAT_BROKEN_BE) : + psf->data_endswap = SF_TRUE ; + psf->write_short = replace_write_s2f ; + psf->write_int = replace_write_i2f ; + psf->write_float = replace_write_f ; + psf->write_double = replace_write_d2f ; + break ; + + default : break ; + } ; + } ; + + if (psf->filelength > psf->dataoffset) + { psf->datalength = (psf->dataend > 0) ? psf->dataend - psf->dataoffset : + psf->filelength - psf->dataoffset ; + } + else + psf->datalength = 0 ; + + psf->sf.frames = psf->blockwidth > 0 ? psf->datalength / psf->blockwidth : 0 ; + + return 0 ; +} /* float32_init */ + +float +float32_be_read (const unsigned char *cptr) +{ int exponent, mantissa, negative ; + float fvalue ; + + negative = cptr [0] & 0x80 ; + exponent = ((cptr [0] & 0x7F) << 1) | ((cptr [1] & 0x80) ? 1 : 0) ; + mantissa = ((cptr [1] & 0x7F) << 16) | (cptr [2] << 8) | (cptr [3]) ; + + if (! (exponent || mantissa)) + return 0.0 ; + + mantissa |= 0x800000 ; + exponent = exponent ? exponent - 127 : 0 ; + + fvalue = mantissa ? ((float) mantissa) / ((float) 0x800000) : 0.0 ; + + if (negative) + fvalue *= -1 ; + + if (exponent > 0) + fvalue *= pow (2.0, exponent) ; + else if (exponent < 0) + fvalue /= pow (2.0, abs (exponent)) ; + + return fvalue ; +} /* float32_be_read */ + +float +float32_le_read (const unsigned char *cptr) +{ int exponent, mantissa, negative ; + float fvalue ; + + negative = cptr [3] & 0x80 ; + exponent = ((cptr [3] & 0x7F) << 1) | ((cptr [2] & 0x80) ? 1 : 0) ; + mantissa = ((cptr [2] & 0x7F) << 16) | (cptr [1] << 8) | (cptr [0]) ; + + if (! (exponent || mantissa)) + return 0.0 ; + + mantissa |= 0x800000 ; + exponent = exponent ? exponent - 127 : 0 ; + + fvalue = mantissa ? ((float) mantissa) / ((float) 0x800000) : 0.0 ; + + if (negative) + fvalue *= -1 ; + + if (exponent > 0) + fvalue *= pow (2.0, exponent) ; + else if (exponent < 0) + fvalue /= pow (2.0, abs (exponent)) ; + + return fvalue ; +} /* float32_le_read */ + +void +float32_le_write (float in, unsigned char *out) +{ int exponent, mantissa, negative = 0 ; + + memset (out, 0, sizeof (int)) ; + + if (fabs (in) < 1e-30) + return ; + + if (in < 0.0) + { in *= -1.0 ; + negative = 1 ; + } ; + + in = frexp (in, &exponent) ; + + exponent += 126 ; + + in *= (float) 0x1000000 ; + mantissa = (((int) in) & 0x7FFFFF) ; + + if (negative) + out [3] |= 0x80 ; + + if (exponent & 0x01) + out [2] |= 0x80 ; + + out [0] = mantissa & 0xFF ; + out [1] = (mantissa >> 8) & 0xFF ; + out [2] |= (mantissa >> 16) & 0x7F ; + out [3] |= (exponent >> 1) & 0x7F ; + + return ; +} /* float32_le_write */ + +void +float32_be_write (float in, unsigned char *out) +{ int exponent, mantissa, negative = 0 ; + + memset (out, 0, sizeof (int)) ; + + if (fabs (in) < 1e-30) + return ; + + if (in < 0.0) + { in *= -1.0 ; + negative = 1 ; + } ; + + in = frexp (in, &exponent) ; + + exponent += 126 ; + + in *= (float) 0x1000000 ; + mantissa = (((int) in) & 0x7FFFFF) ; + + if (negative) + out [0] |= 0x80 ; + + if (exponent & 0x01) + out [1] |= 0x80 ; + + out [3] = mantissa & 0xFF ; + out [2] = (mantissa >> 8) & 0xFF ; + out [1] |= (mantissa >> 16) & 0x7F ; + out [0] |= (exponent >> 1) & 0x7F ; + + return ; +} /* float32_be_write */ + +/*============================================================================================== +** Private functions. +*/ + +static void +float32_peak_update (SF_PRIVATE *psf, const float *buffer, int count, sf_count_t indx) +{ int chan ; + int k, position ; + float fmaxval ; + + for (chan = 0 ; chan < psf->sf.channels ; chan++) + { fmaxval = fabs (buffer [chan]) ; + position = 0 ; + for (k = chan ; k < count ; k += psf->sf.channels) + if (fmaxval < fabs (buffer [k])) + { fmaxval = fabs (buffer [k]) ; + position = k ; + } ; + + if (fmaxval > psf->peak_info->peaks [chan].value) + { psf->peak_info->peaks [chan].value = fmaxval ; + psf->peak_info->peaks [chan].position = psf->write_current + indx + (position / psf->sf.channels) ; + } ; + } ; + + return ; +} /* float32_peak_update */ + +static int +float32_get_capability (SF_PRIVATE *psf) +{ union + { float f ; + int i ; + unsigned char c [4] ; + } data ; + + data.f = (float) 1.23456789 ; /* Some abitrary value. */ + + if (! psf->ieee_replace) + { /* If this test is true ints and floats are compatible and little endian. */ + if (data.c [0] == 0x52 && data.c [1] == 0x06 && data.c [2] == 0x9e && data.c [3] == 0x3f) + return FLOAT_CAN_RW_LE ; + + /* If this test is true ints and floats are compatible and big endian. */ + if (data.c [3] == 0x52 && data.c [2] == 0x06 && data.c [1] == 0x9e && data.c [0] == 0x3f) + return FLOAT_CAN_RW_BE ; + } ; + + /* Floats are broken. Don't expect reading or writing to be fast. */ + psf_log_printf (psf, "Using IEEE replacement code for float.\n") ; + + return (CPU_IS_LITTLE_ENDIAN) ? FLOAT_BROKEN_LE : FLOAT_BROKEN_BE ; +} /* float32_get_capability */ + +/*======================================================================================= +*/ + +static void +f2s_array (const float *src, int count, short *dest, float scale) +{ + for (int i = 0 ; i < count ; i++) + { dest [i] = psf_lrintf (scale * src [i]) ; + } ; +} /* f2s_array */ + +static void +f2s_clip_array (const float *src, int count, short *dest, float scale) +{ for (int i = 0 ; i < count ; i++) + { float tmp = scale * src [i] ; + + if (tmp > 32767.0) + dest [i] = SHRT_MAX ; + else if (tmp < -32768.0) + dest [i] = SHRT_MIN ; + else + dest [i] = psf_lrintf (tmp) ; + } ; +} /* f2s_clip_array */ + +static inline void +f2i_array (const float *src, int count, int *dest, float scale) +{ for (int i = 0 ; i < count ; i++) + { dest [i] = psf_lrintf (scale * src [i]) ; + } ; +} /* f2i_array */ + +static inline void +f2i_clip_array (const float *src, int count, int *dest, float scale) +{ for (int i = 0 ; i < count ; i++) + { float tmp = scale * src [i] ; + + if (CPU_CLIPS_POSITIVE == 0 && tmp > (1.0 * INT_MAX)) + dest [i] = INT_MAX ; + else if (CPU_CLIPS_NEGATIVE == 0 && tmp < (-1.0 * INT_MAX)) + dest [i] = INT_MIN ; + else + dest [i] = psf_lrintf (tmp) ; + } ; +} /* f2i_clip_array */ + +static inline void +f2d_array (const float *src, int count, double *dest) +{ for (int i = 0 ; i < count ; i++) + { dest [i] = src [i] ; + } ; +} /* f2d_array */ + +static inline void +s2f_array (const short *src, float *dest, int count, float scale) +{ for (int i = 0 ; i < count ; i++) + { dest [i] = scale * src [i] ; + } ; +} /* s2f_array */ + +static inline void +i2f_array (const int *src, float *dest, int count, float scale) +{ for (int i = 0 ; i < count ; i++) + { dest [i] = scale * src [i] ; + } ; +} /* i2f_array */ + +static inline void +d2f_array (const double *src, float *dest, int count) +{ for (int i = 0 ; i < count ; i++) + { dest [i] = src [i] ; + } ; +} /* d2f_array */ + +/*---------------------------------------------------------------------------------------------- +*/ + +static sf_count_t +host_read_f2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + void (*convert) (const float *, int, short *, float) ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + float scale ; + + convert = (psf->add_clipping) ? f2s_clip_array : f2s_array ; + bufferlen = ARRAY_LEN (ubuf.fbuf) ; + scale = (psf->float_int_mult == 0) ? 1.0 : 0x7FFF / psf->float_max ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.fbuf, sizeof (float), bufferlen, psf) ; + +/* Fix me : Need lef2s_array */ + if (psf->data_endswap == SF_TRUE) + endswap_int_array (ubuf.ibuf, readcount) ; + + convert (ubuf.fbuf, readcount, ptr + total, scale) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* host_read_f2s */ + +static sf_count_t +host_read_f2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + void (*convert) (const float *, int, int *, float) ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + float scale ; + + convert = (psf->add_clipping) ? f2i_clip_array : f2i_array ; + bufferlen = ARRAY_LEN (ubuf.fbuf) ; + scale = (psf->float_int_mult == 0) ? 1.0 : 2147483648.0f / psf->float_max ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.fbuf, sizeof (float), bufferlen, psf) ; + + if (psf->data_endswap == SF_TRUE) + endswap_int_array (ubuf.ibuf, bufferlen) ; + + convert (ubuf.fbuf, readcount, ptr + total, scale) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* host_read_f2i */ + +static sf_count_t +host_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + + if (psf->data_endswap != SF_TRUE) + return psf_fread (ptr, sizeof (float), len, psf) ; + + bufferlen = ARRAY_LEN (ubuf.fbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.fbuf, sizeof (float), bufferlen, psf) ; + + endswap_int_copy ((int*) (ptr + total), ubuf.ibuf, readcount) ; + + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* host_read_f */ + +static sf_count_t +host_read_f2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + + bufferlen = ARRAY_LEN (ubuf.fbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.fbuf, sizeof (float), bufferlen, psf) ; + + if (psf->data_endswap == SF_TRUE) + endswap_int_array (ubuf.ibuf, bufferlen) ; + +/* Fix me : Need lef2d_array */ + f2d_array (ubuf.fbuf, readcount, ptr + total) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* host_read_f2d */ + +static sf_count_t +host_write_s2f (SF_PRIVATE *psf, const short *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + float scale ; + +/* Erik */ + scale = (psf->scale_int_float == 0) ? 1.0 : 1.0 / 0x8000 ; + bufferlen = ARRAY_LEN (ubuf.fbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + s2f_array (ptr + total, ubuf.fbuf, bufferlen, scale) ; + + if (psf->peak_info) + float32_peak_update (psf, ubuf.fbuf, bufferlen, total / psf->sf.channels) ; + + if (psf->data_endswap == SF_TRUE) + endswap_int_array (ubuf.ibuf, bufferlen) ; + + writecount = (int) psf_fwrite (ubuf.fbuf, sizeof (float), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* host_write_s2f */ + +static sf_count_t +host_write_i2f (SF_PRIVATE *psf, const int *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + float scale ; + + scale = (psf->scale_int_float == 0) ? 1.0 : 1.0 / (8.0 * 0x10000000) ; + bufferlen = ARRAY_LEN (ubuf.fbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + i2f_array (ptr + total, ubuf.fbuf, bufferlen, scale) ; + + if (psf->peak_info) + float32_peak_update (psf, ubuf.fbuf, bufferlen, total / psf->sf.channels) ; + + if (psf->data_endswap == SF_TRUE) + endswap_int_array (ubuf.ibuf, bufferlen) ; + + writecount = (int) psf_fwrite (ubuf.fbuf, sizeof (float) , bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* host_write_i2f */ + +static sf_count_t +host_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + if (psf->peak_info) + float32_peak_update (psf, ptr, len, 0) ; + + if (psf->data_endswap != SF_TRUE) + return psf_fwrite (ptr, sizeof (float), len, psf) ; + + bufferlen = ARRAY_LEN (ubuf.fbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + + endswap_int_copy (ubuf.ibuf, (const int*) (ptr + total), bufferlen) ; + + writecount = (int) psf_fwrite (ubuf.fbuf, sizeof (float), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* host_write_f */ + +static sf_count_t +host_write_d2f (SF_PRIVATE *psf, const double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + bufferlen = ARRAY_LEN (ubuf.fbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + + d2f_array (ptr + total, ubuf.fbuf, bufferlen) ; + + if (psf->peak_info) + float32_peak_update (psf, ubuf.fbuf, bufferlen, total / psf->sf.channels) ; + + if (psf->data_endswap == SF_TRUE) + endswap_int_array (ubuf.ibuf, bufferlen) ; + + writecount = (int) psf_fwrite (ubuf.fbuf, sizeof (float), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* host_write_d2f */ + +/*======================================================================================= +*/ + +static sf_count_t +replace_read_f2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + float scale ; + + bufferlen = ARRAY_LEN (ubuf.fbuf) ; + scale = (psf->float_int_mult == 0) ? 1.0 : 0x7FFF / psf->float_max ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.fbuf, sizeof (float), bufferlen, psf) ; + + if (psf->data_endswap == SF_TRUE) + endswap_int_array (ubuf.ibuf, bufferlen) ; + + bf2f_array (ubuf.fbuf, bufferlen) ; + + f2s_array (ubuf.fbuf, readcount, ptr + total, scale) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* replace_read_f2s */ + +static sf_count_t +replace_read_f2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + float scale ; + + bufferlen = ARRAY_LEN (ubuf.fbuf) ; + scale = (psf->float_int_mult == 0) ? 1.0 : 2147483648.0f / psf->float_max ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.fbuf, sizeof (float), bufferlen, psf) ; + + if (psf->data_endswap == SF_TRUE) + endswap_int_array (ubuf.ibuf, bufferlen) ; + + bf2f_array (ubuf.fbuf, bufferlen) ; + + f2i_array (ubuf.fbuf, readcount, ptr + total, scale) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* replace_read_f2i */ + +static sf_count_t +replace_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + + /* FIX THIS */ + + bufferlen = ARRAY_LEN (ubuf.fbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.fbuf, sizeof (float), bufferlen, psf) ; + + if (psf->data_endswap == SF_TRUE) + endswap_int_array (ubuf.ibuf, bufferlen) ; + + bf2f_array (ubuf.fbuf, bufferlen) ; + + memcpy (ptr + total, ubuf.fbuf, bufferlen * sizeof (float)) ; + + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* replace_read_f */ + +static sf_count_t +replace_read_f2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + + bufferlen = ARRAY_LEN (ubuf.fbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.fbuf, sizeof (float), bufferlen, psf) ; + + if (psf->data_endswap == SF_TRUE) + endswap_int_array (ubuf.ibuf, bufferlen) ; + + bf2f_array (ubuf.fbuf, bufferlen) ; + + f2d_array (ubuf.fbuf, readcount, ptr + total) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* replace_read_f2d */ + +static sf_count_t +replace_write_s2f (SF_PRIVATE *psf, const short *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + float scale ; + + scale = (psf->scale_int_float == 0) ? 1.0 : 1.0 / 0x8000 ; + bufferlen = ARRAY_LEN (ubuf.fbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + s2f_array (ptr + total, ubuf.fbuf, bufferlen, scale) ; + + if (psf->peak_info) + float32_peak_update (psf, ubuf.fbuf, bufferlen, total / psf->sf.channels) ; + + f2bf_array (ubuf.fbuf, bufferlen) ; + + if (psf->data_endswap == SF_TRUE) + endswap_int_array (ubuf.ibuf, bufferlen) ; + + writecount = (int) psf_fwrite (ubuf.fbuf, sizeof (float), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* replace_write_s2f */ + +static sf_count_t +replace_write_i2f (SF_PRIVATE *psf, const int *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + float scale ; + + scale = (psf->scale_int_float == 0) ? 1.0 : 1.0 / (8.0 * 0x10000000) ; + bufferlen = ARRAY_LEN (ubuf.fbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + i2f_array (ptr + total, ubuf.fbuf, bufferlen, scale) ; + + if (psf->peak_info) + float32_peak_update (psf, ubuf.fbuf, bufferlen, total / psf->sf.channels) ; + + f2bf_array (ubuf.fbuf, bufferlen) ; + + if (psf->data_endswap == SF_TRUE) + endswap_int_array (ubuf.ibuf, bufferlen) ; + + writecount = (int) psf_fwrite (ubuf.fbuf, sizeof (float), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* replace_write_i2f */ + +static sf_count_t +replace_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + /* FIX THIS */ + if (psf->peak_info) + float32_peak_update (psf, ptr, len, 0) ; + + bufferlen = ARRAY_LEN (ubuf.fbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + + memcpy (ubuf.fbuf, ptr + total, bufferlen * sizeof (float)) ; + + f2bf_array (ubuf.fbuf, bufferlen) ; + + if (psf->data_endswap == SF_TRUE) + endswap_int_array (ubuf.ibuf, bufferlen) ; + + writecount = (int) psf_fwrite (ubuf.fbuf, sizeof (float) , bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* replace_write_f */ + +static sf_count_t +replace_write_d2f (SF_PRIVATE *psf, const double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + bufferlen = ARRAY_LEN (ubuf.fbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + d2f_array (ptr + total, ubuf.fbuf, bufferlen) ; + + if (psf->peak_info) + float32_peak_update (psf, ubuf.fbuf, bufferlen, total / psf->sf.channels) ; + + f2bf_array (ubuf.fbuf, bufferlen) ; + + if (psf->data_endswap == SF_TRUE) + endswap_int_array (ubuf.ibuf, bufferlen) ; + + writecount = (int) psf_fwrite (ubuf.fbuf, sizeof (float), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* replace_write_d2f */ + +/*---------------------------------------------------------------------------------------------- +*/ + +static void +bf2f_array (float *buffer, int count) +{ for (int i = 0 ; i < count ; i++) + { buffer [i] = FLOAT32_READ ((unsigned char *) &buffer [i]) ; + } ; +} /* bf2f_array */ + +static void +f2bf_array (float *buffer, int count) +{ for (int i = 0 ; i < count ; i++) + { FLOAT32_WRITE (buffer [i], (unsigned char*) &buffer [i]) ; + } ; +} /* f2bf_array */ + diff --git a/extern/libsndfile-modified/src/g72x.c b/extern/libsndfile-modified/src/g72x.c new file mode 100644 index 000000000..62e400513 --- /dev/null +++ b/extern/libsndfile-modified/src/g72x.c @@ -0,0 +1,608 @@ +/* +** Copyright (C) 1999-2014 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" +#include "G72x/g72x.h" + +/* This struct is private to the G72x code. */ +struct g72x_state ; +typedef struct g72x_state G72x_STATE ; + +typedef struct +{ /* Private data. Don't mess with it. */ + struct g72x_state * private ; + + /* Public data. Read only. */ + int blocksize, samplesperblock, bytesperblock ; + + /* Public data. Read and write. */ + int blocks_total, block_curr, sample_curr ; + unsigned char block [G72x_BLOCK_SIZE] ; + short samples [G72x_BLOCK_SIZE] ; +} G72x_PRIVATE ; + +static int psf_g72x_decode_block (SF_PRIVATE *psf, G72x_PRIVATE *pg72x) ; +static int psf_g72x_encode_block (SF_PRIVATE *psf, G72x_PRIVATE *pg72x) ; + +static sf_count_t g72x_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; +static sf_count_t g72x_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; +static sf_count_t g72x_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; +static sf_count_t g72x_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; + +static sf_count_t g72x_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; +static sf_count_t g72x_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; +static sf_count_t g72x_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; +static sf_count_t g72x_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; + +static sf_count_t g72x_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ; + +static int g72x_close (SF_PRIVATE *psf) ; + + +/*============================================================================================ +** WAV G721 Reader initialisation function. +*/ + +int +g72x_init (SF_PRIVATE * psf) +{ G72x_PRIVATE *pg72x ; + int bitspersample, bytesperblock, codec ; + + if (psf->codec_data != NULL) + { psf_log_printf (psf, "*** psf->codec_data is not NULL.\n") ; + return SFE_INTERNAL ; + } ; + + psf->sf.seekable = SF_FALSE ; + + if (psf->sf.channels != 1) + return SFE_G72X_NOT_MONO ; + + if ((pg72x = calloc (1, sizeof (G72x_PRIVATE))) == NULL) + return SFE_MALLOC_FAILED ; + + psf->codec_data = (void*) pg72x ; + + pg72x->block_curr = 0 ; + pg72x->sample_curr = 0 ; + + switch (SF_CODEC (psf->sf.format)) + { case SF_FORMAT_G721_32 : + codec = G721_32_BITS_PER_SAMPLE ; + bytesperblock = G721_32_BYTES_PER_BLOCK ; + bitspersample = G721_32_BITS_PER_SAMPLE ; + break ; + + case SF_FORMAT_G723_24: + codec = G723_24_BITS_PER_SAMPLE ; + bytesperblock = G723_24_BYTES_PER_BLOCK ; + bitspersample = G723_24_BITS_PER_SAMPLE ; + break ; + + case SF_FORMAT_G723_40: + codec = G723_40_BITS_PER_SAMPLE ; + bytesperblock = G723_40_BYTES_PER_BLOCK ; + bitspersample = G723_40_BITS_PER_SAMPLE ; + break ; + + default : return SFE_UNIMPLEMENTED ; + } ; + + psf->filelength = psf_get_filelen (psf) ; + if (psf->filelength < psf->dataoffset) + psf->filelength = psf->dataoffset ; + + psf->datalength = psf->filelength - psf->dataoffset ; + if (psf->dataend > 0) + psf->datalength -= psf->filelength - psf->dataend ; + + if (psf->file.mode == SFM_READ) + { pg72x->private = g72x_reader_init (codec, &(pg72x->blocksize), &(pg72x->samplesperblock)) ; + if (pg72x->private == NULL) + return SFE_MALLOC_FAILED ; + + pg72x->bytesperblock = bytesperblock ; + + psf->read_short = g72x_read_s ; + psf->read_int = g72x_read_i ; + psf->read_float = g72x_read_f ; + psf->read_double = g72x_read_d ; + + psf->seek = g72x_seek ; + + if (psf->datalength % pg72x->blocksize) + { psf_log_printf (psf, "*** Odd psf->datalength (%D) should be a multiple of %d\n", psf->datalength, pg72x->blocksize) ; + pg72x->blocks_total = (psf->datalength / pg72x->blocksize) + 1 ; + } + else + pg72x->blocks_total = psf->datalength / pg72x->blocksize ; + + psf->sf.frames = (sf_count_t) pg72x->blocks_total * pg72x->samplesperblock ; + + psf_g72x_decode_block (psf, pg72x) ; + } + else if (psf->file.mode == SFM_WRITE) + { pg72x->private = g72x_writer_init (codec, &(pg72x->blocksize), &(pg72x->samplesperblock)) ; + if (pg72x->private == NULL) + return SFE_MALLOC_FAILED ; + + pg72x->bytesperblock = bytesperblock ; + + psf->write_short = g72x_write_s ; + psf->write_int = g72x_write_i ; + psf->write_float = g72x_write_f ; + psf->write_double = g72x_write_d ; + + if (psf->datalength % pg72x->blocksize) + pg72x->blocks_total = (psf->datalength / pg72x->blocksize) + 1 ; + else + pg72x->blocks_total = psf->datalength / pg72x->blocksize ; + + if (psf->datalength > 0) + psf->sf.frames = (8 * psf->datalength) / bitspersample ; + + if ((psf->sf.frames * bitspersample) / 8 != psf->datalength) + psf_log_printf (psf, "*** Warning : weird psf->datalength.\n") ; + } ; + + psf->codec_close = g72x_close ; + + return 0 ; +} /* g72x_init */ + +/*============================================================================================ +** G721 Read Functions. +*/ + +static int +psf_g72x_decode_block (SF_PRIVATE *psf, G72x_PRIVATE *pg72x) +{ int k ; + + pg72x->block_curr ++ ; + pg72x->sample_curr = 0 ; + + if (pg72x->block_curr > pg72x->blocks_total) + { memset (pg72x->samples, 0, G72x_BLOCK_SIZE * sizeof (short)) ; + return 1 ; + } ; + + if ((k = psf_fread (pg72x->block, 1, pg72x->bytesperblock, psf)) != pg72x->bytesperblock) + psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, pg72x->bytesperblock) ; + + pg72x->blocksize = k ; + g72x_decode_block (pg72x->private, pg72x->block, pg72x->samples) ; + + return 1 ; +} /* psf_g72x_decode_block */ + +static int +g72x_read_block (SF_PRIVATE *psf, G72x_PRIVATE *pg72x, short *ptr, int len) +{ int count, total = 0, indx = 0 ; + + while (indx < len) + { if (pg72x->block_curr > pg72x->blocks_total) + { memset (&(ptr [indx]), 0, (len - indx) * sizeof (short)) ; + return total ; + } ; + + if (pg72x->sample_curr >= pg72x->samplesperblock) + psf_g72x_decode_block (psf, pg72x) ; + + count = pg72x->samplesperblock - pg72x->sample_curr ; + count = (len - indx > count) ? count : len - indx ; + + memcpy (&(ptr [indx]), &(pg72x->samples [pg72x->sample_curr]), count * sizeof (short)) ; + indx += count ; + pg72x->sample_curr += count ; + total = indx ; + } ; + + return total ; +} /* g72x_read_block */ + +static sf_count_t +g72x_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) +{ G72x_PRIVATE *pg72x ; + int readcount, count ; + sf_count_t total = 0 ; + + if (psf->codec_data == NULL) + return 0 ; + pg72x = (G72x_PRIVATE*) psf->codec_data ; + + while (len > 0) + { readcount = (len > 0x10000000) ? 0x10000000 : (int) len ; + + count = g72x_read_block (psf, pg72x, ptr, readcount) ; + + total += count ; + len -= count ; + + if (count != readcount) + break ; + } ; + + return total ; +} /* g72x_read_s */ + +static sf_count_t +g72x_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + G72x_PRIVATE *pg72x ; + short *sptr ; + int k, bufferlen, readcount = 0, count ; + sf_count_t total = 0 ; + + if (psf->codec_data == NULL) + return 0 ; + pg72x = (G72x_PRIVATE*) psf->codec_data ; + + sptr = ubuf.sbuf ; + bufferlen = SF_BUFFER_LEN / sizeof (short) ; + while (len > 0) + { readcount = (len >= bufferlen) ? bufferlen : (int) len ; + count = g72x_read_block (psf, pg72x, sptr, readcount) ; + + for (k = 0 ; k < readcount ; k++) + ptr [total + k] = arith_shift_left (sptr [k], 16) ; + + total += count ; + len -= readcount ; + if (count != readcount) + break ; + } ; + + return total ; +} /* g72x_read_i */ + +static sf_count_t +g72x_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + G72x_PRIVATE *pg72x ; + short *sptr ; + int k, bufferlen, readcount = 0, count ; + sf_count_t total = 0 ; + float normfact ; + + if (psf->codec_data == NULL) + return 0 ; + pg72x = (G72x_PRIVATE*) psf->codec_data ; + + normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x8000) : 1.0 ; + + sptr = ubuf.sbuf ; + bufferlen = SF_BUFFER_LEN / sizeof (short) ; + while (len > 0) + { readcount = (len >= bufferlen) ? bufferlen : (int) len ; + count = g72x_read_block (psf, pg72x, sptr, readcount) ; + for (k = 0 ; k < readcount ; k++) + ptr [total + k] = normfact * sptr [k] ; + + total += count ; + len -= readcount ; + if (count != readcount) + break ; + } ; + + return total ; +} /* g72x_read_f */ + +static sf_count_t +g72x_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + G72x_PRIVATE *pg72x ; + short *sptr ; + int k, bufferlen, readcount = 0, count ; + sf_count_t total = 0 ; + double normfact ; + + if (psf->codec_data == NULL) + return 0 ; + pg72x = (G72x_PRIVATE*) psf->codec_data ; + + normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x8000) : 1.0 ; + + sptr = ubuf.sbuf ; + bufferlen = SF_BUFFER_LEN / sizeof (short) ; + while (len > 0) + { readcount = (len >= bufferlen) ? bufferlen : (int) len ; + count = g72x_read_block (psf, pg72x, sptr, readcount) ; + for (k = 0 ; k < readcount ; k++) + ptr [total + k] = normfact * (double) (sptr [k]) ; + + total += count ; + len -= readcount ; + if (count != readcount) + break ; + } ; + + return total ; +} /* g72x_read_d */ + +static sf_count_t +g72x_seek (SF_PRIVATE *psf, int UNUSED (mode), sf_count_t UNUSED (offset)) +{ + psf_log_printf (psf, "seek unsupported\n") ; + + /* No simple solution. To do properly, would need to seek + ** to start of file and decode everything up to seek position. + ** Maybe implement SEEK_SET to 0 only? + */ + return 0 ; + +/* +** G72x_PRIVATE *pg72x ; +** int newblock, newsample, sample_curr ; +** +** if (psf->codec_data == NULL) +** return 0 ; +** pg72x = (G72x_PRIVATE*) psf->codec_data ; +** +** if (! (psf->datalength && psf->dataoffset)) +** { psf->error = SFE_BAD_SEEK ; +** return PSF_SEEK_ERROR ; +** } ; +** +** sample_curr = (8 * psf->datalength) / G721_32_BITS_PER_SAMPLE ; +** +** switch (whence) +** { case SEEK_SET : +** if (offset < 0 || offset > sample_curr) +** { psf->error = SFE_BAD_SEEK ; +** return PSF_SEEK_ERROR ; +** } ; +** newblock = offset / pg72x->samplesperblock ; +** newsample = offset % pg72x->samplesperblock ; +** break ; +** +** case SEEK_CUR : +** if (psf->current + offset < 0 || psf->current + offset > sample_curr) +** { psf->error = SFE_BAD_SEEK ; +** return PSF_SEEK_ERROR ; +** } ; +** newblock = (8 * (psf->current + offset)) / pg72x->samplesperblock ; +** newsample = (8 * (psf->current + offset)) % pg72x->samplesperblock ; +** break ; +** +** case SEEK_END : +** if (offset > 0 || sample_curr + offset < 0) +** { psf->error = SFE_BAD_SEEK ; +** return PSF_SEEK_ERROR ; +** } ; +** newblock = (sample_curr + offset) / pg72x->samplesperblock ; +** newsample = (sample_curr + offset) % pg72x->samplesperblock ; +** break ; +** +** default : +** psf->error = SFE_BAD_SEEK ; +** return PSF_SEEK_ERROR ; +** } ; +** +** if (psf->file.mode == SFM_READ) +** { psf_fseek (psf, psf->dataoffset + newblock * pg72x->blocksize, SEEK_SET) ; +** pg72x->block_curr = newblock ; +** psf_g72x_decode_block (psf, pg72x) ; +** pg72x->sample_curr = newsample ; +** } +** else +** { /+* What to do about write??? *+/ +** psf->error = SFE_BAD_SEEK ; +** return PSF_SEEK_ERROR ; +** } ; +** +** psf->current = newblock * pg72x->samplesperblock + newsample ; +** return psf->current ; +** +*/ +} /* g72x_seek */ + +/*========================================================================================== +** G72x Write Functions. +*/ + +static int +psf_g72x_encode_block (SF_PRIVATE *psf, G72x_PRIVATE *pg72x) +{ int k ; + + /* Encode the samples. */ + g72x_encode_block (pg72x->private, pg72x->samples, pg72x->block) ; + + /* Write the block to disk. */ + if ((k = psf_fwrite (pg72x->block, 1, pg72x->blocksize, psf)) != pg72x->blocksize) + psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", k, pg72x->blocksize) ; + + pg72x->sample_curr = 0 ; + pg72x->block_curr ++ ; + + /* Set samples to zero for next block. */ + memset (pg72x->samples, 0, G72x_BLOCK_SIZE * sizeof (short)) ; + + return 1 ; +} /* psf_g72x_encode_block */ + +static int +g72x_write_block (SF_PRIVATE *psf, G72x_PRIVATE *pg72x, const short *ptr, int len) +{ int count, total = 0, indx = 0 ; + + while (indx < len) + { count = pg72x->samplesperblock - pg72x->sample_curr ; + + if (count > len - indx) + count = len - indx ; + + memcpy (&(pg72x->samples [pg72x->sample_curr]), &(ptr [indx]), count * sizeof (short)) ; + indx += count ; + pg72x->sample_curr += count ; + total = indx ; + + if (pg72x->sample_curr >= pg72x->samplesperblock) + psf_g72x_encode_block (psf, pg72x) ; + } ; + + return total ; +} /* g72x_write_block */ + +static sf_count_t +g72x_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) +{ G72x_PRIVATE *pg72x ; + int writecount, count ; + sf_count_t total = 0 ; + + if (psf->codec_data == NULL) + return 0 ; + pg72x = (G72x_PRIVATE*) psf->codec_data ; + + while (len > 0) + { writecount = (len > 0x10000000) ? 0x10000000 : (int) len ; + + count = g72x_write_block (psf, pg72x, ptr, writecount) ; + + total += count ; + len -= count ; + if (count != writecount) + break ; + } ; + + return total ; +} /* g72x_write_s */ + +static sf_count_t +g72x_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + G72x_PRIVATE *pg72x ; + short *sptr ; + int k, bufferlen, writecount = 0, count ; + sf_count_t total = 0 ; + + if (psf->codec_data == NULL) + return 0 ; + pg72x = (G72x_PRIVATE*) psf->codec_data ; + + sptr = ubuf.sbuf ; + bufferlen = SF_BUFFER_LEN / sizeof (short) ; + while (len > 0) + { writecount = (len >= bufferlen) ? bufferlen : (int) len ; + for (k = 0 ; k < writecount ; k++) + sptr [k] = ptr [total + k] >> 16 ; + count = g72x_write_block (psf, pg72x, sptr, writecount) ; + + total += count ; + len -= writecount ; + if (count != writecount) + break ; + } ; + return total ; +} /* g72x_write_i */ + +static sf_count_t +g72x_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + G72x_PRIVATE *pg72x ; + short *sptr ; + int k, bufferlen, writecount = 0, count ; + sf_count_t total = 0 ; + float normfact ; + + if (psf->codec_data == NULL) + return 0 ; + pg72x = (G72x_PRIVATE*) psf->codec_data ; + + normfact = (psf->norm_float == SF_TRUE) ? (1.0 * 0x8000) : 1.0 ; + + sptr = ubuf.sbuf ; + bufferlen = SF_BUFFER_LEN / sizeof (short) ; + while (len > 0) + { writecount = (len >= bufferlen) ? bufferlen : (int) len ; + for (k = 0 ; k < writecount ; k++) + sptr [k] = psf_lrintf (normfact * ptr [total + k]) ; + count = g72x_write_block (psf, pg72x, sptr, writecount) ; + + total += count ; + len -= writecount ; + if (count != writecount) + break ; + } ; + + return total ; +} /* g72x_write_f */ + +static sf_count_t +g72x_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + G72x_PRIVATE *pg72x ; + short *sptr ; + int k, bufferlen, writecount = 0, count ; + sf_count_t total = 0 ; + double normfact ; + + if (psf->codec_data == NULL) + return 0 ; + pg72x = (G72x_PRIVATE*) psf->codec_data ; + + normfact = (psf->norm_double == SF_TRUE) ? (1.0 * 0x8000) : 1.0 ; + + sptr = ubuf.sbuf ; + bufferlen = SF_BUFFER_LEN / sizeof (short) ; + while (len > 0) + { writecount = (len >= bufferlen) ? bufferlen : (int) len ; + for (k = 0 ; k < writecount ; k++) + sptr [k] = psf_lrint (normfact * ptr [total + k]) ; + count = g72x_write_block (psf, pg72x, sptr, writecount) ; + + total += count ; + len -= writecount ; + if (count != writecount) + break ; + } ; + + return total ; +} /* g72x_write_d */ + +static int +g72x_close (SF_PRIVATE *psf) +{ G72x_PRIVATE *pg72x ; + + pg72x = (G72x_PRIVATE*) psf->codec_data ; + + if (psf->file.mode == SFM_WRITE) + { /* If a block has been partially assembled, write it out + ** as the final block. + */ + + if (pg72x->sample_curr && pg72x->sample_curr < G72x_BLOCK_SIZE) + psf_g72x_encode_block (psf, pg72x) ; + + if (psf->write_header) + psf->write_header (psf, SF_FALSE) ; + } ; + + /* Only free the pointer allocated by g72x_(reader|writer)_init. */ + free (pg72x->private) ; + + return 0 ; +} /* g72x_close */ + diff --git a/extern/libsndfile-modified/src/gsm610.c b/extern/libsndfile-modified/src/gsm610.c new file mode 100644 index 000000000..933f03f0a --- /dev/null +++ b/extern/libsndfile-modified/src/gsm610.c @@ -0,0 +1,629 @@ +/* +** Copyright (C) 1999-2019 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" +#include "wavlike.h" +#include "GSM610/gsm.h" + +#define GSM610_BLOCKSIZE 33 +#define GSM610_SAMPLES 160 + +typedef struct gsm610_tag +{ int blocks ; + int blockcount, samplecount ; + int samplesperblock, blocksize ; + + int (*decode_block) (SF_PRIVATE *psf, struct gsm610_tag *pgsm610) ; + int (*encode_block) (SF_PRIVATE *psf, struct gsm610_tag *pgsm610) ; + + short samples [WAVLIKE_GSM610_SAMPLES] ; + unsigned char block [WAVLIKE_GSM610_BLOCKSIZE] ; + + /* Damn I hate typedef-ed pointers; yes, gsm is a pointer type. */ + gsm gsm_data ; +} GSM610_PRIVATE ; + +static sf_count_t gsm610_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; +static sf_count_t gsm610_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; +static sf_count_t gsm610_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; +static sf_count_t gsm610_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; + +static sf_count_t gsm610_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; +static sf_count_t gsm610_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; +static sf_count_t gsm610_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; +static sf_count_t gsm610_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; + +static int gsm610_read_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610, short *ptr, int len) ; +static int gsm610_write_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610, const short *ptr, int len) ; + +static int gsm610_decode_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610) ; +static int gsm610_encode_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610) ; + +static int gsm610_wav_decode_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610) ; +static int gsm610_wav_encode_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610) ; + +static sf_count_t gsm610_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ; + +static int gsm610_close (SF_PRIVATE *psf) ; + +/*============================================================================================ +** WAV GSM610 initialisation function. +*/ + +int +gsm610_init (SF_PRIVATE *psf) +{ GSM610_PRIVATE *pgsm610 ; + int true_flag = 1 ; + + if (psf->codec_data != NULL) + { psf_log_printf (psf, "*** psf->codec_data is not NULL.\n") ; + return SFE_INTERNAL ; + } ; + + if (psf->file.mode == SFM_RDWR) + return SFE_BAD_MODE_RW ; + + psf->sf.seekable = SF_FALSE ; + + if ((pgsm610 = calloc (1, sizeof (GSM610_PRIVATE))) == NULL) + return SFE_MALLOC_FAILED ; + + psf->codec_data = pgsm610 ; + + memset (pgsm610, 0, sizeof (GSM610_PRIVATE)) ; + +/*============================================================ + +Need separate gsm_data structs for encode and decode. + +============================================================*/ + + if ((pgsm610->gsm_data = gsm_create ()) == NULL) + return SFE_MALLOC_FAILED ; + + switch (SF_CONTAINER (psf->sf.format)) + { case SF_FORMAT_WAV : + case SF_FORMAT_WAVEX : + case SF_FORMAT_W64 : + gsm_option (pgsm610->gsm_data, GSM_OPT_WAV49, &true_flag) ; + + pgsm610->encode_block = gsm610_wav_encode_block ; + pgsm610->decode_block = gsm610_wav_decode_block ; + + pgsm610->samplesperblock = WAVLIKE_GSM610_SAMPLES ; + pgsm610->blocksize = WAVLIKE_GSM610_BLOCKSIZE ; + break ; + + case SF_FORMAT_AIFF : + case SF_FORMAT_RAW : + pgsm610->encode_block = gsm610_encode_block ; + pgsm610->decode_block = gsm610_decode_block ; + + pgsm610->samplesperblock = GSM610_SAMPLES ; + pgsm610->blocksize = GSM610_BLOCKSIZE ; + break ; + + default : + return SFE_INTERNAL ; + break ; + } ; + + if (psf->file.mode == SFM_READ) + { if (psf->datalength % pgsm610->blocksize == 0) + pgsm610->blocks = psf->datalength / pgsm610->blocksize ; + else if (psf->datalength % pgsm610->blocksize == 1 && pgsm610->blocksize == GSM610_BLOCKSIZE) + { /* + ** Weird AIFF specific case. + ** AIFF chunks must be at an even offset from the start of file and + ** GSM610_BLOCKSIZE is odd which can result in an odd length SSND + ** chunk. The SSND chunk then gets padded on write which means that + ** when it is read the datalength is too big by 1. + */ + pgsm610->blocks = psf->datalength / pgsm610->blocksize ; + } + else + { psf_log_printf (psf, "*** Warning : data chunk seems to be truncated.\n") ; + pgsm610->blocks = psf->datalength / pgsm610->blocksize + 1 ; + } ; + + psf->sf.frames = (sf_count_t) pgsm610->samplesperblock * pgsm610->blocks ; + + psf_fseek (psf, psf->dataoffset, SEEK_SET) ; + + pgsm610->decode_block (psf, pgsm610) ; /* Read first block. */ + + psf->read_short = gsm610_read_s ; + psf->read_int = gsm610_read_i ; + psf->read_float = gsm610_read_f ; + psf->read_double = gsm610_read_d ; + } ; + + if (psf->file.mode == SFM_WRITE) + { pgsm610->blockcount = 0 ; + pgsm610->samplecount = 0 ; + + psf->write_short = gsm610_write_s ; + psf->write_int = gsm610_write_i ; + psf->write_float = gsm610_write_f ; + psf->write_double = gsm610_write_d ; + } ; + + psf->codec_close = gsm610_close ; + + psf->seek = gsm610_seek ; + + psf->filelength = psf_get_filelen (psf) ; + psf->datalength = psf->filelength - psf->dataoffset ; + + return 0 ; +} /* gsm610_init */ + +/*============================================================================================ +** GSM 6.10 Read Functions. +*/ + +static int +gsm610_wav_decode_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610) +{ int k ; + + pgsm610->blockcount ++ ; + pgsm610->samplecount = 0 ; + + if (pgsm610->blockcount > pgsm610->blocks) + { memset (pgsm610->samples, 0, sizeof (pgsm610->samples)) ; + return 1 ; + } ; + + if ((k = (int) psf_fread (pgsm610->block, 1, WAVLIKE_GSM610_BLOCKSIZE, psf)) != WAVLIKE_GSM610_BLOCKSIZE) + psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, WAVLIKE_GSM610_BLOCKSIZE) ; + + if (gsm_decode (pgsm610->gsm_data, pgsm610->block, pgsm610->samples) < 0) + { psf_log_printf (psf, "Error from WAV gsm_decode() on frame : %d\n", pgsm610->blockcount) ; + return 0 ; + } ; + + if (gsm_decode (pgsm610->gsm_data, pgsm610->block + (WAVLIKE_GSM610_BLOCKSIZE + 1) / 2, pgsm610->samples + WAVLIKE_GSM610_SAMPLES / 2) < 0) + { psf_log_printf (psf, "Error from WAV gsm_decode() on frame : %d.5\n", pgsm610->blockcount) ; + return 0 ; + } ; + + return 1 ; +} /* gsm610_wav_decode_block */ + +static int +gsm610_decode_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610) +{ int k ; + + pgsm610->blockcount ++ ; + pgsm610->samplecount = 0 ; + + if (pgsm610->blockcount > pgsm610->blocks) + { memset (pgsm610->samples, 0, sizeof (pgsm610->samples)) ; + return 1 ; + } ; + + if ((k = (int) psf_fread (pgsm610->block, 1, GSM610_BLOCKSIZE, psf)) != GSM610_BLOCKSIZE) + psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, GSM610_BLOCKSIZE) ; + + if (gsm_decode (pgsm610->gsm_data, pgsm610->block, pgsm610->samples) < 0) + { psf_log_printf (psf, "Error from standard gsm_decode() on frame : %d\n", pgsm610->blockcount) ; + return 0 ; + } ; + + return 1 ; +} /* gsm610_decode_block */ + +static int +gsm610_read_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610, short *ptr, int len) +{ int count, total = 0, indx = 0 ; + + while (indx < len) + { if (pgsm610->blockcount >= pgsm610->blocks && pgsm610->samplecount >= pgsm610->samplesperblock) + { memset (ptr + indx, 0, (len - indx) * sizeof (short)) ; + return total ; + } ; + + if (pgsm610->samplecount >= pgsm610->samplesperblock) + pgsm610->decode_block (psf, pgsm610) ; + + count = pgsm610->samplesperblock - pgsm610->samplecount ; + count = (len - indx > count) ? count : len - indx ; + + memcpy (&(ptr [indx]), &(pgsm610->samples [pgsm610->samplecount]), count * sizeof (short)) ; + indx += count ; + pgsm610->samplecount += count ; + total = indx ; + } ; + + return total ; +} /* gsm610_read_block */ + +static sf_count_t +gsm610_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) +{ GSM610_PRIVATE *pgsm610 ; + int readcount, count ; + sf_count_t total = 0 ; + + if (psf->codec_data == NULL) + return 0 ; + pgsm610 = (GSM610_PRIVATE*) psf->codec_data ; + + while (len > 0) + { readcount = (len > 0x10000000) ? 0x1000000 : (int) len ; + + count = gsm610_read_block (psf, pgsm610, ptr, readcount) ; + + total += count ; + len -= count ; + + if (count != readcount) + break ; + } ; + + return total ; +} /* gsm610_read_s */ + +static sf_count_t +gsm610_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) +{ GSM610_PRIVATE *pgsm610 ; + BUF_UNION ubuf ; + short *sptr ; + int k, bufferlen, readcount = 0, count ; + sf_count_t total = 0 ; + + if (psf->codec_data == NULL) + return 0 ; + pgsm610 = (GSM610_PRIVATE*) psf->codec_data ; + + sptr = ubuf.sbuf ; + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + while (len > 0) + { readcount = (len >= bufferlen) ? bufferlen : (int) len ; + count = gsm610_read_block (psf, pgsm610, sptr, readcount) ; + for (k = 0 ; k < readcount ; k++) + ptr [total + k] = arith_shift_left (sptr [k], 16) ; + + total += count ; + len -= readcount ; + } ; + return total ; +} /* gsm610_read_i */ + +static sf_count_t +gsm610_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) +{ GSM610_PRIVATE *pgsm610 ; + BUF_UNION ubuf ; + short *sptr ; + int k, bufferlen, readcount = 0, count ; + sf_count_t total = 0 ; + float normfact ; + + if (psf->codec_data == NULL) + return 0 ; + pgsm610 = (GSM610_PRIVATE*) psf->codec_data ; + + normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x8000) : 1.0 ; + + sptr = ubuf.sbuf ; + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + while (len > 0) + { readcount = (len >= bufferlen) ? bufferlen : (int) len ; + count = gsm610_read_block (psf, pgsm610, sptr, readcount) ; + for (k = 0 ; k < readcount ; k++) + ptr [total + k] = normfact * sptr [k] ; + + total += count ; + len -= readcount ; + } ; + return total ; +} /* gsm610_read_f */ + +static sf_count_t +gsm610_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) +{ GSM610_PRIVATE *pgsm610 ; + BUF_UNION ubuf ; + short *sptr ; + int k, bufferlen, readcount = 0, count ; + sf_count_t total = 0 ; + double normfact ; + + normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x8000) : 1.0 ; + + if (psf->codec_data == NULL) + return 0 ; + pgsm610 = (GSM610_PRIVATE*) psf->codec_data ; + + sptr = ubuf.sbuf ; + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + while (len > 0) + { readcount = (len >= bufferlen) ? bufferlen : (int) len ; + count = gsm610_read_block (psf, pgsm610, sptr, readcount) ; + for (k = 0 ; k < readcount ; k++) + ptr [total + k] = normfact * sptr [k] ; + + total += count ; + len -= readcount ; + } ; + return total ; +} /* gsm610_read_d */ + +static sf_count_t +gsm610_seek (SF_PRIVATE *psf, int UNUSED (mode), sf_count_t offset) +{ GSM610_PRIVATE *pgsm610 ; + int newblock, newsample ; + + if (psf->codec_data == NULL) + return 0 ; + pgsm610 = (GSM610_PRIVATE*) psf->codec_data ; + + if (psf->dataoffset < 0) + { psf->error = SFE_BAD_SEEK ; + return PSF_SEEK_ERROR ; + } ; + + if (offset == 0) + { int true_flag = 1 ; + + psf_fseek (psf, psf->dataoffset, SEEK_SET) ; + pgsm610->blockcount = 0 ; + + gsm_init (pgsm610->gsm_data) ; + if ((SF_CONTAINER (psf->sf.format)) == SF_FORMAT_WAV || + (SF_CONTAINER (psf->sf.format)) == SF_FORMAT_W64) + gsm_option (pgsm610->gsm_data, GSM_OPT_WAV49, &true_flag) ; + + pgsm610->decode_block (psf, pgsm610) ; + pgsm610->samplecount = 0 ; + return 0 ; + } ; + + if (offset < 0 || offset > pgsm610->blocks * pgsm610->samplesperblock) + { psf->error = SFE_BAD_SEEK ; + return PSF_SEEK_ERROR ; + } ; + + newblock = offset / pgsm610->samplesperblock ; + newsample = offset % pgsm610->samplesperblock ; + + if (psf->file.mode == SFM_READ) + { if (psf->read_current != newblock * pgsm610->samplesperblock + newsample) + { psf_fseek (psf, psf->dataoffset + newblock * pgsm610->samplesperblock, SEEK_SET) ; + pgsm610->blockcount = newblock ; + pgsm610->decode_block (psf, pgsm610) ; + pgsm610->samplecount = newsample ; + } ; + + return newblock * pgsm610->samplesperblock + newsample ; + } ; + + /* What to do about write??? */ + psf->error = SFE_BAD_SEEK ; + return PSF_SEEK_ERROR ; +} /* gsm610_seek */ + +/*========================================================================================== +** GSM 6.10 Write Functions. +*/ + +static int +gsm610_encode_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610) +{ int k ; + + /* Encode the samples. */ + gsm_encode (pgsm610->gsm_data, pgsm610->samples, pgsm610->block) ; + + /* Write the block to disk. */ + if ((k = (int) psf_fwrite (pgsm610->block, 1, GSM610_BLOCKSIZE, psf)) != GSM610_BLOCKSIZE) + psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", k, GSM610_BLOCKSIZE) ; + + pgsm610->samplecount = 0 ; + pgsm610->blockcount ++ ; + + /* Set samples to zero for next block. */ + memset (pgsm610->samples, 0, sizeof (pgsm610->samples)) ; + + return 1 ; +} /* gsm610_encode_block */ + +static int +gsm610_wav_encode_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610) +{ int k ; + + /* Encode the samples. */ + gsm_encode (pgsm610->gsm_data, pgsm610->samples, pgsm610->block) ; + gsm_encode (pgsm610->gsm_data, pgsm610->samples+WAVLIKE_GSM610_SAMPLES / 2, pgsm610->block+WAVLIKE_GSM610_BLOCKSIZE / 2) ; + + /* Write the block to disk. */ + if ((k = (int) psf_fwrite (pgsm610->block, 1, WAVLIKE_GSM610_BLOCKSIZE, psf)) != WAVLIKE_GSM610_BLOCKSIZE) + psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", k, WAVLIKE_GSM610_BLOCKSIZE) ; + + pgsm610->samplecount = 0 ; + pgsm610->blockcount ++ ; + + /* Set samples to zero for next block. */ + memset (pgsm610->samples, 0, sizeof (pgsm610->samples)) ; + + return 1 ; +} /* gsm610_wav_encode_block */ + +static int +gsm610_write_block (SF_PRIVATE *psf, GSM610_PRIVATE *pgsm610, const short *ptr, int len) +{ int count, total = 0, indx = 0 ; + + while (indx < len) + { count = pgsm610->samplesperblock - pgsm610->samplecount ; + + if (count > len - indx) + count = len - indx ; + + memcpy (&(pgsm610->samples [pgsm610->samplecount]), &(ptr [indx]), count * sizeof (short)) ; + indx += count ; + pgsm610->samplecount += count ; + total = indx ; + + if (pgsm610->samplecount >= pgsm610->samplesperblock) + pgsm610->encode_block (psf, pgsm610) ; + } ; + + return total ; +} /* gsm610_write_block */ + +static sf_count_t +gsm610_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) +{ GSM610_PRIVATE *pgsm610 ; + int writecount, count ; + sf_count_t total = 0 ; + + if (psf->codec_data == NULL) + return 0 ; + pgsm610 = (GSM610_PRIVATE*) psf->codec_data ; + + while (len > 0) + { writecount = (len > 0x10000000) ? 0x10000000 : (int) len ; + + count = gsm610_write_block (psf, pgsm610, ptr, writecount) ; + + total += count ; + len -= count ; + + if (count != writecount) + break ; + } ; + + return total ; +} /* gsm610_write_s */ + +static sf_count_t +gsm610_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) +{ GSM610_PRIVATE *pgsm610 ; + BUF_UNION ubuf ; + short *sptr ; + int k, bufferlen, writecount = 0, count ; + sf_count_t total = 0 ; + + if (psf->codec_data == NULL) + return 0 ; + pgsm610 = (GSM610_PRIVATE*) psf->codec_data ; + + sptr = ubuf.sbuf ; + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + while (len > 0) + { writecount = (len >= bufferlen) ? bufferlen : (int) len ; + for (k = 0 ; k < writecount ; k++) + sptr [k] = ptr [total + k] >> 16 ; + count = gsm610_write_block (psf, pgsm610, sptr, writecount) ; + + total += count ; + len -= writecount ; + } ; + return total ; +} /* gsm610_write_i */ + +static sf_count_t +gsm610_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) +{ GSM610_PRIVATE *pgsm610 ; + BUF_UNION ubuf ; + short *sptr ; + int k, bufferlen, writecount = 0, count ; + sf_count_t total = 0 ; + float normfact ; + + if (psf->codec_data == NULL) + return 0 ; + pgsm610 = (GSM610_PRIVATE*) psf->codec_data ; + + normfact = (psf->norm_float == SF_TRUE) ? (1.0 * 0x7FFF) : 1.0 ; + + sptr = ubuf.sbuf ; + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + while (len > 0) + { writecount = (len >= bufferlen) ? bufferlen : (int) len ; + for (k = 0 ; k < writecount ; k++) + sptr [k] = psf_lrintf (normfact * ptr [total + k]) ; + count = gsm610_write_block (psf, pgsm610, sptr, writecount) ; + + total += count ; + len -= writecount ; + if (count != writecount) + break ; + } ; + return total ; +} /* gsm610_write_f */ + +static sf_count_t +gsm610_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) +{ GSM610_PRIVATE *pgsm610 ; + BUF_UNION ubuf ; + short *sptr ; + int k, bufferlen, writecount = 0, count ; + sf_count_t total = 0 ; + double normfact ; + + if (psf->codec_data == NULL) + return 0 ; + pgsm610 = (GSM610_PRIVATE*) psf->codec_data ; + + normfact = (psf->norm_double == SF_TRUE) ? (1.0 * 0x7FFF) : 1.0 ; + + sptr = ubuf.sbuf ; + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + while (len > 0) + { writecount = (len >= bufferlen) ? bufferlen : (int) len ; + for (k = 0 ; k < writecount ; k++) + sptr [k] = psf_lrint (normfact * ptr [total + k]) ; + count = gsm610_write_block (psf, pgsm610, sptr, writecount) ; + + total += count ; + len -= writecount ; + } ; + return total ; +} /* gsm610_write_d */ + +static int +gsm610_close (SF_PRIVATE *psf) +{ GSM610_PRIVATE *pgsm610 ; + + if (psf->codec_data == NULL) + return 0 ; + + pgsm610 = (GSM610_PRIVATE*) psf->codec_data ; + + if (psf->file.mode == SFM_WRITE) + { /* If a block has been partially assembled, write it out + ** as the final block. + */ + + if (pgsm610->samplecount && pgsm610->samplecount < pgsm610->samplesperblock) + pgsm610->encode_block (psf, pgsm610) ; + } ; + + if (pgsm610->gsm_data) + gsm_destroy (pgsm610->gsm_data) ; + + return 0 ; +} /* gsm610_close */ + diff --git a/extern/libsndfile-modified/src/htk.c b/extern/libsndfile-modified/src/htk.c new file mode 100644 index 000000000..1041a8481 --- /dev/null +++ b/extern/libsndfile-modified/src/htk.c @@ -0,0 +1,226 @@ +/* +** Copyright (C) 2002-2017 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + +/*------------------------------------------------------------------------------ +** Macros to handle big/little endian issues. +*/ + +#define SFE_HTK_BAD_FILE_LEN 1666 +#define SFE_HTK_NOT_WAVEFORM 1667 + +/*------------------------------------------------------------------------------ +** Private static functions. +*/ + +static int htk_close (SF_PRIVATE *psf) ; + +static int htk_write_header (SF_PRIVATE *psf, int calc_length) ; +static int htk_read_header (SF_PRIVATE *psf) ; + +/*------------------------------------------------------------------------------ +** Public function. +*/ + +int +htk_open (SF_PRIVATE *psf) +{ int subformat ; + int error = 0 ; + + if (psf->is_pipe) + return SFE_HTK_NO_PIPE ; + + if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0)) + { if ((error = htk_read_header (psf))) + return error ; + } ; + + subformat = SF_CODEC (psf->sf.format) ; + + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_HTK) + return SFE_BAD_OPEN_FORMAT ; + + psf->endian = SF_ENDIAN_BIG ; + + if (htk_write_header (psf, SF_FALSE)) + return psf->error ; + + psf->write_header = htk_write_header ; + } ; + + psf->container_close = htk_close ; + + psf->blockwidth = psf->bytewidth * psf->sf.channels ; + + switch (subformat) + { case SF_FORMAT_PCM_16 : /* 16-bit linear PCM. */ + error = pcm_init (psf) ; + break ; + + default : break ; + } ; + + return error ; +} /* htk_open */ + +/*------------------------------------------------------------------------------ +*/ + +static int +htk_close (SF_PRIVATE *psf) +{ + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + htk_write_header (psf, SF_TRUE) ; + + return 0 ; +} /* htk_close */ + +static int +htk_write_header (SF_PRIVATE *psf, int calc_length) +{ sf_count_t current ; + int sample_count, sample_period ; + + current = psf_ftell (psf) ; + + if (calc_length) + psf->filelength = psf_get_filelen (psf) ; + + /* Reset the current header length to zero. */ + psf->header.ptr [0] = 0 ; + psf->header.indx = 0 ; + psf_fseek (psf, 0, SEEK_SET) ; + + if (psf->filelength > 12) + sample_count = (psf->filelength - 12) / 2 ; + else + sample_count = 0 ; + + sample_period = 10000000 / psf->sf.samplerate ; + + psf_binheader_writef (psf, "E444", BHW4 (sample_count), BHW4 (sample_period), BHW4 (0x20000)) ; + + /* Header construction complete so write it out. */ + psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ; + + if (psf->error) + return psf->error ; + + psf->dataoffset = psf->header.indx ; + + if (current > 0) + psf_fseek (psf, current, SEEK_SET) ; + + return psf->error ; +} /* htk_write_header */ + +/* +** Found the following info in a comment block within Bill Schottstaedt's +** sndlib library. +** +** HTK format files consist of a contiguous sequence of samples preceded by a +** header. Each sample is a vector of either 2-byte integers or 4-byte floats. +** 2-byte integers are used for compressed forms as described below and for +** vector quantised data as described later in section 5.11. HTK format data +** files can also be used to store speech waveforms as described in section 5.8. +** +** The HTK file format header is 12 bytes long and contains the following data +** nSamples -- number of samples in file (4-byte integer) +** sampPeriod -- sample period in 100ns units (4-byte integer) +** sampSize -- number of bytes per sample (2-byte integer) +** parmKind -- a code indicating the sample kind (2-byte integer) +** +** The parameter kind consists of a 6 bit code representing the basic +** parameter kind plus additional bits for each of the possible qualifiers. +** The basic parameter kind codes are +** +** 0 WAVEFORM sampled waveform +** 1 LPC linear prediction filter coefficients +** 2 LPREFC linear prediction reflection coefficients +** 3 LPCEPSTRA LPC cepstral coefficients +** 4 LPDELCEP LPC cepstra plus delta coefficients +** 5 IREFC LPC reflection coef in 16 bit integer format +** 6 MFCC mel-frequency cepstral coefficients +** 7 FBANK log mel-filter bank channel outputs +** 8 MELSPEC linear mel-filter bank channel outputs +** 9 USER user defined sample kind +** 10 DISCRETE vector quantised data +** +** and the bit-encoding for the qualifiers (in octal) is +** _E 000100 has energy +** _N 000200 absolute energy suppressed +** _D 000400 has delta coefficients +** _A 001000 has acceleration coefficients +** _C 002000 is compressed +** _Z 004000 has zero mean static coef. +** _K 010000 has CRC checksum +** _O 020000 has 0'th cepstral coef. +*/ + +static int +htk_read_header (SF_PRIVATE *psf) +{ int sample_count, sample_period, marker ; + + psf_binheader_readf (psf, "pE444", 0, &sample_count, &sample_period, &marker) ; + + if (2 * sample_count + 12 != psf->filelength) + return SFE_HTK_BAD_FILE_LEN ; + + if (marker != 0x20000) + return SFE_HTK_NOT_WAVEFORM ; + + psf->sf.channels = 1 ; + + if (sample_period > 0) + { psf->sf.samplerate = 10000000 / sample_period ; + psf_log_printf (psf, "HTK Waveform file\n Sample Count : %d\n Sample Period : %d => %d Hz\n", + sample_count, sample_period, psf->sf.samplerate) ; + } + else + { psf->sf.samplerate = 16000 ; + psf_log_printf (psf, "HTK Waveform file\n Sample Count : %d\n Sample Period : %d (should be > 0) => Guessed sample rate %d Hz\n", + sample_count, sample_period, psf->sf.samplerate) ; + } ; + + psf->sf.format = SF_FORMAT_HTK | SF_FORMAT_PCM_16 ; + psf->bytewidth = 2 ; + + /* HTK always has a 12 byte header. */ + psf->dataoffset = 12 ; + psf->endian = SF_ENDIAN_BIG ; + + psf->datalength = psf->filelength - psf->dataoffset ; + + psf->blockwidth = psf->sf.channels * psf->bytewidth ; + + if (! psf->sf.frames && psf->blockwidth) + psf->sf.frames = (psf->filelength - psf->dataoffset) / psf->blockwidth ; + + return 0 ; +} /* htk_read_header */ + diff --git a/extern/libsndfile-modified/src/id3.c b/extern/libsndfile-modified/src/id3.c new file mode 100644 index 000000000..1516ee316 --- /dev/null +++ b/extern/libsndfile-modified/src/id3.c @@ -0,0 +1,132 @@ +/* +** Copyright (C) 2010-2017 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" +#include "id3.h" + +#if HAVE_MPEG +#include + +struct id3v1_genre_handler_userdata +{ int number ; + const char *ret ; +} ; + +static void +id3v1_genre_handler (int number, const char *description, void *userdata) +{ struct id3v1_genre_handler_userdata *data = (struct id3v1_genre_handler_userdata *) userdata ; + if (data->number == number) + data->ret = description ; +} + +const char * +id3_lookup_v1_genre (int number) +{ struct id3v1_genre_handler_userdata data ; + + data.number = number ; + data.ret = NULL ; + id3tag_genre_list (id3v1_genre_handler, &data) ; + + return data.ret ; +} + +#else /* HAVE_MPEG */ + +const char * +id3_lookup_v1_genre (int UNUSED (number)) +{ return NULL ; + } + +#endif + +int +id3_skip (SF_PRIVATE * psf) +{ unsigned char buf [10] ; + int offset ; + + memset (buf, 0, sizeof (buf)) ; + psf_binheader_readf (psf, "pb", 0, buf, 10) ; + + if (buf [0] == 'I' && buf [1] == 'D' && buf [2] == '3') + { psf->id3_header.minor_version = buf [3] ; + offset = buf [6] & 0x7f ; + offset = (offset << 7) | (buf [7] & 0x7f) ; + offset = (offset << 7) | (buf [8] & 0x7f) ; + offset = (offset << 7) | (buf [9] & 0x7f) ; + + /* + ** ID3 count field is how many bytes of ID3v2 header FOLLOW the ten + ** bytes of header magic and offset, NOT the total ID3v2 header len. + */ + psf->id3_header.len = offset + 10 ; + psf->id3_header.offset = psf->fileoffset ; + + psf_log_printf (psf, " ID3v2.%d header length : %d\n----------------------------------------\n", + psf->id3_header.minor_version, psf->id3_header.len) ; + + /* Never want to jump backwards in a file. */ + if (offset < 0) + return 0 ; + + /* Position ourselves at the new file offset. */ + if (psf->fileoffset + psf->id3_header.len < psf->filelength) + { psf_binheader_readf (psf, "p!", psf->id3_header.len) ; + psf->fileoffset += psf->id3_header.len ; + return 1 ; + } ; + } ; + + return 0 ; +} /* id3_skip */ + +const char * +id3_process_v2_genre (const char *genre) +{ int num = 0 ; + char c ; + const char *ptr ; + + if (!genre) + return NULL ; + + /* + ** Genre may require more processing. + ** + ** It is allowed to have numeric references to the genre table from ID3v1. + ** We'll just convert the simple case here, strings of the format "(nnn)". + */ + ptr = genre ; + if (ptr [0] == '(' && (c = *++ ptr) && isdigit (c)) + { num = c - '0' ; + while ((c == *++ ptr) && isdigit (c)) + num = num * 10 + (c - '0') ; + if (c == ')' && (c = *++ ptr) == '\0' && num < 256) + if ((ptr = id3_lookup_v1_genre (num))) + return ptr ; + } ; + + return genre ; +} /* id3_process_v2_genre */ diff --git a/extern/libsndfile-modified/src/id3.h b/extern/libsndfile-modified/src/id3.h new file mode 100644 index 000000000..4f54c4fca --- /dev/null +++ b/extern/libsndfile-modified/src/id3.h @@ -0,0 +1,29 @@ +/* +** Copyright (C) 2008-2019 Erik de Castro Lopo +** Copyright (C) 2019 Arthur Taylor +** +** This program is free software ; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation ; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY ; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program ; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef SF_SRC_ID3_H +#define SF_SRC_ID3_H + +int id3_skip (SF_PRIVATE * psf) ; + +const char *id3_lookup_v1_genre (int number) ; + +const char *id3_process_v2_genre (const char *genre) ; + +#endif /* SF_SRC_ID3_H */ diff --git a/extern/libsndfile-modified/src/ima_adpcm.c b/extern/libsndfile-modified/src/ima_adpcm.c new file mode 100644 index 000000000..bc61f4e5a --- /dev/null +++ b/extern/libsndfile-modified/src/ima_adpcm.c @@ -0,0 +1,1008 @@ +/* +** Copyright (C) 1999-2020 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + +typedef struct IMA_ADPCM_PRIVATE_tag +{ int (*decode_block) (SF_PRIVATE *psf, struct IMA_ADPCM_PRIVATE_tag *pima) ; + int (*encode_block) (SF_PRIVATE *psf, struct IMA_ADPCM_PRIVATE_tag *pima) ; + + int channels, blocksize, samplesperblock, blocks ; + int blockcount, samplecount ; + int previous [2] ; + int stepindx [2] ; + unsigned char *block ; + short *samples ; + short data [] ; /* ISO C99 struct flexible array. */ +} IMA_ADPCM_PRIVATE ; + +/*============================================================================================ +** Predefined IMA ADPCM data. +*/ + +static int ima_indx_adjust [16] = +{ -1, -1, -1, -1, /* +0 - +3, decrease the step size */ + +2, +4, +6, +8, /* +4 - +7, increase the step size */ + -1, -1, -1, -1, /* -0 - -3, decrease the step size */ + +2, +4, +6, +8, /* -4 - -7, increase the step size */ +} ; + +static int ima_step_size [89] = +{ 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, + 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, + 253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963, + 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, + 3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493, 10442, + 11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, + 32767 +} ; + +static int ima_reader_init (SF_PRIVATE *psf, int blockalign, int samplesperblock) ; +static int ima_writer_init (SF_PRIVATE *psf, int blockalign) ; + +static int ima_read_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima, short *ptr, int len) ; +static int ima_write_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima, const short *ptr, int len) ; + +static sf_count_t ima_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; +static sf_count_t ima_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; +static sf_count_t ima_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; +static sf_count_t ima_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; + +static sf_count_t ima_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; +static sf_count_t ima_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; +static sf_count_t ima_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; +static sf_count_t ima_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; + +static sf_count_t aiff_ima_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ; +static sf_count_t wavlike_ima_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ; + +static int ima_close (SF_PRIVATE *psf) ; + +static int wavlike_ima_decode_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima) ; +static int wavlike_ima_encode_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima) ; + +/*-static int aiff_ima_reader_init (SF_PRIVATE *psf, int blockalign, int samplesperblock) ;-*/ +static int aiff_ima_decode_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima) ; +static int aiff_ima_encode_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima) ; + + +static inline int +clamp_ima_step_index (int indx) +{ if (indx < 0) + return 0 ; + if (indx >= ARRAY_LEN (ima_step_size)) + return ARRAY_LEN (ima_step_size) - 1 ; + + return indx ; +} /* clamp_ima_step_index */ + +/*============================================================================================ +** IMA ADPCM Reader initialisation function. +*/ + +int +wavlike_ima_init (SF_PRIVATE *psf, int blockalign, int samplesperblock) +{ int error ; + + if (psf->codec_data != NULL) + { psf_log_printf (psf, "*** psf->codec_data is not NULL.\n") ; + return SFE_INTERNAL ; + } ; + + if (psf->file.mode == SFM_RDWR) + return SFE_BAD_MODE_RW ; + + if (psf->file.mode == SFM_READ) + if ((error = ima_reader_init (psf, blockalign, samplesperblock))) + return error ; + + if (psf->file.mode == SFM_WRITE) + if ((error = ima_writer_init (psf, blockalign))) + return error ; + + psf->codec_close = ima_close ; + psf->seek = wavlike_ima_seek ; + + return 0 ; +} /* wavlike_ima_init */ + +int +aiff_ima_init (SF_PRIVATE *psf, int blockalign, int samplesperblock) +{ int error ; + + if (psf->file.mode == SFM_RDWR) + return SFE_BAD_MODE_RW ; + + if (psf->file.mode == SFM_READ) + if ((error = ima_reader_init (psf, blockalign, samplesperblock))) + return error ; + + if (psf->file.mode == SFM_WRITE) + if ((error = ima_writer_init (psf, blockalign))) + return error ; + + psf->codec_close = ima_close ; + psf->seek = aiff_ima_seek ; + + return 0 ; +} /* aiff_ima_init */ + +static int +ima_close (SF_PRIVATE *psf) +{ IMA_ADPCM_PRIVATE *pima ; + + pima = (IMA_ADPCM_PRIVATE*) psf->codec_data ; + + if (psf->file.mode == SFM_WRITE) + { /* If a block has been partially assembled, write it out + ** as the final block. + */ + if (pima->samplecount && pima->samplecount < pima->samplesperblock) + pima->encode_block (psf, pima) ; + + psf->sf.frames = pima->samplesperblock * pima->blockcount / psf->sf.channels ; + } ; + + return 0 ; +} /* ima_close */ + +/*============================================================================================ +** IMA ADPCM Read Functions. +*/ + +static int +ima_reader_init (SF_PRIVATE *psf, int blockalign, int samplesperblock) +{ IMA_ADPCM_PRIVATE *pima ; + int pimasize, count ; + + if (psf->file.mode != SFM_READ) + return SFE_BAD_MODE_RW ; + + /* + ** Allocate enough space for 1 more than a multiple of 8 samples + ** to avoid having to branch when pulling apart the nibbles. + */ + count = ((samplesperblock - 2) | 7) + 2 ; + pimasize = sizeof (IMA_ADPCM_PRIVATE) + psf->sf.channels * (blockalign + samplesperblock + sizeof(short) * count) ; + + if (! (pima = calloc (1, pimasize))) + return SFE_MALLOC_FAILED ; + + psf->codec_data = (void*) pima ; + + pima->samples = pima->data ; + pima->block = (unsigned char*) (pima->data + samplesperblock * psf->sf.channels) ; + + pima->channels = psf->sf.channels ; + pima->blocksize = blockalign ; + pima->samplesperblock = samplesperblock ; + + psf->filelength = psf_get_filelen (psf) ; + psf->datalength = (psf->dataend) ? psf->dataend - psf->dataoffset : + psf->filelength - psf->dataoffset ; + + if (pima->blocksize <= 0) + { psf_log_printf (psf, "*** Error : pima->blocksize should be > 0.\n") ; + return SFE_INTERNAL ; + } ; + + if (pima->samplesperblock <= 0) + { psf_log_printf (psf, "*** Error : pima->samplesperblock should be > 0.\n") ; + return SFE_INTERNAL ; + } ; + + if (psf->datalength % pima->blocksize) + pima->blocks = psf->datalength / pima->blocksize + 1 ; + else + pima->blocks = psf->datalength / pima->blocksize ; + + switch (SF_CONTAINER (psf->sf.format)) + { case SF_FORMAT_WAV : + case SF_FORMAT_W64 : + count = 2 * (pima->blocksize - 4 * pima->channels) / pima->channels + 1 ; + + if (pima->samplesperblock != count) + { psf_log_printf (psf, "*** Error : samplesperblock should be %d.\n", count) ; + return SFE_INTERNAL ; + } ; + + pima->decode_block = wavlike_ima_decode_block ; + + psf->sf.frames = pima->samplesperblock * pima->blocks ; + break ; + + case SF_FORMAT_AIFF : + psf_log_printf (psf, "still need to check block count\n") ; + pima->decode_block = aiff_ima_decode_block ; + psf->sf.frames = pima->samplesperblock * pima->blocks / pima->channels ; + break ; + + default : + psf_log_printf (psf, "ima_reader_init: bad psf->sf.format\n") ; + return SFE_INTERNAL ; + } ; + + pima->decode_block (psf, pima) ; /* Read first block. */ + + psf->read_short = ima_read_s ; + psf->read_int = ima_read_i ; + psf->read_float = ima_read_f ; + psf->read_double = ima_read_d ; + + return 0 ; +} /* ima_reader_init */ + +static int +aiff_ima_decode_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima) +{ unsigned char *blockdata ; + int chan, k, diff, bytecode, predictor ; + short step, stepindx, *sampledata ; + +static int count = 0 ; +count ++ ; + + pima->blockcount += pima->channels ; + pima->samplecount = 0 ; + + if (pima->blockcount > pima->blocks) + { memset (pima->samples, 0, pima->samplesperblock * pima->channels * sizeof (short)) ; + return 1 ; + } ; + + if ((k = (int) psf_fread (pima->block, 1, pima->blocksize * pima->channels, psf)) != pima->blocksize * pima->channels) + psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, pima->blocksize) ; + + /* Read and check the block header. */ + for (chan = 0 ; chan < pima->channels ; chan++) + { blockdata = pima->block + chan * 34 ; + sampledata = pima->samples + chan ; + + /* Sign-extend from 16 bits to 32. */ + predictor = (int) ((short) ((blockdata [0] << 8) | (blockdata [1] & 0x80))) ; + + stepindx = blockdata [1] & 0x7F ; + stepindx = clamp_ima_step_index (stepindx) ; + + /* + ** Pull apart the packed 4 bit samples and store them in their + ** correct sample positions. + */ + for (k = 0 ; k < pima->blocksize - 2 ; k++) + { bytecode = blockdata [k + 2] ; + sampledata [pima->channels * (2 * k + 0)] = bytecode & 0xF ; + sampledata [pima->channels * (2 * k + 1)] = (bytecode >> 4) & 0xF ; + } ; + + /* Decode the encoded 4 bit samples. */ + for (k = 0 ; k < pima->samplesperblock ; k ++) + { step = ima_step_size [stepindx] ; + + bytecode = pima->samples [pima->channels * k + chan] ; + + stepindx += ima_indx_adjust [bytecode] ; + stepindx = clamp_ima_step_index (stepindx) ; + + diff = step >> 3 ; + if (bytecode & 1) diff += step >> 2 ; + if (bytecode & 2) diff += step >> 1 ; + if (bytecode & 4) diff += step ; + if (bytecode & 8) diff = -diff ; + + predictor += diff ; + if (predictor < -32768) + predictor = -32768 ; + else if (predictor > 32767) + predictor = 32767 ; + + pima->samples [pima->channels * k + chan] = predictor ; + } ; + } ; + + return 1 ; +} /* aiff_ima_decode_block */ + +static int +aiff_ima_encode_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima) +{ int chan, k, step, diff, vpdiff, blockindx, indx ; + short bytecode, mask ; + + k = 0 ; + for (chan = 0 ; chan < pima->channels ; chan ++) + { blockindx = chan * pima->blocksize ; + /* Encode the block header. */ + pima->block [blockindx++] = (pima->previous [chan] >> 8) & 0xFF ; + pima->block [blockindx++] = (pima->previous [chan] & 0x80) + (pima->stepindx [chan] & 0x7F) ; + + /* Encode the samples as 4 bit. */ + for (indx = chan ; indx < pima->samplesperblock * pima->channels ; indx += pima->channels) + { diff = pima->samples [indx] - pima->previous [chan] ; + + bytecode = 0 ; + step = ima_step_size [pima->stepindx [chan]] ; + vpdiff = step >> 3 ; + if (diff < 0) + { bytecode = 8 ; + diff = -diff ; + } ; + mask = 4 ; + while (mask) + { if (diff >= step) + { bytecode |= mask ; + diff -= step ; + vpdiff += step ; + } ; + step >>= 1 ; + mask >>= 1 ; + } ; + + if (bytecode & 8) + vpdiff = -vpdiff ; + pima->previous [chan] += vpdiff ; + + if (pima->previous [chan] > 32767) + pima->previous [chan] = 32767 ; + else if (pima->previous [chan] < -32768) + pima->previous [chan] = -32768 ; + + pima->stepindx [chan] += ima_indx_adjust [bytecode] ; + + pima->stepindx [chan] = clamp_ima_step_index (pima->stepindx [chan]) ; + pima->block [blockindx] = (bytecode << (4 * k)) | pima->block [blockindx] ; + blockindx += k ; + k = 1 - k ; + } ; + } ; + + /* Write the block to disk. */ + if ((k = (int) psf_fwrite (pima->block, 1, pima->channels * pima->blocksize, psf)) != pima->channels * pima->blocksize) + psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", k, pima->channels * pima->blocksize) ; + + memset (pima->block, 0, pima->channels * pima->blocksize) ; + pima->samplecount = 0 ; + pima->blockcount ++ ; + + return 1 ; +} /* aiff_ima_encode_block */ + +static int +wavlike_ima_decode_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima) +{ int chan, k, predictor, blockindx, indx, indxstart, diff ; + short step, bytecode, stepindx [2] = { 0 }; + + pima->blockcount ++ ; + pima->samplecount = 0 ; + + if (pima->blockcount > pima->blocks) + { memset (pima->samples, 0, pima->samplesperblock * pima->channels * sizeof (short)) ; + return 1 ; + } ; + + if ((k = (int) psf_fread (pima->block, 1, pima->blocksize, psf)) != pima->blocksize) + psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, pima->blocksize) ; + + /* Read and check the block header. */ + + for (chan = 0 ; chan < pima->channels ; chan++) + { predictor = pima->block [chan*4] | (pima->block [chan*4+1] << 8) ; + if (predictor & 0x8000) + predictor -= 0x10000 ; + + stepindx [chan] = pima->block [chan*4+2] ; + stepindx [chan] = clamp_ima_step_index (stepindx [chan]) ; + + + if (pima->block [chan*4+3] != 0) + psf_log_printf (psf, "IMA ADPCM synchronisation error.\n") ; + + pima->samples [chan] = predictor ; + } ; + + /* + ** Pull apart the packed 4 bit samples and store them in their + ** correct sample positions. + */ + + blockindx = 4 * pima->channels ; + + indxstart = pima->channels ; + while (blockindx < pima->blocksize) + { for (chan = 0 ; chan < pima->channels ; chan++) + { indx = indxstart + chan ; + for (k = 0 ; k < 4 ; k++) + { bytecode = pima->block [blockindx++] ; + pima->samples [indx] = bytecode & 0x0F ; + indx += pima->channels ; + pima->samples [indx] = (bytecode >> 4) & 0x0F ; + indx += pima->channels ; + } ; + } ; + indxstart += 8 * pima->channels ; + } ; + + /* Decode the encoded 4 bit samples. */ + + for (k = pima->channels ; k < (pima->samplesperblock * pima->channels) ; k ++) + { chan = (pima->channels > 1) ? (k % 2) : 0 ; + + bytecode = pima->samples [k] & 0xF ; + + step = ima_step_size [stepindx [chan]] ; + predictor = pima->samples [k - pima->channels] ; + + diff = step >> 3 ; + if (bytecode & 1) + diff += step >> 2 ; + if (bytecode & 2) + diff += step >> 1 ; + if (bytecode & 4) + diff += step ; + if (bytecode & 8) + diff = -diff ; + + predictor += diff ; + + if (predictor > 32767) + predictor = 32767 ; + else if (predictor < -32768) + predictor = -32768 ; + + stepindx [chan] += ima_indx_adjust [bytecode] ; + stepindx [chan] = clamp_ima_step_index (stepindx [chan]) ; + + pima->samples [k] = predictor ; + } ; + + return 1 ; +} /* wavlike_ima_decode_block */ + +static int +wavlike_ima_encode_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima) +{ int chan, k, step, diff, vpdiff, blockindx, indx, indxstart ; + short bytecode, mask ; + + /* Encode the block header. */ + for (chan = 0 ; chan < pima->channels ; chan++) + { pima->block [chan*4] = pima->samples [chan] & 0xFF ; + pima->block [chan*4+1] = (pima->samples [chan] >> 8) & 0xFF ; + + pima->block [chan*4+2] = pima->stepindx [chan] ; + pima->block [chan*4+3] = 0 ; + + pima->previous [chan] = pima->samples [chan] ; + } ; + + /* Encode the samples as 4 bit. */ + + for (k = pima->channels ; k < (pima->samplesperblock * pima->channels) ; k ++) + { chan = (pima->channels > 1) ? (k % 2) : 0 ; + + diff = pima->samples [k] - pima->previous [chan] ; + + bytecode = 0 ; + step = ima_step_size [pima->stepindx [chan]] ; + vpdiff = step >> 3 ; + if (diff < 0) + { bytecode = 8 ; + diff = -diff ; + } ; + mask = 4 ; + while (mask) + { if (diff >= step) + { bytecode |= mask ; + diff -= step ; + vpdiff += step ; + } ; + step >>= 1 ; + mask >>= 1 ; + } ; + + if (bytecode & 8) + pima->previous [chan] -= vpdiff ; + else + pima->previous [chan] += vpdiff ; + + if (pima->previous [chan] > 32767) + pima->previous [chan] = 32767 ; + else if (pima->previous [chan] < -32768) + pima->previous [chan] = -32768 ; + + pima->stepindx [chan] += ima_indx_adjust [bytecode] ; + pima->stepindx [chan] = clamp_ima_step_index (pima->stepindx [chan]) ; + + pima->samples [k] = bytecode ; + } ; + + /* Pack the 4 bit encoded samples. */ + + blockindx = 4 * pima->channels ; + + indxstart = pima->channels ; + while (blockindx < pima->blocksize) + { for (chan = 0 ; chan < pima->channels ; chan++) + { indx = indxstart + chan ; + for (k = 0 ; k < 4 ; k++) + { pima->block [blockindx] = pima->samples [indx] & 0x0F ; + indx += pima->channels ; + pima->block [blockindx] |= (pima->samples [indx] << 4) & 0xF0 ; + indx += pima->channels ; + blockindx ++ ; + } ; + } ; + indxstart += 8 * pima->channels ; + } ; + + /* Write the block to disk. */ + + if ((k = (int) psf_fwrite (pima->block, 1, pima->blocksize, psf)) != pima->blocksize) + psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", k, pima->blocksize) ; + + memset (pima->samples, 0, pima->samplesperblock * sizeof (short)) ; + pima->samplecount = 0 ; + pima->blockcount ++ ; + + return 1 ; +} /* wavlike_ima_encode_block */ + +static int +ima_read_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima, short *ptr, int len) +{ int count, total = 0, indx = 0 ; + + while (indx < len) + { if (pima->blockcount >= pima->blocks && pima->samplecount >= pima->samplesperblock) + { memset (&(ptr [indx]), 0, (size_t) ((len - indx) * sizeof (short))) ; + return total ; + } ; + + if (pima->samplecount >= pima->samplesperblock) + pima->decode_block (psf, pima) ; + + count = (pima->samplesperblock - pima->samplecount) * pima->channels ; + count = (len - indx > count) ? count : len - indx ; + + memcpy (&(ptr [indx]), &(pima->samples [pima->samplecount * pima->channels]), count * sizeof (short)) ; + indx += count ; + pima->samplecount += count / pima->channels ; + total = indx ; + } ; + + return total ; +} /* ima_read_block */ + +static sf_count_t +ima_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) +{ IMA_ADPCM_PRIVATE *pima ; + int readcount, count ; + sf_count_t total = 0 ; + + if (! psf->codec_data) + return 0 ; + pima = (IMA_ADPCM_PRIVATE*) psf->codec_data ; + + while (len > 0) + { readcount = (len > 0x10000000) ? 0x10000000 : (int) len ; + + count = ima_read_block (psf, pima, ptr, readcount) ; + + total += count ; + len -= count ; + if (count != readcount) + break ; + } ; + + return total ; +} /* ima_read_s */ + +static sf_count_t +ima_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) +{ IMA_ADPCM_PRIVATE *pima ; + BUF_UNION ubuf ; + short *sptr ; + int k, bufferlen, readcount, count ; + sf_count_t total = 0 ; + + if (! psf->codec_data) + return 0 ; + pima = (IMA_ADPCM_PRIVATE*) psf->codec_data ; + + sptr = ubuf.sbuf ; + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + while (len > 0) + { readcount = (len >= bufferlen) ? bufferlen : (int) len ; + count = ima_read_block (psf, pima, sptr, readcount) ; + for (k = 0 ; k < readcount ; k++) + ptr [total + k] = arith_shift_left (sptr [k], 16) ; + total += count ; + len -= readcount ; + if (count != readcount) + break ; + } ; + + return total ; +} /* ima_read_i */ + +static sf_count_t +ima_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) +{ IMA_ADPCM_PRIVATE *pima ; + BUF_UNION ubuf ; + short *sptr ; + int k, bufferlen, readcount, count ; + sf_count_t total = 0 ; + float normfact ; + + if (! psf->codec_data) + return 0 ; + pima = (IMA_ADPCM_PRIVATE*) psf->codec_data ; + + normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x8000) : 1.0 ; + + sptr = ubuf.sbuf ; + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + while (len > 0) + { readcount = (len >= bufferlen) ? bufferlen : (int) len ; + count = ima_read_block (psf, pima, sptr, readcount) ; + for (k = 0 ; k < readcount ; k++) + ptr [total + k] = normfact * (float) (sptr [k]) ; + total += count ; + len -= readcount ; + if (count != readcount) + break ; + } ; + + return total ; +} /* ima_read_f */ + +static sf_count_t +ima_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) +{ IMA_ADPCM_PRIVATE *pima ; + BUF_UNION ubuf ; + short *sptr ; + int k, bufferlen, readcount, count ; + sf_count_t total = 0 ; + double normfact ; + + if (! psf->codec_data) + return 0 ; + pima = (IMA_ADPCM_PRIVATE*) psf->codec_data ; + + normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x8000) : 1.0 ; + + sptr = ubuf.sbuf ; + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + while (len > 0) + { readcount = (len >= bufferlen) ? bufferlen : (int) len ; + count = ima_read_block (psf, pima, sptr, readcount) ; + for (k = 0 ; k < readcount ; k++) + ptr [total + k] = normfact * (double) (sptr [k]) ; + total += count ; + len -= readcount ; + if (count != readcount) + break ; + } ; + + return total ; +} /* ima_read_d */ + +static sf_count_t +aiff_ima_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) +{ IMA_ADPCM_PRIVATE *pima ; + int newblock, newsample, newblockaiff ; + + if (! psf->codec_data) + return 0 ; + pima = (IMA_ADPCM_PRIVATE*) psf->codec_data ; + + if (psf->datalength < 0 || psf->dataoffset < 0) + { psf->error = SFE_BAD_SEEK ; + return PSF_SEEK_ERROR ; + } ; + + if (offset == 0) + { psf_fseek (psf, psf->dataoffset, SEEK_SET) ; + pima->blockcount = 0 ; + pima->decode_block (psf, pima) ; + pima->samplecount = 0 ; + return 0 ; + } ; + + if (offset < 0 || offset > pima->blocks * pima->samplesperblock) + { psf->error = SFE_BAD_SEEK ; + return PSF_SEEK_ERROR ; + } ; + + newblock = offset / pima->samplesperblock ; + newsample = offset % pima->samplesperblock ; + newblockaiff = newblock * psf->sf.channels ; + + if (mode == SFM_READ) + { psf_fseek (psf, psf->dataoffset + newblockaiff * pima->blocksize, SEEK_SET) ; + pima->blockcount = newblockaiff ; + pima->decode_block (psf, pima) ; + pima->samplecount = newsample ; + } + else + { /* What to do about write??? */ + psf->error = SFE_BAD_SEEK ; + return PSF_SEEK_ERROR ; + } ; + + return newblock * pima->samplesperblock + newsample ; +} /* aiff_ima_seek */ + +static sf_count_t +wavlike_ima_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) +{ IMA_ADPCM_PRIVATE *pima ; + int newblock, newsample ; + + if (! psf->codec_data) + return 0 ; + pima = (IMA_ADPCM_PRIVATE*) psf->codec_data ; + + if (psf->datalength < 0 || psf->dataoffset < 0) + { psf->error = SFE_BAD_SEEK ; + return PSF_SEEK_ERROR ; + } ; + + if (offset == 0) + { psf_fseek (psf, psf->dataoffset, SEEK_SET) ; + pima->blockcount = 0 ; + if (!pima->decode_block) + return PSF_SEEK_ERROR ; + + pima->decode_block (psf, pima) ; + pima->samplecount = 0 ; + return 0 ; + } ; + + if (offset < 0 || offset > pima->blocks * pima->samplesperblock) + { psf->error = SFE_BAD_SEEK ; + return PSF_SEEK_ERROR ; + } ; + + newblock = offset / pima->samplesperblock ; + newsample = offset % pima->samplesperblock ; + + if (mode == SFM_READ) + { psf_fseek (psf, psf->dataoffset + newblock * pima->blocksize, SEEK_SET) ; + pima->blockcount = newblock ; + pima->decode_block (psf, pima) ; + pima->samplecount = newsample ; + } + else + { /* What to do about write??? */ + psf->error = SFE_BAD_SEEK ; + return PSF_SEEK_ERROR ; + } ; + + return newblock * pima->samplesperblock + newsample ; +} /* wavlike_ima_seek */ + +/*========================================================================================== +** IMA ADPCM Write Functions. +*/ + +static int +ima_writer_init (SF_PRIVATE *psf, int blockalign) +{ IMA_ADPCM_PRIVATE *pima ; + int samplesperblock ; + unsigned int pimasize ; + + if (psf->file.mode != SFM_WRITE) + return SFE_BAD_MODE_RW ; + + switch (SF_CONTAINER (psf->sf.format)) + { case SF_FORMAT_WAV : + case SF_FORMAT_W64 : + samplesperblock = 2 * (blockalign - 4 * psf->sf.channels) / psf->sf.channels + 1 ; + break ; + + case SF_FORMAT_AIFF : + samplesperblock = 2 * ((blockalign - 2) * psf->sf.channels) / psf->sf.channels ; + break ; + + default : + psf_log_printf (psf, "ima_reader_init: bad psf->sf.format\n") ; + return SFE_INTERNAL ; + } ; + + pimasize = sizeof (IMA_ADPCM_PRIVATE) + blockalign + 3 * psf->sf.channels * samplesperblock ; + + if ((pima = calloc (1, pimasize)) == NULL) + return SFE_MALLOC_FAILED ; + + psf->codec_data = (void*) pima ; + + pima->channels = psf->sf.channels ; + pima->blocksize = blockalign ; + pima->samplesperblock = samplesperblock ; + + pima->block = (unsigned char*) pima->data ; + pima->samples = (short*) (pima->data + blockalign) ; + + pima->samplecount = 0 ; + + switch (SF_CONTAINER (psf->sf.format)) + { case SF_FORMAT_WAV : + case SF_FORMAT_W64 : + pima->encode_block = wavlike_ima_encode_block ; + break ; + + case SF_FORMAT_AIFF : + pima->encode_block = aiff_ima_encode_block ; + break ; + + default : + psf_log_printf (psf, "ima_reader_init: bad psf->sf.format\n") ; + return SFE_INTERNAL ; + } ; + + psf->write_short = ima_write_s ; + psf->write_int = ima_write_i ; + psf->write_float = ima_write_f ; + psf->write_double = ima_write_d ; + + return 0 ; +} /* ima_writer_init */ + +/*========================================================================================== +*/ + +static int +ima_write_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima, const short *ptr, int len) +{ int count, total = 0, indx = 0 ; + + while (indx < len) + { count = (pima->samplesperblock - pima->samplecount) * pima->channels ; + + if (count > len - indx) + count = len - indx ; + + memcpy (&(pima->samples [pima->samplecount * pima->channels]), &(ptr [total]), count * sizeof (short)) ; + indx += count ; + pima->samplecount += count / pima->channels ; + total = indx ; + + if (pima->samplecount >= pima->samplesperblock) + pima->encode_block (psf, pima) ; + } ; + + return total ; +} /* ima_write_block */ + +static sf_count_t +ima_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) +{ IMA_ADPCM_PRIVATE *pima ; + int writecount, count ; + sf_count_t total = 0 ; + + if (! psf->codec_data) + return 0 ; + pima = (IMA_ADPCM_PRIVATE*) psf->codec_data ; + + while (len) + { writecount = (len > 0x10000000) ? 0x10000000 : (int) len ; + + count = ima_write_block (psf, pima, ptr, writecount) ; + + total += count ; + len -= count ; + if (count != writecount) + break ; + } ; + + return total ; +} /* ima_write_s */ + +static sf_count_t +ima_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) +{ IMA_ADPCM_PRIVATE *pima ; + BUF_UNION ubuf ; + short *sptr ; + int k, bufferlen, writecount, count ; + sf_count_t total = 0 ; + + if (! psf->codec_data) + return 0 ; + pima = (IMA_ADPCM_PRIVATE*) psf->codec_data ; + + sptr = ubuf.sbuf ; + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + while (len > 0) + { writecount = (len >= bufferlen) ? bufferlen : (int) len ; + for (k = 0 ; k < writecount ; k++) + sptr [k] = ptr [total + k] >> 16 ; + count = ima_write_block (psf, pima, sptr, writecount) ; + total += count ; + len -= writecount ; + if (count != writecount) + break ; + } ; + + return total ; +} /* ima_write_i */ + +static sf_count_t +ima_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) +{ IMA_ADPCM_PRIVATE *pima ; + BUF_UNION ubuf ; + short *sptr ; + int k, bufferlen, writecount, count ; + sf_count_t total = 0 ; + float normfact ; + + if (! psf->codec_data) + return 0 ; + pima = (IMA_ADPCM_PRIVATE*) psf->codec_data ; + + normfact = (psf->norm_float == SF_TRUE) ? (1.0 * 0x7FFF) : 1.0 ; + + sptr = ubuf.sbuf ; + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + while (len > 0) + { writecount = (len >= bufferlen) ? bufferlen : (int) len ; + for (k = 0 ; k < writecount ; k++) + sptr [k] = psf_lrintf (normfact * ptr [total + k]) ; + count = ima_write_block (psf, pima, sptr, writecount) ; + total += count ; + len -= writecount ; + if (count != writecount) + break ; + } ; + + return total ; +} /* ima_write_f */ + +static sf_count_t +ima_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) +{ IMA_ADPCM_PRIVATE *pima ; + BUF_UNION ubuf ; + short *sptr ; + int k, bufferlen, writecount, count ; + sf_count_t total = 0 ; + double normfact ; + + if (! psf->codec_data) + return 0 ; + pima = (IMA_ADPCM_PRIVATE*) psf->codec_data ; + + normfact = (psf->norm_double == SF_TRUE) ? (1.0 * 0x7FFF) : 1.0 ; + + sptr = ubuf.sbuf ; + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + while (len > 0) + { writecount = (len >= bufferlen) ? bufferlen : (int) len ; + for (k = 0 ; k < writecount ; k++) + sptr [k] = psf_lrint (normfact * ptr [total + k]) ; + count = ima_write_block (psf, pima, sptr, writecount) ; + total += count ; + len -= writecount ; + if (count != writecount) + break ; + } ; + + return total ; +} /* ima_write_d */ + diff --git a/extern/libsndfile-modified/src/ima_oki_adpcm.c b/extern/libsndfile-modified/src/ima_oki_adpcm.c new file mode 100644 index 000000000..253216009 --- /dev/null +++ b/extern/libsndfile-modified/src/ima_oki_adpcm.c @@ -0,0 +1,297 @@ +/* +** Copyright (C) 2007-2014 Erik de Castro Lopo +** Copyright (c) 2007 +** +** This library is free software; you can redistribute it and/or modify it +** under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2 of the License, or (at +** your option) any later version. +** +** This library is distributed in the hope that it will be useful, but +** WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +** General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this library. If not, write to the Free Software Foundation, +** Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA. +*/ + +/* ADPCM: IMA, OKI <==> 16-bit PCM. */ + +#include "sfconfig.h" + +#include + +/* Set up for libsndfile environment: */ +#include "common.h" + +#include "ima_oki_adpcm.h" + +#define MIN_SAMPLE -0x8000 +#define MAX_SAMPLE 0x7fff + +static int const ima_steps [] = /* ~16-bit precision */ +{ 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, + 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, + 253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963, + 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, + 3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493, 10442, + 11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, + 32767 +} ; + +static int const oki_steps [] = /* ~12-bit precision */ +{ 256, 272, 304, 336, 368, 400, 448, 496, 544, 592, 656, 720, 800, 880, 960, + 1056, 1168, 1280, 1408, 1552, 1712, 1888, 2080, 2288, 2512, 2768, 3040, 3344, + 3680, 4048, 4464, 4912, 5392, 5936, 6528, 7184, 7904, 8704, 9568, 10528, + 11584, 12736, 14016, 15408, 16960, 18656, 20512, 22576, 24832 +} ; + +static int const step_changes [] = { -1, -1, -1, -1, 2, 4, 6, 8 } ; + +void +ima_oki_adpcm_init (IMA_OKI_ADPCM * state, IMA_OKI_ADPCM_TYPE type) +{ + memset (state, 0, sizeof (*state)) ; + + if (type == IMA_OKI_ADPCM_TYPE_IMA) + { state->max_step_index = ARRAY_LEN (ima_steps) - 1 ; + state->steps = ima_steps ; + state->mask = (~0) ; + } + else + { state->max_step_index = ARRAY_LEN (oki_steps) - 1 ; + state->steps = oki_steps ; + state->mask = arith_shift_left (~0, 4) ; + } ; + +} /* ima_oki_adpcm_init */ + + +int +adpcm_decode (IMA_OKI_ADPCM * state, int code) +{ int s ; + + s = ((code & 7) << 1) | 1 ; + s = ((state->steps [state->step_index] * s) >> 3) & state->mask ; + + if (code & 8) + s = -s ; + s += state->last_output ; + + if (s < MIN_SAMPLE || s > MAX_SAMPLE) + { int grace ; + + grace = (state->steps [state->step_index] >> 3) & state->mask ; + + if (s < MIN_SAMPLE - grace || s > MAX_SAMPLE + grace) + state->errors ++ ; + + s = s < MIN_SAMPLE ? MIN_SAMPLE : MAX_SAMPLE ; + } ; + + state->step_index += step_changes [code & 7] ; + state->step_index = SF_MIN (SF_MAX (state->step_index, 0), state->max_step_index) ; + state->last_output = s ; + + return s ; +} /* adpcm_decode */ + +int +adpcm_encode (IMA_OKI_ADPCM * state, int sample) +{ int delta, sign = 0, code ; + + delta = sample - state->last_output ; + + if (delta < 0) + { sign = 8 ; + delta = -delta ; + } ; + + code = 4 * delta / state->steps [state->step_index] ; + code = sign | SF_MIN (code, 7) ; + adpcm_decode (state, code) ; /* Update encoder state */ + + return code ; +} /* adpcm_encode */ + + +void +ima_oki_adpcm_decode_block (IMA_OKI_ADPCM * state) +{ unsigned char code ; + int k ; + + for (k = 0 ; k < state->code_count ; k++) + { code = state->codes [k] ; + state->pcm [2 * k] = adpcm_decode (state, code >> 4) ; + state->pcm [2 * k + 1] = adpcm_decode (state, code) ; + } ; + + state->pcm_count = 2 * k ; +} /* ima_oki_adpcm_decode_block */ + + +void +ima_oki_adpcm_encode_block (IMA_OKI_ADPCM * state) +{ unsigned char code ; + int k ; + + /* + ** The codec expects an even number of input samples. + ** + ** Samples should always be passed in even length blocks. If the last block to + ** be encoded is odd length, extend that block by one zero valued sample. + */ + if (state->pcm_count % 2 == 1) + state->pcm [state->pcm_count ++] = 0 ; + + for (k = 0 ; k < state->pcm_count / 2 ; k++) + { code = adpcm_encode (state, state->pcm [2 * k]) << 4 ; + code |= adpcm_encode (state, state->pcm [2 * k + 1]) ; + state->codes [k] = code ; + } ; + + state->code_count = k ; +} /* ima_oki_adpcm_encode_block */ + + +#ifdef TEST + +static const unsigned char test_codes [] = +{ 0x08, 0x08, 0x04, 0x7f, 0x72, 0xf7, 0x9f, 0x7c, 0xd7, 0xbc, 0x7a, 0xa7, 0xb8, + 0x4b, 0x0b, 0x38, 0xf6, 0x9d, 0x7a, 0xd7, 0xbc, 0x7a, 0xd7, 0xa8, 0x6c, 0x81, + 0x98, 0xe4, 0x0e, 0x7a, 0xd7, 0x9e, 0x7b, 0xc7, 0xab, 0x7a, 0x85, 0xc0, 0xb3, + 0x8f, 0x58, 0xd7, 0xad, 0x7a, 0xd7, 0xad, 0x7a, 0x87, 0xd0, 0x2b, 0x0e, 0x48, + 0xd7, 0xad, 0x78, 0xf7, 0xbc, 0x7a, 0xb7, 0xa8, 0x4b, 0x88, 0x18, 0xd5, 0x8d, + 0x6a, 0xa4, 0x98, 0x08, 0x00, 0x80, 0x88, +} ; + +static const short test_pcm [] = +{ 32, 0, 32, 0, 32, 320, 880, -336, 2304, 4192, -992, 10128, 5360, -16352, + 30208, 2272, -31872, 14688, -7040, -32432, 14128, -1392, -15488, 22960, + 1232, -1584, 21488, -240, 2576, -15360, 960, -1152, -30032, 10320, 1008, + -30032, 16528, 1008, -30032, 16528, -5200, -30592, 15968, 448, -30592, + 15968, 448, -2368, 30960, 3024, -80, 8384, 704, -1616, -29168, -1232, 1872, + -32768, 13792, -1728, -32768, 13792, 4480, -32192, 14368, -7360, -32752, + 13808, -1712, -21456, 16992, 1472, -1344, 26848, -1088, 2016, -17728, 208, + -2112, -32768, 1376, -1728, -32768, 13792, -1728, -32768, 13792, -1728, + -32768, 13792, -1728, -32768, 13792, -1728, -4544, 32767, -1377, 1727, + 15823, -2113, 207, -27345, 591, -2513, -32768, 13792, -1728, -32768, 13792, + 10688, -31632, 14928, -6800, -32192, 14368, -1152, -20896, 17552, 2032, + -784, 22288, 560, -2256, -4816, 2176, 64, -21120, 9920, 6816, -24224, 16128, + 608, -13488, 9584, 272, -2544, 16, -2304, -192, 1728, -16, 1568, 128, -1184, +} ; + + +static void +test_oki_adpcm (void) +{ + IMA_OKI_ADPCM adpcm ; + unsigned char code ; + int i, j ; + + printf (" Testing encoder : ") ; + fflush (stdout) ; + + ima_oki_adpcm_init (&adpcm, IMA_OKI_ADPCM_TYPE_OKI) ; + for (i = 0 ; i < ARRAY_LEN (test_codes) ; i++) + for (j = 0, code = test_codes [i] ; j < 2 ; j++, code <<= 4) + if (adpcm_decode (&adpcm, code >> 4) != test_pcm [2 * i + j]) + { printf ("\n\nFail at i = %d, j = %d.\n\n", i, j) ; + exit (1) ; + } ; + + puts ("ok") ; + + printf (" Testing decoder : ") ; + fflush (stdout) ; + + ima_oki_adpcm_init (&adpcm, IMA_OKI_ADPCM_TYPE_OKI) ; + for (i = 0 ; i < ARRAY_LEN (test_pcm) ; i += j) + { code = adpcm_encode (&adpcm, test_pcm [i]) ; + code = (code << 4) | adpcm_encode (&adpcm, test_pcm [i + 1]) ; + if (code != test_codes [i / 2]) + { printf ("\n\nFail at i = %d, %d should be %d\n\n", i, code, test_codes [i / 2]) ; + exit (1) ; + } ; + } ; + + puts ("ok") ; +} /* test_oki_adpcm */ + +static void +test_oki_adpcm_block (void) +{ + IMA_OKI_ADPCM adpcm ; + int k ; + + if (ARRAY_LEN (adpcm.pcm) < ARRAY_LEN (test_pcm)) + { printf ("\n\nLine %d : ARRAY_LEN (adpcm->pcm) > ARRAY_LEN (test_pcm) (%d > %d).\n\n", __LINE__, ARRAY_LEN (adpcm.pcm), ARRAY_LEN (test_pcm)) ; + exit (1) ; + } ; + + if (ARRAY_LEN (adpcm.codes) < ARRAY_LEN (test_codes)) + { printf ("\n\nLine %d : ARRAY_LEN (adcodes->codes) > ARRAY_LEN (test_codes).n", __LINE__) ; + exit (1) ; + } ; + + printf (" Testing block encoder : ") ; + fflush (stdout) ; + + ima_oki_adpcm_init (&adpcm, IMA_OKI_ADPCM_TYPE_OKI) ; + + memcpy (adpcm.pcm, test_pcm, sizeof (adpcm.pcm [0]) * ARRAY_LEN (test_pcm)) ; + adpcm.pcm_count = ARRAY_LEN (test_pcm) ; + adpcm.code_count = 13 ; + + ima_oki_adpcm_encode_block (&adpcm) ; + + if (adpcm.code_count * 2 != ARRAY_LEN (test_pcm)) + { printf ("\n\nLine %d : %d * 2 != %d\n\n", __LINE__, adpcm.code_count * 2, ARRAY_LEN (test_pcm)) ; + exit (1) ; + } ; + + for (k = 0 ; k < ARRAY_LEN (test_codes) ; k++) + if (adpcm.codes [k] != test_codes [k]) + { printf ("\n\nLine %d : Fail at k = %d, %d should be %d\n\n", __LINE__, k, adpcm.codes [k], test_codes [k]) ; + exit (1) ; + } ; + + puts ("ok") ; + + printf (" Testing block decoder : ") ; + fflush (stdout) ; + + ima_oki_adpcm_init (&adpcm, IMA_OKI_ADPCM_TYPE_OKI) ; + + memcpy (adpcm.codes, test_codes, sizeof (adpcm.codes [0]) * ARRAY_LEN (test_codes)) ; + adpcm.code_count = ARRAY_LEN (test_codes) ; + adpcm.pcm_count = 13 ; + + ima_oki_adpcm_decode_block (&adpcm) ; + + if (adpcm.pcm_count != 2 * ARRAY_LEN (test_codes)) + { printf ("\n\nLine %d : %d * 2 != %d\n\n", __LINE__, adpcm.pcm_count, 2 * ARRAY_LEN (test_codes)) ; + exit (1) ; + } ; + + for (k = 0 ; k < ARRAY_LEN (test_pcm) ; k++) + if (adpcm.pcm [k] != test_pcm [k]) + { printf ("\n\nLine %d : Fail at i = %d, %d should be %d.\n\n", __LINE__, k, adpcm.pcm [k], test_pcm [k]) ; + exit (1) ; + } ; + + puts ("ok") ; +} /* test_oki_adpcm_block */ + +int +main (void) +{ + test_oki_adpcm () ; + test_oki_adpcm_block () ; + + return 0 ; +} /* main */ + +#endif diff --git a/extern/libsndfile-modified/src/ima_oki_adpcm.h b/extern/libsndfile-modified/src/ima_oki_adpcm.h new file mode 100644 index 000000000..86241e7a2 --- /dev/null +++ b/extern/libsndfile-modified/src/ima_oki_adpcm.h @@ -0,0 +1,54 @@ +/* +** Copyright (C) 2007-2011 Erik de Castro Lopo +** Copyright (c) 2007 +** +** This library is free software; you can redistribute it and/or modify it +** under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2 of the License, or (at +** your option) any later version. +** +** This library is distributed in the hope that it will be useful, but +** WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +** General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this library. If not, write to the Free Software Foundation, +** Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA. +*/ + +/* ADPCM: IMA, OKI <==> 16-bit PCM. */ + + +#define IMA_OKI_ADPCM_CODE_LEN 256 +#define IMA_OKI_ADPCM_PCM_LEN (IMA_OKI_ADPCM_CODE_LEN *2) + +typedef struct +{ + /* private: */ + int mask ; + int last_output ; + int step_index ; + int max_step_index ; + int const * steps ; + + /* public: */ + int errors ; + int code_count, pcm_count ; + + unsigned char codes [IMA_OKI_ADPCM_CODE_LEN] ; + short pcm [IMA_OKI_ADPCM_PCM_LEN] ; +} IMA_OKI_ADPCM ; + +typedef enum +{ IMA_OKI_ADPCM_TYPE_IMA, + IMA_OKI_ADPCM_TYPE_OKI +} IMA_OKI_ADPCM_TYPE ; + +void ima_oki_adpcm_init (IMA_OKI_ADPCM * state, IMA_OKI_ADPCM_TYPE type) ; + +int adpcm_decode (IMA_OKI_ADPCM * state, int /* 0..15 */ code) ; +int adpcm_encode (IMA_OKI_ADPCM * state, int /* -32768..32767 */ sample) ; + +void ima_oki_adpcm_decode_block (IMA_OKI_ADPCM * state) ; +void ima_oki_adpcm_encode_block (IMA_OKI_ADPCM * state) ; diff --git a/extern/libsndfile-modified/src/interleave.c b/extern/libsndfile-modified/src/interleave.c new file mode 100644 index 000000000..5f799444c --- /dev/null +++ b/extern/libsndfile-modified/src/interleave.c @@ -0,0 +1,299 @@ +/* +** Copyright (C) 2002-2013 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfendian.h" + +#include + +#include "sndfile.h" +#include "common.h" + +#define INTERLEAVE_CHANNELS 6 + +typedef struct +{ double buffer [SF_BUFFER_LEN / sizeof (double)] ; + + sf_count_t channel_len ; + + sf_count_t (*read_short) (SF_PRIVATE*, short *ptr, sf_count_t len) ; + sf_count_t (*read_int) (SF_PRIVATE*, int *ptr, sf_count_t len) ; + sf_count_t (*read_float) (SF_PRIVATE*, float *ptr, sf_count_t len) ; + sf_count_t (*read_double) (SF_PRIVATE*, double *ptr, sf_count_t len) ; + +} INTERLEAVE_DATA ; + + + +static sf_count_t interleave_read_short (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; +static sf_count_t interleave_read_int (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; +static sf_count_t interleave_read_float (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; +static sf_count_t interleave_read_double (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; + +static sf_count_t interleave_seek (SF_PRIVATE*, int mode, sf_count_t samples_from_start) ; + + + + +int +interleave_init (SF_PRIVATE *psf) +{ INTERLEAVE_DATA *pdata ; + + if (psf->file.mode != SFM_READ) + return SFE_INTERLEAVE_MODE ; + + if (psf->interleave) + { psf_log_printf (psf, "*** Weird, already have interleave.\n") ; + return 666 ; + } ; + + /* Free this in sf_close() function. */ + if (! (pdata = malloc (sizeof (INTERLEAVE_DATA)))) + return SFE_MALLOC_FAILED ; + +puts ("interleave_init") ; + + psf->interleave = pdata ; + + /* Save the existing methods. */ + pdata->read_short = psf->read_short ; + pdata->read_int = psf->read_int ; + pdata->read_float = psf->read_float ; + pdata->read_double = psf->read_double ; + + pdata->channel_len = psf->sf.frames * psf->bytewidth ; + + /* Insert our new methods. */ + psf->read_short = interleave_read_short ; + psf->read_int = interleave_read_int ; + psf->read_float = interleave_read_float ; + psf->read_double = interleave_read_double ; + + psf->seek = interleave_seek ; + + return 0 ; +} /* pcm_interleave_init */ + +/*------------------------------------------------------------------------------ +*/ + +static sf_count_t +interleave_read_short (SF_PRIVATE *psf, short *ptr, sf_count_t len) +{ INTERLEAVE_DATA *pdata ; + sf_count_t offset, templen ; + int chan, count, k ; + short *inptr, *outptr ; + + if (! (pdata = psf->interleave)) + return 0 ; + + inptr = (short*) pdata->buffer ; + + for (chan = 0 ; chan < psf->sf.channels ; chan++) + { outptr = ptr + chan ; + + offset = psf->dataoffset + chan * psf->bytewidth * psf->read_current ; + + if (psf_fseek (psf, offset, SEEK_SET) != offset) + { psf->error = SFE_INTERLEAVE_SEEK ; + return 0 ; + } ; + + templen = len / psf->sf.channels ; + + while (templen > 0) + { if (templen > SIGNED_SIZEOF (pdata->buffer) / SIGNED_SIZEOF (short)) + count = SIGNED_SIZEOF (pdata->buffer) / SIGNED_SIZEOF (short) ; + else + count = (int) templen ; + + if (pdata->read_short (psf, inptr, count) != count) + { psf->error = SFE_INTERLEAVE_READ ; + return 0 ; + } ; + + for (k = 0 ; k < count ; k++) + { *outptr = inptr [k] ; + outptr += psf->sf.channels ; + } ; + + templen -= count ; + } ; + } ; + + return len ; +} /* interleave_read_short */ + +static sf_count_t +interleave_read_int (SF_PRIVATE *psf, int *ptr, sf_count_t len) +{ INTERLEAVE_DATA *pdata ; + sf_count_t offset, templen ; + int chan, count, k ; + int *inptr, *outptr ; + + if (! (pdata = psf->interleave)) + return 0 ; + + inptr = (int*) pdata->buffer ; + + for (chan = 0 ; chan < psf->sf.channels ; chan++) + { outptr = ptr + chan ; + + offset = psf->dataoffset + chan * psf->bytewidth * psf->read_current ; + + if (psf_fseek (psf, offset, SEEK_SET) != offset) + { psf->error = SFE_INTERLEAVE_SEEK ; + return 0 ; + } ; + + templen = len / psf->sf.channels ; + + while (templen > 0) + { if (templen > SIGNED_SIZEOF (pdata->buffer) / SIGNED_SIZEOF (int)) + count = SIGNED_SIZEOF (pdata->buffer) / SIGNED_SIZEOF (int) ; + else + count = (int) templen ; + + if (pdata->read_int (psf, inptr, count) != count) + { psf->error = SFE_INTERLEAVE_READ ; + return 0 ; + } ; + + for (k = 0 ; k < count ; k++) + { *outptr = inptr [k] ; + outptr += psf->sf.channels ; + } ; + + templen -= count ; + } ; + } ; + + return len ; +} /* interleave_read_int */ + +static sf_count_t +interleave_read_float (SF_PRIVATE *psf, float *ptr, sf_count_t len) +{ INTERLEAVE_DATA *pdata ; + sf_count_t offset, templen ; + int chan, count, k ; + float *inptr, *outptr ; + + if (! (pdata = psf->interleave)) + return 0 ; + + inptr = (float*) pdata->buffer ; + + for (chan = 0 ; chan < psf->sf.channels ; chan++) + { outptr = ptr + chan ; + + offset = psf->dataoffset + pdata->channel_len * chan + psf->read_current * psf->bytewidth ; + +/*-printf ("chan : %d read_current : %6lld offset : %6lld\n", chan, psf->read_current, offset) ;-*/ + + if (psf_fseek (psf, offset, SEEK_SET) != offset) + { psf->error = SFE_INTERLEAVE_SEEK ; +/*-puts ("interleave_seek error") ; exit (1) ;-*/ + return 0 ; + } ; + + templen = len / psf->sf.channels ; + + while (templen > 0) + { if (templen > SIGNED_SIZEOF (pdata->buffer) / SIGNED_SIZEOF (float)) + count = SIGNED_SIZEOF (pdata->buffer) / SIGNED_SIZEOF (float) ; + else + count = (int) templen ; + + if (pdata->read_float (psf, inptr, count) != count) + { psf->error = SFE_INTERLEAVE_READ ; +/*-puts ("interleave_read error") ; exit (1) ;-*/ + return 0 ; + } ; + + for (k = 0 ; k < count ; k++) + { *outptr = inptr [k] ; + outptr += psf->sf.channels ; + } ; + + templen -= count ; + } ; + } ; + + return len ; +} /* interleave_read_float */ + +static sf_count_t +interleave_read_double (SF_PRIVATE *psf, double *ptr, sf_count_t len) +{ INTERLEAVE_DATA *pdata ; + sf_count_t offset, templen ; + int chan, count, k ; + double *inptr, *outptr ; + + if (! (pdata = psf->interleave)) + return 0 ; + + inptr = (double*) pdata->buffer ; + + for (chan = 0 ; chan < psf->sf.channels ; chan++) + { outptr = ptr + chan ; + + offset = psf->dataoffset + chan * psf->bytewidth * psf->read_current ; + + if (psf_fseek (psf, offset, SEEK_SET) != offset) + { psf->error = SFE_INTERLEAVE_SEEK ; + return 0 ; + } ; + + templen = len / psf->sf.channels ; + + while (templen > 0) + { if (templen > SIGNED_SIZEOF (pdata->buffer) / SIGNED_SIZEOF (double)) + count = SIGNED_SIZEOF (pdata->buffer) / SIGNED_SIZEOF (double) ; + else + count = (int) templen ; + + if (pdata->read_double (psf, inptr, count) != count) + { psf->error = SFE_INTERLEAVE_READ ; + return 0 ; + } ; + + for (k = 0 ; k < count ; k++) + { *outptr = inptr [k] ; + outptr += psf->sf.channels ; + } ; + + templen -= count ; + } ; + } ; + + return len ; +} /* interleave_read_double */ + +/*------------------------------------------------------------------------------ +*/ + +static sf_count_t +interleave_seek (SF_PRIVATE * UNUSED (psf), int UNUSED (mode), sf_count_t samples_from_start) +{ + /* + ** Do nothing here. This is a place holder to prevent the default + ** seek function from being called. + */ + + return samples_from_start ; +} /* interleave_seek */ + diff --git a/extern/libsndfile-modified/src/ircam.c b/extern/libsndfile-modified/src/ircam.c new file mode 100644 index 000000000..8e7cdba81 --- /dev/null +++ b/extern/libsndfile-modified/src/ircam.c @@ -0,0 +1,323 @@ +/* +** Copyright (C) 2001-2017 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + +/*------------------------------------------------------------------------------ +** Macros to handle big/little endian issues. +*/ + +/* The IRCAM magic number is weird in that one byte in the number can have +** values of 0x1, 0x2, 0x03 or 0x04. Hence the need for a marker and a mask. +*/ + +#define IRCAM_BE_MASK (MAKE_MARKER (0xFF, 0xFF, 0x00, 0xFF)) +#define IRCAM_BE_MARKER (MAKE_MARKER (0x64, 0xA3, 0x00, 0x00)) + +#define IRCAM_LE_MASK (MAKE_MARKER (0xFF, 0x00, 0xFF, 0xFF)) +#define IRCAM_LE_MARKER (MAKE_MARKER (0x00, 0x00, 0xA3, 0x64)) + +#define IRCAM_02B_MARKER (MAKE_MARKER (0x64, 0xA3, 0x02, 0x00)) +#define IRCAM_03L_MARKER (MAKE_MARKER (0x64, 0xA3, 0x03, 0x00)) + +#define IRCAM_DATA_OFFSET (1024) + +/*------------------------------------------------------------------------------ +** Typedefs. +*/ + +enum +{ IRCAM_PCM_16 = 0x00002, + IRCAM_FLOAT = 0x00004, + IRCAM_ALAW = 0x10001, + IRCAM_ULAW = 0x20001, + IRCAM_PCM_32 = 0x40004 +} ; + + +/*------------------------------------------------------------------------------ +** Private static functions. +*/ + +static int ircam_close (SF_PRIVATE *psf) ; +static int ircam_write_header (SF_PRIVATE *psf, int calc_length) ; +static int ircam_read_header (SF_PRIVATE *psf) ; + +static int get_encoding (int subformat) ; + +static const char* get_encoding_str (int encoding) ; + +/*------------------------------------------------------------------------------ +** Public function. +*/ + +int +ircam_open (SF_PRIVATE *psf) +{ int subformat ; + int error = SFE_NO_ERROR ; + + if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0)) + { if ((error = ircam_read_header (psf))) + return error ; + } ; + + subformat = SF_CODEC (psf->sf.format) ; + + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_IRCAM) + return SFE_BAD_OPEN_FORMAT ; + + psf->endian = SF_ENDIAN (psf->sf.format) ; + if (psf->endian == 0 || psf->endian == SF_ENDIAN_CPU) + psf->endian = (CPU_IS_BIG_ENDIAN) ? SF_ENDIAN_BIG : SF_ENDIAN_LITTLE ; + + psf->dataoffset = IRCAM_DATA_OFFSET ; + + if ((error = ircam_write_header (psf, SF_FALSE))) + return error ; + + psf->write_header = ircam_write_header ; + } ; + + psf->container_close = ircam_close ; + + switch (subformat) + { case SF_FORMAT_ULAW : /* 8-bit Ulaw encoding. */ + error = ulaw_init (psf) ; + break ; + + case SF_FORMAT_ALAW : /* 8-bit Alaw encoding. */ + error = alaw_init (psf) ; + break ; + + case SF_FORMAT_PCM_16 : /* 16-bit linear PCM. */ + case SF_FORMAT_PCM_32 : /* 32-bit linear PCM. */ + error = pcm_init (psf) ; + break ; + + case SF_FORMAT_FLOAT : /* 32-bit linear PCM. */ + error = float32_init (psf) ; + break ; + + default : break ; + } ; + + return error ; +} /* ircam_open */ + +/*------------------------------------------------------------------------------ +*/ + +static int +ircam_read_header (SF_PRIVATE *psf) +{ unsigned int marker, encoding ; + float samplerate ; + int error = SFE_NO_ERROR ; + + psf_binheader_readf (psf, "epmf44", 0, &marker, &samplerate, &(psf->sf.channels), &encoding) ; + + if (((marker & IRCAM_BE_MASK) != IRCAM_BE_MARKER) && ((marker & IRCAM_LE_MASK) != IRCAM_LE_MARKER)) + { psf_log_printf (psf, "marker: 0x%X\n", marker) ; + return SFE_IRCAM_NO_MARKER ; + } ; + + psf->endian = SF_ENDIAN_LITTLE ; + + if (psf->sf.channels > SF_MAX_CHANNELS) + { psf_binheader_readf (psf, "Epmf44", 0, &marker, &samplerate, &(psf->sf.channels), &encoding) ; + + /* Sanity checking for endian-ness detection. */ + if (psf->sf.channels > SF_MAX_CHANNELS) + { psf_log_printf (psf, "marker: 0x%X\n", marker) ; + return SFE_IRCAM_BAD_CHANNELS ; + } ; + + psf->endian = SF_ENDIAN_BIG ; + } ; + + psf_log_printf (psf, "marker: 0x%X\n", marker) ; + + psf->sf.samplerate = (int) samplerate ; + + psf_log_printf (psf, " Sample Rate : %d\n" + " Channels : %d\n" + " Encoding : %X => %s\n", + psf->sf.samplerate, psf->sf.channels, encoding, get_encoding_str (encoding)) ; + + switch (encoding) + { case IRCAM_PCM_16 : + psf->bytewidth = 2 ; + psf->blockwidth = psf->sf.channels * psf->bytewidth ; + + psf->sf.format = SF_FORMAT_IRCAM | SF_FORMAT_PCM_16 ; + break ; + + case IRCAM_PCM_32 : + psf->bytewidth = 4 ; + psf->blockwidth = psf->sf.channels * psf->bytewidth ; + + psf->sf.format = SF_FORMAT_IRCAM | SF_FORMAT_PCM_32 ; + break ; + + case IRCAM_FLOAT : + psf->bytewidth = 4 ; + psf->blockwidth = psf->sf.channels * psf->bytewidth ; + + psf->sf.format = SF_FORMAT_IRCAM | SF_FORMAT_FLOAT ; + break ; + + case IRCAM_ALAW : + psf->bytewidth = 1 ; + psf->blockwidth = psf->sf.channels * psf->bytewidth ; + + psf->sf.format = SF_FORMAT_IRCAM | SF_FORMAT_ALAW ; + break ; + + case IRCAM_ULAW : + psf->bytewidth = 1 ; + psf->blockwidth = psf->sf.channels * psf->bytewidth ; + + psf->sf.format = SF_FORMAT_IRCAM | SF_FORMAT_ULAW ; + break ; + + default : + error = SFE_IRCAM_UNKNOWN_FORMAT ; + break ; + } ; + + if (psf->endian == SF_ENDIAN_BIG) + psf->sf.format |= SF_ENDIAN_BIG ; + else + psf->sf.format |= SF_ENDIAN_LITTLE ; + + if (error) + return error ; + + psf->dataoffset = IRCAM_DATA_OFFSET ; + psf->datalength = psf->filelength - psf->dataoffset ; + + if (psf->sf.frames == 0 && psf->blockwidth) + psf->sf.frames = psf->datalength / psf->blockwidth ; + + psf_log_printf (psf, " Samples : %d\n", psf->sf.frames) ; + + psf_binheader_readf (psf, "p", IRCAM_DATA_OFFSET) ; + + return 0 ; +} /* ircam_read_header */ + +static int +ircam_close (SF_PRIVATE *psf) +{ + psf_log_printf (psf, "close\n") ; + + return 0 ; +} /* ircam_close */ + +static int +ircam_write_header (SF_PRIVATE *psf, int UNUSED (calc_length)) +{ int encoding ; + float samplerate ; + sf_count_t current ; + + if (psf->pipeoffset > 0) + return 0 ; + + current = psf_ftell (psf) ; + + /* This also sets psf->endian. */ + encoding = get_encoding (SF_CODEC (psf->sf.format)) ; + + if (encoding == 0) + return SFE_BAD_OPEN_FORMAT ; + + /* Reset the current header length to zero. */ + psf->header.ptr [0] = 0 ; + psf->header.indx = 0 ; + + if (psf->is_pipe == SF_FALSE) + psf_fseek (psf, 0, SEEK_SET) ; + + samplerate = psf->sf.samplerate ; + + switch (psf->endian) + { case SF_ENDIAN_BIG : + psf_binheader_writef (psf, "Emf", BHWm (IRCAM_02B_MARKER), BHWf (samplerate)) ; + psf_binheader_writef (psf, "E44", BHW4 (psf->sf.channels), BHW4 (encoding)) ; + break ; + + case SF_ENDIAN_LITTLE : + psf_binheader_writef (psf, "emf", BHWm (IRCAM_03L_MARKER), BHWf (samplerate)) ; + psf_binheader_writef (psf, "e44", BHW4 (psf->sf.channels), BHW4 (encoding)) ; + break ; + + default : return SFE_BAD_OPEN_FORMAT ; + } ; + + psf_binheader_writef (psf, "z", BHWz ((size_t) (IRCAM_DATA_OFFSET - psf->header.indx))) ; + + /* Header construction complete so write it out. */ + psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ; + + if (psf->error) + return psf->error ; + + if (current > 0) + psf_fseek (psf, current, SEEK_SET) ; + + return psf->error ; +} /* ircam_write_header */ + +static int +get_encoding (int subformat) +{ switch (subformat) + { case SF_FORMAT_PCM_16 : return IRCAM_PCM_16 ; + case SF_FORMAT_PCM_32 : return IRCAM_PCM_32 ; + + case SF_FORMAT_FLOAT : return IRCAM_FLOAT ; + + case SF_FORMAT_ULAW : return IRCAM_ULAW ; + case SF_FORMAT_ALAW : return IRCAM_ALAW ; + + default : break ; + } ; + + return 0 ; +} /* get_encoding */ + +static const char* +get_encoding_str (int encoding) +{ switch (encoding) + { case IRCAM_PCM_16 : return "16 bit PCM" ; + case IRCAM_FLOAT : return "32 bit float" ; + case IRCAM_ALAW : return "A law" ; + case IRCAM_ULAW : return "u law" ; + case IRCAM_PCM_32 : return "32 bit PCM" ; + } ; + return "Unknown encoding" ; +} /* get_encoding_str */ + diff --git a/extern/libsndfile-modified/src/macos.c b/extern/libsndfile-modified/src/macos.c new file mode 100644 index 000000000..5f6c53191 --- /dev/null +++ b/extern/libsndfile-modified/src/macos.c @@ -0,0 +1,51 @@ +/* +** Copyright (C) 2003-2011 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + +#define STR_MARKER MAKE_MARKER ('S', 'T', 'R', ' ') + +int +macos_guess_file_type (SF_PRIVATE * psf, const char *filename) +{ static char rsrc_name [1024] ; + struct stat statbuf ; + + snprintf (rsrc_name, sizeof (rsrc_name), "%s/rsrc", filename) ; + + /* If there is no resource fork, just return. */ + if (stat (rsrc_name, &statbuf) != 0) + { psf_log_printf (psf, "No resource fork.\n") ; + return 0 ; + } ; + + if (statbuf.st_size == 0) + { psf_log_printf (psf, "Have zero size resource fork.\n") ; + return 0 ; + } ; + + return 0 ; +} /* macos_guess_file_type */ + diff --git a/extern/libsndfile-modified/src/make-static-lib-hidden-privates.sh b/extern/libsndfile-modified/src/make-static-lib-hidden-privates.sh new file mode 100755 index 000000000..5bfd485d2 --- /dev/null +++ b/extern/libsndfile-modified/src/make-static-lib-hidden-privates.sh @@ -0,0 +1,14 @@ +#!/bin/bash -e + +# This script takes a static library and removes all non-public symbols. +# Ie, it makes a static lib whose symbols are far less likely to clash with +# the symbols of another shared or static library. + +grep sf_ Symbols.gnu-binutils | sed -e "s/[ ;]//g" > Symbols.static + +ld -r --whole-archive .libs/libsndfile.a -o libsndfile_a.o + +objcopy --keep-global-symbols=Symbols.static libsndfile_a.o libsndfile.o + +rm -f libsndfile.a +ar cru libsndfile.a libsndfile.o diff --git a/extern/libsndfile-modified/src/mat4.c b/extern/libsndfile-modified/src/mat4.c new file mode 100644 index 000000000..0b1b414b4 --- /dev/null +++ b/extern/libsndfile-modified/src/mat4.c @@ -0,0 +1,391 @@ +/* +** Copyright (C) 2002-2017 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + +/*------------------------------------------------------------------------------ +** Information on how to decode and encode this file was obtained in a PDF +** file which I found on http://www.wotsit.org/. +** Also did a lot of testing with GNU Octave but do not have access to +** Matlab (tm) and so could not test it there. +*/ + +/*------------------------------------------------------------------------------ +** Macros to handle big/little endian issues. +*/ + +#define MAT4_BE_DOUBLE (MAKE_MARKER (0, 0, 0x03, 0xE8)) +#define MAT4_LE_DOUBLE (MAKE_MARKER (0, 0, 0, 0)) + +#define MAT4_BE_FLOAT (MAKE_MARKER (0, 0, 0x03, 0xF2)) +#define MAT4_LE_FLOAT (MAKE_MARKER (0x0A, 0, 0, 0)) + +#define MAT4_BE_PCM_32 (MAKE_MARKER (0, 0, 0x03, 0xFC)) +#define MAT4_LE_PCM_32 (MAKE_MARKER (0x14, 0, 0, 0)) + +#define MAT4_BE_PCM_16 (MAKE_MARKER (0, 0, 0x04, 0x06)) +#define MAT4_LE_PCM_16 (MAKE_MARKER (0x1E, 0, 0, 0)) + +/* Can't see any reason to ever implement this. */ +#define MAT4_BE_PCM_U8 (MAKE_MARKER (0, 0, 0x04, 0x1A)) +#define MAT4_LE_PCM_U8 (MAKE_MARKER (0x32, 0, 0, 0)) + +/*------------------------------------------------------------------------------ +** Private static functions. +*/ + +static int mat4_close (SF_PRIVATE *psf) ; + +static int mat4_format_to_encoding (int format, int endian) ; + +static int mat4_write_header (SF_PRIVATE *psf, int calc_length) ; +static int mat4_read_header (SF_PRIVATE *psf) ; + +static const char * mat4_marker_to_str (int marker) ; + +/*------------------------------------------------------------------------------ +** Public function. +*/ + +int +mat4_open (SF_PRIVATE *psf) +{ int subformat, error = 0 ; + + if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0)) + { if ((error = mat4_read_header (psf))) + return error ; + } ; + + if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_MAT4) + return SFE_BAD_OPEN_FORMAT ; + + subformat = SF_CODEC (psf->sf.format) ; + + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { if (psf->is_pipe) + return SFE_NO_PIPE_WRITE ; + + psf->endian = SF_ENDIAN (psf->sf.format) ; + if (CPU_IS_LITTLE_ENDIAN && (psf->endian == SF_ENDIAN_CPU || psf->endian == 0)) + psf->endian = SF_ENDIAN_LITTLE ; + else if (CPU_IS_BIG_ENDIAN && (psf->endian == SF_ENDIAN_CPU || psf->endian == 0)) + psf->endian = SF_ENDIAN_BIG ; + + if ((error = mat4_write_header (psf, SF_FALSE))) + return error ; + + psf->write_header = mat4_write_header ; + } ; + + psf->container_close = mat4_close ; + + psf->blockwidth = psf->bytewidth * psf->sf.channels ; + + switch (subformat) + { case SF_FORMAT_PCM_16 : + case SF_FORMAT_PCM_32 : + error = pcm_init (psf) ; + break ; + + case SF_FORMAT_FLOAT : + error = float32_init (psf) ; + break ; + + case SF_FORMAT_DOUBLE : + error = double64_init (psf) ; + break ; + + default : break ; + } ; + + return error ; +} /* mat4_open */ + +/*------------------------------------------------------------------------------ +*/ + +static int +mat4_close (SF_PRIVATE *psf) +{ + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + mat4_write_header (psf, SF_TRUE) ; + + return 0 ; +} /* mat4_close */ + +/*------------------------------------------------------------------------------ +*/ + +static int +mat4_write_header (SF_PRIVATE *psf, int calc_length) +{ sf_count_t current ; + int encoding ; + double samplerate ; + + current = psf_ftell (psf) ; + + if (calc_length) + { psf->filelength = psf_get_filelen (psf) ; + + psf->datalength = psf->filelength - psf->dataoffset ; + if (psf->dataend) + psf->datalength -= psf->filelength - psf->dataend ; + + psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ; + } ; + + encoding = mat4_format_to_encoding (SF_CODEC (psf->sf.format), psf->endian) ; + + if (encoding == -1) + return SFE_BAD_OPEN_FORMAT ; + + /* Reset the current header length to zero. */ + psf->header.ptr [0] = 0 ; + psf->header.indx = 0 ; + psf_fseek (psf, 0, SEEK_SET) ; + + /* Need sample rate as a double for writing to the header. */ + samplerate = psf->sf.samplerate ; + + if (psf->endian == SF_ENDIAN_BIG) + { psf_binheader_writef (psf, "Em444", BHWm (MAT4_BE_DOUBLE), BHW4 (1), BHW4 (1), BHW4 (0)) ; + psf_binheader_writef (psf, "E4bd", BHW4 (11), BHWv ("samplerate"), BHWz (11), BHWd (samplerate)) ; + psf_binheader_writef (psf, "tEm484", BHWm (encoding), BHW4 (psf->sf.channels), BHW8 (psf->sf.frames), BHW4 (0)) ; + psf_binheader_writef (psf, "E4b", BHW4 (9), BHWv ("wavedata"), BHWz (9)) ; + } + else if (psf->endian == SF_ENDIAN_LITTLE) + { psf_binheader_writef (psf, "em444", BHWm (MAT4_LE_DOUBLE), BHW4 (1), BHW4 (1), BHW4 (0)) ; + psf_binheader_writef (psf, "e4bd", BHW4 (11), BHWv ("samplerate"), BHWz (11), BHWd (samplerate)) ; + psf_binheader_writef (psf, "tem484", BHWm (encoding), BHW4 (psf->sf.channels), BHW8 (psf->sf.frames), BHW4 (0)) ; + psf_binheader_writef (psf, "e4b", BHW4 (9), BHWv ("wavedata"), BHWz (9)) ; + } + else + return SFE_BAD_OPEN_FORMAT ; + + /* Header construction complete so write it out. */ + psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ; + + if (psf->error) + return psf->error ; + + psf->dataoffset = psf->header.indx ; + + if (current > 0) + psf_fseek (psf, current, SEEK_SET) ; + + return psf->error ; +} /* mat4_write_header */ + +static int +mat4_read_header (SF_PRIVATE *psf) +{ char buffer [256] ; + uint32_t marker, namesize ; + int rows, cols, imag ; + double value ; + const char *marker_str ; + char name [64] ; + + psf_binheader_readf (psf, "pm", 0, &marker) ; + + /* MAT4 file must start with a double for the samplerate. */ + if (marker == MAT4_BE_DOUBLE) + { psf->endian = psf->rwf_endian = SF_ENDIAN_BIG ; + marker_str = "big endian double" ; + } + else if (marker == MAT4_LE_DOUBLE) + { psf->endian = psf->rwf_endian = SF_ENDIAN_LITTLE ; + marker_str = "little endian double" ; + } + else + return SFE_UNIMPLEMENTED ; + + psf_log_printf (psf, "GNU Octave 2.0 / MATLAB v4.2 format\nMarker : %s\n", marker_str) ; + + psf_binheader_readf (psf, "444", &rows, &cols, &imag) ; + + psf_log_printf (psf, " Rows : %d\n Cols : %d\n Imag : %s\n", rows, cols, imag ? "True" : "False") ; + + psf_binheader_readf (psf, "4", &namesize) ; + + if (namesize >= SIGNED_SIZEOF (name)) + return SFE_MAT4_BAD_NAME ; + + psf_binheader_readf (psf, "b", name, namesize) ; + name [namesize] = 0 ; + + psf_log_printf (psf, " Name : %s\n", name) ; + + psf_binheader_readf (psf, "d", &value) ; + + snprintf (buffer, sizeof (buffer), " Value : %f\n", value) ; + psf_log_printf (psf, buffer) ; + + if ((rows != 1) || (cols != 1)) + return SFE_MAT4_NO_SAMPLERATE ; + + psf->sf.samplerate = psf_lrint (value) ; + + /* Now write out the audio data. */ + + psf_binheader_readf (psf, "m", &marker) ; + + psf_log_printf (psf, "Marker : %s\n", mat4_marker_to_str (marker)) ; + + psf_binheader_readf (psf, "444", &rows, &cols, &imag) ; + + psf_log_printf (psf, " Rows : %d\n Cols : %d\n Imag : %s\n", rows, cols, imag ? "True" : "False") ; + + psf_binheader_readf (psf, "4", &namesize) ; + + if (namesize >= SIGNED_SIZEOF (name)) + return SFE_MAT4_BAD_NAME ; + + psf_binheader_readf (psf, "b", name, namesize) ; + name [namesize] = 0 ; + + psf_log_printf (psf, " Name : %s\n", name) ; + + psf->dataoffset = psf_ftell (psf) ; + + if (rows == 0) + { psf_log_printf (psf, "*** Error : zero channel count.\n") ; + return SFE_CHANNEL_COUNT_ZERO ; + } + else if (rows > SF_MAX_CHANNELS) + { psf_log_printf (psf, "*** Error : channel count %d > SF_MAX_CHANNELS.\n", rows) ; + return SFE_CHANNEL_COUNT ; + } ; + + psf->sf.channels = rows ; + psf->sf.frames = cols ; + + psf->sf.format = psf->endian | SF_FORMAT_MAT4 ; + switch (marker) + { case MAT4_BE_DOUBLE : + case MAT4_LE_DOUBLE : + psf->sf.format |= SF_FORMAT_DOUBLE ; + psf->bytewidth = 8 ; + break ; + + case MAT4_BE_FLOAT : + case MAT4_LE_FLOAT : + psf->sf.format |= SF_FORMAT_FLOAT ; + psf->bytewidth = 4 ; + break ; + + case MAT4_BE_PCM_32 : + case MAT4_LE_PCM_32 : + psf->sf.format |= SF_FORMAT_PCM_32 ; + psf->bytewidth = 4 ; + break ; + + case MAT4_BE_PCM_16 : + case MAT4_LE_PCM_16 : + psf->sf.format |= SF_FORMAT_PCM_16 ; + psf->bytewidth = 2 ; + break ; + + default : + psf_log_printf (psf, "*** Error : Bad marker %08X\n", marker) ; + return SFE_UNIMPLEMENTED ; + } ; + + if ((psf->filelength - psf->dataoffset) < psf->sf.channels * psf->sf.frames * psf->bytewidth) + { psf_log_printf (psf, "*** File seems to be truncated. %D <--> %D\n", + psf->filelength - psf->dataoffset, psf->sf.channels * psf->sf.frames * psf->bytewidth) ; + } + else if ((psf->filelength - psf->dataoffset) > psf->sf.channels * psf->sf.frames * psf->bytewidth) + psf->dataend = psf->dataoffset + rows * cols * psf->bytewidth ; + + psf->datalength = psf->filelength - psf->dataoffset - psf->dataend ; + + psf->sf.sections = 1 ; + + return 0 ; +} /* mat4_read_header */ + +static int +mat4_format_to_encoding (int format, int endian) +{ + switch (format | endian) + { case (SF_FORMAT_PCM_16 | SF_ENDIAN_BIG) : + return MAT4_BE_PCM_16 ; + + case (SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE) : + return MAT4_LE_PCM_16 ; + + case (SF_FORMAT_PCM_32 | SF_ENDIAN_BIG) : + return MAT4_BE_PCM_32 ; + + case (SF_FORMAT_PCM_32 | SF_ENDIAN_LITTLE) : + return MAT4_LE_PCM_32 ; + + case (SF_FORMAT_FLOAT | SF_ENDIAN_BIG) : + return MAT4_BE_FLOAT ; + + case (SF_FORMAT_FLOAT | SF_ENDIAN_LITTLE) : + return MAT4_LE_FLOAT ; + + case (SF_FORMAT_DOUBLE | SF_ENDIAN_BIG) : + return MAT4_BE_DOUBLE ; + + case (SF_FORMAT_DOUBLE | SF_ENDIAN_LITTLE) : + return MAT4_LE_DOUBLE ; + + default : break ; + } ; + + return -1 ; +} /* mat4_format_to_encoding */ + +static const char * +mat4_marker_to_str (int marker) +{ static char str [32] ; + + switch (marker) + { + case MAT4_BE_PCM_16 : return "big endian 16 bit PCM" ; + case MAT4_LE_PCM_16 : return "little endian 16 bit PCM" ; + + case MAT4_BE_PCM_32 : return "big endian 32 bit PCM" ; + case MAT4_LE_PCM_32 : return "little endian 32 bit PCM" ; + + + case MAT4_BE_FLOAT : return "big endian float" ; + case MAT4_LE_FLOAT : return "big endian float" ; + + case MAT4_BE_DOUBLE : return "big endian double" ; + case MAT4_LE_DOUBLE : return "little endian double" ; + } ; + + /* This is a little unsafe but is really only for debugging. */ + str [sizeof (str) - 1] = 0 ; + snprintf (str, sizeof (str) - 1, "%08X", marker) ; + return str ; +} /* mat4_marker_to_str */ + diff --git a/extern/libsndfile-modified/src/mat5.c b/extern/libsndfile-modified/src/mat5.c new file mode 100644 index 000000000..da5a6eca0 --- /dev/null +++ b/extern/libsndfile-modified/src/mat5.c @@ -0,0 +1,509 @@ +/* +** Copyright (C) 2002-2017 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + +/*------------------------------------------------------------------------------ +** Information on how to decode and encode this file was obtained in a PDF +** file which I found on http://www.wotsit.org/. +** Also did a lot of testing with GNU Octave but do not have access to +** Matlab (tm) and so could not test it there. +*/ + +/*------------------------------------------------------------------------------ +** Macros to handle big/little endian issues. +*/ + +#define MATL_MARKER (MAKE_MARKER ('M', 'A', 'T', 'L')) + +#define IM_MARKER (('I' << 8) + 'M') +#define MI_MARKER (('M' << 8) + 'I') + +/*------------------------------------------------------------------------------ +** Enums and typedefs. +*/ + +enum +{ MAT5_TYPE_SCHAR = 0x1, + MAT5_TYPE_UCHAR = 0x2, + MAT5_TYPE_INT16 = 0x3, + MAT5_TYPE_UINT16 = 0x4, + MAT5_TYPE_INT32 = 0x5, + MAT5_TYPE_UINT32 = 0x6, + MAT5_TYPE_FLOAT = 0x7, + MAT5_TYPE_DOUBLE = 0x9, + MAT5_TYPE_ARRAY = 0xE, + + MAT5_TYPE_COMP_USHORT = 0x00020004, + MAT5_TYPE_COMP_UINT = 0x00040006 +} ; + +typedef struct +{ sf_count_t size ; + int rows, cols ; + char name [32] ; +} MAT5_MATRIX ; + +/*------------------------------------------------------------------------------ +** Private static functions. +*/ + +static int mat5_close (SF_PRIVATE *psf) ; + +static int mat5_write_header (SF_PRIVATE *psf, int calc_length) ; +static int mat5_read_header (SF_PRIVATE *psf) ; + +/*------------------------------------------------------------------------------ +** Public function. +*/ + +int +mat5_open (SF_PRIVATE *psf) +{ int subformat, error = 0 ; + + if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0)) + { if ((error = mat5_read_header (psf))) + return error ; + } ; + + if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_MAT5) + return SFE_BAD_OPEN_FORMAT ; + + subformat = SF_CODEC (psf->sf.format) ; + + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { if (psf->is_pipe) + return SFE_NO_PIPE_WRITE ; + + psf->endian = SF_ENDIAN (psf->sf.format) ; + if (CPU_IS_LITTLE_ENDIAN && (psf->endian == SF_ENDIAN_CPU || psf->endian == 0)) + psf->endian = SF_ENDIAN_LITTLE ; + else if (CPU_IS_BIG_ENDIAN && (psf->endian == SF_ENDIAN_CPU || psf->endian == 0)) + psf->endian = SF_ENDIAN_BIG ; + + if ((error = mat5_write_header (psf, SF_FALSE))) + return error ; + + psf->write_header = mat5_write_header ; + } ; + + psf->container_close = mat5_close ; + + psf->blockwidth = psf->bytewidth * psf->sf.channels ; + + switch (subformat) + { case SF_FORMAT_PCM_U8 : + case SF_FORMAT_PCM_16 : + case SF_FORMAT_PCM_32 : + error = pcm_init (psf) ; + break ; + + case SF_FORMAT_FLOAT : + error = float32_init (psf) ; + break ; + + case SF_FORMAT_DOUBLE : + error = double64_init (psf) ; + break ; + + default : break ; + } ; + + return error ; +} /* mat5_open */ + +/*------------------------------------------------------------------------------ +*/ + +static int +mat5_close (SF_PRIVATE *psf) +{ + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + mat5_write_header (psf, SF_TRUE) ; + + return 0 ; +} /* mat5_close */ + +/*------------------------------------------------------------------------------ +*/ + +static int +mat5_write_header (SF_PRIVATE *psf, int calc_length) +{ static const char *filename = "MATLAB 5.0 MAT-file, written by " PACKAGE_NAME "-" PACKAGE_VERSION ", " ; + static const char *sr_name = "samplerate\0\0\0\0\0\0\0\0\0\0\0" ; + static const char *wd_name = "wavedata\0" ; + char buffer [256] ; + sf_count_t current, datasize ; + int encoding ; + + current = psf_ftell (psf) ; + + if (calc_length) + { psf_fseek (psf, 0, SEEK_END) ; + psf->filelength = psf_ftell (psf) ; + psf_fseek (psf, 0, SEEK_SET) ; + + psf->datalength = psf->filelength - psf->dataoffset ; + if (psf->dataend) + psf->datalength -= psf->filelength - psf->dataend ; + + psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ; + } ; + + switch (SF_CODEC (psf->sf.format)) + { case SF_FORMAT_PCM_U8 : + encoding = MAT5_TYPE_UCHAR ; + break ; + + case SF_FORMAT_PCM_16 : + encoding = MAT5_TYPE_INT16 ; + break ; + + case SF_FORMAT_PCM_32 : + encoding = MAT5_TYPE_INT32 ; + break ; + + case SF_FORMAT_FLOAT : + encoding = MAT5_TYPE_FLOAT ; + break ; + + case SF_FORMAT_DOUBLE : + encoding = MAT5_TYPE_DOUBLE ; + break ; + + default : + return SFE_BAD_OPEN_FORMAT ; + } ; + + /* Reset the current header length to zero. */ + psf->header.ptr [0] = 0 ; + psf->header.indx = 0 ; + psf_fseek (psf, 0, SEEK_SET) ; + + psf_get_date_str (buffer, sizeof (buffer)) ; + psf_binheader_writef (psf, "bb", BHWv (filename), BHWz (strlen (filename)), BHWv (buffer), BHWz (strlen (buffer) + 1)) ; + + memset (buffer, ' ', 124 - psf->header.indx) ; + psf_binheader_writef (psf, "b", BHWv (buffer), BHWz (124 - psf->header.indx)) ; + + psf->rwf_endian = psf->endian ; + + if (psf->rwf_endian == SF_ENDIAN_BIG) + psf_binheader_writef (psf, "2b", BHW2 (0x0100), BHWv ("MI"), BHWz (2)) ; + else + psf_binheader_writef (psf, "2b", BHW2 (0x0100), BHWv ("IM"), BHWz (2)) ; + + psf_binheader_writef (psf, "444444", BHW4 (MAT5_TYPE_ARRAY), BHW4 (64), BHW4 (MAT5_TYPE_UINT32), BHW4 (8), BHW4 (6), BHW4 (0)) ; + psf_binheader_writef (psf, "4444", BHW4 (MAT5_TYPE_INT32), BHW4 (8), BHW4 (1), BHW4 (1)) ; + psf_binheader_writef (psf, "44b", BHW4 (MAT5_TYPE_SCHAR), BHW4 (strlen (sr_name)), BHWv (sr_name), BHWz (16)) ; + + if (psf->sf.samplerate > 0xFFFF) + psf_binheader_writef (psf, "44", BHW4 (MAT5_TYPE_COMP_UINT), BHW4 (psf->sf.samplerate)) ; + else + { unsigned short samplerate = psf->sf.samplerate ; + + psf_binheader_writef (psf, "422", BHW4 (MAT5_TYPE_COMP_USHORT), BHW2 (samplerate), BHW2 (0)) ; + } ; + + datasize = psf->sf.frames * psf->sf.channels * psf->bytewidth ; + + psf_binheader_writef (psf, "t484444", BHW4 (MAT5_TYPE_ARRAY), BHW8 (datasize + 64), BHW4 (MAT5_TYPE_UINT32), BHW4 (8), BHW4 (6), BHW4 (0)) ; + psf_binheader_writef (psf, "t4448", BHW4 (MAT5_TYPE_INT32), BHW4 (8), BHW4 (psf->sf.channels), BHW8 (psf->sf.frames)) ; + psf_binheader_writef (psf, "44b", BHW4 (MAT5_TYPE_SCHAR), BHW4 (strlen (wd_name)), BHWv (wd_name), BHWz (strlen (wd_name))) ; + + datasize = psf->sf.frames * psf->sf.channels * psf->bytewidth ; + if (datasize > 0x7FFFFFFF) + datasize = 0x7FFFFFFF ; + + psf_binheader_writef (psf, "t48", BHW4 (encoding), BHW8 (datasize)) ; + + /* Header construction complete so write it out. */ + psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ; + + if (psf->error) + return psf->error ; + + psf->dataoffset = psf->header.indx ; + + if (current > 0) + psf_fseek (psf, current, SEEK_SET) ; + + return psf->error ; +} /* mat5_write_header */ + +static int +mat5_read_header (SF_PRIVATE *psf) +{ char buffer [256], name [32] ; + short version, endian ; + int type, flags1, flags2, rows, cols ; + unsigned size ; + int have_samplerate = 1 ; + + psf_binheader_readf (psf, "pb", 0, buffer, 124) ; + + buffer [125] = 0 ; + + if (strlen (buffer) >= 124) + return SFE_UNIMPLEMENTED ; + + if (strstr (buffer, "MATLAB 5.0 MAT-file") == buffer) + psf_log_printf (psf, "%s\n", buffer) ; + + + psf_binheader_readf (psf, "E22", &version, &endian) ; + + if (endian == MI_MARKER) + { psf->endian = psf->rwf_endian = SF_ENDIAN_BIG ; + if (CPU_IS_LITTLE_ENDIAN) version = ENDSWAP_16 (version) ; + } + else if (endian == IM_MARKER) + { psf->endian = psf->rwf_endian = SF_ENDIAN_LITTLE ; + if (CPU_IS_BIG_ENDIAN) version = ENDSWAP_16 (version) ; + } + else + return SFE_MAT5_BAD_ENDIAN ; + + if ((CPU_IS_LITTLE_ENDIAN && endian == IM_MARKER) || + (CPU_IS_BIG_ENDIAN && endian == MI_MARKER)) + version = ENDSWAP_16 (version) ; + + psf_log_printf (psf, "Version : 0x%04X\n", version) ; + psf_log_printf (psf, "Endian : 0x%04X => %s\n", endian, + (psf->endian == SF_ENDIAN_LITTLE) ? "Little" : "Big") ; + + /*========================================================*/ + psf_binheader_readf (psf, "44", &type, &size) ; + psf_log_printf (psf, "Block\n Type : %X Size : %d\n", type, size) ; + + if (type != MAT5_TYPE_ARRAY) + return SFE_MAT5_NO_BLOCK ; + + psf_binheader_readf (psf, "44", &type, &size) ; + psf_log_printf (psf, " Type : %X Size : %d\n", type, size) ; + + if (type != MAT5_TYPE_UINT32) + return SFE_MAT5_NO_BLOCK ; + + psf_binheader_readf (psf, "44", &flags1, &flags2) ; + psf_log_printf (psf, " Flg1 : %X Flg2 : %d\n", flags1, flags2) ; + + psf_binheader_readf (psf, "44", &type, &size) ; + psf_log_printf (psf, " Type : %X Size : %d\n", type, size) ; + + if (type != MAT5_TYPE_INT32) + return SFE_MAT5_NO_BLOCK ; + + psf_binheader_readf (psf, "44", &rows, &cols) ; + psf_log_printf (psf, " Rows : %d Cols : %d\n", rows, cols) ; + + if (rows != 1 || cols != 1) + { if (psf->sf.samplerate == 0) + psf->sf.samplerate = 44100 ; + have_samplerate = 0 ; + } + psf_binheader_readf (psf, "4", &type) ; + + if (type == MAT5_TYPE_SCHAR) + { psf_binheader_readf (psf, "4", &size) ; + psf_log_printf (psf, " Type : %X Size : %d\n", type, size) ; + if (size > SIGNED_SIZEOF (name) - 1) + { psf_log_printf (psf, "Error : Bad name length.\n") ; + return SFE_MAT5_NO_BLOCK ; + } ; + + psf_binheader_readf (psf, "bj", name, size, (8 - (size % 8)) % 8) ; + name [size] = 0 ; + } + else if ((type & 0xFFFF) == MAT5_TYPE_SCHAR) + { size = type >> 16 ; + if (size > 4) + { psf_log_printf (psf, "Error : Bad name length.\n") ; + return SFE_MAT5_NO_BLOCK ; + } ; + + psf_log_printf (psf, " Type : %X\n", type) ; + psf_binheader_readf (psf, "4", &name) ; + name [size] = 0 ; + } + else + return SFE_MAT5_NO_BLOCK ; + + psf_log_printf (psf, " Name : %s\n", name) ; + + /*-----------------------------------------*/ + + psf_binheader_readf (psf, "44", &type, &size) ; + + if (!have_samplerate) + goto skip_samplerate ; + + switch (type) + { case MAT5_TYPE_DOUBLE : + { double samplerate ; + + psf_binheader_readf (psf, "d", &samplerate) ; + snprintf (name, sizeof (name), "%f\n", samplerate) ; + psf_log_printf (psf, " Val : %s\n", name) ; + + psf->sf.samplerate = psf_lrint (samplerate) ; + } ; + break ; + + case MAT5_TYPE_COMP_USHORT : + { unsigned short samplerate ; + + psf_binheader_readf (psf, "j2j", -4, &samplerate, 2) ; + psf_log_printf (psf, " Val : %u\n", samplerate) ; + psf->sf.samplerate = samplerate ; + } + break ; + + case MAT5_TYPE_COMP_UINT : + psf_log_printf (psf, " Val : %u\n", size) ; + psf->sf.samplerate = size ; + break ; + + default : + psf_log_printf (psf, " Type : %X Size : %d ***\n", type, size) ; + return SFE_MAT5_SAMPLE_RATE ; + } ; + + /*-----------------------------------------*/ + + + psf_binheader_readf (psf, "44", &type, &size) ; + psf_log_printf (psf, " Type : %X Size : %d\n", type, size) ; + + if (type != MAT5_TYPE_ARRAY) + return SFE_MAT5_NO_BLOCK ; + + psf_binheader_readf (psf, "44", &type, &size) ; + psf_log_printf (psf, " Type : %X Size : %d\n", type, size) ; + + if (type != MAT5_TYPE_UINT32) + return SFE_MAT5_NO_BLOCK ; + + psf_binheader_readf (psf, "44", &flags1, &flags2) ; + psf_log_printf (psf, " Flg1 : %X Flg2 : %d\n", flags1, flags2) ; + + psf_binheader_readf (psf, "44", &type, &size) ; + psf_log_printf (psf, " Type : %X Size : %d\n", type, size) ; + + if (type != MAT5_TYPE_INT32) + return SFE_MAT5_NO_BLOCK ; + + psf_binheader_readf (psf, "44", &rows, &cols) ; + psf_log_printf (psf, " Rows : %X Cols : %d\n", rows, cols) ; + + psf_binheader_readf (psf, "4", &type) ; + + if (type == MAT5_TYPE_SCHAR) + { psf_binheader_readf (psf, "4", &size) ; + psf_log_printf (psf, " Type : %X Size : %d\n", type, size) ; + if (size > SIGNED_SIZEOF (name) - 1) + { psf_log_printf (psf, "Error : Bad name length.\n") ; + return SFE_MAT5_NO_BLOCK ; + } ; + + psf_binheader_readf (psf, "bj", name, size, (8 - (size % 8)) % 8) ; + name [size] = 0 ; + } + else if ((type & 0xFFFF) == MAT5_TYPE_SCHAR) + { size = type >> 16 ; + if (size > 4) + { psf_log_printf (psf, "Error : Bad name length.\n") ; + return SFE_MAT5_NO_BLOCK ; + } ; + + psf_log_printf (psf, " Type : %X\n", type) ; + psf_binheader_readf (psf, "4", &name) ; + name [size] = 0 ; + } + else + return SFE_MAT5_NO_BLOCK ; + + psf_log_printf (psf, " Name : %s\n", name) ; + + psf_binheader_readf (psf, "44", &type, &size) ; + psf_log_printf (psf, " Type : %X Size : %d\n", type, size) ; + +skip_samplerate : + /*++++++++++++++++++++++++++++++++++++++++++++++++++*/ + + if (rows == 0 && cols == 0) + { psf_log_printf (psf, "*** Error : zero channel count.\n") ; + return SFE_CHANNEL_COUNT_ZERO ; + } ; + + psf->sf.channels = rows ; + psf->sf.frames = cols ; + + psf->sf.format = psf->endian | SF_FORMAT_MAT5 ; + + switch (type) + { case MAT5_TYPE_DOUBLE : + psf_log_printf (psf, "Data type : double\n") ; + psf->sf.format |= SF_FORMAT_DOUBLE ; + psf->bytewidth = 8 ; + break ; + + case MAT5_TYPE_FLOAT : + psf_log_printf (psf, "Data type : float\n") ; + psf->sf.format |= SF_FORMAT_FLOAT ; + psf->bytewidth = 4 ; + break ; + + case MAT5_TYPE_INT32 : + psf_log_printf (psf, "Data type : 32 bit PCM\n") ; + psf->sf.format |= SF_FORMAT_PCM_32 ; + psf->bytewidth = 4 ; + break ; + + case MAT5_TYPE_INT16 : + psf_log_printf (psf, "Data type : 16 bit PCM\n") ; + psf->sf.format |= SF_FORMAT_PCM_16 ; + psf->bytewidth = 2 ; + break ; + + case MAT5_TYPE_UCHAR : + psf_log_printf (psf, "Data type : unsigned 8 bit PCM\n") ; + psf->sf.format |= SF_FORMAT_PCM_U8 ; + psf->bytewidth = 1 ; + break ; + + default : + psf_log_printf (psf, "*** Error : Bad marker %08X\n", type) ; + return SFE_UNIMPLEMENTED ; + } ; + + psf->dataoffset = psf_ftell (psf) ; + psf->datalength = psf->filelength - psf->dataoffset ; + + return 0 ; +} /* mat5_read_header */ + diff --git a/extern/libsndfile-modified/src/mpc2k.c b/extern/libsndfile-modified/src/mpc2k.c new file mode 100644 index 000000000..733f1f4bc --- /dev/null +++ b/extern/libsndfile-modified/src/mpc2k.c @@ -0,0 +1,202 @@ +/* +** Copyright (C) 2008-2017 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + +/* +** Info from Olivier Tristan +** +** HEADER +** 2 magic bytes: 1 and 4. +** 17 char for the name of the sample. +** 3 bytes: level, tune and channels (0 for channels is mono while 1 is stereo) +** 4 uint32: sampleStart, loopEnd, sampleFrames and loopLength +** 1 byte: loopMode (0 no loop, 1 forward looping) +** 1 byte: number of beat in loop +** 1 uint16: sampleRate +** +** DATA +** Data are always non compressed 16 bits interleaved +*/ + +#define HEADER_LENGTH 42 /* Sum of above data fields. */ +#define HEADER_NAME_LEN 17 /* Length of name string. */ + +/*------------------------------------------------------------------------------ +** Private static functions. +*/ + +static int mpc2k_close (SF_PRIVATE *psf) ; + +static int mpc2k_write_header (SF_PRIVATE *psf, int calc_length) ; +static int mpc2k_read_header (SF_PRIVATE *psf) ; + +/*------------------------------------------------------------------------------ +** Public function. +*/ + +int +mpc2k_open (SF_PRIVATE *psf) +{ int error = 0 ; + + if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0)) + { if ((error = mpc2k_read_header (psf))) + return error ; + } ; + + if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_MPC2K) + return SFE_BAD_OPEN_FORMAT ; + + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { if (mpc2k_write_header (psf, SF_FALSE)) + return psf->error ; + + psf->write_header = mpc2k_write_header ; + } ; + + psf->container_close = mpc2k_close ; + + psf->blockwidth = psf->bytewidth * psf->sf.channels ; + + error = pcm_init (psf) ; + + return error ; +} /* mpc2k_open */ + +/*------------------------------------------------------------------------------ +*/ + +static int +mpc2k_close (SF_PRIVATE *psf) +{ + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + mpc2k_write_header (psf, SF_TRUE) ; + + return 0 ; +} /* mpc2k_close */ + +static int +mpc2k_write_header (SF_PRIVATE *psf, int calc_length) +{ char sample_name [HEADER_NAME_LEN + 1] ; + sf_count_t current ; + + if (psf->pipeoffset > 0) + return 0 ; + + current = psf_ftell (psf) ; + + if (calc_length) + { psf->filelength = psf_get_filelen (psf) ; + + psf->dataoffset = HEADER_LENGTH ; + psf->datalength = psf->filelength - psf->dataoffset ; + + psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ; + } ; + + /* Reset the current header length to zero. */ + psf->header.ptr [0] = 0 ; + psf->header.indx = 0 ; + + /* + ** Only attempt to seek if we are not writng to a pipe. If we are + ** writing to a pipe we shouldn't be here anyway. + */ + if (psf->is_pipe == SF_FALSE) + psf_fseek (psf, 0, SEEK_SET) ; + + snprintf (sample_name, sizeof (sample_name), "%-*.*s", HEADER_NAME_LEN, HEADER_NAME_LEN, psf->file.name) ; + + psf_binheader_writef (psf, "e11b", BHW1 (1), BHW1 (4), BHWv (sample_name), BHWz (HEADER_NAME_LEN)) ; + psf_binheader_writef (psf, "e111", BHW1 (100), BHW1 (0), BHW1 ((psf->sf.channels - 1) & 1)) ; + psf_binheader_writef (psf, "et4888", BHW4 (0), BHW8 (psf->sf.frames), BHW8 (psf->sf.frames), BHW8 (psf->sf.frames)) ; + psf_binheader_writef (psf, "e112", BHW1 (0), BHW1 (1), BHW2 ((uint16_t) psf->sf.samplerate)) ; + + /* Always 16 bit little endian data. */ + psf->bytewidth = 2 ; + psf->endian = SF_ENDIAN_LITTLE ; + + psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ; + + if (psf->error) + return psf->error ; + + psf->dataoffset = psf->header.indx ; + + if (current > 0) + psf_fseek (psf, current, SEEK_SET) ; + + return psf->error ; +} /* mpc2k_write_header */ + +static int +mpc2k_read_header (SF_PRIVATE *psf) +{ char sample_name [HEADER_NAME_LEN + 1] ; + unsigned char bytes [4] ; + uint32_t sample_start, loop_end, sample_frames, loop_length ; + uint16_t sample_rate ; + + psf_binheader_readf (psf, "pebb", 0, bytes, 2, sample_name, make_size_t (HEADER_NAME_LEN)) ; + + if (bytes [0] != 1 || bytes [1] != 4) + return SFE_MPC_NO_MARKER ; + + sample_name [HEADER_NAME_LEN] = 0 ; + + psf_log_printf (psf, "MPC2000\n Name : %s\n", sample_name) ; + + psf_binheader_readf (psf, "eb4444", bytes, 3, &sample_start, &loop_end, &sample_frames, &loop_length) ; + + psf->sf.channels = bytes [2] ? 2 : 1 ; + + psf_log_printf (psf, " Level : %d\n Tune : %d\n Stereo : %s\n", bytes [0], bytes [1], bytes [2] ? "Yes" : "No") ; + + psf_log_printf (psf, " Sample start : %d\n Loop end : %d\n Frames : %d\n Length : %d\n", sample_start, loop_end, sample_frames, loop_length) ; + + psf_binheader_readf (psf, "eb2", bytes, 2, &sample_rate) ; + + psf_log_printf (psf, " Loop mode : %s\n Beats : %d\n Sample rate : %d\nEnd\n", bytes [0] ? "None" : "Fwd", bytes [1], sample_rate) ; + + psf->sf.samplerate = sample_rate ; + + psf->sf.format = SF_FORMAT_MPC2K | SF_FORMAT_PCM_16 ; + + psf->dataoffset = psf_ftell (psf) ; + + /* Always 16 bit little endian data. */ + psf->bytewidth = 2 ; + psf->endian = SF_ENDIAN_LITTLE ; + + psf->datalength = psf->filelength - psf->dataoffset ; + psf->blockwidth = psf->sf.channels * psf->bytewidth ; + psf->sf.frames = psf->datalength / psf->blockwidth ; + + psf->sf.frames = (psf->filelength - psf->dataoffset) / psf->blockwidth ; + + return 0 ; +} /* mpc2k_read_header */ + diff --git a/extern/libsndfile-modified/src/mpeg.c b/extern/libsndfile-modified/src/mpeg.c new file mode 100644 index 000000000..44db0adfb --- /dev/null +++ b/extern/libsndfile-modified/src/mpeg.c @@ -0,0 +1,165 @@ +/* +** Copyright (C) 2019 Erik de Castro Lopo +** Copyright (C) 2021 Arthur Taylor +** +** This program is free software ; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation ; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY ; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program ; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include "sndfile.h" +#include "common.h" + +#if HAVE_MPEG + +#include "mpeg.h" + +static int mpeg_write_header (SF_PRIVATE *psf, int calc_length) ; +static int mpeg_command (SF_PRIVATE *psf, int command, void *data, int datasize) ; + +/*------------------------------------------------------------------------------ + * Private functions + */ + +static int +mpeg_write_header (SF_PRIVATE *psf, int UNUSED (calc_length)) +{ + if (psf->have_written) + return 0 ; + + return mpeg_l3_encoder_write_id3tag (psf) ; +} + +static int +mpeg_command (SF_PRIVATE *psf, int command, void *data, int datasize) +{ int bitrate_mode ; + + switch (command) + { case SFC_SET_COMPRESSION_LEVEL : + if (data == NULL || datasize != sizeof (double)) + { psf->error = SFE_BAD_COMMAND_PARAM ; + return SF_FALSE ; + } ; + if (psf->file.mode != SFM_WRITE) + { psf->error = SFE_NOT_WRITEMODE ; + return SF_FALSE ; + } ; + return mpeg_l3_encoder_set_quality (psf, *(double *) data) ; + + case SFC_SET_BITRATE_MODE : + if (psf->file.mode != SFM_WRITE) + { psf->error = SFE_NOT_WRITEMODE ; + return SF_FALSE ; + } ; + if (data == NULL || datasize != sizeof (int)) + { psf->error = SFE_BAD_COMMAND_PARAM ; + return SF_FALSE ; + } ; + bitrate_mode = *(int *) data ; + return mpeg_l3_encoder_set_bitrate_mode (psf, bitrate_mode) ; + + case SFC_GET_BITRATE_MODE : + if (psf->file.mode == SFM_READ) + return mpeg_decoder_get_bitrate_mode (psf) ; + else + return mpeg_l3_encoder_get_bitrate_mode (psf) ; + + default : + return SF_FALSE ; + } ; + + return SF_FALSE ; +} /* mpeg_command */ + +/*------------------------------------------------------------------------------ + * Public functions + */ + +int +mpeg_init (SF_PRIVATE *psf, int bitrate_mode, int write_metadata) +{ int error ; + + if (psf->file.mode == SFM_RDWR) + return SFE_BAD_MODE_RW ; + + if (psf->file.mode == SFM_WRITE) + { switch (SF_CODEC (psf->sf.format)) + { case SF_FORMAT_MPEG_LAYER_III : + if ((error = mpeg_l3_encoder_init (psf, write_metadata))) + return error ; + mpeg_l3_encoder_set_bitrate_mode (psf, bitrate_mode) ; + if (write_metadata) + { /* ID3 support */ + psf->strings.flags = SF_STR_ALLOW_START ; + psf->write_header = mpeg_write_header ; + } ; + break ; + + case SF_FORMAT_MPEG_LAYER_I : + case SF_FORMAT_MPEG_LAYER_II : + psf_log_printf (psf, "MPEG Layer I and II encoding is not yet supported.\n") ; + return SFE_UNIMPLEMENTED ; + + default: + psf_log_printf (psf, "%s: bad psf->sf.format 0x%x.\n", __func__, psf->sf.format) ; + return SFE_INTERNAL ; + } ; + } ; + + if (psf->file.mode == SFM_READ) + { if ((error = mpeg_decoder_init (psf))) + return error ; + } ; + + return 0 ; +} /* mpeg_init */ + +int +mpeg_open (SF_PRIVATE *psf) +{ int error ; + + /* Choose variable bitrate mode by default for standalone files.*/ + if ((error = mpeg_init (psf, SF_BITRATE_MODE_VARIABLE, SF_TRUE))) + return error ; + + psf->dataoffset = 0 ; + psf->command = mpeg_command ; + + if (psf->filelength != SF_COUNT_MAX) + psf->datalength = psf->filelength - psf->dataoffset ; + else + psf->datalength = SF_COUNT_MAX ; + + + return 0 ; +} /* mpeg_open */ + +#else /* HAVE_MPEG */ + +int +mpeg_init (SF_PRIVATE *psf, int UNUSED (bitrate_mode) , int UNUSED (write_metadata)) +{ + psf_log_printf (psf, "This version of libsndfile was compiled without MPEG support.\n") ; + return SFE_UNIMPLEMENTED ; +} /* mpeg_init */ + +int +mpeg_open (SF_PRIVATE *psf) +{ + psf_log_printf (psf, "This version of libsndfile was compiled without MP3 support.\n") ; + return SFE_UNIMPLEMENTED ; +} /* mpeg_open */ + +#endif diff --git a/extern/libsndfile-modified/src/mpeg.h b/extern/libsndfile-modified/src/mpeg.h new file mode 100644 index 000000000..f335745f7 --- /dev/null +++ b/extern/libsndfile-modified/src/mpeg.h @@ -0,0 +1,74 @@ +/* +** Copyright (C) 2019 Erik de Castro Lopo +** Copyright (C) 2019 Arthur Taylor +** +** This program is free software ; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation ; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY ; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program ; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef SNDFILE_MPEG_H +#define SNDFILE_MPEG_H + +#include "common.h" + +int mpeg_decoder_init (SF_PRIVATE *psf) ; + +/* +** Get the file bitrate mode, returning one of the SF_BITRATE_MODE_ enum +** values. Purely informative, 'Frankenstein' files and VBR files without an +** Xing/LAME/Info header may not be detected properly. +*/ +int mpeg_decoder_get_bitrate_mode (SF_PRIVATE *psf) ; + + +/* +** Initialize an encoder instance for writing. If parameter info_tag is +** SF_TRUE, a Xing/LAME/Info header is written at the beginning of the file, +** (unless the file cannot seek.) +*/ +int mpeg_l3_encoder_init (SF_PRIVATE *psf, int info_tag) ; + + +/* +** Write an ID3v2 header from the sndfile string metadata. Must be called +** before any audio data is written. Writing an ID3v2 header will also cause +** a ID3v1 trailer to be written on close automatically. +*/ +int mpeg_l3_encoder_write_id3tag (SF_PRIVATE *psf) ; + +/* +** Set the encoder quality setting. Argument to compression should be identical +** to that for SFC_SET_COMPRESSION_LEVEL; It should be in the range [0-1], +** with 0 being highest quality, least compression, and 1 being the opposite. +** Returns SF_TRUE on success, SF_FALSE otherwise. +*/ +int mpeg_l3_encoder_set_quality (SF_PRIVATE *psf, double compression) ; + +/* +** Set the encoder bitrate mode. Can only be called before any data has been +** written. Argument mode should be one of the SF_BITRATE_MODE_ enum values. +** Returns SF_TRUE on success, SF_FALSE otherwise. The SF_BITRATE_MODE_FILE +** enum value should not be passed here but rather intercepted at the container +** level and translated according to the container. +*/ +int mpeg_l3_encoder_set_bitrate_mode (SF_PRIVATE *psf, int mode) ; + +/* +** Get the encoder bitrate mode in use. Returns a SF_BITRATE_MODE_ enum value. +** Will not return SF_BITRATE_MODE_FILE. +*/ +int mpeg_l3_encoder_get_bitrate_mode (SF_PRIVATE *psf) ; + + +#endif /* SNDFILE_MPEG_H */ diff --git a/extern/libsndfile-modified/src/mpeg_decode.c b/extern/libsndfile-modified/src/mpeg_decode.c new file mode 100644 index 000000000..aaf12bf9c --- /dev/null +++ b/extern/libsndfile-modified/src/mpeg_decode.c @@ -0,0 +1,644 @@ +/* +** Copyright (C) 2019 - 2021 Arthur Taylor +** Copyright (C) 2019 Erik de Castro Lopo +** +** This program is free software ; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation ; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY ; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program ; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include + +#include "sndfile.h" +#include "common.h" +#include "mpeg.h" + +#if HAVE_MPEG + +#include "sfendian.h" +#include "id3.h" + +#include + +typedef struct +{ mpg123_handle *pmh ; + size_t header_remaining ; +} MPEG_DEC_PRIVATE ; + +static int mpeg_dec_close (SF_PRIVATE *psf) ; +static sf_count_t mpeg_dec_seek (SF_PRIVATE *psf, int whence, sf_count_t count) ; + +static ssize_t mpeg_dec_io_read (void *priv, void *buffer, size_t nbytes) ; +static off_t mpeg_dec_io_lseek (void *priv, off_t offset, int whence) ; + +static ssize_t +mpeg_dec_io_read (void *priv, void *buffer, size_t nbytes) +{ SF_PRIVATE *psf = (SF_PRIVATE *) priv ; + MPEG_DEC_PRIVATE *pmp3d = (MPEG_DEC_PRIVATE *) psf->codec_data ; + + if (pmp3d->header_remaining) + { if (pmp3d->header_remaining < nbytes) + nbytes = pmp3d->header_remaining ; + psf_binheader_readf (psf, "b", buffer, nbytes) ; + pmp3d->header_remaining -= nbytes ; + return nbytes ; + } ; + + return psf_fread (buffer, 1, nbytes, psf) ; +} /* mpeg_dec_io_read */ + +static off_t +mpeg_dec_io_lseek (void *priv, off_t offset, int whence) +{ SF_PRIVATE *psf = (SF_PRIVATE *) priv ; + + return psf_fseek (psf, offset, whence) ; +} /* mpeg_dec_io_lseek */ + +static int +mpeg_dec_close (SF_PRIVATE *psf) +{ MPEG_DEC_PRIVATE *pmp3d = (MPEG_DEC_PRIVATE *) psf->codec_data ; + + if (pmp3d) + { if (pmp3d->pmh) + { mpg123_close (pmp3d->pmh) ; + mpg123_delete (pmp3d->pmh) ; + pmp3d->pmh = NULL ; + } + free (psf->codec_data) ; + psf->codec_data = NULL ; + } ; + + return 0 ; +} /* mpeg_dec_close */ + +static sf_count_t +mpeg_dec_decode (SF_PRIVATE *psf, float *ptr, sf_count_t len) +{ MPEG_DEC_PRIVATE *pmp3d = (MPEG_DEC_PRIVATE *) psf->codec_data ; + size_t done ; + int error ; + + error = mpg123_read (pmp3d->pmh, (unsigned char *) ptr, len * sizeof (float), &done) ; + + if (error == MPG123_OK || error == MPG123_DONE) + return done / sizeof (float) ; + + if (error == MPG123_NEW_FORMAT) + { psf->error = SFE_MALFORMED_FILE ; + return -1 ; + } ; + + psf->error = SFE_INTERNAL ; + return -1 ; +} /* mpeg_dec_decode */ + +static sf_count_t +mpeg_dec_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + sf_count_t total, readlen ; + void (*convert) (const float *, short *, int, int) ; + const sf_count_t buflen = ARRAY_LEN (ubuf.fbuf) ; + + convert = (psf->add_clipping) ? psf_f2s_clip_array : psf_f2s_array ; + for (total = 0 ; total < len ; total += readlen) + { readlen = mpeg_dec_decode (psf, ubuf.fbuf, SF_MIN (buflen, len - total)) ; + if (readlen <= 0) + break ; + + convert (ubuf.fbuf, ptr + total, readlen, SF_TRUE) ; + } ; + + return total ; +} /*mpeg_dec_read_s */ + +static sf_count_t +mpeg_dec_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + sf_count_t total, readlen ; + void (*convert) (const float *, int *, int, int) ; + const sf_count_t buflen = ARRAY_LEN (ubuf.fbuf) ; + + convert = (psf->add_clipping) ? psf_f2i_clip_array : psf_f2i_array ; + for (total = 0 ; total < len ; total += readlen) + { readlen = mpeg_dec_decode (psf, ubuf.fbuf, SF_MIN (buflen, len - total)) ; + if (readlen <= 0) + break ; + + convert (ubuf.fbuf, ptr + total, readlen, SF_TRUE) ; + } ; + + return total ; +} /* mpeg_dec_read_i */ + +static sf_count_t +mpeg_dec_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) +{ sf_count_t readlen ; + + readlen = mpeg_dec_decode (psf, ptr, len) ; + if (readlen <= 0) + return 0 ; + + if (psf->norm_float == SF_FALSE) + for (int i = 0 ; i < readlen ; i++) + { ptr [i] *= (1.0f * 0x8000) ; + } ; + + return readlen ; +} /* mpeg_dec_read_f */ + +static inline void +f2d_array (const float *src, int count, double *dest, double normfact) +{ for (int i = 0 ; i < count ; i++) + { dest [i] = src [i] * normfact ; + } +} /* f2d_array */ + +static sf_count_t +mpeg_dec_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + sf_count_t total, readlen ; + double normfact ; + const sf_count_t buflen = ARRAY_LEN (ubuf.fbuf) ; + + normfact = (psf->norm_double == SF_TRUE) ? 1.0 : (1.0 * 0x8000) ; + + for (total = 0 ; total < len ; total += readlen) + { readlen = mpeg_dec_decode (psf, ubuf.fbuf, SF_MIN (buflen, len - total)) ; + if (readlen <= 0) + break ; + + f2d_array (ubuf.fbuf, readlen, ptr + total, normfact) ; + } ; + + return total ; +} /* mpeg_dec_read_d */ + +static sf_count_t +mpeg_dec_seek (SF_PRIVATE *psf, int mode, sf_count_t count) +{ MPEG_DEC_PRIVATE *pmp3d = (MPEG_DEC_PRIVATE *) psf->codec_data ; + off_t ret ; + + if (mode != SFM_READ || psf->file.mode != SFM_READ) + { psf->error = SFE_BAD_SEEK ; + return PSF_SEEK_ERROR ; + } ; + + ret = mpg123_seek (pmp3d->pmh, count, SEEK_SET) ; + + if (ret < 0) + return PSF_SEEK_ERROR ; + + return (sf_count_t) ret ; +} /* mpeg_dec_seek */ + +static int +mpeg_dec_fill_sfinfo (SF_PRIVATE* psf, mpg123_handle *mh, SF_INFO *info) +{ int error ; + int channels ; + int encoding ; + long rate ; + off_t length ; + + error = mpg123_getformat (mh, &rate, &channels, &encoding) ; + if (error != MPG123_OK) + return error ; + + info->samplerate = rate ; + info->channels = channels ; + + length = mpg123_length (mh) ; + if (length <= 0 && !psf->is_pipe) + { if ((error = mpg123_scan (mh)) != MPG123_OK) + return error ; + length = mpg123_length (mh) ; + } + + if (length >= 0) + { info->frames = length ; + info->seekable = SF_TRUE ; + } + else + { info->frames = SF_COUNT_MAX ; + info->seekable = SF_FALSE ; + } + + /* Force 32-bit float samples. */ + if (encoding != MPG123_ENC_FLOAT_32) + { error = mpg123_format (mh, rate, channels, MPG123_ENC_FLOAT_32) ; + } ; + + return error ; +} /* mpeg_dec_fill_sfinfo */ + +static void +mpeg_dec_print_frameinfo (SF_PRIVATE *psf, const struct mpg123_frameinfo *fi) +{ psf_log_printf (psf, "MPEG-1/2 Audio\n----------------------------------------\n") ; + psf_log_printf (psf, " MPEG version : %s\n", + fi->version == MPG123_1_0 ? "MPEG 1.0" : + fi->version == MPG123_2_0 ? "MPEG 2.0" : + fi->version == MPG123_2_5 ? "MPEG 2.5" : "???") ; + psf_log_printf (psf, " layer : %d\n", fi->layer) ; + psf_log_printf (psf, " rate : %d\n", fi->rate) ; + psf_log_printf (psf, " mode : %s\n", + fi->mode == MPG123_M_STEREO ? "stereo" : + fi->mode == MPG123_M_JOINT ? "joint stereo" : + fi->mode == MPG123_M_DUAL ? "dual channel" : + fi->mode == MPG123_M_MONO ? "mono" : "???") ; + psf_log_printf (psf, " mode ext : %d\n", fi->mode_ext) ; + psf_log_printf (psf, " framesize : %d\n", fi->framesize) ; + psf_log_printf (psf, " crc : %d\n", !! (fi->flags & MPG123_CRC)) ; + psf_log_printf (psf, " copyright flag : %d\n", !! (fi->flags & MPG123_COPYRIGHT)) ; + psf_log_printf (psf, " private flag : %d\n", !! (fi->flags & MPG123_PRIVATE)) ; + psf_log_printf (psf, " original flag : %d\n", !! (fi->flags & MPG123_ORIGINAL)) ; + psf_log_printf (psf, " emphasis : %d\n", fi->emphasis) ; + psf_log_printf (psf, " bitrate mode : ") ; + switch (fi->vbr) + { case MPG123_CBR : + psf_log_printf (psf, "constant\n") ; + psf_log_printf (psf, " bitrate : %d kbps\n", fi->bitrate) ; + break ; + case MPG123_VBR : + psf_log_printf (psf, "variable\n") ; + break ; + + case MPG123_ABR : + psf_log_printf (psf, "average\n") ; + psf_log_printf (psf, " ABR target : %d\n", fi->abr_rate) ; + break ; + + default : + psf_log_printf (psf, "(%d) ???\n", fi->vbr) ; + break ; + } ; +} /* mpeg_dec_print_frameinfo */ + +/* + * Like strlcpy, except the size argument is the maximum size of the input, + * always null terminates the output string. Thus, up to size + 1 bytes may be + * written. + * + * Returns the length of the copied string. + */ +static int +strcpy_inbounded (char *dest, size_t size, const char *src) +{ char *c = memccpy (dest, src, '\0', size) ; + if (!c) + c = dest + size ; + *c = '\0' ; + return c - dest ; +} /* strcpy_inbounded */ + +static void +mpeg_decoder_read_strings_id3v1 (SF_PRIVATE *psf, mpg123_id3v1 *tags) +{ const char *genre ; + char buf [31] ; + + psf_log_printf (psf, "ID3v1 Tags\n") ; + + if (strcpy_inbounded (buf, ARRAY_LEN (tags->title), tags->title)) + { psf_log_printf (psf, " Title : %s\n", buf) ; + psf_store_string (psf, SF_STR_TITLE, buf) ; + } ; + + if (strcpy_inbounded (buf, ARRAY_LEN (tags->artist), tags->artist)) + { psf_log_printf (psf, " Artist : %s\n", buf) ; + psf_store_string (psf, SF_STR_ARTIST, buf) ; + } ; + + if (strcpy_inbounded (buf, ARRAY_LEN (tags->album), tags->album)) + { psf_log_printf (psf, " Album : %s\n", buf) ; + psf_store_string (psf, SF_STR_ALBUM, buf) ; + } ; + + if (strcpy_inbounded (buf, ARRAY_LEN (tags->year), tags->year)) + { psf_log_printf (psf, " Year : %s\n", buf) ; + psf_store_string (psf, SF_STR_DATE, buf) ; + } ; + + if (strcpy_inbounded (buf, ARRAY_LEN (tags->comment), tags->comment)) + { psf_log_printf (psf, " Comment : %s\n", buf) ; + psf_store_string (psf, SF_STR_COMMENT, buf) ; + } ; + + /* ID3v1.1 Tracknumber */ + if (tags->comment [28] == '\0' && tags->comment [29] != '\0') + { snprintf (buf, ARRAY_LEN (buf), "%hhu", (unsigned char) tags->comment [29]) ; + psf_log_printf (psf, " Tracknumber : %s\n", buf) ; + psf_store_string (psf, SF_STR_TRACKNUMBER, buf) ; + } ; + + if ((genre = id3_lookup_v1_genre (tags->genre)) != NULL) + { psf_log_printf (psf, " Genre : %s\n", genre) ; + psf_store_string (psf, SF_STR_GENRE, genre) ; + } ; +} /* mpeg_decoder_read_strings_id3v1 */ + +static void +mpeg_decoder_read_strings_id3v2 (SF_PRIVATE *psf, mpg123_id3v2 *tags) +{ mpg123_text *text_frame ; + size_t i ; + uint32_t marker ; + const char *title = NULL ; + const char *copyright = NULL ; + const char *software = NULL ; + const char *artist = NULL ; + const char *comment = NULL ; + const char *date = NULL ; + const char *album = NULL ; + const char *license = NULL ; + const char *tracknumber = NULL ; + const char *genre = NULL ; + const char *tlen = NULL ; + + psf_log_printf (psf, "ID3v2 Tags\n") ; + + // Read the parsed text tags + for (i = 0 ; i < tags->texts ; i++) + { text_frame = &tags->text [i] ; + psf_log_printf (psf, " %.4s : %s\n", text_frame->id, text_frame->text.p) ; + + // Thankfully mpg123 translates v2.2 3-byte frames to v2.3 4-byte for us. + marker = MAKE_MARKER (text_frame->id [0], text_frame->id [1], + text_frame->id [2], text_frame->id [3]) ; + + /* Use our own map of frame types to metadata for text frames */ + switch (marker) + { case MAKE_MARKER ('T', 'I', 'T', '2') : + title = text_frame->text.p ; + break ; + + case MAKE_MARKER ('T', 'C', 'O', 'P') : + copyright = text_frame->text.p ; + break ; + + case MAKE_MARKER ('T', 'E', 'N', 'C') : + case MAKE_MARKER ('T', 'S', 'S', 'E') : + software = text_frame->text.p ; + break ; + + case MAKE_MARKER ('T', 'P', 'E', '1') : + artist = text_frame->text.p ; + break ; + + case MAKE_MARKER ('T', 'A', 'L', 'B') : + album = text_frame->text.p ; + break ; + + case MAKE_MARKER ('T', 'R', 'C', 'K') : + tracknumber = text_frame->text.p ; + break ; + + case MAKE_MARKER ('T', 'Y', 'E', 'R') : + case MAKE_MARKER ('T', 'D', 'R', 'C') : + /* TODO (maybe) + case MAKE_MARKER ('T', 'D', 'A', 'T') : + case MAKE_MARKER ('T', 'I', 'M', 'E') : + case MAKE_MARKER ('T', 'D', 'R', 'A') : + */ + date = text_frame->text.p ; + break ; + + case MAKE_MARKER ('T', 'O', 'W', 'N') : + tracknumber = text_frame->text.p ; + break ; + + case MAKE_MARKER ('T', 'C', 'O', 'N') : + genre = text_frame->text.p ; + break ; + + case MAKE_MARKER ('T', 'L', 'E', 'N') : + tlen = text_frame->text.p ; + break ; + } ; + } ; + + /* Use mpg123's handling of comment headers, but print all the comment headers anyways. */ + if (tags->comment) + comment = tags->comment->p ; + for (i = 0 ; i < tags->comments ; i++) + { text_frame = &tags->comment_list [i] ; + psf_log_printf (psf, " %.4s : (%s)[%s] %s\n", text_frame->id, + text_frame->description. p, text_frame->lang, text_frame->text.p) ; + } ; + + /* Print extra headers */ + for (i = 0 ; i < tags->extras ; i++) + { text_frame = &tags->extra [i] ; + psf_log_printf (psf, " %.4s : (%s) %s\n", text_frame->id, + text_frame->description.p, text_frame->text.p) ; + } ; + + if (title != NULL) + psf_store_string (psf, SF_STR_TITLE, title) ; + if (copyright != NULL) + psf_store_string (psf, SF_STR_COPYRIGHT, copyright) ; + if (software != NULL) + psf_store_string (psf, SF_STR_SOFTWARE, software) ; + if (artist != NULL) + psf_store_string (psf, SF_STR_ARTIST, artist) ; + if (comment != NULL) + psf_store_string (psf, SF_STR_COMMENT, comment) ; + if (date != NULL) + psf_store_string (psf, SF_STR_DATE, date) ; + if (album != NULL) + psf_store_string (psf, SF_STR_ALBUM, album) ; + if (license != NULL) + psf_store_string (psf, SF_STR_LICENSE, license) ; + if (tracknumber != NULL) + psf_store_string (psf, SF_STR_TRACKNUMBER, tracknumber) ; + if (genre != NULL) + psf_store_string (psf, SF_STR_GENRE, id3_process_v2_genre (genre)) ; + if (tlen != NULL) + { /* If non-seekable, set framecount? Can we trust it? */ + } ; +} /* mpeg_decoder_read_strings_id3v2 */ + +static void +mpeg_decoder_read_strings (SF_PRIVATE *psf) +{ MPEG_DEC_PRIVATE *pmp3d = (MPEG_DEC_PRIVATE *) psf->codec_data ; + mpg123_id3v1 *v1_tags ; + mpg123_id3v2 *v2_tags ; + + if (mpg123_id3 (pmp3d->pmh, &v1_tags, &v2_tags) != MPG123_OK) + return ; + + if (v1_tags != NULL) + mpeg_decoder_read_strings_id3v1 (psf, v1_tags) ; + + if (v2_tags != NULL) + mpeg_decoder_read_strings_id3v2 (psf, v2_tags) ; +} /* mpeg_decoder_read_strings */ + +static int +mpeg_dec_byterate (SF_PRIVATE *psf) +{ MPEG_DEC_PRIVATE *pmp3d = (MPEG_DEC_PRIVATE *) psf->codec_data ; + struct mpg123_frameinfo fi ; + + if (mpg123_info (pmp3d->pmh, &fi) == MPG123_OK) + return (fi.bitrate + 7) / 8 ; + + return -1 ; + +} /* mpeg_dec_byterate */ + +/*============================================================================== +** exported functions +*/ + +int +mpeg_decoder_init (SF_PRIVATE *psf) +{ MPEG_DEC_PRIVATE *pmp3d ; + struct mpg123_frameinfo fi ; + int error ; + + if (! (psf->file.mode & SFM_READ)) + return SFE_INTERNAL ; + + /* + ** *** FIXME - Threading issues *** + ** + ** mpg123_init() is a global call that should only be called once, and + ** should be paried with mpg123_exit() when done. libsndfile does not + ** provide for these requirements. + ** + ** Currently this is a moot issue as mpg123_init() non-conditionally writes + ** static areas with calculated data, and mpg123_exit() is a NOP, but this + ** could change in a future version of it! + ** + ** From mpg123.h: + ** > This should be called once in a non-parallel context. It is not explicitly + ** > thread-safe, but repeated/concurrent calls still _should_ be safe as static + ** > tables are filled with the same values anyway. + ** + ** Note that calling mpg123_init() after it has already completed is a NOP. + ** + ** Update 2021-07-04 + ** mpg123 upstream has confirmed that mpg132_init() will become a NOP in future, + ** so this is moot. + */ + if (mpg123_init () != MPG123_OK) + return SFE_INTERNAL ; + + psf->codec_data = pmp3d = calloc (1, sizeof (MPEG_DEC_PRIVATE)) ; + if (!psf->codec_data) + return SFE_MALLOC_FAILED ; + + pmp3d->pmh = mpg123_new (NULL, &error) ; + if (!pmp3d->pmh) + { psf_log_printf (psf, "Could not obtain a mpg123 handle: %s\n", mpg123_plain_strerror (error)) ; + return SFE_INTERNAL ; + } ; + + psf->codec_close = mpeg_dec_close ; + + mpg123_replace_reader_handle (pmp3d->pmh, + mpeg_dec_io_read, mpeg_dec_io_lseek, NULL) ; + + mpg123_param (pmp3d->pmh, MPG123_REMOVE_FLAGS, MPG123_AUTO_RESAMPLE, 1.0) ; + mpg123_param (pmp3d->pmh, MPG123_ADD_FLAGS, MPG123_FORCE_FLOAT | MPG123_GAPLESS, 1.0) ; +#if MPG123_API_VERSION >= 45 + mpg123_param (pmp3d->pmh, MPG123_ADD_FLAGS, MPG123_NO_FRANKENSTEIN, 1.0) ; +#endif + + /* + ** Need to pass the first MPEG frame to libmpg123, but that frame was read + ** into psf->binheader in order that we could identify the stream. + */ + if (psf->is_pipe) + { /* + ** Can't seek, so setup our libmpg123 io callbacks to read the binheader + ** buffer first. + */ + psf_binheader_readf (psf, "p", psf->dataoffset) ; + pmp3d->header_remaining = psf_binheader_readf (psf, NULL) - psf->dataoffset ; + + /* Tell libmpg123 we can't seek the file. */ + mpg123_param (pmp3d->pmh, MPG123_ADD_FLAGS, MPG123_NO_PEEK_END, 1.0) ; + } + else + { /* + ** libmpg123 can parse the ID3v2 header. Undo the embedded file offset if the + ** enclosing file data is the ID3v2 header. + */ + if (psf->id3_header.len > 0 && psf->id3_header.len + psf->id3_header.offset == psf->fileoffset) + psf->fileoffset = psf->id3_header.offset ; + + psf_fseek (psf, 0, SEEK_SET) ; + } ; + + error = mpg123_open_handle (pmp3d->pmh, psf) ; + if (error != MPG123_OK) + { psf_log_printf (psf, "mpg123 could not open the file: %s\n", mpg123_plain_strerror (error)) ; + return SFE_BAD_FILE ; + } ; + + if (mpeg_dec_fill_sfinfo (psf, pmp3d->pmh, &psf->sf) != MPG123_OK) + { psf_log_printf (psf, "Cannot get MPEG decoder configuration: %s\n", mpg123_plain_strerror (error)) ; + return SFE_BAD_FILE ; + } ; + + error = mpg123_info (pmp3d->pmh, &fi) ; + if (error != MPG123_OK) + { psf_log_printf (psf, "Cannot get MPEG frame info: %s\n", mpg123_plain_strerror (error)) ; + return SFE_INTERNAL ; + } + + switch (fi.layer) + { case 1 : psf->sf.format |= SF_FORMAT_MPEG_LAYER_I ; break ; + case 2 : psf->sf.format |= SF_FORMAT_MPEG_LAYER_II ; break ; + case 3 : psf->sf.format |= SF_FORMAT_MPEG_LAYER_III ; break ; + default : + return SFE_BAD_FILE ; + } ; + mpeg_dec_print_frameinfo (psf, &fi) ; + + psf->read_short = mpeg_dec_read_s ; + psf->read_int = mpeg_dec_read_i ; + psf->read_float = mpeg_dec_read_f ; + psf->read_double = mpeg_dec_read_d ; + psf->seek = mpeg_dec_seek ; + psf->byterate = mpeg_dec_byterate ; + + mpeg_decoder_read_strings (psf) ; + + return 0 ; +} /* mpeg_decoder_init */ + +int +mpeg_decoder_get_bitrate_mode (SF_PRIVATE *psf) +{ MPEG_DEC_PRIVATE *pmp3d = (MPEG_DEC_PRIVATE *) psf->codec_data ; + struct mpg123_frameinfo fi ; + + if (mpg123_info (pmp3d->pmh, &fi) == MPG123_OK) + { + switch (fi.vbr) + { case MPG123_CBR : return SF_BITRATE_MODE_CONSTANT ; + case MPG123_ABR : return SF_BITRATE_MODE_AVERAGE ; + case MPG123_VBR : return SF_BITRATE_MODE_VARIABLE ; + default : break ; + } ; + } ; + + psf_log_printf (psf, "Cannot determine MPEG bitrate mode.\n") ; + return -1 ; +} /* mpeg_decoder_get_bitrate_mode */ + +#else /* HAVE_MPEG */ + +int mpeg_decoder_init (SF_PRIVATE *psf) +{ psf_log_printf (psf, "This version of libsndfile was compiled without MPEG decode support.\n") ; + return SFE_UNIMPLEMENTED ; +} /* mpeg_decoder_init */ + +#endif /* HAVE_MPEG */ diff --git a/extern/libsndfile-modified/src/mpeg_l3_encode.c b/extern/libsndfile-modified/src/mpeg_l3_encode.c new file mode 100644 index 000000000..97324f792 --- /dev/null +++ b/extern/libsndfile-modified/src/mpeg_l3_encode.c @@ -0,0 +1,784 @@ +/* +** Copyright (C) 2020 Arthur Taylor +** Copyright (C) 2019 Erik de Castro Lopo +** +** This program is free software ; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation ; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY ; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program ; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" +#include "sndfile.h" +#include "common.h" +#include "mpeg.h" + + +#if HAVE_MPEG + +#include + +/* + * RANT RANT RANT + * + * Lame has 11 functions for inputing sample data of various types and + * configurations, but due to bad definitions, or missing combinations, they + * aren't really of much help to us. + * + */ + +typedef struct +{ lame_t lamef ; + unsigned char *block ; + size_t block_len ; + int frame_samples ; + double compression ; + int initialized ; +} MPEG_L3_ENC_PRIVATE ; + + +/*----------------------------------------------------------------------------------------------- +** Private function prototypes. +*/ + +static int mpeg_l3_encoder_close (SF_PRIVATE *psf) ; +static int mpeg_l3_encoder_construct (SF_PRIVATE *psf) ; +static int mpeg_l3_encoder_byterate (SF_PRIVATE *psf) ; + +static sf_count_t mpeg_l3_encode_write_short_stereo (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; +static sf_count_t mpeg_l3_encode_write_int_stereo (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; +static sf_count_t mpeg_l3_encode_write_float_stereo (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; +static sf_count_t mpeg_l3_encode_write_double_stereo (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; +static sf_count_t mpeg_l3_encode_write_short_mono (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; +static sf_count_t mpeg_l3_encode_write_int_mono (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; +static sf_count_t mpeg_l3_encode_write_float_mono (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; +static sf_count_t mpeg_l3_encode_write_double_mono (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; + +/*----------------------------------------------------------------------------------------------- +** Exported functions. +*/ + +int +mpeg_l3_encoder_init (SF_PRIVATE *psf, int info_tag) +{ MPEG_L3_ENC_PRIVATE* pmpeg = NULL ; + + if (psf->file.mode == SFM_RDWR) + return SFE_BAD_MODE_RW ; + + if (psf->file.mode != SFM_WRITE) + return SFE_INTERNAL ; + + psf->codec_data = pmpeg = calloc (1, sizeof (MPEG_L3_ENC_PRIVATE)) ; + if (!pmpeg) + return SFE_MALLOC_FAILED ; + + if (psf->sf.channels < 1 || psf->sf.channels > 2) + return SFE_BAD_OPEN_FORMAT ; + + if (! (pmpeg->lamef = lame_init ())) + return SFE_MALLOC_FAILED ; + + pmpeg->compression = -1.0 ; /* Unset */ + + lame_set_in_samplerate (pmpeg->lamef, psf->sf.samplerate) ; + lame_set_num_channels (pmpeg->lamef, psf->sf.channels) ; + if (lame_set_out_samplerate (pmpeg->lamef, psf->sf.samplerate) < 0) + return SFE_MPEG_BAD_SAMPLERATE ; + + lame_set_write_id3tag_automatic (pmpeg->lamef, 0) ; + + if (!info_tag || psf->is_pipe) + { /* Can't seek back, so force disable Xing/Lame/Info header. */ + lame_set_bWriteVbrTag (pmpeg->lamef, 0) ; + } ; + + if (psf->sf.channels == 2) + { psf->write_short = mpeg_l3_encode_write_short_stereo ; + psf->write_int = mpeg_l3_encode_write_int_stereo ; + psf->write_float = mpeg_l3_encode_write_float_stereo ; + psf->write_double = mpeg_l3_encode_write_double_stereo ; + } + else + { psf->write_short = mpeg_l3_encode_write_short_mono ; + psf->write_int = mpeg_l3_encode_write_int_mono ; + psf->write_float = mpeg_l3_encode_write_float_mono ; + psf->write_double = mpeg_l3_encode_write_double_mono ; + } + + psf->sf.seekable = 0 ; + psf->codec_close = mpeg_l3_encoder_close ; + psf->byterate = mpeg_l3_encoder_byterate ; + psf->datalength = 0 ; + + return 0 ; +} /* mpeg_l3_encoder_init */ + +int +mpeg_l3_encoder_write_id3tag (SF_PRIVATE *psf) +{ MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE *) psf->codec_data ; + unsigned char *id3v2_buffer ; + int i, id3v2_size ; + + if (psf->have_written) + return 0 ; + + if ((i = mpeg_l3_encoder_construct (psf))) + return i ; + + if (psf_fseek (psf, 0, SEEK_SET) != 0) + return SFE_NOT_SEEKABLE ; + + /* Safe to call multiple times. */ + id3tag_init (pmpeg->lamef) ; + + for (i = 0 ; i < SF_MAX_STRINGS ; i++) + { switch (psf->strings.data [i].type) + { case SF_STR_TITLE : + id3tag_set_title (pmpeg->lamef, psf->strings.storage + psf->strings.data [i].offset) ; + break ; + + case SF_STR_ARTIST : + id3tag_set_artist (pmpeg->lamef, psf->strings.storage + psf->strings.data [i].offset) ; + break ; + + case SF_STR_ALBUM : + id3tag_set_album (pmpeg->lamef, psf->strings.storage + psf->strings.data [i].offset) ; + break ; + + case SF_STR_DATE : + id3tag_set_year (pmpeg->lamef, psf->strings.storage + psf->strings.data [i].offset) ; + break ; + + case SF_STR_COMMENT : + id3tag_set_comment (pmpeg->lamef, psf->strings.storage + psf->strings.data [i].offset) ; + break ; + + case SF_STR_GENRE : + id3tag_set_genre (pmpeg->lamef, psf->strings.storage + psf->strings.data [i].offset) ; + break ; + + case SF_STR_TRACKNUMBER : + id3tag_set_track (pmpeg->lamef, psf->strings.storage + psf->strings.data [i].offset) ; + break ; + + default: + break ; + } ; + } ; + + /* The header in this case is the ID3v2 tag header. */ + id3v2_size = lame_get_id3v2_tag (pmpeg->lamef, 0, 0) ; + if (id3v2_size > 0) + { psf_log_printf (psf, "Writing ID3v2 header.\n") ; + if (! (id3v2_buffer = malloc (id3v2_size))) + return SFE_MALLOC_FAILED ; + lame_get_id3v2_tag (pmpeg->lamef, id3v2_buffer, id3v2_size) ; + psf_fwrite (id3v2_buffer, 1, id3v2_size, psf) ; + psf->dataoffset = id3v2_size ; + free (id3v2_buffer) ; + } ; + + return 0 ; +} + +int +mpeg_l3_encoder_set_quality (SF_PRIVATE *psf, double compression) +{ MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE *) psf->codec_data ; + int bitrate_mode ; + int bitrate ; + int ret ; + + if (compression < 0.0 || compression > 1.0) + return SF_FALSE ; + + /* + ** Save the compression setting, as we may have to re-interpret it if + ** the bitrate mode changes. + */ + pmpeg->compression = compression ; + + bitrate_mode = mpeg_l3_encoder_get_bitrate_mode (psf) ; + if (bitrate_mode == SF_BITRATE_MODE_VARIABLE) + { ret = lame_set_VBR_quality (pmpeg->lamef, compression * 10.0) ; + } + else + { /* Choose a bitrate. */ + if (psf->sf.samplerate >= 32000) + { /* MPEG-1.0, bitrates are [32,320] kbps */ + bitrate = (320.0 - (compression * (320.0 - 32.0))) ; + } + else if (psf->sf.samplerate >= 16000) + { /* MPEG-2.0, bitrates are [8,160] */ + bitrate = (160.0 - (compression * (160.0 - 8.0))) ; + } + else + { /* MPEG-2.5, bitrates are [8,64] */ + bitrate = (64.0 - (compression * (64.0 - 8.0))) ; + } + + if (bitrate_mode == SF_BITRATE_MODE_AVERAGE) + ret = lame_set_VBR_mean_bitrate_kbps (pmpeg->lamef, bitrate) ; + else + ret = lame_set_brate (pmpeg->lamef, bitrate) ; + } ; + + if (ret == LAME_OKAY) + return SF_TRUE ; + + psf_log_printf (psf, "Failed to set lame encoder quality.\n") ; + return SF_FALSE ; +} /* mpeg_l3_encoder_set_quality */ + +int +mpeg_l3_encoder_set_bitrate_mode (SF_PRIVATE *psf, int mode) +{ MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE *) psf->codec_data ; + enum vbr_mode_e vbr_mode ; + + if (pmpeg->initialized) + { psf->error = SFE_CMD_HAS_DATA ; + return SF_FALSE ; + } ; + + switch (mode) + { case SF_BITRATE_MODE_CONSTANT : vbr_mode = vbr_off ; break ; + case SF_BITRATE_MODE_AVERAGE : vbr_mode = vbr_abr ; break ; + case SF_BITRATE_MODE_VARIABLE : vbr_mode = vbr_default ; break ; + default : + psf->error = SFE_BAD_COMMAND_PARAM ; + return SF_FALSE ; + } ; + + if (lame_set_VBR (pmpeg->lamef, vbr_mode) == LAME_OKAY) + { /* Re-evaluate the compression setting. */ + return mpeg_l3_encoder_set_quality (psf, pmpeg->compression) ; + } ; + + psf_log_printf (psf, "Failed to set LAME vbr mode to %d.\n", vbr_mode) ; + return SF_FALSE ; +} /* mpeg_l3_encoder_set_bitrate_mode */ + +int +mpeg_l3_encoder_get_bitrate_mode (SF_PRIVATE *psf) +{ MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE *) psf->codec_data ; + enum vbr_mode_e vbr_mode ; + + vbr_mode = lame_get_VBR (pmpeg->lamef) ; + + if (vbr_mode == vbr_off) + return SF_BITRATE_MODE_CONSTANT ; + if (vbr_mode == vbr_abr) + return SF_BITRATE_MODE_AVERAGE ; + if (vbr_mode == vbr_default || vbr_mode < vbr_max_indicator) + return SF_BITRATE_MODE_VARIABLE ; + + /* Something is wrong. */ + psf->error = SFE_INTERNAL ; + return -1 ; +} /* mpeg_l3_encoder_get_bitrate_mode */ + + +/*----------------------------------------------------------------------------------------------- +** Private functions. +*/ + +static int +mpeg_l3_encoder_close (SF_PRIVATE *psf) +{ MPEG_L3_ENC_PRIVATE* pmpeg = (MPEG_L3_ENC_PRIVATE *) psf->codec_data ; + int ret, len ; + sf_count_t pos ; + unsigned char *buffer ; + + /* Magic number 7200 comes from a comment in lame.h */ + len = 7200 ; + if (! (buffer = malloc (len))) + return SFE_MALLOC_FAILED ; + ret = lame_encode_flush (pmpeg->lamef, buffer, len) ; + if (ret > 0) + psf_fwrite (buffer, 1, ret, psf) ; + + /* + ** Write an IDv1 trailer. The whole tag structure is always 128 bytes, so is + ** guaranteed to fit in the buffer allocated above. + */ + ret = lame_get_id3v1_tag (pmpeg->lamef, buffer, len) ; + if (ret > 0) + { psf_log_printf (psf, " Writing ID3v1 trailer.\n") ; + psf_fwrite (buffer, 1, ret, psf) ; + } ; + + /* + ** If possible, seek back and write the LAME/XING/Info headers. This + ** contains information about the whole file and a seek table, and can + ** only be written after encoding. + ** + ** If enabled, Lame wrote an empty header at the beginning of the data + ** that we now fill in. + */ + ret = lame_get_lametag_frame (pmpeg->lamef, 0, 0) ; + if (ret > 0) + { if (ret > len) + { len = ret ; + free (buffer) ; + if (! (buffer = malloc (len))) + return SFE_MALLOC_FAILED ; + } ; + psf_log_printf (psf, " Writing LAME info header at offset %d, %d bytes.\n", + psf->dataoffset, len) ; + lame_get_lametag_frame (pmpeg->lamef, buffer, len) ; + pos = psf_ftell (psf) ; + if (psf_fseek (psf, psf->dataoffset, SEEK_SET) == psf->dataoffset) + { psf_fwrite (buffer, 1, ret, psf) ; + psf_fseek (psf, pos, SEEK_SET) ; + } ; + } ; + free (buffer) ; + + free (pmpeg->block) ; + pmpeg->block = NULL ; + + if (pmpeg->lamef) + { lame_close (pmpeg->lamef) ; + pmpeg->lamef = NULL ; + } ; + + return 0 ; +} /* mpeg_l3_encoder_close */ + +static void +mpeg_l3_encoder_log_config (SF_PRIVATE *psf, lame_t lamef) +{ const char *version ; + const char *chn_mode ; + + switch (lame_get_version (lamef)) + { case 0 : version = "2" ; break ; + case 1 : version = "1" ; break ; + case 2 : version = "2.5" ; break ; + default : version = "unknown!?" ; break ; + } ; + switch (lame_get_mode (lamef)) + { case STEREO : chn_mode = "stereo" ; break ; + case JOINT_STEREO : chn_mode = "joint-stereo" ; break ; + case MONO : chn_mode = "mono" ; break ; + default : chn_mode = "unknown!?" ; break ; + } ; + psf_log_printf (psf, " MPEG Version : %s\n", version) ; + psf_log_printf (psf, " Block samples : %d\n", lame_get_framesize (lamef)) ; + psf_log_printf (psf, " Channel mode : %s\n", chn_mode) ; + psf_log_printf (psf, " Samplerate : %d\n", lame_get_out_samplerate (lamef)) ; + psf_log_printf (psf, " Encoder mode : ") ; + switch (lame_get_VBR (lamef)) + { case vbr_off : + psf_log_printf (psf, "CBR\n") ; + psf_log_printf (psf, " Bitrate : %d kbps\n", lame_get_brate (lamef)) ; + break ; + case vbr_abr : + psf_log_printf (psf, "ABR\n") ; + psf_log_printf (psf, " Mean Bitrate : %d kbps\n", lame_get_VBR_mean_bitrate_kbps (lamef)) ; + break ; + + case vbr_mt : + case vbr_default : + psf_log_printf (psf, "VBR\n") ; + psf_log_printf (psf, " Quality : %d\n", lame_get_VBR_q (lamef)) ; + break ; + + default: + psf_log_printf (psf, "Unknown!? (%d)\n", lame_get_VBR (lamef)) ; + break ; + } ; + + psf_log_printf (psf, " Encoder delay : %d\n", lame_get_encoder_delay (lamef)) ; + psf_log_printf (psf, " Write INFO header : %d\n", lame_get_bWriteVbrTag (lamef)) ; +} /* mpeg_l3_encoder_log_config */ + +static int +mpeg_l3_encoder_construct (SF_PRIVATE *psf) +{ MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE *) psf->codec_data ; + int frame_samples_per_channel ; + + if (pmpeg->initialized == SF_FALSE) + { if (lame_init_params (pmpeg->lamef) < 0) + { psf_log_printf (psf, "Failed to initialize lame encoder!\n") ; + return SFE_INTERNAL ; + } ; + + psf_log_printf (psf, "Initialized LAME encoder.\n") ; + mpeg_l3_encoder_log_config (psf, pmpeg->lamef) ; + + frame_samples_per_channel = lame_get_framesize (pmpeg->lamef) ; + + /* + * Suggested output buffer size in bytes from lame.h comment is + * 1.25 * samples + 7200 + */ + pmpeg->block_len = (frame_samples_per_channel * 4) / 3 + 7200 ; + pmpeg->frame_samples = frame_samples_per_channel * psf->sf.channels ; + + pmpeg->block = malloc (pmpeg->block_len) ; + if (!pmpeg->block) + return SFE_MALLOC_FAILED ; + + pmpeg->initialized = SF_TRUE ; + } ; + + return 0 ; +} /* mpeg_l3_encoder_construct */ + +static int +mpeg_l3_encoder_byterate (SF_PRIVATE *psf) +{ MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE *) psf->codec_data ; + int bitrate_mode ; + int byterate ; + float calculated_byterate ; + + bitrate_mode = mpeg_l3_encoder_get_bitrate_mode (psf) ; + byterate = (lame_get_brate (pmpeg->lamef) + 7) / 8 ; + + if (bitrate_mode == SF_BITRATE_MODE_VARIABLE) + { /* + ** For VBR, lame_get_brate returns the minimum bitrate, so calculate the + ** average byterate so far. + */ + calculated_byterate = psf_ftell (psf) - psf->dataoffset ; + calculated_byterate /= (float) psf->write_current ; + calculated_byterate *= (float) psf->sf.samplerate ; + + return SF_MIN (byterate, (int) calculated_byterate) ; + } + + return byterate ; +} /* mpeg_l3_encoder_byterate */ + +static sf_count_t +mpeg_l3_encode_write_short_mono (SF_PRIVATE *psf, const short *ptr, sf_count_t len) +{ MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE*) psf->codec_data ; + sf_count_t total = 0 ; + int nbytes, writecount, writen ; + + if ((psf->error = mpeg_l3_encoder_construct (psf))) + return 0 ; + + while (len) + { writecount = SF_MIN (len, (sf_count_t) pmpeg->frame_samples) ; + + nbytes = lame_encode_buffer (pmpeg->lamef, ptr + total, NULL, writecount, pmpeg->block, pmpeg->block_len) ; + if (nbytes < 0) + { psf_log_printf (psf, "lame_encode_buffer returned %d\n", nbytes) ; + break ; + } ; + + if (nbytes) + { writen = psf_fwrite (pmpeg->block, 1, nbytes, psf) ; + if (writen != nbytes) + { psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", writen, nbytes) ; + } ; + } ; + + total += writecount ; + len -= writecount ; + } ; + + return total ; +} + + +static sf_count_t +mpeg_l3_encode_write_short_stereo (SF_PRIVATE *psf, const short *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE*) psf->codec_data ; + sf_count_t total = 0 ; + int nbytes, writecount, writen ; + + if ((psf->error = mpeg_l3_encoder_construct (psf))) + return 0 ; + + const sf_count_t max_samples = SF_MIN (ARRAY_LEN (ubuf.sbuf), pmpeg->frame_samples) ; + while (len) + { writecount = SF_MIN (len, max_samples) ; + /* + * An oversight, but lame_encode_buffer_interleaved() lacks a const. + * As such, need another memcpy to not cause a warning. + */ + memcpy (ubuf.sbuf, ptr + total, writecount) ; + nbytes = lame_encode_buffer_interleaved (pmpeg->lamef, ubuf.sbuf, writecount / 2, pmpeg->block, pmpeg->block_len) ; + if (nbytes < 0) + { psf_log_printf (psf, "lame_encode_buffer returned %d\n", nbytes) ; + break ; + } ; + + if (nbytes) + { writen = psf_fwrite (pmpeg->block, 1, nbytes, psf) ; + if (writen != nbytes) + { psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", writen, nbytes) ; + } ; + } ; + + total += writecount ; + len -= writecount ; + } ; + + return total ; +} + + +static sf_count_t +mpeg_l3_encode_write_int_mono (SF_PRIVATE *psf, const int *ptr, sf_count_t len) +{ MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE*) psf->codec_data ; + sf_count_t total = 0 ; + int nbytes, writecount, writen ; + + if ((psf->error = mpeg_l3_encoder_construct (psf))) + return 0 ; + + while (len) + { writecount = SF_MIN (len, (sf_count_t) pmpeg->frame_samples) ; + + nbytes = lame_encode_buffer_int (pmpeg->lamef, ptr + total, NULL, writecount, pmpeg->block, pmpeg->block_len) ; + if (nbytes < 0) + { psf_log_printf (psf, "lame_encode_buffer returned %d\n", nbytes) ; + break ; + } ; + + if (nbytes) + { writen = psf_fwrite (pmpeg->block, 1, nbytes, psf) ; + if (writen != nbytes) + { psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", writen, nbytes) ; + } ; + } ; + + total += writecount ; + len -= writecount ; + } ; + + return total ; +} + + +static sf_count_t +mpeg_l3_encode_write_int_stereo (SF_PRIVATE *psf, const int *ptr, sf_count_t len) +{ MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE*) psf->codec_data ; + sf_count_t total = 0 ; + int nbytes, writecount, writen ; + + if ((psf->error = mpeg_l3_encoder_construct (psf))) + return 0 ; + + while (len) + { writecount = SF_MIN (len, (sf_count_t) pmpeg->frame_samples) ; + + nbytes = lame_encode_buffer_interleaved_int (pmpeg->lamef, ptr + total, writecount / 2, pmpeg->block, pmpeg->block_len) ; + if (nbytes < 0) + { psf_log_printf (psf, "lame_encode_buffer returned %d\n", nbytes) ; + break ; + } ; + + if (nbytes) + { writen = psf_fwrite (pmpeg->block, 1, nbytes, psf) ; + if (writen != nbytes) + { psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", writen, nbytes) ; + } ; + } ; + + total += writecount ; + len -= writecount ; + } ; + + return total ; +} + + +static sf_count_t +mpeg_l3_encode_write_float_mono (SF_PRIVATE *psf, const float *ptr, sf_count_t len) +{ MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE*) psf->codec_data ; + sf_count_t total = 0 ; + int nbytes, writecount, writen ; + + if ((psf->error = mpeg_l3_encoder_construct (psf))) + return 0 ; + + while (len) + { writecount = SF_MIN (len, (sf_count_t) pmpeg->frame_samples) ; + + if (psf->norm_float) + nbytes = lame_encode_buffer_ieee_float (pmpeg->lamef, ptr + total, NULL, writecount, pmpeg->block, pmpeg->block_len) ; + else + nbytes = lame_encode_buffer_float (pmpeg->lamef, ptr + total, NULL, writecount, pmpeg->block, pmpeg->block_len) ; + if (nbytes < 0) + { psf_log_printf (psf, "lame_encode_buffer returned %d\n", nbytes) ; + break ; + } ; + + if (nbytes) + { writen = psf_fwrite (pmpeg->block, 1, nbytes, psf) ; + if (writen != nbytes) + { psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", writen, nbytes) ; + } ; + } ; + + total += writecount ; + len -= writecount ; + } ; + + return total ; +} + + +static inline void +normalize_float (float *dest, const float *src, sf_count_t count, float norm_fact) +{ while (--count >= 0) + { dest [count] = src [count] * norm_fact ; + } ; +} + + +static sf_count_t +mpeg_l3_encode_write_float_stereo (SF_PRIVATE *psf, const float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE*) psf->codec_data ; + sf_count_t total = 0 ; + int nbytes, writecount, writen ; + + if ((psf->error = mpeg_l3_encoder_construct (psf))) + return 0 ; + + const sf_count_t max_samples = SF_MIN (ARRAY_LEN (ubuf.fbuf), pmpeg->frame_samples) ; + while (len) + { writecount = SF_MIN (len, max_samples) ; + + if (psf->norm_float) + nbytes = lame_encode_buffer_interleaved_ieee_float (pmpeg->lamef, ptr + total, writecount / 2, pmpeg->block, pmpeg->block_len) ; + else + { /* Lame lacks a non-normalized interleaved float write. Bummer. */ + normalize_float (ubuf.fbuf, ptr + total, writecount, 1.0 / (float) 0x8000) ; + nbytes = lame_encode_buffer_interleaved_ieee_float (pmpeg->lamef, ubuf.fbuf, writecount / 2, pmpeg->block, pmpeg->block_len) ; + } + + if (nbytes < 0) + { psf_log_printf (psf, "lame_encode_buffer returned %d\n", nbytes) ; + break ; + } ; + + if (nbytes) + { writen = psf_fwrite (pmpeg->block, 1, nbytes, psf) ; + if (writen != nbytes) + { psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", writen, nbytes) ; + } ; + } ; + + total += writecount ; + len -= writecount ; + } ; + + return total ; +} + + +static inline void +normalize_double (double *dest, const double *src, sf_count_t count, double norm_fact) +{ while (--count >= 0) + { dest [count] = src [count] * norm_fact ; + } ; +} + + +static sf_count_t +mpeg_l3_encode_write_double_mono (SF_PRIVATE *psf, const double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE*) psf->codec_data ; + sf_count_t total = 0 ; + int nbytes, writecount, writen ; + + if ((psf->error = mpeg_l3_encoder_construct (psf))) + return 0 ; + + const sf_count_t max_samples = SF_MIN (ARRAY_LEN (ubuf.dbuf), pmpeg->frame_samples) ; + while (len) + { writecount = SF_MIN (len, max_samples) ; + + if (psf->norm_double) + nbytes = lame_encode_buffer_ieee_double (pmpeg->lamef, ptr + total, NULL, writecount, pmpeg->block, pmpeg->block_len) ; + else + { /* Lame lacks non-normalized double writing */ + normalize_double (ubuf.dbuf, ptr + total, writecount, 1.0 / (double) 0x8000) ; + nbytes = lame_encode_buffer_ieee_double (pmpeg->lamef, ubuf.dbuf, NULL, writecount, pmpeg->block, pmpeg->block_len) ; + } + + if (nbytes < 0) + { psf_log_printf (psf, "lame_encode_buffer returned %d\n", nbytes) ; + break ; + } ; + + if (nbytes) + { writen = psf_fwrite (pmpeg->block, 1, nbytes, psf) ; + if (writen != nbytes) + { psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", writen, nbytes) ; + } ; + } ; + + total += writecount ; + len -= writecount ; + } ; + + return total ; +} + + +static sf_count_t +mpeg_l3_encode_write_double_stereo (SF_PRIVATE *psf, const double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE*) psf->codec_data ; + sf_count_t total = 0 ; + int nbytes, writecount, writen ; + + if ((psf->error = mpeg_l3_encoder_construct (psf))) + return 0 ; + + const sf_count_t max_samples = SF_MIN (ARRAY_LEN (ubuf.dbuf), pmpeg->frame_samples) ; + while (len) + { writecount = SF_MIN (len, max_samples) ; + + if (psf->norm_double) + nbytes = lame_encode_buffer_interleaved_ieee_double (pmpeg->lamef, ptr + total, writecount / 2, pmpeg->block, pmpeg->block_len) ; + else + { /* Lame lacks interleaved non-normalized double writing */ + normalize_double (ubuf.dbuf, ptr + total, writecount, 1.0 / (double) 0x8000) ; + nbytes = lame_encode_buffer_interleaved_ieee_double (pmpeg->lamef, ubuf.dbuf, writecount / 2, pmpeg->block, pmpeg->block_len) ; + } + + if (nbytes < 0) + { psf_log_printf (psf, "lame_encode_buffer returned %d\n", nbytes) ; + break ; + } ; + + if (nbytes) + { writen = psf_fwrite (pmpeg->block, 1, nbytes, psf) ; + if (writen != nbytes) + { psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", writen, nbytes) ; + } ; + } ; + + total += writecount ; + len -= writecount ; + } ; + + return total ; +} + +#else /* HAVE_MPEG */ + +int +mpeg_l3_encoder_init (SF_PRIVATE *psf, int UNUSED (vbr)) +{ psf_log_printf (psf, "This version of libsndfile was compiled without MPEG Layer 3 encoding support.\n") ; + return SFE_UNIMPLEMENTED ; +} /* mpeg_l3_encoder_init */ + +#endif diff --git a/extern/libsndfile-modified/src/ms_adpcm.c b/extern/libsndfile-modified/src/ms_adpcm.c new file mode 100644 index 000000000..0e05181ab --- /dev/null +++ b/extern/libsndfile-modified/src/ms_adpcm.c @@ -0,0 +1,857 @@ +/* +** Copyright (C) 1999-2017 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" +#include "wavlike.h" + + +typedef struct +{ int channels, blocksize, samplesperblock, blocks, dataremaining ; + int blockcount ; + int sync_error ; + sf_count_t samplecount ; + short *samples ; + unsigned char *block ; + short dummydata [] ; /* ISO C99 struct flexible array. */ +} MSADPCM_PRIVATE ; + +/*============================================================================================ +** MS ADPCM static data and functions. +*/ + +static int AdaptationTable [] = +{ 230, 230, 230, 230, 307, 409, 512, 614, + 768, 614, 512, 409, 307, 230, 230, 230 +} ; + +/* TODO : The first 7 coef's are are always hardcode and must + appear in the actual WAVE file. They should be read in + in case a sound program added extras to the list. */ + +static int AdaptCoeff1 [WAVLIKE_MSADPCM_ADAPT_COEFF_COUNT] = +{ 256, 512, 0, 192, 240, 460, 392 +} ; + +static int AdaptCoeff2 [WAVLIKE_MSADPCM_ADAPT_COEFF_COUNT] = +{ 0, -256, 0, 64, 0, -208, -232 +} ; + +/*============================================================================================ +** MS ADPCM Block Layout. +** ====================== +** Block is usually 256, 512 or 1024 bytes depending on sample rate. +** For a mono file, the block is laid out as follows: +** byte purpose +** 0 block predictor [0..6] +** 1,2 initial idelta (positive) +** 3,4 sample 1 +** 5,6 sample 0 +** 7..n packed bytecodes +** +** For a stereo file, the block is laid out as follows: +** byte purpose +** 0 block predictor [0..6] for left channel +** 1 block predictor [0..6] for right channel +** 2,3 initial idelta (positive) for left channel +** 4,5 initial idelta (positive) for right channel +** 6,7 sample 1 for left channel +** 8,9 sample 1 for right channel +** 10,11 sample 0 for left channel +** 12,13 sample 0 for right channel +** 14..n packed bytecodes +*/ + +/*============================================================================================ +** Static functions. +*/ + +static int msadpcm_decode_block (SF_PRIVATE *psf, MSADPCM_PRIVATE *pms) ; +static sf_count_t msadpcm_read_block (SF_PRIVATE *psf, MSADPCM_PRIVATE *pms, short *ptr, int len) ; + +static int msadpcm_encode_block (SF_PRIVATE *psf, MSADPCM_PRIVATE *pms) ; +static sf_count_t msadpcm_write_block (SF_PRIVATE *psf, MSADPCM_PRIVATE *pms, const short *ptr, int len) ; + +static sf_count_t msadpcm_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; +static sf_count_t msadpcm_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; +static sf_count_t msadpcm_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; +static sf_count_t msadpcm_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; + +static sf_count_t msadpcm_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; +static sf_count_t msadpcm_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; +static sf_count_t msadpcm_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; +static sf_count_t msadpcm_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; + +static sf_count_t msadpcm_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ; +static int msadpcm_close (SF_PRIVATE *psf) ; + +static void choose_predictor (unsigned int channels, short *data, int *bpred, int *idelta) ; + +/*============================================================================================ +** MS ADPCM Read Functions. +*/ + +int +wavlike_msadpcm_init (SF_PRIVATE *psf, int blockalign, int samplesperblock) +{ MSADPCM_PRIVATE *pms ; + unsigned int pmssize ; + int count ; + + if (psf->codec_data != NULL) + { psf_log_printf (psf, "*** psf->codec_data is not NULL.\n") ; + return SFE_INTERNAL ; + } ; + + if (psf->file.mode == SFM_WRITE) + samplesperblock = 2 + 2 * (blockalign - 7 * psf->sf.channels) / psf->sf.channels ; + + /* There's 7 samples per channel in the preamble of each block */ + if (samplesperblock < 7 * psf->sf.channels) + { psf_log_printf (psf, "*** Error samplesperblock (%d) should be >= %d.\n", samplesperblock, 7 * psf->sf.channels) ; + return SFE_INTERNAL ; + } ; + + if (2 * blockalign < samplesperblock * psf->sf.channels) + { psf_log_printf (psf, "*** Error blockalign (%d) should be >= %d.\n", blockalign, samplesperblock * psf->sf.channels / 2) ; + return SFE_INTERNAL ; + } ; + + pmssize = sizeof (MSADPCM_PRIVATE) + blockalign + 3 * psf->sf.channels * samplesperblock ; + + if (! (psf->codec_data = calloc (1, pmssize))) + return SFE_MALLOC_FAILED ; + pms = (MSADPCM_PRIVATE*) psf->codec_data ; + + pms->sync_error = 0 ; + pms->samples = pms->dummydata ; + pms->block = (unsigned char*) (pms->dummydata + psf->sf.channels * samplesperblock) ; + + pms->channels = psf->sf.channels ; + pms->blocksize = blockalign ; + pms->samplesperblock = samplesperblock ; + + if (pms->blocksize <= 0) + { psf_log_printf (psf, "*** Error : pms->blocksize should be > 0.\n") ; + return SFE_INTERNAL ; + } ; + + if (psf->file.mode == SFM_READ) + { pms->dataremaining = psf->datalength ; + + if (psf->datalength % pms->blocksize) + pms->blocks = psf->datalength / pms->blocksize + 1 ; + else + pms->blocks = psf->datalength / pms->blocksize ; + + count = 2 * (pms->blocksize - 6 * pms->channels) / pms->channels ; + if (pms->samplesperblock != count) + { psf_log_printf (psf, "*** Error : samplesperblock should be %d.\n", count) ; + return SFE_INTERNAL ; + } ; + + psf->sf.frames = (psf->datalength / pms->blocksize) * pms->samplesperblock ; + + msadpcm_decode_block (psf, pms) ; + + psf->read_short = msadpcm_read_s ; + psf->read_int = msadpcm_read_i ; + psf->read_float = msadpcm_read_f ; + psf->read_double = msadpcm_read_d ; + } ; + + if (psf->file.mode == SFM_WRITE) + { pms->samples = pms->dummydata ; + + pms->samplecount = 0 ; + + psf->write_short = msadpcm_write_s ; + psf->write_int = msadpcm_write_i ; + psf->write_float = msadpcm_write_f ; + psf->write_double = msadpcm_write_d ; + } ; + + psf->codec_close = msadpcm_close ; + psf->seek = msadpcm_seek ; + + return 0 ; +} /* wavlike_msadpcm_init */ + + +static inline short +msadpcm_get_bpred (SF_PRIVATE *psf, MSADPCM_PRIVATE *pms, unsigned char value) +{ if (value >= WAVLIKE_MSADPCM_ADAPT_COEFF_COUNT) + { if (pms->sync_error == 0) + { pms->sync_error = 1 ; + psf_log_printf (psf, "MS ADPCM synchronisation error (%u should be < %u).\n", value, WAVLIKE_MSADPCM_ADAPT_COEFF_COUNT) ; + } ; + return 0 ; + } ; + return value ; +} /* msadpcm_get_bpred */ + + +static int +msadpcm_decode_block (SF_PRIVATE *psf, MSADPCM_PRIVATE *pms) +{ int chan, k, blockindx, sampleindx ; + short bytecode, bpred [2], chan_idelta [2] ; + + int predict ; + int current ; + int idelta ; + + pms->blockcount ++ ; + pms->samplecount = 0 ; + + if (pms->blockcount > pms->blocks) + { memset (pms->samples, 0, pms->samplesperblock * pms->channels) ; + return 1 ; + } ; + + if ((k = (int) psf_fread (pms->block, 1, pms->blocksize, psf)) != pms->blocksize) + { psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, pms->blocksize) ; + if (k <= 0) + return 1 ; + } ; + + /* Read and check the block header. */ + + if (pms->channels == 1) + { bpred [0] = msadpcm_get_bpred (psf, pms, pms->block [0]) ; + + chan_idelta [0] = pms->block [1] | (pms->block [2] << 8) ; + chan_idelta [1] = 0 ; + + pms->samples [1] = pms->block [3] | (pms->block [4] << 8) ; + pms->samples [0] = pms->block [5] | (pms->block [6] << 8) ; + blockindx = 7 ; + } + else + { bpred [0] = msadpcm_get_bpred (psf, pms, pms->block [0]) ; + bpred [1] = msadpcm_get_bpred (psf, pms, pms->block [1]) ; + + chan_idelta [0] = pms->block [2] | (pms->block [3] << 8) ; + chan_idelta [1] = pms->block [4] | (pms->block [5] << 8) ; + + pms->samples [2] = pms->block [6] | (pms->block [7] << 8) ; + pms->samples [3] = pms->block [8] | (pms->block [9] << 8) ; + + pms->samples [0] = pms->block [10] | (pms->block [11] << 8) ; + pms->samples [1] = pms->block [12] | (pms->block [13] << 8) ; + + blockindx = 14 ; + } ; + + /*-------------------------------------------------------- + This was left over from a time when calculations were done + as ints rather than shorts. Keep this around as a reminder + in case I ever find a file which decodes incorrectly. + + if (chan_idelta [0] & 0x8000) + chan_idelta [0] -= 0x10000 ; + if (chan_idelta [1] & 0x8000) + chan_idelta [1] -= 0x10000 ; + --------------------------------------------------------*/ + + /* Pull apart the packed 4 bit samples and store them in their + ** correct sample positions. + */ + + sampleindx = 2 * pms->channels ; + while (blockindx < pms->blocksize) + { bytecode = pms->block [blockindx++] ; + pms->samples [sampleindx++] = (bytecode >> 4) & 0x0F ; + pms->samples [sampleindx++] = bytecode & 0x0F ; + } ; + + /* Decode the encoded 4 bit samples. */ + + for (k = 2 * pms->channels ; k < (pms->samplesperblock * pms->channels) ; k ++) + { chan = (pms->channels > 1) ? (k % 2) : 0 ; + + bytecode = pms->samples [k] & 0xF ; + + /* Compute next Adaptive Scale Factor (ASF) */ + idelta = chan_idelta [chan] ; + chan_idelta [chan] = (AdaptationTable [bytecode] * idelta) >> 8 ; /* => / 256 => FIXED_POINT_ADAPTATION_BASE == 256 */ + if (chan_idelta [chan] < 16) + chan_idelta [chan] = 16 ; + if (bytecode & 0x8) + bytecode -= 0x10 ; + + predict = ((pms->samples [k - pms->channels] * AdaptCoeff1 [bpred [chan]]) + + (pms->samples [k - 2 * pms->channels] * AdaptCoeff2 [bpred [chan]])) >> 8 ; /* => / 256 => FIXED_POINT_COEFF_BASE == 256 */ + current = (bytecode * idelta) + predict ; + + if (current > 32767) + current = 32767 ; + else if (current < -32768) + current = -32768 ; + + pms->samples [k] = current ; + } ; + + return 0 ; +} /* msadpcm_decode_block */ + +static sf_count_t +msadpcm_read_block (SF_PRIVATE *psf, MSADPCM_PRIVATE *pms, short *ptr, int len) +{ int count, total = 0, indx = 0 ; + + while (indx < len) + { if (pms->blockcount >= pms->blocks && pms->samplecount >= pms->samplesperblock) + { memset (&(ptr [indx]), 0, (size_t) ((len - indx) * sizeof (short))) ; + return total ; + } ; + + if (pms->samplecount >= pms->samplesperblock) + if (msadpcm_decode_block (psf, pms) != 0) + return total ; + + count = (pms->samplesperblock - pms->samplecount) * pms->channels ; + count = (len - indx > count) ? count : len - indx ; + + memcpy (&(ptr [indx]), &(pms->samples [pms->samplecount * pms->channels]), count * sizeof (short)) ; + indx += count ; + pms->samplecount += count / pms->channels ; + total = indx ; + } ; + + return total ; +} /* msadpcm_read_block */ + +static sf_count_t +msadpcm_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) +{ MSADPCM_PRIVATE *pms ; + int readcount, count ; + sf_count_t total = 0 ; + + if (! psf->codec_data) + return 0 ; + pms = (MSADPCM_PRIVATE*) psf->codec_data ; + + while (len > 0) + { readcount = (len > 0x10000000) ? 0x10000000 : (int) len ; + + if ((count = (int) msadpcm_read_block (psf, pms, ptr, readcount)) <= 0) + return -1 ; + + total += count ; + len -= count ; + if (count != readcount) + break ; + } ; + + return total ; +} /* msadpcm_read_s */ + +static sf_count_t +msadpcm_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) +{ MSADPCM_PRIVATE *pms ; + BUF_UNION ubuf ; + short *sptr ; + int k, bufferlen, readcount = 0, count ; + sf_count_t total = 0 ; + + if (! psf->codec_data) + return 0 ; + pms = (MSADPCM_PRIVATE*) psf->codec_data ; + + sptr = ubuf.sbuf ; + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + while (len > 0) + { readcount = (len >= bufferlen) ? bufferlen : (int) len ; + + if ((count = (int) msadpcm_read_block (psf, pms, sptr, readcount)) <= 0) + return -1 ; + + for (k = 0 ; k < readcount ; k++) + ptr [total + k] = arith_shift_left (sptr [k], 16) ; + total += count ; + len -= readcount ; + if (count != readcount) + break ; + } ; + return total ; +} /* msadpcm_read_i */ + +static sf_count_t +msadpcm_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) +{ MSADPCM_PRIVATE *pms ; + BUF_UNION ubuf ; + short *sptr ; + int k, bufferlen, readcount = 0, count ; + sf_count_t total = 0 ; + float normfact ; + + if (! psf->codec_data) + return 0 ; + pms = (MSADPCM_PRIVATE*) psf->codec_data ; + + normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x8000) : 1.0 ; + sptr = ubuf.sbuf ; + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + while (len > 0) + { readcount = (len >= bufferlen) ? bufferlen : (int) len ; + + if ((count = (int) msadpcm_read_block (psf, pms, sptr, readcount)) <= 0) + return -1 ; + + for (k = 0 ; k < readcount ; k++) + ptr [total + k] = normfact * (float) (sptr [k]) ; + total += count ; + len -= readcount ; + if (count != readcount) + break ; + } ; + return total ; +} /* msadpcm_read_f */ + +static sf_count_t +msadpcm_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) +{ MSADPCM_PRIVATE *pms ; + BUF_UNION ubuf ; + short *sptr ; + int k, bufferlen, readcount = 0, count ; + sf_count_t total = 0 ; + double normfact ; + + if (! psf->codec_data) + return 0 ; + pms = (MSADPCM_PRIVATE*) psf->codec_data ; + + normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x8000) : 1.0 ; + sptr = ubuf.sbuf ; + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + while (len > 0) + { readcount = (len >= bufferlen) ? bufferlen : (int) len ; + + if ((count = (int) msadpcm_read_block (psf, pms, sptr, readcount)) <= 0) + return -1 ; + + for (k = 0 ; k < readcount ; k++) + ptr [total + k] = normfact * (double) (sptr [k]) ; + total += count ; + len -= readcount ; + if (count != readcount) + break ; + } ; + + return total ; +} /* msadpcm_read_d */ + +static sf_count_t +msadpcm_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) +{ MSADPCM_PRIVATE *pms ; + int newblock, newsample ; + + if (! psf->codec_data) + return 0 ; + pms = (MSADPCM_PRIVATE*) psf->codec_data ; + + if (psf->datalength < 0 || psf->dataoffset < 0) + { psf->error = SFE_BAD_SEEK ; + return PSF_SEEK_ERROR ; + } ; + + if (offset == 0) + { psf_fseek (psf, psf->dataoffset, SEEK_SET) ; + pms->blockcount = 0 ; + msadpcm_decode_block (psf, pms) ; + pms->samplecount = 0 ; + return 0 ; + } ; + + if (offset < 0 || offset > pms->blocks * pms->samplesperblock) + { psf->error = SFE_BAD_SEEK ; + return PSF_SEEK_ERROR ; + } ; + + newblock = offset / pms->samplesperblock ; + newsample = offset % pms->samplesperblock ; + + if (mode == SFM_READ) + { psf_fseek (psf, psf->dataoffset + newblock * pms->blocksize, SEEK_SET) ; + pms->blockcount = newblock ; + msadpcm_decode_block (psf, pms) ; + pms->samplecount = newsample ; + } + else + { /* What to do about write??? */ + psf->error = SFE_BAD_SEEK ; + return PSF_SEEK_ERROR ; + } ; + + return newblock * pms->samplesperblock + newsample ; +} /* msadpcm_seek */ + +/*========================================================================================== +** MS ADPCM Write Functions. +*/ + +void +wavlike_msadpcm_write_adapt_coeffs (SF_PRIVATE *psf) +{ int k ; + + for (k = 0 ; k < WAVLIKE_MSADPCM_ADAPT_COEFF_COUNT ; k++) + psf_binheader_writef (psf, "22", BHW2 (AdaptCoeff1 [k]), BHW2 (AdaptCoeff2 [k])) ; +} /* wavlike_msadpcm_write_adapt_coeffs */ + +/*========================================================================================== +*/ + +static int +msadpcm_encode_block (SF_PRIVATE *psf, MSADPCM_PRIVATE *pms) +{ unsigned int blockindx ; + unsigned char byte ; + int chan, k, predict, bpred [2] = { 0 }, idelta [2] = { 0 }, + errordelta, newsamp ; + + choose_predictor (pms->channels, pms->samples, bpred, idelta) ; + + /* Write the block header. */ + + if (pms->channels == 1) + { pms->block [0] = bpred [0] ; + pms->block [1] = idelta [0] & 0xFF ; + pms->block [2] = idelta [0] >> 8 ; + pms->block [3] = pms->samples [1] & 0xFF ; + pms->block [4] = pms->samples [1] >> 8 ; + pms->block [5] = pms->samples [0] & 0xFF ; + pms->block [6] = pms->samples [0] >> 8 ; + + blockindx = 7 ; + byte = 0 ; + + /* Encode the samples as 4 bit. */ + + for (k = 2 ; k < pms->samplesperblock ; k++) + { predict = (pms->samples [k-1] * AdaptCoeff1 [bpred [0]] + pms->samples [k-2] * AdaptCoeff2 [bpred [0]]) >> 8 ; + errordelta = (pms->samples [k] - predict) / idelta [0] ; + if (errordelta < -8) + errordelta = -8 ; + else if (errordelta > 7) + errordelta = 7 ; + newsamp = predict + (idelta [0] * errordelta) ; + if (newsamp > 32767) + newsamp = 32767 ; + else if (newsamp < -32768) + newsamp = -32768 ; + if (errordelta < 0) + errordelta += 0x10 ; + + byte = (byte << 4) | (errordelta & 0xF) ; + if (k % 2) + { pms->block [blockindx++] = byte ; + byte = 0 ; + } ; + + idelta [0] = (idelta [0] * AdaptationTable [errordelta]) >> 8 ; + if (idelta [0] < 16) + idelta [0] = 16 ; + pms->samples [k] = newsamp ; + } ; + } + else + { /* Stereo file. */ + pms->block [0] = bpred [0] ; + pms->block [1] = bpred [1] ; + + pms->block [2] = idelta [0] & 0xFF ; + pms->block [3] = idelta [0] >> 8 ; + pms->block [4] = idelta [1] & 0xFF ; + pms->block [5] = idelta [1] >> 8 ; + + pms->block [6] = pms->samples [2] & 0xFF ; + pms->block [7] = pms->samples [2] >> 8 ; + pms->block [8] = pms->samples [3] & 0xFF ; + pms->block [9] = pms->samples [3] >> 8 ; + + pms->block [10] = pms->samples [0] & 0xFF ; + pms->block [11] = pms->samples [0] >> 8 ; + pms->block [12] = pms->samples [1] & 0xFF ; + pms->block [13] = pms->samples [1] >> 8 ; + + blockindx = 14 ; + byte = 0 ; + chan = 1 ; + + for (k = 4 ; k < 2 * pms->samplesperblock ; k++) + { chan = k & 1 ; + + predict = (pms->samples [k-2] * AdaptCoeff1 [bpred [chan]] + pms->samples [k-4] * AdaptCoeff2 [bpred [chan]]) >> 8 ; + errordelta = (pms->samples [k] - predict) / idelta [chan] ; + + + if (errordelta < -8) + errordelta = -8 ; + else if (errordelta > 7) + errordelta = 7 ; + newsamp = predict + (idelta [chan] * errordelta) ; + if (newsamp > 32767) + newsamp = 32767 ; + else if (newsamp < -32768) + newsamp = -32768 ; + if (errordelta < 0) + errordelta += 0x10 ; + + byte = (byte << 4) | (errordelta & 0xF) ; + + if (chan) + { pms->block [blockindx++] = byte ; + byte = 0 ; + } ; + + idelta [chan] = (idelta [chan] * AdaptationTable [errordelta]) >> 8 ; + if (idelta [chan] < 16) + idelta [chan] = 16 ; + pms->samples [k] = newsamp ; + } ; + } ; + + /* Write the block to disk. */ + + if ((k = (int) psf_fwrite (pms->block, 1, pms->blocksize, psf)) != pms->blocksize) + psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", k, pms->blocksize) ; + + memset (pms->samples, 0, pms->samplesperblock * sizeof (short)) ; + + pms->blockcount ++ ; + pms->samplecount = 0 ; + + return 1 ; +} /* msadpcm_encode_block */ + +static sf_count_t +msadpcm_write_block (SF_PRIVATE *psf, MSADPCM_PRIVATE *pms, const short *ptr, int len) +{ int count, total = 0, indx = 0 ; + + while (indx < len) + { count = (pms->samplesperblock - pms->samplecount) * pms->channels ; + + if (count > len - indx) + count = len - indx ; + + memcpy (&(pms->samples [pms->samplecount * pms->channels]), &(ptr [total]), count * sizeof (short)) ; + indx += count ; + pms->samplecount += count / pms->channels ; + total = indx ; + + if (pms->samplecount >= pms->samplesperblock) + msadpcm_encode_block (psf, pms) ; + } ; + + return total ; +} /* msadpcm_write_block */ + +static sf_count_t +msadpcm_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) +{ MSADPCM_PRIVATE *pms ; + int writecount, count ; + sf_count_t total = 0 ; + + if (! psf->codec_data) + return 0 ; + pms = (MSADPCM_PRIVATE*) psf->codec_data ; + + while (len > 0) + { writecount = (len > 0x10000000) ? 0x10000000 : (int) len ; + + count = (int) msadpcm_write_block (psf, pms, ptr, writecount) ; + + total += count ; + len -= count ; + if (count != writecount) + break ; + } ; + + return total ; +} /* msadpcm_write_s */ + +static sf_count_t +msadpcm_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) +{ MSADPCM_PRIVATE *pms ; + BUF_UNION ubuf ; + short *sptr ; + int k, bufferlen, writecount, count ; + sf_count_t total = 0 ; + + if (! psf->codec_data) + return 0 ; + pms = (MSADPCM_PRIVATE*) psf->codec_data ; + + sptr = ubuf.sbuf ; + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + while (len > 0) + { writecount = (len >= bufferlen) ? bufferlen : (int) len ; + for (k = 0 ; k < writecount ; k++) + sptr [k] = ptr [total + k] >> 16 ; + count = (int) msadpcm_write_block (psf, pms, sptr, writecount) ; + total += count ; + len -= writecount ; + if (count != writecount) + break ; + } ; + return total ; +} /* msadpcm_write_i */ + +static sf_count_t +msadpcm_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) +{ MSADPCM_PRIVATE *pms ; + BUF_UNION ubuf ; + short *sptr ; + int k, bufferlen, writecount, count ; + sf_count_t total = 0 ; + float normfact ; + + if (! psf->codec_data) + return 0 ; + pms = (MSADPCM_PRIVATE*) psf->codec_data ; + + normfact = (psf->norm_float == SF_TRUE) ? (1.0 * 0x7FFF) : 1.0 ; + + sptr = ubuf.sbuf ; + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + while (len > 0) + { writecount = (len >= bufferlen) ? bufferlen : (int) len ; + for (k = 0 ; k < writecount ; k++) + sptr [k] = psf_lrintf (normfact * ptr [total + k]) ; + count = (int) msadpcm_write_block (psf, pms, sptr, writecount) ; + total += count ; + len -= writecount ; + if (count != writecount) + break ; + } ; + return total ; +} /* msadpcm_write_f */ + +static sf_count_t +msadpcm_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) +{ MSADPCM_PRIVATE *pms ; + BUF_UNION ubuf ; + short *sptr ; + int k, bufferlen, writecount, count ; + sf_count_t total = 0 ; + double normfact ; + + normfact = (psf->norm_double == SF_TRUE) ? (1.0 * 0x7FFF) : 1.0 ; + + if (! psf->codec_data) + return 0 ; + pms = (MSADPCM_PRIVATE*) psf->codec_data ; + + sptr = ubuf.sbuf ; + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + while (len > 0) + { writecount = (len >= bufferlen) ? bufferlen : (int) len ; + for (k = 0 ; k < writecount ; k++) + sptr [k] = psf_lrint (normfact * ptr [total + k]) ; + count = (int) msadpcm_write_block (psf, pms, sptr, writecount) ; + total += count ; + len -= writecount ; + if (count != writecount) + break ; + } ; + return total ; +} /* msadpcm_write_d */ + +/*======================================================================================== +*/ + +static int +msadpcm_close (SF_PRIVATE *psf) +{ MSADPCM_PRIVATE *pms ; + + pms = (MSADPCM_PRIVATE*) psf->codec_data ; + + if (psf->file.mode == SFM_WRITE) + { /* Now we know static int for certain the length of the file we can + ** re-write the header. + */ + + if (pms->samplecount && pms->samplecount < pms->samplesperblock) + msadpcm_encode_block (psf, pms) ; + } ; + + return 0 ; +} /* msadpcm_close */ + +/*======================================================================================== +** Static functions. +*/ + +/*---------------------------------------------------------------------------------------- +** Choosing the block predictor. +** Each block requires a predictor and an idelta for each channel. +** The predictor is in the range [0..6] which is an indx into the two AdaptCoeff tables. +** The predictor is chosen by trying all of the possible predictors on a small set of +** samples at the beginning of the block. The predictor with the smallest average +** abs (idelta) is chosen as the best predictor for this block. +** The value of idelta is chosen to to give a 4 bit code value of +/- 4 (approx. half the +** max. code value). If the average abs (idelta) is zero, the sixth predictor is chosen. +** If the value of idelta is less then 16 it is set to 16. +** +** Microsoft uses an IDELTA_COUNT (number of sample pairs used to choose best predictor) +** value of 3. The best possible results would be obtained by using all the samples to +** choose the predictor. +*/ + +#define IDELTA_COUNT 3 + +static void +choose_predictor (unsigned int channels, short *data, int *block_pred, int *idelta) +{ unsigned int chan, k, bpred, idelta_sum, best_bpred, best_idelta ; + + for (chan = 0 ; chan < channels ; chan++) + { best_bpred = best_idelta = 0 ; + + for (bpred = 0 ; bpred < 7 ; bpred++) + { idelta_sum = 0 ; + for (k = 2 ; k < 2 + IDELTA_COUNT ; k++) + idelta_sum += abs (data [k * channels] - ((data [(k - 1) * channels] * AdaptCoeff1 [bpred] + data [(k - 2) * channels] * AdaptCoeff2 [bpred]) >> 8)) ; + idelta_sum /= (4 * IDELTA_COUNT) ; + + if (bpred == 0 || idelta_sum < best_idelta) + { best_bpred = bpred ; + best_idelta = idelta_sum ; + } ; + + if (! idelta_sum) + { best_bpred = bpred ; + best_idelta = 16 ; + break ; + } ; + + } ; /* for bpred ... */ + if (best_idelta < 16) + best_idelta = 16 ; + + block_pred [chan] = best_bpred ; + idelta [chan] = best_idelta ; + } ; + + return ; +} /* choose_predictor */ + diff --git a/extern/libsndfile-modified/src/new.c b/extern/libsndfile-modified/src/new.c new file mode 100644 index 000000000..23f3087f1 --- /dev/null +++ b/extern/libsndfile-modified/src/new.c @@ -0,0 +1,116 @@ +/* +** Copyright (C) 2002-2011 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + +#if (ENABLE_EXPERIMENTAL_CODE == 0) + +int +new_open (SF_PRIVATE *psf) +{ if (psf) + return SFE_UNIMPLEMENTED ; + return (psf && 0) ; +} /* new_open */ + +#else + +/*------------------------------------------------------------------------------ +** Macros to handle big/little endian issues. +*/ + +/*------------------------------------------------------------------------------ +** Typedefs. +*/ + +/*------------------------------------------------------------------------------ +** Private static functions. +*/ + +static int new_read_header (SF_PRIVATE *psf) ; + +/*------------------------------------------------------------------------------ +** Public function. +*/ + +int +new_open (SF_PRIVATE *psf) +{ int subformat, error = 0 ; + + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + return SFE_UNIMPLEMENTED ; + + if ((error = new_read_header (psf))) + return error ; + + if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_WVE) + return SFE_BAD_OPEN_FORMAT ; + + subformat = SF_CODEC (psf->sf.format) ; + + return error ; +} /* new_open */ + +/*------------------------------------------------------------------------------ +*/ + +static int +new_read_header (SF_PRIVATE *psf) +{ int marker ; + + /* Set position to start of file to begin reading header. */ + psf_binheader_readf (psf, "pm", 0, &marker) ; + if (marker != ALAW_MARKER) + return SFE_WVE_NOT_WVE ; + + psf_binheader_readf (psf, "m", &marker) ; + if (marker != SOUN_MARKER) + return SFE_WVE_NOT_WVE ; + + psf_binheader_readf (psf, "m", &marker) ; + if (marker != DFIL_MARKER) + return SFE_WVE_NOT_WVE ; + + psf_log_printf (psf, "Read only : Psion Alaw\n" + " Sample Rate : 8000\n" + " Channels : 1\n" + " Encoding : A-law\n") ; + + psf->dataoffset = 0x20 ; + psf->datalength = psf->filelength - psf->dataoffset ; + + psf->sf.format = SF_FORMAT_WVE | SF_FORMAT_ALAW ; + psf->sf.samplerate = 8000 ; + psf->sf.frames = psf->datalength ; + psf->sf.channels = 1 ; + + return alaw_init (psf) ; +} /* new_read_header */ + +/*------------------------------------------------------------------------------ +*/ + +#endif diff --git a/extern/libsndfile-modified/src/nist.c b/extern/libsndfile-modified/src/nist.c new file mode 100644 index 000000000..657c4d41f --- /dev/null +++ b/extern/libsndfile-modified/src/nist.c @@ -0,0 +1,372 @@ +/* +** Copyright (C) 1999-2017 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/* +** Some of the information used to read NIST files was gleaned from +** reading the code of Bill Schottstaedt's sndlib library +** ftp://ccrma-ftp.stanford.edu/pub/Lisp/sndlib.tar.gz +** However, no code from that package was used. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + +/*------------------------------------------------------------------------------ +*/ + +#define NIST_HEADER_LENGTH 1024 + +/*------------------------------------------------------------------------------ +** Private static functions. +*/ + +static int nist_close (SF_PRIVATE *psf) ; +static int nist_write_header (SF_PRIVATE *psf, int calc_length) ; +static int nist_read_header (SF_PRIVATE *psf) ; + +/*------------------------------------------------------------------------------ +*/ + +int +nist_open (SF_PRIVATE *psf) +{ int error ; + + if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0)) + { if ((error = nist_read_header (psf))) + return error ; + } ; + + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { if (psf->is_pipe) + return SFE_NO_PIPE_WRITE ; + + if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_NIST) + return SFE_BAD_OPEN_FORMAT ; + + psf->endian = SF_ENDIAN (psf->sf.format) ; + if (psf->endian == 0 || psf->endian == SF_ENDIAN_CPU) + psf->endian = (CPU_IS_BIG_ENDIAN) ? SF_ENDIAN_BIG : SF_ENDIAN_LITTLE ; + + psf->blockwidth = psf->bytewidth * psf->sf.channels ; + psf->sf.frames = 0 ; + + if ((error = nist_write_header (psf, SF_FALSE))) + return error ; + + psf->write_header = nist_write_header ; + } ; + + psf->container_close = nist_close ; + + switch (SF_CODEC (psf->sf.format)) + { case SF_FORMAT_PCM_S8 : + error = pcm_init (psf) ; + break ; + + case SF_FORMAT_PCM_16 : + case SF_FORMAT_PCM_24 : + case SF_FORMAT_PCM_32 : + error = pcm_init (psf) ; + break ; + + case SF_FORMAT_ULAW : + error = ulaw_init (psf) ; + break ; + + case SF_FORMAT_ALAW : + error = alaw_init (psf) ; + break ; + + default : error = SFE_UNIMPLEMENTED ; + break ; + } ; + + return error ; +} /* nist_open */ + +/*------------------------------------------------------------------------------ +*/ + +static char bad_header [] = +{ 'N', 'I', 'S', 'T', '_', '1', 'A', 0x0d, 0x0a, + ' ', ' ', ' ', '1', '0', '2', '4', 0x0d, 0x0a, + 0 +} ; + + static int +nist_read_header (SF_PRIVATE *psf) +{ char psf_header [NIST_HEADER_LENGTH + 2] ; + int bitwidth = 0, count, encoding ; + unsigned bytes = 0 ; + char str [64], *cptr ; + long samples ; + + /* Go to start of file and read in the whole header. */ + psf_binheader_readf (psf, "pb", 0, psf_header, NIST_HEADER_LENGTH) ; + + /* Header is a string, so make sure it is null terminated. */ + psf_header [NIST_HEADER_LENGTH] = 0 ; + + /* Now trim the header after the end marker. */ + if ((cptr = strstr (psf_header, "end_head"))) + { cptr += strlen ("end_head") + 1 ; + cptr [0] = 0 ; + } ; + + if (strstr (psf_header, bad_header) == psf_header) + return SFE_NIST_CRLF_CONVERISON ; + + /* Make sure its a NIST file. */ + if (strstr (psf_header, "NIST_1A\n") != psf_header) + { psf_log_printf (psf, "Not a NIST file.\n") ; + return SFE_NIST_BAD_HEADER ; + } ; + + if (sscanf (psf_header, "NIST_1A\n%d\n", &count) == 1) + psf->dataoffset = count ; + else + { psf_log_printf (psf, "*** Suspicious header length.\n") ; + psf->dataoffset = NIST_HEADER_LENGTH ; + } ; + + /* Determine sample encoding, start by assuming PCM. */ + encoding = SF_FORMAT_PCM_U8 ; + if ((cptr = strstr (psf_header, "sample_coding -s"))) + { sscanf (cptr, "sample_coding -s%d %63s", &count, str) ; + + if (strcmp (str, "pcm") == 0) + { /* Correct this later when we find out the bitwidth. */ + encoding = SF_FORMAT_PCM_U8 ; + } + else if (strcmp (str, "alaw") == 0) + encoding = SF_FORMAT_ALAW ; + else if ((strcmp (str, "ulaw") == 0) || (strcmp (str, "mu-law") == 0)) + encoding = SF_FORMAT_ULAW ; + else + { psf_log_printf (psf, "*** Unknown encoding : %s\n", str) ; + encoding = 0 ; + } ; + } ; + + if ((cptr = strstr (psf_header, "channel_count -i ")) != NULL) + sscanf (cptr, "channel_count -i %d", &(psf->sf.channels)) ; + + if ((cptr = strstr (psf_header, "sample_rate -i ")) != NULL) + sscanf (cptr, "sample_rate -i %d", &(psf->sf.samplerate)) ; + + if ((cptr = strstr (psf_header, "sample_count -i ")) != NULL) + { sscanf (cptr, "sample_count -i %ld", &samples) ; + psf->sf.frames = samples ; + } ; + + if ((cptr = strstr (psf_header, "sample_n_bytes -i ")) != NULL) + sscanf (cptr, "sample_n_bytes -i %d", &(psf->bytewidth)) ; + + /* Default endian-ness (for 8 bit, u-law, A-law. */ + psf->endian = (CPU_IS_BIG_ENDIAN) ? SF_ENDIAN_BIG : SF_ENDIAN_LITTLE ; + + /* This is where we figure out endian-ness. */ + if ((cptr = strstr (psf_header, "sample_byte_format -s")) + && sscanf (cptr, "sample_byte_format -s%u %8s", &bytes, str) == 2) + { + if (bytes != strlen (str)) + psf_log_printf (psf, "Weird sample_byte_format : strlen '%s' != %d\n", str, bytes) ; + + if (bytes > 1) + { if (psf->bytewidth == 0) + psf->bytewidth = bytes ; + else if (psf->bytewidth - bytes != 0) + { psf_log_printf (psf, "psf->bytewidth (%d) != bytes (%d)\n", psf->bytewidth, bytes) ; + return SFE_NIST_BAD_ENCODING ; + } ; + + if (strcmp (str, "01") == 0) + psf->endian = SF_ENDIAN_LITTLE ; + else if (strcmp (str, "10") == 0) + psf->endian = SF_ENDIAN_BIG ; + else + { psf_log_printf (psf, "Weird endian-ness : %s\n", str) ; + return SFE_NIST_BAD_ENCODING ; + } ; + } ; + + psf->sf.format |= psf->endian ; + } ; + + if ((cptr = strstr (psf_header, "sample_sig_bits -i "))) + sscanf (cptr, "sample_sig_bits -i %d", &bitwidth) ; + + if (strstr (psf_header, "channels_interleaved -s5 FALSE")) + { psf_log_printf (psf, "Non-interleaved data unsupported.\n", str) ; + return SFE_NIST_BAD_ENCODING ; + } ; + + psf->blockwidth = psf->sf.channels * psf->bytewidth ; + psf->datalength = psf->filelength - psf->dataoffset ; + + psf_fseek (psf, psf->dataoffset, SEEK_SET) ; + + if (encoding == SF_FORMAT_PCM_U8) + { switch (psf->bytewidth) + { case 1 : + psf->sf.format |= SF_FORMAT_PCM_S8 ; + break ; + + case 2 : + psf->sf.format |= SF_FORMAT_PCM_16 ; + break ; + + case 3 : + psf->sf.format |= SF_FORMAT_PCM_24 ; + break ; + + case 4 : + psf->sf.format |= SF_FORMAT_PCM_32 ; + break ; + + default : break ; + } ; + } + else if (encoding != 0) + psf->sf.format |= encoding ; + else + return SFE_UNIMPLEMENTED ; + + /* Sanitize psf->sf.format. */ + switch (SF_CODEC (psf->sf.format)) + { case SF_FORMAT_ULAW : + case SF_FORMAT_ALAW : + case SF_FORMAT_PCM_U8 : + /* Blank out endian bits. */ + psf->sf.format = SF_FORMAT_NIST | SF_CODEC (psf->sf.format) ; + break ; + + default : + break ; + } ; + + return 0 ; +} /* nist_read_header */ + +static int +nist_close (SF_PRIVATE *psf) +{ + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + nist_write_header (psf, SF_TRUE) ; + + return 0 ; +} /* nist_close */ + +/*========================================================================= +*/ + +static int +nist_write_header (SF_PRIVATE *psf, int calc_length) +{ const char *end_str ; + long samples ; + sf_count_t current ; + + current = psf_ftell (psf) ; + + if (calc_length) + { psf->filelength = psf_get_filelen (psf) ; + + psf->datalength = psf->filelength - psf->dataoffset ; + + if (psf->dataend) + psf->datalength -= psf->filelength - psf->dataend ; + + if (psf->bytewidth > 0) + psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ; + } ; + + if (psf->endian == SF_ENDIAN_BIG) + end_str = "10" ; + else if (psf->endian == SF_ENDIAN_LITTLE) + end_str = "01" ; + else + end_str = "error" ; + + /* Clear the whole header. */ + memset (psf->header.ptr, 0, psf->header.len) ; + psf->header.indx = 0 ; + + psf_fseek (psf, 0, SEEK_SET) ; + + psf_asciiheader_printf (psf, "NIST_1A\n 1024\n") ; + psf_asciiheader_printf (psf, "channel_count -i %d\n", psf->sf.channels) ; + psf_asciiheader_printf (psf, "sample_rate -i %d\n", psf->sf.samplerate) ; + + switch (SF_CODEC (psf->sf.format)) + { case SF_FORMAT_PCM_S8 : + psf_asciiheader_printf (psf, "sample_coding -s3 pcm\n") ; + psf_asciiheader_printf (psf, "sample_n_bytes -i 1\n" + "sample_sig_bits -i 8\n") ; + break ; + + case SF_FORMAT_PCM_16 : + case SF_FORMAT_PCM_24 : + case SF_FORMAT_PCM_32 : + psf_asciiheader_printf (psf, "sample_n_bytes -i %d\n", psf->bytewidth) ; + psf_asciiheader_printf (psf, "sample_sig_bits -i %d\n", psf->bytewidth * 8) ; + psf_asciiheader_printf (psf, "sample_coding -s3 pcm\n" + "sample_byte_format -s%d %s\n", psf->bytewidth, end_str) ; + break ; + + case SF_FORMAT_ALAW : + psf_asciiheader_printf (psf, "sample_coding -s4 alaw\n") ; + psf_asciiheader_printf (psf, "sample_n_bytes -s1 1\n") ; + break ; + + case SF_FORMAT_ULAW : + psf_asciiheader_printf (psf, "sample_coding -s4 ulaw\n") ; + psf_asciiheader_printf (psf, "sample_n_bytes -s1 1\n") ; + break ; + + default : return SFE_UNIMPLEMENTED ; + } ; + + psf->dataoffset = NIST_HEADER_LENGTH ; + + /* Fix this */ + samples = psf->sf.frames ; + psf_asciiheader_printf (psf, "sample_count -i %ld\n", samples) ; + psf_asciiheader_printf (psf, "end_head\n") ; + + /* Zero fill to dataoffset. */ + psf_binheader_writef (psf, "z", BHWz ((size_t) (NIST_HEADER_LENGTH - psf->header.indx))) ; + + psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ; + + if (psf->error) + return psf->error ; + + if (current > 0) + psf_fseek (psf, current, SEEK_SET) ; + + return psf->error ; +} /* nist_write_header */ + diff --git a/extern/libsndfile-modified/src/nms_adpcm.c b/extern/libsndfile-modified/src/nms_adpcm.c new file mode 100644 index 000000000..96d6ad268 --- /dev/null +++ b/extern/libsndfile-modified/src/nms_adpcm.c @@ -0,0 +1,1156 @@ +/* +** Copyright (C) 1999-2014 Erik de Castro Lopo +** Copyright (C) 2017 Arthur Taylor +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/* +** This is a Natural MicroSystems ADPCM encoder/decoder. It converts 14 bit linear +** PCM to and from either a 2, 3, or 4 bit ADPCM. NMS-ADPCM does not have appeared +** to have ever been publicly documented, and appears to have debuted in the early +** 90s in the Natural Access suite of PC-based telephony products. Raw NMS ADPCM +** files usually have a .vce extension, although this does not encode what bitrate +** is used. +** +** NMS-ADPCM is an 'optimised variation' of the ITU G.726 ADPCM scheme. The dominant +** variation is that it removes the tone (modem) operation mode, and it's associated +** voice/modem transition detection. This simplifies the computation of the step +** size multiplier, as all operations on it remain in a log domain. +*/ + +#include "sfconfig.h" + +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + + +#define NMS_SAMPLES_PER_BLOCK 160 +#define NMS_BLOCK_SHORTS_32 41 +#define NMS_BLOCK_SHORTS_24 31 +#define NMS_BLOCK_SHORTS_16 21 + +/* Variable names from ITU G.726 spec */ +struct nms_adpcm_state +{ /* Log of the step size multiplier. Operated on by codewords. */ + int yl ; + + /* Quantizer step size multiplier. Generated from yl. */ + int y ; + + /* Coefficents of the pole predictor */ + int a [2] ; + + /* Coefficents of the zero predictor */ + int b [6] ; + + /* Previous quantized deltas (multiplied by 2^14) */ + int d_q [7] ; + + /* d_q [x] + s_ez [x], used by the pole-predictor for signs only. */ + int p [3] ; + + /* Previous reconstructed signal values. */ + int s_r [2] ; + + /* Zero predictor components of the signal estimate. */ + int s_ez ; + + /* Signal estimate, (including s_ez). */ + int s_e ; + + /* The most recent codeword (enc:generated, dec:inputted) */ + int Ik ; + + int parity ; + + /* + ** Offset into code tables for the bitrate. + ** 2-bit words: +0 + ** 3-bit words: +8 + ** 4-bit words: +16 + */ + int t_off ; +} ; + +enum nms_enc_type +{ NMS16, + NMS24, + NMS32 +} ; + +typedef struct +{ struct nms_adpcm_state state ; + + /* The encoding type */ + enum nms_enc_type type ; + + int shortsperblock ; + int blocks_total ; + int block_curr, sample_curr ; + + unsigned short block [NMS_BLOCK_SHORTS_32] ; + short samples [NMS_SAMPLES_PER_BLOCK] ; +} NMS_ADPCM_PRIVATE ; + +/* Pre-computed exponential interval used in the antilog approximation. */ +static unsigned int table_expn [] = +{ 0x4000, 0x4167, 0x42d5, 0x444c, 0x45cb, 0x4752, 0x48e2, 0x4a7a, + 0x4c1b, 0x4dc7, 0x4f7a, 0x5138, 0x52ff, 0x54d1, 0x56ac, 0x5892, + 0x5a82, 0x5c7e, 0x5e84, 0x6096, 0x62b4, 0x64dd, 0x6712, 0x6954, + 0x6ba2, 0x6dfe, 0x7066, 0x72dc, 0x7560, 0x77f2, 0x7a93, 0x7d42, +} ; + +/* Table mapping codewords to scale factor deltas. */ +static int table_scale_factor_step [] = +{ 0x0, 0x0, 0x0, 0x0, 0x4b0, 0x0, 0x0, 0x0, /* 2-bit */ + -0x3c, 0x0, 0x90, 0x0, 0x2ee, 0x0, 0x898, 0x0, /* 3-bit */ + -0x30, 0x12, 0x6b, 0xc8, 0x188, 0x2e0, 0x551, 0x1150, /* 4-bit */ +} ; + +/* Table mapping codewords to quantized delta interval steps. */ +static unsigned int table_step [] = +{ 0x73F, 0, 0, 0, 0x1829, 0, 0, 0, /* 2-bit */ + 0x3EB, 0, 0xC18, 0, 0x1581, 0, 0x226E, 0, /* 3-bit */ + 0x20C, 0x635, 0xA83, 0xF12, 0x1418, 0x19E3, 0x211A, 0x2BBA, /* 4-bit */ +} ; + +/* Binary search lookup table for quantizing using table_step. */ +static int table_step_search [] = +{ 0, 0x1F6D, 0, -0x1F6D, 0, 0, 0, 0, /* 2-bit */ + 0x1008, 0x1192, 0, -0x219A, 0x1656, -0x1656, 0, 0, /* 3-bit */ + 0x872, 0x1277, -0x8E6, -0x232B, 0xD06, -0x17D7, -0x11D3, 0, /* 4-bit */ +} ; + + +/*============================================================================================ +** Static functions. +*/ + +static void nms_adpcm_update (struct nms_adpcm_state *s) ; +static void nms_adpcm_codec_init (struct nms_adpcm_state *s, enum nms_enc_type type) ; + +static int16_t nms_adpcm_reconstruct_sample (struct nms_adpcm_state *s, uint8_t I) ; +static uint8_t nms_adpcm_encode_sample (struct nms_adpcm_state *s, int16_t sl) ; +static int16_t nms_adpcm_decode_sample (struct nms_adpcm_state *s, uint8_t code) ; + +static void nms_adpcm_block_pack_16 (const int16_t codewords [], uint16_t block [], int16_t rms) ; +static void nms_adpcm_block_pack_24 (const int16_t codewords [], uint16_t block [], int16_t rms) ; +static void nms_adpcm_block_pack_32 (const int16_t codewords [], uint16_t block [], int16_t rms) ; + +static void nms_adpcm_block_unpack_16 (const uint16_t block [], int16_t codewords [], int16_t *rms) ; +static void nms_adpcm_block_unpack_24 (const uint16_t block [], int16_t codewords [], int16_t *rms) ; +static void nms_adpcm_block_unpack_32 (const uint16_t block [], int16_t codewords [], int16_t *rms) ; + +static int nms_adpcm_decode_block (SF_PRIVATE *psf, NMS_ADPCM_PRIVATE *pnms, uint16_t block [], int16_t samples []) ; +static int nms_adpcm_encode_block (SF_PRIVATE *psf, NMS_ADPCM_PRIVATE *pnms, int16_t samples [], uint16_t block []) ; + +static sf_count_t nms_adpcm_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; +static sf_count_t nms_adpcm_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; +static sf_count_t nms_adpcm_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; +static sf_count_t nms_adpcm_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; + +static sf_count_t nms_adpcm_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; +static sf_count_t nms_adpcm_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; +static sf_count_t nms_adpcm_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; +static sf_count_t nms_adpcm_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; + +static int nms_adpcm_close (SF_PRIVATE *psf) ; +static sf_count_t nms_adpcm_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ; + +/* +** An exponential function (antilog) approximation. +** +** Maps [1,20480] to [1,1024] in an exponential relationship. This is +** approximately ret = b^exp where b = e^(ln(1024)/ln(20480)) ~= 1.0003385 +*/ +static inline int +nms_adpcm_antilog (int exp) +{ int ret ; + + ret = 0x1000 ; + ret += (((exp & 0x3f) * 0x166b) >> 12) ; + ret *= table_expn [(exp & 0x7c0) >> 6] ; + ret >>= (26 - (exp >> 11)) ; + + return ret ; +} /* nms_adpcm_antilog */ + +static void +nms_adpcm_update (struct nms_adpcm_state *s) +{ /* Variable names from ITU G.726 spec */ + int a1ul ; + int fa1 ; + int i ; + + /* Decay and Modify the scale factor in the log domain based on the codeword. */ + s->yl = ((s->yl *0xf8) >> 8) + table_scale_factor_step [s->t_off + (s->Ik & 7)] ; + if (s->yl < 2171) + s->yl = 2171 ; + else if (s->yl > 20480) + s->yl = 20480 ; + s->y = nms_adpcm_antilog (s->yl) ; + + /* Update the zero predictor coefficents. */ + for (i = 0 ; i < 6 ; i++) + { s->b [i] = (s->b [i] * 0xff) >> 8 ; + if ((s->d_q [0] ^ s->d_q [i + 1]) >= 0) + s->b [i] += 128 ; + else + s->b [i] -= 128 ; + } + + /* Update the pole predictor coefficents. */ + fa1 = s->a [0] >> 5 ; + if (fa1 < -256) + fa1 = -256 ; + else if (fa1 > 256) + fa1 = 256 ; + + s->a [0] = (0xff * s->a [0]) >> 8 ; + if (s->p [0] != 0 && s->p [1] != 0 && ((s->p [0] ^ s->p [1]) < 0)) + s->a [0] -= 192 ; + else + { s->a [0] += 192 ; + fa1 = -fa1 ; + } + + s->a [1] = fa1 + ((0xfe * s->a [1]) >> 8) ; + if (s->p [0] != 0 && s->p [2] != 0 && ((s->p [0] ^ s->p [2]) < 0)) + s->a [1] -= 128 ; + else + s->a [1] += 128 ; + + /* Stability constraints. */ + if (s->a [1] < -12288) + s->a [1] = -12288 ; + else if (s->a [1] > 12288) + s->a [1] = 12288 ; + a1ul = 15360 - s->a [1] ; + if (s->a [0] >= a1ul) + s->a [0] = a1ul ; + else + { a1ul = -a1ul ; + if (s->a [0] < a1ul) + s->a [0] = a1ul ; + } ; + + /* Compute the zero predictor estimate. Rotate past deltas too. */ + s->s_ez = 0 ; + for (i = 5 ; i >= 0 ; i--) + { s->s_ez += s->d_q [i] * s->b [i] ; + s->d_q [i + 1] = s->d_q [i] ; + } ; + + /* Compute the signal estimate. */ + s->s_e = s->a [0] * s->s_r [0] + s->a [1] * s->s_r [1] + s->s_ez ; + + /* Return to scale */ + s->s_ez >>= 14 ; + s->s_e >>= 14 ; + + /* Rotate members to prepare for next iteration. */ + s->s_r [1] = s->s_r [0] ; + s->p [2] = s->p [1] ; + s->p [1] = s->p [0] ; +} /* nms_adpcm_update */ + + +static int16_t +nms_adpcm_reconstruct_sample (struct nms_adpcm_state *s, uint8_t I) +{ /* Variable names from ITU G.726 spec */ + int dqx ; + + /* + ** The ordering of the 12-bit right-shift is a precision loss. It agrees + ** with the output of a 16-bit NMSVCE.DLL, but disagrees with the output + ** of a CG6565 board. + */ + + /* Look up the delta, scale and sign it. */ + dqx = table_step [s->t_off + (I & 7)] * s->y ; + if (I & 8) + dqx = -dqx ; + + /* Take from delta scale to actual scale. */ + dqx >>= 12 ; + + /* Set variables used as input for the next predictor update. */ + s->d_q [0] = dqx ; + s->s_r [0] = s->s_e + dqx ; + s->Ik = I & 0xf ; + s->p [0] = s->s_ez + dqx ; + + return s->s_r [0] ; +} /* nms_adpcm_reconstruct_sample */ + +static void +nms_adpcm_codec_init (struct nms_adpcm_state *s, enum nms_enc_type type) +{ memset (s, 0, sizeof (struct nms_adpcm_state)) ; + s->t_off = (type == NMS32) ? 16 : (type == NMS24) ? 8 : 0 ; +} /* nms_adpcm_codec_init */ + +/* +** nms_adpcm_encode_sample() +** +** Encode a linear 16-bit pcm sample into a 2,3, or 4 bit NMS-ADPCM codeword +** using and updating the predictor state. +*/ +static uint8_t +nms_adpcm_encode_sample (struct nms_adpcm_state *s, int16_t sl) +{ /* Variable names from ITU G.726 spec */ + int d ; + uint8_t I ; + + /* Down scale the sample from 16 => ~14 bits. */ + sl = (sl * 0x1fdf) / 0x7fff ; + + /* Compute estimate, and delta from actual value */ + nms_adpcm_update (s) ; + d = sl - s->s_e ; + + /* + ** Vary the input signal. Not sure why. It agrees with NMSVCE.DLL and + ** a CG6565 board. + */ + if (s->parity ^= 1) + d -= 2 ; + + /* Encode the delta signed-ness (Codeword bit 4) */ + if (d < 0) + { d = -d ; + I = 8 ; + } + else + I = 0 ; + + /* Increase magnitude to be in the range of the delta steps */ + d <<= 13 ; + + /* Quantize the delta using a binary search. */ + d += table_step_search [s->t_off + 3] * s->y ; + /* Codeword bit 3 */ + if (d >= 0) + { d += table_step_search [s->t_off + 5] * s->y ; + /* Codeword bit 2 */ + if (d >= 0) + { d += table_step_search [s->t_off + 6] * s->y ; + /* Codeword bit 1 */ + if (d >= 0) + I |= 7 ; + else + I |= 6 ; + } + else + { d += table_step_search [s->t_off + 4] * s->y ; + /* Codeword bit 1 */ + if (d >= 0) + I |= 5 ; + else + I |= 4 ; + } ; + } + else { + d += table_step_search [s->t_off + 1] * s->y ; + /* Codeword bit 2 */ + if (d >= 0) + { d += table_step_search [s->t_off + 2] * s->y ; + /* Codeword bit 1 */ + if (d >= 0) + I |= 3 ; + else + I |= 2 ; + } + else { + d += table_step_search [s->t_off + 0] * s->y ; + /* Codeword bit 1 */ + if (d >= 0) + I |= 1 ; + else + I |= 0 ; + } ; + } ; + /* What's left in d is actually our quantizer noise. */ + + /* Reduce the codeword size for the bitrate accordingly. */ + if (s->t_off == 8) + I &= 0xe ; + else if (s->t_off == 0) + I &= 0xc ; + + /* Call reconstruct for side effects preparing for the next update. */ + nms_adpcm_reconstruct_sample (s, I) ; + + return I ; +} /* nms_adpcm_encode_sample */ + +/* +** nms_adpcm_decode_sample() +** +** Given a 2,3 or 4-bit NMS-ADPCM codeword, decode the next 16-bit linear PCM +** sample using and updating the predictor state. +*/ +static int16_t +nms_adpcm_decode_sample (struct nms_adpcm_state *s, uint8_t I) +{ int sl ; + + nms_adpcm_update (s) ; + sl = nms_adpcm_reconstruct_sample (s, I) ; + + /* Clamp to [-0x1fdf, 0x1fdf] (just under 14 bits resolution) */ + if (sl < -0x1fdf) + sl = -0x1fdf ; + else if (sl > 0x1fdf) + sl = 0x1fdf ; + + /* Expand from 14 to 16 bits */ + sl = (sl * 0x7fff) / 0x1fdf ; + + return (int16_t) sl ; +} /* nms_adpcm_decode_sample */ + +/** +** NMS ADPCM Codeword packing scheme. +** +** The serialized form of NMS-ADPCM operates on blocks of 160 mono samples +** (20ms at 8000Hz.) Blocks are 42, 62 and 82 bytes in size for the 2, 3, and +** 4 bit codeword sizes respectively. The data is treated as an array of +** little-endian 2-byte shorts, and the data is packed into the first 20, 30 +** or 40 shorts. The last short represents the block's root-mean-square +** average. This is apparently an optimization so that energy/silence +** detection processes can avoid decoding a block. +** +** All codewords are nibbles, with the least significant bits dropped as +** required for the 3 and 2 bit codeword sizes. +** +** Nibbles are packed into shorts in order of most significant to least. The +** 4-bit scheme is trivial. The three bit scheme reconstructs a fourth sample +** from the leftover bits of the proceeding three samples. The 2-bit scheme +** uses a two-pass, left two bit shift. +*/ + +/* +** Reads 21 shorts from block, unpacks 160 codewords of 2-bits each, writing +** each to its sequential array index of codewords. If rms is non-null, the +** read block rms is copied to its location. +*/ +static void +nms_adpcm_block_unpack_16 (const uint16_t block [], int16_t codewords [], int16_t *rms) +{ int k ; + uint16_t w = 0 ; + + for (k = 0 ; k < NMS_SAMPLES_PER_BLOCK ; ) + { /* + ** k % 8 == [0-3]: Top 2-bits of a nibble + ** k % 8 == [4-7]: Bottom 2-bits of a nibble + */ + if ((k & 4) == 0) + w = *(block++) ; + else + w <<= 2 ; + codewords [k++] = (w >> 12) & 0xc ; + codewords [k++] = (w >> 8) & 0xc ; + codewords [k++] = (w >> 4) & 0xc ; + codewords [k++] = w & 0xc ; + } ; + + /* + ** Every block ends with a short representing a RMS-approximation for the + ** block. + **/ + if (rms) + *rms = *block ; +} /* nms_adpcm_unpack_16 */ + +/* +** Reads 31 shorts from block, unpacks 160 codewords of 3-bits each, writing +** each to its sequential array index of codewords. If rms is non-null, the +** read block rms is copied to its location. +*/ +static void +nms_adpcm_block_unpack_24 (const uint16_t block [], int16_t codewords [], int16_t *rms) +{ int k ; + uint16_t w = 0, residual = 0 ; + + for (k = 0 ; k < NMS_SAMPLES_PER_BLOCK ; ) + { /* + ** k % 16 == [0, 11]: Unpack new nibble, build residual + ** k % 16 == [12, 15]: Unpack residual + */ + if ((k & 12) != 12) + { w = *(block++) ; + residual = (residual << 1) | (w & 0x1111) ; + } + else + { w = residual << 1 ; + residual = 0 ; + } ; + codewords [k++] = (w >> 12) & 0xe ; + codewords [k++] = (w >> 8) & 0xe ; + codewords [k++] = (w >> 4) & 0xe ; + codewords [k++] = w & 0xe ; + } ; + + /* + ** Every block ends with a short representing a RMS-approximation for the + ** block. + **/ + if (rms) + *rms = *block ; +} /* nms_adpcm_unpack_24 */ + +/* +** Reads 41 shorts from block, unpacks 160 codewords of 4-bits each, writing +** each to its sequential array index of codewords. If rms is non-null, the +** read block rms is copied to its location. +*/ +static void +nms_adpcm_block_unpack_32 (const uint16_t block [], int16_t codewords [], int16_t *rms) +{ int k ; + uint16_t w = 0 ; + + for (k = 0 ; k < NMS_SAMPLES_PER_BLOCK ; ) + { w = *(block++) ; + codewords [k++] = (w >> 12) & 0xf ; + codewords [k++] = (w >> 8) & 0xf ; + codewords [k++] = (w >> 4) & 0xf ; + codewords [k++] = w & 0xf ; + } ; + /* + ** Every block ends with a short representing a RMS-approximation for the + ** block. + **/ + if (rms) + *rms = *block ; +} /* nms_adpcm_unpack_32 */ + +/* +** Reads 160 indicies of codewords for one 2-bit codeword each, packing them +** into 20 shorts of block, and writes the short rms for a total of 42 bytes. +*/ +static void +nms_adpcm_block_pack_16 (const int16_t codewords [], uint16_t block [], int16_t rms) +{ int k ; + uint16_t w ; + + for (k = 0 ; k < NMS_SAMPLES_PER_BLOCK ; ) + { w = codewords [k++] << 12 ; + w |= codewords [k++] << 8 ; + w |= codewords [k++] << 4 ; + w |= codewords [k++] ; + w |= codewords [k++] << 10 ; + w |= codewords [k++] << 6 ; + w |= codewords [k++] << 2 ; + w |= codewords [k++] >> 2 ; + + *(block++) = w ; + } ; + + /* Every block ends with a short representing the blocks RMS */ + *block = rms ; +} /* nms_adpcm_pack_16 */ + +/* +** Reads 160 indicies of codewords for one 3-bit codeword each, packing them +** into 30 shorts of block, and writes the short rms for a total of 62 bytes. +*/ +static void +nms_adpcm_block_pack_24 (const int16_t codewords [], uint16_t block [], int16_t rms) +{ int k ; + uint16_t w [3] ; + uint16_t residual ; + + for (k = 0 ; k < NMS_SAMPLES_PER_BLOCK ; ) + { w [0] = codewords [k++] << 12 ; + w [0] |= codewords [k++] << 8 ; + w [0] |= codewords [k++] << 4 ; + w [0] |= codewords [k++] ; + + w [1] = codewords [k++] << 12 ; + w [1] |= codewords [k++] << 8 ; + w [1] |= codewords [k++] << 4 ; + w [1] |= codewords [k++] ; + + w [2] = codewords [k++] << 12 ; + w [2] |= codewords [k++] << 8 ; + w [2] |= codewords [k++] << 4 ; + w [2] |= codewords [k++] ; + + residual = codewords [k++] << 12 ; + residual |= codewords [k++] << 8 ; + residual |= codewords [k++] << 4 ; + residual |= codewords [k++] ; + + residual >>= 1 ; + w [2] |= (residual & 0x1111) ; + residual >>= 1 ; + w [1] |= (residual & 0x1111) ; + residual >>= 1 ; + w [0] |= (residual & 0x1111) ; + + *(block++) = w [0] ; + *(block++) = w [1] ; + *(block++) = w [2] ; + } ; + + /* Every block ends with a short representing the blocks RMS */ + *block = rms ; +} /* nms_adpcm_pack_24 */ + +/* +** Reads 160 indicies of codewords for one 4-bit codeword each, packing them +** into 40 shorts of block, and writes the short rms for a total of 82 bytes. +*/ +static void +nms_adpcm_block_pack_32 (const int16_t codewords [], uint16_t block [], int16_t rms) +{ int k ; + uint16_t w ; + + for (k = 0 ; k < NMS_SAMPLES_PER_BLOCK ; ) + { w = codewords [k++] << 12 ; + w |= codewords [k++] << 8 ; + w |= codewords [k++] << 4 ; + w |= codewords [k++] ; + + *(block++) = w ; + } ; + + /* Every block ends with a short representing the blocks RMS */ + *block = rms ; +} /*nms_adpcm_block_pack_32 */ + +static int +nms_adpcm_decode_block (SF_PRIVATE *psf, NMS_ADPCM_PRIVATE *pnms, uint16_t block [], int16_t samples []) +{ int k ; + + switch (pnms->type) + { case NMS16 : + nms_adpcm_block_unpack_16 (block, samples, NULL) ; + break ; + case NMS24 : + nms_adpcm_block_unpack_24 (block, samples, NULL) ; + break ; + case NMS32 : + nms_adpcm_block_unpack_32 (block, samples, NULL) ; + break ; + + default : + psf_log_printf (psf, "*** Error : Unhandled NMS ADPCM type %d.\n", pnms->type) ; + return 0 ; + } ; + + for (k = 0 ; k < NMS_SAMPLES_PER_BLOCK ; k++) + samples [k] = nms_adpcm_decode_sample (&pnms->state, samples [k]) ; + + return NMS_SAMPLES_PER_BLOCK ; +} /* nms_adpcm_decode_block */ + +static int +nms_adpcm_encode_block (SF_PRIVATE *psf, NMS_ADPCM_PRIVATE *pnms, int16_t samples [], uint16_t block []) +{ int k ; + unsigned int rms = 0 ; + + /* + ** The rms we write is a complete lie. Considering that the various + ** other implementations I've tested don't completely agree, that this data + ** is usually ignored, and except for some weird offloading of "energy + ** detection", so long as we don't write zeros for non-zero data, I don't + ** think it really matters. + */ + + for (k = 0 ; k < NMS_SAMPLES_PER_BLOCK ; k++) + { rms += (samples [k] * samples [k]) >> 2 ; + samples [k] = nms_adpcm_encode_sample (&pnms->state, samples [k]) ; + } ; + + rms <<= 12 ; + switch (pnms->type) + { case NMS16 : + nms_adpcm_block_pack_16 (samples, block, rms) ; + break ; + case NMS24 : + nms_adpcm_block_pack_24 (samples, block, rms) ; + break ; + case NMS32 : + nms_adpcm_block_pack_32 (samples, block, rms) ; + break ; + + default : + psf_log_printf (psf, "*** Error : Unhandled NMS ADPCM type %d.\n", pnms->type) ; + return 0 ; + } ; + + return NMS_SAMPLES_PER_BLOCK ; +} /* nms_adpcm_encode_block */ + +static int +psf_nms_adpcm_decode_block (SF_PRIVATE *psf, NMS_ADPCM_PRIVATE *pnms) +{ int k ; + + if ((k = (int) psf_fread (pnms->block, sizeof (short), pnms->shortsperblock, psf)) != pnms->shortsperblock) + { psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, pnms->shortsperblock) ; + memset (pnms->block + (k * sizeof (short)), 0, (pnms->shortsperblock - k) * sizeof (short)) ; + } ; + + if (CPU_IS_BIG_ENDIAN) + endswap_short_array ((signed short *) pnms->block, pnms->shortsperblock) ; + + nms_adpcm_decode_block (psf, pnms, pnms->block, pnms->samples) ; + + return 1 ; +} /* nms_adpcm_decode_block */ + +static int +nms_adpcm_read_block (SF_PRIVATE *psf, NMS_ADPCM_PRIVATE *pnms, short *ptr, int len) +{ int count, indx = 0 ; + + while (indx < len) + { if (pnms->sample_curr >= NMS_SAMPLES_PER_BLOCK) + { pnms->block_curr ++ ; + pnms->sample_curr = 0 ; + } ; + + if (pnms->block_curr > pnms->blocks_total) + { memset (&(ptr [indx]), 0, (len - indx) * sizeof (short)) ; + return indx ; + } ; + + if (pnms->sample_curr == 0) + psf_nms_adpcm_decode_block (psf, pnms) ; + + count = NMS_SAMPLES_PER_BLOCK - pnms->sample_curr ; + if (len - indx < count) + count = len - indx ; + + memcpy (&(ptr [indx]), &(pnms->samples [pnms->sample_curr]), count * sizeof (short)) ; + indx += count ; + pnms->sample_curr += count ; + } ; + + return indx ; +} /* nms_adpcm_read_block */ + +static sf_count_t +nms_adpcm_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) +{ NMS_ADPCM_PRIVATE *pnms ; + int readcount, count ; + sf_count_t total = 0 ; + + if (psf->codec_data == NULL) + return 0 ; + pnms = (NMS_ADPCM_PRIVATE*) psf->codec_data ; + + while (len > 0) + { readcount = (len > 0x10000000) ? 0x10000000 : (int) len ; + + count = nms_adpcm_read_block (psf, pnms, ptr, readcount) ; + + total += count ; + len -= count ; + + if (count != readcount) + break ; + } ; + + return total ; +} /* nms_adpcm_read_s */ + +static sf_count_t +nms_adpcm_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + NMS_ADPCM_PRIVATE *pnms ; + short *sptr ; + int k, bufferlen, readcount = 0, count ; + sf_count_t total = 0 ; + + if (psf->codec_data == NULL) + return 0 ; + pnms = (NMS_ADPCM_PRIVATE *) psf->codec_data ; + + sptr = ubuf.sbuf ; + bufferlen = SF_BUFFER_LEN / sizeof (short) ; + while (len > 0) + { readcount = (len >= bufferlen) ? bufferlen : (int) len ; + count = nms_adpcm_read_block (psf, pnms, sptr, readcount) ; + + for (k = 0 ; k < readcount ; k++) + ptr [total + k] = arith_shift_left (sptr [k], 16) ; + + total += count ; + len -= readcount ; + if (count != readcount) + break ; + } ; + + return total ; +} /* nms_adpcm_read_i */ + +static sf_count_t +nms_adpcm_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + NMS_ADPCM_PRIVATE *pnms ; + short *sptr ; + int k, bufferlen, readcount = 0, count ; + sf_count_t total = 0 ; + float normfact ; + + if (psf->codec_data == NULL) + return 0 ; + pnms = (NMS_ADPCM_PRIVATE*) psf->codec_data ; + + normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x8000) : 1.0 ; + + sptr = ubuf.sbuf ; + bufferlen = SF_BUFFER_LEN / sizeof (short) ; + while (len > 0) + { readcount = (len >= bufferlen) ? bufferlen : (int) len ; + count = nms_adpcm_read_block (psf, pnms, sptr, readcount) ; + for (k = 0 ; k < readcount ; k++) + ptr [total + k] = normfact * sptr [k] ; + + total += count ; + len -= readcount ; + if (count != readcount) + break ; + } ; + + return total ; +} /* nms_adpcm_read_f */ + +static sf_count_t +nms_adpcm_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + NMS_ADPCM_PRIVATE *pnms ; + short *sptr ; + int k, bufferlen, readcount = 0, count ; + sf_count_t total = 0 ; + double normfact ; + + if (psf->codec_data == NULL) + return 0 ; + pnms = (NMS_ADPCM_PRIVATE*) psf->codec_data ; + + normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x8000) : 1.0 ; + + sptr = ubuf.sbuf ; + bufferlen = SF_BUFFER_LEN / sizeof (short) ; + while (len > 0) + { readcount = (len >= bufferlen) ? bufferlen : (int) len ; + count = nms_adpcm_read_block (psf, pnms, sptr, readcount) ; + for (k = 0 ; k < readcount ; k++) + ptr [total + k] = normfact * (double) (sptr [k]) ; + + total += count ; + len -= readcount ; + if (count != readcount) + break ; + } ; + + return total ; +} /* nms_adpcm_read_d */ + +static int +psf_nms_adpcm_encode_block (SF_PRIVATE *psf, NMS_ADPCM_PRIVATE *pnms) +{ int k ; + + /* Encode the samples. */ + nms_adpcm_encode_block (psf, pnms, pnms->samples, pnms->block) ; + + if (CPU_IS_BIG_ENDIAN) + endswap_short_array ((signed short *) pnms->block, pnms->shortsperblock) ; + + /* Write the block to disk. */ + if ((k = (int) psf_fwrite (pnms->block, sizeof (short), pnms->shortsperblock, psf)) != pnms->shortsperblock) + psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", k, pnms->shortsperblock) ; + + pnms->sample_curr = 0 ; + pnms->block_curr ++ ; + + return 1 ; +} /* psf_nms_adpcm_encode_block */ + +static int +nms_adpcm_write_block (SF_PRIVATE *psf, NMS_ADPCM_PRIVATE *pnms, const short *ptr, int len) +{ int count, total = 0, indx = 0 ; + + while (indx < len) + { count = NMS_SAMPLES_PER_BLOCK - pnms->sample_curr ; + + if (count > len - indx) + count = len - indx ; + + memcpy (&(pnms->samples [pnms->sample_curr]), &(ptr [indx]), count * sizeof (short)) ; + indx += count ; + pnms->sample_curr += count ; + total = indx ; + + if (pnms->sample_curr >= NMS_SAMPLES_PER_BLOCK) + psf_nms_adpcm_encode_block (psf, pnms) ; + } ; + + return total ; +} /* nms_adpcm_write_block */ + +static sf_count_t +nms_adpcm_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) +{ NMS_ADPCM_PRIVATE *pnms ; + int writecount, count ; + sf_count_t total = 0 ; + + if (psf->codec_data == NULL) + return 0 ; + pnms = (NMS_ADPCM_PRIVATE*) psf->codec_data ; + + while (len > 0) + { writecount = (len > 0x10000000) ? 0x10000000 : (int) len ; + + count = nms_adpcm_write_block (psf, pnms, ptr, writecount) ; + + total += count ; + len -= count ; + if (count != writecount) + break ; + } ; + + return total ; +} /* nms_adpcm_write_s */ + +static sf_count_t +nms_adpcm_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + NMS_ADPCM_PRIVATE *pnms ; + short *sptr ; + int k, bufferlen, writecount = 0, count ; + sf_count_t total = 0 ; + + if (psf->codec_data == NULL) + return 0 ; + pnms = (NMS_ADPCM_PRIVATE*) psf->codec_data ; + + sptr = ubuf.sbuf ; + bufferlen = SF_BUFFER_LEN / sizeof (short) ; + while (len > 0) + { writecount = (len >= bufferlen) ? bufferlen : (int) len ; + for (k = 0 ; k < writecount ; k++) + sptr [k] = ptr [total + k] >> 16 ; + count = nms_adpcm_write_block (psf, pnms, sptr, writecount) ; + + total += count ; + len -= writecount ; + if (count != writecount) + break ; + } ; + return total ; +} /* nms_adpcm_write_i */ + +static sf_count_t +nms_adpcm_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + NMS_ADPCM_PRIVATE *pnms ; + short *sptr ; + int k, bufferlen, writecount = 0, count ; + sf_count_t total = 0 ; + float normfact ; + + if (psf->codec_data == NULL) + return 0 ; + pnms = (NMS_ADPCM_PRIVATE*) psf->codec_data ; + + normfact = (psf->norm_float == SF_TRUE) ? (1.0 * 0x8000) : 1.0 ; + + sptr = ubuf.sbuf ; + bufferlen = SF_BUFFER_LEN / sizeof (short) ; + while (len > 0) + { writecount = (len >= bufferlen) ? bufferlen : (int) len ; + for (k = 0 ; k < writecount ; k++) + sptr [k] = psf_lrintf (normfact * ptr [total + k]) ; + count = nms_adpcm_write_block (psf, pnms, sptr, writecount) ; + + total += count ; + len -= writecount ; + if (count != writecount) + break ; + } ; + + return total ; +} /* nms_adpcm_write_f */ + +static sf_count_t +nms_adpcm_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + NMS_ADPCM_PRIVATE *pnms ; + short *sptr ; + int k, bufferlen, writecount = 0, count ; + sf_count_t total = 0 ; + double normfact ; + + if (psf->codec_data == NULL) + return 0 ; + pnms = (NMS_ADPCM_PRIVATE*) psf->codec_data ; + + normfact = (psf->norm_double == SF_TRUE) ? (1.0 * 0x8000) : 1.0 ; + + sptr = ubuf.sbuf ; + bufferlen = SF_BUFFER_LEN / sizeof (short) ; + while (len > 0) + { writecount = (len >= bufferlen) ? bufferlen : (int) len ; + for (k = 0 ; k < writecount ; k++) + sptr [k] = psf_lrint (normfact * ptr [total + k]) ; + count = nms_adpcm_write_block (psf, pnms, sptr, writecount) ; + + total += count ; + len -= writecount ; + if (count != writecount) + break ; + } ; + + return total ; +} /* nms_adpcm_write_d */ + +int +nms_adpcm_init (SF_PRIVATE *psf) +{ NMS_ADPCM_PRIVATE *pnms ; + + if (psf->codec_data != NULL) + { psf_log_printf (psf, "*** psf->codec_data is not NULL.\n") ; + return SFE_INTERNAL ; + } ; + + psf->sf.seekable = SF_FALSE ; + + if (psf->sf.channels != 1) + return SFE_NMS_ADPCM_NOT_MONO ; + + if ((pnms = calloc (1, sizeof (NMS_ADPCM_PRIVATE))) == NULL) + return SFE_MALLOC_FAILED ; + + psf->codec_data = (void*) pnms ; + + pnms->block_curr = 0 ; + pnms->sample_curr = 0 ; + + switch (SF_CODEC (psf->sf.format)) + { case SF_FORMAT_NMS_ADPCM_16 : + pnms->type = NMS16 ; + pnms->shortsperblock = NMS_BLOCK_SHORTS_16 ; + break ; + case SF_FORMAT_NMS_ADPCM_24 : + pnms->type = NMS24 ; + pnms->shortsperblock = NMS_BLOCK_SHORTS_24 ; + break ; + case SF_FORMAT_NMS_ADPCM_32 : + pnms->type = NMS32 ; + pnms->shortsperblock = NMS_BLOCK_SHORTS_32 ; + break ; + + default : return SFE_UNIMPLEMENTED ; + } ; + nms_adpcm_codec_init (&pnms->state, pnms->type) ; + + psf->filelength = psf_get_filelen (psf) ; + if (psf->filelength < psf->dataoffset) + psf->filelength = psf->dataoffset ; + + psf->datalength = psf->filelength - psf->dataoffset ; + if (psf->dataend > 0) + psf->datalength -= psf->filelength - psf->dataend ; + + if (psf->file.mode == SFM_READ) + { psf->read_short = nms_adpcm_read_s ; + psf->read_int = nms_adpcm_read_i ; + psf->read_float = nms_adpcm_read_f ; + psf->read_double = nms_adpcm_read_d ; + } + else if (psf->file.mode == SFM_WRITE) + { psf->write_short = nms_adpcm_write_s ; + psf->write_int = nms_adpcm_write_i ; + psf->write_float = nms_adpcm_write_f ; + psf->write_double = nms_adpcm_write_d ; + } ; + + if (psf->datalength % (pnms->shortsperblock * sizeof (short))) + { psf_log_printf (psf, "*** Odd psf->datalength (%D) should be a multiple of %d\n", + psf->datalength, pnms->shortsperblock * sizeof (short)) ; + pnms->blocks_total = (psf->datalength / (pnms->shortsperblock * sizeof (short))) + 1 ; + } + else + pnms->blocks_total = psf->datalength / (pnms->shortsperblock * sizeof (short)) ; + + psf->sf.frames = pnms->blocks_total * NMS_SAMPLES_PER_BLOCK ; + psf->codec_close = nms_adpcm_close ; + psf->seek = nms_adpcm_seek ; + + return 0 ; +} /* nms_adpcm_init */ + +static int +nms_adpcm_close (SF_PRIVATE *psf) +{ NMS_ADPCM_PRIVATE *pnms ; + + pnms = (NMS_ADPCM_PRIVATE*) psf->codec_data ; + + /* + ** If a block has been partially assembled, write it out as the final + ** block. + */ + if (psf->file.mode == SFM_WRITE) + { if (pnms->sample_curr && pnms->sample_curr < NMS_SAMPLES_PER_BLOCK) + { memset (pnms->samples + pnms->sample_curr, 0, (NMS_SAMPLES_PER_BLOCK - pnms->sample_curr) * sizeof (short)) ; + psf_nms_adpcm_encode_block (psf, pnms) ; + } + + if (psf->write_header) + psf->write_header (psf, SF_FALSE) ; + } + + return 0 ; +} /* nms_adpcm_close */ + +static sf_count_t +nms_adpcm_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) +{ NMS_ADPCM_PRIVATE *pnms ; + + pnms = (NMS_ADPCM_PRIVATE *) psf->codec_data ; + + /* + ** NMS ADPCM is symmetric, so transitioning from reading and writing is + ** possible, but unimplemented, as it would require syncing partial blocks. + */ + if (mode != psf->file.mode) + { psf->error = SFE_BAD_SEEK ; + return PSF_SEEK_ERROR ; + } ; + + /* + ** NMS ADPCM cannot be seek'ed, as codec state depends on previous samples, + ** so only a seek to 0 is supported. + */ + if (offset != 0) + { psf->error = SFE_BAD_SEEK ; + return PSF_SEEK_ERROR ; + } ; + + if (psf_fseek (psf, psf->dataoffset, SEEK_SET) == PSF_SEEK_ERROR) + return PSF_SEEK_ERROR ; + + nms_adpcm_codec_init (&pnms->state, pnms->type) ; + pnms->block_curr = 0 ; + pnms->sample_curr = 0 ; + return 0 ; +} /* nms_adpcm_seek */ + diff --git a/extern/libsndfile-modified/src/ogg.c b/extern/libsndfile-modified/src/ogg.c new file mode 100644 index 000000000..8cd4379dd --- /dev/null +++ b/extern/libsndfile-modified/src/ogg.c @@ -0,0 +1,921 @@ +/* +** Copyright (C) 2002-2019 Erik de Castro Lopo +** Copyright (C) 2007 John ffitch +** Copyright (C) 2018 Arthur Taylor +** +** This program is free software ; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation ; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY ; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program ; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/* +** This file contains code based on OpusFile and Opus-Tools, both by +** Xiph.Org. COPYING from each is identical and is as follows: +** +** Copyright (c) 1994-2013 Xiph.Org Foundation and contributors +** +** 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 "sfconfig.h" + +#include +#include +#include +#include +#include +#include + +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + +#if HAVE_EXTERNAL_XIPH_LIBS + +#include + +#include "ogg.h" + +#define OGG_SYNC_READ_SIZE (2048) +#define OGG_PAGE_SIZE_MAX (65307) +#define OGG_CHUNK_SIZE (65536) +#define OGG_CHUNK_SIZE_MAX (1024*1024) + +/* + * The Ogg container may seem overly complicated, particularly when used for a + * on-disk audio file format. This is probably because Ogg is designed with + * streaming rather than storage as a priority, and can handle multiple codec + * payloads multiplexed together, then possibly chained on top of that. + * Ogg achieves its goals well, but it does lend to a bit of a learning curve, + * with many internal structures to push data around in compared to most sound + * file formats which only have a header and raw data. + * + * See + * - [https://xiph.org/ogg/doc/oggstream.html] + * - [https://xiph.org/ogg/doc/framing.html] + * + * libogg Memory Management + * =========================================================================== + * + * libOgg's memory management is documented in code, not in headers or external + * documentation. What follows is not an attempt to completely document it, but + * an explanation of the basics. + * + * libOgg has two data structures which allocate and manage data buffers: The + * ogg_sync_state structure and the ogg_stream_state structure. The remaining + * structures of ogg_page and ogg_packet are views into the buffers managed by + * the previous structures. + * + * ogg_sync_state is used for reading purposes. It takes a physical bitstream + * and searches for, validates, and returns complete Ogg Pages. The + * ogg_sync_state buffers the returned page data, holding at most one + * complete page at a time. A returned Ogg page remains valid until any + * operation other than ogg_sync_check() is called. + * + * ogg_stream_state is used for both reading and writing. For reading, the + * contents of an ogg_page is copied into the stream state. This data is + * buffered to be split or joined as necessary into complete ogg_packets. If, + * after copying an ogg_page into an ogg_stream_state, packets are available to + * be read, then all of those packets remain in memory and valid until either + * the ogg_stream_state is reset, destroyed, or a new ogg_page is read into it. + * As the maximum number of packets an Ogg Page may contain is 255, at most 255 + * packets may be available from an ogg_stream_state at one time. + * + * For writing, the life cycle of a buffer pointed to by a ogg_packet is the + * responsibility of the caller. Packets written into an ogg_stream_state are + * buffered until a complete page is ready for writing. Pages for writing out + * remain in the ogg_stream_state's buffer and valid until either the + * ogg_stream_state is reset, cleared, destroyed. Writing another packet into + * the ogg_stream_state might also invalidate such pages, but writing in + * packets when a page is ready to be written out is a caller bug anyways. + */ + +/*----------------------------------------------------------------------------------------------- +** Private function prototypes. +*/ + +static int ogg_close (SF_PRIVATE *psf) ; +static int ogg_stream_classify (SF_PRIVATE *psf, OGG_PRIVATE * odata) ; +static int ogg_page_classify (SF_PRIVATE * psf, const ogg_page * og) ; +static uint64_t ogg_page_search_do_rescale (uint64_t x, uint64_t from, uint64_t to) ; +static void ogg_page_search_continued_data (OGG_PRIVATE *odata, ogg_page *page) ; + +/*----------------------------------------------------------------------------------------------- +** Exported functions. +*/ + +int +ogg_read_first_page (SF_PRIVATE *psf, OGG_PRIVATE *odata) +{ int ret ; + char *buffer ; + + /* + ** The ogg standard requires that the first pages of a physical ogg + ** bitstream be only the first pages of each logical bitstream. These + ** pages MUST have the Beginning-Of-Stream bit set, and must contain + ** only the stream's relevant header. Currently we only load the first + ** page and check that it contains a codec we support as supporting + ** multiplexed streams (video+audio(en)+audio(fs)+subtitles, etc) is + ** beyond the scope of this library. + */ + + ret = ogg_sync_fseek (psf, psf->header.indx, SEEK_SET) ; + if (ret < 0) + return SFE_NOT_SEEKABLE ; + + buffer = ogg_sync_buffer (&odata->osync, psf->header.indx) ; + if (buffer == NULL) + return SFE_MALLOC_FAILED ; + memcpy (buffer, psf->header.ptr, psf->header.indx) ; + ogg_sync_wrote (&odata->osync, psf->header.indx) ; + + ret = ogg_sync_next_page (psf, &odata->opage, SF_MAX ((sf_count_t) 0, 4096 - psf->header.indx), NULL) ; + + /* Have we simply run out of data? If so, we're done. */ + if (ret == 0) + return 0 ; + if (ret < 0) + return psf->error ; + + if (!ogg_page_bos (&odata->opage)) + { /* + ** Error case. Either must not be an Ogg bitstream, or is in the + ** middle of a bitstream (live capture), or in the middle of a + ** bitstream and no complete page was in the buffer. + */ + psf_log_printf (psf, "Input does not appear to be the start of an Ogg bitstream.\n") ; + return SFE_MALFORMED_FILE ; + } ; + + /* + ** Get the serial number and set up the rest of decode. + ** Serialno first ; use it to set up a logical stream. + */ + ogg_stream_reset_serialno (&odata->ostream, ogg_page_serialno (&odata->opage)) ; + + if (ogg_stream_pagein (&odata->ostream, &odata->opage) < 0) + { /* Error ; stream version mismatch perhaps. */ + psf_log_printf (psf, "Error reading first page of Ogg bitstream data\n") ; + return SFE_MALFORMED_FILE ; + } ; + + if (ogg_stream_packetout (&odata->ostream, &odata->opacket) != 1) + { /* No page? */ + psf_log_printf (psf, "Error reading initial header page packet.\n") ; + return SFE_MALFORMED_FILE ; + } ; + + return 0 ; +} /* ogg_read_first_page */ + +int +ogg_write_page (SF_PRIVATE *psf, ogg_page *page) +{ int bytes ; + + bytes = psf_fwrite (page->header, 1, page->header_len, psf) ; + bytes += psf_fwrite (page->body, 1, page->body_len, psf) ; + + return bytes == page->header_len + page->body_len ; +} /* ogg_write_page */ + +sf_count_t +ogg_sync_ftell (SF_PRIVATE *psf) +{ OGG_PRIVATE* odata = (OGG_PRIVATE *) psf->container_data ; + sf_count_t position ; + + position = psf_ftell (psf) ; + if (position >= 0) + { /* success */ + if (position < odata->osync.fill) + { /* Really, this should be an assert. */ + psf->error = SFE_INTERNAL ; + return -1 ; + } + position += (sf_count_t) (odata->osync.returned - odata->osync.fill) ; + } + + return position ; +} /* ogg_sync_ftell */ + +sf_count_t +ogg_sync_fseek (SF_PRIVATE *psf, sf_count_t offset, int whence) +{ OGG_PRIVATE* odata = (OGG_PRIVATE *) psf->container_data ; + sf_count_t ret ; + + ret = psf_fseek (psf, offset, whence) ; + if (ret >= 0) + { /* success */ + odata->eos = 0 ; + ogg_sync_reset (&odata->osync) ; + } + + return ret ; +} /* ogg_sync_fseek */ + +int +ogg_sync_next_page (SF_PRIVATE * psf, ogg_page *og, sf_count_t readmax, sf_count_t *offset) +{ OGG_PRIVATE* odata = (OGG_PRIVATE *) psf->container_data ; + sf_count_t position, nb_read, read_ret ; + unsigned char *buffer ; + int synced ; + int report_hole = 0 ; + + for (position = 0 ; readmax <= 0 || readmax > position ; ) + { synced = ogg_sync_pageseek (&odata->osync, og) ; + if (synced < 0) + { /* + ** Skipped -synced bytes before finding the start of a page. + ** If seeking, we have just landed in the middle of a page. + ** Otherwise, warn about junk in the bitstream. + ** Page might not yet be ready, hence the continue. + */ + if (!offset) + report_hole = 1 ; + position -= synced ; + continue ; + } ; + + if (report_hole) + { psf_log_printf (psf, "Ogg : Skipped %d bytes looking for the next page. Corrupted bitstream?!\n", position) ; + report_hole = 0 ; + } ; + + if (synced > 0) + { /* Have a page */ + if (offset) + *offset += position ; + return og->header_len + og->body_len ; + } ; + + /* + ** Else readmax == 0, Out of data. Try to read more in without + ** invalidating our boundary (readmax) constraint. + */ + if (readmax == 0) + return 0 ; + if (readmax > 0) + nb_read = SF_MIN ((sf_count_t) OGG_SYNC_READ_SIZE, readmax - position) ; + else + nb_read = OGG_SYNC_READ_SIZE ; + buffer = (unsigned char *) ogg_sync_buffer (&odata->osync, nb_read) ; + if (buffer == NULL) + { psf->error = SFE_MALLOC_FAILED ; + return -1 ; + } + read_ret = psf_fread (buffer, 1, nb_read, psf) ; + if (read_ret == 0) + return psf->error ? -1 : 0 ; + ogg_sync_wrote (&odata->osync, read_ret) ; + } ; + return 0 ; +} /* ogg_sync_next_page */ + +int +ogg_stream_next_page (SF_PRIVATE *psf, OGG_PRIVATE *odata) +{ int nn ; + + if (odata->eos) + return 0 ; + + for ( ; ; ) + { nn = ogg_sync_next_page (psf, &odata->opage, -1, NULL) ; + if (nn == 0) + { psf_log_printf (psf, "Ogg : File ended unexpectedly without an End-Of-Stream flag set.\n") ; + odata->eos = 1 ; + } + if (nn <= 0) + return nn ; + + if (ogg_page_serialno (&odata->opage) == odata->ostream.serialno) + break ; + } ; + + if (ogg_page_eos (&odata->opage)) + odata->eos = 1 ; + + if (ogg_stream_pagein (&odata->ostream, &odata->opage) < 0) + { psf->error = SFE_INTERNAL ; + return -1 ; + } + + return 1 ; +} /* ogg_stream_next_page */ + +int +ogg_stream_unpack_page (SF_PRIVATE *psf, OGG_PRIVATE *odata) +{ int nn ; + int i ; + int found_hole = 0 ; + ogg_packet *ppkt = odata->pkt ; + + odata->pkt_indx = 0 ; + nn = ogg_stream_packetout (&odata->ostream, ppkt) ; + if (nn == 0) + { /* + ** Steam is out of packets. Read in more pages until there is one, or + ** the stream ends, or an error occurs. + */ + for ( ; nn == 0 ; nn = ogg_stream_packetout (&odata->ostream, ppkt)) + { nn = ogg_stream_next_page (psf, odata) ; + if (nn <= 0) + { odata->pkt_len = 0 ; + return nn ; + } + } + /* + ** In the case of the for loop exiting because + ** ogg_stream_packetout() == -1, fall-through. + */ + } + + if (nn == -1) + { /* + ** libOgg found a hole. That is, the next packet found was out of + ** sequence. As such, "flush" the hole marker by removing the invalid + ** packet, as the valid packets are queued behind it. + */ + psf_log_printf (psf, "Ogg : Warning, libogg reports a hole at %d bytes.\n", ogg_sync_ftell (psf)) ; + nn = ogg_stream_packetout (&odata->ostream, ppkt) ; + found_hole = 1 ; + } + + /* + ** Unpack all the packets on the page. It is undocumented (like much of + ** libOgg behavior) but all packets from a page read into the stream are + ** guarenteed to remain valid in memory until a new page is read into the + ** stream. + */ + for (i = 1 ; ; i++) + { /* Not an off-by-one, there are 255 not 256 packets max. */ + if (i == 255) + { if (ogg_stream_packetpeek (&odata->ostream, NULL) == 1) + { psf->error = SFE_INTERNAL ; + return -1 ; + } + break ; + } + if (ogg_stream_packetout (&odata->ostream, ++ ppkt) != 1) + break ; + } + odata->pkt_len = i ; + + /* 1 = ok, 2 = ok, and found a hole. */ + return 1 + found_hole ; +} /* ogg_stream_unpack_page */ + +sf_count_t +ogg_sync_last_page_before (SF_PRIVATE *psf, OGG_PRIVATE *odata, uint64_t *gp_out, sf_count_t offset, int32_t serialno) +{ sf_count_t begin, end, original_end, chunk_size, ret ; + sf_count_t position = 0 ; + uint64_t gp = -1 ; + int left_link ; + + /* Based on code from Xiph.org's Opusfile */ + + original_end = end = begin = offset ; + offset = -1 ; + chunk_size = OGG_CHUNK_SIZE ; + do + { begin = SF_MAX (begin - chunk_size, (sf_count_t) 0) ; + position = ogg_sync_fseek (psf, begin, SEEK_SET) ; + if (position < 0) + return position ; + left_link = 0 ; + while (position < end) + { ret = ogg_sync_next_page (psf, &odata->opage, end - position, &position) ; + if (ret < 0) + return -1 ; + else if (ret == 0) + { // Hit EOF before EOS + break ; + } + if (ogg_page_serialno (&odata->opage) == serialno) + { uint64_t page_gp = ogg_page_granulepos (&odata->opage) ; + if (page_gp != (uint64_t) -1) + { offset = position ; + gp = page_gp ; + } + } + else + left_link = 1 ; + position += ret ; + } + + if ((left_link || !begin) && offset < 0) + { psf->error = SFE_MALFORMED_FILE ; + return -1 ; + } + + chunk_size = SF_MIN (2 * chunk_size, (sf_count_t) OGG_CHUNK_SIZE_MAX) ; + end = SF_MIN (begin + OGG_PAGE_SIZE_MAX - 1, original_end) ; + } + while (offset < 0) ; + + *gp_out = gp ; + return offset ; +} /* 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, uint64_t gp_rate) +{ ogg_page page ; + uint64_t gp ; + sf_count_t d0, d1, d2 ; + sf_count_t best ; + sf_count_t best_start ; + sf_count_t boundary ; + sf_count_t next_boundary ; + sf_count_t page_offset = -1 ; + sf_count_t seek_pos = -1 ; + sf_count_t bisect ; + sf_count_t chunk_size ; + int buffering = SF_FALSE ; + int force_bisect = SF_FALSE ; + int ret ; + int has_packets ; + + *best_gp = pcm_start ; + best = best_start = begin ; + boundary = end ; + + ogg_stream_reset_serialno (&odata->ostream, odata->ostream.serialno) ; + + /* + ** This code is based on op_pcm_seek_page() from Opusfile, which is in turn + ** based on "new search algorithm by Nicholas Vinen" from libvorbisfile. + */ + + d2 = d1 = d0 = end - begin ; + while (begin < end) + { /* + ** Figure out if and where to try and seek in the file. + */ + if (end - begin < OGG_CHUNK_SIZE) + bisect = begin ; + else + { /* Update the interval size history */ + d0 = d1 >> 1 ; + d1 = d2 >> 1 ; + d2 = (end - begin) >> 1 ; + if (force_bisect == SF_TRUE) + bisect = begin + ((end - begin) >> 1) ; + else + { /* Take a decent guess. */ + bisect = begin + ogg_page_search_do_rescale (target_gp - pcm_start, pcm_end - pcm_start, end - begin) ; + } + if (bisect - OGG_CHUNK_SIZE < begin) + bisect = begin ; + else + bisect -= OGG_CHUNK_SIZE ; + force_bisect = SF_FALSE ; + } + + /* + ** Avoid an actual fseek if we can (common for final iterations.) + */ + if (seek_pos != bisect) + { if (buffering == SF_TRUE) + ogg_stream_reset (&odata->ostream) ; + buffering = SF_FALSE ; + page_offset = -1 ; + seek_pos = ogg_sync_fseek (psf, bisect, SEEK_SET) ; + if (seek_pos < 0) + return seek_pos ; + } + + chunk_size = OGG_CHUNK_SIZE ; + next_boundary = boundary ; + + /* + ** Scan forward, figure out where we landed. + ** The ideal case is we see a page that ends before our target followed + ** by a page that ends after our target. + ** If we are too far before or after, breaking out will bisect what we + ** have found so far. + */ + while (begin < end) + { ret = ogg_sync_next_page (psf, &page, boundary - seek_pos, &seek_pos) ; + if (ret <= 0) + return ret ; + page_offset = seek_pos ; + if (ret == 0) + { /* + ** There are no more pages in this interval from our stream + ** with a granulepos less than our target. + */ + if (bisect <= begin + 1) + { /* Scanned the whole interval, so we are done. */ + end = begin ; + } + else + { /* + ** Otherwise, back up one chunk. First discard any data + ** from a continued packet. + */ + if (buffering) + ogg_stream_reset (&odata->ostream) ; + buffering = SF_FALSE ; + bisect = SF_MAX (bisect - chunk_size, begin) ; + seek_pos = ogg_sync_fseek (psf, bisect, SEEK_SET) ; + if (seek_pos < 0) + return seek_pos ; + /* Bump up the chunk size. */ + chunk_size = SF_MIN (2 * chunk_size, (sf_count_t) OGG_CHUNK_SIZE_MAX) ; + /* + ** If we did find a page from another stream or without a + ** timestamp, don't read past it. + */ + boundary = next_boundary ; + } + continue ; + } + + /* Found a page. Advance seek_pos past it */ + seek_pos += page.header_len + page.body_len ; + /* + ** Save the offset of the first page we found after the seek, + ** regardless of the stream it came from or whether or not it has a + ** timestamp. + */ + next_boundary = SF_MIN (page_offset, next_boundary) ; + + /* If not from our stream, continue. */ + if (odata->ostream.serialno != ogg_page_serialno (&page)) + continue ; + + /* + ** The Ogg spec says that a page with a granule pos of -1 must not + ** contain and packets which complete, but the lack of biconditional + ** wording means that /technically/ a packet which does not complete + ** any packets can have a granule pos other than -1. To make matters + ** worse, older versions of libogg did just that. + */ + has_packets = ogg_page_packets (&page) > 0 ; + gp = has_packets ? ogg_page_granulepos (&page) : -1 ; + if (gp == (uint64_t) -1) + { if (buffering == SF_TRUE) + { if (!has_packets) + ogg_stream_pagein (&odata->ostream, &page) ; + else + { /* + ** If packets did end on this page, but we still didn't + ** have a valid granule position (in violation of the + ** spec!), stop buffering continued packet data. + ** Otherwise we might continue past the packet we + ** actually wanted. + */ + ogg_stream_reset (&odata->ostream) ; + buffering = SF_FALSE ; + } + } + continue ; + } + + if (gp < target_gp) + { /* + ** We found a page that ends before our target. Advance to + ** the raw offset of the next page. + */ + begin = seek_pos ; + if (pcm_start > gp || pcm_end < gp) + break ; + /* Save the byte offset of after this page. */ + best = best_start = begin ; + if (buffering) + ogg_stream_reset (&odata->ostream) ; + /* Check to see if the last packet continues. */ + if (ogg_page_continues (&page)) + { ogg_page_search_continued_data (odata, &page) ; + /* + ** If we have a continued packet, remember the offset of + ** this page's start, so that if we do wind up having to + ** seek back here later, we can prime the stream with the + ** continued packet data. With no continued packet, we + ** 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 ; + } ; + *best_gp = pcm_start = gp ; + if (target_gp - gp > gp_rate) + { /* Out by over a second. Try another bisection. */ + break ; + } + /* Otherwise, keep scanning forward (do NOT use begin+1). */ + bisect = begin ; + } + else + { /* + ** Found a page that ends after our target. If we had just + ** scanned the whole interval before we found it, we're good. + */ + if (bisect <= begin + 1) + end = begin ; + else + { end = bisect ; + /* + ** In later iterations, don't read past the first page we + ** found. + */ + boundary = next_boundary ; + /* + ** If we're not making much progress shrinking the interval + ** size, start forcing straight bisection to limit the + ** worst case. + */ + force_bisect = end - begin > d0 * 2 ? SF_TRUE : SF_FALSE ; + /* + ** Don't let pcm_end get out of range! That could happen + ** with an invalid timestamp. + */ + if (pcm_end > gp && pcm_start <= gp) + pcm_end = gp ; + } + break ; + } + } + } + + /* + ** If we are buffering, the page we want is currently buffered in the + ** Ogg stream structure, or in the Ogg page which has not been submitted. + ** If not, we need to seek back and load it again. + */ + if (buffering == SF_FALSE) + { if (best_start != page_offset) + { page_offset = -1 ; + seek_pos = ogg_sync_fseek (psf, best_start, SEEK_SET) ; + if (seek_pos < 0) + return seek_pos ; + } + if (best_start < best) + { if (page_offset < 0) + { ret = ogg_sync_next_page (psf, &page, -1, &seek_pos) ; + if (seek_pos != best_start) + return -1 ; + } + ogg_page_search_continued_data (odata, &page) ; + page_offset = -1 ; + } + } ; + + if (page_offset >= 0) + ogg_stream_pagein (&odata->ostream, &page) ; + + return 0 ; +} /* ogg_stream_seek_page_search */ + +int +ogg_open (SF_PRIVATE *psf) +{ OGG_PRIVATE* odata = calloc (1, sizeof (OGG_PRIVATE)) ; + sf_count_t pos = psf_ftell (psf) ; + int error = 0 ; + + psf->container_data = odata ; + psf->container_close = ogg_close ; + + if (psf->file.mode == SFM_RDWR) + return SFE_BAD_MODE_RW ; + + if (psf->file.mode == SFM_READ) + if ((error = ogg_stream_classify (psf, odata)) != 0) + return error ; + + if (SF_ENDIAN (psf->sf.format) != 0) + return SFE_BAD_ENDIAN ; + + switch (psf->sf.format) + { case SF_FORMAT_OGG | SF_FORMAT_VORBIS : + return ogg_vorbis_open (psf) ; + + case SF_FORMAT_OGGFLAC : + /* Reset everything to an initial state. */ + ogg_sync_clear (&odata->osync) ; + ogg_stream_clear (&odata->ostream) ; + psf_fseek (psf, pos, SEEK_SET) ; + free (psf->container_data) ; + psf->container_data = NULL ; + psf->container_close = NULL ; + return flac_open (psf) ; + + case SF_FORMAT_OGG | SF_FORMAT_OPUS : + return ogg_opus_open (psf) ; + +#if ENABLE_EXPERIMENTAL_CODE + case SF_FORMAT_OGG | SF_FORMAT_SPEEX : + return ogg_speex_open (psf) ; + + case SF_FORMAT_OGG | SF_FORMAT_PCM_16 : + case SF_FORMAT_OGG | SF_FORMAT_PCM_24 : + return ogg_pcm_open (psf) ; +#endif + + default : + break ; + } ; + + psf_log_printf (psf, "%s : bad psf->sf.format 0x%x.\n", __func__, psf->sf.format) ; + return SFE_INTERNAL ; +} /* ogg_open */ + +/*============================================================================== +** Private functions. +*/ + +static int +ogg_close (SF_PRIVATE *psf) +{ OGG_PRIVATE* odata = psf->container_data ; + + ogg_sync_clear (&odata->osync) ; + ogg_stream_clear (&odata->ostream) ; + + return 0 ; +} /* ogg_close */ + +static int +ogg_stream_classify (SF_PRIVATE *psf, OGG_PRIVATE* odata) +{ int error ; + + /* Call this here so it only gets called once, so no memory is leaked. */ + ogg_sync_init (&odata->osync) ; + ogg_stream_init (&odata->ostream, 0) ; + + /* Load the first page in the physical bitstream. */ + if ((error = ogg_read_first_page (psf, odata)) != 0) + return error ; + + odata->codec = ogg_page_classify (psf, &odata->opage) ; + + switch (odata->codec) + { case OGG_VORBIS : + psf->sf.format = SF_FORMAT_OGG | SF_FORMAT_VORBIS ; + return 0 ; + + case OGG_FLAC : + case OGG_FLAC0 : + psf->sf.format = SF_FORMAT_OGGFLAC ; + return 0 ; + + case OGG_SPEEX : + psf->sf.format = SF_FORMAT_OGG | SF_FORMAT_SPEEX ; + return 0 ; + + case OGG_OPUS : + psf->sf.format = SF_FORMAT_OGG | SF_FORMAT_OPUS ; + return 0 ; + + case OGG_PCM : + psf_log_printf (psf, "Detected Ogg/PCM data. This is not supported yet.\n") ; + return SFE_UNIMPLEMENTED ; + + default : + break ; + } ; + + psf_log_printf (psf, "This Ogg bitstream contains some uknown data type.\n") ; + return SFE_UNIMPLEMENTED ; +} /* ogg_stream_classify */ + +/*============================================================================== +*/ + +static struct +{ const char *str, *name ; + int len, codec ; +} codec_lookup [] = +{ { "Annodex", "Annodex", 8, OGG_ANNODEX }, + { "AnxData", "AnxData", 7, OGG_ANXDATA }, + { "\177FLAC", "Flac1", 5, OGG_FLAC }, + { "fLaC", "Flac0", 4, OGG_FLAC0 }, + { "PCM ", "PCM", 8, OGG_PCM }, + { "Speex", "Speex", 5, OGG_SPEEX }, + { "\001vorbis", "Vorbis", 7, OGG_VORBIS }, + { "OpusHead", "Opus", 8, OGG_OPUS }, +} ; + +static int +ogg_page_classify (SF_PRIVATE * psf, const ogg_page * og) +{ int k, len ; + + for (k = 0 ; k < ARRAY_LEN (codec_lookup) ; k++) + { if (codec_lookup [k].len > og->body_len) + continue ; + + if (memcmp (og->body, codec_lookup [k].str, codec_lookup [k].len) == 0) + { psf_log_printf (psf, "Ogg stream data : %s\n", codec_lookup [k].name) ; + psf_log_printf (psf, "Stream serialno : %u\n", (uint32_t) ogg_page_serialno (og)) ; + return codec_lookup [k].codec ; + } ; + } ; + + len = og->body_len < 8 ? og->body_len : 8 ; + + psf_log_printf (psf, "Ogg_stream data : '") ; + for (k = 0 ; k < len ; k++) + psf_log_printf (psf, "%c", isprint (og->body [k]) ? og->body [k] : '.') ; + psf_log_printf (psf, "' ") ; + for (k = 0 ; k < len ; k++) + psf_log_printf (psf, " %02x", og->body [k] & 0xff) ; + psf_log_printf (psf, "\n") ; + + return 0 ; +} /* ogg_page_classify */ + +/* +** Scale x from the range [0, from] to the range [0, to] +*/ +static uint64_t +ogg_page_search_do_rescale (uint64_t x, uint64_t from, uint64_t to) +{ uint64_t frac ; + uint64_t ret ; + int i ; + + /* I should have paid more attention in CSc 349A: Numerical Analysis */ + if (x >= from) + return to ; + if (x == 0) + return 0 ; + frac = 0 ; + for (i = 0 ; i < 63 ; i++) + { frac <<= 1 ; + if (x >= from >> 1) + { x -= from - x ; + frac |= 1 ; + } + else + x <<= 1 ; + } + ret = 0 ; + for (i = 0 ; i < 63 ; i++) + { if (frac & 1) + ret = (ret & to & 1) + (ret >> 1) + (to >> 1) ; + else + ret >>= 1 ; + frac >>= 1 ; + } + return ret ; +} /* ogg_page_search_do_rescale */ + +static void +ogg_page_search_continued_data (OGG_PRIVATE *odata, ogg_page *page) +{ ogg_stream_pagein (&odata->ostream, page) ; + while (ogg_stream_packetout (&odata->ostream, &odata->opacket)) ; +} /* ogg_page_search_continued_data */ + +#else /* HAVE_EXTERNAL_XIPH_LIBS */ + +int +ogg_open (SF_PRIVATE *psf) +{ + psf_log_printf (psf, "This version of libsndfile was compiled without Ogg/Vorbis support.\n") ; + return SFE_UNIMPLEMENTED ; +} /* ogg_open */ + +#endif diff --git a/extern/libsndfile-modified/src/ogg.h b/extern/libsndfile-modified/src/ogg.h new file mode 100644 index 000000000..8b2927a90 --- /dev/null +++ b/extern/libsndfile-modified/src/ogg.h @@ -0,0 +1,169 @@ +/* +** Copyright (C) 2008-2011 Erik de Castro Lopo +** Copyright (C) 2018 Arthur Taylor +** +** This program is free software ; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation ; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY ; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program ; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef SF_SRC_OGG_H +#define SF_SRC_OGG_H + +enum +{ OGG_ANNODEX = 300, + OGG_ANXDATA, + OGG_FLAC, + OGG_FLAC0, + OGG_PCM, + OGG_SPEEX, + OGG_VORBIS, + OGG_OPUS, +} ; + +typedef struct +{ /* Sync and verify incoming physical bitstream */ + ogg_sync_state osync ; + /* Take physical pages, weld into a logical stream of packets */ + ogg_stream_state ostream ; + /* One Ogg bitstream page. Codec packets are inside */ + ogg_page opage ; + /* One raw packet of data for decode */ + ogg_packet opacket ; + + /* Unpacked packets. 255 is max there can ever be in one page. */ + ogg_packet pkt [255] ; + /* How many packets */ + int pkt_len ; + /* Current packet */ + int pkt_indx ; + + int eos ; + int codec ; +} OGG_PRIVATE ; + + +#define readint(buf, base) (((buf [base + 3] << 24) & 0xff000000) | \ + ((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 *) ; + +/* +** Write the whole Ogg page out. Convenience function as the ogg_page struct +** splits header and body data into separate buffers. +*/ +int ogg_write_page (SF_PRIVATE *, ogg_page *) ; + +/* +** Wrapper around psf_ftell() that returns the current offset in the file after +** the most recent page that has been returned by ogg_sync_pageout(). +*/ +sf_count_t ogg_sync_ftell (SF_PRIVATE *) ; + +/* +** Wrapper around psf_fseek() that on success resets the ogg_sync_state struct +** so that it doesn't get corrupted. +*/ +sf_count_t ogg_sync_fseek (SF_PRIVATE *, sf_count_t offset, int whence) ; + +/* +** Get the next page from the physical bitstream, reading in data as necessary. +** Pays no attention to Ogg BOS/EOS markers or stream serial numbers. +** The page is buffered in the ogg_sync_state struct, (replacing any other +** buffered there) and also returned in *og. readmax sets a boundary for how +** many bytes more may be read from the file, use already buffered only, or +** unlimited reading in the case of a positive, zero or negative argument +** respectively. If a pointer to a sf_count_t is passed in offset, then it will +** be incremented by how many bytes were skipped to find the next page header. +** (Useful for seeking, normally zero.) Returns the page size in bytes on +** success, 0 on out-of-data (be it end of file or readmax reached) and -1 on +** error with psf->error set appropriately. +*/ +int ogg_sync_next_page (SF_PRIVATE * psf, ogg_page *og, sf_count_t readmax, sf_count_t *offset) ; + +/* +** Load the last page of a stream before the provided file offset. Searches the +** physical bitstream, and selects a page of the passed serialno. The page +** found is loaded in the sync buffer and exposed in odata->opage, and not +** loaded into the ogg_stream_state. If found, the granulepos is returned in +** *gp_out. Returns the file offset *before* the last page on success, or -1 on +** error, setting psf->error as appropriate. +*/ +sf_count_t ogg_sync_last_page_before (SF_PRIVATE *psf, OGG_PRIVATE *odata, uint64_t *gp_out, sf_count_t offset, int32_t serialno) ; + +/* +** Load the next page from the virtual bitstream, reading data as necessary. +** Reads in pages from the physical bitstream, skipping pages until one of the +** virtual bitstream of interest is found, and then feeds it into the +** ogg_stream_state of odata->ostream, where it is buffered. Heeds EOS markers. +** Returns 1 on success, 0 on end of stream, and -1 on fatal error. +*/ +int ogg_stream_next_page (SF_PRIVATE * psf, OGG_PRIVATE *odata) ; + +/* +** Loads the next page using ogg_stream_next_page() and unpacks all packets +** into the array odata->pkt, updating odata->pkt_len and setting +** odata->pkt_indx to 0. Returns 1 if okay, 2 if okay but a hole was found +** in the bitstream, 0 if on end of stream, and -1 on fatal error. +*/ +int ogg_stream_unpack_page (SF_PRIVATE *psf, OGG_PRIVATE *odata) ; + +/* +** Seek within the Ogg virtual bitstream for a page containing target_gp. +** 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 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 gp_rate) ; + +#endif /* SF_SRC_OGG_H */ diff --git a/extern/libsndfile-modified/src/ogg_opus.c b/extern/libsndfile-modified/src/ogg_opus.c new file mode 100644 index 000000000..c9383624c --- /dev/null +++ b/extern/libsndfile-modified/src/ogg_opus.c @@ -0,0 +1,1823 @@ +/* +** Copyright (C) 2013-2020 Erik de Castro Lopo +** Copyright (C) 2018 Arthur Taylor +** +** This program is free software ; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation ; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY ; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program ; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/* +** This file contains code based on OpusFile and Opus-Tools, both by +** Xiph.Org. COPYING from each is identical and is as follows: +** +** Copyright (c) 1994-2013 Xiph.Org Foundation and contributors +** +** 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. +*/ + +/* +** TODO: +** - Channel mapping modification / reporting +** - connect psf->channel_map and Opus channel mapping somehow? +** - Gain parameters and their mappings +*/ + +/* +** Opus Sample, Frame, and Samples/Channel Terminology +** +** libsndfile refers to one PCM value as a 'sample,' and a group of samples of +** the same sample time, one for each channel, as a 'frame.' This differs from +** Opus, which has no corresponding name for sample, and refers to a group of +** PCM values, one per channel (aka libsndfile frames) as 'samples.' +** Further, Opus has an object called a 'frame' that is made up of multiple +** Opus-samples. +** All this means that one has to be careful with what is meant by each term. +** In an attempt to avoid ambiguity, this file adopts the following terms: +** - Samples shall refer to discrete PCM values, regardless of any channel +** considerations. This is the same as what libsndfile calls samples. +** - Samples/channel shall refer to groups of samples, one for each channel. +** This is what Opus calles samples, and what libsndfile calles frames. It +** has the advantage that its name is also the formula to calculate it. +** +** +** Opus vs OggOpus +** +** In this file a distinction is made between Opus and OggOpus. Opus refers to +** the codec alone, support for which is by libopus. OggOpus refers to an Opus +** payload encapsulated in an Ogg stream. This is also know as an "Opus file." +** The OggOpus spec includes information on header and granule position +** interpretation, which is outside of the scope of the Opus spec. As such, an +** attempt here is made to refer to either Opus or OggOpus depending on which +** spec is being referenced. See https://wiki.xiph.org/OggOpus +** +** +** Opus Sample Rates +** +** Opus only supports a fixed number of sample rates: 48kHz, 24kHz, 16kHz, +** 12kHz, 8kHz. Audio may be decoded or encoded at any of these rates, +** independent of the rate it was encoded at or to be decoded at respectively. +** Other sample rates must be converted to one of these rates. +** +** As 44.1kHz (CD sample rate) and 22.5kHz are popular sample rates, and to +** support any other sample rate there may be, the Opus header includes a field +** to save the input (original) sample rate before converting it to a supported +** one. Implementations are recommended by the Opus spec to do a sample rate +** conversion at encode, but decode at 48kHz if outputting to hardware, or do +** the reverse sample rate conversion if outputting to file. +** +** Heretofore libsndfile does not contain a sample rate converter, so doing the +** sample rate conversion is not supported. Instead audio must be provided by +** the user at a supported rate. However, the input sample rate field can be +** set and retrieved by the user using sf_command(). At decode we choose to +** decode at the lowest valid rate that is greater than or equal to the input +** sample rate. +** +** +** OggOpus Granule Positions +** +** Ogg streams include a strictly increasing granule position value. The +** interpretation of this value is dependent on the payload type. For Opus +** streams the granule position is the count of samples in the stream when +** encoding/decoding at 48kHz. Note that the actual position of the output +** sample relative to the granule position is offset by the preskip amount. +** That is, if a packet ends with a granule position of x, the last sample +** output when decoding is actually sample (x - preskip). +** +** Further, to allow for clipping off of the front of a stream without +** rewriting all following granule positions, an Opus stream granule position +** may be offset by a constant amount. This amount is evident by comparing the +** granule position of the first page of an Opus stream on which an audio +** packet completes is greater than the sum of the samples of all audio +** packets completed on the page. Only the first such page is allows to have an +** 'excessive' granule position, and only if it is not also the last page of +** the stream (e_o_s bit is not set.) +** +** The granule position is an unsigned 64-bit integer, with the special value +** of UINT64_MAX/-1 being treated as invalid. However, as not all platforms +** support unsigned 64-bit integers, libOgg uses signed 64-bit integers for the +** granule position. +** +** Remembering that signed integer overflow/underflow is explicitly undefined +** in C, and as we already assume support for unsigned 64-bit integers, the +** easiest way to deal with this problem is to modify granule positions as +** unsigned integers. +*/ + + +#include "sfconfig.h" + +#include +#include +#include +#include +#include +#include + +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + +#if HAVE_EXTERNAL_XIPH_LIBS + +#include +#include +#include + +#include "ogg.h" +#include "ogg_vcomment.h" + +#define OGG_OPUS_COMMENT_PAD (512) /* Same as oggenc default */ + +/* +** 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) + +/* +** 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 (660 * 48) /* 660 milliseconds (33 packets of 20ms) */ + +typedef struct +{ uint8_t version ; + + /* Number of channels, 1...255 */ + uint8_t channels ; + + /* Encoder latency, the amount to skip before valid data comes out. */ + uint16_t preskip ; + + /* The sample rate of a the encoded source, as it may have been converted. */ + int32_t input_samplerate ; + + /* 'baked-in' gain to apply, dB S7.8 format. Should be zero when possible. */ + int16_t gain ; + + /* Channel mapping type. See OggOpus spec */ + uint8_t channel_mapping ; + + /* The rest is only used if channel_mapping != 0 */ + /* How many streams are there? */ + uint8_t nb_streams ; + + /* How man of those streams are coupled? (aka stereo) */ + uint8_t nb_coupled ; + + /* Mapping of opus streams to output channels */ + uint8_t stream_map [255] ; +} OpusHeader ; + +typedef struct +{ uint32_t serialno ; + OpusHeader header ; + + /* Encode: Granule position after the previous packet. + * Decode: Granule position after the current packet */ + uint64_t pkt_pos ; + + /* 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 */ + int sr_factor ; + + /* Current position in buffer expressed as samples/channel */ + int loc ; + + /* Current data fill (decode) or target (encode) of buffer expressed in samples/channel */ + int len ; + + /* Size of the buffer storage, in sizeof (float) * channels */ + int buffersize ; + + /* Samples, either decoded from a packet, or assembling for encode. */ + float *buffer ; + + union { + /* decode only members */ + struct { + OpusMSDecoder *state ; + uint64_t gp_start ; + uint64_t gp_end ; + sf_count_t last_offset ; + } decode ; + + /* encode only members */ + struct { + OpusMSEncoder *state ; + + /* How many Ogg page segments are in Ogg page currently being assembled. */ + int last_segments ; + + int bitrate ; + unsigned long latency ; + + /* Least significant bit of the source (aka bitwidth) */ + int lsb ; + int lsb_last ; + } encode ; + } u ; +} OPUS_PRIVATE ; + +/*----------------------------------------------------------------------------------------------- +** Private function prototypes. +*/ + +static int ogg_opus_close (SF_PRIVATE *psf) ; +static void opus_print_header (SF_PRIVATE *psf, OpusHeader *h) ; +static int opus_read_header_packet (SF_PRIVATE *psf, OpusHeader *h, ogg_packet *opacket) ; +static int ogg_opus_read_header (SF_PRIVATE * psf) ; +static int ogg_opus_setup_decoder (SF_PRIVATE *psf, int input_samplerate) ; + +static int ogg_opus_setup_encoder (SF_PRIVATE *psf, OGG_PRIVATE *odata, OPUS_PRIVATE *oopus) ; +static int ogg_opus_write_header (SF_PRIVATE * psf, int calc_length) ; +static void ogg_opus_flush (SF_PRIVATE *psf) ; +static int ogg_opus_unpack_next_page (SF_PRIVATE *psf, OGG_PRIVATE *odata, OPUS_PRIVATE *oopus) ; +static int ogg_opus_calculate_page_duration (OGG_PRIVATE *odata) ; +static int ogg_opus_read_refill (SF_PRIVATE *psf, OGG_PRIVATE *odata, OPUS_PRIVATE *oopus) ; +static int ogg_opus_write_out (SF_PRIVATE *psf, OGG_PRIVATE *odata, OPUS_PRIVATE *oopus) ; + +static sf_count_t ogg_opus_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; +static sf_count_t ogg_opus_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; +static sf_count_t ogg_opus_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; +static sf_count_t ogg_opus_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; + +static sf_count_t ogg_opus_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; +static sf_count_t ogg_opus_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; +static sf_count_t ogg_opus_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; +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_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) ; +static int ogg_opus_byterate (SF_PRIVATE *psf) ; + +/*----------------------------------------------------------------------------------------------- +*/ + +static vorbiscomment_ident opustags_ident = { "OpusTags", 8 } ; + +/*----------------------------------------------------------------------------------------------- +** Exported functions. +*/ + +int +ogg_opus_open (SF_PRIVATE *psf) +{ OGG_PRIVATE* odata = psf->container_data ; + OPUS_PRIVATE* oopus = calloc (1, sizeof (OPUS_PRIVATE)) ; + int error = 0 ; + + if (odata == NULL) + { psf_log_printf (psf, "%s : odata is NULL???\n", __func__) ; + free (oopus) ; + return SFE_INTERNAL ; + } ; + + psf->codec_data = oopus ; + if (oopus == NULL) + return SFE_MALLOC_FAILED ; + + if (psf->file.mode == SFM_RDWR) + return SFE_BAD_MODE_RW ; + + psf_log_printf (psf, "Opus library version: %s\n", opus_get_version_string ()) ; + + psf->codec_close = ogg_opus_close ; + if (psf->file.mode == SFM_READ) + { if ((error = ogg_opus_read_header (psf))) + return error ; + if ((error = ogg_opus_analyze_file (psf))) + return error ; + + psf->read_short = ogg_opus_read_s ; + psf->read_int = ogg_opus_read_i ; + psf->read_float = ogg_opus_read_f ; + psf->read_double = ogg_opus_read_d ; + } ; + + if (psf->file.mode == SFM_WRITE) + { if ((error = ogg_opus_setup_encoder (psf, odata, oopus))) + return error ; + + psf->write_header = ogg_opus_write_header ; + psf->write_short = ogg_opus_write_s ; + psf->write_int = ogg_opus_write_i ; + psf->write_float = ogg_opus_write_f ; + psf->write_double = ogg_opus_write_d ; + + psf->sf.frames = SF_COUNT_MAX ; /* Unknown really */ + psf->strings.flags = SF_STR_ALLOW_START ; + psf->datalength = 0 ; + psf->dataoffset = 0 ; /* will be updated */ + } ; + + psf->seek = ogg_opus_seek ; + psf->command = ogg_opus_command ; + psf->byterate = ogg_opus_byterate ; + psf->sf.format = SF_FORMAT_OGG | SF_FORMAT_OPUS ; + + return error ; +} /* ogg_opus_open */ + +/*============================================================================== +** Private functions. +*/ + +static int +ogg_opus_close (SF_PRIVATE *psf) +{ OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; + OPUS_PRIVATE *oopus = (OPUS_PRIVATE *) psf->codec_data ; + + if (!oopus) + return 0 ; + + if (psf->file.mode == SFM_WRITE) + { if (psf->have_written) + ogg_opus_flush (psf) ; + else { + /* Write a header... it is expected. */ + ogg_opus_write_header (psf, 0) ; + } ; + ogg_packet_clear (&odata->opacket) ; + if (oopus->u.encode.state) + { opus_multistream_encoder_destroy (oopus->u.encode.state) ; + oopus->u.encode.state = NULL ; + } ; + } + else if (psf->file.mode == SFM_READ) + { if (oopus->u.decode.state) + { opus_multistream_decoder_destroy (oopus->u.decode.state) ; + oopus->u.decode.state = NULL ; + } ; + } ; + + psf->codec_data = NULL ; + if (oopus->buffer) + free (oopus->buffer) ; + free (oopus) ; + + return 0 ; +} /* ogg_opus_close */ + +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", (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", (int) h->channel_mapping) ; break ; + } ; + + if (h->channel_mapping > 0) + { int i ; + 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,", (int) (h->stream_map [i])) ; + psf_log_printf (psf, "%d]\n", (int) (h->stream_map [i])) ; + } ; +} /* opus_print_header */ + +static int +opus_read_header_packet (SF_PRIVATE *psf, OpusHeader *h, ogg_packet *opacket) +{ int count, i ; + + /* + ** Opus headers are 19 bytes, in the case of type 0 channel mapping, + ** or 19 + 2 + (1 * channel count) bytes for other channel mappings, to a + ** maximum of 276 (255 channels). + */ + + if (opacket->bytes < 19 || opacket->bytes > 276) + return SFE_MALFORMED_FILE ; + + if (memcmp (opacket->packet, "OpusHead", 8) != 0) + return SFE_MALFORMED_FILE ; + + /* + ** Copy the header page into the binheader so we can use binheader + ** functions to safely unpack it. + */ + count = psf_binheader_writef (psf, "ob", BHWo (0), BHWv (opacket->packet), BHWz (opacket->bytes)) ; + psf->header.end = count ; + + 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", (int) h->version) ; + return SFE_UNIMPLEMENTED ; + } ; + + count += psf_binheader_readf (psf, "e12421", &h->channels, &h->preskip, + &h->input_samplerate, &h->gain, &h->channel_mapping) ; + + if (h->channel_mapping == 0) + { if (h->channels > 2) + return SFE_MALFORMED_FILE ; + + /* + ** Setup the stream mapping, so we can use the multistream decoder, + ** rather than have to deal with two decoder pointer types + */ + h->nb_streams = 1 ; + h->nb_coupled = h->channels - 1 ; + h->stream_map [0] = 0 ; + h->stream_map [1] = 1 ; + } + else + { if (opacket->bytes < 19 + 2 + h->channels) + return SFE_MALFORMED_FILE ; + + if (h->channel_mapping == 1 && h->channels > 8) + return SFE_MALFORMED_FILE ; + + count += psf_binheader_readf (psf, "11", &h->nb_streams, &h->nb_coupled) ; + + if (h->nb_streams < 1 || + h->nb_coupled > h->nb_streams || + h->nb_coupled + h->nb_streams > 255) + return SFE_MALFORMED_FILE ; + + for (i = 0 ; i < h->channels ; i++) + { count += psf_binheader_readf (psf, "1", &(h->stream_map [i])) ; + if (h->stream_map [i] > h->nb_streams + h->nb_coupled && h->stream_map [i] != 255) + return SFE_MALFORMED_FILE ; + } ; + } ; + + if (count != opacket->bytes) + { /* OggOpus spec mandates that this is a hard error. */ + psf_log_printf (psf, "Opus : Error, extra data in Ogg Opus header.\n") ; + return SFE_MALFORMED_FILE ; + } ; + + opus_print_header (psf, h) ; + + return 0 ; +} /* ogg_opus_read_header_packet */ + +static int +ogg_opus_read_header (SF_PRIVATE *psf) +{ OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; + OPUS_PRIVATE *oopus = (OPUS_PRIVATE *) psf->codec_data ; + int error ; + + /* + ** First page is already loaded by the ogg container code when it + ** classified the stream, no need to re-load it now. + */ + + if (ogg_page_packets (&odata->opage) != 1 || !ogg_page_bos (&odata->opage)) + return SFE_MALFORMED_FILE ; + + oopus->serialno = ogg_page_serialno (&odata->opage) ; + if ((error = opus_read_header_packet (psf, &oopus->header, &odata->opacket))) + return error ; + + /* + ** The comment header MUST be next. It is one packet, that packet MUST begin + ** on the second page of the stream, but it MAY span multiple pages. + */ + + while (ogg_stream_packetout (&odata->ostream, &odata->opacket) != 1) + { if (ogg_stream_next_page (psf, odata) != 1) + { /* out of data... technically that's malformed. */ + return psf->error ? psf->error : SFE_MALFORMED_FILE ; + } ; + } ; + + if ((error = vorbiscomment_read_tags (psf, &odata->opacket, &opustags_ident))) + return error ; + + return ogg_opus_setup_decoder (psf, oopus->header.input_samplerate) ; +} /* ogg_opus_read_header */ + +static int +ogg_opus_setup_decoder (SF_PRIVATE *psf, int input_samplerate) +{ OPUS_PRIVATE *oopus = (OPUS_PRIVATE *) psf->codec_data ; + OpusMSDecoder *decoder ; + int sr_factor ; + int error ; + + /* + ** Decide what sample rate to decode at. We choose the lowest valid rate + ** that is greater or equal to the original rate. + ** + ** Opus documentation recommends always decoding at 48000Hz if the file is + ** being decoded for playback, since most hardware will resample it back to + ** 48000Hz anyways. We don't know if that's true, maybe the user is + ** decoding for editing or transcoding purposes. + */ + if (input_samplerate > 24000) + sr_factor = 1 ; + else if (input_samplerate > 16000) + sr_factor = 2 ; + else if (input_samplerate > 12000) + sr_factor = 3 ; + else if (input_samplerate > 8000) + sr_factor = 4 ; + else + sr_factor = 6 ; + + decoder = opus_multistream_decoder_create ( + 48000 / sr_factor, + oopus->header.channels, + oopus->header.nb_streams, + oopus->header.nb_coupled, + oopus->header.stream_map, + &error) ; + + if (error != OPUS_OK) + { psf_log_printf (psf, "Opus : Failed to create multistream decoder: %s\n", + opus_strerror (error)) ; + return SFE_INTERNAL ; + } + + /* + ** Replace the decoder, if one was already initialized (see + ** SFC_GET_ORIGINAL_SAMPLERATE) + */ + if (oopus->u.decode.state) + opus_multistream_decoder_destroy (oopus->u.decode.state) ; + oopus->u.decode.state = decoder ; + + oopus->sr_factor = sr_factor ; + psf->sf.samplerate = 48000 / sr_factor ; + psf->sf.channels = oopus->header.channels ; + oopus->loc = oopus->len = 0 ; + + /* + ** The Opus decoder can do our gain for us. The OggOpus header contains a + ** gain field. This field, unlike various gain-related tags, is intended to + ** be a perminent baked-in gain applied before any user-configurable gain + ** (eg replay-gain.) This is so the gain of track can be set without having + ** to re-encode. + ** + ** Both the header.gain field and the parameter are in the Q7.8 format. + ** + ** TODO: Make this configurable? Include other gain sources too? + */ + opus_multistream_decoder_ctl (oopus->u.decode.state, OPUS_SET_GAIN (oopus->header.gain)) ; + + /* + ** Opus packets can vary in length, with the legal values being 2.5, 5, 10, + ** 20, 40 or 60ms. The recommended default for non-realtime is 20ms. As + ** such, allocate a buffer of that size now, we'll realloc later if a + ** larger one is needed. + ** + ** buffersize is expressed in samples/channel, as that is what opus_decode + ** expects. + */ + if (oopus->buffer) + { free (oopus->buffer) ; + oopus->buffer = NULL ; + } ; + oopus->buffersize = 20 * psf->sf.samplerate / 1000 ; + oopus->buffer = malloc (sizeof (float) * psf->sf.channels * oopus->buffersize) ; + if (oopus->buffer == NULL) + return SFE_MALLOC_FAILED ; + + return 0 ; +} /* ogg_opus_setup_decoder */ + +static int +ogg_opus_setup_encoder (SF_PRIVATE *psf, OGG_PRIVATE *odata, OPUS_PRIVATE *oopus) +{ int error ; + int lookahead ; + int nb_streams ; + int nb_coupled ; + + /* default page latency value (1000ms) */ + oopus->u.encode.latency = 1000 * 48 ; + + switch (psf->sf.samplerate) + { case 8000 : + case 12000 : + case 16000 : + case 24000 : + case 48000 : + oopus->sr_factor = 48000 / psf->sf.samplerate ; + break ; + default : + return SFE_OPUS_BAD_SAMPLERATE ; + } ; + + if (psf->sf.channels <= 2) + { oopus->header.channel_mapping = 0 ; + nb_streams = 1 ; + nb_coupled = psf->sf.channels - 1 ; + oopus->header.stream_map [0] = 0 ; + oopus->header.stream_map [1] = 1 ; + + oopus->u.encode.state = opus_multistream_encoder_create ( + psf->sf.samplerate, + psf->sf.channels, + nb_streams, + nb_coupled, + oopus->header.stream_map, + OPUS_APPLICATION_AUDIO, + &error) ; + } + else + { if (psf->sf.channels <= 8) + { /* Use Vorbis/AC3 channel mappings for surround. */ + oopus->header.channel_mapping = 1 ; + } + else + { /* There is no channel mapping, just audio, in parallel, good luck */ + oopus->header.channel_mapping = 255 ; + } + + oopus->u.encode.state = opus_multistream_surround_encoder_create ( + psf->sf.samplerate, + psf->sf.channels, + oopus->header.channel_mapping, + &nb_streams, + &nb_coupled, + oopus->header.stream_map, + OPUS_APPLICATION_AUDIO, + &error) ; + + } + + if (error != OPUS_OK) + { psf_log_printf (psf, "Opus : Error, opus_multistream_encoder_create returned %s\n", opus_strerror (error)) ; + return SFE_BAD_OPEN_FORMAT ; + } ; + oopus->header.nb_streams = nb_streams ; + oopus->header.nb_coupled = nb_coupled ; + + opus_multistream_encoder_ctl (oopus->u.encode.state, OPUS_GET_BITRATE (&oopus->u.encode.bitrate)) ; + psf_log_printf (psf, "Encoding at target bitrate of %dbps\n", oopus->u.encode.bitrate) ; + + /* TODO: Make configurable? */ + error = opus_multistream_encoder_ctl (oopus->u.encode.state, OPUS_SET_COMPLEXITY (10)) ; + if (error != OPUS_OK) + { /* Non-fatal */ + psf_log_printf (psf, "Opus : OPUS_SET_COMPLEXITY returned: %s\n", opus_strerror (error)) ; + } + + /* + ** Get the encoder delay. This can vary depending on implementation and + ** encoder configuration. + ** GOTCHA: This returns the preskip at the encoder samplerate, not the + ** granulepos rate of 48000Hz needed for header.preskip. + */ + error = opus_multistream_encoder_ctl (oopus->u.encode.state, OPUS_GET_LOOKAHEAD (&lookahead)) ; + if (error != OPUS_OK) + { psf_log_printf (psf, "Opus : OPUS_GET_LOOKAHEAD returned: %s\n", opus_strerror (error)) ; + return SFE_BAD_OPEN_FORMAT ; + } ; + oopus->header.preskip = lookahead * oopus->sr_factor ; + + oopus->len = OGG_OPUS_ENCODE_PACKET_LEN (psf->sf.samplerate) ; + oopus->buffer = malloc (sizeof (float) * psf->sf.channels * oopus->len) ; + if (oopus->buffer == NULL) + return SFE_MALLOC_FAILED ; + + /* + ** Set up the resident ogg packet structure, ready for writing into. + ** 1275 * 3 + 7 bytes of packet per stream is from opusenc from opus-tools + */ + ogg_packet_clear (&odata->opacket) ; + oopus->buffersize = (1275 * 3 + 7) * oopus->header.nb_streams ; + odata->opacket.packet = malloc (oopus->buffersize) ; + odata->opacket.packetno = 2 ; + if (odata->opacket.packet == NULL) + return SFE_MALLOC_FAILED ; + + oopus->serialno = psf_rand_int32 () ; + ogg_stream_init (&odata->ostream, oopus->serialno) ; + + return 0 ; +} /* ogg_opus_setup_encoder */ + +static int +ogg_opus_write_header (SF_PRIVATE *psf, int UNUSED (calc_length)) +{ OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; + OPUS_PRIVATE *oopus = (OPUS_PRIVATE *) psf->codec_data ; + int nn ; + ogg_packet op ; + + oopus->header.version = 1 ; + oopus->header.channels = psf->sf.channels ; + + /* FIXME: Allow the user to set this ?! */ + oopus->header.gain = 0 ; + + if (psf->dataoffset > 0) + { if (psf->have_written) + { /* + ** Might be possible to deal with this, but it's difficult as we + ** have to take Ogg Page header sizes in to account, not just + ** packet sizes. + */ + return SFE_UNIMPLEMENTED ; + } + if (psf_is_pipe (psf)) + return SFE_NOT_SEEKABLE ; + if (psf_fseek (psf, 0, SEEK_SET) < 0) + return SFE_SEEK_FAILED ; + ogg_stream_reset_serialno (&odata->ostream, oopus->serialno) ; + psf->dataoffset = 0 ; + } + else + opus_print_header (psf, &oopus->header) ; + + psf->header.ptr [0] = 0 ; + psf->header.indx = 0 ; + + /* Opus Header Marker */ + psf_binheader_writef (psf, "eb", BHWv ("OpusHead"), BHWz (8)) ; + + /* Ogg Embedding scheme version, Channel Count, Preskip Samples */ + psf_binheader_writef (psf, "e112", BHW1 (oopus->header.version), BHW1 (psf->sf.channels), BHW2 (oopus->header.preskip)) ; + + /* + ** If an original samplerate has not been set by the user command + ** SFC_SET_ORIGINAL_SAMPLERATE, write the current samplerate. + */ + if (oopus->header.input_samplerate) + psf_binheader_writef (psf, "e4", BHW4 (oopus->header.input_samplerate)) ; + else + psf_binheader_writef (psf, "e4", BHW4 (psf->sf.samplerate)) ; + + /* Input Sample Rate, Gain (S7.8 format), Channel Mapping Type */ + psf_binheader_writef (psf, "e21", BHW2 (oopus->header.gain), BHW1 (oopus->header.channel_mapping)) ; + + /* Channel mappings, required if not using type 0 (mono/stereo) */ + if (oopus->header.channel_mapping > 0) + { psf_binheader_writef (psf, "11", BHW1 (oopus->header.nb_streams), BHW1 (oopus->header.nb_coupled)) ; + for (nn = 0 ; nn < oopus->header.channels ; nn++) + psf_binheader_writef (psf, "1", BHW1 (oopus->header.stream_map [nn])) ; + } ; + + op.packet = psf->header.ptr ; + op.bytes = psf->header.indx ; + op.b_o_s = 1 ; + op.e_o_s = 0 ; + op.granulepos = 0 ; + op.packetno = 1 ; + + /* The first page MUST only contain the header, so flush it out now */ + ogg_stream_packetin (&odata->ostream, &op) ; + for ( ; (nn = ogg_stream_flush (&odata->ostream, &odata->opage)) ; ) + { if (! (nn = ogg_write_page (psf, &odata->opage))) + { psf_log_printf (psf, "Opus : Failed to write header!\n") ; + if (psf->error) + return psf->error ; + return SFE_INTERNAL ; + } ; + psf->dataoffset += nn ; + } + + /* + ** Metadata Tags (manditory) + ** + ** All tags must be in one packet, which may span pages, and these pages + ** must not contain any other packets, so flush. The vendor string should + ** be the libopus library version, as it is doing the actual encoding. We + ** put the libsndfile identifier in the ENCODER tag. + ** + ** See: https://wiki.xiph.org/VorbisComment#ENCODER + */ + vorbiscomment_write_tags (psf, &op, &opustags_ident, opus_get_version_string (), - (OGG_OPUS_COMMENT_PAD)) ; + op.packetno = 2 ; + ogg_stream_packetin (&odata->ostream, &op) ; + for ( ; (nn = ogg_stream_flush (&odata->ostream, &odata->opage)) ; ) + { if (! (nn = ogg_write_page (psf, &odata->opage))) + { psf_log_printf (psf, "Opus : Failed to write comments!\n") ; + if (psf->error) + return psf->error ; + return SFE_INTERNAL ; + } ; + psf->dataoffset += nn ; + } + + return 0 ; +} /* ogg_opus_write_header */ + +static void +ogg_opus_flush (SF_PRIVATE *psf) +{ OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; + OPUS_PRIVATE *oopus = (OPUS_PRIVATE *) psf->codec_data ; + uint64_t last_granulepos ; + int nbytes ; + int len ; + int last_packet ; + + /* + ** Need to flush both samples waiting for a complete packet and samples + ** currently 'inside' the encoder because of its latency. In the case of + ** the latter, we need to encode an equivalent amount of silence to push + ** them out. + ** + ** Note that the last packet's granule position might be less than the + ** total number of samples completed in it. This is how Ogg embedded Opus + ** encodes the amount of appended padding to truncate for gapless playback. + */ + + last_granulepos = oopus->pkt_pos + (oopus->sr_factor * oopus->loc) + oopus->header.preskip ; + last_packet = SF_FALSE ; + memset (&(oopus->buffer [oopus->loc * psf->sf.channels]), 0, sizeof (float) * psf->sf.channels * (oopus->len - oopus->loc)) ; + + for (last_packet = SF_FALSE ; last_packet == SF_FALSE ; ) + { oopus->pkt_pos += oopus->len * oopus->sr_factor ; + if (oopus->pkt_pos >= last_granulepos) + { last_packet = SF_TRUE ; + /* + ** Try to shorten the last packet to the smallest valid packet size + ** to minimize padding samples. + */ + len = (oopus->len * oopus->sr_factor) - (oopus->pkt_pos - last_granulepos) ; + if (len <= 120) /* 2.5 ms */ + len = 120 / oopus->sr_factor ; + else if (len <= 240) /* 5 ms */ + len = 240 / oopus->sr_factor ; + else if (len <= 480) /* 10 ms */ + len = 480 / oopus->sr_factor ; + else + len = oopus->len ; + } + else + len = oopus->len ; + + nbytes = opus_multistream_encode_float (oopus->u.encode.state, oopus->buffer, + len, odata->opacket.packet, oopus->buffersize) ; + + if (nbytes < 0) + { psf_log_printf (psf, "Opus : opus_multistream_encode_float returned: %s\n", opus_strerror (nbytes)) ; + break ; + } + + odata->opacket.bytes = nbytes ; + odata->opacket.packetno++ ; + if (last_packet) + { odata->opacket.granulepos = (ogg_int64_t) last_granulepos ; + odata->opacket.e_o_s = 1 ; + } + else + odata->opacket.granulepos = (ogg_int64_t) oopus->pkt_pos ; + + ogg_stream_packetin (&odata->ostream, &odata->opacket) ; + while (ogg_stream_pageout (&odata->ostream, &odata->opage)) + ogg_write_page (psf, &odata->opage) ; + } ; + + while (ogg_stream_flush (&odata->ostream, &odata->opage)) + ogg_write_page (psf, &odata->opage) ; +} /* ogg_opus_flush */ + +static int +ogg_opus_calculate_page_duration (OGG_PRIVATE *odata) +{ int i, samples, duration ; + ogg_packet *ppkt ; + + duration = 0 ; + for (i = 0 , ppkt = odata->pkt ; i < odata->pkt_len ; i++, ppkt++) + { /* Use 48kHz to get the sample count for use with granule positions. */ + samples = opus_packet_get_nb_samples (ppkt->packet, ppkt->bytes, 48000) ; + if (samples > 0) + duration += samples ; + } ; + return duration ; +} /* ogg_opus_calculate_page_duration */ + +static int +ogg_opus_unpack_next_page (SF_PRIVATE *psf, OGG_PRIVATE *odata, OPUS_PRIVATE *oopus) +{ int nn ; + + nn = ogg_stream_unpack_page (psf, odata) ; + + if (nn == 1) + { oopus->pkt_pos = oopus->pg_pos ; + oopus->pg_pos = odata->pkt [odata->pkt_len - 1].granulepos ; + } + else if (nn == 2) + { uint64_t gp, last_page ; + + /* Found a hole. Need to recalculated pkt_pos from pg_pos */ + last_page = oopus->pg_pos ; + 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) / (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 + ** PLC by generating white-noise for the duration of the hole. That is + ** the correct thing for use in telephony, but it isn't generally + ** appropriate here. It actually sounds better with no PLC, as the + ** lapped nature of full-width Opus means the two edges of the hole + ** will be blended together. + */ + return 1 ; + } + + return nn ; +} /* ogg_opus_unpack_next_page */ + +static int +ogg_opus_read_refill (SF_PRIVATE *psf, OGG_PRIVATE *odata, OPUS_PRIVATE *oopus) +{ uint64_t pkt_granulepos ; + int nn, nsamp ; + ogg_packet *ppkt ; + + if (odata->pkt_indx == odata->pkt_len) + { nn = ogg_opus_unpack_next_page (psf, odata, oopus) ; + if (nn <= 0) + return nn ; + } + + if (odata->pkt_indx == odata->pkt_len) + return 0 ; + + ppkt = odata->pkt + odata->pkt_indx ; + nsamp = opus_multistream_decode_float (oopus->u.decode.state, + ppkt->packet, ppkt->bytes, oopus->buffer, oopus->buffersize, 0) ; + + if (nsamp == OPUS_BUFFER_TOO_SMALL) + { nsamp = opus_packet_get_nb_samples (ppkt->packet, ppkt->bytes, psf->sf.samplerate) ; + psf_log_printf (psf, "Growing decode buffer to hold %d samples from %d\n", + nsamp, oopus->buffersize) ; + if (nsamp > 5760) + { psf_log_printf (psf, "Packet is larger than maximum allowable of 120ms!? Skipping.\n") ; + return 0 ; + } ; + oopus->buffersize = nsamp ; + + free (oopus->buffer) ; + oopus->buffer = NULL ; + oopus->buffer = malloc (sizeof (float) * oopus->buffersize * psf->sf.channels) ; + if (oopus->buffer == NULL) + { psf->error = SFE_MALLOC_FAILED ; + oopus->buffersize = 0 ; + return -1 ; + } ; + + nsamp = opus_multistream_decode_float (oopus->u.decode.state, + ppkt->packet, ppkt->bytes, oopus->buffer, oopus->buffersize, 0) ; + } ; + odata->pkt_indx ++ ; + + if (nsamp < 0) + { psf_log_printf (psf, "Opus : opus_multistream_decode returned: %s\n", + opus_strerror (nsamp)) ; + psf->error = SFE_INTERNAL ; + return nsamp ; + } ; + + /* + ** Check for if this decoded packet is the last of the stream, in + ** which case a page granule position which is shorter than the + ** sample count of all packets in the page indicates that the last + ** samples are padding and should be dropped. + */ + pkt_granulepos = oopus->pkt_pos + (nsamp * oopus->sr_factor) ; + if (pkt_granulepos <= oopus->pg_pos) + { oopus->len = nsamp ; + } + else + { if (ogg_page_eos (&odata->opage)) + { /* + ** Possible for pg_pos < pkt_pos if there is a trailing + ** packet. It's not supposed to happen, but could. + */ + oopus->len = SF_MAX ((int) (oopus->pg_pos - oopus->pkt_pos) / oopus->sr_factor, 0) ; + } + else + { /* + ** From https://wiki.xiph.org/OggOpus#Granule_Position + ** A decoder MUST reject as invalid any stream where the granule + ** position is smaller than the number of samples contained in + ** packets that complete on the first page with a completed + ** packet, unless that page has the 'end of stream' flag set. It + ** MAY defer this action until it decodes the last packet + ** completed on that page. + */ + 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 ; + } ; + } ; + + if (oopus->len > oopus->buffersize) + { free (oopus->buffer) ; + oopus->buffersize = oopus->len ; + oopus->buffer = malloc (sizeof (float) * oopus->buffersize * psf->sf.channels) ; + if (oopus->buffer == NULL) + { psf->error = SFE_MALLOC_FAILED ; + oopus->buffersize = 0 ; + return -1 ; + } ; + } ; + + /* + ** Check for if this decoded packet contains samples from before the pre- + ** skip point, indicating that these samples are padding to get the decoder + ** to converge and should be dropped. + */ + if (oopus->pkt_pos < (unsigned) oopus->header.preskip) + oopus->loc = SF_MIN ((oopus->header.preskip - (int) oopus->pkt_pos) / oopus->sr_factor, oopus->len) ; + else + oopus->loc = 0 ; + + oopus->pkt_pos = pkt_granulepos ; + + return nsamp ; +} /* ogg_opus_read_refill */ + +static int +ogg_opus_write_out (SF_PRIVATE *psf, OGG_PRIVATE *odata, OPUS_PRIVATE *oopus) +{ int nbytes ; + + if (oopus->u.encode.lsb != oopus->u.encode.lsb_last) + opus_multistream_encoder_ctl (oopus->u.encode.state, OPUS_SET_LSB_DEPTH (oopus->u.encode.lsb)) ; + + nbytes = opus_multistream_encode_float (oopus->u.encode.state, + oopus->buffer, oopus->len, + odata->opacket.packet, oopus->buffersize) ; + + if (nbytes < 0) + { psf_log_printf (psf, "Opus : Error, opus_multistream_encode_float returned: %s\n", opus_strerror (nbytes)) ; + psf->error = SFE_INTERNAL ; + return nbytes ; + } ; + + oopus->u.encode.last_segments += (nbytes + 255) / 255 ; + oopus->pkt_pos += oopus->len * oopus->sr_factor ; + odata->opacket.bytes = nbytes ; + odata->opacket.granulepos = oopus->pkt_pos ; + odata->opacket.packetno++ ; + + /* + ** Decide whether to flush the Ogg page *before* adding the new packet to + ** it. Check both for if there is more than 1 second of audio (our default + ** Ogg page latency, this latency can be modified using sf_command()) + ** or if adding the packet would cause a continued page, + ** in which case we might as well make a new page anyways. + */ + for ( ; ; ) + { if (oopus->pkt_pos - oopus->pg_pos >= oopus->u.encode.latency || oopus->u.encode.last_segments >= 255) + nbytes = ogg_stream_flush_fill (&odata->ostream, &odata->opage, 255 * 255) ; + else + nbytes = ogg_stream_pageout_fill (&odata->ostream, &odata->opage, 255 * 255) ; + if (nbytes > 0) + { oopus->u.encode.last_segments -= ogg_page_segments (&odata->opage) ; + oopus->pg_pos = oopus->pkt_pos ; + ogg_write_page (psf, &odata->opage) ; + } + else + break ; + } ; + + ogg_stream_packetin (&odata->ostream, &odata->opacket) ; + oopus->loc = 0 ; + oopus->u.encode.lsb_last = oopus->u.encode.lsb ; + oopus->u.encode.lsb = 0 ; + + return 1 ; +} /* ogg_opus_write_out */ + +static sf_count_t +ogg_opus_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) +{ OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; + OPUS_PRIVATE *oopus = (OPUS_PRIVATE *) psf->codec_data ; + sf_count_t total = 0 ; + sf_count_t readlen, i ; + float *iptr ; + + while (total < len) + { if (oopus->loc == oopus->len) + { if (ogg_opus_read_refill (psf, odata, oopus) <= 0) + return total ; + } ; + + readlen = SF_MIN (len - total, (sf_count_t) (oopus->len - oopus->loc) * psf->sf.channels) ; + if (readlen > 0) + { iptr = oopus->buffer + oopus->loc * psf->sf.channels ; + i = total ; + total += readlen ; + + if (psf->float_int_mult) + { float inverse = 1.0 / psf->float_max ; + for ( ; i < total ; i++) + { ptr [i] = psf_lrintf (((*(iptr++)) * inverse) * 32767.0f) ; + } ; + } + else + { for ( ; i < total ; i++) + { ptr [i] = psf_lrintf ((*(iptr++)) * 32767.0f) ; + } ; + } ; + oopus->loc += (readlen / psf->sf.channels) ; + } ; + } ; + return total ; +} /* ogg_opus_read_s */ + +static sf_count_t +ogg_opus_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) +{ OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; + OPUS_PRIVATE *oopus = (OPUS_PRIVATE *) psf->codec_data ; + sf_count_t total = 0 ; + sf_count_t readlen, i ; + float *iptr ; + + while (total < len) + { if (oopus->loc == oopus->len) + { if (ogg_opus_read_refill (psf, odata, oopus) <= 0) + return total ; + } ; + + readlen = SF_MIN (len - total, (sf_count_t) (oopus->len - oopus->loc) * psf->sf.channels) ; + if (readlen > 0) + { iptr = oopus->buffer + oopus->loc * psf->sf.channels ; + i = total ; + total += readlen ; + + if (psf->float_int_mult) + { float inverse = 1.0 / psf->float_max ; + for ( ; i < total ; i++) + { ptr [i] = psf_lrintf (((*(iptr++)) * inverse) * 2147483647.0f) ; + } + } + else + { for ( ; i < total ; i++) + { ptr [i] = psf_lrintf ((*(iptr++)) * 2147483647.0f) ; + } + } ; + oopus->loc += (readlen / psf->sf.channels) ; + } ; + } ; + return total ; +} /* ogg_opus_read_i */ + +static sf_count_t +ogg_opus_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) +{ OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; + OPUS_PRIVATE *oopus = (OPUS_PRIVATE *) psf->codec_data ; + sf_count_t total = 0 ; + sf_count_t readlen ; + + while (total < len) + { if (oopus->loc == oopus->len) + { if (ogg_opus_read_refill (psf, odata, oopus) <= 0) + return total ; + } ; + + readlen = SF_MIN (len - total, (sf_count_t) (oopus->len - oopus->loc) * psf->sf.channels) ; + if (readlen > 0) + { memcpy (&(ptr [total]), &(oopus->buffer [oopus->loc * psf->sf.channels]), sizeof (float) * readlen) ; + total += readlen ; + oopus->loc += (readlen / psf->sf.channels) ; + } ; + } ; + return total ; +} /* ogg_opus_read_f */ + +static sf_count_t +ogg_opus_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) +{ OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; + OPUS_PRIVATE *oopus = (OPUS_PRIVATE *) psf->codec_data ; + sf_count_t total = 0 ; + sf_count_t readlen, i ; + float *fptr ; + + while (total < len) + { if (oopus->loc >= oopus->len) + { if (ogg_opus_read_refill (psf, odata, oopus) <= 0) + return total ; + } ; + + readlen = SF_MIN (len - total, (sf_count_t) (oopus->len - oopus->loc) * psf->sf.channels) ; + + if (readlen > 0) + { fptr = oopus->buffer + oopus->loc * psf->sf.channels ; + i = total ; + total += readlen ; + for ( ; i < total ; i++) + { ptr [i] = *fptr++ ; + } ; + oopus->loc += readlen / psf->sf.channels ; + } ; + } ; + return total ; +} /* ogg_opus_read_d */ + +static sf_count_t +ogg_opus_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) +{ OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; + OPUS_PRIVATE *oopus = (OPUS_PRIVATE *) psf->codec_data ; + sf_count_t total, i ; + int writelen ; + float *optr ; + + if (oopus->u.encode.lsb < 16) + oopus->u.encode.lsb = 16 ; + + for (total = 0 ; total < len ; ) + { if (oopus->loc >= oopus->len) + { /* Need to encode the buffer */ + if (ogg_opus_write_out (psf, odata, oopus) <= 0) + return total ; + } ; + + writelen = SF_MIN (len - total, (sf_count_t) (oopus->len - oopus->loc) * psf->sf.channels) ; + if (writelen) + { optr = oopus->buffer + oopus->loc * psf->sf.channels ; + i = total ; + total += writelen ; + for ( ; i < total ; i++) + { *optr++ = (float) (ptr [i]) / 32767.0f ; + } + oopus->loc += (writelen / psf->sf.channels) ; + } ; + } ; + return total ; +} /* ogg_opus_write_s */ + +static sf_count_t +ogg_opus_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) +{ OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; + OPUS_PRIVATE *oopus = (OPUS_PRIVATE *) psf->codec_data ; + sf_count_t total, i ; + int writelen ; + float *optr ; + + if (oopus->u.encode.lsb < 24) + oopus->u.encode.lsb = 24 ; + + for (total = 0 ; total < len ; ) + { if (oopus->loc >= oopus->len) + { /* Need to encode the buffer */ + if (ogg_opus_write_out (psf, odata, oopus) <= 0) + return total ; + } ; + + writelen = SF_MIN (len - total, (sf_count_t) (oopus->len - oopus->loc) * psf->sf.channels) ; + if (writelen) + { optr = oopus->buffer + oopus->loc * psf->sf.channels ; + i = total ; + total += writelen ; + for ( ; i < total ; i++) + { *optr++ = (float) (ptr [i]) / 2147483647.0f ; + } ; + oopus->loc += (writelen / psf->sf.channels) ; + } ; + } ; + return total ; +} /* ogg_opus_write_i */ + +static sf_count_t +ogg_opus_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) +{ OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; + OPUS_PRIVATE *oopus = (OPUS_PRIVATE *) psf->codec_data ; + sf_count_t total ; + int writelen ; + + if (oopus->u.encode.lsb < 24) + oopus->u.encode.lsb = 24 ; + + for (total = 0 ; total < len ; ) + { if (oopus->loc >= oopus->len) + { /* Need to encode the buffer */ + if (ogg_opus_write_out (psf, odata, oopus) <= 0) + return total ; + } ; + + writelen = SF_MIN (len - total, (sf_count_t) (oopus->len - oopus->loc) * psf->sf.channels) ; + if (writelen) + { memcpy (&(oopus->buffer [oopus->loc * psf->sf.channels]), &(ptr [total]), sizeof (float) * writelen) ; + total += writelen ; + oopus->loc += (writelen / psf->sf.channels) ; + } ; + } ; + return total ; +} /* ogg_opus_write_f */ + +static sf_count_t +ogg_opus_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) +{ OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; + OPUS_PRIVATE *oopus = (OPUS_PRIVATE *) psf->codec_data ; + sf_count_t total, i ; + int writelen ; + float *optr ; + + if (oopus->u.encode.lsb < 24) + oopus->u.encode.lsb = 24 ; + + for (total = 0 ; total < len ; ) + { if (oopus->loc >= oopus->len) + { /* Need to encode the buffer */ + if (ogg_opus_write_out (psf, odata, oopus) <= 0) + return total ; + } ; + + writelen = SF_MIN (len - total, (sf_count_t) (oopus->len - oopus->loc) * psf->sf.channels) ; + if (writelen) + { optr = oopus->buffer + oopus->loc * psf->sf.channels ; + i = total ; + total += writelen ; + for ( ; i < total ; i++) + { *optr++ = (float) (ptr [i]) ; + } ; + oopus->loc += (writelen / psf->sf.channels) ; + } ; + } ; + return total ; +} /* ogg_opus_write_d */ + +static int +ogg_opus_analyze_file (SF_PRIVATE *psf) +{ OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; + OPUS_PRIVATE *oopus = (OPUS_PRIVATE *) psf->codec_data ; + uint64_t gp ; + sf_count_t saved_offset, last_page ; + int error ; + + psf->sf.sections = 1 ; + psf->sf.frames = SF_COUNT_MAX ; + oopus->u.decode.gp_end = (uint64_t) -1 ; + oopus->u.decode.last_offset = SF_COUNT_MAX ; + + psf->dataoffset = ogg_sync_ftell (psf) ; + if (psf->filelength != SF_COUNT_MAX) + psf->datalength = psf->filelength - psf->dataoffset ; + else + psf->datalength = SF_COUNT_MAX ; + + /* + ** Calculate the start granule position offset + ** + ** OggOpus streams are allowed to start with a granule position other than + ** zero. This allows for cutting the beginning off of streams without + ** having to modify all following granule positions, or for recording/ + ** joining a live stream in the middle. To figure out the offset, we need + ** to sum up how many samples are in all the packets that complete in the + ** page and subtract it from the page granule position. + ** + ** If this is the last page of the steam (EOS set), this is not possible, + ** as the granule position may be /less/ than the number of samples, to + ** indicate how many samples are end-padding. In this case the granule + ** position offset of the file must be 0, as otherwise it is considered + ** malformed. + */ + error = ogg_opus_unpack_next_page (psf, odata, oopus) ; + if (error < 0 && psf->error) + return psf->error ; + + gp = ogg_opus_calculate_page_duration (odata) ; + if (gp <= 0) + { psf_log_printf (psf, "Opus : Page duration of zero!\n") ; + return SFE_MALFORMED_FILE ; + } ; + + if (!ogg_page_eos (&odata->opage)) + { if (gp > oopus->pg_pos) + { psf_log_printf (psf, "Opus : First data page's granule position is less than total number of samples on the page!\n") ; + return SFE_MALFORMED_FILE ; + } + oopus->pkt_pos = oopus->pg_pos - gp ; + } + else if (gp < oopus->pg_pos) + { psf_log_printf (psf, "Opus : First data page is also the last, and granule position has an (ambigious) offset.\n") ; + return SFE_MALFORMED_FILE ; + } ; + oopus->u.decode.gp_start = oopus->pkt_pos ; + + if (!psf->sf.seekable) + return 0 ; + + /* + ** Find the last page and fetch the last granule position. + ** First, save were we are now. + */ + saved_offset = ogg_sync_ftell (psf) ; + + /* This uses the sync page buffer, the stream page buffer is untouched. */ + last_page = ogg_sync_last_page_before (psf, odata, &oopus->u.decode.gp_end, psf->filelength, oopus->serialno) ; + if (last_page > 0) + { if (!ogg_page_eos (&odata->opage)) + psf_log_printf (psf, "Ogg : Last page lacks an end-of-stream bit.\n") ; + if (last_page + odata->opage.header_len + odata->opage.body_len < psf->filelength) + psf_log_printf (psf, "Ogg : Junk after the last page.\n") ; + oopus->u.decode.last_offset = last_page ; + + if (oopus->u.decode.gp_end != (uint64_t) -1) + { 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) ; + return 0 ; +} /* ogg_opus_analyze_file */ + +/* +** ogg_opus_null_read +** +** Decode samples, doing nothing with them, until the desired granule position +** is reached. +*/ +static sf_count_t +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 ; + + total = (oopus->pkt_pos / oopus->sr_factor) - (oopus->len - oopus->loc) ; + for ( ; total < offset ; ) + { 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 ; + /* + ** Ignore pre-skip skipping. The preskip was accounted for in the + ** arugment to offset, so we need to count it. + */ + oopus->loc = 0 ; + } ; + } ; + return total ; +} /* 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_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 ; + uint64_t pcm_end ; + 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 ; + + /* 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) ; + + return 0 ; +} /* 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_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 (oopus->pg_pos > target_gp) + { ogg_stream_reset (&odata->ostream) ; + pos = ogg_sync_fseek (psf, psf->dataoffset, SEEK_SET) ; + if (pos < 0) + return pos ; + oopus->pg_pos = oopus->u.decode.gp_start ; + opus_multistream_decoder_ctl (oopus->u.decode.state, OPUS_RESET_STATE) ; + } ; + + while (oopus->pg_pos < target_gp) + { nn = ogg_opus_unpack_next_page (psf, odata, oopus) ; + if (nn <= 0) + return nn ; + } ; + + return 1 ; +} /* ogg_opus_page_seek_manual */ + +static sf_count_t +ogg_opus_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) +{ 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. */ + if (mode != SFM_READ || psf->file.mode != SFM_READ) + { psf->error = SFE_BAD_SEEK ; + return PSF_SEEK_ERROR ; + } ; + + /* 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_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 + ** either fall-back to manual seeking or bail. Manaul seeking + ** from the beginning has the advantage of finding where the + ** file goes bad. + */ + ret = ogg_opus_page_seek_manual (psf, preroll_gp) ; + if (ret < 0) + { /* + ** If were here, and there is no error, we can be pretty + ** sure that it's the file that is to blame. + */ + if (!psf->error) + psf->error = SFE_MALFORMED_FILE ; + return ret ; + } ; + } ; + } ; + + /* + ** 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_null_read (psf, target_gp / oopus->sr_factor) ; + return offset - ((oopus->header.preskip + oopus->u.decode.gp_start) / oopus->sr_factor) ; + +} /* ogg_opus_seek */ + +static int +ogg_opus_command (SF_PRIVATE *psf, int command, void *data, int datasize) +{ OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; + OPUS_PRIVATE *oopus = (OPUS_PRIVATE *) psf->codec_data ; + double quality ; + double latency ; + int error ; + + switch (command) + { case SFC_SET_CHANNEL_MAP_INFO : + /* TODO: figure this out */ + break ; + + case SFC_SET_OGG_PAGE_LATENCY : + /* + ** Argument: double, range 50 to 1600. + ** Average length of OGG page in ms. + ** This length drive the flush of pages. + */ + if (data == NULL || datasize != SIGNED_SIZEOF (double)) + return SFE_BAD_COMMAND_PARAM ; + + latency = *((double *) data) ; + if (latency < 50) + latency = 50 ; + + if (latency > 1600) + latency = 1600 ; + + oopus->u.encode.latency = ((unsigned long) latency) * 48 ; + break ; + + case SFC_SET_COMPRESSION_LEVEL : + /* + ** Argument: double, range 0.0 (lest compressed, best quality) to + ** 1.0 (most compressed, worst quality) + */ + if (data == NULL || datasize != SIGNED_SIZEOF (double)) + return SFE_BAD_COMMAND_PARAM ; + + /* Usable bitrate range is [6, 256] kbps per channel. */ + quality = *((double *) data) ; + oopus->u.encode.bitrate = (int) (((1.0 - quality) * (250000.0)) + 6000.0) * psf->sf.channels ; + if (opus_multistream_encoder_ctl (oopus->u.encode.state, OPUS_SET_BITRATE (oopus->u.encode.bitrate)) == OPUS_OK) + { psf_log_printf (psf, "User changed encoding target bitrate to %dbps\n", oopus->u.encode.bitrate) ; + return SF_TRUE ; + } + psf_log_printf (psf, "Failed to set user encoding target bitrate of %dbps\n", oopus->u.encode.bitrate) ; + return SF_FALSE ; + break ; + + case SFC_SET_ORIGINAL_SAMPLERATE : + if (data == NULL || datasize != SIGNED_SIZEOF (int)) + return SFE_BAD_COMMAND_PARAM ; + /* + ** Only allow changing the input samplerate if at the beginning + ** of the stream, because while it might be possible to change + ** samplerate mid-decode, or to re-write the header for encode, + ** ain't nobody got time to implement and test that. + */ + if (psf->file.mode == SFM_WRITE) + { if (psf->have_written) + return SF_FALSE ; + oopus->header.input_samplerate = *((int *) data) ; + } + else { + if (oopus->pkt_pos > oopus->u.decode.gp_start || oopus->loc > 0) + return SF_FALSE ; + if ((error = ogg_opus_setup_decoder (psf, *((int *) data)))) + return error ; + odata->pkt_indx = 0 ; + /* Adjust file frames count. */ + if (oopus->u.decode.gp_end != (uint64_t) -1) + psf->sf.frames = (oopus->u.decode.gp_end - oopus->u.decode.gp_start + - oopus->header.preskip) / oopus->sr_factor ; + } ; + return SF_TRUE ; + + case SFC_GET_ORIGINAL_SAMPLERATE : + if (data == NULL || datasize != SIGNED_SIZEOF (int)) + return SFE_BAD_COMMAND_PARAM ; + *((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 ; + } + + return SF_FALSE ; +} /* ogg_opus_command */ + +static int +ogg_opus_byterate (SF_PRIVATE *psf) +{ OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; + OPUS_PRIVATE *oopus = (OPUS_PRIVATE *) psf->codec_data ; + + if (psf->file.mode == SFM_READ) + { if (odata->pkt_indx == odata->pkt_len) + { if (ogg_opus_unpack_next_page (psf, odata, oopus) < 0) + return -1 ; + } ; + + if (odata->pkt_indx < odata->pkt_len) + { ogg_packet *ppkt = &odata->pkt [odata->pkt_indx] ; + return (ppkt->bytes * 8000) / opus_packet_get_nb_samples (ppkt->packet, ppkt->bytes, 8000) ; + } ; + + if (psf->datalength != SF_COUNT_MAX) + return (psf->datalength * psf->sf.samplerate) / psf->sf.frames ; + } ; + + if (psf->file.mode == SFM_WRITE && oopus->u.encode.state != NULL) + return (oopus->u.encode.bitrate + 7) / 8 ; + + return -1 ; +} /* ogg_opus_byterate */ + +#else /* HAVE_EXTERNAL_XIPH_LIBS */ + +int +ogg_opus_open (SF_PRIVATE *psf) +{ + psf_log_printf (psf, "This version of libsndfile was compiled without Ogg/Opus support.\n") ; + return SFE_UNIMPLEMENTED ; +} /* ogg_opus_open */ + +#endif diff --git a/extern/libsndfile-modified/src/ogg_pcm.c b/extern/libsndfile-modified/src/ogg_pcm.c new file mode 100644 index 000000000..f105214b7 --- /dev/null +++ b/extern/libsndfile-modified/src/ogg_pcm.c @@ -0,0 +1,167 @@ +/* +** Copyright (C) 2008-2016 Erik de Castro Lopo +** +** This program is free software ; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation ; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY ; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program ; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + + +#include "sfconfig.h" + +#include +#include +#include +#include +#include +#include + +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + +#if (ENABLE_EXPERIMENTAL_CODE && HAVE_EXTERNAL_XIPH_LIBS) + +#include + +#include "ogg.h" + +typedef struct +{ int32_t serialno ; + + + void * state ; +} OPCM_PRIVATE ; + +static int opcm_read_header (SF_PRIVATE * psf) ; +static int opcm_close (SF_PRIVATE *psf) ; + +int +ogg_pcm_open (SF_PRIVATE *psf) +{ OGG_PRIVATE* odata = psf->container_data ; + OPCM_PRIVATE* opcm = calloc (1, sizeof (OPCM_PRIVATE)) ; + int error = 0 ; + + if (odata == NULL) + { psf_log_printf (psf, "%s : odata is NULL???\n", __func__) ; + free (opcm) ; + return SFE_INTERNAL ; + } ; + + psf->codec_data = opcm ; + if (opcm == NULL) + return SFE_MALLOC_FAILED ; + + if (psf->file.mode == SFM_RDWR) + return SFE_BAD_MODE_RW ; + + if (psf->file.mode == SFM_READ) + { /* Call this here so it only gets called once, so no memory is leaked. */ + ogg_sync_init (&odata->osync) ; + + if ((error = opcm_read_header (psf))) + return error ; + +#if 0 + psf->read_short = opcm_read_s ; + psf->read_int = opcm_read_i ; + psf->read_float = opcm_read_f ; + psf->read_double = opcm_read_d ; + psf->sf.frames = opcm_length (psf) ; +#endif + } ; + + psf->codec_close = opcm_close ; + + if (psf->file.mode == SFM_WRITE) + { +#if 0 + /* Set the default opcm quality here. */ + vdata->quality = 0.4 ; + + psf->write_header = opcm_write_header ; + psf->write_short = opcm_write_s ; + psf->write_int = opcm_write_i ; + psf->write_float = opcm_write_f ; + psf->write_double = opcm_write_d ; +#endif + + psf->sf.frames = SF_COUNT_MAX ; /* Unknown really */ + psf->strings.flags = SF_STR_ALLOW_START ; + } ; + + psf->bytewidth = 1 ; + psf->blockwidth = psf->bytewidth * psf->sf.channels ; + +#if 0 + psf->seek = opcm_seek ; + psf->command = opcm_command ; +#endif + + /* FIXME, FIXME, FIXME : Hack these here for now and correct later. */ + psf->sf.format = SF_FORMAT_OGG | SF_FORMAT_SPEEX ; + psf->sf.sections = 1 ; + + psf->datalength = 1 ; + psf->dataoffset = 0 ; + /* End FIXME. */ + + return error ; +} /* ogg_pcm_open */ + +static int +opcm_read_header (SF_PRIVATE * UNUSED (psf)) +{ + return 0 ; +} /* opcm_read_header */ + +static int +opcm_close (SF_PRIVATE * UNUSED (psf)) +{ + + + return 0 ; +} /* opcm_close */ + + + +/* +encoded_speex_frames = (frames_per_packet * Packets) + = 1 * 272 + = 272 + +audio_samples = encoded_speex_frames * frame_size + = 272 * 640 + = 174080 + +duration = audio_samples / rate + = 174080 / 44100 + = 3.947 +*/ + +#else /* ENABLE_EXPERIMENTAL_CODE && HAVE_EXTERNAL_XIPH_LIBS */ + +int +ogg_pcm_open (SF_PRIVATE *psf) +{ + psf_log_printf (psf, "This version of libsndfile was compiled without Ogg/Speex support.\n") ; + return SFE_UNIMPLEMENTED ; +} /* ogg_pcm_open */ + +#endif diff --git a/extern/libsndfile-modified/src/ogg_speex.c b/extern/libsndfile-modified/src/ogg_speex.c new file mode 100644 index 000000000..546cf35d7 --- /dev/null +++ b/extern/libsndfile-modified/src/ogg_speex.c @@ -0,0 +1,428 @@ +/* +** Copyright (C) 2008-2016 Erik de Castro Lopo +** +** This program is free software ; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation ; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY ; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program ; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + + +#include "sfconfig.h" + +#include +#include +#include +#include +#include +#include + +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + +#if (ENABLE_EXPERIMENTAL_CODE && HAVE_EXTERNAL_XIPH_LIBS) + +#include + +#include +#include +#include +#include + +#include "ogg.h" + +#define OGG_SPX_READ_SIZE 200 + +typedef struct +{ SpeexBits bits ; + + int32_t serialno ; + + int frame_size, granule_frame_size, nframes ; + int force_mode ; + + SpeexStereoState stereo ; + SpeexHeader header ; + + void * state ; +} SPX_PRIVATE ; + +static int spx_read_header (SF_PRIVATE * psf) ; +static int spx_close (SF_PRIVATE *psf) ; +static void *spx_header_read (SF_PRIVATE * psf, ogg_packet *op, spx_int32_t enh_enabled, int force_mode) ; +static void spx_print_comments (const char *comments, int length) ; + +int +ogg_speex_open (SF_PRIVATE *psf) +{ OGG_PRIVATE* odata = psf->container_data ; + SPX_PRIVATE* spx = calloc (1, sizeof (SPX_PRIVATE)) ; + int error = 0 ; + + if (odata == NULL) + { psf_log_printf (psf, "%s : odata is NULL???\n", __func__) ; + free (spx) ; + return SFE_INTERNAL ; + } ; + + psf->codec_data = spx ; + if (spx == NULL) + return SFE_MALLOC_FAILED ; + + if (psf->file.mode == SFM_RDWR) + return SFE_BAD_MODE_RW ; + + if (psf->file.mode == SFM_READ) + { /* Call this here so it only gets called once, so no memory is leaked. */ + ogg_sync_init (&odata->osync) ; + + if ((error = spx_read_header (psf))) + return error ; + +#if 0 + psf->read_short = spx_read_s ; + psf->read_int = spx_read_i ; + psf->read_float = spx_read_f ; + psf->read_double = spx_read_d ; + psf->sf.frames = spx_length (psf) ; +#endif + } ; + + psf->codec_close = spx_close ; + + if (psf->file.mode == SFM_WRITE) + { +#if 0 + /* Set the default spx quality here. */ + vdata->quality = 0.4 ; + + psf->write_header = spx_write_header ; + psf->write_short = spx_write_s ; + psf->write_int = spx_write_i ; + psf->write_float = spx_write_f ; + psf->write_double = spx_write_d ; +#endif + + psf->sf.frames = SF_COUNT_MAX ; /* Unknown really */ + psf->strings.flags = SF_STR_ALLOW_START ; + } ; + + psf->bytewidth = 1 ; + psf->blockwidth = psf->bytewidth * psf->sf.channels ; + +#if 0 + psf->seek = spx_seek ; + psf->command = spx_command ; +#endif + + /* FIXME, FIXME, FIXME : Hack these here for now and correct later. */ + psf->sf.format = SF_FORMAT_OGG | SF_FORMAT_SPEEX ; + psf->sf.sections = 1 ; + + psf->datalength = 1 ; + psf->dataoffset = 0 ; + /* End FIXME. */ + + return error ; +} /* ogg_speex_open */ + +#define le_short (x) (x) + +static int +spx_read_header (SF_PRIVATE * psf) +{ static SpeexStereoState STEREO_INIT = SPEEX_STEREO_STATE_INIT ; + + OGG_PRIVATE* odata = psf->container_data ; + SPX_PRIVATE* spx = psf->codec_data ; + + ogg_int64_t page_granule = 0 ; + int stream_init = 0 ; + int page_nb_packets = 0 ; + int packet_count = 0 ; + int enh_enabled = 1 ; + int force_mode = -1 ; + char * data ; + int nb_read ; + int lookahead ; + +printf ("%s %d\n", __func__, __LINE__) ; + + psf_log_printf (psf, "Speex header\n") ; + odata->eos = 0 ; + + /* Reset ogg stuff which has already been used in src/ogg.c. */ + ogg_stream_reset (&odata->ostream) ; + ogg_sync_reset (&odata->osync) ; + + /* Seek to start of stream. */ + psf_fseek (psf, 0, SEEK_SET) ; + + /* Initialize. */ + ogg_sync_init (&odata->osync) ; + speex_bits_init (&spx->bits) ; + + /* Set defaults. */ + psf->sf.channels = -1 ; + psf->sf.samplerate = 0 ; + spx->stereo = STEREO_INIT ; + + /* Get a pointer to the ogg buffer and read data into it. */ + data = ogg_sync_buffer (&odata->osync, OGG_SPX_READ_SIZE) ; + nb_read = psf_fread (data, 1, OGG_SPX_READ_SIZE, psf) ; + ogg_sync_wrote (&odata->osync, nb_read) ; + + /* Now we chew on Ogg packets. */ + while (ogg_sync_pageout (&odata->osync, &odata->opage) == 1) + { if (stream_init == 0) + { ogg_stream_init (&odata->ostream, ogg_page_serialno (&odata->opage)) ; + stream_init = 1 ; + } ; + + if (ogg_page_serialno (&odata->opage) != odata->ostream.serialno) + { /* so all streams are read. */ + ogg_stream_reset_serialno (&odata->ostream, ogg_page_serialno (&odata->opage)) ; + } ; + + /*Add page to the bitstream*/ + ogg_stream_pagein (&odata->ostream, &odata->opage) ; + page_granule = ogg_page_granulepos (&odata->opage) ; + page_nb_packets = ogg_page_packets (&odata->opage) ; + + /*Extract all available packets*/ + while (odata->eos == 0 && ogg_stream_packetout (&odata->ostream, &odata->opacket) == 1) + { if (odata->opacket.bytes >= 8 && memcmp (odata->opacket.packet, "Speex ", 8) == 0) + { spx->serialno = odata->ostream.serialno ; + } ; + + if (spx->serialno == -1 || odata->ostream.serialno != spx->serialno) + break ; + + if (packet_count == 0) + { spx->state = spx_header_read (psf, &odata->opacket, enh_enabled, force_mode) ; + if (! spx->state) + break ; + + speex_decoder_ctl (spx->state, SPEEX_GET_LOOKAHEAD, &lookahead) ; + if (spx->nframes == 0) + spx->nframes = 1 ; + } + else if (packet_count == 1) + { spx_print_comments ((const char*) odata->opacket.packet, odata->opacket.bytes) ; + } + else if (packet_count < 2 + spx->header.extra_headers) + { /* Ignore extra headers */ + } + packet_count ++ ; + } ; + } ; + + psf_log_printf (psf, "End\n") ; + + psf_log_printf (psf, "packet_count %d\n", packet_count) ; + psf_log_printf (psf, "page_nb_packets %d\n", page_nb_packets) ; + psf_log_printf (psf, "page_granule %lld\n", page_granule) ; + + return 0 ; +} /* spx_read_header */ + +static int +spx_close (SF_PRIVATE *psf) +{ SPX_PRIVATE* spx = psf->codec_data ; + + if (spx->state) + speex_decoder_destroy (spx->state) ; + + if (spx) + speex_bits_destroy (&spx->bits) ; + + return 0 ; +} /* spx_close */ + + + +static void * +spx_header_read (SF_PRIVATE * psf, ogg_packet *op, spx_int32_t enh_enabled, int force_mode) +{ SPX_PRIVATE* spx = psf->codec_data ; + void *st ; + const SpeexMode *mode ; + SpeexHeader *tmp_header ; + int modeID ; + SpeexCallback callback ; + + tmp_header = speex_packet_to_header ((char*) op->packet, op->bytes) ; + if (tmp_header == NULL) + { psf_log_printf (psf, "Cannot read Speex header\n") ; + return NULL ; + } ; + + memcpy (&spx->header, tmp_header, sizeof (spx->header)) ; + free (tmp_header) ; + tmp_header = NULL ; + + if (spx->header.mode >= SPEEX_NB_MODES || spx->header.mode < 0) + { psf_log_printf (psf, "Mode number %d does not (yet/any longer) exist in this version\n", spx->header.mode) ; + return NULL ; + } ; + + modeID = spx->header.mode ; + if (force_mode != -1) + modeID = force_mode ; + + mode = speex_lib_get_mode (modeID) ; + + if (spx->header.speex_version_id > 1) + { psf_log_printf (psf, "This file was encoded with Speex bit-stream version %d, which I don't know how to decode\n", spx->header.speex_version_id) ; + return NULL ; + } ; + + if (mode->bitstream_version < spx->header.mode_bitstream_version) + { psf_log_printf (psf, "The file was encoded with a newer version of Speex. You need to upgrade in order to play it.\n") ; + return NULL ; + } ; + + if (mode->bitstream_version > spx->header.mode_bitstream_version) + { psf_log_printf (psf, "The file was encoded with an older version of Speex. You would need to downgrade the version in order to play it.\n") ; + return NULL ; + } ; + + st = speex_decoder_init (mode) ; + if (!st) + { psf_log_printf (psf, "Decoder initialization failed.\n") ; + return NULL ; + } ; + + speex_decoder_ctl (st, SPEEX_SET_ENH, &enh_enabled) ; + speex_decoder_ctl (st, SPEEX_GET_FRAME_SIZE, &spx->frame_size) ; + spx->granule_frame_size = spx->frame_size ; + + if (!psf->sf.samplerate) + psf->sf.samplerate = spx->header.rate ; + /* Adjust rate if --force-* options are used */ + if (force_mode != -1) + { if (spx->header.mode < force_mode) + { psf->sf.samplerate <<= (force_mode - spx->header.mode) ; + spx->granule_frame_size >>= (force_mode - spx->header.mode) ; + } ; + if (spx->header.mode > force_mode) + { psf->sf.samplerate >>= (spx->header.mode - force_mode) ; + spx->granule_frame_size <<= (spx->header.mode - force_mode) ; + } ; + } ; + + speex_decoder_ctl (st, SPEEX_SET_SAMPLING_RATE, &psf->sf.samplerate) ; + + spx->nframes = spx->header.frames_per_packet ; + + if (psf->sf.channels == -1) + psf->sf.channels = spx->header.nb_channels ; + + if (! (psf->sf.channels == 1)) + { psf->sf.channels = 2 ; + callback.callback_id = SPEEX_INBAND_STEREO ; + callback.func = speex_std_stereo_request_handler ; + callback.data = &spx->stereo ; + speex_decoder_ctl (st, SPEEX_SET_HANDLER, &callback) ; + } ; + + spx->header.speex_version [sizeof (spx->header.speex_version) - 1] = 0 ; + + psf_log_printf (psf, " Encoder ver : %s\n Frames/packet : %d\n", + spx->header.speex_version, spx->header.frames_per_packet) ; + + if (spx->header.bitrate > 0) + psf_log_printf (psf, " Bit rate : %d\n", spx->header.bitrate) ; + + psf_log_printf (psf, " Sample rate : %d\n Mode : %s\n VBR : %s\n Channels : %d\n", + psf->sf.samplerate, mode->modeName, (spx->header.vbr ? "yes" : "no"), psf->sf.channels) ; + + psf_log_printf (psf, " Extra headers : %d\n", spx->header.extra_headers) ; + + return st ; +} /* spx_header_read */ + + +static void +spx_print_comments (const char *c, int length) +{ + const char *end ; + int len, i, nb_fields ; + +printf ("%s %d\n", __func__, __LINE__) ; + if (length < 8) + { fprintf (stderr, "Invalid/corrupted comments\n") ; + return ; + } + end = c + length ; + len = readint (c, 0) ; + c += 4 ; + if (len < 0 || c + len > end) + { fprintf (stderr, "Invalid/corrupted comments\n") ; + return ; + } + (void) fwrite (c, 1, len, stderr) ; + c += len ; + fprintf (stderr, "\n") ; + if (c + 4 > end) + { fprintf (stderr, "Invalid/corrupted comments\n") ; + return ; + } + nb_fields = readint (c, 0) ; + c += 4 ; + for (i = 0 ; i < nb_fields ; i++) + { if (c + 4 > end) + { fprintf (stderr, "Invalid/corrupted comments\n") ; + return ; + } ; + len = readint (c, 0) ; + c += 4 ; + if (len < 0 || c + len > end) + { fprintf (stderr, "Invalid/corrupted comments\n") ; + return ; + } + (void) fwrite (c, 1, len, stderr) ; + c += len ; + fprintf (stderr, "\n") ; + } ; + return ; +} /* spx_print_comments */ + + +/* +encoded_speex_frames = (frames_per_packet * Packets) + = 1 * 272 + = 272 + +audio_samples = encoded_speex_frames * frame_size + = 272 * 640 + = 174080 + +duration = audio_samples / rate + = 174080 / 44100 + = 3.947 +*/ + +#else /* ENABLE_EXPERIMENTAL_CODE && HAVE_EXTERNAL_XIPH_LIBS */ + +int +ogg_speex_open (SF_PRIVATE *psf) +{ + psf_log_printf (psf, "This version of libsndfile was compiled without Ogg/Speex support.\n") ; + return SFE_UNIMPLEMENTED ; +} /* ogg_speex_open */ + +#endif diff --git a/extern/libsndfile-modified/src/ogg_vcomment.c b/extern/libsndfile-modified/src/ogg_vcomment.c new file mode 100644 index 000000000..252ed61d0 --- /dev/null +++ b/extern/libsndfile-modified/src/ogg_vcomment.c @@ -0,0 +1,277 @@ +/* +** Copyright (C) 2008-2019 Erik de Castro Lopo +** Copyright (C) 2018 Arthur Taylor +** +** This program is free software ; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation ; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY ; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program ; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + +#if HAVE_EXTERNAL_XIPH_LIBS + +#include + +#include "ogg_vcomment.h" + +typedef struct +{ int id ; + const char *name ; +} STR_PAIR ; + +/* See https://xiph.org/vorbis/doc/v-comment.html */ +static STR_PAIR vorbiscomment_mapping [] = +{ { SF_STR_TITLE, "TITLE" }, + { SF_STR_COPYRIGHT, "COPYRIGHT", }, + { SF_STR_SOFTWARE, "ENCODER", }, + { SF_STR_ARTIST, "ARTIST" }, + { SF_STR_COMMENT, "COMMENT" }, + { SF_STR_DATE, "DATE", }, + { SF_STR_ALBUM, "ALBUM" }, + { SF_STR_LICENSE, "LICENSE", }, + { SF_STR_TRACKNUMBER, "TRACKNUMBER", }, + { SF_STR_GENRE, "GENRE", }, + { 0, NULL, }, +} ; + +/*----------------------------------------------------------------------------------------------- +** Private function prototypes. +*/ + +static int vorbiscomment_lookup_id (const char *name) ; +static const char * vorbiscomment_lookup_name (int id) ; + +static inline size_t read_32bit_size_t (const unsigned char * ptr) +{ /* Read a 32 bit positive value from the provided pointer. */ + return LE2H_32_PTR (ptr) & 0x7fffffff ; +} /* read_32bit_size_t */ + +/*----------------------------------------------------------------------------------------------- +** Exported functions. +*/ + +int +vorbiscomment_read_tags (SF_PRIVATE *psf, ogg_packet *packet, vorbiscomment_ident *ident) +{ unsigned char *p, *ep ; + char *tag, *c ; + size_t tag_size, tag_len = 0 ; + unsigned int ntags, i = 0 ; + int id, ret = 0 ; + + /* + ** The smallest possible header is the ident string length plus two 4-byte + ** integers, (vender string length, tags count.) + */ + if (packet->bytes < (ident ? ident->length : 0) + 4 + 4) + return SFE_MALFORMED_FILE ; + + /* Our working pointer. */ + p = packet->packet ; + /* Our end pointer for bound checking. */ + ep = p + packet->bytes ; + + if (ident) + { if (memcmp (p, ident->ident, ident->length) != 0) + { psf_log_printf (psf, "Expected comment packet identifier missing.\n") ; + return SFE_MALFORMED_FILE ; + } ; + p += ident->length ; + } ; + + tag_size = 1024 ; + tag = malloc (tag_size) ; + /* Unlikely */ + if (!tag) + return SFE_MALLOC_FAILED ; + + psf_log_printf (psf, "VorbisComment Metadata\n") ; + + /* + ** Vendor tag, manditory, no field name. + */ + tag_len = read_32bit_size_t (p) ; + p += 4 ; + if (tag_len > 0) + { /* Bound checking. 4 bytes for remaining manditory fields. */ + if (p + tag_len + 4 > ep) + { ret = SFE_MALFORMED_FILE ; + goto free_tag_out ; + } ; + if (tag_len > tag_size - 1) + { free (tag) ; + tag_size = tag_len + 1 ; + tag = malloc (tag_size) ; + /* Unlikely */ + if (!tag) + return SFE_MALLOC_FAILED ; + } ; + memcpy (tag, p, tag_len) ; p += tag_len ; + tag [tag_len] = '\0' ; + psf_log_printf (psf, " Vendor: %s\n", tag) ; + } ; + + /* + ** List of tags of the form NAME=value + ** Allowable characters for NAME are the same as shell variable names. + */ + ntags = read_32bit_size_t (p) ; + p += 4 ; + for (i = 0 ; i < ntags ; i++) + { if (p + 4 > ep) + { ret = SFE_MALFORMED_FILE ; + goto free_tag_out ; + } ; + tag_len = read_32bit_size_t (p) ; + p += 4 ; + if (p + tag_len > ep) + { ret = SFE_MALFORMED_FILE ; + goto free_tag_out ; + } ; + if (tag_len > tag_size - 1) + { free (tag) ; + tag_size = tag_len + 1 ; + tag = malloc (tag_size) ; + /* Unlikely */ + if (!tag) + return SFE_MALLOC_FAILED ; + } ; + memcpy (tag, p, tag_len) ; p += tag_len ; + tag [tag_len] = '\0' ; + psf_log_printf (psf, " %s\n", tag) ; + for (c = tag ; *c ; c++) + { if (*c == '=') + break ; + *c = toupper (*c) ; + } ; + if (!c) + { psf_log_printf (psf, "Malformed Vorbis comment, no '=' found.\n") ; + continue ; + } ; + *c = '\0' ; + if ((id = vorbiscomment_lookup_id (tag)) != 0) + psf_store_string (psf, id, c + 1) ; + } ; + +free_tag_out: + if (tag != NULL) + free (tag) ; + return ret ; +} /* vorbiscomment_read_tags */ + +int +vorbiscomment_write_tags (SF_PRIVATE *psf, ogg_packet *packet, vorbiscomment_ident *ident, const char *vendor, int targetsize) +{ int i, ntags ; + int tags_start ; + const char *tag_name ; + int tag_name_len, tag_body_len ; + + psf->header.ptr [0] = 0 ; + psf->header.indx = 0 ; + + /* Packet identifier */ + if (ident) + psf_binheader_writef (psf, "eb", BHWv (ident->ident), BHWz (ident->length)) ; + + /* Manditory Vendor Tag */ + tag_name_len = vendor ? strlen (vendor) : 0 ; + psf_binheader_writef (psf, "e4b", BHW4 (tag_name_len), BHWv (vendor), BHWz (tag_name_len)) ; + + /* Tags Count. Skip for now, write after. */ + tags_start = psf->header.indx ; + psf_binheader_writef (psf, "j", BHWj (4)) ; + + ntags = 0 ; + /* Write each tag */ + for (i = 0 ; i < SF_MAX_STRINGS ; i++) + { if (psf->strings.data [i].type == 0) + continue ; + + tag_name = vorbiscomment_lookup_name (psf->strings.data [i].type) ; + if (tag_name == NULL) + continue ; + + tag_name_len = strlen (tag_name) ; + tag_body_len = strlen (psf->strings.storage + psf->strings.data [i].offset) ; + if (targetsize > 0 && tag_name_len + tag_body_len + psf->header.indx > targetsize) + { /* If we are out of space, stop now. */ + return SFE_STR_MAX_DATA ; + } + psf_binheader_writef (psf, "e4b1b", + BHW4 (tag_name_len + 1 + tag_body_len), + BHWv (tag_name), BHWz (tag_name_len), + BHW1 ('='), + BHWv (psf->strings.storage + psf->strings.data [i].offset), BHWz (tag_body_len)) ; + ntags++ ; + } ; + + if (targetsize < 0) + { /* + ** Padding. + ** + ** Pad to a minimum of -targetsize, but make sure length % 255 + ** = 254 so that we get the most out of the ogg segment lacing. + */ + psf_binheader_writef (psf, "z", BHWz ((psf->header.indx + -targetsize + 255) / 255 * 255 - 1)) ; + } + else if (targetsize > 0) + psf_binheader_writef (psf, "z", BHWz (targetsize - psf->header.indx)) ; + + packet->packet = psf->header.ptr ; + packet->bytes = psf->header.indx ; + packet->b_o_s = 0 ; + packet->e_o_s = 0 ; + + /* Seek back and write the tag count. */ + psf_binheader_writef (psf, "eo4", BHWo (tags_start), BHW4 (ntags)) ; + + return 0 ; +} /* vorbiscomment_write_tags */ + +/*============================================================================== +** Private functions. +*/ + +static int +vorbiscomment_lookup_id (const char * name) +{ STR_PAIR *p ; + + for (p = vorbiscomment_mapping ; p->id ; p++) + { if (!strcmp (name, p->name)) + return p->id ; + } ; + + return 0 ; +} /* vorbiscomment_lookup_id */ + +static const char * +vorbiscomment_lookup_name (int id) +{ STR_PAIR *p ; + + for (p = vorbiscomment_mapping ; p->id ; p++) + { if (p->id == id) + return p->name ; + } ; + + return NULL ; +} /* vorbiscomment_lookup_name */ + +#endif /* HAVE_EXTERNAL_XIPH_LIBS */ diff --git a/extern/libsndfile-modified/src/ogg_vcomment.h b/extern/libsndfile-modified/src/ogg_vcomment.h new file mode 100644 index 000000000..c25d900f6 --- /dev/null +++ b/extern/libsndfile-modified/src/ogg_vcomment.h @@ -0,0 +1,45 @@ +/* +** Copyright (C) 2008-2018 Erik de Castro Lopo +** Copyright (C) 2018 Arthur Taylor +** +** This program is free software ; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation ; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY ; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program ; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef SF_SRC_OGG_VCOMMENT_H +#define SF_SRC_OGG_VCOMMENT_H + +/* +** Voriscomment identifier. Some Ogg stream embedding schemes require it. +*/ +typedef struct +{ const char *ident ; + int length ; +} vorbiscomment_ident ; + +/* +** Read all vorbiscomment tags from *packet. Tags which match ones used +** by libsndfile strings are loaded into *psf. Ogg streams which require an +** identifier for the tags packet should pass it in *ident. +*/ +int vorbiscomment_read_tags (SF_PRIVATE *psf, ogg_packet *packet, vorbiscomment_ident *ident) ; + +/* +** Write metadata strings stored in *psf to *packet. The packet is optionally +** prefixed with *ident. The always-present vendor field should be the library +** used for encoding the audio data. +*/ +int vorbiscomment_write_tags (SF_PRIVATE *psf, ogg_packet *packet, vorbiscomment_ident *ident, const char *vendor, int targetsize) ; + +#endif /* SF_SRC_OGG_VCOMMENT_H */ diff --git a/extern/libsndfile-modified/src/ogg_vorbis.c b/extern/libsndfile-modified/src/ogg_vorbis.c new file mode 100644 index 000000000..f9428ed1f --- /dev/null +++ b/extern/libsndfile-modified/src/ogg_vorbis.c @@ -0,0 +1,1057 @@ +/* +** Copyright (C) 2018-2021 Arthur Taylor +** Copyright (C) 2002-2016 Erik de Castro Lopo +** Copyright (C) 2002-2005 Michael Smith +** Copyright (C) 2007 John ffitch +** +** This program is free software ; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation ; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY ; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program ; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/* +** Much of this code is based on the examples in libvorbis from the +** XIPHOPHORUS Company http://www.xiph.org/ which has a BSD-style Licence +** Copyright (c) 2002, 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 "sfconfig.h" + +#include +#include +#include +#include +#include +#include + +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + +#if HAVE_EXTERNAL_XIPH_LIBS + +#include +#include +#include + +#include "ogg.h" + +/* How many seconds in the future to not bother bisection searching for. */ +#define VORBIS_SEEK_THRESHOLD 2 + +typedef int convert_func (SF_PRIVATE *psf, int, void *, int, int, float **) ; + +static int vorbis_read_header (SF_PRIVATE *psf) ; +static int vorbis_write_header (SF_PRIVATE *psf, int calc_length) ; +static int vorbis_close (SF_PRIVATE *psf) ; +static int vorbis_command (SF_PRIVATE *psf, int command, void *data, int datasize) ; +static int vorbis_byterate (SF_PRIVATE *psf) ; +static int vorbis_calculate_granulepos (SF_PRIVATE *psf, uint64_t *gp_out) ; +static int vorbis_skip (SF_PRIVATE *psf, uint64_t target_gp) ; +static int vorbis_seek_trysearch (SF_PRIVATE *psf, uint64_t target_gp) ; +static sf_count_t vorbis_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ; +static sf_count_t vorbis_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; +static sf_count_t vorbis_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; +static sf_count_t vorbis_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; +static sf_count_t vorbis_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; +static sf_count_t vorbis_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; +static sf_count_t vorbis_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; +static sf_count_t vorbis_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; +static sf_count_t vorbis_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; +static sf_count_t vorbis_read_sample (SF_PRIVATE *psf, void *ptr, sf_count_t lens, convert_func *transfn) ; +static int vorbis_rnull (SF_PRIVATE *psf, int samples, void *vptr, int off , int channels, float **pcm) ; + +typedef struct +{ int id ; + const char *name ; +} STR_PAIRS ; + + +/* See https://xiph.org/vorbis/doc/v-comment.html */ +static STR_PAIRS vorbis_metatypes [] = +{ { SF_STR_TITLE, "Title" }, + { SF_STR_COPYRIGHT, "Copyright" }, + { SF_STR_SOFTWARE, "Software" }, + { SF_STR_ARTIST, "Artist" }, + { SF_STR_COMMENT, "Comment" }, + { SF_STR_DATE, "Date" }, + { SF_STR_ALBUM, "Album" }, + { SF_STR_LICENSE, "License" }, + { SF_STR_TRACKNUMBER, "Tracknumber" }, + { SF_STR_GENRE, "Genre" }, +} ; + +typedef struct +{ /* Current granule position. */ + uint64_t gp ; + /* Struct that stores all the static vorbis bitstream settings */ + vorbis_info vinfo ; + /* Struct that stores all the bitstream user comments */ + vorbis_comment vcomment ; + /* Central working state for the packet->PCM decoder */ + vorbis_dsp_state vdsp ; + /* Local working space for packet->PCM decode */ + vorbis_block vblock ; + /* Encoding quality in range [0.0, 1.0]. */ + double quality ; + /* Offset of the first samples' granule position. */ + uint64_t pcm_start ; + /* Last valid samples' granule position. */ + uint64_t pcm_end ; + /* File offset of the start of the last page. */ + sf_count_t last_page ; +} VORBIS_PRIVATE ; + +static int +vorbis_read_header (SF_PRIVATE *psf) +{ OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; + VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ; + int printed_metadata_msg = 0 ; + int i, nn ; + sf_count_t last_page ; + sf_count_t saved_offset ; + + /* + ** The first page of the Ogg stream we are told to try and open as Vorbis + ** has already been loaded into odata->ostream by ogg_open(). + ** + ** Extract the initial header from the first page and verify that the + ** Ogg bitstream is in fact Vorbis data. + */ + + vorbis_info_init (&vdata->vinfo) ; + vorbis_comment_init (&vdata->vcomment) ; + + if (!odata->opacket.b_o_s) + { psf_log_printf (psf, "Vorbis: First packet does not have a beginning-of-stream bit.\n") ; + return SFE_MALFORMED_FILE ; + } + + if (ogg_stream_packetpeek (&odata->ostream, NULL)) + { psf_log_printf (psf, "Vorbis: First page contains extraneous packets!\n") ; + return SFE_MALFORMED_FILE ; + } + + if (vorbis_synthesis_headerin (&vdata->vinfo, &vdata->vcomment, &odata->opacket) < 0) + { /* Error case ; not a vorbis header. */ + psf_log_printf (psf, "Found Vorbis in stream header, but vorbis_synthesis_headerin failed.\n") ; + return SFE_MALFORMED_FILE ; + } ; + + /* + ** At this point, we're sure we're Vorbis. We've set up the logical (Ogg) + ** bitstream decoder. Get the comment and codebook headers and set up the + ** Vorbis decoder. + ** + ** The next two packets in order are the comment and codebook headers. + ** They're likely large and may span multiple pages. Thus we read + ** and submit data until we get our two packets, watching that no + ** pages are missing. If a page is missing, error out ; losing a + ** header page is the only place where missing data is fatal. + */ + + i = 0 ; /* Count of number of packets read */ + while (i < 2) + { nn = ogg_stream_packetout (&odata->ostream, &odata->opacket) ; + + if (nn == 0) + { nn = ogg_stream_next_page (psf, odata) ; + if (nn == 0) + { psf_log_printf (psf, "End of file before finding all Vorbis headers!\n") ; + return SFE_MALFORMED_FILE ; + } ; + if (nn == -1) + { psf_log_printf (psf, "Error reading file while finding Vorbis headers!\n") ; + return psf->error ; + } ; + continue ; + } + + if (nn < 0) + { /* A hole while reading headers. This could be bad. */ + psf_log_printf (psf, "Corrupt secondary header. Exiting.\n") ; + return SFE_MALFORMED_FILE ; + } ; + + vorbis_synthesis_headerin (&vdata->vinfo, &vdata->vcomment, &odata->opacket) ; + i++ ; + } ; + + /* Check for extraneous packets in the last headers page. */ + while (ogg_stream_packetout (&odata->ostream, &odata->opacket) == 1) + { i++ ; + } + if (i > 2) + psf_log_printf (psf, "Vorbis: stream has extraneous header packets.\n") ; + + psf_log_printf (psf, "Bitstream is %d channel, %D Hz\n", vdata->vinfo.channels, vdata->vinfo.rate) ; + psf_log_printf (psf, "Encoded by : %s\n", vdata->vcomment.vendor) ; + + /* Save the offset of the first payload page */ + psf->dataoffset = ogg_sync_ftell (psf) ; + + /* + ** Calculate the granule position offset. The first page with a payload + ** packet shouldn't end in a continued packet. The difference between the + ** page's granule position and the sum of frames on the page tells us the + ** granule position offset. + ** See https://xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-132000A.2 + */ + ogg_stream_unpack_page (psf, odata) ; + vorbis_calculate_granulepos (psf, &vdata->pcm_start) ; + vdata->gp = vdata->pcm_start ; + + /* + ** Find the end of the stream, save it. Only works if the file is seekable. + */ + vdata->pcm_end = (uint64_t) -1 ; + psf->datalength = psf->filelength ; + if (!psf->is_pipe) + { saved_offset = ogg_sync_ftell (psf) ; + last_page = ogg_sync_last_page_before (psf, odata, &vdata->pcm_end, psf->filelength, odata->ostream.serialno) ; + if (last_page > 0) + { if (!ogg_page_eos (&odata->opage)) + psf_log_printf (psf, "Ogg: Last page lacks an end-of-stream bit.\n") ; + psf->datalength = last_page + odata->opage.header_len + odata->opage.body_len - psf->dataoffset ; + if (psf->datalength + psf->dataoffset < psf->filelength) + psf_log_printf (psf, "Ogg: Junk after the last page.\n") ; + vdata->last_page = last_page ; + } ; + + ogg_sync_fseek (psf, saved_offset, SEEK_SET) ; + } + + 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) ; + else + psf_log_printf (psf, "PCM end : unknown\n") ; + + /* Throw the comments plus a few lines about the bitstream we're decoding. */ + for (i = 0 ; i < ARRAY_LEN (vorbis_metatypes) ; i++) + { char *dd ; + + dd = vorbis_comment_query (&vdata->vcomment, vorbis_metatypes [i].name, 0) ; + if (dd == NULL) + continue ; + + if (printed_metadata_msg == 0) + { psf_log_printf (psf, "Metadata :\n") ; + printed_metadata_msg = 1 ; + } ; + + psf_store_string (psf, vorbis_metatypes [i].id, dd) ; + psf_log_printf (psf, " %-10s : %s\n", vorbis_metatypes [i].name, dd) ; + } ; + psf_log_printf (psf, "End\n") ; + + psf->sf.samplerate = vdata->vinfo.rate ; + psf->sf.channels = vdata->vinfo.channels ; + psf->sf.format = SF_FORMAT_OGG | SF_FORMAT_VORBIS ; + psf->sf.frames = (vdata->pcm_end != (uint64_t) -1) ? vdata->pcm_end - vdata->pcm_start : SF_COUNT_MAX ; + + /* OK, got and parsed all three headers. Initialize the Vorbis + ** packet->PCM decoder. + ** Central decode state. */ + vorbis_synthesis_init (&vdata->vdsp, &vdata->vinfo) ; + + /* Local state for most of the decode so multiple block decodes can + ** proceed in parallel. We could init multiple vorbis_block structures + ** for vdsp here. */ + vorbis_block_init (&vdata->vdsp, &vdata->vblock) ; + + return 0 ; +} /* vorbis_read_header */ + +static int +vorbis_write_header (SF_PRIVATE *psf, int UNUSED (calc_length)) +{ + OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; + VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ; + int k, ret ; + + vorbis_info_init (&vdata->vinfo) ; + + /* The style of encoding should be selectable here, VBR quality mode. */ + ret = vorbis_encode_init_vbr (&vdata->vinfo, psf->sf.channels, psf->sf.samplerate, vdata->quality) ; + +#if 0 + ret = vorbis_encode_init (&vdata->vinfo, psf->sf.channels, psf->sf.samplerate, -1, 128000, -1) ; /* average bitrate mode */ + ret = ( vorbis_encode_setup_managed (&vdata->vinfo, psf->sf.channels, psf->sf.samplerate, -1, 128000, -1) + || vorbis_encode_ctl (&vdata->vinfo, OV_ECTL_RATEMANAGE_AVG, NULL) + || vorbis_encode_setup_init (&vdata->vinfo) + ) ; +#endif + if (ret) + return SFE_BAD_OPEN_FORMAT ; + + vdata->gp = 0 ; + + /* add a comment */ + vorbis_comment_init (&vdata->vcomment) ; + + vorbis_comment_add_tag (&vdata->vcomment, "ENCODER", "libsndfile") ; + for (k = 0 ; k < SF_MAX_STRINGS ; k++) + { const char * name ; + + if (psf->strings.data [k].type == 0) + break ; + + switch (psf->strings.data [k].type) + { case SF_STR_TITLE : name = "TITLE" ; break ; + case SF_STR_COPYRIGHT : name = "COPYRIGHT" ; break ; + case SF_STR_SOFTWARE : name = "SOFTWARE" ; break ; + case SF_STR_ARTIST : name = "ARTIST" ; break ; + case SF_STR_COMMENT : name = "COMMENT" ; break ; + case SF_STR_DATE : name = "DATE" ; break ; + case SF_STR_ALBUM : name = "ALBUM" ; break ; + case SF_STR_LICENSE : name = "LICENSE" ; break ; + case SF_STR_TRACKNUMBER : name = "Tracknumber" ; break ; + case SF_STR_GENRE : name = "Genre" ; break ; + + default : continue ; + } ; + + vorbis_comment_add_tag (&vdata->vcomment, name, psf->strings.storage + psf->strings.data [k].offset) ; + } ; + + /* set up the analysis state and auxiliary encoding storage */ + vorbis_analysis_init (&vdata->vdsp, &vdata->vinfo) ; + vorbis_block_init (&vdata->vdsp, &vdata->vblock) ; + + /* + ** Set up our packet->stream encoder. + ** Pick a random serial number ; that way we can more likely build + ** chained streams just by concatenation. + */ + + ogg_stream_init (&odata->ostream, psf_rand_int32 ()) ; + + /* Vorbis streams begin with three headers ; the initial header (with + most of the codec setup parameters) which is mandated by the Ogg + bitstream spec. The second header holds any comment fields. The + third header holds the bitstream codebook. We merely need to + make the headers, then pass them to libvorbis one at a time ; + libvorbis handles the additional Ogg bitstream constraints */ + + { ogg_packet header ; + ogg_packet header_comm ; + ogg_packet header_code ; + int result ; + + vorbis_analysis_headerout (&vdata->vdsp, &vdata->vcomment, &header, &header_comm, &header_code) ; + ogg_stream_packetin (&odata->ostream, &header) ; /* automatically placed in its own page */ + ogg_stream_packetin (&odata->ostream, &header_comm) ; + ogg_stream_packetin (&odata->ostream, &header_code) ; + + /* This ensures the actual + * audio data will start on a new page, as per spec + */ + while ((result = ogg_stream_flush (&odata->ostream, &odata->opage)) != 0) + { ogg_write_page (psf, &odata->opage) ; + } ; + } + + return 0 ; +} /* vorbis_write_header */ + +static int +vorbis_close (SF_PRIVATE *psf) +{ OGG_PRIVATE* odata = psf->container_data ; + VORBIS_PRIVATE *vdata = psf->codec_data ; + + if (odata == NULL || vdata == NULL) + return 0 ; + + /* Clean up this logical bitstream ; before exit we shuld see if we're + ** followed by another [chained]. */ + + if (psf->file.mode == SFM_WRITE) + { + if (psf->write_current <= 0) + vorbis_write_header (psf, 0) ; + + vorbis_analysis_wrote (&vdata->vdsp, 0) ; + while (vorbis_analysis_blockout (&vdata->vdsp, &vdata->vblock) == 1) + { + + /* analysis, assume we want to use bitrate management */ + vorbis_analysis (&vdata->vblock, NULL) ; + vorbis_bitrate_addblock (&vdata->vblock) ; + + while (vorbis_bitrate_flushpacket (&vdata->vdsp, &odata->opacket)) + { /* weld the packet into the bitstream */ + ogg_stream_packetin (&odata->ostream, &odata->opacket) ; + + /* write out pages (if any) */ + while (!odata->eos) + { int result = ogg_stream_pageout (&odata->ostream, &odata->opage) ; + if (result == 0) break ; + ogg_write_page (psf, &odata->opage) ; + + /* this could be set above, but for illustrative purposes, I do + it here (to show that vorbis does know where the stream ends) */ + + if (ogg_page_eos (&odata->opage)) odata->eos = 1 ; + } + } + } + } + + /* ogg_page and ogg_packet structs always point to storage in + libvorbis. They are never freed or manipulated directly */ + + vorbis_block_clear (&vdata->vblock) ; + vorbis_dsp_clear (&vdata->vdsp) ; + vorbis_comment_clear (&vdata->vcomment) ; + vorbis_info_clear (&vdata->vinfo) ; + + return 0 ; +} /* vorbis_close */ + +int +ogg_vorbis_open (SF_PRIVATE *psf) +{ OGG_PRIVATE* odata = psf->container_data ; + VORBIS_PRIVATE* vdata ; + int error = 0 ; + + if (odata == NULL) + { psf_log_printf (psf, "%s : odata is NULL???\n", __func__) ; + return SFE_INTERNAL ; + } ; + + vdata = calloc (1, sizeof (VORBIS_PRIVATE)) ; + psf->codec_data = vdata ; + + if (psf->file.mode == SFM_RDWR) + return SFE_BAD_MODE_RW ; + + psf_log_printf (psf, "Vorbis library version : %s\n", vorbis_version_string ()) ; + + if (psf->file.mode == SFM_READ) + { if ((error = vorbis_read_header (psf))) + return error ; + + psf->read_short = vorbis_read_s ; + psf->read_int = vorbis_read_i ; + psf->read_float = vorbis_read_f ; + psf->read_double = vorbis_read_d ; + } ; + + psf->codec_close = vorbis_close ; + if (psf->file.mode == SFM_WRITE) + { + /* Set the default vorbis quality here. */ + vdata->quality = 0.4 ; + + psf->write_header = vorbis_write_header ; + psf->write_short = vorbis_write_s ; + psf->write_int = vorbis_write_i ; + psf->write_float = vorbis_write_f ; + psf->write_double = vorbis_write_d ; + + psf->sf.frames = 0 ; + psf->datalength = 0 ; + psf->filelength = 0 ; + psf->dataoffset = 0 ; + psf->strings.flags = SF_STR_ALLOW_START ; + } ; + + psf->seek = vorbis_seek ; + psf->command = vorbis_command ; + psf->byterate = vorbis_byterate ; + psf->sf.format = SF_FORMAT_OGG | SF_FORMAT_VORBIS ; + psf->sf.sections = 1 ; + + return error ; +} /* ogg_vorbis_open */ + +static int +vorbis_command (SF_PRIVATE *psf, int command, void * data, int datasize) +{ OGG_PRIVATE* odata = psf->container_data ; + VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ; + + switch (command) + { case SFC_SET_COMPRESSION_LEVEL : + if (data == NULL || datasize != sizeof (double)) + return SF_FALSE ; + + if (psf->have_written) + return SF_FALSE ; + + vdata->quality = 1.0 - *((double *) data) ; + + /* Clip range. */ + vdata->quality = SF_MAX (0.0, SF_MIN (1.0, vdata->quality)) ; + + 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 ; + } ; + + return SF_FALSE ; +} /* vorbis_command */ + +static int +vorbis_rnull (SF_PRIVATE *UNUSED (psf), int samples, void *UNUSED (vptr), int UNUSED (off) , int channels, float **UNUSED (pcm)) +{ + return samples * channels ; +} /* vorbis_rnull */ + +static int +vorbis_rshort (SF_PRIVATE *psf, int samples, void *vptr, int off, int channels, float **pcm) +{ + short *ptr = (short*) vptr + off ; + int i = 0, j, n ; + if (psf->float_int_mult) + { + float inverse = 1.0 / psf->float_max ; + for (j = 0 ; j < samples ; j++) + for (n = 0 ; n < channels ; n++) + ptr [i++] = psf_lrintf ((pcm [n][j] * inverse) * 32767.0f) ; + } + else + { + for (j = 0 ; j < samples ; j++) + for (n = 0 ; n < channels ; n++) + ptr [i++] = psf_lrintf (pcm [n][j] * 32767.0f) ; + } + return i ; +} /* vorbis_rshort */ + +static int +vorbis_rint (SF_PRIVATE *psf, int samples, void *vptr, int off, int channels, float **pcm) +{ + int *ptr = (int*) vptr + off ; + int i = 0, j, n ; + + if (psf->float_int_mult) + { + float inverse = 1.0 / psf->float_max ; + for (j = 0 ; j < samples ; j++) + for (n = 0 ; n < channels ; n++) + ptr [i++] = psf_lrintf ((pcm [n][j] * inverse) * 2147483647.0f) ; + } + else + { + for (j = 0 ; j < samples ; j++) + for (n = 0 ; n < channels ; n++) + ptr [i++] = psf_lrintf (pcm [n][j] * 2147483647.0f) ; + } + return i ; +} /* vorbis_rint */ + +static int +vorbis_rfloat (SF_PRIVATE *UNUSED (psf), int samples, void *vptr, int off, int channels, float **pcm) +{ + float *ptr = (float*) vptr + off ; + int i = 0, j, n ; + for (j = 0 ; j < samples ; j++) + for (n = 0 ; n < channels ; n++) + ptr [i++] = pcm [n][j] ; + return i ; +} /* vorbis_rfloat */ + +static int +vorbis_rdouble (SF_PRIVATE *UNUSED (psf), int samples, void *vptr, int off, int channels, float **pcm) +{ + double *ptr = (double*) vptr + off ; + int i = 0, j, n ; + for (j = 0 ; j < samples ; j++) + for (n = 0 ; n < channels ; n++) + ptr [i++] = pcm [n][j] ; + return i ; +} /* vorbis_rdouble */ + + +static sf_count_t +vorbis_read_sample (SF_PRIVATE *psf, void *ptr, sf_count_t lens, convert_func *transfn) +{ VORBIS_PRIVATE *vdata = psf->codec_data ; + OGG_PRIVATE *odata = psf->container_data ; + int len, samples, i = 0 , nn ; + float **pcm ; + + len = lens / psf->sf.channels ; + + while (len > 0) + { /* + ** pcm is a multichannel float vector. In stereo, for + ** example, pcm [0] is left, and pcm [1] is right. samples is + ** the size of each channel. Convert the float values + ** (-1.<=range<=1.) to whatever PCM format and write it out. + */ + while ((samples = vorbis_synthesis_pcmout (&vdata->vdsp, &pcm)) > 0) + { if (samples > len) samples = len ; + i += transfn (psf, samples, ptr, i, psf->sf.channels, pcm) ; + len -= samples ; + /* tell libvorbis how many samples we actually consumed */ + vorbis_synthesis_read (&vdata->vdsp, samples) ; + vdata->gp += samples ; + if (len == 0) + return i ; + } ; + + /* Out of samples, load the next packet. */ + if (odata->pkt_indx == odata->pkt_len) + { /* Page out of packets, load and unpack the next page. */ + nn = ogg_stream_unpack_page (psf, odata) ; + if (nn <= 0) + return i ; + if (nn == 2) + { /* Ran over a hole. gp is now out of date, need to recalculate. */ + vorbis_synthesis_restart (&vdata->vdsp) ; + vorbis_calculate_granulepos (psf, &vdata->gp) ; + } + } ; + + /* Decode the packet */ + if (vorbis_synthesis (&vdata->vblock, &(odata->pkt [odata->pkt_indx])) == 0) /* test for success! */ + vorbis_synthesis_blockin (&vdata->vdsp, &vdata->vblock) ; + odata->pkt_indx++ ; + } ; + + return i ; +} /* vorbis_read_sample */ + +static sf_count_t +vorbis_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t lens) +{ return vorbis_read_sample (psf, (void*) ptr, lens, vorbis_rshort) ; +} /* vorbis_read_s */ + +static sf_count_t +vorbis_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t lens) +{ return vorbis_read_sample (psf, (void*) ptr, lens, vorbis_rint) ; +} /* vorbis_read_i */ + +static sf_count_t +vorbis_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t lens) +{ return vorbis_read_sample (psf, (void*) ptr, lens, vorbis_rfloat) ; +} /* vorbis_read_f */ + +static sf_count_t +vorbis_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t lens) +{ return vorbis_read_sample (psf, (void*) ptr, lens, vorbis_rdouble) ; +} /* vorbis_read_d */ + +/*============================================================================== +*/ + +static void +vorbis_write_samples (SF_PRIVATE *psf, OGG_PRIVATE *odata, VORBIS_PRIVATE *vdata, int in_frames) +{ + vorbis_analysis_wrote (&vdata->vdsp, in_frames) ; + + /* + ** Vorbis does some data preanalysis, then divvies up blocks for + ** more involved (potentially parallel) processing. Get a single + ** block for encoding now. + */ + while (vorbis_analysis_blockout (&vdata->vdsp, &vdata->vblock) == 1) + { + /* analysis, assume we want to use bitrate management */ + vorbis_analysis (&vdata->vblock, NULL) ; + vorbis_bitrate_addblock (&vdata->vblock) ; + + while (vorbis_bitrate_flushpacket (&vdata->vdsp, &odata->opacket)) + { + /* weld the packet into the bitstream */ + ogg_stream_packetin (&odata->ostream, &odata->opacket) ; + + /* write out pages (if any) */ + while (!odata->eos) + { int result = ogg_stream_pageout (&odata->ostream, &odata->opage) ; + if (result == 0) + break ; + ogg_write_page (psf, &odata->opage) ; + + /* This could be set above, but for illustrative purposes, I do + ** it here (to show that vorbis does know where the stream ends) */ + if (ogg_page_eos (&odata->opage)) + odata->eos = 1 ; + } ; + } ; + } ; + + vdata->gp += in_frames ; +} /* vorbis_write_data */ + + +static sf_count_t +vorbis_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t lens) +{ + int i, m, j = 0 ; + OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; + VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ; + int in_frames = lens / psf->sf.channels ; + float **buffer = vorbis_analysis_buffer (&vdata->vdsp, in_frames) ; + for (i = 0 ; i < in_frames ; i++) + for (m = 0 ; m < psf->sf.channels ; m++) + buffer [m][i] = (float) (ptr [j++]) / 32767.0f ; + + vorbis_write_samples (psf, odata, vdata, in_frames) ; + + return lens ; +} /* vorbis_write_s */ + +static sf_count_t +vorbis_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t lens) +{ int i, m, j = 0 ; + OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; + VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ; + int in_frames = lens / psf->sf.channels ; + float **buffer = vorbis_analysis_buffer (&vdata->vdsp, in_frames) ; + for (i = 0 ; i < in_frames ; i++) + for (m = 0 ; m < psf->sf.channels ; m++) + buffer [m][i] = (float) (ptr [j++]) / 2147483647.0f ; + + vorbis_write_samples (psf, odata, vdata, in_frames) ; + + return lens ; +} /* vorbis_write_i */ + +static sf_count_t +vorbis_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t lens) +{ int i, m, j = 0 ; + OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; + VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ; + int in_frames = lens / psf->sf.channels ; + float **buffer = vorbis_analysis_buffer (&vdata->vdsp, in_frames) ; + for (i = 0 ; i < in_frames ; i++) + for (m = 0 ; m < psf->sf.channels ; m++) + buffer [m][i] = ptr [j++] ; + + vorbis_write_samples (psf, odata, vdata, in_frames) ; + + return lens ; +} /* vorbis_write_f */ + +static sf_count_t +vorbis_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t lens) +{ int i, m, j = 0 ; + OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; + VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ; + int in_frames = lens / psf->sf.channels ; + float **buffer = vorbis_analysis_buffer (&vdata->vdsp, in_frames) ; + for (i = 0 ; i < in_frames ; i++) + for (m = 0 ; m < psf->sf.channels ; m++) + buffer [m][i] = (float) ptr [j++] ; + + vorbis_write_samples (psf, odata, vdata, in_frames) ; + + return lens ; +} /* vorbis_write_d */ + +static int +vorbis_skip (SF_PRIVATE *psf, uint64_t target) +{ OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; + VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ; + ogg_packet *pkt ; + int thisblock, lastblock, nn ; + const int blocksize = vorbis_info_blocksize (&vdata->vinfo, 1) ; + + /* Read out any samples that may be in the decoder from a seek without a + ** search. */ + thisblock = vorbis_synthesis_pcmout (&vdata->vdsp, NULL) ; + if (thisblock > 0) + { if ((uint64_t) thisblock + vdata->gp >= target) + thisblock = SF_MIN (thisblock, (int) (target - vdata->gp)) ; + + vorbis_synthesis_read (&vdata->vdsp, thisblock) ; + vdata->gp += thisblock ; + if (vdata->gp == target) + return 0 ; + } ; + + /* Read through packets that are before our target */ + lastblock = 0 ; + for ( ; vdata->gp < target ; ) + { /* Ensure there are unpacked packets. */ + if (odata->pkt_indx == odata->pkt_len) + { /* Page out of packets, load and unpack the next page. */ + nn = ogg_stream_unpack_page (psf, odata) ; + if (nn < 0) + return nn ; + if (nn == 0) + break ; + if (nn == 2) + { /* Ran over a hole. gp is now out of date, need to recalculate. */ + vorbis_synthesis_restart (&vdata->vdsp) ; + vorbis_calculate_granulepos (psf, &vdata->gp) ; + if (target < vdata->gp) + { /* Our target is inside the hole :-( */ + return 0 ; + } ; + } ; + } ; + + pkt = &odata->pkt [odata->pkt_indx] ; + thisblock = vorbis_packet_blocksize (&vdata->vinfo, pkt) ; + if (thisblock < 0) + { /* Not an audio packet */ + odata->pkt_indx++ ; + continue ; + } ; + + if (lastblock) + { vdata->gp += ((lastblock + thisblock) / 4) ; + } ; + + /* Check to see if the block contains our target */ + if (vdata->gp + ((thisblock + blocksize) / 4) >= target) + break ; + + /* Block is before the target. Track for state, but don't decode. */ + odata->pkt_indx++ ; + vorbis_synthesis_trackonly (&vdata->vblock, pkt) ; + vorbis_synthesis_blockin (&vdata->vdsp, &vdata->vblock) ; + lastblock = thisblock ; + } ; + + /* We are at the correct block, but still need to consume samples to reach + ** our target. */ + vorbis_read_sample (psf, (void *) NULL, (target - vdata->gp) * psf->sf.channels, vorbis_rnull) ; + + return 0 ; +} /* vorbis_skip */ + +static int +vorbis_seek_trysearch (SF_PRIVATE *psf, uint64_t target_gp) +{ OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; + VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ; + uint64_t best_gp, search_target_gp ; + int ret ; + + /* Can't bisect a file we don't know the end of (cannot seek). */ + if (vdata->pcm_end == (uint64_t) -1) + return 0 ; + + /* If the target is for the near future, don't bother bisecting, just skip + ** to it. */ + if (target_gp >= vdata->gp && + target_gp - vdata->gp < ((unsigned) (VORBIS_SEEK_THRESHOLD) * psf->sf.samplerate)) + return 0 ; + + /* Search for a position a half large-block before our target. As Vorbis is + ** lapped, every sample position come from two blocks, the "left" half of + ** one block and the "right" half of the previous block. The granule + ** position of an Ogg page of a Vorbis stream is the sample offset of the + ** last finished sample in the stream that can be decoded from a page. A + ** page also contains another half-block of samples waiting to be lapped + ** with the first half-block of samples from the next page. + ** + ** Searching for a sample one half of a large block before our target + ** guarantees we always load a page containing the previous half block + ** required to decode the target. Downside is we can't use best_gp + ** parameter of the page seek function. */ + search_target_gp = vorbis_info_blocksize (&vdata->vinfo, 1) / 2 ; + 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->vinfo.rate) ; + if (ret < 0) + return ret ; + + ret = ogg_stream_unpack_page (psf, odata) ; + if (ret > 0) + { /* Reset the decoder, recalculate position */ + vorbis_synthesis_restart (&vdata->vdsp) ; + ret = vorbis_calculate_granulepos (psf, &vdata->gp) ; + } ; + + return ret ; +} /* vorbis_seek_trysearch */ + +static sf_count_t +vorbis_seek (SF_PRIVATE *psf, int UNUSED (mode), sf_count_t offset) +{ OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; + VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ; + uint64_t target_gp ; + int ret ; + + if (odata == NULL || vdata == NULL) + return 0 ; + + if (offset < 0) + { psf->error = SFE_BAD_SEEK ; + return ((sf_count_t) -1) ; + } ; + + if (psf->file.mode == SFM_READ) + { target_gp = (uint64_t) offset + vdata->pcm_start ; + + ret = vorbis_seek_trysearch (psf, target_gp) ; + + if (ret < 0 || vdata->gp > target_gp) + { /* Search failed (bad data?), reset to the beginning of the stream. */ + psf_log_printf (psf, "Vorbis: Seek search failed. Reading through stream from start.\n") ; + ogg_stream_reset_serialno (&odata->ostream, odata->ostream.serialno) ; + odata->pkt_len = 0 ; + odata->pkt_indx = 0 ; + ogg_sync_fseek (psf, psf->dataoffset, SEEK_SET) ; + vdata->gp = vdata->pcm_start ; + vorbis_synthesis_restart (&vdata->vdsp) ; + } ; + + vorbis_skip (psf, target_gp) ; + + return vdata->gp - vdata->pcm_start ; + } ; + + psf->error = SFE_BAD_SEEK ; + return ((sf_count_t) -1) ; +} /* vorbis_seek */ + +static int +vorbis_byterate (SF_PRIVATE *psf) +{ + if (psf->file.mode == SFM_READ) + return (psf->datalength * psf->sf.samplerate) / psf->sf.frames ; + + return -1 ; +} /* vorbis_byterate */ + +static int +vorbis_calculate_granulepos (SF_PRIVATE *psf, uint64_t *gp_out) +{ OGG_PRIVATE *odata = (OGG_PRIVATE *) psf->container_data ; + VORBIS_PRIVATE *vdata = (VORBIS_PRIVATE *) psf->codec_data ; + ogg_packet *pkt ; + uint64_t last_gp ; + int thisblock, lastblock, i ; + unsigned duration ; + + /* Calculate the granule position when dropped into the middle of a stream + ** with an un-primed decoder. + ** + ** Normally the last unpacked packet contains the granule position of the + ** last completed sample from decoding all the blocks in the page's + ** packets. By calculating how many samples we can decode from the blocks + ** in the page's packets and subtracting it from the final packet's granule + ** position we get the position of the first sample to be output from the + ** decoder after it primes. That is, the current granule position. + ** + ** However, there is an ambiguity if this is the last page of a stream. The + ** last page of a stream may have a granule position of fewer samples than + ** the page actually contains. The excess samples are padding leftovers + ** for and exact sample length file. */ + + if (odata->pkt_len > 0) + { /* Calculate how many samples can be decoded from blocks in this page, + ** accounting for the fact that blocks are 1/2 lapped. */ + lastblock = -1 ; + duration = 0 ; + pkt = odata->pkt ; + for (i = 0 ; i < odata->pkt_len ; i++) + { thisblock = vorbis_packet_blocksize (&vdata->vinfo, &pkt [i]) ; + if (thisblock >= 0) + { if (lastblock != -1) + duration += (lastblock + thisblock) >> 2 ; + lastblock = thisblock ; + } ; + } ; + + pkt = &odata->pkt [odata->pkt_len - 1] ; + last_gp = pkt->granulepos ; + if (last_gp == (uint64_t) -1) + { psf_log_printf (psf, "Vorbis: Ogg page has no granule position, cannot calculate sample position!\n") ; + psf->error = SFE_MALFORMED_FILE ; + return -1 ; + } ; + + if (pkt->e_o_s) + { if (last_gp <= duration) + { /* Corner case: One page stream. Ogg/Vorbis spec dictates the + ** granule position offset MUST be zero, hence this first (and + ** only) page must start at 0. */ + *gp_out = 0 ; + return 1 ; + } ; + + /* Otherwise, we cannot know where we are without looking at the + ** blocks of the previous page. (The granule position of the + ** previous page is not enough, we need the block sizes.) + ** + ** We avoid this case by never allowing a bisection search to seek + ** beyond the second-to-last page, so the last page is always + ** approached with a known location and never dropped into. + ** + ** The only way we should be able to end up here is if there was a + ** hole in stream just before the last page, in which case all bets + ** are off anyways. */ + psf_log_printf (psf, "Vorbis: Cannot calculate ambiguous last page duration. Sample count may be wrong.\n") ; + } ; + + if (last_gp < duration) + { psf_log_printf (psf, "Vorbis: Granule position is nonsensical! (Missing end-of-stream marker?)\n") ; + psf->error = SFE_MALFORMED_FILE ; + return -1 ; + } ; + + *gp_out = last_gp - duration ; + return 1 ; + } ; + + return 0 ; +} /* vorbis_calculate_granulepos */ + +#else /* HAVE_EXTERNAL_XIPH_LIBS */ + +int +ogg_vorbis_open (SF_PRIVATE *psf) +{ + psf_log_printf (psf, "This version of libsndfile was compiled without Ogg/Vorbis support.\n") ; + return SFE_UNIMPLEMENTED ; +} /* ogg_vorbis_open */ + +#endif diff --git a/extern/libsndfile-modified/src/paf.c b/extern/libsndfile-modified/src/paf.c new file mode 100644 index 000000000..871931c6c --- /dev/null +++ b/extern/libsndfile-modified/src/paf.c @@ -0,0 +1,818 @@ +/* +** Copyright (C) 1999-2017 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + +/*------------------------------------------------------------------------------ +** Macros to handle big/little endian issues. +*/ + +#define FAP_MARKER (MAKE_MARKER ('f', 'a', 'p', ' ')) +#define PAF_MARKER (MAKE_MARKER (' ', 'p', 'a', 'f')) + +/*------------------------------------------------------------------------------ +** Other defines. +*/ + +#define PAF_HEADER_LENGTH 2048 + +#define PAF24_SAMPLES_PER_BLOCK 10 +#define PAF24_BLOCK_SIZE 32 + +/*------------------------------------------------------------------------------ +** Typedefs. +*/ + +typedef struct +{ int version ; + int endianness ; + int samplerate ; + int format ; + int channels ; + int source ; +} PAF_FMT ; + +typedef struct +{ int max_blocks, channels, blocksize ; + int read_block, write_block, read_count, write_count ; + sf_count_t sample_count ; + int *samples ; + int *block ; + int data [] ; /* ISO C99 struct flexible array. */ +} PAF24_PRIVATE ; + +/*------------------------------------------------------------------------------ +** Private static functions. +*/ + +static int paf24_init (SF_PRIVATE *psf) ; + +static int paf_read_header (SF_PRIVATE *psf) ; +static int paf_write_header (SF_PRIVATE *psf, int calc_length) ; + +static sf_count_t paf24_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; +static sf_count_t paf24_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; +static sf_count_t paf24_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; +static sf_count_t paf24_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; + +static sf_count_t paf24_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; +static sf_count_t paf24_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; +static sf_count_t paf24_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; +static sf_count_t paf24_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; + +static sf_count_t paf24_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ; + +enum +{ PAF_PCM_16 = 0, + PAF_PCM_24 = 1, + PAF_PCM_S8 = 2 +} ; + +/*------------------------------------------------------------------------------ +** Public function. +*/ + +int +paf_open (SF_PRIVATE *psf) +{ int subformat, error, endian ; + + psf->dataoffset = PAF_HEADER_LENGTH ; + + if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0)) + { if ((error = paf_read_header (psf))) + return error ; + } ; + + subformat = SF_CODEC (psf->sf.format) ; + + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_PAF) + return SFE_BAD_OPEN_FORMAT ; + + endian = SF_ENDIAN (psf->sf.format) ; + + /* PAF is by default big endian. */ + psf->endian = SF_ENDIAN_BIG ; + + if (endian == SF_ENDIAN_LITTLE || (CPU_IS_LITTLE_ENDIAN && (endian == SF_ENDIAN_CPU))) + psf->endian = SF_ENDIAN_LITTLE ; + + if ((error = paf_write_header (psf, SF_FALSE))) + return error ; + + psf->write_header = paf_write_header ; + } ; + + switch (subformat) + { case SF_FORMAT_PCM_S8 : + psf->bytewidth = 1 ; + error = pcm_init (psf) ; + break ; + + case SF_FORMAT_PCM_16 : + psf->bytewidth = 2 ; + error = pcm_init (psf) ; + break ; + + case SF_FORMAT_PCM_24 : + /* No bytewidth because of whacky 24 bit encoding. */ + error = paf24_init (psf) ; + break ; + + default : return SFE_PAF_UNKNOWN_FORMAT ; + } ; + + return error ; +} /* paf_open */ + +/*------------------------------------------------------------------------------ +*/ + +static int +paf_read_header (SF_PRIVATE *psf) +{ PAF_FMT paf_fmt ; + int marker ; + + if (psf->filelength < PAF_HEADER_LENGTH) + return SFE_PAF_SHORT_HEADER ; + + memset (&paf_fmt, 0, sizeof (paf_fmt)) ; + psf_binheader_readf (psf, "pm", 0, &marker) ; + + psf_log_printf (psf, "Signature : '%M'\n", marker) ; + + if (marker == PAF_MARKER) + { psf_binheader_readf (psf, "E444444", &(paf_fmt.version), &(paf_fmt.endianness), + &(paf_fmt.samplerate), &(paf_fmt.format), &(paf_fmt.channels), &(paf_fmt.source)) ; + } + else if (marker == FAP_MARKER) + { psf_binheader_readf (psf, "e444444", &(paf_fmt.version), &(paf_fmt.endianness), + &(paf_fmt.samplerate), &(paf_fmt.format), &(paf_fmt.channels), &(paf_fmt.source)) ; + } + else + return SFE_PAF_NO_MARKER ; + + psf_log_printf (psf, "Version : %d\n", paf_fmt.version) ; + + if (paf_fmt.version != 0) + { psf_log_printf (psf, "*** Bad version number. should be zero.\n") ; + return SFE_PAF_VERSION ; + } ; + + psf_log_printf (psf, "Sample Rate : %d\n", paf_fmt.samplerate) ; + psf_log_printf (psf, "Channels : %d\n", paf_fmt.channels) ; + + psf_log_printf (psf, "Endianness : %d => ", paf_fmt.endianness) ; + if (paf_fmt.endianness) + { psf_log_printf (psf, "Little\n", paf_fmt.endianness) ; + psf->endian = SF_ENDIAN_LITTLE ; + } + else + { psf_log_printf (psf, "Big\n", paf_fmt.endianness) ; + psf->endian = SF_ENDIAN_BIG ; + } ; + + if (paf_fmt.channels < 1 || paf_fmt.channels > SF_MAX_CHANNELS) + return SFE_PAF_BAD_CHANNELS ; + + psf->datalength = psf->filelength - psf->dataoffset ; + + psf_binheader_readf (psf, "p", (int) psf->dataoffset) ; + + psf->sf.samplerate = paf_fmt.samplerate ; + psf->sf.channels = paf_fmt.channels ; + + /* Only fill in type major. */ + psf->sf.format = SF_FORMAT_PAF ; + + psf_log_printf (psf, "Format : %d => ", paf_fmt.format) ; + + /* PAF is by default big endian. */ + psf->sf.format |= paf_fmt.endianness ? SF_ENDIAN_LITTLE : SF_ENDIAN_BIG ; + + switch (paf_fmt.format) + { case PAF_PCM_S8 : + psf_log_printf (psf, "8 bit linear PCM\n") ; + psf->bytewidth = 1 ; + + psf->sf.format |= SF_FORMAT_PCM_S8 ; + + psf->blockwidth = psf->bytewidth * psf->sf.channels ; + psf->sf.frames = psf->datalength / psf->blockwidth ; + break ; + + case PAF_PCM_16 : + psf_log_printf (psf, "16 bit linear PCM\n") ; + psf->bytewidth = 2 ; + + psf->sf.format |= SF_FORMAT_PCM_16 ; + + psf->blockwidth = psf->bytewidth * psf->sf.channels ; + psf->sf.frames = psf->datalength / psf->blockwidth ; + break ; + + case PAF_PCM_24 : + psf_log_printf (psf, "24 bit linear PCM\n") ; + psf->bytewidth = 3 ; + + psf->sf.format |= SF_FORMAT_PCM_24 ; + + psf->blockwidth = 0 ; + psf->sf.frames = PAF24_SAMPLES_PER_BLOCK * psf->datalength / + (PAF24_BLOCK_SIZE * psf->sf.channels) ; + break ; + + default : psf_log_printf (psf, "Unknown\n") ; + return SFE_PAF_UNKNOWN_FORMAT ; + break ; + } ; + + psf_log_printf (psf, "Source : %d => ", paf_fmt.source) ; + + switch (paf_fmt.source) + { case 1 : psf_log_printf (psf, "Analog Recording\n") ; + break ; + case 2 : psf_log_printf (psf, "Digital Transfer\n") ; + break ; + case 3 : psf_log_printf (psf, "Multi-track Mixdown\n") ; + break ; + case 5 : psf_log_printf (psf, "Audio Resulting From DSP Processing\n") ; + break ; + default : psf_log_printf (psf, "Unknown\n") ; + break ; + } ; + + return 0 ; +} /* paf_read_header */ + +static int +paf_write_header (SF_PRIVATE *psf, int UNUSED (calc_length)) +{ int paf_format ; + + /* PAF header already written so no need to re-write. */ + if (psf_ftell (psf) >= PAF_HEADER_LENGTH) + return 0 ; + + psf->dataoffset = PAF_HEADER_LENGTH ; + + switch (SF_CODEC (psf->sf.format)) + { case SF_FORMAT_PCM_S8 : + paf_format = PAF_PCM_S8 ; + break ; + + case SF_FORMAT_PCM_16 : + paf_format = PAF_PCM_16 ; + break ; + + case SF_FORMAT_PCM_24 : + paf_format = PAF_PCM_24 ; + break ; + + default : return SFE_PAF_UNKNOWN_FORMAT ; + } ; + + /* Reset the current header length to zero. */ + psf->header.ptr [0] = 0 ; + psf->header.indx = 0 ; + + if (psf->endian == SF_ENDIAN_BIG) + { /* Marker, version, endianness, samplerate */ + psf_binheader_writef (psf, "Em444", BHWm (PAF_MARKER), BHW4 (0), BHW4 (0), BHW4 (psf->sf.samplerate)) ; + /* format, channels, source */ + psf_binheader_writef (psf, "E444", BHW4 (paf_format), BHW4 (psf->sf.channels), BHW4 (0)) ; + } + else if (psf->endian == SF_ENDIAN_LITTLE) + { /* Marker, version, endianness, samplerate */ + psf_binheader_writef (psf, "em444", BHWm (FAP_MARKER), BHW4 (0), BHW4 (1), BHW4 (psf->sf.samplerate)) ; + /* format, channels, source */ + psf_binheader_writef (psf, "e444", BHW4 (paf_format), BHW4 (psf->sf.channels), BHW4 (0)) ; + } ; + + /* Zero fill to dataoffset. */ + psf_binheader_writef (psf, "z", BHWz ((size_t) (psf->dataoffset - psf->header.indx))) ; + + psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ; + + return psf->error ; +} /* paf_write_header */ + +/*=============================================================================== +** 24 bit PAF files have a really weird encoding. +** For a mono file, 10 samples (each being 3 bytes) are packed into a 32 byte +** block. The 8 ints in this 32 byte block are then endian swapped (as ints) +** if necessary before being written to disk. +** For a stereo file, blocks of 10 samples from the same channel are encoded +** into 32 bytes as for the mono case. The 32 byte blocks are then interleaved +** on disk. +** Reading has to reverse the above process :-). +** Weird!!! +** +** The code below attempts to gain efficiency while maintaining readability. +*/ + +static int paf24_read_block (SF_PRIVATE *psf, PAF24_PRIVATE *ppaf24) ; +static int paf24_write_block (SF_PRIVATE *psf, PAF24_PRIVATE *ppaf24) ; +static int paf24_close (SF_PRIVATE *psf) ; + + +static int +paf24_init (SF_PRIVATE *psf) +{ PAF24_PRIVATE *ppaf24 ; + int paf24size ; + + paf24size = sizeof (PAF24_PRIVATE) + psf->sf.channels * + (PAF24_BLOCK_SIZE + PAF24_SAMPLES_PER_BLOCK * sizeof (int)) ; + + /* + ** Not exatly sure why this needs to be here but the tests + ** fail without it. + */ + psf->last_op = 0 ; + + if (! (psf->codec_data = calloc (1, paf24size))) + return SFE_MALLOC_FAILED ; + + ppaf24 = (PAF24_PRIVATE*) psf->codec_data ; + + ppaf24->channels = psf->sf.channels ; + ppaf24->samples = ppaf24->data ; + ppaf24->block = ppaf24->data + PAF24_SAMPLES_PER_BLOCK * ppaf24->channels ; + + ppaf24->blocksize = PAF24_BLOCK_SIZE * ppaf24->channels ; + + if (psf->file.mode == SFM_READ || psf->file.mode == SFM_RDWR) + { paf24_read_block (psf, ppaf24) ; /* Read first block. */ + + psf->read_short = paf24_read_s ; + psf->read_int = paf24_read_i ; + psf->read_float = paf24_read_f ; + psf->read_double = paf24_read_d ; + } ; + + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { psf->write_short = paf24_write_s ; + psf->write_int = paf24_write_i ; + psf->write_float = paf24_write_f ; + psf->write_double = paf24_write_d ; + } ; + + psf->seek = paf24_seek ; + psf->container_close = paf24_close ; + + psf->filelength = psf_get_filelen (psf) ; + psf->datalength = psf->filelength - psf->dataoffset ; + + if (psf->datalength % PAF24_BLOCK_SIZE) + { if (psf->file.mode == SFM_READ) + psf_log_printf (psf, "*** Warning : file seems to be truncated.\n") ; + ppaf24->max_blocks = psf->datalength / ppaf24->blocksize + 1 ; + } + else + ppaf24->max_blocks = psf->datalength / ppaf24->blocksize ; + + ppaf24->read_block = 0 ; + if (psf->file.mode == SFM_RDWR) + ppaf24->write_block = ppaf24->max_blocks ; + else + ppaf24->write_block = 0 ; + + psf->sf.frames = PAF24_SAMPLES_PER_BLOCK * ppaf24->max_blocks ; + ppaf24->sample_count = psf->sf.frames ; + + return 0 ; +} /* paf24_init */ + +static sf_count_t +paf24_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) +{ PAF24_PRIVATE *ppaf24 ; + int newblock, newsample ; + + if (psf->codec_data == NULL) + { psf->error = SFE_INTERNAL ; + return PSF_SEEK_ERROR ; + } ; + + ppaf24 = (PAF24_PRIVATE*) psf->codec_data ; + + if (mode == SFM_READ && ppaf24->write_count > 0) + paf24_write_block (psf, ppaf24) ; + + newblock = offset / PAF24_SAMPLES_PER_BLOCK ; + newsample = offset % PAF24_SAMPLES_PER_BLOCK ; + + switch (mode) + { case SFM_READ : + if (psf->last_op == SFM_WRITE && ppaf24->write_count) + paf24_write_block (psf, ppaf24) ; + + psf_fseek (psf, psf->dataoffset + newblock * ppaf24->blocksize, SEEK_SET) ; + ppaf24->read_block = newblock ; + paf24_read_block (psf, ppaf24) ; + ppaf24->read_count = newsample ; + break ; + + case SFM_WRITE : + if (offset > ppaf24->sample_count) + { psf->error = SFE_BAD_SEEK ; + return PSF_SEEK_ERROR ; + } ; + + if (psf->last_op == SFM_WRITE && ppaf24->write_count) + paf24_write_block (psf, ppaf24) ; + + psf_fseek (psf, psf->dataoffset + newblock * ppaf24->blocksize, SEEK_SET) ; + ppaf24->write_block = newblock ; + paf24_read_block (psf, ppaf24) ; + ppaf24->write_count = newsample ; + break ; + + default : + psf->error = SFE_BAD_SEEK ; + return PSF_SEEK_ERROR ; + } ; + + return newblock * PAF24_SAMPLES_PER_BLOCK + newsample ; +} /* paf24_seek */ + +static int +paf24_close (SF_PRIVATE *psf) +{ PAF24_PRIVATE *ppaf24 ; + + if (psf->codec_data == NULL) + return 0 ; + + ppaf24 = (PAF24_PRIVATE*) psf->codec_data ; + + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { if (ppaf24->write_count > 0) + paf24_write_block (psf, ppaf24) ; + } ; + + return 0 ; +} /* paf24_close */ + +/*--------------------------------------------------------------------------- +*/ +static int +paf24_read_block (SF_PRIVATE *psf, PAF24_PRIVATE *ppaf24) +{ int k, channel ; + unsigned char *cptr ; + + ppaf24->read_block ++ ; + ppaf24->read_count = 0 ; + + if (ppaf24->read_block * PAF24_SAMPLES_PER_BLOCK > ppaf24->sample_count) + { memset (ppaf24->samples, 0, PAF24_SAMPLES_PER_BLOCK * ppaf24->channels) ; + return 1 ; + } ; + + /* Read the block. */ + if ((k = (int) psf_fread (ppaf24->block, 1, ppaf24->blocksize, psf)) != ppaf24->blocksize) + psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, ppaf24->blocksize) ; + + /* Do endian swapping if necessary. */ + if ((CPU_IS_BIG_ENDIAN && psf->endian == SF_ENDIAN_LITTLE) || (CPU_IS_LITTLE_ENDIAN && psf->endian == SF_ENDIAN_BIG)) + endswap_int_array (ppaf24->block, 8 * ppaf24->channels) ; + + /* Unpack block. */ + for (k = 0 ; k < PAF24_SAMPLES_PER_BLOCK * ppaf24->channels ; k++) + { channel = k % ppaf24->channels ; + cptr = ((unsigned char *) ppaf24->block) + PAF24_BLOCK_SIZE * channel + 3 * (k / ppaf24->channels) ; + ppaf24->samples [k] = (cptr [0] << 8) | (cptr [1] << 16) | (((unsigned) cptr [2]) << 24) ; + } ; + + return 1 ; +} /* paf24_read_block */ + +static int +paf24_read (SF_PRIVATE *psf, PAF24_PRIVATE *ppaf24, int *ptr, int len) +{ int count, total = 0 ; + + while (total < len) + { if (ppaf24->read_block * PAF24_SAMPLES_PER_BLOCK >= ppaf24->sample_count) + { memset (&(ptr [total]), 0, (len - total) * sizeof (int)) ; + return total ; + } ; + + if (ppaf24->read_count >= PAF24_SAMPLES_PER_BLOCK) + paf24_read_block (psf, ppaf24) ; + + count = (PAF24_SAMPLES_PER_BLOCK - ppaf24->read_count) * ppaf24->channels ; + count = (len - total > count) ? count : len - total ; + + memcpy (&(ptr [total]), &(ppaf24->samples [ppaf24->read_count * ppaf24->channels]), count * sizeof (int)) ; + total += count ; + ppaf24->read_count += count / ppaf24->channels ; + } ; + + return total ; +} /* paf24_read */ + +static sf_count_t +paf24_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + PAF24_PRIVATE *ppaf24 ; + int *iptr ; + int k, bufferlen, readcount, count ; + sf_count_t total = 0 ; + + if (psf->codec_data == NULL) + return 0 ; + ppaf24 = (PAF24_PRIVATE*) psf->codec_data ; + + iptr = ubuf.ibuf ; + bufferlen = ARRAY_LEN (ubuf.ibuf) ; + while (len > 0) + { readcount = (len >= bufferlen) ? bufferlen : (int) len ; + count = paf24_read (psf, ppaf24, iptr, readcount) ; + for (k = 0 ; k < readcount ; k++) + ptr [total + k] = iptr [k] >> 16 ; + total += count ; + len -= readcount ; + } ; + return total ; +} /* paf24_read_s */ + +static sf_count_t +paf24_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) +{ PAF24_PRIVATE *ppaf24 ; + int total ; + + if (psf->codec_data == NULL) + return 0 ; + ppaf24 = (PAF24_PRIVATE*) psf->codec_data ; + + total = paf24_read (psf, ppaf24, ptr, len) ; + + return total ; +} /* paf24_read_i */ + +static sf_count_t +paf24_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + PAF24_PRIVATE *ppaf24 ; + int *iptr ; + int k, bufferlen, readcount, count ; + sf_count_t total = 0 ; + float normfact ; + + if (psf->codec_data == NULL) + return 0 ; + ppaf24 = (PAF24_PRIVATE*) psf->codec_data ; + + normfact = (psf->norm_float == SF_TRUE) ? (1.0 / 0x80000000) : (1.0 / 0x100) ; + + iptr = ubuf.ibuf ; + bufferlen = ARRAY_LEN (ubuf.ibuf) ; + while (len > 0) + { readcount = (len >= bufferlen) ? bufferlen : (int) len ; + count = paf24_read (psf, ppaf24, iptr, readcount) ; + for (k = 0 ; k < readcount ; k++) + ptr [total + k] = normfact * iptr [k] ; + total += count ; + len -= readcount ; + } ; + return total ; +} /* paf24_read_f */ + +static sf_count_t +paf24_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + PAF24_PRIVATE *ppaf24 ; + int *iptr ; + int k, bufferlen, readcount, count ; + sf_count_t total = 0 ; + double normfact ; + + if (psf->codec_data == NULL) + return 0 ; + ppaf24 = (PAF24_PRIVATE*) psf->codec_data ; + + normfact = (psf->norm_double == SF_TRUE) ? (1.0 / 0x80000000) : (1.0 / 0x100) ; + + iptr = ubuf.ibuf ; + bufferlen = ARRAY_LEN (ubuf.ibuf) ; + while (len > 0) + { readcount = (len >= bufferlen) ? bufferlen : (int) len ; + count = paf24_read (psf, ppaf24, iptr, readcount) ; + for (k = 0 ; k < readcount ; k++) + ptr [total + k] = normfact * iptr [k] ; + total += count ; + len -= readcount ; + } ; + return total ; +} /* paf24_read_d */ + +/*--------------------------------------------------------------------------- +*/ + +static int +paf24_write_block (SF_PRIVATE *psf, PAF24_PRIVATE *ppaf24) +{ int k, nextsample, channel ; + unsigned char *cptr ; + + /* First pack block. */ + + if (CPU_IS_LITTLE_ENDIAN) + { for (k = 0 ; k < PAF24_SAMPLES_PER_BLOCK * ppaf24->channels ; k++) + { channel = k % ppaf24->channels ; + cptr = ((unsigned char *) ppaf24->block) + PAF24_BLOCK_SIZE * channel + 3 * (k / ppaf24->channels) ; + nextsample = ppaf24->samples [k] >> 8 ; + cptr [0] = nextsample ; + cptr [1] = nextsample >> 8 ; + cptr [2] = nextsample >> 16 ; + } ; + + /* Do endian swapping if necessary. */ + if (psf->endian == SF_ENDIAN_BIG) + endswap_int_array (ppaf24->block, 8 * ppaf24->channels) ; + } + else if (CPU_IS_BIG_ENDIAN) + { /* This is correct. */ + for (k = 0 ; k < PAF24_SAMPLES_PER_BLOCK * ppaf24->channels ; k++) + { channel = k % ppaf24->channels ; + cptr = ((unsigned char *) ppaf24->block) + PAF24_BLOCK_SIZE * channel + 3 * (k / ppaf24->channels) ; + nextsample = ppaf24->samples [k] >> 8 ; + cptr [0] = nextsample ; + cptr [1] = nextsample >> 8 ; + cptr [2] = nextsample >> 16 ; + } ; + if (psf->endian == SF_ENDIAN_LITTLE) + endswap_int_array (ppaf24->block, 8 * ppaf24->channels) ; + } ; + + /* Write block to disk. */ + if ((k = (int) psf_fwrite (ppaf24->block, 1, ppaf24->blocksize, psf)) != ppaf24->blocksize) + psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", k, ppaf24->blocksize) ; + + if (ppaf24->sample_count < ppaf24->write_block * PAF24_SAMPLES_PER_BLOCK + ppaf24->write_count) + ppaf24->sample_count = ppaf24->write_block * PAF24_SAMPLES_PER_BLOCK + ppaf24->write_count ; + + if (ppaf24->write_count == PAF24_SAMPLES_PER_BLOCK) + { ppaf24->write_block ++ ; + ppaf24->write_count = 0 ; + } ; + + return 1 ; +} /* paf24_write_block */ + +static int +paf24_write (SF_PRIVATE *psf, PAF24_PRIVATE *ppaf24, const int *ptr, int len) +{ int count, total = 0 ; + + while (total < len) + { count = (PAF24_SAMPLES_PER_BLOCK - ppaf24->write_count) * ppaf24->channels ; + + if (count > len - total) + count = len - total ; + + memcpy (&(ppaf24->samples [ppaf24->write_count * ppaf24->channels]), &(ptr [total]), count * sizeof (int)) ; + total += count ; + ppaf24->write_count += count / ppaf24->channels ; + + if (ppaf24->write_count >= PAF24_SAMPLES_PER_BLOCK) + paf24_write_block (psf, ppaf24) ; + } ; + + return total ; +} /* paf24_write */ + +static sf_count_t +paf24_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + PAF24_PRIVATE *ppaf24 ; + int *iptr ; + int k, bufferlen, writecount = 0, count ; + sf_count_t total = 0 ; + + if (psf->codec_data == NULL) + return 0 ; + ppaf24 = (PAF24_PRIVATE*) psf->codec_data ; + + iptr = ubuf.ibuf ; + bufferlen = ARRAY_LEN (ubuf.ibuf) ; + while (len > 0) + { writecount = (len >= bufferlen) ? bufferlen : (int) len ; + for (k = 0 ; k < writecount ; k++) + iptr [k] = ptr [total + k] << 16 ; + count = paf24_write (psf, ppaf24, iptr, writecount) ; + total += count ; + len -= writecount ; + if (count != writecount) + break ; + } ; + return total ; +} /* paf24_write_s */ + +static sf_count_t +paf24_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) +{ PAF24_PRIVATE *ppaf24 ; + int writecount, count ; + sf_count_t total = 0 ; + + if (psf->codec_data == NULL) + return 0 ; + ppaf24 = (PAF24_PRIVATE*) psf->codec_data ; + + while (len > 0) + { writecount = (len > 0x10000000) ? 0x10000000 : (int) len ; + + count = paf24_write (psf, ppaf24, ptr, writecount) ; + + total += count ; + len -= count ; + if (count != writecount) + break ; + } ; + + return total ; +} /* paf24_write_i */ + +static sf_count_t +paf24_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + PAF24_PRIVATE *ppaf24 ; + int *iptr ; + int k, bufferlen, writecount = 0, count ; + sf_count_t total = 0 ; + float normfact ; + + if (psf->codec_data == NULL) + return 0 ; + ppaf24 = (PAF24_PRIVATE*) psf->codec_data ; + + normfact = (psf->norm_float == SF_TRUE) ? (1.0 * 0x7FFFFFFF) : (1.0 / 0x100) ; + + iptr = ubuf.ibuf ; + bufferlen = ARRAY_LEN (ubuf.ibuf) ; + while (len > 0) + { writecount = (len >= bufferlen) ? bufferlen : (int) len ; + for (k = 0 ; k < writecount ; k++) + iptr [k] = psf_lrintf (normfact * ptr [total + k]) ; + count = paf24_write (psf, ppaf24, iptr, writecount) ; + total += count ; + len -= writecount ; + if (count != writecount) + break ; + } ; + + return total ; +} /* paf24_write_f */ + +static sf_count_t +paf24_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + PAF24_PRIVATE *ppaf24 ; + int *iptr ; + int k, bufferlen, writecount = 0, count ; + sf_count_t total = 0 ; + double normfact ; + + if (psf->codec_data == NULL) + return 0 ; + ppaf24 = (PAF24_PRIVATE*) psf->codec_data ; + + normfact = (psf->norm_double == SF_TRUE) ? (1.0 * 0x7FFFFFFF) : (1.0 / 0x100) ; + + iptr = ubuf.ibuf ; + bufferlen = ARRAY_LEN (ubuf.ibuf) ; + while (len > 0) + { writecount = (len >= bufferlen) ? bufferlen : (int) len ; + for (k = 0 ; k < writecount ; k++) + iptr [k] = psf_lrint (normfact * ptr [total+k]) ; + count = paf24_write (psf, ppaf24, iptr, writecount) ; + total += count ; + len -= writecount ; + if (count != writecount) + break ; + } ; + + return total ; +} /* paf24_write_d */ + diff --git a/extern/libsndfile-modified/src/pcm.c b/extern/libsndfile-modified/src/pcm.c new file mode 100644 index 000000000..d7dc82c4f --- /dev/null +++ b/extern/libsndfile-modified/src/pcm.c @@ -0,0 +1,2918 @@ +/* +** Copyright (C) 1999-2016 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + +/* Need to be able to handle 3 byte (24 bit) integers. So defined a +** type and use SIZEOF_TRIBYTE instead of (tribyte). +*/ + +typedef struct tribyte +{ uint8_t bytes [3] ; + } tribyte ; + +#define SIZEOF_TRIBYTE 3 + +static sf_count_t pcm_read_sc2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; +static sf_count_t pcm_read_uc2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; +static sf_count_t pcm_read_bes2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; +static sf_count_t pcm_read_les2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; +static sf_count_t pcm_read_bet2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; +static sf_count_t pcm_read_let2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; +static sf_count_t pcm_read_bei2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; +static sf_count_t pcm_read_lei2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; + +static sf_count_t pcm_read_sc2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; +static sf_count_t pcm_read_uc2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; +static sf_count_t pcm_read_bes2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; +static sf_count_t pcm_read_les2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; +static sf_count_t pcm_read_bet2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; +static sf_count_t pcm_read_let2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; +static sf_count_t pcm_read_bei2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; +static sf_count_t pcm_read_lei2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; + +static sf_count_t pcm_read_sc2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; +static sf_count_t pcm_read_uc2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; +static sf_count_t pcm_read_bes2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; +static sf_count_t pcm_read_les2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; +static sf_count_t pcm_read_bet2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; +static sf_count_t pcm_read_let2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; +static sf_count_t pcm_read_bei2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; +static sf_count_t pcm_read_lei2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; + +static sf_count_t pcm_read_sc2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; +static sf_count_t pcm_read_uc2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; +static sf_count_t pcm_read_bes2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; +static sf_count_t pcm_read_les2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; +static sf_count_t pcm_read_bet2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; +static sf_count_t pcm_read_let2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; +static sf_count_t pcm_read_bei2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; +static sf_count_t pcm_read_lei2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; + +static sf_count_t pcm_write_s2sc (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; +static sf_count_t pcm_write_s2uc (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; +static sf_count_t pcm_write_s2bes (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; +static sf_count_t pcm_write_s2les (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; +static sf_count_t pcm_write_s2bet (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; +static sf_count_t pcm_write_s2let (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; +static sf_count_t pcm_write_s2bei (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; +static sf_count_t pcm_write_s2lei (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; + +static sf_count_t pcm_write_i2sc (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; +static sf_count_t pcm_write_i2uc (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; +static sf_count_t pcm_write_i2bes (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; +static sf_count_t pcm_write_i2les (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; +static sf_count_t pcm_write_i2bet (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; +static sf_count_t pcm_write_i2let (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; +static sf_count_t pcm_write_i2bei (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; +static sf_count_t pcm_write_i2lei (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; + +static sf_count_t pcm_write_f2sc (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; +static sf_count_t pcm_write_f2uc (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; +static sf_count_t pcm_write_f2bes (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; +static sf_count_t pcm_write_f2les (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; +static sf_count_t pcm_write_f2bet (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; +static sf_count_t pcm_write_f2let (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; +static sf_count_t pcm_write_f2bei (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; +static sf_count_t pcm_write_f2lei (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; + +static sf_count_t pcm_write_d2sc (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; +static sf_count_t pcm_write_d2uc (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; +static sf_count_t pcm_write_d2bes (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; +static sf_count_t pcm_write_d2les (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; +static sf_count_t pcm_write_d2bet (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; +static sf_count_t pcm_write_d2let (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; +static sf_count_t pcm_write_d2bei (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; +static sf_count_t pcm_write_d2lei (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; + +/*----------------------------------------------------------------------------------------------- +*/ + +enum +{ /* Char type for 8 bit files. */ + SF_CHARS_SIGNED = 200, + SF_CHARS_UNSIGNED = 201 +} ; + +/*----------------------------------------------------------------------------------------------- +*/ + +int +pcm_init (SF_PRIVATE *psf) +{ int chars = 0 ; + + if (psf->bytewidth == 0 || psf->sf.channels == 0) + { psf_log_printf (psf, "pcm_init : internal error : bytewitdh = %d, channels = %d\n", psf->bytewidth, psf->sf.channels) ; + return SFE_INTERNAL ; + } ; + + psf->blockwidth = psf->bytewidth * psf->sf.channels ; + + if ((SF_CODEC (psf->sf.format)) == SF_FORMAT_PCM_S8) + chars = SF_CHARS_SIGNED ; + else if ((SF_CODEC (psf->sf.format)) == SF_FORMAT_PCM_U8) + chars = SF_CHARS_UNSIGNED ; + +#if CPU_IS_BIG_ENDIAN + psf->data_endswap = (psf->endian == SF_ENDIAN_BIG) ? SF_FALSE : SF_TRUE ; +#else + psf->data_endswap = (psf->endian == SF_ENDIAN_LITTLE) ? SF_FALSE : SF_TRUE ; +#endif + + if (psf->file.mode == SFM_READ || psf->file.mode == SFM_RDWR) + { switch (psf->bytewidth * 0x10000 + psf->endian + chars) + { case (0x10000 + SF_ENDIAN_BIG + SF_CHARS_SIGNED) : + case (0x10000 + SF_ENDIAN_LITTLE + SF_CHARS_SIGNED) : + psf->read_short = pcm_read_sc2s ; + psf->read_int = pcm_read_sc2i ; + psf->read_float = pcm_read_sc2f ; + psf->read_double = pcm_read_sc2d ; + break ; + case (0x10000 + SF_ENDIAN_BIG + SF_CHARS_UNSIGNED) : + case (0x10000 + SF_ENDIAN_LITTLE + SF_CHARS_UNSIGNED) : + psf->read_short = pcm_read_uc2s ; + psf->read_int = pcm_read_uc2i ; + psf->read_float = pcm_read_uc2f ; + psf->read_double = pcm_read_uc2d ; + break ; + + case (2 * 0x10000 + SF_ENDIAN_BIG) : + psf->read_short = pcm_read_bes2s ; + psf->read_int = pcm_read_bes2i ; + psf->read_float = pcm_read_bes2f ; + psf->read_double = pcm_read_bes2d ; + break ; + case (3 * 0x10000 + SF_ENDIAN_BIG) : + psf->read_short = pcm_read_bet2s ; + psf->read_int = pcm_read_bet2i ; + psf->read_float = pcm_read_bet2f ; + psf->read_double = pcm_read_bet2d ; + break ; + case (4 * 0x10000 + SF_ENDIAN_BIG) : + + psf->read_short = pcm_read_bei2s ; + psf->read_int = pcm_read_bei2i ; + psf->read_float = pcm_read_bei2f ; + psf->read_double = pcm_read_bei2d ; + break ; + + case (2 * 0x10000 + SF_ENDIAN_LITTLE) : + psf->read_short = pcm_read_les2s ; + psf->read_int = pcm_read_les2i ; + psf->read_float = pcm_read_les2f ; + psf->read_double = pcm_read_les2d ; + break ; + case (3 * 0x10000 + SF_ENDIAN_LITTLE) : + psf->read_short = pcm_read_let2s ; + psf->read_int = pcm_read_let2i ; + psf->read_float = pcm_read_let2f ; + psf->read_double = pcm_read_let2d ; + break ; + case (4 * 0x10000 + SF_ENDIAN_LITTLE) : + psf->read_short = pcm_read_lei2s ; + psf->read_int = pcm_read_lei2i ; + psf->read_float = pcm_read_lei2f ; + psf->read_double = pcm_read_lei2d ; + break ; + default : + psf_log_printf (psf, "pcm.c returning SFE_UNIMPLEMENTED\nbytewidth %d endian %d\n", psf->bytewidth, psf->endian) ; + return SFE_UNIMPLEMENTED ; + } ; + } ; + + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { switch (psf->bytewidth * 0x10000 + psf->endian + chars) + { case (0x10000 + SF_ENDIAN_BIG + SF_CHARS_SIGNED) : + case (0x10000 + SF_ENDIAN_LITTLE + SF_CHARS_SIGNED) : + psf->write_short = pcm_write_s2sc ; + psf->write_int = pcm_write_i2sc ; + psf->write_float = pcm_write_f2sc ; + psf->write_double = pcm_write_d2sc ; + break ; + case (0x10000 + SF_ENDIAN_BIG + SF_CHARS_UNSIGNED) : + case (0x10000 + SF_ENDIAN_LITTLE + SF_CHARS_UNSIGNED) : + psf->write_short = pcm_write_s2uc ; + psf->write_int = pcm_write_i2uc ; + psf->write_float = pcm_write_f2uc ; + psf->write_double = pcm_write_d2uc ; + break ; + + case (2 * 0x10000 + SF_ENDIAN_BIG) : + psf->write_short = pcm_write_s2bes ; + psf->write_int = pcm_write_i2bes ; + psf->write_float = pcm_write_f2bes ; + psf->write_double = pcm_write_d2bes ; + break ; + + case (3 * 0x10000 + SF_ENDIAN_BIG) : + psf->write_short = pcm_write_s2bet ; + psf->write_int = pcm_write_i2bet ; + psf->write_float = pcm_write_f2bet ; + psf->write_double = pcm_write_d2bet ; + break ; + + case (4 * 0x10000 + SF_ENDIAN_BIG) : + psf->write_short = pcm_write_s2bei ; + psf->write_int = pcm_write_i2bei ; + psf->write_float = pcm_write_f2bei ; + psf->write_double = pcm_write_d2bei ; + break ; + + case (2 * 0x10000 + SF_ENDIAN_LITTLE) : + psf->write_short = pcm_write_s2les ; + psf->write_int = pcm_write_i2les ; + psf->write_float = pcm_write_f2les ; + psf->write_double = pcm_write_d2les ; + break ; + + case (3 * 0x10000 + SF_ENDIAN_LITTLE) : + psf->write_short = pcm_write_s2let ; + psf->write_int = pcm_write_i2let ; + psf->write_float = pcm_write_f2let ; + psf->write_double = pcm_write_d2let ; + break ; + + case (4 * 0x10000 + SF_ENDIAN_LITTLE) : + psf->write_short = pcm_write_s2lei ; + psf->write_int = pcm_write_i2lei ; + psf->write_float = pcm_write_f2lei ; + psf->write_double = pcm_write_d2lei ; + break ; + + default : + psf_log_printf (psf, "pcm.c returning SFE_UNIMPLEMENTED\nbytewidth %d endian %d\n", psf->bytewidth, psf->endian) ; + return SFE_UNIMPLEMENTED ; + } ; + + } ; + + if (psf->filelength > psf->dataoffset) + { psf->datalength = (psf->dataend > 0) ? psf->dataend - psf->dataoffset : + psf->filelength - psf->dataoffset ; + } + else + psf->datalength = 0 ; + + psf->sf.frames = psf->blockwidth > 0 ? psf->datalength / psf->blockwidth : 0 ; + + return 0 ; +} /* pcm_init */ + +/*============================================================================== +*/ + +static inline void +sc2s_array (const signed char *src, int count, short *dest) +{ for (int i = 0 ; i < count ; i++) + { dest [i] = ((uint16_t) src [i]) << 8 ; + } ; +} /* sc2s_array */ + +static inline void +uc2s_array (const unsigned char *src, int count, short *dest) +{ for (int i = 0 ; i < count ; i++) + { dest [i] = (((uint32_t) src [i]) - 0x80) << 8 ; + } ; +} /* uc2s_array */ + +static inline void +let2s_array (const tribyte *src, int count, short *dest) +{ for (int i = 0 ; i < count ; i++) + dest [i] = LET2H_16_PTR (src [i].bytes) ; +} /* let2s_array */ + +static inline void +bet2s_array (const tribyte *src, int count, short *dest) +{ for (int i = 0 ; i < count ; i++) + dest [i] = BET2H_16_PTR (src [i].bytes) ; +} /* bet2s_array */ + +static inline void +lei2s_array (const int *src, int count, short *dest) +{ int value ; + + for (int i = 0 ; i < count ; i++) + { value = LE2H_32 (src [i]) ; + dest [i] = value >> 16 ; + } ; +} /* lei2s_array */ + +static inline void +bei2s_array (const int *src, int count, short *dest) +{ int value ; + + for (int i = 0 ; i < count ; i++) + { value = BE2H_32 (src [i]) ; + dest [i] = value >> 16 ; + } ; +} /* bei2s_array */ + +/*-------------------------------------------------------------------------- +*/ + +static inline void +sc2i_array (const signed char *src, int count, int *dest) +{ for (int i = 0 ; i < count ; i++) + { dest [i] = arith_shift_left ((int) src [i], 24) ; + } ; +} /* sc2i_array */ + +static inline void +uc2i_array (const unsigned char *src, int count, int *dest) +{ for (int i = 0 ; i < count ; i++) + { dest [i] = arith_shift_left (((int) src [i]) - 128, 24) ; + } ; +} /* uc2i_array */ + +static inline void +bes2i_array (const short *src, int count, int *dest) +{ short value ; + + for (int i = 0 ; i < count ; i++) + { value = BE2H_16 (src [i]) ; + dest [i] = arith_shift_left (value, 16) ; + } ; +} /* bes2i_array */ + +static inline void +les2i_array (const short *src, int count, int *dest) +{ short value ; + + for (int i = 0 ; i < count ; i++) + { value = LE2H_16 (src [i]) ; + dest [i] = arith_shift_left (value, 16) ; + } ; +} /* les2i_array */ + +static inline void +bet2i_array (const tribyte *src, int count, int *dest) +{ for (int i = 0 ; i < count ; i++) + dest [i] = psf_get_be24 (src [i].bytes, 0) ; +} /* bet2i_array */ + +static inline void +let2i_array (const tribyte *src, int count, int *dest) +{ for (int i = 0 ; i < count ; i++) + dest [i] = psf_get_le24 (src [i].bytes, 0) ; +} /* let2i_array */ + +/*-------------------------------------------------------------------------- +*/ + +static inline void +sc2f_array (const signed char *src, int count, float *dest, float normfact) +{ for (int i = 0 ; i < count ; i++) + dest [i] = ((float) src [i]) * normfact ; +} /* sc2f_array */ + +static inline void +uc2f_array (const unsigned char *src, int count, float *dest, float normfact) +{ for (int i = 0 ; i < count ; i++) + dest [i] = (((int) src [i]) - 128) * normfact ; +} /* uc2f_array */ + +static inline void +les2f_array (const short *src, int count, float *dest, float normfact) +{ short value ; + + for (int i = 0 ; i < count ; i++) + { value = src [i] ; + value = LE2H_16 (value) ; + dest [i] = ((float) value) * normfact ; + } ; +} /* les2f_array */ + +static inline void +bes2f_array (const short *src, int count, float *dest, float normfact) +{ short value ; + + for (int i = 0 ; i < count ; i++) + { value = src [i] ; + value = BE2H_16 (value) ; + dest [i] = ((float) value) * normfact ; + } ; +} /* bes2f_array */ + +static inline void +let2f_array (const tribyte *src, int count, float *dest, float normfact) +{ int value ; + + for (int i = 0 ; i < count ; i++) + { value = psf_get_le24 (src [i].bytes, 0) ; + dest [i] = ((float) value) * normfact ; + } ; +} /* let2f_array */ + +static inline void +bet2f_array (const tribyte *src, int count, float *dest, float normfact) +{ int value ; + + for (int i = 0 ; i < count ; i++) + { value = psf_get_be24 (src [i].bytes, 0) ; + dest [i] = ((float) value) * normfact ; + } ; +} /* bet2f_array */ + +static inline void +lei2f_array (const int *src, int count, float *dest, float normfact) +{ int value ; + + for (int i = 0 ; i < count ; i++) + { value = src [i] ; + value = LE2H_32 (value) ; + dest [i] = ((float) value) * normfact ; + } ; +} /* lei2f_array */ + +static inline void +bei2f_array (const int *src, int count, float *dest, float normfact) +{ int value ; + + for (int i = 0 ; i < count ; i++) + { value = src [i] ; + value = BE2H_32 (value) ; + dest [i] = ((float) value) * normfact ; + } ; +} /* bei2f_array */ + +/*-------------------------------------------------------------------------- +*/ + +static inline void +sc2d_array (const signed char *src, int count, double *dest, double normfact) +{ for (int i = 0 ; i < count ; i++) + dest [i] = ((double) src [i]) * normfact ; +} /* sc2d_array */ + +static inline void +uc2d_array (const unsigned char *src, int count, double *dest, double normfact) +{ for (int i = 0 ; i < count ; i++) + dest [i] = (((int) src [i]) - 128) * normfact ; +} /* uc2d_array */ + +static inline void +les2d_array (const short *src, int count, double *dest, double normfact) +{ short value ; + + for (int i = 0 ; i < count ; i++) + { value = src [i] ; + value = LE2H_16 (value) ; + dest [i] = ((double) value) * normfact ; + } ; +} /* les2d_array */ + +static inline void +bes2d_array (const short *src, int count, double *dest, double normfact) +{ short value ; + + for (int i = 0 ; i < count ; i++) + { value = src [i] ; + value = BE2H_16 (value) ; + dest [i] = ((double) value) * normfact ; + } ; +} /* bes2d_array */ + +static inline void +let2d_array (const tribyte *src, int count, double *dest, double normfact) +{ int value ; + + for (int i = 0 ; i < count ; i++) + { value = psf_get_le24 (src [i].bytes, 0) ; + dest [i] = ((double) value) * normfact ; + } ; +} /* let2d_array */ + +static inline void +bet2d_array (const tribyte *src, int count, double *dest, double normfact) +{ int value ; + + for (int i = 0 ; i < count ; i++) + { value = psf_get_be24 (src [i].bytes, 0) ; + dest [i] = ((double) value) * normfact ; + } ; +} /* bet2d_array */ + +static inline void +lei2d_array (const int *src, int count, double *dest, double normfact) +{ int value ; + + for (int i = 0 ; i < count ; i++) + { value = src [i] ; + value = LE2H_32 (value) ; + dest [i] = ((double) value) * normfact ; + } ; +} /* lei2d_array */ + +static inline void +bei2d_array (const int *src, int count, double *dest, double normfact) +{ int value ; + + for (int i = 0 ; i < count ; i++) + { value = src [i] ; + value = BE2H_32 (value) ; + dest [i] = ((double) value) * normfact ; + } ; +} /* bei2d_array */ + +/*-------------------------------------------------------------------------- +*/ + +static inline void +s2sc_array (const short *src, signed char *dest, int count) +{ for (int i = 0 ; i < count ; i++) + dest [i] = src [i] >> 8 ; +} /* s2sc_array */ + +static inline void +s2uc_array (const short *src, unsigned char *dest, int count) +{ for (int i = 0 ; i < count ; i++) + dest [i] = (src [i] >> 8) + 0x80 ; +} /* s2uc_array */ + +static inline void +s2let_array (const short *src, tribyte *dest, int count) +{ for (int i = 0 ; i < count ; i++) + { dest [i].bytes [0] = 0 ; + dest [i].bytes [1] = src [i] ; + dest [i].bytes [2] = src [i] >> 8 ; + } ; +} /* s2let_array */ + +static inline void +s2bet_array (const short *src, tribyte *dest, int count) +{ for (int i = 0 ; i < count ; i++) + { dest [i].bytes [2] = 0 ; + dest [i].bytes [1] = src [i] ; + dest [i].bytes [0] = src [i] >> 8 ; + } ; +} /* s2bet_array */ + +static inline void +s2lei_array (const short *src, int *dest, int count) +{ unsigned char *ucptr ; + + for (int i = 0 ; i < count ; i++) + { ucptr = (unsigned char*) &dest [i] ; + ucptr [0] = 0 ; + ucptr [1] = 0 ; + ucptr [2] = src [i] ; + ucptr [3] = src [i] >> 8 ; + } ; +} /* s2lei_array */ + +static inline void +s2bei_array (const short *src, int *dest, int count) +{ unsigned char *ucptr ; + + for (int i = 0 ; i < count ; i++) + { ucptr = (unsigned char*) &dest [i] ; + ucptr [0] = src [i] >> 8 ; + ucptr [1] = src [i] ; + ucptr [2] = 0 ; + ucptr [3] = 0 ; + } ; +} /* s2bei_array */ + +/*-------------------------------------------------------------------------- +*/ + +static inline void +i2sc_array (const int *src, signed char *dest, int count) +{ for (int i = 0 ; i < count ; i++) + dest [i] = (src [i] >> 24) ; +} /* i2sc_array */ + +static inline void +i2uc_array (const int *src, unsigned char *dest, int count) +{ for (int i = 0 ; i < count ; i++) + dest [i] = ((src [i] >> 24) + 128) ; +} /* i2uc_array */ + +static inline void +i2bes_array (const int *src, short *dest, int count) +{ unsigned char *ucptr ; + + for (int i = 0 ; i < count ; i++) + { ucptr = (unsigned char*) &dest [i] ; + ucptr [0] = src [i] >> 24 ; + ucptr [1] = src [i] >> 16 ; + } ; +} /* i2bes_array */ + +static inline void +i2les_array (const int *src, short *dest, int count) +{ unsigned char *ucptr ; + + for (int i = 0 ; i < count ; i++) + { ucptr = (unsigned char*) &dest [i] ; + ucptr [0] = src [i] >> 16 ; + ucptr [1] = src [i] >> 24 ; + } ; +} /* i2les_array */ + +static inline void +i2let_array (const int *src, tribyte *dest, int count) +{ int value ; + + for (int i = 0 ; i < count ; i++) + { value = src [i] >> 8 ; + dest [i].bytes [0] = value ; + dest [i].bytes [1] = value >> 8 ; + dest [i].bytes [2] = value >> 16 ; + } ; +} /* i2let_array */ + +static inline void +i2bet_array (const int *src, tribyte *dest, int count) +{ int value ; + + for (int i = 0 ; i < count ; i++) + { value = src [i] >> 8 ; + dest [i].bytes [2] = value ; + dest [i].bytes [1] = value >> 8 ; + dest [i].bytes [0] = value >> 16 ; + } ; +} /* i2bet_array */ + +/*=============================================================================================== +*/ + +static sf_count_t +pcm_read_sc2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + + bufferlen = ARRAY_LEN (ubuf.scbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.scbuf, sizeof (signed char), bufferlen, psf) ; + sc2s_array (ubuf.scbuf, readcount, ptr + total) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* pcm_read_sc2s */ + +static sf_count_t +pcm_read_uc2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + + bufferlen = ARRAY_LEN (ubuf.ucbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.ucbuf, sizeof (unsigned char), bufferlen, psf) ; + uc2s_array (ubuf.ucbuf, readcount, ptr + total) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* pcm_read_uc2s */ + +static sf_count_t +pcm_read_bes2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) +{ int total ; + + total = (int) psf_fread (ptr, sizeof (short), len, psf) ; +#if CPU_IS_LITTLE_ENDIAN + endswap_short_array (ptr, len) ; +#endif + + return total ; +} /* pcm_read_bes2s */ + +static sf_count_t +pcm_read_les2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) +{ int total ; + + total = psf_fread (ptr, sizeof (short), len, psf) ; +#if CPU_IS_BIG_ENDIAN + endswap_short_array (ptr, len) ; +#endif + + return total ; +} /* pcm_read_les2s */ + +static sf_count_t +pcm_read_bet2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + + bufferlen = sizeof (ubuf.ucbuf) / SIZEOF_TRIBYTE ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ; + bet2s_array ((tribyte*) (ubuf.ucbuf), readcount, ptr + total) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* pcm_read_bet2s */ + +static sf_count_t +pcm_read_let2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + + bufferlen = sizeof (ubuf.ucbuf) / SIZEOF_TRIBYTE ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ; + let2s_array ((tribyte*) (ubuf.ucbuf), readcount, ptr + total) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* pcm_read_let2s */ + +static sf_count_t +pcm_read_bei2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + + bufferlen = ARRAY_LEN (ubuf.ibuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.ibuf, sizeof (int), bufferlen, psf) ; + bei2s_array (ubuf.ibuf, readcount, ptr + total) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* pcm_read_bei2s */ + +static sf_count_t +pcm_read_lei2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + + bufferlen = ARRAY_LEN (ubuf.ibuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.ibuf, sizeof (int), bufferlen, psf) ; + lei2s_array (ubuf.ibuf, readcount, ptr + total) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* pcm_read_lei2s */ + +/*----------------------------------------------------------------------------------------------- +*/ + +static sf_count_t +pcm_read_sc2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + + bufferlen = ARRAY_LEN (ubuf.scbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.scbuf, sizeof (signed char), bufferlen, psf) ; + sc2i_array (ubuf.scbuf, readcount, ptr + total) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* pcm_read_sc2i */ + +static sf_count_t +pcm_read_uc2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + + bufferlen = ARRAY_LEN (ubuf.ucbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.ucbuf, sizeof (unsigned char), bufferlen, psf) ; + uc2i_array (ubuf.ucbuf, readcount, ptr + total) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* pcm_read_uc2i */ + +static sf_count_t +pcm_read_bes2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.sbuf, sizeof (short), bufferlen, psf) ; + bes2i_array (ubuf.sbuf, readcount, ptr + total) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* pcm_read_bes2i */ + +static sf_count_t +pcm_read_les2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.sbuf, sizeof (short), bufferlen, psf) ; + les2i_array (ubuf.sbuf, readcount, ptr + total) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* pcm_read_les2i */ + +static sf_count_t +pcm_read_bet2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + + bufferlen = sizeof (ubuf.ucbuf) / SIZEOF_TRIBYTE ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ; + bet2i_array ((tribyte*) (ubuf.ucbuf), readcount, ptr + total) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* pcm_read_bet2i */ + +static sf_count_t +pcm_read_let2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + + bufferlen = sizeof (ubuf.ucbuf) / SIZEOF_TRIBYTE ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ; + let2i_array ((tribyte*) (ubuf.ucbuf), readcount, ptr + total) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* pcm_read_let2i */ + +static sf_count_t +pcm_read_bei2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) +{ int total ; + + total = psf_fread (ptr, sizeof (int), len, psf) ; +#if CPU_IS_LITTLE_ENDIAN + endswap_int_array (ptr, len) ; +#endif + + return total ; +} /* pcm_read_bei2i */ + +static sf_count_t +pcm_read_lei2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) +{ int total ; + + total = psf_fread (ptr, sizeof (int), len, psf) ; +#if CPU_IS_BIG_ENDIAN + endswap_int_array (ptr, len) ; +#endif + + return total ; +} /* pcm_read_lei2i */ + +/*----------------------------------------------------------------------------------------------- +*/ + +static sf_count_t +pcm_read_sc2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + float normfact ; + + normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x80) : 1.0 ; + + bufferlen = ARRAY_LEN (ubuf.scbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.scbuf, sizeof (signed char), bufferlen, psf) ; + sc2f_array (ubuf.scbuf, readcount, ptr + total, normfact) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* pcm_read_sc2f */ + +static sf_count_t +pcm_read_uc2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + float normfact ; + + normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x80) : 1.0 ; + + bufferlen = ARRAY_LEN (ubuf.ucbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.ucbuf, sizeof (unsigned char), bufferlen, psf) ; + uc2f_array (ubuf.ucbuf, readcount, ptr + total, normfact) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* pcm_read_uc2f */ + +static sf_count_t +pcm_read_bes2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + float normfact ; + + normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x8000) : 1.0 ; + + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.sbuf, sizeof (short), bufferlen, psf) ; + bes2f_array (ubuf.sbuf, readcount, ptr + total, normfact) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* pcm_read_bes2f */ + +static sf_count_t +pcm_read_les2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + float normfact ; + + normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x8000) : 1.0 ; + + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.sbuf, sizeof (short), bufferlen, psf) ; + les2f_array (ubuf.sbuf, readcount, ptr + total, normfact) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* pcm_read_les2f */ + +static sf_count_t +pcm_read_bet2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + float normfact ; + + /* Special normfactor because tribyte value is read into an int. */ + normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x80000000) : 1.0 / 256.0 ; + + bufferlen = sizeof (ubuf.ucbuf) / SIZEOF_TRIBYTE ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ; + bet2f_array ((tribyte*) (ubuf.ucbuf), readcount, ptr + total, normfact) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* pcm_read_bet2f */ + +static sf_count_t +pcm_read_let2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + float normfact ; + + /* Special normfactor because tribyte value is read into an int. */ + normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x80000000) : 1.0 / 256.0 ; + + bufferlen = sizeof (ubuf.ucbuf) / SIZEOF_TRIBYTE ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ; + let2f_array ((tribyte*) (ubuf.ucbuf), readcount, ptr + total, normfact) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* pcm_read_let2f */ + +static sf_count_t +pcm_read_bei2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + float normfact ; + + normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x80000000) : 1.0 ; + + bufferlen = ARRAY_LEN (ubuf.ibuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.ibuf, sizeof (int), bufferlen, psf) ; + bei2f_array (ubuf.ibuf, readcount, ptr + total, normfact) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* pcm_read_bei2f */ + +static sf_count_t +pcm_read_lei2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + float normfact ; + + normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x80000000) : 1.0 ; + + bufferlen = ARRAY_LEN (ubuf.ibuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.ibuf, sizeof (int), bufferlen, psf) ; + lei2f_array (ubuf.ibuf, readcount, ptr + total, normfact) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* pcm_read_lei2f */ + +/*----------------------------------------------------------------------------------------------- +*/ + +static sf_count_t +pcm_read_sc2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + double normfact ; + + normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x80) : 1.0 ; + + bufferlen = ARRAY_LEN (ubuf.scbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.scbuf, sizeof (signed char), bufferlen, psf) ; + sc2d_array (ubuf.scbuf, readcount, ptr + total, normfact) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* pcm_read_sc2d */ + +static sf_count_t +pcm_read_uc2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + double normfact ; + + normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x80) : 1.0 ; + + bufferlen = ARRAY_LEN (ubuf.ucbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.ucbuf, sizeof (unsigned char), bufferlen, psf) ; + uc2d_array (ubuf.ucbuf, readcount, ptr + total, normfact) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* pcm_read_uc2d */ + +static sf_count_t +pcm_read_bes2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + double normfact ; + + normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x8000) : 1.0 ; + + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.sbuf, sizeof (short), bufferlen, psf) ; + bes2d_array (ubuf.sbuf, readcount, ptr + total, normfact) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* pcm_read_bes2d */ + +static sf_count_t +pcm_read_les2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + double normfact ; + + normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x8000) : 1.0 ; + + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.sbuf, sizeof (short), bufferlen, psf) ; + les2d_array (ubuf.sbuf, readcount, ptr + total, normfact) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* pcm_read_les2d */ + +static sf_count_t +pcm_read_bet2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + double normfact ; + + normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x80000000) : 1.0 / 256.0 ; + + bufferlen = sizeof (ubuf.ucbuf) / SIZEOF_TRIBYTE ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ; + bet2d_array ((tribyte*) (ubuf.ucbuf), readcount, ptr + total, normfact) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* pcm_read_bet2d */ + +static sf_count_t +pcm_read_let2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + double normfact ; + + /* Special normfactor because tribyte value is read into an int. */ + normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x80000000) : 1.0 / 256.0 ; + + bufferlen = sizeof (ubuf.ucbuf) / SIZEOF_TRIBYTE ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ; + let2d_array ((tribyte*) (ubuf.ucbuf), readcount, ptr + total, normfact) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* pcm_read_let2d */ + +static sf_count_t +pcm_read_bei2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + double normfact ; + + normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x80000000) : 1.0 ; + + bufferlen = ARRAY_LEN (ubuf.ibuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.ibuf, sizeof (int), bufferlen, psf) ; + bei2d_array (ubuf.ibuf, readcount, ptr + total, normfact) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* pcm_read_bei2d */ + +static sf_count_t +pcm_read_lei2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + double normfact ; + + normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x80000000) : 1.0 ; + + bufferlen = ARRAY_LEN (ubuf.ibuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.ibuf, sizeof (int), bufferlen, psf) ; + lei2d_array (ubuf.ibuf, readcount, ptr + total, normfact) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* pcm_read_lei2d */ + +/*=============================================================================================== +**----------------------------------------------------------------------------------------------- +**=============================================================================================== +*/ + +static sf_count_t +pcm_write_s2sc (SF_PRIVATE *psf, const short *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + bufferlen = ARRAY_LEN (ubuf.scbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + s2sc_array (ptr + total, ubuf.scbuf, bufferlen) ; + writecount = (int) psf_fwrite (ubuf.scbuf, sizeof (signed char), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* pcm_write_s2sc */ + +static sf_count_t +pcm_write_s2uc (SF_PRIVATE *psf, const short *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + bufferlen = ARRAY_LEN (ubuf.ucbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + s2uc_array (ptr + total, ubuf.ucbuf, bufferlen) ; + writecount = (int) psf_fwrite (ubuf.ucbuf, sizeof (unsigned char), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* pcm_write_s2uc */ + +static sf_count_t +pcm_write_s2bes (SF_PRIVATE *psf, const short *ptr, sf_count_t len) +{ +#if CPU_IS_BIG_ENDIAN + return psf_fwrite (ptr, sizeof (short), len, psf) ; +#else + BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + endswap_short_copy (ubuf.sbuf, ptr + total, bufferlen) ; + writecount = (int) psf_fwrite (ubuf.sbuf, sizeof (short), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +#endif +} /* pcm_write_s2bes */ + +static sf_count_t +pcm_write_s2les (SF_PRIVATE *psf, const short *ptr, sf_count_t len) +{ +#if CPU_IS_LITTLE_ENDIAN + return psf_fwrite (ptr, sizeof (short), len, psf) ; +#else + BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + endswap_short_copy (ubuf.sbuf, ptr + total, bufferlen) ; + writecount = (int) psf_fwrite (ubuf.sbuf, sizeof (short), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +#endif +} /* pcm_write_s2les */ + +static sf_count_t +pcm_write_s2bet (SF_PRIVATE *psf, const short *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + bufferlen = sizeof (ubuf.ucbuf) / SIZEOF_TRIBYTE ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + s2bet_array (ptr + total, (tribyte*) (ubuf.ucbuf), bufferlen) ; + writecount = (int) psf_fwrite (ubuf.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* pcm_write_s2bet */ + +static sf_count_t +pcm_write_s2let (SF_PRIVATE *psf, const short *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + bufferlen = sizeof (ubuf.ucbuf) / SIZEOF_TRIBYTE ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + s2let_array (ptr + total, (tribyte*) (ubuf.ucbuf), bufferlen) ; + writecount = (int) psf_fwrite (ubuf.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* pcm_write_s2let */ + +static sf_count_t +pcm_write_s2bei (SF_PRIVATE *psf, const short *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + bufferlen = ARRAY_LEN (ubuf.ibuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + s2bei_array (ptr + total, ubuf.ibuf, bufferlen) ; + writecount = (int) psf_fwrite (ubuf.ibuf, sizeof (int), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* pcm_write_s2bei */ + +static sf_count_t +pcm_write_s2lei (SF_PRIVATE *psf, const short *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + bufferlen = ARRAY_LEN (ubuf.ibuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + s2lei_array (ptr + total, ubuf.ibuf, bufferlen) ; + writecount = (int) psf_fwrite (ubuf.ibuf, sizeof (int), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* pcm_write_s2lei */ + +/*----------------------------------------------------------------------------------------------- +*/ + +static sf_count_t +pcm_write_i2sc (SF_PRIVATE *psf, const int *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + bufferlen = ARRAY_LEN (ubuf.scbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + i2sc_array (ptr + total, ubuf.scbuf, bufferlen) ; + writecount = (int) psf_fwrite (ubuf.scbuf, sizeof (signed char), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* pcm_write_i2sc */ + +static sf_count_t +pcm_write_i2uc (SF_PRIVATE *psf, const int *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + bufferlen = ARRAY_LEN (ubuf.ucbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + i2uc_array (ptr + total, ubuf.ucbuf, bufferlen) ; + writecount = (int) psf_fwrite (ubuf.ucbuf, sizeof (signed char), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* pcm_write_i2uc */ + +static sf_count_t +pcm_write_i2bes (SF_PRIVATE *psf, const int *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + i2bes_array (ptr + total, ubuf.sbuf, bufferlen) ; + writecount = (int) psf_fwrite (ubuf.sbuf, sizeof (short), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* pcm_write_i2bes */ + +static sf_count_t +pcm_write_i2les (SF_PRIVATE *psf, const int *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + i2les_array (ptr + total, ubuf.sbuf, bufferlen) ; + writecount = (int) psf_fwrite (ubuf.sbuf, sizeof (short), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* pcm_write_i2les */ + +static sf_count_t +pcm_write_i2bet (SF_PRIVATE *psf, const int *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + bufferlen = sizeof (ubuf.ucbuf) / SIZEOF_TRIBYTE ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + i2bet_array (ptr + total, (tribyte*) (ubuf.ucbuf), bufferlen) ; + writecount = (int) psf_fwrite (ubuf.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* pcm_write_i2bet */ + +static sf_count_t +pcm_write_i2let (SF_PRIVATE *psf, const int *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + bufferlen = sizeof (ubuf.ucbuf) / SIZEOF_TRIBYTE ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + i2let_array (ptr + total, (tribyte*) (ubuf.ucbuf), bufferlen) ; + writecount = (int) psf_fwrite (ubuf.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* pcm_write_i2les */ + +static sf_count_t +pcm_write_i2bei (SF_PRIVATE *psf, const int *ptr, sf_count_t len) +{ +#if CPU_IS_BIG_ENDIAN + return psf_fwrite (ptr, sizeof (int), len, psf) ; +#else + BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + bufferlen = ARRAY_LEN (ubuf.ibuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + endswap_int_copy (ubuf.ibuf, ptr + total, bufferlen) ; + writecount = (int) psf_fwrite (ubuf.ibuf, sizeof (int), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +#endif +} /* pcm_write_i2bei */ + +static sf_count_t +pcm_write_i2lei (SF_PRIVATE *psf, const int *ptr, sf_count_t len) +{ +#if CPU_IS_LITTLE_ENDIAN + return psf_fwrite (ptr, sizeof (int), len, psf) ; +#else + BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + bufferlen = ARRAY_LEN (ubuf.ibuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + endswap_int_copy (ubuf.ibuf, ptr + total, bufferlen) ; + writecount = (int) psf_fwrite (ubuf.ibuf, sizeof (int), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +#endif +} /* pcm_write_i2lei */ + +/*------------------------------------------------------------------------------ +**============================================================================== +**------------------------------------------------------------------------------ +*/ + +static void +f2sc_array (const float *src, signed char *dest, int count, int normalize) +{ float normfact ; + + normfact = normalize ? (1.0 * 0x7F) : 1.0 ; + + for (int i = 0 ; i < count ; i++) + { dest [i] = psf_lrintf (src [i] * normfact) ; + } ; +} /* f2sc_array */ + +static void +f2sc_clip_array (const float *src, signed char *dest, int count, int normalize) +{ float normfact, scaled_value ; + + normfact = normalize ? (8.0 * 0x10000000) : (1.0 * 0x1000000) ; + + for (int i = 0 ; i < count ; i++) + { scaled_value = src [i] * normfact ; + if (scaled_value >= (1.0 * 0x7FFFFFFF)) + { dest [i] = 127 ; + continue ; + } ; + if (scaled_value <= (-8.0 * 0x10000000)) + { dest [i] = -128 ; + continue ; + } ; + + dest [i] = psf_lrintf (scaled_value) >> 24 ; + } ; +} /* f2sc_clip_array */ + +static sf_count_t +pcm_write_f2sc (SF_PRIVATE *psf, const float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + void (*convert) (const float *, signed char *, int, int) ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + convert = (psf->add_clipping) ? f2sc_clip_array : f2sc_array ; + bufferlen = ARRAY_LEN (ubuf.scbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + convert (ptr + total, ubuf.scbuf, bufferlen, psf->norm_float) ; + writecount = (int) psf_fwrite (ubuf.scbuf, sizeof (signed char), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* pcm_write_f2sc */ + +/*============================================================================== +*/ + +static void +f2uc_array (const float *src, unsigned char *dest, int count, int normalize) +{ float normfact ; + + normfact = normalize ? (1.0 * 0x7F) : 1.0 ; + + for (int i = 0 ; i < count ; i++) + { dest [i] = psf_lrintf (src [i] * normfact) + 128 ; + } ; +} /* f2uc_array */ + +static void +f2uc_clip_array (const float *src, unsigned char *dest, int count, int normalize) +{ float normfact, scaled_value ; + + normfact = normalize ? (8.0 * 0x10000000) : (1.0 * 0x1000000) ; + + for (int i = 0 ; i < count ; i++) + { scaled_value = src [i] * normfact ; + if (scaled_value >= (1.0 * 0x7FFFFFFF)) + { dest [i] = 0xFF ; + continue ; + } ; + if (scaled_value <= (-8.0 * 0x10000000)) + { dest [i] = 0 ; + continue ; + } ; + + dest [i] = (psf_lrintf (scaled_value) >> 24) + 128 ; + } ; +} /* f2uc_clip_array */ + +static sf_count_t +pcm_write_f2uc (SF_PRIVATE *psf, const float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + void (*convert) (const float *, unsigned char *, int, int) ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + convert = (psf->add_clipping) ? f2uc_clip_array : f2uc_array ; + bufferlen = ARRAY_LEN (ubuf.ucbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + convert (ptr + total, ubuf.ucbuf, bufferlen, psf->norm_float) ; + writecount = (int) psf_fwrite (ubuf.ucbuf, sizeof (unsigned char), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* pcm_write_f2uc */ + +/*============================================================================== +*/ + +static void +f2bes_array (const float *src, short *dest, int count, int normalize) +{ unsigned char *ucptr ; + float normfact ; + short value ; + + normfact = normalize ? (1.0 * 0x7FFF) : 1.0 ; + + for (int i = 0 ; i < count ; i++) + { ucptr = (unsigned char*) &dest [i] ; + value = psf_lrintf (src [i] * normfact) ; + ucptr [1] = value ; + ucptr [0] = value >> 8 ; + } ; +} /* f2bes_array */ + +static void +f2bes_clip_array (const float *src, short *dest, int count, int normalize) +{ unsigned char *ucptr ; + float normfact, scaled_value ; + int value ; + + normfact = normalize ? (8.0 * 0x10000000) : (1.0 * 0x10000) ; + + for (int i = 0 ; i < count ; i++) + { ucptr = (unsigned char*) &dest [i] ; + scaled_value = src [i] * normfact ; + if (scaled_value >= (1.0 * 0x7FFFFFFF)) + { ucptr [1] = 0xFF ; + ucptr [0] = 0x7F ; + continue ; + } ; + if (scaled_value <= (-8.0 * 0x10000000)) + { ucptr [1] = 0x00 ; + ucptr [0] = 0x80 ; + continue ; + } ; + + value = psf_lrintf (scaled_value) ; + ucptr [1] = value >> 16 ; + ucptr [0] = value >> 24 ; + } ; +} /* f2bes_clip_array */ + +static sf_count_t +pcm_write_f2bes (SF_PRIVATE *psf, const float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + void (*convert) (const float *, short *t, int, int) ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + convert = (psf->add_clipping) ? f2bes_clip_array : f2bes_array ; + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + convert (ptr + total, ubuf.sbuf, bufferlen, psf->norm_float) ; + writecount = (int) psf_fwrite (ubuf.sbuf, sizeof (short), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* pcm_write_f2bes */ + +/*============================================================================== +*/ + +static void +f2les_array (const float *src, short *dest, int count, int normalize) +{ unsigned char *ucptr ; + float normfact ; + int value ; + + normfact = normalize ? (1.0 * 0x7FFF) : 1.0 ; + + for (int i = 0 ; i < count ; i++) + { ucptr = (unsigned char*) &dest [i] ; + value = psf_lrintf (src [i] * normfact) ; + ucptr [0] = value ; + ucptr [1] = value >> 8 ; + } ; +} /* f2les_array */ + +static void +f2les_clip_array (const float *src, short *dest, int count, int normalize) +{ unsigned char *ucptr ; + float normfact, scaled_value ; + int value ; + + normfact = normalize ? (8.0 * 0x10000000) : (1.0 * 0x10000) ; + + for (int i = 0 ; i < count ; i++) + { ucptr = (unsigned char*) &dest [i] ; + scaled_value = src [i] * normfact ; + if (scaled_value >= (1.0 * 0x7FFFFFFF)) + { ucptr [0] = 0xFF ; + ucptr [1] = 0x7F ; + continue ; + } ; + if (scaled_value <= (-8.0 * 0x10000000)) + { ucptr [0] = 0x00 ; + ucptr [1] = 0x80 ; + continue ; + } ; + + value = psf_lrintf (scaled_value) ; + ucptr [0] = value >> 16 ; + ucptr [1] = value >> 24 ; + } ; +} /* f2les_clip_array */ + +static sf_count_t +pcm_write_f2les (SF_PRIVATE *psf, const float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + void (*convert) (const float *, short *t, int, int) ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + convert = (psf->add_clipping) ? f2les_clip_array : f2les_array ; + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + convert (ptr + total, ubuf.sbuf, bufferlen, psf->norm_float) ; + writecount = (int) psf_fwrite (ubuf.sbuf, sizeof (short), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* pcm_write_f2les */ + +/*============================================================================== +*/ + +static void +f2let_array (const float *src, tribyte *dest, int count, int normalize) +{ float normfact ; + int value ; + + normfact = normalize ? (1.0 * 0x7FFFFF) : 1.0 ; + + for (int i = 0 ; i < count ; i++) + { value = psf_lrintf (src [i] * normfact) ; + dest [i].bytes [0] = value ; + dest [i].bytes [1] = value >> 8 ; + dest [i].bytes [2] = value >> 16 ; + } ; +} /* f2let_array */ + +static void +f2let_clip_array (const float *src, tribyte *dest, int count, int normalize) +{ float normfact, scaled_value ; + int value ; + + normfact = normalize ? (8.0 * 0x10000000) : (1.0 * 0x100) ; + + for (int i = 0 ; i < count ; i++) + { scaled_value = src [i] * normfact ; +#if CPU_CLIPS_POSITIVE == 0 + if (scaled_value >= (1.0 * 0x7FFFFFFF)) + { dest [i].bytes [0] = 0xFF ; + dest [i].bytes [1] = 0xFF ; + dest [i].bytes [2] = 0x7F ; + continue ; + } ; +#endif +#if CPU_CLIPS_NEGATIVE == 0 + if (scaled_value <= (-8.0 * 0x10000000)) + { dest [i].bytes [0] = 0x00 ; + dest [i].bytes [1] = 0x00 ; + dest [i].bytes [2] = 0x80 ; + continue ; + } ; +#endif + + value = psf_lrintf (scaled_value) ; + dest [i].bytes [0] = value >> 8 ; + dest [i].bytes [1] = value >> 16 ; + dest [i].bytes [2] = value >> 24 ; + } ; +} /* f2let_clip_array */ + +static sf_count_t +pcm_write_f2let (SF_PRIVATE *psf, const float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + void (*convert) (const float *, tribyte *, int, int) ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + convert = (psf->add_clipping) ? f2let_clip_array : f2let_array ; + bufferlen = sizeof (ubuf.ucbuf) / SIZEOF_TRIBYTE ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + convert (ptr + total, (tribyte*) (ubuf.ucbuf), bufferlen, psf->norm_float) ; + writecount = (int) psf_fwrite (ubuf.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* pcm_write_f2let */ + +/*============================================================================== +*/ + +static void +f2bet_array (const float *src, tribyte *dest, int count, int normalize) +{ float normfact ; + int value ; + + normfact = normalize ? (1.0 * 0x7FFFFF) : 1.0 ; + + for (int i = 0 ; i < count ; i++) + { value = psf_lrintf (src [i] * normfact) ; + dest [i].bytes [0] = value >> 16 ; + dest [i].bytes [1] = value >> 8 ; + dest [i].bytes [2] = value ; + } ; +} /* f2bet_array */ + +static void +f2bet_clip_array (const float *src, tribyte *dest, int count, int normalize) +{ float normfact, scaled_value ; + int value ; + + normfact = normalize ? (8.0 * 0x10000000) : (1.0 * 0x100) ; + + for (int i = 0 ; i < count ; i++) + { scaled_value = src [i] * normfact ; +#if CPU_CLIPS_POSITIVE == 0 + if (scaled_value >= (1.0 * 0x7FFFFFFF)) + { dest [i].bytes [0] = 0x7F ; + dest [i].bytes [1] = 0xFF ; + dest [i].bytes [2] = 0xFF ; + continue ; + } ; +#endif +#if CPU_CLIPS_NEGATIVE == 0 + if (scaled_value <= (-8.0 * 0x10000000)) + { dest [i].bytes [0] = 0x80 ; + dest [i].bytes [1] = 0x00 ; + dest [i].bytes [2] = 0x00 ; + continue ; + } ; +#endif + + value = psf_lrint (scaled_value) ; + dest [i].bytes [0] = value >> 24 ; + dest [i].bytes [1] = value >> 16 ; + dest [i].bytes [2] = value >> 8 ; + } ; +} /* f2bet_clip_array */ + +static sf_count_t +pcm_write_f2bet (SF_PRIVATE *psf, const float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + void (*convert) (const float *, tribyte *, int, int) ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + convert = (psf->add_clipping) ? f2bet_clip_array : f2bet_array ; + bufferlen = sizeof (ubuf.ucbuf) / SIZEOF_TRIBYTE ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + convert (ptr + total, (tribyte*) (ubuf.ucbuf), bufferlen, psf->norm_float) ; + writecount = (int) psf_fwrite (ubuf.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* pcm_write_f2bet */ + +/*============================================================================== +*/ + +static void +f2bei_array (const float *src, int *dest, int count, int normalize) +{ unsigned char *ucptr ; + float normfact ; + int value ; + + normfact = normalize ? (1.0 * 0x7FFFFFFF) : 1.0 ; + + for (int i = 0 ; i < count ; i++) + { ucptr = (unsigned char*) &dest [i] ; + value = psf_lrintf (src [i] * normfact) ; + ucptr [0] = value >> 24 ; + ucptr [1] = value >> 16 ; + ucptr [2] = value >> 8 ; + ucptr [3] = value ; + } ; +} /* f2bei_array */ + +static void +f2bei_clip_array (const float *src, int *dest, int count, int normalize) +{ unsigned char *ucptr ; + float normfact, scaled_value ; + int value ; + + normfact = normalize ? (8.0 * 0x10000000) : 1.0 ; + + for (int i = 0 ; i < count ; i++) + { ucptr = (unsigned char*) &dest [i] ; + scaled_value = src [i] * normfact ; +#if CPU_CLIPS_POSITIVE == 0 + if (scaled_value >= 1.0 * 0x7FFFFFFF) + { ucptr [0] = 0x7F ; + ucptr [1] = 0xFF ; + ucptr [2] = 0xFF ; + ucptr [3] = 0xFF ; + continue ; + } ; +#endif +#if CPU_CLIPS_NEGATIVE == 0 + if (scaled_value <= (-8.0 * 0x10000000)) + { ucptr [0] = 0x80 ; + ucptr [1] = 0x00 ; + ucptr [2] = 0x00 ; + ucptr [3] = 0x00 ; + continue ; + } ; +#endif + + value = psf_lrintf (scaled_value) ; + ucptr [0] = value >> 24 ; + ucptr [1] = value >> 16 ; + ucptr [2] = value >> 8 ; + ucptr [3] = value ; + } ; +} /* f2bei_clip_array */ + +static sf_count_t +pcm_write_f2bei (SF_PRIVATE *psf, const float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + void (*convert) (const float *, int *, int, int) ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + convert = (psf->add_clipping) ? f2bei_clip_array : f2bei_array ; + bufferlen = ARRAY_LEN (ubuf.ibuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + convert (ptr + total, ubuf.ibuf, bufferlen, psf->norm_float) ; + writecount = (int) psf_fwrite (ubuf.ibuf, sizeof (int), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* pcm_write_f2bei */ + +/*============================================================================== +*/ + +static void +f2lei_array (const float *src, int *dest, int count, int normalize) +{ unsigned char *ucptr ; + float normfact ; + int value ; + + normfact = normalize ? (1.0 * 0x7FFFFFFF) : 1.0 ; + + for (int i = 0 ; i < count ; i++) + { ucptr = (unsigned char*) &dest [i] ; + value = psf_lrintf (src [i] * normfact) ; + ucptr [0] = value ; + ucptr [1] = value >> 8 ; + ucptr [2] = value >> 16 ; + ucptr [3] = value >> 24 ; + } ; +} /* f2lei_array */ + +static void +f2lei_clip_array (const float *src, int *dest, int count, int normalize) +{ unsigned char *ucptr ; + float normfact, scaled_value ; + int value ; + + normfact = normalize ? (8.0 * 0x10000000) : 1.0 ; + + for (int i = 0 ; i < count ; i++) + { ucptr = (unsigned char*) &dest [i] ; + scaled_value = src [i] * normfact ; +#if CPU_CLIPS_POSITIVE == 0 + if (scaled_value >= (1.0 * 0x7FFFFFFF)) + { ucptr [0] = 0xFF ; + ucptr [1] = 0xFF ; + ucptr [2] = 0xFF ; + ucptr [3] = 0x7F ; + continue ; + } ; +#endif +#if CPU_CLIPS_NEGATIVE == 0 + if (scaled_value <= (-8.0 * 0x10000000)) + { ucptr [0] = 0x00 ; + ucptr [1] = 0x00 ; + ucptr [2] = 0x00 ; + ucptr [3] = 0x80 ; + continue ; + } ; +#endif + + value = psf_lrintf (scaled_value) ; + ucptr [0] = value ; + ucptr [1] = value >> 8 ; + ucptr [2] = value >> 16 ; + ucptr [3] = value >> 24 ; + } ; +} /* f2lei_clip_array */ + +static sf_count_t +pcm_write_f2lei (SF_PRIVATE *psf, const float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + void (*convert) (const float *, int *, int, int) ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + convert = (psf->add_clipping) ? f2lei_clip_array : f2lei_array ; + bufferlen = ARRAY_LEN (ubuf.ibuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + convert (ptr + total, ubuf.ibuf, bufferlen, psf->norm_float) ; + writecount = (int) psf_fwrite (ubuf.ibuf, sizeof (int), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* pcm_write_f2lei */ + +/*============================================================================== +*/ + +static void +d2sc_array (const double *src, signed char *dest, int count, int normalize) +{ double normfact ; + + normfact = normalize ? (1.0 * 0x7F) : 1.0 ; + + for (int i = 0 ; i < count ; i++) + { dest [i] = psf_lrint (src [i] * normfact) ; + } ; +} /* d2sc_array */ + +static void +d2sc_clip_array (const double *src, signed char *dest, int count, int normalize) +{ double normfact, scaled_value ; + + normfact = normalize ? (8.0 * 0x10000000) : (1.0 * 0x1000000) ; + + for (int i = 0 ; i < count ; i++) + { scaled_value = src [i] * normfact ; + if (scaled_value >= (1.0 * 0x7FFFFFFF)) + { dest [i] = 127 ; + continue ; + } ; + if (scaled_value <= (-8.0 * 0x10000000)) + { dest [i] = -128 ; + continue ; + } ; + + dest [i] = psf_lrintf (scaled_value) >> 24 ; + } ; +} /* d2sc_clip_array */ + +static sf_count_t +pcm_write_d2sc (SF_PRIVATE *psf, const double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + void (*convert) (const double *, signed char *, int, int) ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + convert = (psf->add_clipping) ? d2sc_clip_array : d2sc_array ; + bufferlen = ARRAY_LEN (ubuf.scbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + convert (ptr + total, ubuf.scbuf, bufferlen, psf->norm_double) ; + writecount = (int) psf_fwrite (ubuf.scbuf, sizeof (signed char), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* pcm_write_d2sc */ + +/*============================================================================== +*/ + +static void +d2uc_array (const double *src, unsigned char *dest, int count, int normalize) +{ double normfact ; + + normfact = normalize ? (1.0 * 0x7F) : 1.0 ; + + for (int i = 0 ; i < count ; i++) + { dest [i] = psf_lrint (src [i] * normfact) + 128 ; + } ; +} /* d2uc_array */ + +static void +d2uc_clip_array (const double *src, unsigned char *dest, int count, int normalize) +{ double normfact, scaled_value ; + + normfact = normalize ? (8.0 * 0x10000000) : (1.0 * 0x1000000) ; + + for (int i = 0 ; i < count ; i++) + { scaled_value = src [i] * normfact ; + if (scaled_value >= (1.0 * 0x7FFFFFFF)) + { dest [i] = 255 ; + continue ; + } ; + if (scaled_value <= (-8.0 * 0x10000000)) + { dest [i] = 0 ; + continue ; + } ; + + dest [i] = (psf_lrint (src [i] * normfact) >> 24) + 128 ; + } ; +} /* d2uc_clip_array */ + +static sf_count_t +pcm_write_d2uc (SF_PRIVATE *psf, const double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + void (*convert) (const double *, unsigned char *, int, int) ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + convert = (psf->add_clipping) ? d2uc_clip_array : d2uc_array ; + bufferlen = ARRAY_LEN (ubuf.ucbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + convert (ptr + total, ubuf.ucbuf, bufferlen, psf->norm_double) ; + writecount = (int) psf_fwrite (ubuf.ucbuf, sizeof (unsigned char), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* pcm_write_d2uc */ + +/*============================================================================== +*/ + +static void +d2bes_array (const double *src, short *dest, int count, int normalize) +{ unsigned char *ucptr ; + short value ; + double normfact ; + + normfact = normalize ? (1.0 * 0x7FFF) : 1.0 ; + + for (int i = 0 ; i < count ; i++) + { ucptr = (unsigned char*) &dest [i] ; + value = psf_lrint (src [i] * normfact) ; + ucptr [1] = value ; + ucptr [0] = value >> 8 ; + } ; +} /* d2bes_array */ + +static void +d2bes_clip_array (const double *src, short *dest, int count, int normalize) +{ unsigned char *ucptr ; + double normfact, scaled_value ; + int value ; + + normfact = normalize ? (8.0 * 0x10000000) : (1.0 * 0x10000) ; + + for (int i = 0 ; i < count ; i++) + { ucptr = (unsigned char*) &dest [i] ; + scaled_value = src [i] * normfact ; + if (scaled_value >= (1.0 * 0x7FFFFFFF)) + { ucptr [1] = 0xFF ; + ucptr [0] = 0x7F ; + continue ; + } ; + if (scaled_value <= (-8.0 * 0x10000000)) + { ucptr [1] = 0x00 ; + ucptr [0] = 0x80 ; + continue ; + } ; + + value = psf_lrint (scaled_value) ; + ucptr [1] = value >> 16 ; + ucptr [0] = value >> 24 ; + } ; +} /* d2bes_clip_array */ + +static sf_count_t +pcm_write_d2bes (SF_PRIVATE *psf, const double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + void (*convert) (const double *, short *, int, int) ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + convert = (psf->add_clipping) ? d2bes_clip_array : d2bes_array ; + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + convert (ptr + total, ubuf.sbuf, bufferlen, psf->norm_double) ; + writecount = (int) psf_fwrite (ubuf.sbuf, sizeof (short), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* pcm_write_d2bes */ + +/*============================================================================== +*/ + +static void +d2les_array (const double *src, short *dest, int count, int normalize) +{ unsigned char *ucptr ; + short value ; + double normfact ; + + normfact = normalize ? (1.0 * 0x7FFF) : 1.0 ; + + for (int i = 0 ; i < count ; i++) + { ucptr = (unsigned char*) &dest [i] ; + value = psf_lrint (src [i] * normfact) ; + ucptr [0] = value ; + ucptr [1] = value >> 8 ; + } ; +} /* d2les_array */ + +static void +d2les_clip_array (const double *src, short *dest, int count, int normalize) +{ unsigned char *ucptr ; + int value ; + double normfact, scaled_value ; + + normfact = normalize ? (8.0 * 0x10000000) : (1.0 * 0x10000) ; + + for (int i = 0 ; i < count ; i++) + { ucptr = (unsigned char*) &dest [i] ; + scaled_value = src [i] * normfact ; + if (scaled_value >= (1.0 * 0x7FFFFFFF)) + { ucptr [0] = 0xFF ; + ucptr [1] = 0x7F ; + continue ; + } ; + if (scaled_value <= (-8.0 * 0x10000000)) + { ucptr [0] = 0x00 ; + ucptr [1] = 0x80 ; + continue ; + } ; + + value = psf_lrint (scaled_value) ; + ucptr [0] = value >> 16 ; + ucptr [1] = value >> 24 ; + } ; +} /* d2les_clip_array */ + +static sf_count_t +pcm_write_d2les (SF_PRIVATE *psf, const double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + void (*convert) (const double *, short *, int, int) ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + convert = (psf->add_clipping) ? d2les_clip_array : d2les_array ; + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + convert (ptr + total, ubuf.sbuf, bufferlen, psf->norm_double) ; + writecount = (int) psf_fwrite (ubuf.sbuf, sizeof (short), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* pcm_write_d2les */ + +/*============================================================================== +*/ + +static void +d2let_array (const double *src, tribyte *dest, int count, int normalize) +{ int value ; + double normfact ; + + normfact = normalize ? (1.0 * 0x7FFFFF) : 1.0 ; + + for (int i = 0 ; i < count ; i++) + { value = psf_lrint (src [i] * normfact) ; + dest [i].bytes [0] = value ; + dest [i].bytes [1] = value >> 8 ; + dest [i].bytes [2] = value >> 16 ; + } ; +} /* d2let_array */ + +static void +d2let_clip_array (const double *src, tribyte *dest, int count, int normalize) +{ int value ; + double normfact, scaled_value ; + + normfact = normalize ? (8.0 * 0x10000000) : (1.0 * 0x100) ; + + for (int i = 0 ; i < count ; i++) + { scaled_value = src [i] * normfact ; +#if CPU_CLIPS_POSITIVE == 0 + if (scaled_value >= (1.0 * 0x7FFFFFFF)) + { dest [i].bytes [0] = 0xFF ; + dest [i].bytes [1] = 0xFF ; + dest [i].bytes [2] = 0x7F ; + continue ; + } ; +#endif +#if CPU_CLIPS_NEGATIVE == 0 + if (scaled_value <= (-8.0 * 0x10000000)) + { dest [i].bytes [0] = 0x00 ; + dest [i].bytes [1] = 0x00 ; + dest [i].bytes [2] = 0x80 ; + continue ; + } ; +#endif + + value = psf_lrint (scaled_value) ; + dest [i].bytes [0] = value >> 8 ; + dest [i].bytes [1] = value >> 16 ; + dest [i].bytes [2] = value >> 24 ; + } ; +} /* d2let_clip_array */ + +static sf_count_t +pcm_write_d2let (SF_PRIVATE *psf, const double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + void (*convert) (const double *, tribyte *, int, int) ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + convert = (psf->add_clipping) ? d2let_clip_array : d2let_array ; + bufferlen = sizeof (ubuf.ucbuf) / SIZEOF_TRIBYTE ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + convert (ptr + total, (tribyte*) (ubuf.ucbuf), bufferlen, psf->norm_double) ; + writecount = (int) psf_fwrite (ubuf.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* pcm_write_d2let */ + +/*============================================================================== +*/ + +static void +d2bet_array (const double *src, tribyte *dest, int count, int normalize) +{ int value ; + double normfact ; + + normfact = normalize ? (1.0 * 0x7FFFFF) : 1.0 ; + + for (int i = 0 ; i < count ; i++) + { value = psf_lrint (src [i] * normfact) ; + dest [i].bytes [2] = value ; + dest [i].bytes [1] = value >> 8 ; + dest [i].bytes [0] = value >> 16 ; + } ; +} /* d2bet_array */ + +static void +d2bet_clip_array (const double *src, tribyte *dest, int count, int normalize) +{ int value ; + double normfact, scaled_value ; + + normfact = normalize ? (8.0 * 0x10000000) : (1.0 * 0x100) ; + + for (int i = 0 ; i < count ; i++) + { scaled_value = src [i] * normfact ; +#if CPU_CLIPS_POSITIVE == 0 + if (scaled_value >= (1.0 * 0x7FFFFFFF)) + { dest [i].bytes [2] = 0xFF ; + dest [i].bytes [1] = 0xFF ; + dest [i].bytes [0] = 0x7F ; + continue ; + } ; +#endif +#if CPU_CLIPS_NEGATIVE == 0 + if (scaled_value <= (-8.0 * 0x10000000)) + { dest [i].bytes [2] = 0x00 ; + dest [i].bytes [1] = 0x00 ; + dest [i].bytes [0] = 0x80 ; + continue ; + } ; +#endif + + value = psf_lrint (scaled_value) ; + dest [i].bytes [2] = value >> 8 ; + dest [i].bytes [1] = value >> 16 ; + dest [i].bytes [0] = value >> 24 ; + } ; +} /* d2bet_clip_array */ + +static sf_count_t +pcm_write_d2bet (SF_PRIVATE *psf, const double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + void (*convert) (const double *, tribyte *, int, int) ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + convert = (psf->add_clipping) ? d2bet_clip_array : d2bet_array ; + bufferlen = sizeof (ubuf.ucbuf) / SIZEOF_TRIBYTE ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + convert (ptr + total, (tribyte*) (ubuf.ucbuf), bufferlen, psf->norm_double) ; + writecount = (int) psf_fwrite (ubuf.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* pcm_write_d2bet */ + +/*============================================================================== +*/ + +static void +d2bei_array (const double *src, int *dest, int count, int normalize) +{ unsigned char *ucptr ; + int value ; + double normfact ; + + normfact = normalize ? (1.0 * 0x7FFFFFFF) : 1.0 ; + + for (int i = 0 ; i < count ; i++) + { ucptr = (unsigned char*) &dest [i] ; + value = psf_lrint (src [i] * normfact) ; + ucptr [0] = value >> 24 ; + ucptr [1] = value >> 16 ; + ucptr [2] = value >> 8 ; + ucptr [3] = value ; + } ; +} /* d2bei_array */ + +static void +d2bei_clip_array (const double *src, int *dest, int count, int normalize) +{ unsigned char *ucptr ; + int value ; + double normfact, scaled_value ; + + normfact = normalize ? (8.0 * 0x10000000) : 1.0 ; + + for (int i = 0 ; i < count ; i++) + { ucptr = (unsigned char*) &dest [i] ; + scaled_value = src [i] * normfact ; +#if CPU_CLIPS_POSITIVE == 0 + if (scaled_value >= (1.0 * 0x7FFFFFFF)) + { ucptr [3] = 0xFF ; + ucptr [2] = 0xFF ; + ucptr [1] = 0xFF ; + ucptr [0] = 0x7F ; + continue ; + } ; +#endif +#if CPU_CLIPS_NEGATIVE == 0 + if (scaled_value <= (-8.0 * 0x10000000)) + { ucptr [3] = 0x00 ; + ucptr [2] = 0x00 ; + ucptr [1] = 0x00 ; + ucptr [0] = 0x80 ; + continue ; + } ; +#endif + + value = psf_lrint (scaled_value) ; + ucptr [0] = value >> 24 ; + ucptr [1] = value >> 16 ; + ucptr [2] = value >> 8 ; + ucptr [3] = value ; + } ; +} /* d2bei_clip_array */ + +static sf_count_t +pcm_write_d2bei (SF_PRIVATE *psf, const double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + void (*convert) (const double *, int *, int, int) ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + convert = (psf->add_clipping) ? d2bei_clip_array : d2bei_array ; + bufferlen = ARRAY_LEN (ubuf.ibuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + convert (ptr + total, ubuf.ibuf, bufferlen, psf->norm_double) ; + writecount = (int) psf_fwrite (ubuf.ibuf, sizeof (int), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* pcm_write_d2bei */ + +/*============================================================================== +*/ + +static void +d2lei_array (const double *src, int *dest, int count, int normalize) +{ unsigned char *ucptr ; + int value ; + double normfact ; + + normfact = normalize ? (1.0 * 0x7FFFFFFF) : 1.0 ; + + for (int i = 0 ; i < count ; i++) + { ucptr = (unsigned char*) &dest [i] ; + value = psf_lrint (src [i] * normfact) ; + ucptr [0] = value ; + ucptr [1] = value >> 8 ; + ucptr [2] = value >> 16 ; + ucptr [3] = value >> 24 ; + } ; +} /* d2lei_array */ + +static void +d2lei_clip_array (const double *src, int *dest, int count, int normalize) +{ unsigned char *ucptr ; + int value ; + double normfact, scaled_value ; + + normfact = normalize ? (8.0 * 0x10000000) : 1.0 ; + + for (int i = 0 ; i < count ; i++) + { ucptr = (unsigned char*) &dest [i] ; + scaled_value = src [i] * normfact ; +#if CPU_CLIPS_POSITIVE == 0 + if (scaled_value >= (1.0 * 0x7FFFFFFF)) + { ucptr [0] = 0xFF ; + ucptr [1] = 0xFF ; + ucptr [2] = 0xFF ; + ucptr [3] = 0x7F ; + continue ; + } ; +#endif +#if CPU_CLIPS_NEGATIVE == 0 + if (scaled_value <= (-8.0 * 0x10000000)) + { ucptr [0] = 0x00 ; + ucptr [1] = 0x00 ; + ucptr [2] = 0x00 ; + ucptr [3] = 0x80 ; + continue ; + } ; +#endif + + value = psf_lrint (scaled_value) ; + ucptr [0] = value ; + ucptr [1] = value >> 8 ; + ucptr [2] = value >> 16 ; + ucptr [3] = value >> 24 ; + } ; +} /* d2lei_clip_array */ + +static sf_count_t +pcm_write_d2lei (SF_PRIVATE *psf, const double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + void (*convert) (const double *, int *, int, int) ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + convert = (psf->add_clipping) ? d2lei_clip_array : d2lei_array ; + bufferlen = ARRAY_LEN (ubuf.ibuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + convert (ptr + total, ubuf.ibuf, bufferlen, psf->norm_double) ; + writecount = (int) psf_fwrite (ubuf.ibuf, sizeof (int), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* pcm_write_d2lei */ + diff --git a/extern/libsndfile-modified/src/pvf.c b/extern/libsndfile-modified/src/pvf.c new file mode 100644 index 000000000..714f5b380 --- /dev/null +++ b/extern/libsndfile-modified/src/pvf.c @@ -0,0 +1,188 @@ +/* +** Copyright (C) 2002-2016 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + +/*------------------------------------------------------------------------------ +** Macros to handle big/little endian issues. +*/ + +#define PVF1_MARKER (MAKE_MARKER ('P', 'V', 'F', '1')) + +/*------------------------------------------------------------------------------ +** Private static functions. +*/ + +static int pvf_close (SF_PRIVATE *psf) ; + +static int pvf_write_header (SF_PRIVATE *psf, int calc_length) ; +static int pvf_read_header (SF_PRIVATE *psf) ; + +/*------------------------------------------------------------------------------ +** Public function. +*/ + +int +pvf_open (SF_PRIVATE *psf) +{ int subformat ; + int error = 0 ; + + if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0)) + { if ((error = pvf_read_header (psf))) + return error ; + } ; + + subformat = SF_CODEC (psf->sf.format) ; + + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_PVF) + return SFE_BAD_OPEN_FORMAT ; + + psf->endian = SF_ENDIAN_BIG ; + + if (pvf_write_header (psf, SF_FALSE)) + return psf->error ; + + psf->write_header = pvf_write_header ; + } ; + + psf->container_close = pvf_close ; + + psf->blockwidth = psf->bytewidth * psf->sf.channels ; + + switch (subformat) + { case SF_FORMAT_PCM_S8 : /* 8-bit linear PCM. */ + case SF_FORMAT_PCM_16 : /* 16-bit linear PCM. */ + case SF_FORMAT_PCM_32 : /* 32-bit linear PCM. */ + error = pcm_init (psf) ; + break ; + + default : break ; + } ; + + return error ; +} /* pvf_open */ + +/*------------------------------------------------------------------------------ +*/ + +static int +pvf_close (SF_PRIVATE * UNUSED (psf)) +{ + return 0 ; +} /* pvf_close */ + +static int +pvf_write_header (SF_PRIVATE *psf, int UNUSED (calc_length)) +{ sf_count_t current ; + + if (psf->pipeoffset > 0) + return 0 ; + + current = psf_ftell (psf) ; + + /* Reset the current header length to zero. */ + psf->header.ptr [0] = 0 ; + psf->header.indx = 0 ; + + if (psf->is_pipe == SF_FALSE) + psf_fseek (psf, 0, SEEK_SET) ; + + snprintf ((char*) psf->header.ptr, psf->header.len, "PVF1\n%d %d %d\n", + psf->sf.channels, psf->sf.samplerate, psf->bytewidth * 8) ; + + psf->header.indx = strlen ((char*) psf->header.ptr) ; + + /* Header construction complete so write it out. */ + psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ; + + if (psf->error) + return psf->error ; + + psf->dataoffset = psf->header.indx ; + + if (current > 0) + psf_fseek (psf, current, SEEK_SET) ; + + return psf->error ; +} /* pvf_write_header */ + +static int +pvf_read_header (SF_PRIVATE *psf) +{ char buffer [32] ; + int marker, channels, samplerate, bitwidth ; + + psf_binheader_readf (psf, "pmj", 0, &marker, 1) ; + psf_log_printf (psf, "%M\n", marker) ; + + if (marker != PVF1_MARKER) + return SFE_PVF_NO_PVF1 ; + + /* Grab characters up until a newline which is replaced by an EOS. */ + psf_binheader_readf (psf, "G", buffer, sizeof (buffer)) ; + + if (sscanf (buffer, "%d %d %d", &channels, &samplerate, &bitwidth) != 3) + return SFE_PVF_BAD_HEADER ; + + psf_log_printf (psf, " Channels : %d\n Sample rate : %d\n Bit width : %d\n", + channels, samplerate, bitwidth) ; + + psf->sf.channels = channels ; + psf->sf.samplerate = samplerate ; + + switch (bitwidth) + { case 8 : + psf->sf.format = SF_FORMAT_PVF | SF_FORMAT_PCM_S8 ; + psf->bytewidth = 1 ; + break ; + + case 16 : + psf->sf.format = SF_FORMAT_PVF | SF_FORMAT_PCM_16 ; + psf->bytewidth = 2 ; + break ; + case 32 : + psf->sf.format = SF_FORMAT_PVF | SF_FORMAT_PCM_32 ; + psf->bytewidth = 4 ; + break ; + + default : + return SFE_PVF_BAD_BITWIDTH ; + } ; + + psf->dataoffset = psf_ftell (psf) ; + psf_log_printf (psf, " Data Offset : %D\n", psf->dataoffset) ; + + psf->endian = SF_ENDIAN_BIG ; + + psf->datalength = psf->filelength - psf->dataoffset ; + psf->blockwidth = psf->sf.channels * psf->bytewidth ; + + if (! psf->sf.frames && psf->blockwidth) + psf->sf.frames = (psf->filelength - psf->dataoffset) / psf->blockwidth ; + + return 0 ; +} /* pvf_read_header */ diff --git a/extern/libsndfile-modified/src/raw.c b/extern/libsndfile-modified/src/raw.c new file mode 100644 index 000000000..c8fcbfde2 --- /dev/null +++ b/extern/libsndfile-modified/src/raw.c @@ -0,0 +1,111 @@ +/* +** Copyright (C) 1999-2011 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include + +#include "sndfile.h" +#include "common.h" + +/*------------------------------------------------------------------------------ +** Public function. +*/ + +int +raw_open (SF_PRIVATE *psf) +{ int subformat, error = SFE_NO_ERROR ; + + subformat = SF_CODEC (psf->sf.format) ; + + psf->endian = SF_ENDIAN (psf->sf.format) ; + + if (CPU_IS_BIG_ENDIAN && (psf->endian == 0 || psf->endian == SF_ENDIAN_CPU)) + psf->endian = SF_ENDIAN_BIG ; + else if (CPU_IS_LITTLE_ENDIAN && (psf->endian == 0 || psf->endian == SF_ENDIAN_CPU)) + psf->endian = SF_ENDIAN_LITTLE ; + + psf->blockwidth = psf->bytewidth * psf->sf.channels ; + psf->dataoffset = 0 ; + psf->datalength = psf->filelength ; + + switch (subformat) + { case SF_FORMAT_PCM_S8 : + error = pcm_init (psf) ; + break ; + + case SF_FORMAT_PCM_U8 : + error = pcm_init (psf) ; + break ; + + case SF_FORMAT_PCM_16 : + case SF_FORMAT_PCM_24 : + case SF_FORMAT_PCM_32 : + error = pcm_init (psf) ; + break ; + + case SF_FORMAT_ULAW : + error = ulaw_init (psf) ; + break ; + + case SF_FORMAT_ALAW : + error = alaw_init (psf) ; + break ; + + case SF_FORMAT_GSM610 : + error = gsm610_init (psf) ; + break ; + + /* Lite remove start */ + + case SF_FORMAT_NMS_ADPCM_16 : + case SF_FORMAT_NMS_ADPCM_24 : + case SF_FORMAT_NMS_ADPCM_32 : + error = nms_adpcm_init (psf) ; + break ; + + case SF_FORMAT_FLOAT : + error = float32_init (psf) ; + break ; + + case SF_FORMAT_DOUBLE : + error = double64_init (psf) ; + break ; + + case SF_FORMAT_DWVW_12 : + error = dwvw_init (psf, 12) ; + break ; + + case SF_FORMAT_DWVW_16 : + error = dwvw_init (psf, 16) ; + break ; + + case SF_FORMAT_DWVW_24 : + error = dwvw_init (psf, 24) ; + break ; + + case SF_FORMAT_VOX_ADPCM : + error = vox_adpcm_init (psf) ; + break ; + /* Lite remove end */ + + default : return SFE_BAD_OPEN_FORMAT ; + } ; + + return error ; +} /* raw_open */ diff --git a/extern/libsndfile-modified/src/rf64.c b/extern/libsndfile-modified/src/rf64.c new file mode 100644 index 000000000..123db445a --- /dev/null +++ b/extern/libsndfile-modified/src/rf64.c @@ -0,0 +1,894 @@ +/* +** Copyright (C) 2008-2018 Erik de Castro Lopo +** Copyright (C) 2009 Uli Franke +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/* +** This format documented at: +** http://www.sr.se/utveckling/tu/bwf/prog/RF_64v1_4.pdf +** +** But this may be a better reference: +** http://www.ebu.ch/CMSimages/en/tec_doc_t3306-2007_tcm6-42570.pdf +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" +#include "wavlike.h" + +/*------------------------------------------------------------------------------ +** Macros to handle big/little endian issues. +*/ +#define RF64_MARKER MAKE_MARKER ('R', 'F', '6', '4') +#define RIFF_MARKER MAKE_MARKER ('R', 'I', 'F', 'F') +#define JUNK_MARKER MAKE_MARKER ('J', 'U', 'N', 'K') +#define FFFF_MARKER MAKE_MARKER (0xff, 0xff, 0xff, 0xff) +#define WAVE_MARKER MAKE_MARKER ('W', 'A', 'V', 'E') +#define ds64_MARKER MAKE_MARKER ('d', 's', '6', '4') +#define fmt_MARKER MAKE_MARKER ('f', 'm', 't', ' ') +#define fact_MARKER MAKE_MARKER ('f', 'a', 'c', 't') +#define data_MARKER MAKE_MARKER ('d', 'a', 't', 'a') + +#define bext_MARKER MAKE_MARKER ('b', 'e', 'x', 't') +#define cart_MARKER MAKE_MARKER ('c', 'a', 'r', 't') +#define OggS_MARKER MAKE_MARKER ('O', 'g', 'g', 'S') +#define wvpk_MARKER MAKE_MARKER ('w', 'v', 'p', 'k') +#define LIST_MARKER MAKE_MARKER ('L', 'I', 'S', 'T') + +/* +** The file size limit in bytes below which we can, if requested, write this +** file as a RIFF/WAVE file. +*/ + +#define RIFF_DOWNGRADE_BYTES ((sf_count_t) 0xffffffff) + +/*------------------------------------------------------------------------------ +** Private static functions. +*/ + +static int rf64_read_header (SF_PRIVATE *psf, int *blockalign, int *framesperblock) ; +static int rf64_write_header (SF_PRIVATE *psf, int calc_length) ; +static int rf64_write_tailer (SF_PRIVATE *psf) ; +static int rf64_close (SF_PRIVATE *psf) ; +static int rf64_command (SF_PRIVATE *psf, int command, void * UNUSED (data), int datasize) ; + +static int rf64_set_chunk (SF_PRIVATE *psf, const SF_CHUNK_INFO * chunk_info) ; +static SF_CHUNK_ITERATOR * rf64_next_chunk_iterator (SF_PRIVATE *psf, SF_CHUNK_ITERATOR * iterator) ; +static int rf64_get_chunk_size (SF_PRIVATE *psf, const SF_CHUNK_ITERATOR * iterator, SF_CHUNK_INFO * chunk_info) ; +static int rf64_get_chunk_data (SF_PRIVATE *psf, const SF_CHUNK_ITERATOR * iterator, SF_CHUNK_INFO * chunk_info) ; + +/*------------------------------------------------------------------------------ +** Public function. +*/ + +int +rf64_open (SF_PRIVATE *psf) +{ WAVLIKE_PRIVATE *wpriv ; + int subformat, error = 0 ; + int blockalign, framesperblock ; + + if ((wpriv = calloc (1, sizeof (WAVLIKE_PRIVATE))) == NULL) + return SFE_MALLOC_FAILED ; + psf->container_data = wpriv ; + wpriv->wavex_ambisonic = SF_AMBISONIC_NONE ; + + /* All RF64 files are little endian. */ + psf->endian = SF_ENDIAN_LITTLE ; + + psf->strings.flags = SF_STR_ALLOW_START | SF_STR_ALLOW_END ; + + if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0)) + { if ((error = rf64_read_header (psf, &blockalign, &framesperblock)) != 0) + return error ; + + psf->next_chunk_iterator = rf64_next_chunk_iterator ; + psf->get_chunk_size = rf64_get_chunk_size ; + psf->get_chunk_data = rf64_get_chunk_data ; + } ; + + if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_RF64) + return SFE_BAD_OPEN_FORMAT ; + + subformat = psf->sf.format & SF_FORMAT_SUBMASK ; + + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { if (psf->is_pipe) + return SFE_NO_PIPE_WRITE ; + + psf->blockwidth = psf->bytewidth * psf->sf.channels ; + + if ((error = rf64_write_header (psf, SF_FALSE))) + return error ; + + psf->write_header = rf64_write_header ; + psf->set_chunk = rf64_set_chunk ; + } ; + + psf->container_close = rf64_close ; + psf->command = rf64_command ; + + switch (subformat) + { case SF_FORMAT_PCM_U8 : + case SF_FORMAT_PCM_16 : + case SF_FORMAT_PCM_24 : + case SF_FORMAT_PCM_32 : + error = pcm_init (psf) ; + break ; + + case SF_FORMAT_ULAW : + error = ulaw_init (psf) ; + break ; + + case SF_FORMAT_ALAW : + error = alaw_init (psf) ; + break ; + + /* Lite remove start */ + case SF_FORMAT_FLOAT : + error = float32_init (psf) ; + break ; + + case SF_FORMAT_DOUBLE : + error = double64_init (psf) ; + break ; + + /* Lite remove end */ + + default : return SFE_UNIMPLEMENTED ; + } ; + + return error ; +} /* rf64_open */ + +/*------------------------------------------------------------------------------ +*/ +enum +{ HAVE_ds64 = 0x01, + HAVE_fmt = 0x02, + HAVE_bext = 0x04, + HAVE_data = 0x08, + HAVE_cart = 0x10, + HAVE_PEAK = 0x20, + HAVE_other = 0x40 +} ; + +#define HAVE_CHUNK(CHUNK) ((parsestage & CHUNK) != 0) + +static int +rf64_read_header (SF_PRIVATE *psf, int *blockalign, int *framesperblock) +{ WAVLIKE_PRIVATE *wpriv ; + WAV_FMT *wav_fmt ; + sf_count_t riff_size = 0, frame_count = 0, ds64_datalength = 0 ; + uint32_t marks [2], marker, chunk_size, parsestage = 0 ; + int error, done = 0, format = 0 ; + + if ((wpriv = psf->container_data) == NULL) + return SFE_INTERNAL ; + wav_fmt = &wpriv->wav_fmt ; + + /* Set position to start of file to begin reading header. */ + psf_binheader_readf (psf, "pmmm", 0, &marker, marks, marks + 1) ; + if (marker != RF64_MARKER || marks [1] != WAVE_MARKER) + return SFE_RF64_NOT_RF64 ; + + if (marks [0] == FFFF_MARKER) + psf_log_printf (psf, "%M\n %M\n", RF64_MARKER, WAVE_MARKER) ; + else + psf_log_printf (psf, "%M : 0x%x (should be 0xFFFFFFFF)\n %M\n", RF64_MARKER, WAVE_MARKER) ; + + while (!done) + { + marker = chunk_size = 0 ; + psf_binheader_readf (psf, "em4", &marker, &chunk_size) ; + + if (marker == 0) + { sf_count_t pos = psf_ftell (psf) ; + psf_log_printf (psf, "Have 0 marker at position %D (0x%x).\n", pos, pos) ; + break ; + } ; + + psf_store_read_chunk_u32 (&psf->rchunks, marker, psf_ftell (psf), chunk_size) ; + + switch (marker) + { case ds64_MARKER : + if (parsestage & HAVE_ds64) + { psf_log_printf (psf, "*** Second 'ds64' chunk?\n") ; + break ; + } ; + + { unsigned int table_len, bytesread ; + + /* Read ds64 sizes (3 8-byte words). */ + bytesread = psf_binheader_readf (psf, "888", &riff_size, &ds64_datalength, &frame_count) ; + + /* Read table length. */ + bytesread += psf_binheader_readf (psf, "4", &table_len) ; + /* Skip table for now. (this was "table_len + 4", why?) */ + bytesread += psf_binheader_readf (psf, "j", table_len) ; + + if (chunk_size == bytesread) + psf_log_printf (psf, "%M : %u\n", marker, chunk_size) ; + else if (chunk_size >= bytesread + 4) + { unsigned int next ; + psf_binheader_readf (psf, "m", &next) ; + if (next == fmt_MARKER) + { psf_log_printf (psf, "%M : %u (should be %u)\n", marker, chunk_size, bytesread) ; + psf_binheader_readf (psf, "j", -4) ; + } + else + { psf_log_printf (psf, "%M : %u\n", marker, chunk_size) ; + psf_binheader_readf (psf, "j", chunk_size - bytesread - 4) ; + } ; + } ; + + if (psf->filelength != riff_size + 8) + psf_log_printf (psf, " Riff size : %D (should be %D)\n", riff_size, psf->filelength - 8) ; + else + psf_log_printf (psf, " Riff size : %D\n", riff_size) ; + + psf_log_printf (psf, " Data size : %D\n", ds64_datalength) ; + + psf_log_printf (psf, " Frames : %D\n", frame_count) ; + psf_log_printf (psf, " Table length : %u\n", table_len) ; + + } ; + parsestage |= HAVE_ds64 ; + break ; + + case fmt_MARKER: + psf_log_printf (psf, "%M : %u\n", marker, chunk_size) ; + if ((error = wavlike_read_fmt_chunk (psf, chunk_size)) != 0) + return error ; + format = wav_fmt->format ; + parsestage |= HAVE_fmt ; + break ; + + case bext_MARKER : + if ((error = wavlike_read_bext_chunk (psf, chunk_size)) != 0) + return error ; + parsestage |= HAVE_bext ; + break ; + + case cart_MARKER : + if ((error = wavlike_read_cart_chunk (psf, chunk_size)) != 0) + return error ; + parsestage |= HAVE_cart ; + break ; + + case INFO_MARKER : + case LIST_MARKER : + if ((error = wavlike_subchunk_parse (psf, marker, chunk_size)) != 0) + return error ; + parsestage |= HAVE_other ; + break ; + + case PEAK_MARKER : + if ((parsestage & (HAVE_ds64 | HAVE_fmt)) != (HAVE_ds64 | HAVE_fmt)) + return SFE_RF64_PEAK_B4_FMT ; + + parsestage |= HAVE_PEAK ; + + psf_log_printf (psf, "%M : %u\n", marker, chunk_size) ; + if ((error = wavlike_read_peak_chunk (psf, chunk_size)) != 0) + return error ; + psf->peak_info->peak_loc = ((parsestage & HAVE_data) == 0) ? SF_PEAK_START : SF_PEAK_END ; + break ; + + case data_MARKER : + /* see wav for more sophisticated parsing -> implement state machine with parsestage */ + + if (HAVE_CHUNK (HAVE_ds64)) + { if (chunk_size == 0xffffffff) + psf_log_printf (psf, "%M : 0x%x\n", marker, chunk_size) ; + else + psf_log_printf (psf, "%M : 0x%x (should be 0xffffffff\n", marker, chunk_size) ; + psf->datalength = ds64_datalength ; + } + else + { if (chunk_size == 0xffffffff) + { psf_log_printf (psf, "%M : 0x%x\n", marker, chunk_size) ; + psf_log_printf (psf, " *** Data length not specified no 'ds64' chunk.\n") ; + } + else + { psf_log_printf (psf, "%M : 0x%x\n**** Weird, RF64 file without a 'ds64' chunk and no valid 'data' size.\n", marker, chunk_size) ; + psf->datalength = chunk_size ; + } ; + } ; + + psf->dataoffset = psf_ftell (psf) ; + + if (psf->dataoffset > 0) + { if (chunk_size == 0 && riff_size == 8 && psf->filelength > 44) + { psf_log_printf (psf, " *** Looks like a WAV file which wasn't closed properly. Fixing it.\n") ; + psf->datalength = psf->filelength - psf->dataoffset ; + } ; + + /* Only set dataend if there really is data at the end. */ + if (psf->datalength + psf->dataoffset < psf->filelength) + psf->dataend = psf->datalength + psf->dataoffset ; + + if (!psf->sf.seekable || psf->dataoffset < 0) + break ; + + /* Seek past data and continue reading header. */ + psf_fseek (psf, psf->datalength, SEEK_CUR) ; + + if (psf_ftell (psf) != psf->datalength + psf->dataoffset) + psf_log_printf (psf, " *** psf_fseek past end error ***\n") ; + } ; + break ; + + case JUNK_MARKER : + case PAD_MARKER : + psf_log_printf (psf, "%M : %d\n", marker, chunk_size) ; + psf_binheader_readf (psf, "j", chunk_size) ; + break ; + + default : + if (chunk_size >= 0xffff0000) + { psf_log_printf (psf, "*** Unknown chunk marker (%X) at position %D with length %u. Exiting parser.\n", marker, psf_ftell (psf) - 8, chunk_size) ; + done = SF_TRUE ; + break ; + } ; + + if (isprint ((marker >> 24) & 0xFF) && isprint ((marker >> 16) & 0xFF) + && isprint ((marker >> 8) & 0xFF) && isprint (marker & 0xFF)) + { psf_log_printf (psf, "*** %M : %d (unknown marker)\n", marker, chunk_size) ; + psf_binheader_readf (psf, "j", chunk_size) ; + break ; + } ; + if (psf_ftell (psf) & 0x03) + { psf_log_printf (psf, " Unknown chunk marker at position 0x%x. Resynching.\n", chunk_size - 4) ; + psf_binheader_readf (psf, "j", -3) ; + break ; + } ; + psf_log_printf (psf, "*** Unknown chunk marker (0x%X) at position 0x%X. Exiting parser.\n", marker, psf_ftell (psf) - 4) ; + done = SF_TRUE ; + break ; + } ; /* switch (marker) */ + + /* The 'data' chunk, a chunk size of 0xffffffff means that the 'data' chunk size + ** is actually given by the ds64_datalength field. + */ + if (marker != data_MARKER && chunk_size >= psf->filelength) + { psf_log_printf (psf, "*** Chunk size %u > file length %D. Exiting parser.\n", chunk_size, psf->filelength) ; + break ; + } ; + + if (psf_ftell (psf) >= psf->filelength - SIGNED_SIZEOF (marker)) + { psf_log_printf (psf, "End\n") ; + break ; + } ; + } ; + + if (psf->dataoffset <= 0) + return SFE_RF64_NO_DATA ; + + if (psf->sf.channels < 1) + return SFE_CHANNEL_COUNT_ZERO ; + + if (psf->sf.channels > SF_MAX_CHANNELS) + return SFE_CHANNEL_COUNT ; + + /* WAVs can be little or big endian */ + psf->endian = psf->rwf_endian ; + + psf_fseek (psf, psf->dataoffset, SEEK_SET) ; + + if (psf->is_pipe == 0) + { /* + ** Check for 'wvpk' at the start of the DATA section. Not able to + ** handle this. + */ + psf_binheader_readf (psf, "4", &marker) ; + if (marker == wvpk_MARKER || marker == OggS_MARKER) + return SFE_WAV_WVPK_DATA ; + } ; + + /* Seek to start of DATA section. */ + psf_fseek (psf, psf->dataoffset, SEEK_SET) ; + + if (psf->blockwidth) + { if (psf->filelength - psf->dataoffset < psf->datalength) + psf->sf.frames = (psf->filelength - psf->dataoffset) / psf->blockwidth ; + else + psf->sf.frames = psf->datalength / psf->blockwidth ; + } ; + + if (frame_count != psf->sf.frames) + psf_log_printf (psf, "*** Calculated frame count %d does not match value from 'ds64' chunk of %d.\n", psf->sf.frames, frame_count) ; + + switch (format) + { + case WAVE_FORMAT_EXTENSIBLE : + + /* with WAVE_FORMAT_EXTENSIBLE the psf->sf.format field is already set. We just have to set the major to rf64 */ + psf->sf.format = (psf->sf.format & ~SF_FORMAT_TYPEMASK) | SF_FORMAT_RF64 ; + + if (psf->sf.format == (SF_FORMAT_WAVEX | SF_FORMAT_MS_ADPCM)) + { *blockalign = wav_fmt->msadpcm.blockalign ; + *framesperblock = wav_fmt->msadpcm.samplesperblock ; + } ; + break ; + + case WAVE_FORMAT_PCM : + psf->sf.format = SF_FORMAT_RF64 | u_bitwidth_to_subformat (psf->bytewidth * 8) ; + break ; + + case WAVE_FORMAT_MULAW : + case IBM_FORMAT_MULAW : + psf->sf.format = (SF_FORMAT_RF64 | SF_FORMAT_ULAW) ; + break ; + + case WAVE_FORMAT_ALAW : + case IBM_FORMAT_ALAW : + psf->sf.format = (SF_FORMAT_RF64 | SF_FORMAT_ALAW) ; + break ; + + case WAVE_FORMAT_MS_ADPCM : + psf->sf.format = (SF_FORMAT_RF64 | SF_FORMAT_MS_ADPCM) ; + *blockalign = wav_fmt->msadpcm.blockalign ; + *framesperblock = wav_fmt->msadpcm.samplesperblock ; + break ; + + case WAVE_FORMAT_IMA_ADPCM : + psf->sf.format = (SF_FORMAT_RF64 | SF_FORMAT_IMA_ADPCM) ; + *blockalign = wav_fmt->ima.blockalign ; + *framesperblock = wav_fmt->ima.samplesperblock ; + break ; + + case WAVE_FORMAT_GSM610 : + psf->sf.format = (SF_FORMAT_RF64 | SF_FORMAT_GSM610) ; + break ; + + case WAVE_FORMAT_IEEE_FLOAT : + psf->sf.format = SF_FORMAT_RF64 ; + psf->sf.format |= (psf->bytewidth == 8) ? SF_FORMAT_DOUBLE : SF_FORMAT_FLOAT ; + break ; + + case WAVE_FORMAT_G721_ADPCM : + psf->sf.format = SF_FORMAT_RF64 | SF_FORMAT_G721_32 ; + break ; + + default : return SFE_UNIMPLEMENTED ; + } ; + + if (wpriv->fmt_is_broken) + wavlike_analyze (psf) ; + + /* Only set the format endian-ness if its non-standard big-endian. */ + if (psf->endian == SF_ENDIAN_BIG) + psf->sf.format |= SF_ENDIAN_BIG ; + + return 0 ; +} /* rf64_read_header */ + +/* known WAVEFORMATEXTENSIBLE GUIDS */ +static const EXT_SUBFORMAT MSGUID_SUBTYPE_PCM = +{ 0x00000001, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } +} ; + +#if 0 +static const EXT_SUBFORMAT MSGUID_SUBTYPE_MS_ADPCM = +{ 0x00000002, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } +} ; +#endif + +static const EXT_SUBFORMAT MSGUID_SUBTYPE_IEEE_FLOAT = +{ 0x00000003, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } +} ; + +static const EXT_SUBFORMAT MSGUID_SUBTYPE_ALAW = +{ 0x00000006, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } +} ; + +static const EXT_SUBFORMAT MSGUID_SUBTYPE_MULAW = +{ 0x00000007, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } +} ; + +/* +** the next two are from +** http://dream.cs.bath.ac.uk/researchdev/wave-ex/bformat.html +*/ +static const EXT_SUBFORMAT MSGUID_SUBTYPE_AMBISONIC_B_FORMAT_PCM = +{ 0x00000001, 0x0721, 0x11d3, { 0x86, 0x44, 0xC8, 0xC1, 0xCA, 0x00, 0x00, 0x00 } +} ; + +static const EXT_SUBFORMAT MSGUID_SUBTYPE_AMBISONIC_B_FORMAT_IEEE_FLOAT = +{ 0x00000003, 0x0721, 0x11d3, { 0x86, 0x44, 0xC8, 0xC1, 0xCA, 0x00, 0x00, 0x00 } +} ; + + +static int +rf64_write_fmt_chunk (SF_PRIVATE *psf) +{ WAVLIKE_PRIVATE *wpriv ; + int subformat, fmt_size ; + + if ((wpriv = psf->container_data) == NULL) + return SFE_INTERNAL ; + + subformat = psf->sf.format & SF_FORMAT_SUBMASK ; + + /* initial section (same for all, it appears) */ + switch (subformat) + { case SF_FORMAT_PCM_U8 : + case SF_FORMAT_PCM_16 : + case SF_FORMAT_PCM_24 : + case SF_FORMAT_PCM_32 : + case SF_FORMAT_FLOAT : + case SF_FORMAT_DOUBLE : + case SF_FORMAT_ULAW : + case SF_FORMAT_ALAW : + fmt_size = 2 + 2 + 4 + 4 + 2 + 2 + 2 + 2 + 4 + 4 + 2 + 2 + 8 ; + + /* fmt : format, channels, samplerate */ + psf_binheader_writef (psf, "4224", BHW4 (fmt_size), BHW2 (WAVE_FORMAT_EXTENSIBLE), BHW2 (psf->sf.channels), BHW4 (psf->sf.samplerate)) ; + /* fmt : bytespersec */ + psf_binheader_writef (psf, "4", BHW4 (psf->sf.samplerate * psf->bytewidth * psf->sf.channels)) ; + /* fmt : blockalign, bitwidth */ + psf_binheader_writef (psf, "22", BHW2 (psf->bytewidth * psf->sf.channels), BHW2 (psf->bytewidth * 8)) ; + + /* cbSize 22 is sizeof (WAVEFORMATEXTENSIBLE) - sizeof (WAVEFORMATEX) */ + psf_binheader_writef (psf, "2", BHW2 (22)) ; + + /* wValidBitsPerSample, for our use same as bitwidth as we use it fully */ + psf_binheader_writef (psf, "2", BHW2 (psf->bytewidth * 8)) ; + + /* For an Ambisonic file set the channel mask to zero. + ** Otherwise use a default based on the channel count. + */ + if (wpriv->wavex_ambisonic != SF_AMBISONIC_NONE) + psf_binheader_writef (psf, "4", BHW4 (0)) ; + else if (wpriv->wavex_channelmask != 0) + psf_binheader_writef (psf, "4", BHW4 (wpriv->wavex_channelmask)) ; + else + { /* + ** Ok some liberty is taken here to use the most commonly used channel masks + ** instead of "no mapping". If you really want to use "no mapping" for 8 channels and less + ** please don't use wavex. (otherwise we'll have to create a new SF_COMMAND) + */ + switch (psf->sf.channels) + { case 1 : /* center channel mono */ + psf_binheader_writef (psf, "4", BHW4 (0x4)) ; + break ; + + case 2 : /* front left and right */ + psf_binheader_writef (psf, "4", BHW4 (0x1 | 0x2)) ; + break ; + + case 4 : /* Quad */ + psf_binheader_writef (psf, "4", BHW4 (0x1 | 0x2 | 0x10 | 0x20)) ; + break ; + + case 6 : /* 5.1 */ + psf_binheader_writef (psf, "4", BHW4 (0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20)) ; + break ; + + case 8 : /* 7.1 */ + psf_binheader_writef (psf, "4", BHW4 (0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20 | 0x40 | 0x80)) ; + break ; + + default : /* 0 when in doubt , use direct out, ie NO mapping*/ + psf_binheader_writef (psf, "4", BHW4 (0x0)) ; + break ; + } ; + } ; + break ; + + case SF_FORMAT_MS_ADPCM : /* Todo, GUID exists might have different header as per wav_write_header */ + default : + return SFE_UNIMPLEMENTED ; + } ; + + /* GUID section, different for each */ + + switch (subformat) + { case SF_FORMAT_PCM_U8 : + case SF_FORMAT_PCM_16 : + case SF_FORMAT_PCM_24 : + case SF_FORMAT_PCM_32 : + wavlike_write_guid (psf, wpriv->wavex_ambisonic == SF_AMBISONIC_NONE ? + &MSGUID_SUBTYPE_PCM : &MSGUID_SUBTYPE_AMBISONIC_B_FORMAT_PCM) ; + break ; + + case SF_FORMAT_FLOAT : + case SF_FORMAT_DOUBLE : + wavlike_write_guid (psf, wpriv->wavex_ambisonic == SF_AMBISONIC_NONE ? + &MSGUID_SUBTYPE_IEEE_FLOAT : &MSGUID_SUBTYPE_AMBISONIC_B_FORMAT_IEEE_FLOAT) ; + break ; + + case SF_FORMAT_ULAW : + wavlike_write_guid (psf, &MSGUID_SUBTYPE_MULAW) ; + break ; + + case SF_FORMAT_ALAW : + wavlike_write_guid (psf, &MSGUID_SUBTYPE_ALAW) ; + break ; + + default : return SFE_UNIMPLEMENTED ; + } ; + + return 0 ; +} /* rf64_write_fmt_chunk */ + + +static int +rf64_write_header (SF_PRIVATE *psf, int calc_length) +{ sf_count_t current, pad_size ; + int error = 0, has_data = SF_FALSE, add_fact_chunk = 0 ; + WAVLIKE_PRIVATE *wpriv ; + + if ((wpriv = psf->container_data) == NULL) + return SFE_INTERNAL ; + + current = psf_ftell (psf) ; + + if (psf->dataoffset > 0 && current > psf->dataoffset) + has_data = SF_TRUE ; + + if (calc_length) + { psf->filelength = psf_get_filelen (psf) ; + psf->datalength = psf->filelength - psf->dataoffset ; + + if (psf->dataend) + psf->datalength -= psf->filelength - psf->dataend ; + + if (psf->bytewidth > 0) + psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ; + } ; + + /* Reset the current header length to zero. */ + psf->header.ptr [0] = 0 ; + psf->header.indx = 0 ; + psf_fseek (psf, 0, SEEK_SET) ; + + if (wpriv->rf64_downgrade && psf->filelength < RIFF_DOWNGRADE_BYTES) + { psf_binheader_writef (psf, "etm8m", BHWm (RIFF_MARKER), BHW8 ((psf->filelength < 8) ? 8 : psf->filelength - 8), BHWm (WAVE_MARKER)) ; + psf_binheader_writef (psf, "m4z", BHWm (JUNK_MARKER), BHW4 (24), BHWz (24)) ; + add_fact_chunk = 1 ; + } + else + { psf_binheader_writef (psf, "em4m", BHWm (RF64_MARKER), BHW4 (0xffffffff), BHWm (WAVE_MARKER)) ; + /* Currently no table. */ + psf_binheader_writef (psf, "m48884", BHWm (ds64_MARKER), BHW4 (28), BHW8 (psf->filelength - 8), BHW8 (psf->datalength), BHW8 (psf->sf.frames), BHW4 (0)) ; + } ; + + /* WAVE and 'fmt ' markers. */ + psf_binheader_writef (psf, "m", BHWm (fmt_MARKER)) ; + + /* Write the 'fmt ' chunk. */ + switch (psf->sf.format & SF_FORMAT_TYPEMASK) + { case SF_FORMAT_WAV : + psf_log_printf (psf, "ooops SF_FORMAT_WAV\n") ; + return SFE_UNIMPLEMENTED ; + break ; + + case SF_FORMAT_WAVEX : + case SF_FORMAT_RF64 : + if ((error = rf64_write_fmt_chunk (psf)) != 0) + return error ; + if (add_fact_chunk) + psf_binheader_writef (psf, "tm48", BHWm (fact_MARKER), BHW4 (4), BHW8 (psf->sf.frames)) ; + break ; + + default : + return SFE_UNIMPLEMENTED ; + } ; + + if (psf->broadcast_16k != NULL) + wavlike_write_bext_chunk (psf) ; + + if (psf->cart_16k != NULL) + wavlike_write_cart_chunk (psf) ; + + /* The LIST/INFO chunk. */ + if (psf->strings.flags & SF_STR_LOCATE_START) + wavlike_write_strings (psf, SF_STR_LOCATE_START) ; + + if (psf->peak_info != NULL && psf->peak_info->peak_loc == SF_PEAK_START) + wavlike_write_peak_chunk (psf) ; + + /* Write custom headers. */ + if (psf->wchunks.used > 0) + wavlike_write_custom_chunks (psf) ; + +#if 0 + if (psf->instrument != NULL) + { int tmp ; + double dtune = (double) (0x40000000) / 25.0 ; + + psf_binheader_writef (psf, "m4", BHWm (smpl_MARKER), BHW4 (9 * 4 + psf->instrument->loop_count * 6 * 4)) ; + psf_binheader_writef (psf, "44", BHW4 (0), BHW4 (0)) ; /* Manufacturer zero is everyone */ + tmp = (int) (1.0e9 / psf->sf.samplerate) ; /* Sample period in nano seconds */ + psf_binheader_writef (psf, "44", BHW4 (tmp), BHW4 (psf->instrument->basenote)) ; + tmp = (unsigned int) (psf->instrument->detune * dtune + 0.5) ; + psf_binheader_writef (psf, "4", BHW4 (tmp)) ; + psf_binheader_writef (psf, "44", BHW4 (0), BHW4 (0)) ; /* SMTPE format */ + psf_binheader_writef (psf, "44", BHW4 (psf->instrument->loop_count), BHW4 (0)) ; + + for (tmp = 0 ; tmp < psf->instrument->loop_count ; tmp++) + { int type ; + + type = psf->instrument->loops [tmp].mode ; + type = (type == SF_LOOP_FORWARD ? 0 : type == SF_LOOP_BACKWARD ? 2 : type == SF_LOOP_ALTERNATING ? 1 : 32) ; + + psf_binheader_writef (psf, "44", BHW4 (tmp), BHW4 (type)) ; + psf_binheader_writef (psf, "44", BHW4 (psf->instrument->loops [tmp].start), BHW4 (psf->instrument->loops [tmp].end)) ; + psf_binheader_writef (psf, "44", BHW4 (0), BHW4 (psf->instrument->loops [tmp].count)) ; + } ; + } ; + +#endif + + /* Padding may be needed if string data sizes change. */ + pad_size = psf->dataoffset - 16 - psf->header.indx ; + if (pad_size >= 0) + psf_binheader_writef (psf, "m4z", BHWm (PAD_MARKER), BHW4 ((unsigned int) pad_size), BHWz (pad_size)) ; + + if (wpriv->rf64_downgrade && (psf->filelength < RIFF_DOWNGRADE_BYTES)) + psf_binheader_writef (psf, "tm8", BHWm (data_MARKER), BHW8 (psf->datalength)) ; + else + psf_binheader_writef (psf, "m4", BHWm (data_MARKER), BHW4 (0xffffffff)) ; + + psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ; + if (psf->error) + return psf->error ; + + if (has_data && psf->dataoffset != psf->header.indx) + { psf_log_printf (psf, "Oooops : has_data && psf->dataoffset != psf->header.indx\n") ; + return psf->error = SFE_INTERNAL ; + } ; + + psf->dataoffset = psf->header.indx ; + + if (!has_data) + psf_fseek (psf, psf->dataoffset, SEEK_SET) ; + else if (current > 0) + psf_fseek (psf, current, SEEK_SET) ; + + return psf->error ; +} /* rf64_write_header */ + +static int +rf64_write_tailer (SF_PRIVATE *psf) +{ + /* Reset the current header buffer length to zero. */ + psf->header.ptr [0] = 0 ; + psf->header.indx = 0 ; + + if (psf->bytewidth > 0 && psf->sf.seekable == SF_TRUE) + { psf->datalength = psf->sf.frames * psf->bytewidth * psf->sf.channels ; + psf->dataend = psf->dataoffset + psf->datalength ; + } ; + + if (psf->dataend > 0) + psf_fseek (psf, psf->dataend, SEEK_SET) ; + else + psf->dataend = psf_fseek (psf, 0, SEEK_END) ; + + if (psf->dataend & 1) + psf_binheader_writef (psf, "z", BHWz (1)) ; + + if (psf->strings.flags & SF_STR_LOCATE_END) + wavlike_write_strings (psf, SF_STR_LOCATE_END) ; + + /* Write the tailer. */ + if (psf->header.indx > 0) + psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ; + + return 0 ; +} /* rf64_write_tailer */ + +static int +rf64_close (SF_PRIVATE *psf) +{ + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { rf64_write_tailer (psf) ; + rf64_write_header (psf, SF_TRUE) ; + } ; + + return 0 ; +} /* rf64_close */ + +static int +rf64_command (SF_PRIVATE *psf, int command, void * UNUSED (data), int datasize) +{ WAVLIKE_PRIVATE *wpriv ; + + if ((wpriv = psf->container_data) == NULL) + return SFE_INTERNAL ; + + switch (command) + { case SFC_WAVEX_SET_AMBISONIC : + if ((SF_CONTAINER (psf->sf.format)) == SF_FORMAT_WAVEX) + { if (datasize == SF_AMBISONIC_NONE) + wpriv->wavex_ambisonic = SF_AMBISONIC_NONE ; + else if (datasize == SF_AMBISONIC_B_FORMAT) + wpriv->wavex_ambisonic = SF_AMBISONIC_B_FORMAT ; + else + return 0 ; + } ; + return wpriv->wavex_ambisonic ; + + case SFC_WAVEX_GET_AMBISONIC : + return wpriv->wavex_ambisonic ; + + case SFC_SET_CHANNEL_MAP_INFO : + wpriv->wavex_channelmask = wavlike_gen_channel_mask (psf->channel_map, psf->sf.channels) ; + return (wpriv->wavex_channelmask != 0) ; + + case SFC_RF64_AUTO_DOWNGRADE : + if (psf->have_written == 0) + wpriv->rf64_downgrade = datasize ? SF_TRUE : SF_FALSE ; + return wpriv->rf64_downgrade ; + + default : + break ; + } ; + + return 0 ; +} /* rf64_command */ + +static int +rf64_set_chunk (SF_PRIVATE *psf, const SF_CHUNK_INFO * chunk_info) +{ return psf_save_write_chunk (&psf->wchunks, chunk_info) ; +} /* rf64_set_chunk */ + +static SF_CHUNK_ITERATOR * +rf64_next_chunk_iterator (SF_PRIVATE *psf, SF_CHUNK_ITERATOR * iterator) +{ return psf_next_chunk_iterator (&psf->rchunks, iterator) ; +} /* rf64_next_chunk_iterator */ + +static int +rf64_get_chunk_size (SF_PRIVATE *psf, const SF_CHUNK_ITERATOR * iterator, SF_CHUNK_INFO * chunk_info) +{ int indx ; + + if ((indx = psf_find_read_chunk_iterator (&psf->rchunks, iterator)) < 0) + return SFE_UNKNOWN_CHUNK ; + + chunk_info->datalen = psf->rchunks.chunks [indx].len ; + + return SFE_NO_ERROR ; +} /* rf64_get_chunk_size */ + +static int +rf64_get_chunk_data (SF_PRIVATE *psf, const SF_CHUNK_ITERATOR * iterator, SF_CHUNK_INFO * chunk_info) +{ int indx ; + sf_count_t pos ; + + if ((indx = psf_find_read_chunk_iterator (&psf->rchunks, iterator)) < 0) + return SFE_UNKNOWN_CHUNK ; + + if (chunk_info->data == NULL) + return SFE_BAD_CHUNK_DATA_PTR ; + + chunk_info->id_size = psf->rchunks.chunks [indx].id_size ; + memcpy (chunk_info->id, psf->rchunks.chunks [indx].id, sizeof (chunk_info->id) / sizeof (*chunk_info->id)) ; + + pos = psf_ftell (psf) ; + psf_fseek (psf, psf->rchunks.chunks [indx].offset, SEEK_SET) ; + psf_fread (chunk_info->data, SF_MIN (chunk_info->datalen, psf->rchunks.chunks [indx].len), 1, psf) ; + psf_fseek (psf, pos, SEEK_SET) ; + + return SFE_NO_ERROR ; +} /* rf64_get_chunk_data */ diff --git a/extern/libsndfile-modified/src/rx2.c b/extern/libsndfile-modified/src/rx2.c new file mode 100644 index 000000000..0a730480e --- /dev/null +++ b/extern/libsndfile-modified/src/rx2.c @@ -0,0 +1,318 @@ +/* +** Copyright (C) 2001-2012 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + +#if (ENABLE_EXPERIMENTAL_CODE == 0) + +int +rx2_open (SF_PRIVATE *psf) +{ if (psf) + return SFE_UNIMPLEMENTED ; + return 0 ; +} /* rx2_open */ + +#else + +/*------------------------------------------------------------------------------ + * Macros to handle big/little endian issues. +*/ + +#define CAT_MARKER (MAKE_MARKER ('C', 'A', 'T', ' ')) +#define GLOB_MARKER (MAKE_MARKER ('G', 'L', 'O', 'B')) + +#define RECY_MARKER (MAKE_MARKER ('R', 'E', 'C', 'Y')) + +#define SLCL_MARKER (MAKE_MARKER ('S', 'L', 'C', 'L')) +#define SLCE_MARKER (MAKE_MARKER ('S', 'L', 'C', 'E')) + +#define DEVL_MARKER (MAKE_MARKER ('D', 'E', 'V', 'L')) +#define TRSH_MARKER (MAKE_MARKER ('T', 'R', 'S', 'H')) + +#define EQ_MARKER (MAKE_MARKER ('E', 'Q', ' ', ' ')) +#define COMP_MARKER (MAKE_MARKER ('C', 'O', 'M', 'P')) + +#define SINF_MARKER (MAKE_MARKER ('S', 'I', 'N', 'F')) +#define SDAT_MARKER (MAKE_MARKER ('S', 'D', 'A', 'T')) + +/*------------------------------------------------------------------------------ + * Typedefs for file chunks. +*/ + + +/*------------------------------------------------------------------------------ + * Private static functions. +*/ +static int rx2_close (SF_PRIVATE *psf) ; + +/*------------------------------------------------------------------------------ +** Public functions. +*/ + +int +rx2_open (SF_PRIVATE *psf) +{ static const char *marker_type [4] = + { "Original Enabled", "Enabled Hidden", + "Additional/PencilTool", "Disabled" + } ; + + BUF_UNION ubuf ; + int error, marker, length, glob_offset, slce_count, frames ; + int sdat_length = 0, slce_total = 0 ; + int n_channels ; + + + /* So far only doing read. */ + + psf_binheader_readf (psf, "Epm4", 0, &marker, &length) ; + + if (marker != CAT_MARKER) + { psf_log_printf (psf, "length : %d\n", length) ; + return -1000 ; + } ; + + if (length != psf->filelength - 8) + psf_log_printf (psf, "%M : %d (should be %d)\n", marker, length, psf->filelength - 8) ; + else + psf_log_printf (psf, "%M : %d\n", marker, length) ; + + /* 'REX2' marker */ + psf_binheader_readf (psf, "m", &marker) ; + psf_log_printf (psf, "%M", marker) ; + + /* 'HEAD' marker */ + psf_binheader_readf (psf, "m", &marker) ; + psf_log_printf (psf, "%M\n", marker) ; + + /* Grab 'GLOB' offset. */ + psf_binheader_readf (psf, "E4", &glob_offset) ; + glob_offset += 0x14 ; /* Add the current file offset. */ + + /* Jump to offset 0x30 */ + psf_binheader_readf (psf, "p", 0x30) ; + + /* Get name length */ + length = 0 ; + psf_binheader_readf (psf, "1", &length) ; + if (length >= SIGNED_SIZEOF (ubuf.cbuf)) + { psf_log_printf (psf, " Text : %d *** Error : Too sf_count_t!\n") ; + return -1001 ; + } + + memset (ubuf.cbuf, 0, sizeof (ubuf.cbuf)) ; + psf_binheader_readf (psf, "b", ubuf.cbuf, length) ; + psf_log_printf (psf, " Text : \"%s\"\n", ubuf.cbuf) ; + + /* Jump to GLOB offset position. */ + if (glob_offset & 1) + glob_offset ++ ; + + psf_binheader_readf (psf, "p", glob_offset) ; + + slce_count = 0 ; + /* GLOB */ + while (1) + { psf_binheader_readf (psf, "m", &marker) ; + + if (marker != SLCE_MARKER && slce_count > 0) + { psf_log_printf (psf, " SLCE count : %d\n", slce_count) ; + slce_count = 0 ; + } + switch (marker) + { case GLOB_MARKER: + psf_binheader_readf (psf, "E4", &length) ; + psf_log_printf (psf, " %M : %d\n", marker, length) ; + psf_binheader_readf (psf, "j", length) ; + break ; + + case RECY_MARKER: + psf_binheader_readf (psf, "E4", &length) ; + psf_log_printf (psf, " %M : %d\n", marker, length) ; + psf_binheader_readf (psf, "j", (length+1) & 0xFFFFFFFE) ; /* ?????? */ + break ; + + case CAT_MARKER: + psf_binheader_readf (psf, "E4", &length) ; + psf_log_printf (psf, " %M : %d\n", marker, length) ; + /*-psf_binheader_readf (psf, "j", length) ;-*/ + break ; + + case DEVL_MARKER: + psf_binheader_readf (psf, "mE4", &marker, &length) ; + psf_log_printf (psf, " DEVL%M : %d\n", marker, length) ; + if (length & 1) + length ++ ; + psf_binheader_readf (psf, "j", length) ; + break ; + + case EQ_MARKER: + case COMP_MARKER: + psf_binheader_readf (psf, "E4", &length) ; + psf_log_printf (psf, " %M : %d\n", marker, length) ; + /* This is weird!!!! why make this (length - 1) */ + if (length & 1) + length ++ ; + psf_binheader_readf (psf, "j", length) ; + break ; + + case SLCL_MARKER: + psf_log_printf (psf, " %M\n (Offset, Next Offset, Type)\n", marker) ; + slce_count = 0 ; + break ; + + case SLCE_MARKER: + { int len [4], indx ; + + psf_binheader_readf (psf, "E4444", &len [0], &len [1], &len [2], &len [3]) ; + + indx = ((len [3] & 0x0000FFFF) >> 8) & 3 ; + + if (len [2] == 1) + { if (indx != 1) + indx = 3 ; /* 2 cases, where next slice offset = 1 -> disabled & enabled/hidden */ + + psf_log_printf (psf, " %M : (%6d, ?: 0x%X, %s)\n", marker, len [1], (len [3] & 0xFFFF0000) >> 16, marker_type [indx]) ; + } + else + { slce_total += len [2] ; + + psf_log_printf (psf, " %M : (%6d, SLCE_next_ofs:%d, ?: 0x%X, %s)\n", marker, len [1], len [2], (len [3] & 0xFFFF0000) >> 16, marker_type [indx]) ; + } ; + + slce_count ++ ; + } ; + break ; + + case SINF_MARKER: + psf_binheader_readf (psf, "E4", &length) ; + psf_log_printf (psf, " %M : %d\n", marker, length) ; + + psf_binheader_readf (psf, "E2", &n_channels) ; + n_channels = (n_channels & 0x0000FF00) >> 8 ; + psf_log_printf (psf, " Channels : %d\n", n_channels) ; + + psf_binheader_readf (psf, "E44", &psf->sf.samplerate, &frames) ; + psf->sf.frames = frames ; + psf_log_printf (psf, " Sample Rate : %d\n", psf->sf.samplerate) ; + psf_log_printf (psf, " Frames : %D\n", psf->sf.frames) ; + + psf_binheader_readf (psf, "E4", &length) ; + psf_log_printf (psf, " ??????????? : %d\n", length) ; + + psf_binheader_readf (psf, "E4", &length) ; + psf_log_printf (psf, " ??????????? : %d\n", length) ; + break ; + + case SDAT_MARKER: + psf_binheader_readf (psf, "E4", &length) ; + + sdat_length = length ; + + /* Get the current offset. */ + psf->dataoffset = psf_binheader_readf (psf, NULL) ; + + if (psf->dataoffset + length != psf->filelength) + psf_log_printf (psf, " %M : %d (should be %d)\n", marker, length, psf->dataoffset + psf->filelength) ; + else + psf_log_printf (psf, " %M : %d\n", marker, length) ; + break ; + + default : + psf_log_printf (psf, "Unknown marker : 0x%X %M", marker, marker) ; + return -1003 ; + break ; + } ; + + /* SDAT always last marker in file. */ + if (marker == SDAT_MARKER) + break ; + } ; + + puts (psf->parselog.buf) ; + puts ("-----------------------------------") ; + + printf ("SDAT length : %d\n", sdat_length) ; + printf ("SLCE count : %d\n", slce_count) ; + + /* Hack for zero slice count. */ + if (slce_count == 0 && slce_total == 1) + slce_total = frames ; + + printf ("SLCE samples : %d\n", slce_total) ; + + /* Two bytes per sample. */ + printf ("Comp Ratio : %f:1\n", (2.0 * slce_total * n_channels) / sdat_length) ; + + puts (" ") ; + + psf->parselog.buf [0] = 0 ; + + /* OK, have the header although not too sure what it all means. */ + + psf->endian = SF_ENDIAN_BIG ; + + psf->datalength = psf->filelength - psf->dataoffset ; + + if (psf_fseek (psf, psf->dataoffset, SEEK_SET)) + return SFE_BAD_SEEK ; + + psf->sf.format = (SF_FORMAT_REX2 | SF_FORMAT_DWVW_12) ; + + psf->sf.channels = 1 ; + psf->bytewidth = 2 ; + psf->blockwidth = psf->sf.channels * psf->bytewidth ; + + if ((error = dwvw_init (psf, 16))) + return error ; + + psf->container_close = rx2_close ; + + if (! psf->sf.frames && psf->blockwidth) + psf->sf.frames = psf->datalength / psf->blockwidth ; + + /* All done. */ + + return 0 ; +} /* rx2_open */ + +/*------------------------------------------------------------------------------ +*/ + +static int +rx2_close (SF_PRIVATE *psf) +{ + if (psf->file.mode == SFM_WRITE) + { /* Now we know for certain the length of the file we can re-write + ** correct values for the FORM, 8SVX and BODY chunks. + */ + + } ; + + return 0 ; +} /* rx2_close */ + +#endif diff --git a/extern/libsndfile-modified/src/sd2.c b/extern/libsndfile-modified/src/sd2.c new file mode 100644 index 000000000..f5ef9de20 --- /dev/null +++ b/extern/libsndfile-modified/src/sd2.c @@ -0,0 +1,619 @@ +/* +** Copyright (C) 2001-2020 Erik de Castro Lopo +** Copyright (C) 2004 Paavo Jumppanen +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/* +** The sd2 support implemented in this file was partially sponsored +** (financially) by Paavo Jumppanen. +*/ + +/* +** Documentation on the Mac resource fork was obtained here : +** http://developer.apple.com/documentation/mac/MoreToolbox/MoreToolbox-99.html +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + +/*------------------------------------------------------------------------------ + * Markers. +*/ + +#define Sd2f_MARKER MAKE_MARKER ('S', 'd', '2', 'f') +#define Sd2a_MARKER MAKE_MARKER ('S', 'd', '2', 'a') +#define ALCH_MARKER MAKE_MARKER ('A', 'L', 'C', 'H') +#define lsf1_MARKER MAKE_MARKER ('l', 's', 'f', '1') + +#define STR_MARKER MAKE_MARKER ('S', 'T', 'R', ' ') +#define sdML_MARKER MAKE_MARKER ('s', 'd', 'M', 'L') + +enum +{ RSRC_STR = 111, + RSRC_BIN +} ; + +typedef struct +{ unsigned char * rsrc_data ; + int rsrc_len ; + int need_to_free_rsrc_data ; + + int data_offset, data_length ; + int map_offset, map_length ; + + int type_count, type_offset ; + int item_offset ; + + int str_index, str_count ; + + int string_offset ; + + /* All the above just to get these three. */ + int sample_size, sample_rate, channels ; +} SD2_RSRC ; + +typedef struct +{ int type ; + int id ; + char name [32] ; + char value [32] ; + int value_len ; +} STR_RSRC ; + +/*------------------------------------------------------------------------------ + * Private static functions. +*/ + +static int sd2_close (SF_PRIVATE *psf) ; + +static int sd2_parse_rsrc_fork (SF_PRIVATE *psf) ; +static int parse_str_rsrc (SF_PRIVATE *psf, SD2_RSRC * rsrc) ; + +static int sd2_write_rsrc_fork (SF_PRIVATE *psf, int calc_length) ; + +/*------------------------------------------------------------------------------ +** Public functions. +*/ + +int +sd2_open (SF_PRIVATE *psf) +{ int subformat, error = 0, valid ; + + /* SD2 is always big endian. */ + psf->endian = SF_ENDIAN_BIG ; + + if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->rsrclength > 0)) + { psf_use_rsrc (psf, SF_TRUE) ; + valid = psf_file_valid (psf) ; + psf_use_rsrc (psf, SF_FALSE) ; + if (! valid) + { psf_log_printf (psf, "sd2_open : psf->rsrc.filedes < 0\n") ; + return SFE_SD2_BAD_RSRC ; + } ; + + error = sd2_parse_rsrc_fork (psf) ; + + if (error) + goto error_cleanup ; + } ; + + if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_SD2) + { error = SFE_BAD_OPEN_FORMAT ; + goto error_cleanup ; + } ; + + subformat = SF_CODEC (psf->sf.format) ; + psf->dataoffset = 0 ; + + /* Only open and write the resource in RDWR mode is its current length is zero. */ + if (psf->file.mode == SFM_WRITE || (psf->file.mode == SFM_RDWR && psf->rsrclength == 0)) + { psf->rsrc.mode = psf->file.mode ; + psf_open_rsrc (psf) ; + + error = sd2_write_rsrc_fork (psf, SF_FALSE) ; + + if (error) + goto error_cleanup ; + + /* Not needed. */ + psf->write_header = NULL ; + } ; + + psf->container_close = sd2_close ; + + psf->blockwidth = psf->bytewidth * psf->sf.channels ; + + switch (subformat) + { case SF_FORMAT_PCM_S8 : /* 8-bit linear PCM. */ + case SF_FORMAT_PCM_16 : /* 16-bit linear PCM. */ + case SF_FORMAT_PCM_24 : /* 24-bit linear PCM */ + case SF_FORMAT_PCM_32 : /* 32-bit linear PCM */ + error = pcm_init (psf) ; + break ; + + default : + error = SFE_UNIMPLEMENTED ; + break ; + } ; + + psf_fseek (psf, psf->dataoffset, SEEK_SET) ; + +error_cleanup: + + /* Close the resource fork regardless. We won't need it again. */ + psf_close_rsrc (psf) ; + + return error ; +} /* sd2_open */ + +/*------------------------------------------------------------------------------ +*/ + +static int +sd2_close (SF_PRIVATE *psf) +{ + if (psf->file.mode == SFM_WRITE) + { /* Now we know for certain the audio_length of the file we can re-write + ** correct values for the FORM, 8SVX and BODY chunks. + */ + + } ; + + return 0 ; +} /* sd2_close */ + +/*------------------------------------------------------------------------------ +*/ + +static int +sd2_write_rsrc_fork (SF_PRIVATE *psf, int UNUSED (calc_length)) +{ SD2_RSRC rsrc ; + STR_RSRC str_rsrc [] = + { { RSRC_STR, 1000, "_sample-size", "", 0 }, + { RSRC_STR, 1001, "_sample-rate", "", 0 }, + { RSRC_STR, 1002, "_channels", "", 0 }, + { RSRC_BIN, 1000, "_Markers", "", 8 } + } ; + + int k, str_offset, data_offset, next_str ; + + psf_use_rsrc (psf, SF_TRUE) ; + + memset (&rsrc, 0, sizeof (rsrc)) ; + + rsrc.sample_rate = psf->sf.samplerate ; + rsrc.sample_size = psf->bytewidth ; + rsrc.channels = psf->sf.channels ; + + rsrc.rsrc_data = psf->header.ptr ; + rsrc.rsrc_len = psf->header.len ; + memset (rsrc.rsrc_data, 0xea, rsrc.rsrc_len) ; + + snprintf (str_rsrc [0].value, sizeof (str_rsrc [0].value), "_%d", rsrc.sample_size) ; + snprintf (str_rsrc [1].value, sizeof (str_rsrc [1].value), "_%d.000000", rsrc.sample_rate) ; + snprintf (str_rsrc [2].value, sizeof (str_rsrc [2].value), "_%d", rsrc.channels) ; + + for (k = 0 ; k < ARRAY_LEN (str_rsrc) ; k++) + { if (str_rsrc [k].value_len == 0) + { str_rsrc [k].value_len = strlen (str_rsrc [k].value) ; + str_rsrc [k].value [0] = str_rsrc [k].value_len - 1 ; + } ; + + /* Turn name string into a pascal string. */ + str_rsrc [k].name [0] = strlen (str_rsrc [k].name) - 1 ; + } ; + + rsrc.data_offset = 0x100 ; + + /* + ** Calculate data length : + ** length of strings, plus the length of the sdML chunk. + */ + rsrc.data_length = 0 ; + for (k = 0 ; k < ARRAY_LEN (str_rsrc) ; k++) + rsrc.data_length += str_rsrc [k].value_len + 4 ; + + rsrc.map_offset = rsrc.data_offset + rsrc.data_length ; + + /* Very start of resource fork. */ + psf_binheader_writef (psf, "E444", BHW4 (rsrc.data_offset), BHW4 (rsrc.map_offset), BHW4 (rsrc.data_length)) ; + + psf_binheader_writef (psf, "Eop", BHWo (0x30), BHWp (psf->file.name)) ; + psf_binheader_writef (psf, "Eo2mm", BHWo (0x50), BHW2 (0), BHWm (Sd2f_MARKER), BHWm (lsf1_MARKER)) ; + + /* Very start of resource map. */ + psf_binheader_writef (psf, "E4444", BHW4 (rsrc.map_offset), BHW4 (rsrc.data_offset), BHW4 (rsrc.map_offset), BHW4 (rsrc.data_length)) ; + + /* These I don't currently understand. */ + if (1) + { psf_binheader_writef (psf, "Eo1422", BHWo (rsrc.map_offset + 16), BHW1 (1), BHW4 (0x12345678), BHW2 (0xabcd), BHW2 (0)) ; + } ; + + /* Resource type offset. */ + rsrc.type_offset = rsrc.map_offset + 30 ; + psf_binheader_writef (psf, "Eo2", BHWo (rsrc.map_offset + 24), BHW2 (rsrc.type_offset - rsrc.map_offset - 2)) ; + + /* Type index max. */ + rsrc.type_count = 2 ; + psf_binheader_writef (psf, "Eo2", BHWo (rsrc.map_offset + 28), BHW2 (rsrc.type_count - 1)) ; + + rsrc.item_offset = rsrc.type_offset + rsrc.type_count * 8 ; + + rsrc.str_count = ARRAY_LEN (str_rsrc) ; + rsrc.string_offset = rsrc.item_offset + (rsrc.str_count + 1) * 12 - rsrc.map_offset ; + psf_binheader_writef (psf, "Eo2", BHWo (rsrc.map_offset + 26), BHW2 (rsrc.string_offset)) ; + + /* Write 'STR ' resource type. */ + rsrc.str_count = 3 ; + psf_binheader_writef (psf, "Eom22", BHWo (rsrc.type_offset), BHWm (STR_MARKER), BHW2 (rsrc.str_count - 1), BHW2 (0x12)) ; + + /* Write 'sdML' resource type. */ + psf_binheader_writef (psf, "Em22", BHWm (sdML_MARKER), BHW2 (0), BHW2 (0x36)) ; + + str_offset = rsrc.map_offset + rsrc.string_offset ; + next_str = 0 ; + data_offset = rsrc.data_offset ; + for (k = 0 ; k < ARRAY_LEN (str_rsrc) ; k++) + { psf_binheader_writef (psf, "Eop", BHWo (str_offset), BHWp (str_rsrc [k].name)) ; + psf_binheader_writef (psf, "Eo22", BHWo (rsrc.item_offset + k * 12), BHW2 (str_rsrc [k].id), BHW2 (next_str)) ; + + str_offset += strlen (str_rsrc [k].name) ; + next_str += strlen (str_rsrc [k].name) ; + + psf_binheader_writef (psf, "Eo4", BHWo (rsrc.item_offset + k * 12 + 4), BHW4 (data_offset - rsrc.data_offset)) ; + psf_binheader_writef (psf, "Eo4", BHWo (data_offset), BHW4 (str_rsrc [k].value_len)) ; + + psf_binheader_writef (psf, "Eob", BHWo (data_offset + 4), BHWv (str_rsrc [k].value), BHWz (str_rsrc [k].value_len)) ; + data_offset += 4 + str_rsrc [k].value_len ; + } ; + + /* Finally, calculate and set map length. */ + rsrc.map_length = str_offset - rsrc.map_offset ; + psf_binheader_writef (psf, "Eo4o4", BHWo (12), BHW4 (rsrc.map_length), + BHWo (rsrc.map_offset + 12), BHW4 (rsrc.map_length)) ; + + psf->header.indx = rsrc.map_offset + rsrc.map_length ; + + psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ; + + psf_use_rsrc (psf, SF_FALSE) ; + + if (psf->error) + return psf->error ; + + return 0 ; +} /* sd2_write_rsrc_fork */ + +/*------------------------------------------------------------------------------ +*/ + +static inline int +read_rsrc_char (const SD2_RSRC *prsrc, int offset) +{ const unsigned char * data = prsrc->rsrc_data ; + if (offset < 0 || offset >= prsrc->rsrc_len) + return 0 ; + return data [offset] ; +} /* read_rsrc_char */ + +static inline int +read_rsrc_short (const SD2_RSRC *prsrc, int offset) +{ const unsigned char * data = prsrc->rsrc_data ; + if (offset < 0 || offset + 1 >= prsrc->rsrc_len) + return 0 ; + return (data [offset] << 8) + data [offset + 1] ; +} /* read_rsrc_short */ + +static inline int +read_rsrc_int (const SD2_RSRC *prsrc, int offset) +{ const unsigned char * data = prsrc->rsrc_data ; + if (offset < 0 || offset + 3 >= prsrc->rsrc_len) + return 0 ; + return (((uint32_t) data [offset]) << 24) + (data [offset + 1] << 16) + (data [offset + 2] << 8) + data [offset + 3] ; +} /* read_rsrc_int */ + +static inline int +read_rsrc_marker (const SD2_RSRC *prsrc, int offset) +{ const unsigned char * data = prsrc->rsrc_data ; + + if (offset < 0 || offset + 3 >= prsrc->rsrc_len) + return 0 ; + + if (CPU_IS_BIG_ENDIAN) + return (((uint32_t) data [offset]) << 24) + (data [offset + 1] << 16) + (data [offset + 2] << 8) + data [offset + 3] ; + if (CPU_IS_LITTLE_ENDIAN) + return data [offset] + (data [offset + 1] << 8) + (data [offset + 2] << 16) + (((uint32_t) data [offset + 3]) << 24) ; + + return 0 ; +} /* read_rsrc_marker */ + +static void +read_rsrc_str (const SD2_RSRC *prsrc, int offset, char * buffer, int buffer_len) +{ const unsigned char * data = prsrc->rsrc_data ; + int k ; + + memset (buffer, 0, buffer_len) ; + + if (offset < 0 || offset + buffer_len >= prsrc->rsrc_len) + return ; + + for (k = 0 ; k < buffer_len - 1 ; k++) + { if (psf_isprint (data [offset + k]) == 0) + return ; + buffer [k] = data [offset + k] ; + } ; + return ; +} /* read_rsrc_str */ + +static int +sd2_parse_rsrc_fork (SF_PRIVATE *psf) +{ SD2_RSRC rsrc ; + int k, marker, error = 0 ; + + psf_use_rsrc (psf, SF_TRUE) ; + + memset (&rsrc, 0, sizeof (rsrc)) ; + + rsrc.rsrc_len = psf_get_filelen (psf) ; + psf_log_printf (psf, "Resource length : %d (0x%04X)\n", rsrc.rsrc_len, rsrc.rsrc_len) ; + + if (rsrc.rsrc_len > psf->header.len) + { rsrc.rsrc_data = calloc (1, rsrc.rsrc_len) ; + rsrc.need_to_free_rsrc_data = SF_TRUE ; + } + else + { + rsrc.rsrc_data = psf->header.ptr ; + // rsrc.rsrc_len > psf->header.len ; + rsrc.need_to_free_rsrc_data = SF_FALSE ; + } ; + + /* Read in the whole lot. */ + psf_fread (rsrc.rsrc_data, rsrc.rsrc_len, 1, psf) ; + + /* Reset the header storage because we have changed to the rsrcdes. */ + psf->header.indx = psf->header.end = rsrc.rsrc_len ; + + rsrc.data_offset = read_rsrc_int (&rsrc, 0) ; + rsrc.map_offset = read_rsrc_int (&rsrc, 4) ; + rsrc.data_length = read_rsrc_int (&rsrc, 8) ; + rsrc.map_length = read_rsrc_int (&rsrc, 12) ; + + if (rsrc.data_offset == 0x51607 && rsrc.map_offset == 0x20000) + { psf_log_printf (psf, "Trying offset of 0x52 bytes.\n") ; + rsrc.data_offset = read_rsrc_int (&rsrc, 0x52 + 0) + 0x52 ; + rsrc.map_offset = read_rsrc_int (&rsrc, 0x52 + 4) + 0x52 ; + rsrc.data_length = read_rsrc_int (&rsrc, 0x52 + 8) ; + rsrc.map_length = read_rsrc_int (&rsrc, 0x52 + 12) ; + } ; + + psf_log_printf (psf, " data offset : 0x%04X\n map offset : 0x%04X\n" + " data length : 0x%04X\n map length : 0x%04X\n", + rsrc.data_offset, rsrc.map_offset, rsrc.data_length, rsrc.map_length) ; + + if (rsrc.data_offset > rsrc.rsrc_len) + { psf_log_printf (psf, "Error : rsrc.data_offset (%d, 0x%x) > len\n", rsrc.data_offset, rsrc.data_offset) ; + error = SFE_SD2_BAD_DATA_OFFSET ; + goto parse_rsrc_fork_cleanup ; + } ; + + if (rsrc.map_offset > rsrc.rsrc_len) + { psf_log_printf (psf, "Error : rsrc.map_offset > len\n") ; + error = SFE_SD2_BAD_MAP_OFFSET ; + goto parse_rsrc_fork_cleanup ; + } ; + + if (rsrc.data_length > rsrc.rsrc_len) + { psf_log_printf (psf, "Error : rsrc.data_length > len\n") ; + error = SFE_SD2_BAD_DATA_LENGTH ; + goto parse_rsrc_fork_cleanup ; + } ; + + if (rsrc.map_length > rsrc.rsrc_len) + { psf_log_printf (psf, "Error : rsrc.map_length > len\n") ; + error = SFE_SD2_BAD_MAP_LENGTH ; + goto parse_rsrc_fork_cleanup ; + } ; + + if (rsrc.data_offset + rsrc.data_length != rsrc.map_offset || rsrc.map_offset + rsrc.map_length != rsrc.rsrc_len) + { psf_log_printf (psf, "Error : This does not look like a MacOSX resource fork.\n") ; + error = SFE_SD2_BAD_RSRC ; + goto parse_rsrc_fork_cleanup ; + } ; + + if (rsrc.map_offset + 28 >= rsrc.rsrc_len) + { psf_log_printf (psf, "Bad map offset (%d + 28 > %d).\n", rsrc.map_offset, rsrc.rsrc_len) ; + error = SFE_SD2_BAD_RSRC ; + goto parse_rsrc_fork_cleanup ; + } ; + + rsrc.string_offset = rsrc.map_offset + read_rsrc_short (&rsrc, rsrc.map_offset + 26) ; + if (rsrc.string_offset > rsrc.rsrc_len) + { psf_log_printf (psf, "Bad string offset (%d).\n", rsrc.string_offset) ; + error = SFE_SD2_BAD_RSRC ; + goto parse_rsrc_fork_cleanup ; + } ; + + rsrc.type_offset = rsrc.map_offset + 30 ; + + if (rsrc.map_offset + 28 > rsrc.rsrc_len) + { psf_log_printf (psf, "Bad map offset.\n") ; + goto parse_rsrc_fork_cleanup ; + } ; + + rsrc.type_count = read_rsrc_short (&rsrc, rsrc.map_offset + 28) + 1 ; + if (rsrc.type_count < 1) + { psf_log_printf (psf, "Bad type count.\n") ; + error = SFE_SD2_BAD_RSRC ; + goto parse_rsrc_fork_cleanup ; + } ; + + rsrc.item_offset = rsrc.type_offset + rsrc.type_count * 8 ; + if (rsrc.item_offset < 0 || rsrc.item_offset > rsrc.rsrc_len) + { psf_log_printf (psf, "Bad item offset (%d).\n", rsrc.item_offset) ; + error = SFE_SD2_BAD_RSRC ; + goto parse_rsrc_fork_cleanup ; + } ; + + rsrc.str_index = -1 ; + for (k = 0 ; k < rsrc.type_count ; k ++) + { if (rsrc.type_offset + k * 8 > rsrc.rsrc_len) + { psf_log_printf (psf, "Bad rsrc marker.\n") ; + goto parse_rsrc_fork_cleanup ; + } ; + + marker = read_rsrc_marker (&rsrc, rsrc.type_offset + k * 8) ; + + if (marker == STR_MARKER) + { rsrc.str_index = k ; + rsrc.str_count = read_rsrc_short (&rsrc, rsrc.type_offset + k * 8 + 4) + 1 ; + error = parse_str_rsrc (psf, &rsrc) ; + goto parse_rsrc_fork_cleanup ; + } ; + } ; + + psf_log_printf (psf, "No 'STR ' resource.\n") ; + error = SFE_SD2_BAD_RSRC ; + +parse_rsrc_fork_cleanup : + + psf_use_rsrc (psf, SF_FALSE) ; + + if (rsrc.need_to_free_rsrc_data) + free (rsrc.rsrc_data) ; + + return error ; +} /* sd2_parse_rsrc_fork */ + +static int +parse_str_rsrc (SF_PRIVATE *psf, SD2_RSRC * rsrc) +{ char name [32], value [32] ; + int k, str_offset, rsrc_id, data_offset = 0, data_len = 0 ; + + psf_log_printf (psf, "Finding parameters :\n") ; + + str_offset = rsrc->string_offset ; + psf_log_printf (psf, " Offset RsrcId dlen slen Value\n") ; + + + for (k = 0 ; data_offset + data_len < rsrc->rsrc_len ; k++) + { int slen ; + + slen = read_rsrc_char (rsrc, str_offset) ; + read_rsrc_str (rsrc, str_offset + 1, name, SF_MIN (SIGNED_SIZEOF (name), slen + 1)) ; + str_offset += slen + 1 ; + + // work-around for GitHub issue #340 + int id_offset = rsrc->item_offset + k * 12 ; + if (id_offset < 0 || id_offset + 1 >= rsrc->rsrc_len) + { psf_log_printf (psf, "Exiting parser on id_offset of %d.\n", id_offset) ; + break ; + } + rsrc_id = read_rsrc_short (rsrc, id_offset) ; + + data_offset = rsrc->data_offset + read_rsrc_int (rsrc, rsrc->item_offset + k * 12 + 4) ; + if (data_offset < 0 || data_offset > rsrc->rsrc_len) + { psf_log_printf (psf, "Exiting parser on data offset of %d.\n", data_offset) ; + break ; + } ; + + data_len = read_rsrc_int (rsrc, data_offset) ; + if (data_len < 0 || data_len > rsrc->rsrc_len) + { psf_log_printf (psf, "Exiting parser on data length of %d.\n", data_len) ; + break ; + } ; + + slen = read_rsrc_char (rsrc, data_offset + 4) ; + read_rsrc_str (rsrc, data_offset + 5, value, SF_MIN (SIGNED_SIZEOF (value), slen + 1)) ; + + psf_log_printf (psf, " 0x%04x %4d %4d %3d '%s'\n", data_offset, rsrc_id, data_len, slen, value) ; + + if (strstr (value, "Photoshop")) + { psf_log_printf (psf, "Exiting parser on Photoshop data.\n", data_offset) ; + break ; + } ; + + if (rsrc_id == 1000 && rsrc->sample_size == 0) + rsrc->sample_size = strtol (value, NULL, 10) ; + else if (rsrc_id == 1001 && rsrc->sample_rate == 0) + rsrc->sample_rate = strtol (value, NULL, 10) ; + else if (rsrc_id == 1002 && rsrc->channels == 0) + rsrc->channels = strtol (value, NULL, 10) ; + } ; + + psf_log_printf (psf, "Found Parameters :\n") ; + psf_log_printf (psf, " sample-size : %d\n", rsrc->sample_size) ; + psf_log_printf (psf, " sample-rate : %d\n", rsrc->sample_rate) ; + psf_log_printf (psf, " channels : %d\n", rsrc->channels) ; + + if (rsrc->sample_rate <= 4 && rsrc->sample_size > 4) + { int temp ; + + psf_log_printf (psf, "Geez!! Looks like sample rate and sample size got switched.\nCorrecting this screw up.\n") ; + temp = rsrc->sample_rate ; + rsrc->sample_rate = rsrc->sample_size ; + rsrc->sample_size = temp ; + } ; + + if (rsrc->sample_rate < 0) + { psf_log_printf (psf, "Bad sample rate (%d)\n", rsrc->sample_rate) ; + return SFE_SD2_BAD_RSRC ; + } ; + + if (rsrc->channels < 0) + { psf_log_printf (psf, "Bad channel count (%d)\n", rsrc->channels) ; + return SFE_SD2_BAD_RSRC ; + } ; + + psf->sf.samplerate = rsrc->sample_rate ; + psf->sf.channels = rsrc->channels ; + psf->bytewidth = rsrc->sample_size ; + + switch (rsrc->sample_size) + { case 1 : + psf->sf.format = SF_FORMAT_SD2 | SF_FORMAT_PCM_S8 ; + break ; + + case 2 : + psf->sf.format = SF_FORMAT_SD2 | SF_FORMAT_PCM_16 ; + break ; + + case 3 : + psf->sf.format = SF_FORMAT_SD2 | SF_FORMAT_PCM_24 ; + break ; + + case 4 : + psf->sf.format = SF_FORMAT_SD2 | SF_FORMAT_PCM_32 ; + break ; + + default : + psf_log_printf (psf, "Bad sample size (%d)\n", rsrc->sample_size) ; + return SFE_SD2_BAD_SAMPLE_SIZE ; + } ; + + psf_log_printf (psf, "ok\n") ; + + return 0 ; +} /* parse_str_rsrc */ + diff --git a/extern/libsndfile-modified/src/sds.c b/extern/libsndfile-modified/src/sds.c new file mode 100644 index 000000000..6bc761716 --- /dev/null +++ b/extern/libsndfile-modified/src/sds.c @@ -0,0 +1,1022 @@ +/* +** Copyright (C) 2002-2017 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + +/*------------------------------------------------------------------------------ +*/ + +#define SDS_DATA_OFFSET 0x15 +#define SDS_BLOCK_SIZE 127 + +#define SDS_AUDIO_BYTES_PER_BLOCK 120 + +#define SDS_3BYTE_TO_INT_DECODE(x) (((x) & 0x7F) | (((x) & 0x7F00) >> 1) | (((x) & 0x7F0000) >> 2)) +#define SDS_INT_TO_3BYTE_ENCODE(x) (((x) & 0x7F) | (((x) << 1) & 0x7F00) | (((x) << 2) & 0x7F0000)) + +/*------------------------------------------------------------------------------ +** Typedefs. +*/ + +typedef struct tag_SDS_PRIVATE +{ int bitwidth, frames ; + int samplesperblock, total_blocks ; + + int (*reader) (SF_PRIVATE *psf, struct tag_SDS_PRIVATE *psds) ; + int (*writer) (SF_PRIVATE *psf, struct tag_SDS_PRIVATE *psds) ; + + int read_block, read_count ; + unsigned char read_data [SDS_BLOCK_SIZE] ; + int read_samples [SDS_BLOCK_SIZE / 2] ; /* Maximum samples per block */ + + int write_block, write_count ; + int total_written ; + unsigned char write_data [SDS_BLOCK_SIZE] ; + int write_samples [SDS_BLOCK_SIZE / 2] ; /* Maximum samples per block */ +} SDS_PRIVATE ; + +/*------------------------------------------------------------------------------ +** Private static functions. +*/ + +static int sds_close (SF_PRIVATE *psf) ; + +static int sds_write_header (SF_PRIVATE *psf, int calc_length) ; +static int sds_read_header (SF_PRIVATE *psf, SDS_PRIVATE *psds) ; + +static int sds_init (SF_PRIVATE *psf, SDS_PRIVATE *psds) ; + +static sf_count_t sds_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; +static sf_count_t sds_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; +static sf_count_t sds_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; +static sf_count_t sds_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; + +static sf_count_t sds_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; +static sf_count_t sds_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; +static sf_count_t sds_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; +static sf_count_t sds_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; + +static sf_count_t sds_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ; +static int sds_byterate (SF_PRIVATE * psf) ; + +static int sds_2byte_read (SF_PRIVATE *psf, SDS_PRIVATE *psds) ; +static int sds_3byte_read (SF_PRIVATE *psf, SDS_PRIVATE *psds) ; +static int sds_4byte_read (SF_PRIVATE *psf, SDS_PRIVATE *psds) ; + +static int sds_read (SF_PRIVATE *psf, SDS_PRIVATE *psds, int *iptr, int readcount) ; + +static int sds_2byte_write (SF_PRIVATE *psf, SDS_PRIVATE *psds) ; +static int sds_3byte_write (SF_PRIVATE *psf, SDS_PRIVATE *psds) ; +static int sds_4byte_write (SF_PRIVATE *psf, SDS_PRIVATE *psds) ; + +static int sds_write (SF_PRIVATE *psf, SDS_PRIVATE *psds, const int *iptr, int writecount) ; + +/*------------------------------------------------------------------------------ +** Public function. +*/ + +int +sds_open (SF_PRIVATE *psf) +{ SDS_PRIVATE *psds ; + int error = 0 ; + + /* Hmmmm, need this here to pass update_header_test. */ + psf->sf.frames = 0 ; + + if (! (psds = calloc (1, sizeof (SDS_PRIVATE)))) + return SFE_MALLOC_FAILED ; + psf->codec_data = psds ; + + if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0)) + { if ((error = sds_read_header (psf, psds))) + return error ; + } ; + + if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_SDS) + return SFE_BAD_OPEN_FORMAT ; + + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { if (sds_write_header (psf, SF_FALSE)) + return psf->error ; + + psf->write_header = sds_write_header ; + + psf_fseek (psf, SDS_DATA_OFFSET, SEEK_SET) ; + } ; + + if ((error = sds_init (psf, psds)) != 0) + return error ; + + psf->container_close = sds_close ; + psf->seek = sds_seek ; + psf->byterate = sds_byterate ; + + psf->blockwidth = 0 ; + + return error ; +} /* sds_open */ + +/*------------------------------------------------------------------------------ +*/ + +static int +sds_close (SF_PRIVATE *psf) +{ + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { SDS_PRIVATE *psds ; + + if ((psds = (SDS_PRIVATE *) psf->codec_data) == NULL) + { psf_log_printf (psf, "*** Bad psf->codec_data ptr.\n") ; + return SFE_INTERNAL ; + } ; + + if (psds->write_count > 0) + { memset (&(psds->write_data [psds->write_count]), 0, (psds->samplesperblock - psds->write_count) * sizeof (int)) ; + psds->writer (psf, psds) ; + } ; + + sds_write_header (psf, SF_TRUE) ; + } ; + + return 0 ; +} /* sds_close */ + +static int +sds_init (SF_PRIVATE *psf, SDS_PRIVATE *psds) +{ + if (psds->bitwidth < 8 || psds->bitwidth > 28) + return (psf->error = SFE_SDS_BAD_BIT_WIDTH) ; + + if (psds->bitwidth < 14) + { psds->reader = sds_2byte_read ; + psds->writer = sds_2byte_write ; + psds->samplesperblock = SDS_AUDIO_BYTES_PER_BLOCK / 2 ; + } + else if (psds->bitwidth < 21) + { psds->reader = sds_3byte_read ; + psds->writer = sds_3byte_write ; + psds->samplesperblock = SDS_AUDIO_BYTES_PER_BLOCK / 3 ; + } + else + { psds->reader = sds_4byte_read ; + psds->writer = sds_4byte_write ; + psds->samplesperblock = SDS_AUDIO_BYTES_PER_BLOCK / 4 ; + } ; + + if (psf->file.mode == SFM_READ || psf->file.mode == SFM_RDWR) + { psf->read_short = sds_read_s ; + psf->read_int = sds_read_i ; + psf->read_float = sds_read_f ; + psf->read_double = sds_read_d ; + + /* Read first block. */ + psds->reader (psf, psds) ; + } ; + + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { psf->write_short = sds_write_s ; + psf->write_int = sds_write_i ; + psf->write_float = sds_write_f ; + psf->write_double = sds_write_d ; + } ; + + return 0 ; +} /* sds_init */ + +static int +sds_read_header (SF_PRIVATE *psf, SDS_PRIVATE *psds) +{ unsigned char channel, bitwidth, loop_type, byte ; + unsigned short sample_no, marker ; + unsigned int samp_period, data_length, sustain_loop_start, sustain_loop_end ; + int bytesread, blockcount ; + + /* Set position to start of file to begin reading header. */ + bytesread = psf_binheader_readf (psf, "pE211", 0, &marker, &channel, &byte) ; + + if (marker != 0xF07E || byte != 0x01) + return SFE_SDS_NOT_SDS ; + + bytesread += psf_binheader_readf (psf, "e2", &sample_no) ; + sample_no = SDS_3BYTE_TO_INT_DECODE (sample_no) ; + + psf_log_printf (psf, "Midi Sample Dump Standard (.sds)\nF07E\n" + " Midi Channel : %d\n Sample Number : %d\n", + channel, sample_no) ; + + bytesread += psf_binheader_readf (psf, "e13", &bitwidth, &samp_period) ; + + samp_period = SDS_3BYTE_TO_INT_DECODE (samp_period) ; + + psds->bitwidth = bitwidth ; + + if (psds->bitwidth > 1) + psf_log_printf (psf, " Bit Width : %d\n", psds->bitwidth) ; + else + { psf_log_printf (psf, " Bit Width : %d (should be > 1)\n", psds->bitwidth) ; + return SFE_SDS_BAD_BIT_WIDTH ; + } ; + + if (samp_period > 0) + { psf->sf.samplerate = 1000000000 / samp_period ; + + psf_log_printf (psf, " Sample Period : %d\n" + " Sample Rate : %d\n", + samp_period, psf->sf.samplerate) ; + } + else + { psf->sf.samplerate = 16000 ; + + psf_log_printf (psf, " Sample Period : %d (should be > 0)\n" + " Sample Rate : %d (guessed)\n", + samp_period, psf->sf.samplerate) ; + } ; + + bytesread += psf_binheader_readf (psf, "e3331", &data_length, &sustain_loop_start, &sustain_loop_end, &loop_type) ; + + data_length = SDS_3BYTE_TO_INT_DECODE (data_length) ; + + psf->sf.frames = psds->frames = data_length ; + + sustain_loop_start = SDS_3BYTE_TO_INT_DECODE (sustain_loop_start) ; + sustain_loop_end = SDS_3BYTE_TO_INT_DECODE (sustain_loop_end) ; + + psf_log_printf (psf, " Sustain Loop\n" + " Start : %d\n" + " End : %d\n" + " Loop Type : %d\n", + sustain_loop_start, sustain_loop_end, loop_type) ; + + psf->dataoffset = SDS_DATA_OFFSET ; + psf->datalength = psf->filelength - psf->dataoffset ; + + bytesread += psf_binheader_readf (psf, "1", &byte) ; + if (byte != 0xF7) + psf_log_printf (psf, "bad end : %X\n", byte & 0xFF) ; + + for (blockcount = 0 ; bytesread < psf->filelength ; blockcount++) + { + bytesread += (int) psf_fread (&marker, 1, 2, psf) ; + + if (marker == 0) + break ; + + psf_fseek (psf, SDS_BLOCK_SIZE - 2, SEEK_CUR) ; + bytesread += SDS_BLOCK_SIZE - 2 ; + } ; + + psf_log_printf (psf, "\nBlocks : %d\n", blockcount) ; + psds->total_blocks = blockcount ; + + psds->samplesperblock = SDS_AUDIO_BYTES_PER_BLOCK / ((psds->bitwidth + 6) / 7) ; + psf_log_printf (psf, "Samples/Block : %d\n", psds->samplesperblock) ; + + psf_log_printf (psf, "Frames : %d\n", blockcount * psds->samplesperblock) ; + + /* Always Mono */ + psf->sf.channels = 1 ; + psf->sf.sections = 1 ; + + /* + ** Lie to the user about PCM bit width. Always round up to + ** the next multiple of 8. + */ + switch ((psds->bitwidth + 7) / 8) + { case 1 : + psf->sf.format = SF_FORMAT_SDS | SF_FORMAT_PCM_S8 ; + break ; + + case 2 : + psf->sf.format = SF_FORMAT_SDS | SF_FORMAT_PCM_16 ; + break ; + + case 3 : + psf->sf.format = SF_FORMAT_SDS | SF_FORMAT_PCM_24 ; + break ; + + case 4 : + psf->sf.format = SF_FORMAT_SDS | SF_FORMAT_PCM_32 ; + break ; + + default : + psf_log_printf (psf, "*** Weird byte width (%d)\n", (psds->bitwidth + 7) / 8) ; + return SFE_SDS_BAD_BIT_WIDTH ; + } ; + + psf_fseek (psf, SDS_DATA_OFFSET, SEEK_SET) ; + + return 0 ; +} /* sds_read_header */ + +static int +sds_write_header (SF_PRIVATE *psf, int calc_length) +{ SDS_PRIVATE *psds ; + sf_count_t current ; + int samp_period, data_length, sustain_loop_start, sustain_loop_end ; + unsigned char loop_type = 0 ; + + if ((psds = (SDS_PRIVATE *) psf->codec_data) == NULL) + { psf_log_printf (psf, "*** Bad psf->codec_data ptr.\n") ; + return SFE_INTERNAL ; + } ; + + if (psf->pipeoffset > 0) + return 0 ; + + current = psf_ftell (psf) ; + + if (calc_length) + psf->sf.frames = psds->total_written ; + + if (psds->write_count > 0) + { int current_count = psds->write_count ; + int current_block = psds->write_block ; + + psds->writer (psf, psds) ; + + psf_fseek (psf, -1 * SDS_BLOCK_SIZE, SEEK_CUR) ; + + psds->write_count = current_count ; + psds->write_block = current_block ; + } ; + + /* Reset the current header length to zero. */ + psf->header.ptr [0] = 0 ; + psf->header.indx = 0 ; + + if (psf->is_pipe == SF_FALSE) + psf_fseek (psf, 0, SEEK_SET) ; + + psf_binheader_writef (psf, "E211", BHW2 (0xF07E), BHW1 (0), BHW1 (1)) ; + + switch (SF_CODEC (psf->sf.format)) + { case SF_FORMAT_PCM_S8 : + psds->bitwidth = 8 ; + break ; + case SF_FORMAT_PCM_16 : + psds->bitwidth = 16 ; + break ; + case SF_FORMAT_PCM_24 : + psds->bitwidth = 24 ; + break ; + default: + return SFE_SDS_BAD_BIT_WIDTH ; + } ; + + samp_period = SDS_INT_TO_3BYTE_ENCODE (1000000000 / psf->sf.samplerate) ; + + psf_binheader_writef (psf, "e213", BHW2 (0), BHW1 (psds->bitwidth), BHW3 (samp_period)) ; + + data_length = SDS_INT_TO_3BYTE_ENCODE (psds->total_written) ; + sustain_loop_start = SDS_INT_TO_3BYTE_ENCODE (0) ; + sustain_loop_end = SDS_INT_TO_3BYTE_ENCODE (0) ; + + psf_binheader_writef (psf, "e33311", BHW3 (data_length), BHW3 (sustain_loop_start), BHW3 (sustain_loop_end), BHW1 (loop_type), BHW1 (0xF7)) ; + + /* Header construction complete so write it out. */ + psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ; + + if (psf->error) + return psf->error ; + + psf->dataoffset = psf->header.indx ; + psf->datalength = psds->write_block * SDS_BLOCK_SIZE ; + + if (current > 0) + psf_fseek (psf, current, SEEK_SET) ; + + return psf->error ; +} /* sds_write_header */ + + +/*------------------------------------------------------------------------------ +*/ + +static int +sds_2byte_read (SF_PRIVATE *psf, SDS_PRIVATE *psds) +{ unsigned char *ucptr, checksum ; + unsigned int sample ; + int k ; + + psds->read_block ++ ; + psds->read_count = 0 ; + + if (psds->read_block * psds->samplesperblock > psds->frames) + { memset (psds->read_samples, 0, psds->samplesperblock * sizeof (int)) ; + return 1 ; + } ; + + if ((k = (int) psf_fread (psds->read_data, 1, SDS_BLOCK_SIZE, psf)) != SDS_BLOCK_SIZE) + psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, SDS_BLOCK_SIZE) ; + + if (psds->read_data [0] != 0xF0) + { printf ("Error A : %02X\n", psds->read_data [0] & 0xFF) ; + } ; + + checksum = psds->read_data [1] ; + if (checksum != 0x7E) + { printf ("Error 1 : %02X\n", checksum & 0xFF) ; + } + + for (k = 2 ; k <= SDS_BLOCK_SIZE - 3 ; k ++) + checksum ^= psds->read_data [k] ; + + checksum &= 0x7F ; + + if (checksum != psds->read_data [SDS_BLOCK_SIZE - 2]) + { psf_log_printf (psf, "Block %d : checksum is %02X should be %02X\n", psds->read_data [4], checksum, psds->read_data [SDS_BLOCK_SIZE - 2]) ; + } ; + + ucptr = psds->read_data + 5 ; + for (k = 0 ; k < 120 ; k += 2) + { sample = arith_shift_left (ucptr [k], 25) + arith_shift_left (ucptr [k + 1], 18) ; + psds->read_samples [k / 2] = (int) (sample - 0x80000000) ; + } ; + + return 1 ; +} /* sds_2byte_read */ + +static int +sds_3byte_read (SF_PRIVATE *psf, SDS_PRIVATE *psds) +{ unsigned char *ucptr, checksum ; + unsigned int sample ; + int k ; + + psds->read_block ++ ; + psds->read_count = 0 ; + + if (psds->read_block * psds->samplesperblock > psds->frames) + { memset (psds->read_samples, 0, psds->samplesperblock * sizeof (int)) ; + return 1 ; + } ; + + if ((k = (int) psf_fread (psds->read_data, 1, SDS_BLOCK_SIZE, psf)) != SDS_BLOCK_SIZE) + psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, SDS_BLOCK_SIZE) ; + + if (psds->read_data [0] != 0xF0) + { printf ("Error A : %02X\n", psds->read_data [0] & 0xFF) ; + } ; + + checksum = psds->read_data [1] ; + if (checksum != 0x7E) + { printf ("Error 1 : %02X\n", checksum & 0xFF) ; + } + + for (k = 2 ; k <= SDS_BLOCK_SIZE - 3 ; k ++) + checksum ^= psds->read_data [k] ; + + checksum &= 0x7F ; + + if (checksum != psds->read_data [SDS_BLOCK_SIZE - 2]) + { psf_log_printf (psf, "Block %d : checksum is %02X should be %02X\n", psds->read_data [4], checksum, psds->read_data [SDS_BLOCK_SIZE - 2]) ; + } ; + + ucptr = psds->read_data + 5 ; + for (k = 0 ; k < 120 ; k += 3) + { sample = (((uint32_t) ucptr [k]) << 25) + (ucptr [k + 1] << 18) + (ucptr [k + 2] << 11) ; + psds->read_samples [k / 3] = (int) (sample - 0x80000000) ; + } ; + + return 1 ; +} /* sds_3byte_read */ + +static int +sds_4byte_read (SF_PRIVATE *psf, SDS_PRIVATE *psds) +{ unsigned char *ucptr, checksum ; + uint32_t sample ; + int k ; + + psds->read_block ++ ; + psds->read_count = 0 ; + + if (psds->read_block * psds->samplesperblock > psds->frames) + { memset (psds->read_samples, 0, psds->samplesperblock * sizeof (int)) ; + return 1 ; + } ; + + if ((k = (int) psf_fread (psds->read_data, 1, SDS_BLOCK_SIZE, psf)) != SDS_BLOCK_SIZE) + psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, SDS_BLOCK_SIZE) ; + + if (psds->read_data [0] != 0xF0) + { printf ("Error A : %02X\n", psds->read_data [0] & 0xFF) ; + } ; + + checksum = psds->read_data [1] ; + if (checksum != 0x7E) + { printf ("Error 1 : %02X\n", checksum & 0xFF) ; + } + + for (k = 2 ; k <= SDS_BLOCK_SIZE - 3 ; k ++) + checksum ^= psds->read_data [k] ; + + checksum &= 0x7F ; + + if (checksum != psds->read_data [SDS_BLOCK_SIZE - 2]) + { psf_log_printf (psf, "Block %d : checksum is %02X should be %02X\n", psds->read_data [4], checksum, psds->read_data [SDS_BLOCK_SIZE - 2]) ; + } ; + + ucptr = psds->read_data + 5 ; + for (k = 0 ; k < 120 ; k += 4) + { sample = (((uint32_t) ucptr [k]) << 25) + (ucptr [k + 1] << 18) + (ucptr [k + 2] << 11) + (ucptr [k + 3] << 4) ; + psds->read_samples [k / 4] = (int) (sample - 0x80000000) ; + } ; + + return 1 ; +} /* sds_4byte_read */ + + +static sf_count_t +sds_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + SDS_PRIVATE *psds ; + int *iptr ; + int k, bufferlen, readcount, count ; + sf_count_t total = 0 ; + + if (psf->codec_data == NULL) + return 0 ; + psds = (SDS_PRIVATE*) psf->codec_data ; + + iptr = ubuf.ibuf ; + bufferlen = ARRAY_LEN (ubuf.ibuf) ; + while (len > 0) + { readcount = (len >= bufferlen) ? bufferlen : (int) len ; + count = sds_read (psf, psds, iptr, readcount) ; + for (k = 0 ; k < readcount ; k++) + ptr [total + k] = iptr [k] >> 16 ; + total += count ; + len -= readcount ; + } ; + + return total ; +} /* sds_read_s */ + +static sf_count_t +sds_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) +{ SDS_PRIVATE *psds ; + int total ; + + if (psf->codec_data == NULL) + return 0 ; + psds = (SDS_PRIVATE*) psf->codec_data ; + + total = sds_read (psf, psds, ptr, len) ; + + return total ; +} /* sds_read_i */ + +static sf_count_t +sds_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + SDS_PRIVATE *psds ; + int *iptr ; + int k, bufferlen, readcount, count ; + sf_count_t total = 0 ; + float normfact ; + + if (psf->codec_data == NULL) + return 0 ; + psds = (SDS_PRIVATE*) psf->codec_data ; + + if (psf->norm_float == SF_TRUE) + normfact = 1.0 / 0x80000000 ; + else + normfact = 1.0 / (1 << psds->bitwidth) ; + + iptr = ubuf.ibuf ; + bufferlen = ARRAY_LEN (ubuf.ibuf) ; + while (len > 0) + { readcount = (len >= bufferlen) ? bufferlen : (int) len ; + count = sds_read (psf, psds, iptr, readcount) ; + for (k = 0 ; k < readcount ; k++) + ptr [total + k] = normfact * iptr [k] ; + total += count ; + len -= readcount ; + } ; + + return total ; +} /* sds_read_f */ + +static sf_count_t +sds_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + SDS_PRIVATE *psds ; + int *iptr ; + int k, bufferlen, readcount, count ; + sf_count_t total = 0 ; + double normfact ; + + if (psf->codec_data == NULL) + return 0 ; + psds = (SDS_PRIVATE*) psf->codec_data ; + + if (psf->norm_double == SF_TRUE) + normfact = 1.0 / 0x80000000 ; + else + normfact = 1.0 / (1 << psds->bitwidth) ; + + iptr = ubuf.ibuf ; + bufferlen = ARRAY_LEN (ubuf.ibuf) ; + while (len > 0) + { readcount = (len >= bufferlen) ? bufferlen : (int) len ; + count = sds_read (psf, psds, iptr, readcount) ; + for (k = 0 ; k < readcount ; k++) + ptr [total + k] = normfact * iptr [k] ; + total += count ; + len -= readcount ; + } ; + + return total ; +} /* sds_read_d */ + +static int +sds_read (SF_PRIVATE *psf, SDS_PRIVATE *psds, int *ptr, int len) +{ int count, total = 0 ; + + while (total < len) + { if (psds->read_block * psds->samplesperblock >= psds->frames) + { memset (&(ptr [total]), 0, (len - total) * sizeof (int)) ; + return total ; + } ; + + if (psds->read_count >= psds->samplesperblock) + psds->reader (psf, psds) ; + + count = (psds->samplesperblock - psds->read_count) ; + count = (len - total > count) ? count : len - total ; + + memcpy (&(ptr [total]), &(psds->read_samples [psds->read_count]), count * sizeof (int)) ; + total += count ; + psds->read_count += count ; + } ; + + return total ; +} /* sds_read */ + +/*============================================================================== +*/ + +static sf_count_t +sds_seek (SF_PRIVATE *psf, int mode, sf_count_t seek_from_start) +{ SDS_PRIVATE *psds ; + sf_count_t file_offset ; + int newblock, newsample ; + + if ((psds = psf->codec_data) == NULL) + { psf->error = SFE_INTERNAL ; + return PSF_SEEK_ERROR ; + } ; + + if (psf->datalength < 0 || psf->dataoffset < 0) + { psf->error = SFE_BAD_SEEK ; + return PSF_SEEK_ERROR ; + } ; + + if (seek_from_start < 0 || seek_from_start > psf->sf.frames) + { psf->error = SFE_BAD_SEEK ; + return PSF_SEEK_ERROR ; + } ; + + if (mode == SFM_READ && psds->write_count > 0) + psds->writer (psf, psds) ; + + newblock = seek_from_start / psds->samplesperblock ; + newsample = seek_from_start % psds->samplesperblock ; + + switch (mode) + { case SFM_READ : + if (newblock > psds->total_blocks) + { psf->error = SFE_BAD_SEEK ; + return PSF_SEEK_ERROR ; + } ; + + file_offset = psf->dataoffset + newblock * SDS_BLOCK_SIZE ; + + if (psf_fseek (psf, file_offset, SEEK_SET) != file_offset) + { psf->error = SFE_SEEK_FAILED ; + return PSF_SEEK_ERROR ; + } ; + + psds->read_block = newblock ; + psds->reader (psf, psds) ; + psds->read_count = newsample ; + break ; + + case SFM_WRITE : + if (newblock > psds->total_blocks) + { psf->error = SFE_BAD_SEEK ; + return PSF_SEEK_ERROR ; + } ; + + file_offset = psf->dataoffset + newblock * SDS_BLOCK_SIZE ; + + if (psf_fseek (psf, file_offset, SEEK_SET) != file_offset) + { psf->error = SFE_SEEK_FAILED ; + return PSF_SEEK_ERROR ; + } ; + + psds->write_block = newblock ; + psds->reader (psf, psds) ; + psds->write_count = newsample ; + break ; + + default : + psf->error = SFE_BAD_SEEK ; + return PSF_SEEK_ERROR ; + break ; + } ; + + return seek_from_start ; +} /* sds_seek */ + +static int +sds_byterate (SF_PRIVATE * psf) +{ + if (psf->file.mode == SFM_READ) + return (psf->datalength * psf->sf.samplerate) / psf->sf.frames ; + + return -1 ; +} /* sds_byterate */ + +/*============================================================================== +*/ + +static int +sds_2byte_write (SF_PRIVATE *psf, SDS_PRIVATE *psds) +{ unsigned char *ucptr, checksum ; + unsigned int sample ; + int k ; + + psds->write_data [0] = 0xF0 ; + psds->write_data [1] = 0x7E ; + psds->write_data [2] = 0 ; /* Channel number */ + psds->write_data [3] = 2 ; + psds->write_data [4] = psds->write_block & 0x7F ; /* Packet number */ + + ucptr = psds->write_data + 5 ; + for (k = 0 ; k < 120 ; k += 2) + { sample = psds->write_samples [k / 2] ; + sample += 0x80000000 ; + ucptr [k] = (sample >> 25) & 0x7F ; + ucptr [k + 1] = (sample >> 18) & 0x7F ; + } ; + + checksum = psds->write_data [1] ; + for (k = 2 ; k <= SDS_BLOCK_SIZE - 3 ; k ++) + checksum ^= psds->write_data [k] ; + checksum &= 0x7F ; + + psds->write_data [SDS_BLOCK_SIZE - 2] = checksum ; + psds->write_data [SDS_BLOCK_SIZE - 1] = 0xF7 ; + + if ((k = (int) psf_fwrite (psds->write_data, 1, SDS_BLOCK_SIZE, psf)) != SDS_BLOCK_SIZE) + psf_log_printf (psf, "*** Warning : psf_fwrite (%d != %d).\n", k, SDS_BLOCK_SIZE) ; + + psds->write_block ++ ; + psds->write_count = 0 ; + + if (psds->write_block > psds->total_blocks) + psds->total_blocks = psds->write_block ; + psds->frames = psds->total_blocks * psds->samplesperblock ; + + return 1 ; +} /* sds_2byte_write */ + +static int +sds_3byte_write (SF_PRIVATE *psf, SDS_PRIVATE *psds) +{ unsigned char *ucptr, checksum ; + unsigned int sample ; + int k ; + + psds->write_data [0] = 0xF0 ; + psds->write_data [1] = 0x7E ; + psds->write_data [2] = 0 ; /* Channel number */ + psds->write_data [3] = 2 ; + psds->write_data [4] = psds->write_block & 0x7F ; /* Packet number */ + + ucptr = psds->write_data + 5 ; + for (k = 0 ; k < 120 ; k += 3) + { sample = psds->write_samples [k / 3] ; + sample += 0x80000000 ; + ucptr [k] = (sample >> 25) & 0x7F ; + ucptr [k + 1] = (sample >> 18) & 0x7F ; + ucptr [k + 2] = (sample >> 11) & 0x7F ; + } ; + + checksum = psds->write_data [1] ; + for (k = 2 ; k <= SDS_BLOCK_SIZE - 3 ; k ++) + checksum ^= psds->write_data [k] ; + checksum &= 0x7F ; + + psds->write_data [SDS_BLOCK_SIZE - 2] = checksum ; + psds->write_data [SDS_BLOCK_SIZE - 1] = 0xF7 ; + + if ((k = (int) psf_fwrite (psds->write_data, 1, SDS_BLOCK_SIZE, psf)) != SDS_BLOCK_SIZE) + psf_log_printf (psf, "*** Warning : psf_fwrite (%d != %d).\n", k, SDS_BLOCK_SIZE) ; + + psds->write_block ++ ; + psds->write_count = 0 ; + + if (psds->write_block > psds->total_blocks) + psds->total_blocks = psds->write_block ; + psds->frames = psds->total_blocks * psds->samplesperblock ; + + return 1 ; +} /* sds_3byte_write */ + +static int +sds_4byte_write (SF_PRIVATE *psf, SDS_PRIVATE *psds) +{ unsigned char *ucptr, checksum ; + unsigned int sample ; + int k ; + + psds->write_data [0] = 0xF0 ; + psds->write_data [1] = 0x7E ; + psds->write_data [2] = 0 ; /* Channel number */ + psds->write_data [3] = 2 ; + psds->write_data [4] = psds->write_block & 0x7F ; /* Packet number */ + + ucptr = psds->write_data + 5 ; + for (k = 0 ; k < 120 ; k += 4) + { sample = psds->write_samples [k / 4] ; + sample += 0x80000000 ; + ucptr [k] = (sample >> 25) & 0x7F ; + ucptr [k + 1] = (sample >> 18) & 0x7F ; + ucptr [k + 2] = (sample >> 11) & 0x7F ; + ucptr [k + 3] = (sample >> 4) & 0x7F ; + } ; + + checksum = psds->write_data [1] ; + for (k = 2 ; k <= SDS_BLOCK_SIZE - 3 ; k ++) + checksum ^= psds->write_data [k] ; + checksum &= 0x7F ; + + psds->write_data [SDS_BLOCK_SIZE - 2] = checksum ; + psds->write_data [SDS_BLOCK_SIZE - 1] = 0xF7 ; + + if ((k = (int) psf_fwrite (psds->write_data, 1, SDS_BLOCK_SIZE, psf)) != SDS_BLOCK_SIZE) + psf_log_printf (psf, "*** Warning : psf_fwrite (%d != %d).\n", k, SDS_BLOCK_SIZE) ; + + psds->write_block ++ ; + psds->write_count = 0 ; + + if (psds->write_block > psds->total_blocks) + psds->total_blocks = psds->write_block ; + psds->frames = psds->total_blocks * psds->samplesperblock ; + + return 1 ; +} /* sds_4byte_write */ + +static sf_count_t +sds_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + SDS_PRIVATE *psds ; + int *iptr ; + int k, bufferlen, writecount, count ; + sf_count_t total = 0 ; + + if (psf->codec_data == NULL) + return 0 ; + psds = (SDS_PRIVATE*) psf->codec_data ; + psds->total_written += len ; + + iptr = ubuf.ibuf ; + bufferlen = ARRAY_LEN (ubuf.ibuf) ; + while (len > 0) + { writecount = (len >= bufferlen) ? bufferlen : (int) len ; + for (k = 0 ; k < writecount ; k++) + iptr [k] = arith_shift_left (ptr [total + k], 16) ; + count = sds_write (psf, psds, iptr, writecount) ; + total += count ; + len -= writecount ; + } ; + + return total ; +} /* sds_write_s */ + +static sf_count_t +sds_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) +{ SDS_PRIVATE *psds ; + int total ; + + if (psf->codec_data == NULL) + return 0 ; + psds = (SDS_PRIVATE*) psf->codec_data ; + psds->total_written += len ; + + total = sds_write (psf, psds, ptr, len) ; + + return total ; +} /* sds_write_i */ + +static sf_count_t +sds_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + SDS_PRIVATE *psds ; + int *iptr ; + int k, bufferlen, writecount, count ; + sf_count_t total = 0 ; + float normfact ; + + if (psf->codec_data == NULL) + return 0 ; + psds = (SDS_PRIVATE*) psf->codec_data ; + psds->total_written += len ; + + if (psf->norm_float == SF_TRUE) + normfact = 1.0 * 0x80000000 ; + else + normfact = 1.0 * (1 << psds->bitwidth) ; + + iptr = ubuf.ibuf ; + bufferlen = ARRAY_LEN (ubuf.ibuf) ; + while (len > 0) + { writecount = (len >= bufferlen) ? bufferlen : (int) len ; + for (k = 0 ; k < writecount ; k++) + iptr [k] = normfact * ptr [total + k] ; + count = sds_write (psf, psds, iptr, writecount) ; + total += count ; + len -= writecount ; + } ; + + return total ; +} /* sds_write_f */ + +static sf_count_t +sds_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + SDS_PRIVATE *psds ; + int *iptr ; + int k, bufferlen, writecount, count ; + sf_count_t total = 0 ; + double normfact ; + + if (psf->codec_data == NULL) + return 0 ; + psds = (SDS_PRIVATE*) psf->codec_data ; + psds->total_written += len ; + + if (psf->norm_double == SF_TRUE) + normfact = 1.0 * 0x80000000 ; + else + normfact = 1.0 * (1 << psds->bitwidth) ; + + iptr = ubuf.ibuf ; + bufferlen = ARRAY_LEN (ubuf.ibuf) ; + while (len > 0) + { writecount = (len >= bufferlen) ? bufferlen : (int) len ; + for (k = 0 ; k < writecount ; k++) + iptr [k] = normfact * ptr [total + k] ; + count = sds_write (psf, psds, iptr, writecount) ; + total += count ; + len -= writecount ; + } ; + + return total ; +} /* sds_write_d */ + +static int +sds_write (SF_PRIVATE *psf, SDS_PRIVATE *psds, const int *ptr, int len) +{ int count, total = 0 ; + + while (total < len) + { count = psds->samplesperblock - psds->write_count ; + if (count > len - total) + count = len - total ; + + memcpy (&(psds->write_samples [psds->write_count]), &(ptr [total]), count * sizeof (int)) ; + total += count ; + psds->write_count += count ; + + if (psds->write_count >= psds->samplesperblock) + psds->writer (psf, psds) ; + } ; + + return total ; +} /* sds_write */ + diff --git a/extern/libsndfile-modified/src/sf_unistd.h b/extern/libsndfile-modified/src/sf_unistd.h new file mode 100644 index 000000000..698eff21c --- /dev/null +++ b/extern/libsndfile-modified/src/sf_unistd.h @@ -0,0 +1,112 @@ +/* +** Copyright (C) 2002-2017 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/* Microsoft declares some 'unistd.h' functions in 'io.h'. */ + +#include +#ifdef HAVE_IO_H +#include +#endif + +/* Some defines that microsoft 'forgot' to implement. */ + +#ifndef R_OK +#define R_OK 4 /* Test for read permission. */ +#endif + +#ifndef W_OK +#define W_OK 2 /* Test for write permission. */ +#endif + +#ifndef X_OK +#ifdef _WIN32 +#define X_OK 0 +#else +#define X_OK 1 /* execute permission - unsupported in windows*/ +#endif +#endif + +#ifndef F_OK +#define F_OK 0 /* Test for existence. */ +#endif + +#ifndef S_IRWXU +#define S_IRWXU 0000700 /* rwx, owner */ +#endif + +#ifndef S_IRUSR +#define S_IRUSR 0000400 /* read permission, owner */ +#endif + +#ifndef S_IWUSR +#define S_IWUSR 0000200 /* write permission, owner */ +#endif + +#ifndef S_IXUSR +#define S_IXUSR 0000100 /* execute/search permission, owner */ +#endif + +/* Windows (except MinGW) doesn't have group permissions so set all these to zero. */ +#ifndef S_IRWXG +#define S_IRWXG 0 /* rwx, group */ +#endif + +#ifndef S_IRGRP +#define S_IRGRP 0 /* read permission, group */ +#endif + +#ifndef S_IWGRP +#define S_IWGRP 0 /* write permission, grougroup */ +#endif + +#ifndef S_IXGRP +#define S_IXGRP 0 /* execute/search permission, group */ +#endif + +/* Windows (except MinGW) doesn't have others permissions so set all these to zero. */ +#ifndef S_IRWXO +#define S_IRWXO 0 /* rwx, other */ +#endif + +#ifndef S_IROTH +#define S_IROTH 0 /* read permission, other */ +#endif + +#ifndef S_IWOTH +#define S_IWOTH 0 /* write permission, other */ +#endif + +#ifndef S_IXOTH +#define S_IXOTH 0 /* execute/search permission, other */ +#endif + +#ifndef S_ISFIFO +#define S_ISFIFO(mode) (((mode) & _S_IFMT) == _S_IFIFO) +#endif + +#ifndef S_ISREG +#define S_ISREG(mode) (((mode) & _S_IFREG) == _S_IFREG) +#endif + +/* +** Don't know if these are still needed. +** +** #define _IFMT _S_IFMT +** #define _IFREG _S_IFREG +*/ + diff --git a/extern/libsndfile-modified/src/sfconfig.h b/extern/libsndfile-modified/src/sfconfig.h new file mode 100644 index 000000000..de2e56d62 --- /dev/null +++ b/extern/libsndfile-modified/src/sfconfig.h @@ -0,0 +1,131 @@ +/* +** Copyright (C) 2005-2017 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/* +** Autoconf leaves many config parameters undefined. +** Here we change then from being undefined to defining them to 0. +** This allows things like: +** +** #if HAVE_CONFIG_PARAM +** +** and +** +** if (HAVE_CONFIG_PARAM) +** do_something () ; +*/ + +#ifndef SFCONFIG_H +#define SFCONFIG_H + +/* Include the Autoconf generated file. */ +#include "config.h" + +/* Now fiddle the values. */ + +#ifndef HAVE_ALSA_ASOUNDLIB_H +#define HAVE_ALSA_ASOUNDLIB_H 0 +#endif + +#ifndef HAVE_BYTESWAP_H +#define HAVE_BYTESWAP_H 0 +#endif + +#ifndef HAVE_DECL_S_IRGRP +#define HAVE_DECL_S_IRGRP 0 +#endif + +#ifndef HAVE_ENDIAN_H +#define HAVE_ENDIAN_H 0 +#endif + +#ifndef HAVE_FSTAT64 +#define HAVE_FSTAT64 0 +#endif + +#ifndef HAVE_FSYNC +#define HAVE_FSYNC 0 +#endif + +#ifndef HAVE_LOCALE_H +#define HAVE_LOCALE_H 0 +#endif + +#ifndef HAVE_LRINT +#define HAVE_LRINT 0 +#endif + +#ifndef HAVE_LRINTF +#define HAVE_LRINTF 0 +#endif + +#ifndef HAVE_MMAP +#define HAVE_MMAP 0 +#endif + +#ifndef HAVE_SETLOCALE +#define HAVE_SETLOCALE 0 +#endif + +#ifndef HAVE_SQLITE3 +#define HAVE_SQLITE3 0 +#endif + +#ifndef HAVE_STDINT_H +#define HAVE_STDINT_H 0 +#endif + +#ifndef HAVE_SYS_WAIT_H +#define HAVE_SYS_WAIT_H 0 +#endif + +#ifndef HAVE_SYS_TIME_H +#define HAVE_SYS_TIME_H 0 +#endif + +#ifndef HAVE_UNISTD_H +#define HAVE_UNISTD_H 0 +#endif + +#ifndef HAVE_PIPE +#define HAVE_PIPE 0 +#endif + +#ifndef HAVE_WAITPID +#define HAVE_WAITPID 0 +#endif + +#ifndef HAVE_X86INTRIN_H +#define HAVE_X86INTRIN_H 0 +#endif + +#if (defined __x86_64__) || (defined _M_X64) +#define CPU_IS_X86_64 1 /* Define both for x86_64 */ +#define CPU_IS_X86 1 +#elif defined (__i486__) || defined (__i586__) || defined (__i686__) || defined (_M_IX86) +#define CPU_IS_X86 1 +#define CPU_IS_X86_64 0 +#else +#define CPU_IS_X86 0 +#define CPU_IS_X86_64 0 +#endif + +#if (defined (__SSE2__) || defined (_M_AMD64) || (defined (_M_IX86_FP) && (_M_IX86_FP >= 2)) && HAVE_IMMINTRIN_H) +#define USE_SSE2 +#endif + +#endif diff --git a/extern/libsndfile-modified/src/sfendian.h b/extern/libsndfile-modified/src/sfendian.h new file mode 100644 index 000000000..ab02742b2 --- /dev/null +++ b/extern/libsndfile-modified/src/sfendian.h @@ -0,0 +1,360 @@ +/* +** Copyright (C) 1999-2018 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef SFENDIAN_INCLUDED +#define SFENDIAN_INCLUDED + +#include "sfconfig.h" + +#include +#include + +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif + +#if HAVE_BYTESWAP_H /* Linux, any CPU */ +#include + +#define ENDSWAP_16(x) (bswap_16 (x)) +#define ENDSWAP_32(x) (bswap_32 (x)) +#define ENDSWAP_64(x) (bswap_64 (x)) + +#elif __has_builtin(__builtin_bswap16) && __has_builtin(__builtin_bswap32) && __has_builtin(__builtin_bswap64) + +#define ENDSWAP_16(x) ((int16_t) __builtin_bswap16 ((uint16_t) x)) +#define ENDSWAP_32(x) ((int32_t) __builtin_bswap32 ((uint32_t) x)) +#define ENDSWAP_64(x) ((int64_t) __builtin_bswap64 ((uint64_t) x)) + +#elif COMPILER_IS_GCC + +#if CPU_IS_X86 + +static inline int16_t +ENDSWAP_16X (int16_t x) +{ int16_t y ; + __asm__ ("rorw $8, %w0" : "=r" (y) : "0" (x) : "cc") ; + return y ; +} /* ENDSWAP_16 */ + +static inline int32_t +ENDSWAP_32X (int32_t x) +{ int32_t y ; + __asm__ ("bswap %0" : "=r" (y) : "0" (x)) ; + return y ; +} /* ENDSWAP_32 */ + +#define ENDSWAP_16 ENDSWAP_16X +#define ENDSWAP_32 ENDSWAP_32X + +#endif + +#if CPU_IS_X86_64 + +static inline int64_t +ENDSWAP_64X (int64_t x) +{ int64_t y ; + __asm__ ("bswap %q0" : "=r" (y) : "0" (x)) ; + return y ; +} /* ENDSWAP_64X */ + +#define ENDSWAP_64 ENDSWAP_64X + +#endif + +#elif defined _MSC_VER +#include + +#define ENDSWAP_16(x) (_byteswap_ushort (x)) +#define ENDSWAP_32(x) (_byteswap_ulong (x)) +#define ENDSWAP_64(x) (_byteswap_uint64 (x)) + +#endif + +#ifndef ENDSWAP_16 +#define ENDSWAP_16(x) ((((x) >> 8) & 0xFF) + (((x) & 0xFF) << 8)) +#endif + +#ifndef ENDSWAP_32 +#define ENDSWAP_32(x) ((((x) >> 24) & 0xFF) + (((x) >> 8) & 0xFF00) + (((x) & 0xFF00) << 8) + (((x) & 0xFF) << 24)) +#endif + +#ifndef ENDSWAP_64 +static inline uint64_t +ENDSWAP_64 (uint64_t x) +{ union + { uint32_t parts [2] ; + uint64_t whole ; + } u ; + uint32_t temp ; + + u.whole = x ; + temp = u.parts [0] ; + u.parts [0] = ENDSWAP_32 (u.parts [1]) ; + u.parts [1] = ENDSWAP_32 (temp) ; + return u.whole ; +} +#endif + +/* +** Many file types (ie WAV, AIFF) use sets of four consecutive bytes as a +** marker indicating different sections of the file. +** The following MAKE_MARKER macro allows th creation of integer constants +** for these markers. +*/ + +#if (CPU_IS_LITTLE_ENDIAN == 1) + #define MAKE_MARKER(a, b, c, d) ((uint32_t) ((a) | ((b) << 8) | ((c) << 16) | (((uint32_t) (d)) << 24))) +#elif (CPU_IS_BIG_ENDIAN == 1) + #define MAKE_MARKER(a, b, c, d) ((uint32_t) ((((uint32_t) (a)) << 24) | ((b) << 16) | ((c) << 8) | (d))) +#else + #error "Target CPU endian-ness unknown. May need to hand edit src/sfconfig.h" +#endif + +/* +** Macros to handle reading of data of a specific endian-ness into host endian +** shorts and ints. The single input is an unsigned char* pointer to the start +** of the object. There are two versions of each macro as we need to deal with +** both big and little endian CPUs. +*/ + +#if (CPU_IS_LITTLE_ENDIAN == 1) + #define LE2H_16(x) (x) + #define LE2H_32(x) (x) + + #define BE2H_16(x) ENDSWAP_16 (x) + #define BE2H_32(x) ENDSWAP_32 (x) + #define BE2H_64(x) ENDSWAP_64 (x) + + #define H2BE_16(x) ENDSWAP_16 (x) + #define H2BE_32(x) ENDSWAP_32 (x) + + #define H2LE_16(x) (x) + #define H2LE_32(x) (x) + +#elif (CPU_IS_BIG_ENDIAN == 1) + #define LE2H_16(x) ENDSWAP_16 (x) + #define LE2H_32(x) ENDSWAP_32 (x) + + #define BE2H_16(x) (x) + #define BE2H_32(x) (x) + #define BE2H_64(x) (x) + + #define H2BE_16(x) (x) + #define H2BE_32(x) (x) + + #define H2LE_16(x) ENDSWAP_16 (x) + #define H2LE_32(x) ENDSWAP_32 (x) + +#else + #error "Target CPU endian-ness unknown. May need to hand edit src/sfconfig.h" +#endif + +#define LE2H_32_PTR(x) (((x) [0]) + ((x) [1] << 8) + ((x) [2] << 16) + ((x) [3] << 24)) + +#define LET2H_16_PTR(x) ((x) [1] + ((x) [2] << 8)) +#define LET2H_32_PTR(x) (((x) [0] << 8) + ((x) [1] << 16) + ((x) [2] << 24)) + +#define BET2H_16_PTR(x) (((x) [0] << 8) + (x) [1]) +#define BET2H_32_PTR(x) (((x) [0] << 24) + ((x) [1] << 16) + ((x) [2] << 8)) + +static inline void +psf_put_be64 (uint8_t *ptr, int offset, int64_t value) +{ + ptr [offset] = (uint8_t) (value >> 56) ; + ptr [offset + 1] = (uint8_t) (value >> 48) ; + ptr [offset + 2] = (uint8_t) (value >> 40) ; + ptr [offset + 3] = (uint8_t) (value >> 32) ; + ptr [offset + 4] = (uint8_t) (value >> 24) ; + ptr [offset + 5] = (uint8_t) (value >> 16) ; + ptr [offset + 6] = (uint8_t) (value >> 8) ; + ptr [offset + 7] = (uint8_t) value ; +} /* psf_put_be64 */ + +static inline void +psf_put_be32 (uint8_t *ptr, int offset, int32_t value) +{ + ptr [offset] = (uint8_t) (value >> 24) ; + ptr [offset + 1] = (uint8_t) (value >> 16) ; + ptr [offset + 2] = (uint8_t) (value >> 8) ; + ptr [offset + 3] = (uint8_t) value ; +} /* psf_put_be32 */ + +static inline void +psf_put_be16 (uint8_t *ptr, int offset, int16_t value) +{ + ptr [offset] = (uint8_t) (value >> 8) ; + ptr [offset + 1] = (uint8_t) value ; +} /* psf_put_be16 */ + +static inline int64_t +psf_get_be64 (const uint8_t *ptr, int offset) +{ int64_t value ; + + value = (int64_t) ((uint64_t) ptr [offset] << 24) ; + value += (int64_t) ((uint64_t) ptr [offset + 1] << 16) ; + value += (int64_t) ((uint64_t) ptr [offset + 2] << 8) ; + value += ptr [offset + 3] ; + + value = (int64_t) (((uint64_t) value) << 32) ; + + value += (int64_t) ((uint64_t) ptr [offset + 4] << 24) ; + value += (int64_t) ((uint64_t) ptr [offset + 5] << 16) ; + value += (int64_t) ((uint64_t) ptr [offset + 6] << 8) ; + value += ptr [offset + 7] ; + return value ; +} /* psf_get_be64 */ + +static inline int64_t +psf_get_le64 (const uint8_t *ptr, int offset) +{ int64_t value = (int64_t) ((uint64_t) ptr [offset + 7] << 24) ; + value += (int64_t) ((uint64_t) ptr [offset + 6] << 16) ; + value += (int64_t) ((uint64_t) ptr [offset + 5] << 8) ; + value += ptr [offset + 4] ; + + value = (int64_t) (((uint64_t) value) << 32) ; + + value += (int64_t) ((uint64_t) ptr [offset + 3] << 24) ; + value += (int64_t) ((uint64_t) ptr [offset + 2] << 16) ; + value += (int64_t) ((uint64_t) ptr [offset + 1] << 8) ; + value += ptr [offset] ; + return value ; +} /* psf_get_le64 */ + +static inline int32_t +psf_get_be32 (const uint8_t *ptr, int offset) +{ int32_t value = ((uint32_t) ptr [offset]) << 24 ; + value += ptr [offset + 1] << 16 ; + value += ptr [offset + 2] << 8 ; + value += ptr [offset + 3] ; + return value ; +} /* psf_get_be32 */ + +static inline int32_t +psf_get_le32 (const uint8_t *ptr, int offset) +{ int32_t value = ((uint32_t) ptr [offset + 3]) << 24 ; + value += ptr [offset + 2] << 16 ; + value += ptr [offset + 1] << 8 ; + value += ptr [offset] ; + return value ; +} /* psf_get_le32 */ + +static inline int32_t +psf_get_be24 (const uint8_t *ptr, int offset) +{ int32_t value = ((uint32_t) ptr [offset]) << 24 ; + value += ptr [offset + 1] << 16 ; + value += ptr [offset + 2] << 8 ; + return value ; +} /* psf_get_be24 */ + +static inline int32_t +psf_get_le24 (const uint8_t *ptr, int offset) +{ int32_t value = ((uint32_t) ptr [offset + 2]) << 24 ; + value += ptr [offset + 1] << 16 ; + value += ptr [offset] << 8 ; + return value ; +} /* psf_get_le24 */ + +static inline int16_t +psf_get_be16 (const uint8_t *ptr, int offset) +{ return (int16_t) (ptr [offset] << 8) + ptr [offset + 1] ; +} /* psf_get_be16 */ + +/*----------------------------------------------------------------------------------------------- +** Generic functions for performing endian swapping on integer arrays. +*/ + +static inline void +endswap_short_array (short *ptr, int len) +{ + for (int i = 0 ; i < len ; i++) + { short temp = ptr [i] ; + ptr [i] = ENDSWAP_16 (temp) ; + } ; +} /* endswap_short_array */ + +static inline void +endswap_short_copy (short *dest, const short *src, int len) +{ + for (int i = 0 ; i < len ; i++) + { dest [i] = ENDSWAP_16 (src [i]) ; + } ; +} /* endswap_short_copy */ + +static inline void +endswap_int_array (int *ptr, int len) +{ + for (int i = 0 ; i < len ; i++) + { int temp = ptr [i] ; + ptr [i] = ENDSWAP_32 (temp) ; + } ; +} /* endswap_int_array */ + +static inline void +endswap_int_copy (int *dest, const int *src, int len) +{ + for (int i = 0 ; i < len ; i++) + { dest [i] = ENDSWAP_32 (src [i]) ; + } ; +} /* endswap_int_copy */ + +/*======================================================================================== +*/ + +static inline void +endswap_int64_t_array (int64_t *ptr, int len) +{ + for (int i = 0 ; i < len ; i++) + { int64_t value = ptr [i] ; + ptr [i] = ENDSWAP_64 (value) ; + } ; +} /* endswap_int64_t_array */ + +static inline void +endswap_int64_t_copy (int64_t *dest, const int64_t *src, int len) +{ + for (int i = 0 ; i < len ; i++) + { int64_t value = src [i] ; + dest [i] = ENDSWAP_64 (value) ; + } ; +} /* endswap_int64_t_copy */ + +/* A couple of wrapper functions. */ + +static inline void +endswap_float_array (float *ptr, int len) +{ endswap_int_array ((int *) ptr, len) ; +} /* endswap_float_array */ + +static inline void +endswap_double_array (double *ptr, int len) +{ endswap_int64_t_array ((int64_t *) ptr, len) ; +} /* endswap_double_array */ + +static inline void +endswap_float_copy (float *dest, const float *src, int len) +{ endswap_int_copy ((int *) dest, (const int *) src, len) ; +} /* endswap_float_copy */ + +static inline void +endswap_double_copy (double *dest, const double *src, int len) +{ endswap_int64_t_copy ((int64_t *) dest, (const int64_t *) src, len) ; +} /* endswap_double_copy */ + +#endif /* SFENDIAN_INCLUDED */ + diff --git a/extern/libsndfile-modified/src/sndfile.c b/extern/libsndfile-modified/src/sndfile.c new file mode 100644 index 000000000..9a6c62275 --- /dev/null +++ b/extern/libsndfile-modified/src/sndfile.c @@ -0,0 +1,3450 @@ +/* +** Copyright (C) 1999-2018 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + +#if HAVE_UNISTD_H +#include +#elif defined _WIN32 +#include +#endif + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif + +#define SNDFILE_MAGICK 0x1234C0DE + +#ifdef __APPLE__ + /* + ** Detect if a compile for a universal binary is being attempted and barf if it is. + ** See the URL below for the rationale. + */ + #ifdef __BIG_ENDIAN__ + #if (CPU_IS_LITTLE_ENDIAN == 1) + #error "Universal binary compile detected. See http://libsndfile.github.io/libsndfile/FAQ.html#Q018" + #endif + #endif + + #ifdef __LITTLE_ENDIAN__ + #if (CPU_IS_BIG_ENDIAN == 1) + #error "Universal binary compile detected. See http://libsndfile.github.io/libsndfile/FAQ.html#Q018" + #endif + #endif +#endif + + +typedef struct +{ int error ; + const char *str ; +} ErrorStruct ; + +static +ErrorStruct SndfileErrors [] = +{ + /* Public error values and their associated strings. */ + { SF_ERR_NO_ERROR , "No Error." }, + { SF_ERR_UNRECOGNISED_FORMAT , "Format not recognised." }, + { SF_ERR_SYSTEM , "System error." /* Often replaced. */ }, + { SF_ERR_MALFORMED_FILE , "Supported file format but file is malformed." }, + { SF_ERR_UNSUPPORTED_ENCODING , "Supported file format but unsupported encoding." }, + + /* Private error values and their associated strings. */ + { SFE_ZERO_MAJOR_FORMAT , "Error : major format is 0." }, + { SFE_ZERO_MINOR_FORMAT , "Error : minor format is 0." }, + { SFE_BAD_FILE , "File does not exist or is not a regular file (possibly a pipe?)." }, + { SFE_BAD_FILE_READ , "File exists but no data could be read." }, + { SFE_OPEN_FAILED , "Could not open file." }, + { SFE_BAD_SNDFILE_PTR , "Not a valid SNDFILE* pointer." }, + { SFE_BAD_SF_INFO_PTR , "NULL SF_INFO pointer passed to libsndfile." }, + { SFE_BAD_SF_INCOMPLETE , "SF_PRIVATE struct incomplete and end of header parsing." }, + { SFE_BAD_FILE_PTR , "Bad FILE pointer." }, + { SFE_BAD_INT_PTR , "Internal error, Bad pointer." }, + { SFE_BAD_STAT_SIZE , "Error : software was misconfigured at compile time (sizeof statbuf.st_size)." }, + { SFE_NO_TEMP_DIR , "Error : Could not file temp dir." }, + + { SFE_MALLOC_FAILED , "Internal malloc () failed." }, + { SFE_UNIMPLEMENTED , "File contains data in an unimplemented format." }, + { SFE_BAD_READ_ALIGN , "Attempt to read a non-integer number of channels." }, + { SFE_BAD_WRITE_ALIGN , "Attempt to write a non-integer number of channels." }, + { SFE_NOT_READMODE , "Read attempted on file currently open for write." }, + { SFE_NOT_WRITEMODE , "Write attempted on file currently open for read." }, + { SFE_BAD_MODE_RW , "Error : This file format does not support read/write mode." }, + { SFE_BAD_SF_INFO , "Internal error : SF_INFO struct incomplete." }, + { SFE_BAD_OFFSET , "Error : supplied offset beyond end of file." }, + { SFE_NO_EMBED_SUPPORT , "Error : embedding not supported for this file format." }, + { SFE_NO_EMBEDDED_RDWR , "Error : cannot open embedded file read/write." }, + { SFE_NO_PIPE_WRITE , "Error : this file format does not support pipe write." }, + { SFE_BAD_VIRTUAL_IO , "Error : bad pointer on SF_VIRTUAL_IO struct." }, + { SFE_BAD_BROADCAST_INFO_SIZE + , "Error : bad coding_history_size in SF_BROADCAST_INFO struct." }, + { SFE_BAD_BROADCAST_INFO_TOO_BIG + , "Error : SF_BROADCAST_INFO struct too large." }, + { SFE_BAD_CART_INFO_SIZE , "Error: SF_CART_INFO struct too large." }, + { SFE_BAD_CART_INFO_TOO_BIG , "Error: bad tag_text_size in SF_CART_INFO struct." }, + { SFE_INTERLEAVE_MODE , "Attempt to write to file with non-interleaved data." }, + { SFE_INTERLEAVE_SEEK , "Bad karma in seek during interleave read operation." }, + { SFE_INTERLEAVE_READ , "Bad karma in read during interleave read operation." }, + + { SFE_INTERNAL , "Unspecified internal error." }, + { SFE_BAD_COMMAND_PARAM , "Bad parameter passed to function sf_command." }, + { SFE_BAD_ENDIAN , "Bad endian-ness. Try default endian-ness" }, + { SFE_CHANNEL_COUNT_ZERO , "Channel count is zero." }, + { SFE_CHANNEL_COUNT , "Too many channels specified." }, + { SFE_CHANNEL_COUNT_BAD , "Bad channel count." }, + + { SFE_BAD_SEEK , "Internal psf_fseek() failed." }, + { SFE_NOT_SEEKABLE , "Seek attempted on unseekable file type." }, + { SFE_AMBIGUOUS_SEEK , "Error : combination of file open mode and seek command is ambiguous." }, + { SFE_WRONG_SEEK , "Error : invalid seek parameters." }, + { SFE_SEEK_FAILED , "Error : parameters OK, but psf_seek() failed." }, + + { SFE_BAD_OPEN_MODE , "Error : bad mode parameter for file open." }, + { SFE_OPEN_PIPE_RDWR , "Error : attempt to open a pipe in read/write mode." }, + { SFE_RDWR_POSITION , "Error on RDWR position (cryptic)." }, + { SFE_RDWR_BAD_HEADER , "Error : Cannot open file in read/write mode due to string data in header." }, + { SFE_CMD_HAS_DATA , "Error : Command fails because file already has audio data." }, + + { SFE_STR_NO_SUPPORT , "Error : File type does not support string data." }, + { SFE_STR_NOT_WRITE , "Error : Trying to set a string when file is not in write mode." }, + { SFE_STR_MAX_DATA , "Error : Maximum string data storage reached." }, + { SFE_STR_MAX_COUNT , "Error : Maximum string data count reached." }, + { SFE_STR_BAD_TYPE , "Error : Bad string data type." }, + { SFE_STR_NO_ADD_END , "Error : file type does not support strings added at end of file." }, + { SFE_STR_BAD_STRING , "Error : bad string." }, + { SFE_STR_WEIRD , "Error : Weird string error." }, + + { SFE_WAV_NO_RIFF , "Error in WAV file. No 'RIFF' chunk marker." }, + { SFE_WAV_NO_WAVE , "Error in WAV file. No 'WAVE' chunk marker." }, + { SFE_WAV_NO_FMT , "Error in WAV/W64/RF64 file. No 'fmt ' chunk marker." }, + { SFE_WAV_BAD_FMT , "Error in WAV/W64/RF64 file. Malformed 'fmt ' chunk." }, + { SFE_WAV_FMT_SHORT , "Error in WAV/W64/RF64 file. Short 'fmt ' chunk." }, + + { SFE_WAV_BAD_FACT , "Error in WAV file. 'fact' chunk out of place." }, + { SFE_WAV_BAD_PEAK , "Error in WAV file. Bad 'PEAK' chunk." }, + { SFE_WAV_PEAK_B4_FMT , "Error in WAV file. 'PEAK' chunk found before 'fmt ' chunk." }, + + { SFE_WAV_BAD_FORMAT , "Error in WAV file. Errors in 'fmt ' chunk." }, + { SFE_WAV_BAD_BLOCKALIGN , "Error in WAV file. Block alignment in 'fmt ' chunk is incorrect." }, + { SFE_WAV_NO_DATA , "Error in WAV file. No 'data' chunk marker." }, + { SFE_WAV_BAD_LIST , "Error in WAV file. Malformed LIST chunk." }, + { SFE_WAV_UNKNOWN_CHUNK , "Error in WAV file. File contains an unknown chunk marker." }, + { SFE_WAV_WVPK_DATA , "Error in WAV file. Data is in WAVPACK format." }, + + { SFE_WAV_ADPCM_NOT4BIT , "Error in ADPCM WAV file. Invalid bit width." }, + { SFE_WAV_ADPCM_CHANNELS , "Error in ADPCM WAV file. Invalid number of channels." }, + { SFE_WAV_ADPCM_SAMPLES , "Error in ADPCM WAV file. Invalid number of samples per block." }, + { SFE_WAV_GSM610_FORMAT , "Error in GSM610 WAV file. Invalid format chunk." }, + { SFE_WAV_NMS_FORMAT , "Error in NMS ADPCM WAV file. Invalid format chunk." }, + + { SFE_AIFF_NO_FORM , "Error in AIFF file, bad 'FORM' marker." }, + { SFE_AIFF_AIFF_NO_FORM , "Error in AIFF file, 'AIFF' marker without 'FORM'." }, + { SFE_AIFF_COMM_NO_FORM , "Error in AIFF file, 'COMM' marker without 'FORM'." }, + { SFE_AIFF_SSND_NO_COMM , "Error in AIFF file, 'SSND' marker without 'COMM'." }, + { SFE_AIFF_UNKNOWN_CHUNK , "Error in AIFF file, unknown chunk." }, + { SFE_AIFF_COMM_CHUNK_SIZE, "Error in AIFF file, bad 'COMM' chunk size." }, + { SFE_AIFF_BAD_COMM_CHUNK , "Error in AIFF file, bad 'COMM' chunk." }, + { SFE_AIFF_PEAK_B4_COMM , "Error in AIFF file. 'PEAK' chunk found before 'COMM' chunk." }, + { SFE_AIFF_BAD_PEAK , "Error in AIFF file. Bad 'PEAK' chunk." }, + { SFE_AIFF_NO_SSND , "Error in AIFF file, bad 'SSND' chunk." }, + { SFE_AIFF_NO_DATA , "Error in AIFF file, no sound data." }, + { SFE_AIFF_RW_SSND_NOT_LAST, "Error in AIFF file, RDWR only possible if SSND chunk at end of file." }, + + { SFE_AU_UNKNOWN_FORMAT , "Error in AU file, unknown format." }, + { SFE_AU_NO_DOTSND , "Error in AU file, missing '.snd' or 'dns.' marker." }, + { SFE_AU_EMBED_BAD_LEN , "Embedded AU file with unknown length." }, + + { SFE_RAW_READ_BAD_SPEC , "Error while opening RAW file for read. Must specify format and channels.\n" + "Possibly trying to open unsupported format." }, + { SFE_RAW_BAD_BITWIDTH , "Error. RAW file bitwidth must be a multiple of 8." }, + { SFE_RAW_BAD_FORMAT , "Error. Bad format field in SF_INFO struct when opening a RAW file for read." }, + + { SFE_PAF_NO_MARKER , "Error in PAF file, no marker." }, + { SFE_PAF_VERSION , "Error in PAF file, bad version." }, + { SFE_PAF_UNKNOWN_FORMAT , "Error in PAF file, unknown format." }, + { SFE_PAF_SHORT_HEADER , "Error in PAF file. File shorter than minimal header." }, + { SFE_PAF_BAD_CHANNELS , "Error in PAF file. Bad channel count." }, + + { SFE_SVX_NO_FORM , "Error in 8SVX / 16SV file, no 'FORM' marker." }, + { SFE_SVX_NO_BODY , "Error in 8SVX / 16SV file, no 'BODY' marker." }, + { SFE_SVX_NO_DATA , "Error in 8SVX / 16SV file, no sound data." }, + { SFE_SVX_BAD_COMP , "Error in 8SVX / 16SV file, unsupported compression format." }, + { SFE_SVX_BAD_NAME_LENGTH , "Error in 8SVX / 16SV file, NAME chunk too long." }, + + { SFE_NIST_BAD_HEADER , "Error in NIST file, bad header." }, + { SFE_NIST_CRLF_CONVERISON, "Error : NIST file damaged by Windows CR -> CRLF conversion process." }, + { SFE_NIST_BAD_ENCODING , "Error in NIST file, unsupported compression format." }, + + { SFE_VOC_NO_CREATIVE , "Error in VOC file, no 'Creative Voice File' marker." }, + { SFE_VOC_BAD_FORMAT , "Error in VOC file, bad format." }, + { SFE_VOC_BAD_VERSION , "Error in VOC file, bad version number." }, + { SFE_VOC_BAD_MARKER , "Error in VOC file, bad marker in file." }, + { SFE_VOC_BAD_SECTIONS , "Error in VOC file, incompatible VOC sections." }, + { SFE_VOC_MULTI_SAMPLERATE, "Error in VOC file, more than one sample rate defined." }, + { SFE_VOC_MULTI_SECTION , "Unimplemented VOC file feature, file contains multiple sound sections." }, + { SFE_VOC_MULTI_PARAM , "Error in VOC file, file contains multiple bit or channel widths." }, + { SFE_VOC_SECTION_COUNT , "Error in VOC file, too many sections." }, + { SFE_VOC_NO_PIPE , "Error : not able to operate on VOC files over a pipe." }, + + { SFE_IRCAM_NO_MARKER , "Error in IRCAM file, bad IRCAM marker." }, + { SFE_IRCAM_BAD_CHANNELS , "Error in IRCAM file, bad channel count." }, + { SFE_IRCAM_UNKNOWN_FORMAT, "Error in IRCAM file, unknown encoding format." }, + + { SFE_W64_64_BIT , "Error in W64 file, file contains 64 bit offset." }, + { SFE_W64_NO_RIFF , "Error in W64 file. No 'riff' chunk marker." }, + { SFE_W64_NO_WAVE , "Error in W64 file. No 'wave' chunk marker." }, + { SFE_W64_NO_DATA , "Error in W64 file. No 'data' chunk marker." }, + { SFE_W64_ADPCM_NOT4BIT , "Error in ADPCM W64 file. Invalid bit width." }, + { SFE_W64_ADPCM_CHANNELS , "Error in ADPCM W64 file. Invalid number of channels." }, + { SFE_W64_GSM610_FORMAT , "Error in GSM610 W64 file. Invalid format chunk." }, + + { SFE_MAT4_BAD_NAME , "Error in MAT4 file. No variable name." }, + { SFE_MAT4_NO_SAMPLERATE , "Error in MAT4 file. No sample rate." }, + + { SFE_MAT5_BAD_ENDIAN , "Error in MAT5 file. Not able to determine endian-ness." }, + { SFE_MAT5_NO_BLOCK , "Error in MAT5 file. Bad block structure." }, + { SFE_MAT5_SAMPLE_RATE , "Error in MAT5 file. Not able to determine sample rate." }, + + { SFE_PVF_NO_PVF1 , "Error in PVF file. No PVF1 marker." }, + { SFE_PVF_BAD_HEADER , "Error in PVF file. Bad header." }, + { SFE_PVF_BAD_BITWIDTH , "Error in PVF file. Bad bit width." }, + + { SFE_XI_BAD_HEADER , "Error in XI file. Bad header." }, + { SFE_XI_EXCESS_SAMPLES , "Error in XI file. Excess samples in file." }, + { SFE_XI_NO_PIPE , "Error : not able to operate on XI files over a pipe." }, + + { SFE_HTK_NO_PIPE , "Error : not able to operate on HTK files over a pipe." }, + + { SFE_SDS_NOT_SDS , "Error : not an SDS file." }, + { SFE_SDS_BAD_BIT_WIDTH , "Error : bad bit width for SDS file." }, + + { SFE_SD2_FD_DISALLOWED , "Error : cannot open SD2 file without a file name." }, + { SFE_SD2_BAD_DATA_OFFSET , "Error : bad data offset." }, + { SFE_SD2_BAD_MAP_OFFSET , "Error : bad map offset." }, + { SFE_SD2_BAD_DATA_LENGTH , "Error : bad data length." }, + { SFE_SD2_BAD_MAP_LENGTH , "Error : bad map length." }, + { SFE_SD2_BAD_RSRC , "Error : bad resource fork." }, + { SFE_SD2_BAD_SAMPLE_SIZE , "Error : bad sample size." }, + + { SFE_FLAC_BAD_HEADER , "Error : bad flac header." }, + { SFE_FLAC_NEW_DECODER , "Error : problem while creating flac decoder." }, + { SFE_FLAC_INIT_DECODER , "Error : problem with initialization of the flac decoder." }, + { SFE_FLAC_LOST_SYNC , "Error : flac decoder lost sync." }, + { SFE_FLAC_BAD_SAMPLE_RATE, "Error : flac does not support this sample rate." }, + { SFE_FLAC_CHANNEL_COUNT_CHANGED, "Error : flac channel changed mid stream." }, + { SFE_FLAC_UNKOWN_ERROR , "Error : unknown error in flac decoder." }, + + { SFE_WVE_NOT_WVE , "Error : not a WVE file." }, + { SFE_WVE_NO_PIPE , "Error : not able to operate on WVE files over a pipe." }, + + { SFE_DWVW_BAD_BITWIDTH , "Error : Bad bit width for DWVW encoding. Must be 12, 16 or 24." }, + { SFE_G72X_NOT_MONO , "Error : G72x encoding does not support more than 1 channel." }, + { SFE_NMS_ADPCM_NOT_MONO , "Error : NMS ADPCM encoding does not support more than 1 channel." }, + + { SFE_VORBIS_ENCODER_BUG , "Error : Sample rate chosen is known to trigger a Vorbis encoder bug on this CPU." }, + + { SFE_RF64_NOT_RF64 , "Error : Not an RF64 file." }, + { SFE_RF64_PEAK_B4_FMT , "Error in RF64 file. 'PEAK' chunk found before 'fmt ' chunk." }, + { SFE_RF64_NO_DATA , "Error in RF64 file. No 'data' chunk marker." }, + + { SFE_ALAC_FAIL_TMPFILE , "Error : Failed to open tmp file for ALAC encoding." }, + + { SFE_BAD_CHUNK_PTR , "Error : Bad SF_CHUNK_INFO pointer." }, + { SFE_UNKNOWN_CHUNK , "Error : Unknown chunk marker." }, + { SFE_BAD_CHUNK_FORMAT , "Error : Reading/writing chunks from this file format is not supported." }, + { SFE_BAD_CHUNK_MARKER , "Error : Bad chunk marker." }, + { SFE_BAD_CHUNK_DATA_PTR , "Error : Bad data pointer in SF_CHUNK_INFO struct." }, + { SFE_FILENAME_TOO_LONG , "Error : Supplied filename too long." }, + { SFE_NEGATIVE_RW_LEN , "Error : Length parameter passed to read/write is negative." }, + + { SFE_OPUS_BAD_SAMPLERATE , "Error : Opus only supports sample rates of 8000, 12000, 16000, 24000, and 48000." }, + + { SFE_MPEG_BAD_SAMPLERATE , "Error : MPEG-1/2/2.5 only supports sample rates of 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, and 48000." }, + + { SFE_CAF_NOT_CAF , "Error : Not a CAF file." }, + { SFE_CAF_NO_DESC , "Error : No 'desc' marker in CAF file." }, + { SFE_CAF_BAD_PEAK , "Error : Bad 'PEAK' chunk in CAF file." }, + + { SFE_AVR_NOT_AVR , "Error : Not an AVR file." }, + { SFE_AVR_BAD_REZ_SIGN , "Error : Bad rez/sign combination." }, + + { SFE_MPC_NO_MARKER , "Error : No marker in MPC2K file." }, + + { SFE_MAX_ERROR , "Maximum error number." }, + { SFE_MAX_ERROR + 1 , NULL } +} ; + +/*------------------------------------------------------------------------------ +*/ + +static int format_from_extension (SF_PRIVATE *psf) ; +static int guess_file_type (SF_PRIVATE *psf) ; +static int validate_sfinfo (SF_INFO *sfinfo) ; +static int validate_psf (SF_PRIVATE *psf) ; +static void save_header_info (SF_PRIVATE *psf) ; +static int psf_close (SF_PRIVATE *psf) ; + +static int try_resource_fork (SF_PRIVATE * psf) ; + +/*------------------------------------------------------------------------------ +** Private (static) variables. +*/ + +int sf_errno = 0 ; +static char sf_parselog [SF_BUFFER_LEN] = { 0 } ; +static char sf_syserr [SF_SYSERR_LEN] = { 0 } ; + +/*------------------------------------------------------------------------------ +*/ + +#define VALIDATE_SNDFILE_AND_ASSIGN_PSF(a, b, c) \ + { if ((a) == NULL) \ + { sf_errno = SFE_BAD_SNDFILE_PTR ; \ + return 0 ; \ + } ; \ + (b) = (SF_PRIVATE*) (a) ; \ + if ((b)->virtual_io == SF_FALSE && \ + psf_file_valid (b) == 0) \ + { (b)->error = SFE_BAD_FILE_PTR ; \ + return 0 ; \ + } ; \ + if ((b)->Magick != SNDFILE_MAGICK) \ + { (b)->error = SFE_BAD_SNDFILE_PTR ; \ + return 0 ; \ + } ; \ + if (c) (b)->error = 0 ; \ + } + +/*------------------------------------------------------------------------------ +** Public functions. +*/ + +SNDFILE* +sf_open (const char *path, int mode, SF_INFO *sfinfo) +{ SF_PRIVATE *psf ; + const char *utf8path_ptr ; +#ifdef _WIN32 + LPWSTR wpath ; + int nResult ; + int wpath_len ; + char utf8path [SF_FILENAME_LEN] ; + DWORD dwError ; +#endif + + /* Ultimate sanity check. */ + assert (sizeof (sf_count_t) == 8) ; + + if ((psf = psf_allocate ()) == NULL) + { sf_errno = SFE_MALLOC_FAILED ; + return NULL ; + } ; + + psf_init_files (psf) ; + + psf_log_printf (psf, "File : %s\n", path) ; + +#ifdef _WIN32 + nResult = MultiByteToWideChar (CP_ACP, 0, path, -1, NULL, 0) ; + if (nResult == 0) + { sf_errno = SF_ERR_UNSUPPORTED_ENCODING ; + psf_close (psf) ; + return NULL ; + } ; + + wpath_len = nResult ; + wpath = malloc (wpath_len * sizeof (WCHAR)) ; + if (!wpath) + { sf_errno = SFE_MALLOC_FAILED ; + psf_close (psf) ; + return NULL ; + } ; + + nResult = MultiByteToWideChar (CP_ACP, 0, path, -1, wpath, wpath_len) ; + if (nResult == 0) + { sf_errno = SF_ERR_UNSUPPORTED_ENCODING ; + free (wpath) ; + psf_close (psf) ; + return NULL ; + } ; + + nResult = WideCharToMultiByte (CP_UTF8, 0, wpath, wpath_len, NULL, 0, NULL, + NULL) ; + if (nResult == 0) + { sf_errno = SF_ERR_UNSUPPORTED_ENCODING ; + free (wpath) ; + psf_close (psf) ; + return NULL ; + } ; + + nResult = WideCharToMultiByte (CP_UTF8, 0, wpath, wpath_len, utf8path, + SF_FILENAME_LEN, NULL, NULL) ; + + free (wpath) ; + + if (nResult == 0) + { dwError = GetLastError () ; + if (dwError == ERROR_INSUFFICIENT_BUFFER) + sf_errno = SFE_FILENAME_TOO_LONG ; + else + sf_errno = SF_ERR_UNSUPPORTED_ENCODING ; + psf_close (psf) ; + return NULL ; + } ; + + utf8path_ptr = utf8path ; +#else + utf8path_ptr = path ; +#endif + + if (psf_copy_filename (psf, utf8path_ptr) != 0) + { sf_errno = psf->error ; + psf_close (psf) ; + return NULL ; + } ; + + psf->file.mode = mode ; + if (strcmp (path, "-") == 0) + psf->error = psf_set_stdio (psf) ; + else + psf->error = psf_fopen (psf) ; + + return psf_open_file (psf, sfinfo) ; +} /* sf_open */ + +SNDFILE* +sf_open_fd (int fd, int mode, SF_INFO *sfinfo, int close_desc) +{ SF_PRIVATE *psf ; + + if ((SF_CONTAINER (sfinfo->format)) == SF_FORMAT_SD2) + { sf_errno = SFE_SD2_FD_DISALLOWED ; + if (close_desc) + close (fd) ; + + return NULL ; + } ; + + if ((psf = psf_allocate ()) == NULL) + { sf_errno = SFE_MALLOC_FAILED ; + if (close_desc) + close (fd) ; + + return NULL ; + } ; + + psf_init_files (psf) ; + psf_copy_filename (psf, "") ; + + psf->file.mode = mode ; + psf->file.do_not_close_descriptor = !close_desc; + psf_set_file (psf, fd) ; + psf->is_pipe = psf_is_pipe (psf) ; + psf->fileoffset = psf_ftell (psf) ; + + return psf_open_file (psf, sfinfo) ; +} /* sf_open_fd */ + +SNDFILE* +sf_open_virtual (SF_VIRTUAL_IO *sfvirtual, int mode, SF_INFO *sfinfo, void *user_data) +{ SF_PRIVATE *psf ; + + /* Make sure we have a valid set ot virtual pointers. */ + if (sfvirtual->get_filelen == NULL) + { sf_errno = SFE_BAD_VIRTUAL_IO ; + snprintf (sf_parselog, sizeof (sf_parselog), "Bad vio_get_filelen in SF_VIRTUAL_IO struct.\n") ; + return NULL ; + } ; + + if ((sfvirtual->seek == NULL || sfvirtual->tell == NULL) && sfinfo->seekable) + { sf_errno = SFE_BAD_VIRTUAL_IO ; + snprintf (sf_parselog, sizeof (sf_parselog), "Bad vio_seek / vio_tell in SF_VIRTUAL_IO struct.\n") ; + return NULL ; + } ; + + if ((mode == SFM_READ || mode == SFM_RDWR) && sfvirtual->read == NULL) + { sf_errno = SFE_BAD_VIRTUAL_IO ; + snprintf (sf_parselog, sizeof (sf_parselog), "Bad vio_read in SF_VIRTUAL_IO struct.\n") ; + return NULL ; + } ; + + if ((mode == SFM_WRITE || mode == SFM_RDWR) && sfvirtual->write == NULL) + { sf_errno = SFE_BAD_VIRTUAL_IO ; + snprintf (sf_parselog, sizeof (sf_parselog), "Bad vio_write in SF_VIRTUAL_IO struct.\n") ; + return NULL ; + } ; + + if ((psf = psf_allocate ()) == NULL) + { sf_errno = SFE_MALLOC_FAILED ; + return NULL ; + } ; + + psf_init_files (psf) ; + + psf->virtual_io = SF_TRUE ; + psf->vio = *sfvirtual ; + psf->vio_user_data = user_data ; + + psf->file.mode = mode ; + + return psf_open_file (psf, sfinfo) ; +} /* sf_open_virtual */ + +int +sf_close (SNDFILE *sndfile) +{ SF_PRIVATE *psf ; + + VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; + + return psf_close (psf) ; +} /* sf_close */ + +void +sf_write_sync (SNDFILE *sndfile) +{ SF_PRIVATE *psf ; + + if ((psf = (SF_PRIVATE *) sndfile) == NULL) + return ; + + psf_fsync (psf) ; + + return ; +} /* sf_write_sync */ + +/*============================================================================== +*/ + +const char* +sf_error_number (int errnum) +{ static const char *bad_errnum = + "No error defined for this error number. This is a bug in libsndfile." ; + int k ; + + if (errnum == SFE_MAX_ERROR) + return SndfileErrors [0].str ; + + if (errnum < 0 || errnum > SFE_MAX_ERROR) + { /* This really shouldn't happen in release versions. */ + printf ("Not a valid error number (%d).\n", errnum) ; + return bad_errnum ; + } ; + + for (k = 0 ; SndfileErrors [k].str ; k++) + if (errnum == SndfileErrors [k].error) + return SndfileErrors [k].str ; + + return bad_errnum ; +} /* sf_error_number */ + +const char* +sf_strerror (SNDFILE *sndfile) +{ SF_PRIVATE *psf = NULL ; + int errnum ; + + if (sndfile == NULL) + { errnum = sf_errno ; + if (errnum == SFE_SYSTEM && sf_syserr [0]) + return sf_syserr ; + } + else + { psf = (SF_PRIVATE *) sndfile ; + + if (psf->Magick != SNDFILE_MAGICK) + return "sf_strerror : Bad magic number." ; + + errnum = psf->error ; + + if (errnum == SFE_SYSTEM && psf->syserr [0]) + return psf->syserr ; + } ; + + return sf_error_number (errnum) ; +} /* sf_strerror */ + +/*------------------------------------------------------------------------------ +*/ + +int +sf_error (SNDFILE *sndfile) +{ SF_PRIVATE *psf ; + + if (sndfile == NULL) + return sf_errno ; + + VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 0) ; + + if (psf->error) + return psf->error ; + + return 0 ; +} /* sf_error */ + +/*------------------------------------------------------------------------------ +*/ + +int +sf_perror (SNDFILE *sndfile) +{ SF_PRIVATE *psf ; + int errnum ; + + if (sndfile == NULL) + { errnum = sf_errno ; + } + else + { VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 0) ; + errnum = psf->error ; + } ; + + fprintf (stderr, "%s\n", sf_error_number (errnum)) ; + return SFE_NO_ERROR ; +} /* sf_perror */ + + +/*------------------------------------------------------------------------------ +*/ + +int +sf_error_str (SNDFILE *sndfile, char *str, size_t maxlen) +{ SF_PRIVATE *psf ; + int errnum ; + + if (str == NULL) + return SFE_INTERNAL ; + + if (sndfile == NULL) + errnum = sf_errno ; + else + { VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 0) ; + errnum = psf->error ; + } ; + + snprintf (str, maxlen, "%s", sf_error_number (errnum)) ; + + return SFE_NO_ERROR ; +} /* sf_error_str */ + +/*============================================================================== +*/ + +int +sf_format_check (const SF_INFO *info) +{ int subformat, endian ; + + subformat = SF_CODEC (info->format) ; + endian = SF_ENDIAN (info->format) ; + + /* This is the place where each file format can check if the supplied + ** SF_INFO struct is valid. + ** Return 0 on failure, 1 ons success. + */ + + if (info->channels < 1 || info->channels > SF_MAX_CHANNELS) + return 0 ; + + if (info->samplerate < 0) + return 0 ; + + switch (SF_CONTAINER (info->format)) + { case SF_FORMAT_WAV : + /* WAV now allows both endian, RIFF or RIFX (little or big respectively) */ + if (subformat == SF_FORMAT_PCM_U8 || subformat == SF_FORMAT_PCM_16) + return 1 ; + if (subformat == SF_FORMAT_PCM_24 || subformat == SF_FORMAT_PCM_32) + return 1 ; + if ((subformat == SF_FORMAT_IMA_ADPCM || subformat == SF_FORMAT_MS_ADPCM) && info->channels <= 2) + return 1 ; + if (subformat == SF_FORMAT_GSM610 && info->channels == 1) + return 1 ; + if (subformat == SF_FORMAT_G721_32 && info->channels == 1) + return 1 ; + if (subformat == SF_FORMAT_ULAW || subformat == SF_FORMAT_ALAW) + return 1 ; + if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE) + return 1 ; + if ((subformat == SF_FORMAT_NMS_ADPCM_16 || subformat == SF_FORMAT_NMS_ADPCM_24 || + subformat == SF_FORMAT_NMS_ADPCM_32) && info->channels == 1) + return 1 ; + if (subformat == SF_FORMAT_MPEG_LAYER_III && info->channels <= 2) + return 1 ; + break ; + + case SF_FORMAT_WAVEX : + if (endian == SF_ENDIAN_BIG || endian == SF_ENDIAN_CPU) + return 0 ; + if (subformat == SF_FORMAT_PCM_U8 || subformat == SF_FORMAT_PCM_16) + return 1 ; + if (subformat == SF_FORMAT_PCM_24 || subformat == SF_FORMAT_PCM_32) + return 1 ; + if (subformat == SF_FORMAT_ULAW || subformat == SF_FORMAT_ALAW) + return 1 ; + if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE) + return 1 ; + break ; + + case SF_FORMAT_AIFF : + /* AIFF does allow both endian-nesses for PCM data.*/ + if (subformat == SF_FORMAT_PCM_16 || subformat == SF_FORMAT_PCM_24 || subformat == SF_FORMAT_PCM_32) + return 1 ; + /* For other encodings reject any endian-ness setting. */ + if (endian != 0) + return 0 ; + if (subformat == SF_FORMAT_PCM_U8 || subformat == SF_FORMAT_PCM_S8) + return 1 ; + if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE) + return 1 ; + if (subformat == SF_FORMAT_ULAW || subformat == SF_FORMAT_ALAW) + return 1 ; + if ((subformat == SF_FORMAT_DWVW_12 || subformat == SF_FORMAT_DWVW_16 || + subformat == SF_FORMAT_DWVW_24) && info-> channels == 1) + return 1 ; + if (subformat == SF_FORMAT_GSM610 && info->channels == 1) + return 1 ; + if (subformat == SF_FORMAT_IMA_ADPCM && (info->channels == 1 || info->channels == 2)) + return 1 ; + break ; + + case SF_FORMAT_AU : + if (subformat == SF_FORMAT_PCM_S8 || subformat == SF_FORMAT_PCM_16) + return 1 ; + if (subformat == SF_FORMAT_PCM_24 || subformat == SF_FORMAT_PCM_32) + return 1 ; + if (subformat == SF_FORMAT_ULAW || subformat == SF_FORMAT_ALAW) + return 1 ; + if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE) + return 1 ; + if (subformat == SF_FORMAT_G721_32 && info->channels == 1) + return 1 ; + if (subformat == SF_FORMAT_G723_24 && info->channels == 1) + return 1 ; + if (subformat == SF_FORMAT_G723_40 && info->channels == 1) + return 1 ; + break ; + + case SF_FORMAT_CAF : + if (subformat == SF_FORMAT_PCM_S8 || subformat == SF_FORMAT_PCM_16) + return 1 ; + if (subformat == SF_FORMAT_PCM_24 || subformat == SF_FORMAT_PCM_32) + return 1 ; + if (subformat == SF_FORMAT_ULAW || subformat == SF_FORMAT_ALAW) + return 1 ; + if (subformat == SF_FORMAT_ALAC_16 || subformat == SF_FORMAT_ALAC_20) + return 1 ; + if (subformat == SF_FORMAT_ALAC_24 || subformat == SF_FORMAT_ALAC_32) + return 1 ; + if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE) + return 1 ; + break ; + + case SF_FORMAT_RAW : + if (subformat == SF_FORMAT_PCM_U8 || subformat == SF_FORMAT_PCM_S8 || subformat == SF_FORMAT_PCM_16) + return 1 ; + if (subformat == SF_FORMAT_PCM_24 || subformat == SF_FORMAT_PCM_32) + return 1 ; + if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE) + return 1 ; + if (subformat == SF_FORMAT_ALAW || subformat == SF_FORMAT_ULAW) + return 1 ; + if ((subformat == SF_FORMAT_DWVW_12 || subformat == SF_FORMAT_DWVW_16 || + subformat == SF_FORMAT_DWVW_24) && info-> channels == 1) + return 1 ; + if (subformat == SF_FORMAT_GSM610 && info->channels == 1) + return 1 ; + if (subformat == SF_FORMAT_VOX_ADPCM && info->channels == 1) + return 1 ; + if ((subformat == SF_FORMAT_NMS_ADPCM_16 || subformat == SF_FORMAT_NMS_ADPCM_24 || + subformat == SF_FORMAT_NMS_ADPCM_32) && info->channels == 1) + return 1 ; + break ; + + case SF_FORMAT_PAF : + if (subformat == SF_FORMAT_PCM_S8 || subformat == SF_FORMAT_PCM_16 || subformat == SF_FORMAT_PCM_24) + return 1 ; + break ; + + case SF_FORMAT_SVX : + /* SVX only supports writing mono SVX files. */ + if (info->channels > 1) + return 0 ; + /* Always big endian. */ + if (endian == SF_ENDIAN_LITTLE || endian == SF_ENDIAN_CPU) + return 0 ; + + if (subformat == SF_FORMAT_PCM_S8 || subformat == SF_FORMAT_PCM_16) + return 1 ; + break ; + + case SF_FORMAT_NIST : + if (subformat == SF_FORMAT_PCM_S8 || subformat == SF_FORMAT_PCM_16) + return 1 ; + if (subformat == SF_FORMAT_PCM_24 || subformat == SF_FORMAT_PCM_32) + return 1 ; + if (subformat == SF_FORMAT_ULAW || subformat == SF_FORMAT_ALAW) + return 1 ; + break ; + + case SF_FORMAT_IRCAM : + if (info->channels > 256) + return 0 ; + if (subformat == SF_FORMAT_PCM_16 || subformat == SF_FORMAT_PCM_32) + return 1 ; + if (subformat == SF_FORMAT_ULAW || subformat == SF_FORMAT_ALAW || subformat == SF_FORMAT_FLOAT) + return 1 ; + break ; + + case SF_FORMAT_VOC : + if (info->channels > 2) + return 0 ; + /* VOC is strictly little endian. */ + if (endian == SF_ENDIAN_BIG || endian == SF_ENDIAN_CPU) + return 0 ; + if (subformat == SF_FORMAT_PCM_U8 || subformat == SF_FORMAT_PCM_16) + return 1 ; + if (subformat == SF_FORMAT_ULAW || subformat == SF_FORMAT_ALAW) + return 1 ; + break ; + + case SF_FORMAT_W64 : + /* W64 is strictly little endian. */ + if (endian == SF_ENDIAN_BIG || endian == SF_ENDIAN_CPU) + return 0 ; + if (subformat == SF_FORMAT_PCM_U8 || subformat == SF_FORMAT_PCM_16) + return 1 ; + if (subformat == SF_FORMAT_PCM_24 || subformat == SF_FORMAT_PCM_32) + return 1 ; + if ((subformat == SF_FORMAT_IMA_ADPCM || subformat == SF_FORMAT_MS_ADPCM) && info->channels <= 2) + return 1 ; + if (subformat == SF_FORMAT_GSM610 && info->channels == 1) + return 1 ; + if (subformat == SF_FORMAT_ULAW || subformat == SF_FORMAT_ALAW) + return 1 ; + if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE) + return 1 ; + break ; + + case SF_FORMAT_MAT4 : + if (subformat == SF_FORMAT_PCM_16 || subformat == SF_FORMAT_PCM_32) + return 1 ; + if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE) + return 1 ; + break ; + + case SF_FORMAT_MAT5 : + if (subformat == SF_FORMAT_PCM_U8 || subformat == SF_FORMAT_PCM_16 || subformat == SF_FORMAT_PCM_32) + return 1 ; + if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE) + return 1 ; + break ; + + case SF_FORMAT_PVF : + if (subformat == SF_FORMAT_PCM_S8 || subformat == SF_FORMAT_PCM_16 || subformat == SF_FORMAT_PCM_32) + return 1 ; + break ; + + case SF_FORMAT_XI : + if (info->channels != 1) + return 0 ; + if (subformat == SF_FORMAT_DPCM_8 || subformat == SF_FORMAT_DPCM_16) + return 1 ; + break ; + + case SF_FORMAT_HTK : + if (info->channels != 1) + return 0 ; + /* HTK is strictly big endian. */ + if (endian == SF_ENDIAN_LITTLE || endian == SF_ENDIAN_CPU) + return 0 ; + if (subformat == SF_FORMAT_PCM_16) + return 1 ; + break ; + + case SF_FORMAT_SDS : + if (info->channels != 1) + return 0 ; + /* SDS is strictly big endian. */ + if (endian == SF_ENDIAN_LITTLE || endian == SF_ENDIAN_CPU) + return 0 ; + if (subformat == SF_FORMAT_PCM_S8 || subformat == SF_FORMAT_PCM_16 || subformat == SF_FORMAT_PCM_24) + return 1 ; + break ; + + case SF_FORMAT_AVR : + if (info->channels > 2) + return 0 ; + /* SDS is strictly big endian. */ + if (endian == SF_ENDIAN_LITTLE || endian == SF_ENDIAN_CPU) + return 0 ; + if (subformat == SF_FORMAT_PCM_U8 || subformat == SF_FORMAT_PCM_S8 || subformat == SF_FORMAT_PCM_16) + return 1 ; + break ; + + case SF_FORMAT_FLAC : + /* FLAC can't do more than 8 channels. */ + if (info->channels > 8) + return 0 ; + if (endian != SF_ENDIAN_FILE) + return 0 ; + if (subformat == SF_FORMAT_PCM_S8 || subformat == SF_FORMAT_PCM_16 || subformat == SF_FORMAT_PCM_24) + return 1 ; + break ; + + case SF_FORMAT_SD2 : + /* SD2 is strictly big endian. */ + if (endian == SF_ENDIAN_LITTLE || endian == SF_ENDIAN_CPU) + return 0 ; + if (subformat == SF_FORMAT_PCM_S8 || subformat == SF_FORMAT_PCM_16 || subformat == SF_FORMAT_PCM_24 || subformat == SF_FORMAT_PCM_32) + return 1 ; + break ; + + case SF_FORMAT_WVE : + if (info->channels > 1) + return 0 ; + /* WVE is strictly big endian. */ + if (endian == SF_ENDIAN_BIG || endian == SF_ENDIAN_CPU) + return 0 ; + if (subformat == SF_FORMAT_ALAW) + return 1 ; + break ; + + case SF_FORMAT_OGG : + if (endian != SF_ENDIAN_FILE) + return 0 ; + if (subformat == SF_FORMAT_VORBIS) + return 1 ; + if (subformat == SF_FORMAT_OPUS) + return 1 ; + break ; + + case SF_FORMAT_MPC2K : + if (info->channels > 2) + return 0 ; + /* MPC2000 is strictly little endian. */ + if (endian == SF_ENDIAN_BIG || endian == SF_ENDIAN_CPU) + return 0 ; + if (subformat == SF_FORMAT_PCM_16) + return 1 ; + break ; + + case SF_FORMAT_RF64 : + if (endian == SF_ENDIAN_BIG || endian == SF_ENDIAN_CPU) + return 0 ; + if (subformat == SF_FORMAT_PCM_U8 || subformat == SF_FORMAT_PCM_16) + return 1 ; + if (subformat == SF_FORMAT_PCM_24 || subformat == SF_FORMAT_PCM_32) + return 1 ; + if (subformat == SF_FORMAT_ULAW || subformat == SF_FORMAT_ALAW) + return 1 ; + if (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE) + return 1 ; + break ; + + case SF_FORMAT_MPEG : + if (info->channels > 2) + return 0 ; + if (endian != SF_ENDIAN_FILE) + return 0 ; + if (subformat == SF_FORMAT_MPEG_LAYER_I || subformat == SF_FORMAT_MPEG_LAYER_II || subformat == SF_FORMAT_MPEG_LAYER_III) + return 1 ; + break ; + default : break ; + } ; + + return 0 ; +} /* sf_format_check */ + +/*------------------------------------------------------------------------------ +*/ + +const char * +sf_version_string (void) +{ +#if ENABLE_EXPERIMENTAL_CODE + return PACKAGE_NAME "-" PACKAGE_VERSION "-exp" ; +#else + return PACKAGE_NAME "-" PACKAGE_VERSION ; +#endif +} + + +/*------------------------------------------------------------------------------ +*/ + +int +sf_command (SNDFILE *sndfile, int command, void *data, int datasize) +{ SF_PRIVATE *psf = (SF_PRIVATE *) sndfile ; + double quality ; + double latency ; + int old_value ; + + /* This set of commands do not need the sndfile parameter. */ + switch (command) + { case SFC_GET_LIB_VERSION : + if (data == NULL) + { if (psf) + psf->error = SFE_BAD_COMMAND_PARAM ; + return 0 ; + } ; + snprintf (data, datasize, "%s", sf_version_string ()) ; + return strlen (data) ; + + case SFC_GET_SIMPLE_FORMAT_COUNT : + if (data == NULL || datasize != SIGNED_SIZEOF (int)) + return (sf_errno = SFE_BAD_COMMAND_PARAM) ; + *((int*) data) = psf_get_format_simple_count () ; + return 0 ; + + case SFC_GET_SIMPLE_FORMAT : + if (data == NULL || datasize != SIGNED_SIZEOF (SF_FORMAT_INFO)) + return (sf_errno = SFE_BAD_COMMAND_PARAM) ; + return psf_get_format_simple (data) ; + + case SFC_GET_FORMAT_MAJOR_COUNT : + if (data == NULL || datasize != SIGNED_SIZEOF (int)) + return (sf_errno = SFE_BAD_COMMAND_PARAM) ; + *((int*) data) = psf_get_format_major_count () ; + return 0 ; + + case SFC_GET_FORMAT_MAJOR : + if (data == NULL || datasize != SIGNED_SIZEOF (SF_FORMAT_INFO)) + return (sf_errno = SFE_BAD_COMMAND_PARAM) ; + return psf_get_format_major (data) ; + + case SFC_GET_FORMAT_SUBTYPE_COUNT : + if (data == NULL || datasize != SIGNED_SIZEOF (int)) + return (sf_errno = SFE_BAD_COMMAND_PARAM) ; + *((int*) data) = psf_get_format_subtype_count () ; + return 0 ; + + case SFC_GET_FORMAT_SUBTYPE : + if (data == NULL || datasize != SIGNED_SIZEOF (SF_FORMAT_INFO)) + return (sf_errno = SFE_BAD_COMMAND_PARAM) ; + return psf_get_format_subtype (data) ; + + case SFC_GET_FORMAT_INFO : + if (data == NULL || datasize != SIGNED_SIZEOF (SF_FORMAT_INFO)) + return (sf_errno = SFE_BAD_COMMAND_PARAM) ; + return psf_get_format_info (data) ; + } ; + + if (sndfile == NULL && command == SFC_GET_LOG_INFO) + { if (data == NULL) + return (sf_errno = SFE_BAD_COMMAND_PARAM) ; + snprintf (data, datasize, "%s", sf_parselog) ; + return strlen (data) ; + } ; + + VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; + + switch (command) + { case SFC_SET_NORM_FLOAT : + old_value = psf->norm_float ; + psf->norm_float = (datasize) ? SF_TRUE : SF_FALSE ; + return old_value ; + + case SFC_GET_CURRENT_SF_INFO : + if (data == NULL || datasize != SIGNED_SIZEOF (SF_INFO)) + return (sf_errno = SFE_BAD_COMMAND_PARAM) ; + memcpy (data, &psf->sf, sizeof (SF_INFO)) ; + break ; + + case SFC_SET_NORM_DOUBLE : + old_value = psf->norm_double ; + psf->norm_double = (datasize) ? SF_TRUE : SF_FALSE ; + return old_value ; + + case SFC_GET_NORM_FLOAT : + return psf->norm_float ; + + case SFC_GET_NORM_DOUBLE : + return psf->norm_double ; + + case SFC_SET_SCALE_FLOAT_INT_READ : + old_value = psf->float_int_mult ; + + psf->float_int_mult = (datasize != 0) ? SF_TRUE : SF_FALSE ; + if (psf->float_int_mult && psf->float_max < 0.0) + /* Scale to prevent wrap-around distortion. */ + psf->float_max = (32768.0 / 32767.0) * psf_calc_signal_max (psf, SF_FALSE) ; + return old_value ; + + case SFC_SET_SCALE_INT_FLOAT_WRITE : + old_value = psf->scale_int_float ; + psf->scale_int_float = (datasize != 0) ? SF_TRUE : SF_FALSE ; + return old_value ; + + case SFC_SET_ADD_PEAK_CHUNK : + { int format = SF_CONTAINER (psf->sf.format) ; + + /* Only WAV and AIFF support the PEAK chunk. */ + switch (format) + { case SF_FORMAT_AIFF : + case SF_FORMAT_CAF : + case SF_FORMAT_WAV : + case SF_FORMAT_WAVEX : + case SF_FORMAT_RF64 : + break ; + + default : + return SF_FALSE ; + } ; + + format = SF_CODEC (psf->sf.format) ; + + /* Only files containg the following data types support the PEAK chunk. */ + if (format != SF_FORMAT_FLOAT && format != SF_FORMAT_DOUBLE) + return SF_FALSE ; + + } ; + /* Can only do this is in SFM_WRITE mode. */ + if (psf->file.mode != SFM_WRITE && psf->file.mode != SFM_RDWR) + return SF_FALSE ; + /* If data has already been written this must fail. */ + if (psf->have_written) + { psf->error = SFE_CMD_HAS_DATA ; + return SF_FALSE ; + } ; + /* Everything seems OK, so set psf->has_peak and re-write header. */ + if (datasize == SF_FALSE && psf->peak_info != NULL) + { free (psf->peak_info) ; + psf->peak_info = NULL ; + } + else if (psf->peak_info == NULL) + { psf->peak_info = peak_info_calloc (psf->sf.channels) ; + if (psf->peak_info != NULL) + psf->peak_info->peak_loc = SF_PEAK_START ; + } ; + + if (psf->write_header) + psf->write_header (psf, SF_TRUE) ; + return datasize ; + + case SFC_SET_ADD_HEADER_PAD_CHUNK : + return SF_FALSE ; + + case SFC_GET_LOG_INFO : + if (data == NULL) + return SFE_BAD_COMMAND_PARAM ; + snprintf (data, datasize, "%s", psf->parselog.buf) ; + return strlen (data) ; + + case SFC_CALC_SIGNAL_MAX : + if (data == NULL || datasize != sizeof (double)) + return (psf->error = SFE_BAD_COMMAND_PARAM) ; + *((double*) data) = psf_calc_signal_max (psf, SF_FALSE) ; + break ; + + case SFC_CALC_NORM_SIGNAL_MAX : + if (data == NULL || datasize != sizeof (double)) + return (psf->error = SFE_BAD_COMMAND_PARAM) ; + *((double*) data) = psf_calc_signal_max (psf, SF_TRUE) ; + break ; + + case SFC_CALC_MAX_ALL_CHANNELS : + if (data == NULL || datasize != SIGNED_SIZEOF (double) * psf->sf.channels) + return (psf->error = SFE_BAD_COMMAND_PARAM) ; + return psf_calc_max_all_channels (psf, (double*) data, SF_FALSE) ; + + case SFC_CALC_NORM_MAX_ALL_CHANNELS : + if (data == NULL || datasize != SIGNED_SIZEOF (double) * psf->sf.channels) + return (psf->error = SFE_BAD_COMMAND_PARAM) ; + return psf_calc_max_all_channels (psf, (double*) data, SF_TRUE) ; + + case SFC_GET_SIGNAL_MAX : + if (data == NULL || datasize != sizeof (double)) + { psf->error = SFE_BAD_COMMAND_PARAM ; + return SF_FALSE ; + } ; + return psf_get_signal_max (psf, (double *) data) ; + + case SFC_GET_MAX_ALL_CHANNELS : + if (data == NULL || datasize != SIGNED_SIZEOF (double) * psf->sf.channels) + { psf->error = SFE_BAD_COMMAND_PARAM ; + return SF_FALSE ; + } ; + return psf_get_max_all_channels (psf, (double*) data) ; + + case SFC_UPDATE_HEADER_NOW : + if (psf->write_header) + psf->write_header (psf, SF_TRUE) ; + break ; + + case SFC_SET_UPDATE_HEADER_AUTO : + psf->auto_header = datasize ? SF_TRUE : SF_FALSE ; + return psf->auto_header ; + break ; + + case SFC_SET_ADD_DITHER_ON_WRITE : + case SFC_SET_ADD_DITHER_ON_READ : + /* + ** FIXME ! + ** These are obsolete. Just return. + ** Remove some time after version 1.0.8. + */ + break ; + + case SFC_SET_DITHER_ON_WRITE : + if (data == NULL || datasize != SIGNED_SIZEOF (SF_DITHER_INFO)) + return (psf->error = SFE_BAD_COMMAND_PARAM) ; + memcpy (&psf->write_dither, data, sizeof (psf->write_dither)) ; + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + dither_init (psf, SFM_WRITE) ; + break ; + + case SFC_SET_DITHER_ON_READ : + if (data == NULL || datasize != SIGNED_SIZEOF (SF_DITHER_INFO)) + return (psf->error = SFE_BAD_COMMAND_PARAM) ; + memcpy (&psf->read_dither, data, sizeof (psf->read_dither)) ; + if (psf->file.mode == SFM_READ || psf->file.mode == SFM_RDWR) + dither_init (psf, SFM_READ) ; + break ; + + case SFC_FILE_TRUNCATE : + if (psf->file.mode != SFM_WRITE && psf->file.mode != SFM_RDWR) + return SF_TRUE ; + if (datasize != sizeof (sf_count_t)) + return SF_TRUE ; + if (data == NULL || datasize != sizeof (sf_count_t)) + { psf->error = SFE_BAD_COMMAND_PARAM ; + return SF_FALSE ; + } + else + { sf_count_t position ; + + position = *((sf_count_t*) data) ; + + if (sf_seek (sndfile, position, SEEK_SET) != position) + return SF_TRUE ; + + psf->sf.frames = position ; + + position = psf_fseek (psf, 0, SEEK_CUR) ; + + return psf_ftruncate (psf, position) ; + } ; + break ; + + case SFC_SET_RAW_START_OFFSET : + if (data == NULL || datasize != sizeof (sf_count_t)) + return (psf->error = SFE_BAD_COMMAND_PARAM) ; + + if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_RAW) + return (psf->error = SFE_BAD_COMMAND_PARAM) ; + + psf->dataoffset = *((sf_count_t*) data) ; + sf_seek (sndfile, 0, SEEK_CUR) ; + break ; + + case SFC_GET_EMBED_FILE_INFO : + if (data == NULL || datasize != sizeof (SF_EMBED_FILE_INFO)) + return (psf->error = SFE_BAD_COMMAND_PARAM) ; + + ((SF_EMBED_FILE_INFO*) data)->offset = psf->fileoffset ; + ((SF_EMBED_FILE_INFO*) data)->length = psf->filelength ; + break ; + + /* Lite remove start */ + case SFC_TEST_IEEE_FLOAT_REPLACE : + psf->ieee_replace = (datasize) ? SF_TRUE : SF_FALSE ; + if ((SF_CODEC (psf->sf.format)) == SF_FORMAT_FLOAT) + float32_init (psf) ; + else if ((SF_CODEC (psf->sf.format)) == SF_FORMAT_DOUBLE) + double64_init (psf) ; + else + return (psf->error = SFE_BAD_COMMAND_PARAM) ; + break ; + /* Lite remove end */ + + case SFC_SET_CLIPPING : + psf->add_clipping = (datasize) ? SF_TRUE : SF_FALSE ; + return psf->add_clipping ; + + case SFC_GET_CLIPPING : + return psf->add_clipping ; + + case SFC_GET_LOOP_INFO : + if (datasize != sizeof (SF_LOOP_INFO) || data == NULL) + { psf->error = SFE_BAD_COMMAND_PARAM ; + return SF_FALSE ; + } ; + if (psf->loop_info == NULL) + return SF_FALSE ; + memcpy (data, psf->loop_info, sizeof (SF_LOOP_INFO)) ; + return SF_TRUE ; + + case SFC_SET_BROADCAST_INFO : + { int format = SF_CONTAINER (psf->sf.format) ; + + /* Only WAV and RF64 supports the BEXT (Broadcast) chunk. */ + if (format != SF_FORMAT_WAV && format != SF_FORMAT_WAVEX && format != SF_FORMAT_RF64) + return SF_FALSE ; + } ; + + /* Only makes sense in SFM_WRITE or SFM_RDWR mode. */ + if ((psf->file.mode != SFM_WRITE) && (psf->file.mode != SFM_RDWR)) + return SF_FALSE ; + /* If data has already been written this must fail. */ + if (psf->broadcast_16k == NULL && psf->have_written) + { psf->error = SFE_CMD_HAS_DATA ; + return SF_FALSE ; + } ; + + if (!broadcast_var_set (psf, data, datasize)) + return SF_FALSE ; + + if (psf->write_header) + psf->write_header (psf, SF_TRUE) ; + return SF_TRUE ; + + case SFC_GET_BROADCAST_INFO : + if (data == NULL) + { psf->error = SFE_BAD_COMMAND_PARAM ; + return SF_FALSE ; + } ; + return broadcast_var_get (psf, data, datasize) ; + + case SFC_SET_CART_INFO : + { int format = SF_CONTAINER (psf->sf.format) ; + /* Only WAV and RF64 support cart chunk format */ + if (format != SF_FORMAT_WAV && format != SF_FORMAT_RF64) + return SF_FALSE ; + } ; + + /* Only makes sense in SFM_WRITE or SFM_RDWR mode */ + if ((psf->file.mode != SFM_WRITE) && (psf->file.mode != SFM_RDWR)) + return SF_FALSE ; + /* If data has already been written this must fail. */ + if (psf->cart_16k == NULL && psf->have_written) + { psf->error = SFE_CMD_HAS_DATA ; + return SF_FALSE ; + } ; + if (!cart_var_set (psf, data, datasize)) + return SF_FALSE ; + if (psf->write_header) + psf->write_header (psf, SF_TRUE) ; + return SF_TRUE ; + + case SFC_GET_CART_INFO : + if (data == NULL) + { psf->error = SFE_BAD_COMMAND_PARAM ; + return SF_FALSE ; + } ; + return cart_var_get (psf, data, datasize) ; + + case SFC_GET_CUE_COUNT : + if (datasize != sizeof (uint32_t) || data == NULL) + { psf->error = SFE_BAD_COMMAND_PARAM ; + return SF_FALSE ; + } ; + if (psf->cues != NULL) + { *((uint32_t *) data) = psf->cues->cue_count ; + return SF_TRUE ; + } ; + return SF_FALSE ; + + case SFC_GET_CUE : + if (datasize < (int) sizeof (uint32_t) || data == NULL) + { psf->error = SFE_BAD_COMMAND_PARAM ; + return SF_FALSE ; + } ; + if (psf->cues == NULL) + return SF_FALSE ; + psf_get_cues (psf, data, datasize) ; + return SF_TRUE ; + + case SFC_SET_CUE : + if (psf->have_written) + { psf->error = SFE_CMD_HAS_DATA ; + return SF_FALSE ; + } ; + if (datasize < (int) sizeof (uint32_t) || data == NULL) + { psf->error = SFE_BAD_COMMAND_PARAM ; + return SF_FALSE ; + } ; + if (psf->cues == NULL && (psf->cues = psf_cues_dup (data, datasize)) == NULL) + { psf->error = SFE_MALLOC_FAILED ; + return SF_FALSE ; + } ; + return SF_TRUE ; + + case SFC_GET_INSTRUMENT : + if (datasize != sizeof (SF_INSTRUMENT) || data == NULL) + { psf->error = SFE_BAD_COMMAND_PARAM ; + return SF_FALSE ; + } ; + if (psf->instrument == NULL) + return SF_FALSE ; + memcpy (data, psf->instrument, sizeof (SF_INSTRUMENT)) ; + return SF_TRUE ; + + case SFC_SET_INSTRUMENT : + /* If data has already been written this must fail. */ + if (psf->have_written) + { psf->error = SFE_CMD_HAS_DATA ; + return SF_FALSE ; + } ; + if (datasize != sizeof (SF_INSTRUMENT) || data == NULL) + { psf->error = SFE_BAD_COMMAND_PARAM ; + return SF_FALSE ; + } ; + + if (psf->instrument == NULL && (psf->instrument = psf_instrument_alloc ()) == NULL) + { psf->error = SFE_MALLOC_FAILED ; + return SF_FALSE ; + } ; + memcpy (psf->instrument, data, sizeof (SF_INSTRUMENT)) ; + return SF_TRUE ; + + case SFC_RAW_DATA_NEEDS_ENDSWAP : + return psf->data_endswap ; + + case SFC_GET_CHANNEL_MAP_INFO : + if (psf->channel_map == NULL) + return SF_FALSE ; + + if (data == NULL || datasize != SIGNED_SIZEOF (psf->channel_map [0]) * psf->sf.channels) + { psf->error = SFE_BAD_COMMAND_PARAM ; + return SF_FALSE ; + } ; + + memcpy (data, psf->channel_map, datasize) ; + return SF_TRUE ; + + case SFC_SET_CHANNEL_MAP_INFO : + if (psf->have_written) + { psf->error = SFE_CMD_HAS_DATA ; + return SF_FALSE ; + } ; + if (data == NULL || datasize != SIGNED_SIZEOF (psf->channel_map [0]) * psf->sf.channels) + { psf->error = SFE_BAD_COMMAND_PARAM ; + return SF_FALSE ; + } ; + + { int *iptr ; + + for (iptr = data ; iptr < (int*) data + psf->sf.channels ; iptr++) + { if (*iptr <= SF_CHANNEL_MAP_INVALID || *iptr >= SF_CHANNEL_MAP_MAX) + { psf->error = SFE_BAD_COMMAND_PARAM ; + return SF_FALSE ; + } ; + } ; + } ; + + free (psf->channel_map) ; + if ((psf->channel_map = malloc (datasize)) == NULL) + { psf->error = SFE_MALLOC_FAILED ; + return SF_FALSE ; + } ; + + memcpy (psf->channel_map, data, datasize) ; + + /* + ** Pass the command down to the container's command handler. + ** Don't pass user data, use validated psf->channel_map data instead. + */ + if (psf->command) + return psf->command (psf, command, NULL, 0) ; + return SF_FALSE ; + + case SFC_SET_VBR_ENCODING_QUALITY : + if (data == NULL || datasize != sizeof (double)) + return SF_FALSE ; + + quality = *((double *) data) ; + quality = 1.0 - SF_MAX (0.0, SF_MIN (1.0, quality)) ; + return sf_command (sndfile, SFC_SET_COMPRESSION_LEVEL, &quality, sizeof (quality)) ; + + case SFC_SET_OGG_PAGE_LATENCY_MS : + if (data == NULL || datasize != sizeof (double)) + return SF_FALSE ; + + latency = *((double *) data) ; + return sf_command (sndfile, SFC_SET_OGG_PAGE_LATENCY, &latency, sizeof (latency)) ; + + default : + /* Must be a file specific command. Pass it on. */ + if (psf->command) + return psf->command (psf, command, data, datasize) ; + + psf_log_printf (psf, "*** sf_command : cmd = 0x%X\n", command) ; + return (psf->error = SFE_BAD_COMMAND_PARAM) ; + } ; + + return 0 ; +} /* sf_command */ + +/*------------------------------------------------------------------------------ +*/ + +sf_count_t +sf_seek (SNDFILE *sndfile, sf_count_t offset, int whence) +{ SF_PRIVATE *psf ; + sf_count_t seek_from_start = 0, retval ; + + VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; + + if (! psf->sf.seekable) + { psf->error = SFE_NOT_SEEKABLE ; + return PSF_SEEK_ERROR ; + } ; + + /* If the whence parameter has a mode ORed in, check to see that + ** it makes sense. + */ + if (((whence & SFM_MASK) == SFM_WRITE && psf->file.mode == SFM_READ) || + ((whence & SFM_MASK) == SFM_READ && psf->file.mode == SFM_WRITE)) + { psf->error = SFE_WRONG_SEEK ; + return PSF_SEEK_ERROR ; + } ; + + /* Convert all SEEK_CUR and SEEK_END into seek_from_start to be + ** used with SEEK_SET. + */ + switch (whence) + { /* The SEEK_SET behaviour is independant of mode. */ + case SEEK_SET : + case SEEK_SET | SFM_READ : + case SEEK_SET | SFM_WRITE : + case SEEK_SET | SFM_RDWR : + seek_from_start = offset ; + break ; + + /* The SEEK_CUR is a little more tricky. */ + case SEEK_CUR : + if (offset == 0) + { if (psf->file.mode == SFM_READ) + return psf->read_current ; + if (psf->file.mode == SFM_WRITE) + return psf->write_current ; + } ; + if (psf->file.mode == SFM_READ) + seek_from_start = psf->read_current + offset ; + else if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + seek_from_start = psf->write_current + offset ; + else + psf->error = SFE_AMBIGUOUS_SEEK ; + break ; + + case SEEK_CUR | SFM_READ : + if (offset == 0) + return psf->read_current ; + seek_from_start = psf->read_current + offset ; + break ; + + case SEEK_CUR | SFM_WRITE : + if (offset == 0) + return psf->write_current ; + seek_from_start = psf->write_current + offset ; + break ; + + /* The SEEK_END */ + case SEEK_END : + case SEEK_END | SFM_READ : + case SEEK_END | SFM_WRITE : + seek_from_start = psf->sf.frames + offset ; + break ; + + default : + psf->error = SFE_BAD_SEEK ; + break ; + } ; + + if (psf->error) + return PSF_SEEK_ERROR ; + + if (psf->file.mode == SFM_RDWR || psf->file.mode == SFM_WRITE) + { if (seek_from_start < 0) + { psf->error = SFE_BAD_SEEK ; + return PSF_SEEK_ERROR ; + } ; + } + else if (seek_from_start < 0 || seek_from_start > psf->sf.frames) + { psf->error = SFE_BAD_SEEK ; + return PSF_SEEK_ERROR ; + } ; + + if (psf->seek) + { int new_mode = (whence & SFM_MASK) ? (whence & SFM_MASK) : psf->file.mode ; + + retval = psf->seek (psf, new_mode, seek_from_start) ; + + switch (new_mode) + { case SFM_READ : + psf->read_current = retval ; + break ; + case SFM_WRITE : + psf->write_current = retval ; + break ; + case SFM_RDWR : + psf->read_current = retval ; + psf->write_current = retval ; + new_mode = SFM_READ ; + break ; + } ; + + psf->last_op = new_mode ; + + return retval ; + } ; + + psf->error = SFE_AMBIGUOUS_SEEK ; + return PSF_SEEK_ERROR ; +} /* sf_seek */ + +/*------------------------------------------------------------------------------ +*/ + +const char* +sf_get_string (SNDFILE *sndfile, int str_type) +{ SF_PRIVATE *psf ; + + if ((psf = (SF_PRIVATE*) sndfile) == NULL) + return NULL ; + if (psf->Magick != SNDFILE_MAGICK) + return NULL ; + + return psf_get_string (psf, str_type) ; +} /* sf_get_string */ + +int +sf_set_string (SNDFILE *sndfile, int str_type, const char* str) +{ SF_PRIVATE *psf ; + + VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; + + return psf_set_string (psf, str_type, str) ; +} /* sf_get_string */ + +/*------------------------------------------------------------------------------ +*/ + +int +sf_current_byterate (SNDFILE *sndfile) +{ SF_PRIVATE *psf ; + + if ((psf = (SF_PRIVATE*) sndfile) == NULL) + return -1 ; + if (psf->Magick != SNDFILE_MAGICK) + return -1 ; + + /* This should cover all PCM and floating point formats. */ + if (psf->bytewidth) + return psf->sf.samplerate * psf->sf.channels * psf->bytewidth ; + + if (psf->byterate) + return psf->byterate (psf) ; + + switch (SF_CODEC (psf->sf.format)) + { case SF_FORMAT_IMA_ADPCM : + case SF_FORMAT_MS_ADPCM : + case SF_FORMAT_VOX_ADPCM : + return (psf->sf.samplerate * psf->sf.channels) / 2 ; + + case SF_FORMAT_GSM610 : + return (psf->sf.samplerate * psf->sf.channels * 13000) / 8000 ; + + case SF_FORMAT_NMS_ADPCM_16: + return psf->sf.samplerate / 4 + 10 ; + + case SF_FORMAT_NMS_ADPCM_24: + return psf->sf.samplerate * 3 / 8 + 10 ; + + case SF_FORMAT_NMS_ADPCM_32: + return psf->sf.samplerate / 2 + 10 ; + + case SF_FORMAT_G721_32 : /* 32kbs G721 ADPCM encoding. */ + return (psf->sf.samplerate * psf->sf.channels) / 2 ; + + case SF_FORMAT_G723_24 : /* 24kbs G723 ADPCM encoding. */ + return (psf->sf.samplerate * psf->sf.channels * 3) / 8 ; + + case SF_FORMAT_G723_40 : /* 40kbs G723 ADPCM encoding. */ + return (psf->sf.samplerate * psf->sf.channels * 5) / 8 ; + + default : + break ; + } ; + + return -1 ; +} /* sf_current_byterate */ + +/*============================================================================== +*/ + +sf_count_t +sf_read_raw (SNDFILE *sndfile, void *ptr, sf_count_t bytes) +{ SF_PRIVATE *psf ; + sf_count_t count, extra ; + int bytewidth, blockwidth ; + + if (bytes == 0) + return 0 ; + + VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; + + bytewidth = (psf->bytewidth > 0) ? psf->bytewidth : 1 ; + blockwidth = (psf->blockwidth > 0) ? psf->blockwidth : 1 ; + + if (psf->file.mode == SFM_WRITE) + { psf->error = SFE_NOT_READMODE ; + return 0 ; + } ; + + if (bytes < 0 || psf->read_current >= psf->sf.frames) + { psf_memset (ptr, 0, bytes) ; + return 0 ; + } ; + + if (bytes % (psf->sf.channels * bytewidth)) + { psf->error = SFE_BAD_READ_ALIGN ; + return 0 ; + } ; + + if (psf->last_op != SFM_READ) + if (psf->seek (psf, SFM_READ, psf->read_current) < 0) + return 0 ; + + count = psf_fread (ptr, 1, bytes, psf) ; + + if (psf->read_current + count / blockwidth <= psf->sf.frames) + psf->read_current += count / blockwidth ; + else + { count = (psf->sf.frames - psf->read_current) * blockwidth ; + extra = bytes - count ; + psf_memset (((char *) ptr) + count, 0, extra) ; + psf->read_current = psf->sf.frames ; + } ; + + psf->last_op = SFM_READ ; + + return count ; +} /* sf_read_raw */ + +/*------------------------------------------------------------------------------ +*/ + +sf_count_t +sf_read_short (SNDFILE *sndfile, short *ptr, sf_count_t len) +{ SF_PRIVATE *psf ; + sf_count_t count, extra ; + + if (len == 0) + return 0 ; + + VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; + + if (len <= 0) + { psf->error = SFE_NEGATIVE_RW_LEN ; + return 0 ; + } ; + + if (psf->file.mode == SFM_WRITE) + { psf->error = SFE_NOT_READMODE ; + return 0 ; + } ; + + if (len % psf->sf.channels) + { psf->error = SFE_BAD_READ_ALIGN ; + return 0 ; + } ; + + if (psf->read_current >= psf->sf.frames) + { psf_memset (ptr, 0, len * sizeof (short)) ; + return 0 ; /* End of file. */ + } ; + + if (psf->read_short == NULL || psf->seek == NULL) + { psf->error = SFE_UNIMPLEMENTED ; + return 0 ; + } ; + + if (psf->last_op != SFM_READ) + if (psf->seek (psf, SFM_READ, psf->read_current) < 0) + return 0 ; + + count = psf->read_short (psf, ptr, len) ; + + if (psf->read_current + count / psf->sf.channels <= psf->sf.frames) + psf->read_current += count / psf->sf.channels ; + else + { count = (psf->sf.frames - psf->read_current) * psf->sf.channels ; + extra = len - count ; + psf_memset (ptr + count, 0, extra * sizeof (short)) ; + psf->read_current = psf->sf.frames ; + } ; + + psf->last_op = SFM_READ ; + + return count ; +} /* sf_read_short */ + +sf_count_t +sf_readf_short (SNDFILE *sndfile, short *ptr, sf_count_t frames) +{ SF_PRIVATE *psf ; + sf_count_t count, extra ; + + if (frames == 0) + return 0 ; + + VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; + + if (frames <= 0) + { psf->error = SFE_NEGATIVE_RW_LEN ; + return 0 ; + } ; + + if (psf->file.mode == SFM_WRITE) + { psf->error = SFE_NOT_READMODE ; + return 0 ; + } ; + + if (psf->read_current >= psf->sf.frames) + { psf_memset (ptr, 0, frames * psf->sf.channels * sizeof (short)) ; + return 0 ; /* End of file. */ + } ; + + if (psf->read_short == NULL || psf->seek == NULL) + { psf->error = SFE_UNIMPLEMENTED ; + return 0 ; + } ; + + if (psf->last_op != SFM_READ) + if (psf->seek (psf, SFM_READ, psf->read_current) < 0) + return 0 ; + + count = psf->read_short (psf, ptr, frames * psf->sf.channels) ; + + if (psf->read_current + count / psf->sf.channels <= psf->sf.frames) + psf->read_current += count / psf->sf.channels ; + else + { count = (psf->sf.frames - psf->read_current) * psf->sf.channels ; + extra = frames * psf->sf.channels - count ; + psf_memset (ptr + count, 0, extra * sizeof (short)) ; + psf->read_current = psf->sf.frames ; + } ; + + psf->last_op = SFM_READ ; + + return count / psf->sf.channels ; +} /* sf_readf_short */ + +/*------------------------------------------------------------------------------ +*/ + +sf_count_t +sf_read_int (SNDFILE *sndfile, int *ptr, sf_count_t len) +{ SF_PRIVATE *psf ; + sf_count_t count, extra ; + + if (len == 0) + return 0 ; + + VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; + + if (len <= 0) + { psf->error = SFE_NEGATIVE_RW_LEN ; + return 0 ; + } ; + + if (psf->file.mode == SFM_WRITE) + { psf->error = SFE_NOT_READMODE ; + return 0 ; + } ; + + if (len % psf->sf.channels) + { psf->error = SFE_BAD_READ_ALIGN ; + return 0 ; + } ; + + if (psf->read_current >= psf->sf.frames) + { psf_memset (ptr, 0, len * sizeof (int)) ; + return 0 ; + } ; + + if (psf->read_int == NULL || psf->seek == NULL) + { psf->error = SFE_UNIMPLEMENTED ; + return 0 ; + } ; + + if (psf->last_op != SFM_READ) + if (psf->seek (psf, SFM_READ, psf->read_current) < 0) + return 0 ; + + count = psf->read_int (psf, ptr, len) ; + + if (psf->read_current + count / psf->sf.channels <= psf->sf.frames) + psf->read_current += count / psf->sf.channels ; + else + { count = (psf->sf.frames - psf->read_current) * psf->sf.channels ; + extra = len - count ; + psf_memset (ptr + count, 0, extra * sizeof (int)) ; + psf->read_current = psf->sf.frames ; + } ; + + psf->last_op = SFM_READ ; + + return count ; +} /* sf_read_int */ + +sf_count_t +sf_readf_int (SNDFILE *sndfile, int *ptr, sf_count_t frames) +{ SF_PRIVATE *psf ; + sf_count_t count, extra ; + + if (frames == 0) + return 0 ; + + VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; + + if (frames <= 0) + { psf->error = SFE_NEGATIVE_RW_LEN ; + return 0 ; + } ; + + if (psf->file.mode == SFM_WRITE) + { psf->error = SFE_NOT_READMODE ; + return 0 ; + } ; + + if (psf->read_current >= psf->sf.frames) + { psf_memset (ptr, 0, frames * psf->sf.channels * sizeof (int)) ; + return 0 ; + } ; + + if (psf->read_int == NULL || psf->seek == NULL) + { psf->error = SFE_UNIMPLEMENTED ; + return 0 ; + } ; + + if (psf->last_op != SFM_READ) + if (psf->seek (psf, SFM_READ, psf->read_current) < 0) + return 0 ; + + count = psf->read_int (psf, ptr, frames * psf->sf.channels) ; + + if (psf->read_current + count / psf->sf.channels <= psf->sf.frames) + psf->read_current += count / psf->sf.channels ; + else + { count = (psf->sf.frames - psf->read_current) * psf->sf.channels ; + extra = frames * psf->sf.channels - count ; + psf_memset (ptr + count, 0, extra * sizeof (int)) ; + psf->read_current = psf->sf.frames ; + } ; + + psf->last_op = SFM_READ ; + + return count / psf->sf.channels ; +} /* sf_readf_int */ + +/*------------------------------------------------------------------------------ +*/ + +sf_count_t +sf_read_float (SNDFILE *sndfile, float *ptr, sf_count_t len) +{ SF_PRIVATE *psf ; + sf_count_t count, extra ; + + if (len == 0) + return 0 ; + + VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; + + if (len <= 0) + { psf->error = SFE_NEGATIVE_RW_LEN ; + return 0 ; + } ; + + if (psf->file.mode == SFM_WRITE) + { psf->error = SFE_NOT_READMODE ; + return 0 ; + } ; + + if (len % psf->sf.channels) + { psf->error = SFE_BAD_READ_ALIGN ; + return 0 ; + } ; + + if (psf->read_current >= psf->sf.frames) + { psf_memset (ptr, 0, len * sizeof (float)) ; + return 0 ; + } ; + + if (psf->read_float == NULL || psf->seek == NULL) + { psf->error = SFE_UNIMPLEMENTED ; + return 0 ; + } ; + + if (psf->last_op != SFM_READ) + if (psf->seek (psf, SFM_READ, psf->read_current) < 0) + return 0 ; + + count = psf->read_float (psf, ptr, len) ; + + if (psf->read_current + count / psf->sf.channels <= psf->sf.frames) + psf->read_current += count / psf->sf.channels ; + else + { count = (psf->sf.frames - psf->read_current) * psf->sf.channels ; + extra = len - count ; + psf_memset (ptr + count, 0, extra * sizeof (float)) ; + psf->read_current = psf->sf.frames ; + } ; + + psf->last_op = SFM_READ ; + + return count ; +} /* sf_read_float */ + +sf_count_t +sf_readf_float (SNDFILE *sndfile, float *ptr, sf_count_t frames) +{ SF_PRIVATE *psf ; + sf_count_t count, extra ; + + if (frames == 0) + return 0 ; + + VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; + + if (frames <= 0) + { psf->error = SFE_NEGATIVE_RW_LEN ; + return 0 ; + } ; + + if (psf->file.mode == SFM_WRITE) + { psf->error = SFE_NOT_READMODE ; + return 0 ; + } ; + + if (psf->read_current >= psf->sf.frames) + { psf_memset (ptr, 0, frames * psf->sf.channels * sizeof (float)) ; + return 0 ; + } ; + + if (psf->read_float == NULL || psf->seek == NULL) + { psf->error = SFE_UNIMPLEMENTED ; + return 0 ; + } ; + + if (psf->last_op != SFM_READ) + if (psf->seek (psf, SFM_READ, psf->read_current) < 0) + return 0 ; + + count = psf->read_float (psf, ptr, frames * psf->sf.channels) ; + + if (psf->read_current + count / psf->sf.channels <= psf->sf.frames) + psf->read_current += count / psf->sf.channels ; + else + { count = (psf->sf.frames - psf->read_current) * psf->sf.channels ; + extra = frames * psf->sf.channels - count ; + psf_memset (ptr + count, 0, extra * sizeof (float)) ; + psf->read_current = psf->sf.frames ; + } ; + + psf->last_op = SFM_READ ; + + return count / psf->sf.channels ; +} /* sf_readf_float */ + +/*------------------------------------------------------------------------------ +*/ + +sf_count_t +sf_read_double (SNDFILE *sndfile, double *ptr, sf_count_t len) +{ SF_PRIVATE *psf ; + sf_count_t count, extra ; + + if (len == 0) + return 0 ; + + VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; + + if (len <= 0) + { psf->error = SFE_NEGATIVE_RW_LEN ; + return 0 ; + } ; + + if (psf->file.mode == SFM_WRITE) + { psf->error = SFE_NOT_READMODE ; + return 0 ; + } ; + + if (len % psf->sf.channels) + { psf->error = SFE_BAD_READ_ALIGN ; + return 0 ; + } ; + + if (psf->read_current >= psf->sf.frames) + { psf_memset (ptr, 0, len * sizeof (double)) ; + return 0 ; + } ; + + if (psf->read_double == NULL || psf->seek == NULL) + { psf->error = SFE_UNIMPLEMENTED ; + return 0 ; + } ; + + if (psf->last_op != SFM_READ) + if (psf->seek (psf, SFM_READ, psf->read_current) < 0) + return 0 ; + + count = psf->read_double (psf, ptr, len) ; + + if (psf->read_current + count / psf->sf.channels <= psf->sf.frames) + psf->read_current += count / psf->sf.channels ; + else + { count = (psf->sf.frames - psf->read_current) * psf->sf.channels ; + extra = len - count ; + psf_memset (ptr + count, 0, extra * sizeof (double)) ; + psf->read_current = psf->sf.frames ; + } ; + + psf->last_op = SFM_READ ; + + return count ; +} /* sf_read_double */ + +sf_count_t +sf_readf_double (SNDFILE *sndfile, double *ptr, sf_count_t frames) +{ SF_PRIVATE *psf ; + sf_count_t count, extra ; + + if (frames == 0) + return 0 ; + + VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; + + if (frames <= 0) + { psf->error = SFE_NEGATIVE_RW_LEN ; + return 0 ; + } ; + + if (psf->file.mode == SFM_WRITE) + { psf->error = SFE_NOT_READMODE ; + return 0 ; + } ; + + if (psf->read_current >= psf->sf.frames) + { psf_memset (ptr, 0, frames * psf->sf.channels * sizeof (double)) ; + return 0 ; + } ; + + if (psf->read_double == NULL || psf->seek == NULL) + { psf->error = SFE_UNIMPLEMENTED ; + return 0 ; + } ; + + if (psf->last_op != SFM_READ) + if (psf->seek (psf, SFM_READ, psf->read_current) < 0) + return 0 ; + + count = psf->read_double (psf, ptr, frames * psf->sf.channels) ; + + if (psf->read_current + count / psf->sf.channels <= psf->sf.frames) + psf->read_current += count / psf->sf.channels ; + else + { count = (psf->sf.frames - psf->read_current) * psf->sf.channels ; + extra = frames * psf->sf.channels - count ; + psf_memset (ptr + count, 0, extra * sizeof (double)) ; + psf->read_current = psf->sf.frames ; + } ; + + psf->last_op = SFM_READ ; + + return count / psf->sf.channels ; +} /* sf_readf_double */ + +/*------------------------------------------------------------------------------ +*/ + +sf_count_t +sf_write_raw (SNDFILE *sndfile, const void *ptr, sf_count_t len) +{ SF_PRIVATE *psf ; + sf_count_t count ; + int bytewidth, blockwidth ; + + if (len == 0) + return 0 ; + + VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; + + if (len <= 0) + { psf->error = SFE_NEGATIVE_RW_LEN ; + return 0 ; + } ; + + bytewidth = (psf->bytewidth > 0) ? psf->bytewidth : 1 ; + blockwidth = (psf->blockwidth > 0) ? psf->blockwidth : 1 ; + + if (psf->file.mode == SFM_READ) + { psf->error = SFE_NOT_WRITEMODE ; + return 0 ; + } ; + + if (len % (psf->sf.channels * bytewidth)) + { psf->error = SFE_BAD_WRITE_ALIGN ; + return 0 ; + } ; + + if (psf->last_op != SFM_WRITE) + if (psf->seek (psf, SFM_WRITE, psf->write_current) < 0) + return 0 ; + + if (psf->have_written == SF_FALSE && psf->write_header != NULL) + { if ((psf->error = psf->write_header (psf, SF_FALSE))) + return 0 ; + } ; + psf->have_written = SF_TRUE ; + + count = psf_fwrite (ptr, 1, len, psf) ; + + psf->write_current += count / blockwidth ; + + psf->last_op = SFM_WRITE ; + + if (psf->write_current > psf->sf.frames) + { psf->sf.frames = psf->write_current ; + psf->dataend = 0 ; + } ; + + if (psf->auto_header && psf->write_header != NULL) + psf->write_header (psf, SF_TRUE) ; + + return count ; +} /* sf_write_raw */ + +/*------------------------------------------------------------------------------ +*/ + +sf_count_t +sf_write_short (SNDFILE *sndfile, const short *ptr, sf_count_t len) +{ SF_PRIVATE *psf ; + sf_count_t count ; + + if (len == 0) + return 0 ; + + VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; + + if (len <= 0) + { psf->error = SFE_NEGATIVE_RW_LEN ; + return 0 ; + } ; + + if (psf->file.mode == SFM_READ) + { psf->error = SFE_NOT_WRITEMODE ; + return 0 ; + } ; + + if (len % psf->sf.channels) + { psf->error = SFE_BAD_WRITE_ALIGN ; + return 0 ; + } ; + + if (psf->write_short == NULL || psf->seek == NULL) + { psf->error = SFE_UNIMPLEMENTED ; + return 0 ; + } ; + + if (psf->last_op != SFM_WRITE) + if (psf->seek (psf, SFM_WRITE, psf->write_current) < 0) + return 0 ; + + if (psf->have_written == SF_FALSE && psf->write_header != NULL) + { if ((psf->error = psf->write_header (psf, SF_FALSE))) + return 0 ; + } ; + psf->have_written = SF_TRUE ; + + count = psf->write_short (psf, ptr, len) ; + + psf->write_current += count / psf->sf.channels ; + + psf->last_op = SFM_WRITE ; + + if (psf->write_current > psf->sf.frames) + { psf->sf.frames = psf->write_current ; + psf->dataend = 0 ; + } ; + + if (psf->auto_header && psf->write_header != NULL) + psf->write_header (psf, SF_TRUE) ; + + return count ; +} /* sf_write_short */ + +sf_count_t +sf_writef_short (SNDFILE *sndfile, const short *ptr, sf_count_t frames) +{ SF_PRIVATE *psf ; + sf_count_t count ; + + if (frames == 0) + return 0 ; + + VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; + + if (frames <= 0) + { psf->error = SFE_NEGATIVE_RW_LEN ; + return 0 ; + } ; + + if (psf->file.mode == SFM_READ) + { psf->error = SFE_NOT_WRITEMODE ; + return 0 ; + } ; + + if (psf->write_short == NULL || psf->seek == NULL) + { psf->error = SFE_UNIMPLEMENTED ; + return 0 ; + } ; + + if (psf->last_op != SFM_WRITE) + if (psf->seek (psf, SFM_WRITE, psf->write_current) < 0) + return 0 ; + + if (psf->have_written == SF_FALSE && psf->write_header != NULL) + { if ((psf->error = psf->write_header (psf, SF_FALSE))) + return 0 ; + } ; + psf->have_written = SF_TRUE ; + + count = psf->write_short (psf, ptr, frames * psf->sf.channels) ; + + psf->write_current += count / psf->sf.channels ; + + psf->last_op = SFM_WRITE ; + + if (psf->write_current > psf->sf.frames) + { psf->sf.frames = psf->write_current ; + psf->dataend = 0 ; + } ; + + if (psf->auto_header && psf->write_header != NULL) + psf->write_header (psf, SF_TRUE) ; + + return count / psf->sf.channels ; +} /* sf_writef_short */ + +/*------------------------------------------------------------------------------ +*/ + +sf_count_t +sf_write_int (SNDFILE *sndfile, const int *ptr, sf_count_t len) +{ SF_PRIVATE *psf ; + sf_count_t count ; + + if (len == 0) + return 0 ; + + VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; + + if (len <= 0) + { psf->error = SFE_NEGATIVE_RW_LEN ; + return 0 ; + } ; + + if (psf->file.mode == SFM_READ) + { psf->error = SFE_NOT_WRITEMODE ; + return 0 ; + } ; + + if (len % psf->sf.channels) + { psf->error = SFE_BAD_WRITE_ALIGN ; + return 0 ; + } ; + + if (psf->write_int == NULL || psf->seek == NULL) + { psf->error = SFE_UNIMPLEMENTED ; + return 0 ; + } ; + + if (psf->last_op != SFM_WRITE) + if (psf->seek (psf, SFM_WRITE, psf->write_current) < 0) + return 0 ; + + if (psf->have_written == SF_FALSE && psf->write_header != NULL) + { if ((psf->error = psf->write_header (psf, SF_FALSE))) + return 0 ; + } ; + psf->have_written = SF_TRUE ; + + count = psf->write_int (psf, ptr, len) ; + + psf->write_current += count / psf->sf.channels ; + + psf->last_op = SFM_WRITE ; + + if (psf->write_current > psf->sf.frames) + { psf->sf.frames = psf->write_current ; + psf->dataend = 0 ; + } ; + + if (psf->auto_header && psf->write_header != NULL) + psf->write_header (psf, SF_TRUE) ; + + return count ; +} /* sf_write_int */ + +sf_count_t +sf_writef_int (SNDFILE *sndfile, const int *ptr, sf_count_t frames) +{ SF_PRIVATE *psf ; + sf_count_t count ; + + if (frames == 0) + return 0 ; + + VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; + + if (frames <= 0) + { psf->error = SFE_NEGATIVE_RW_LEN ; + return 0 ; + } ; + + if (psf->file.mode == SFM_READ) + { psf->error = SFE_NOT_WRITEMODE ; + return 0 ; + } ; + + if (psf->write_int == NULL || psf->seek == NULL) + { psf->error = SFE_UNIMPLEMENTED ; + return 0 ; + } ; + + if (psf->last_op != SFM_WRITE) + if (psf->seek (psf, SFM_WRITE, psf->write_current) < 0) + return 0 ; + + if (psf->have_written == SF_FALSE && psf->write_header != NULL) + { if ((psf->error = psf->write_header (psf, SF_FALSE))) + return 0 ; + } ; + psf->have_written = SF_TRUE ; + + count = psf->write_int (psf, ptr, frames * psf->sf.channels) ; + + psf->write_current += count / psf->sf.channels ; + + psf->last_op = SFM_WRITE ; + + if (psf->write_current > psf->sf.frames) + { psf->sf.frames = psf->write_current ; + psf->dataend = 0 ; + } ; + + if (psf->auto_header && psf->write_header != NULL) + psf->write_header (psf, SF_TRUE) ; + + return count / psf->sf.channels ; +} /* sf_writef_int */ + +/*------------------------------------------------------------------------------ +*/ + +sf_count_t +sf_write_float (SNDFILE *sndfile, const float *ptr, sf_count_t len) +{ SF_PRIVATE *psf ; + sf_count_t count ; + + if (len == 0) + return 0 ; + + VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; + + if (len <= 0) + { psf->error = SFE_NEGATIVE_RW_LEN ; + return 0 ; + } ; + + if (psf->file.mode == SFM_READ) + { psf->error = SFE_NOT_WRITEMODE ; + return 0 ; + } ; + + if (len % psf->sf.channels) + { psf->error = SFE_BAD_WRITE_ALIGN ; + return 0 ; + } ; + + if (psf->write_float == NULL || psf->seek == NULL) + { psf->error = SFE_UNIMPLEMENTED ; + return 0 ; + } ; + + if (psf->last_op != SFM_WRITE) + if (psf->seek (psf, SFM_WRITE, psf->write_current) < 0) + return 0 ; + + if (psf->have_written == SF_FALSE && psf->write_header != NULL) + { if ((psf->error = psf->write_header (psf, SF_FALSE))) + return 0 ; + } ; + psf->have_written = SF_TRUE ; + + count = psf->write_float (psf, ptr, len) ; + + psf->write_current += count / psf->sf.channels ; + + psf->last_op = SFM_WRITE ; + + if (psf->write_current > psf->sf.frames) + { psf->sf.frames = psf->write_current ; + psf->dataend = 0 ; + } ; + + if (psf->auto_header && psf->write_header != NULL) + psf->write_header (psf, SF_TRUE) ; + + return count ; +} /* sf_write_float */ + +sf_count_t +sf_writef_float (SNDFILE *sndfile, const float *ptr, sf_count_t frames) +{ SF_PRIVATE *psf ; + sf_count_t count ; + + if (frames == 0) + return 0 ; + + VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; + + if (frames <= 0) + { psf->error = SFE_NEGATIVE_RW_LEN ; + return 0 ; + } ; + + if (psf->file.mode == SFM_READ) + { psf->error = SFE_NOT_WRITEMODE ; + return 0 ; + } ; + + if (psf->write_float == NULL || psf->seek == NULL) + { psf->error = SFE_UNIMPLEMENTED ; + return 0 ; + } ; + + if (psf->last_op != SFM_WRITE) + if (psf->seek (psf, SFM_WRITE, psf->write_current) < 0) + return 0 ; + + if (psf->have_written == SF_FALSE && psf->write_header != NULL) + { if ((psf->error = psf->write_header (psf, SF_FALSE))) + return 0 ; + } ; + psf->have_written = SF_TRUE ; + + count = psf->write_float (psf, ptr, frames * psf->sf.channels) ; + + psf->write_current += count / psf->sf.channels ; + + psf->last_op = SFM_WRITE ; + + if (psf->write_current > psf->sf.frames) + { psf->sf.frames = psf->write_current ; + psf->dataend = 0 ; + } ; + + if (psf->auto_header && psf->write_header != NULL) + psf->write_header (psf, SF_TRUE) ; + + return count / psf->sf.channels ; +} /* sf_writef_float */ + +/*------------------------------------------------------------------------------ +*/ + +sf_count_t +sf_write_double (SNDFILE *sndfile, const double *ptr, sf_count_t len) +{ SF_PRIVATE *psf ; + sf_count_t count ; + + if (len == 0) + return 0 ; + + VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; + + if (len <= 0) + { psf->error = SFE_NEGATIVE_RW_LEN ; + return 0 ; + } ; + + if (psf->file.mode == SFM_READ) + { psf->error = SFE_NOT_WRITEMODE ; + return 0 ; + } ; + + if (len % psf->sf.channels) + { psf->error = SFE_BAD_WRITE_ALIGN ; + return 0 ; + } ; + + if (psf->write_double == NULL || psf->seek == NULL) + { psf->error = SFE_UNIMPLEMENTED ; + return 0 ; + } ; + + if (psf->last_op != SFM_WRITE) + if (psf->seek (psf, SFM_WRITE, psf->write_current) < 0) + return 0 ; + + if (psf->have_written == SF_FALSE && psf->write_header != NULL) + { if ((psf->error = psf->write_header (psf, SF_FALSE))) + return 0 ; + } ; + psf->have_written = SF_TRUE ; + + count = psf->write_double (psf, ptr, len) ; + + psf->write_current += count / psf->sf.channels ; + + psf->last_op = SFM_WRITE ; + + if (psf->write_current > psf->sf.frames) + { psf->sf.frames = psf->write_current ; + psf->dataend = 0 ; + } ; + + if (psf->auto_header && psf->write_header != NULL) + psf->write_header (psf, SF_TRUE) ; + + return count ; +} /* sf_write_double */ + +sf_count_t +sf_writef_double (SNDFILE *sndfile, const double *ptr, sf_count_t frames) +{ SF_PRIVATE *psf ; + sf_count_t count ; + + if (frames == 0) + return 0 ; + + VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; + + if (frames <= 0) + { psf->error = SFE_NEGATIVE_RW_LEN ; + return 0 ; + } ; + + if (psf->file.mode == SFM_READ) + { psf->error = SFE_NOT_WRITEMODE ; + return 0 ; + } ; + + if (psf->write_double == NULL || psf->seek == NULL) + { psf->error = SFE_UNIMPLEMENTED ; + return 0 ; + } ; + + if (psf->last_op != SFM_WRITE) + if (psf->seek (psf, SFM_WRITE, psf->write_current) < 0) + return 0 ; + + if (psf->have_written == SF_FALSE && psf->write_header != NULL) + { if ((psf->error = psf->write_header (psf, SF_FALSE))) + return 0 ; + } ; + psf->have_written = SF_TRUE ; + + count = psf->write_double (psf, ptr, frames * psf->sf.channels) ; + + psf->write_current += count / psf->sf.channels ; + + psf->last_op = SFM_WRITE ; + + if (psf->write_current > psf->sf.frames) + { psf->sf.frames = psf->write_current ; + psf->dataend = 0 ; + } ; + + if (psf->auto_header && psf->write_header != NULL) + psf->write_header (psf, SF_TRUE) ; + + return count / psf->sf.channels ; +} /* sf_writef_double */ + +/*========================================================================= +** Private functions. +*/ + +static int +try_resource_fork (SF_PRIVATE * psf) +{ int old_error = psf->error ; + + /* Set READ mode now, to see if resource fork exists. */ + psf->rsrc.mode = SFM_READ ; + if (psf_open_rsrc (psf) != 0) + { psf->error = old_error ; + return 0 ; + } ; + + /* More checking here. */ + psf_log_printf (psf, "Resource fork : %s\n", psf->rsrc.path) ; + + return SF_FORMAT_SD2 ; +} /* try_resource_fork */ + +static int +format_from_extension (SF_PRIVATE *psf) +{ char *cptr ; + char buffer [16] ; + int format = 0 ; + + if ((cptr = strrchr (psf->file.name, '.')) == NULL) + return 0 ; + + cptr ++ ; + if (strlen (cptr) > sizeof (buffer) - 1) + return 0 ; + + psf_strlcpy (buffer, sizeof (buffer), cptr) ; + buffer [sizeof (buffer) - 1] = 0 ; + + /* Convert everything in the buffer to lower case. */ + cptr = buffer ; + while (*cptr) + { *cptr = tolower (*cptr) ; + cptr ++ ; + } ; + + cptr = buffer ; + + if (strcmp (cptr, "au") == 0) + { psf->sf.channels = 1 ; + psf->sf.samplerate = 8000 ; + format = SF_FORMAT_RAW | SF_FORMAT_ULAW ; + } + else if (strcmp (cptr, "snd") == 0) + { psf->sf.channels = 1 ; + psf->sf.samplerate = 8000 ; + format = SF_FORMAT_RAW | SF_FORMAT_ULAW ; + } + + else if (strcmp (cptr, "vox") == 0 || strcmp (cptr, "vox8") == 0) + { psf->sf.channels = 1 ; + psf->sf.samplerate = 8000 ; + format = SF_FORMAT_RAW | SF_FORMAT_VOX_ADPCM ; + } + else if (strcmp (cptr, "vox6") == 0) + { psf->sf.channels = 1 ; + psf->sf.samplerate = 6000 ; + format = SF_FORMAT_RAW | SF_FORMAT_VOX_ADPCM ; + } + else if (strcmp (cptr, "gsm") == 0) + { psf->sf.channels = 1 ; + psf->sf.samplerate = 8000 ; + format = SF_FORMAT_RAW | SF_FORMAT_GSM610 ; + } + else if (strcmp (cptr, "mp3") == 0) + { /* + * MPEG streams are quite tollerate of crap. If we couldn't identify a + * MP3 stream, but it has a .mp3 extension, let libmpg123 have a try. + */ + format = SF_FORMAT_MPEG ; + } + + /* For RAW files, make sure the dataoffset if set correctly. */ + if ((SF_CONTAINER (format)) == SF_FORMAT_RAW) + psf->dataoffset = 0 ; + + return format ; +} /* format_from_extension */ + +static int +identify_mpeg (uint32_t marker) +{ if ((marker & MAKE_MARKER (0xFF, 0xE0, 0, 0)) == MAKE_MARKER (0xFF, 0xE0, 0, 0) && /* Frame sync */ + (marker & MAKE_MARKER (0, 0x18, 0, 0)) != MAKE_MARKER (0, 0x08, 0, 0) && /* Valid MPEG version */ + (marker & MAKE_MARKER (0, 0x06, 0, 0)) != MAKE_MARKER (0, 0, 0, 0) && /* Valid layer description */ + (marker & MAKE_MARKER (0, 0, 0xF0, 0)) != MAKE_MARKER (0, 0, 0xF0, 0) && /* Valid bitrate */ + (marker & MAKE_MARKER (0, 0, 0x0C, 0)) != MAKE_MARKER (0, 0, 0x0C, 0)) /* Valid samplerate */ + return SF_FORMAT_MPEG ; + return 0 ; +} /* identify_mpeg */ + +static int +guess_file_type (SF_PRIVATE *psf) +{ uint32_t buffer [3], format ; + +retry: + if (psf_binheader_readf (psf, "b", &buffer, SIGNED_SIZEOF (buffer)) != SIGNED_SIZEOF (buffer)) + { psf->error = SFE_BAD_FILE_READ ; + return 0 ; + } ; + + if ((buffer [0] == MAKE_MARKER ('R', 'I', 'F', 'F') || buffer [0] == MAKE_MARKER ('R', 'I', 'F', 'X')) + && buffer [2] == MAKE_MARKER ('W', 'A', 'V', 'E')) + return SF_FORMAT_WAV ; + + if (buffer [0] == MAKE_MARKER ('F', 'O', 'R', 'M')) + { if (buffer [2] == MAKE_MARKER ('A', 'I', 'F', 'F') || buffer [2] == MAKE_MARKER ('A', 'I', 'F', 'C')) + return SF_FORMAT_AIFF ; + if (buffer [2] == MAKE_MARKER ('8', 'S', 'V', 'X') || buffer [2] == MAKE_MARKER ('1', '6', 'S', 'V')) + return SF_FORMAT_SVX ; + return 0 ; + } ; + + if (buffer [0] == MAKE_MARKER ('.', 's', 'n', 'd') || buffer [0] == MAKE_MARKER ('d', 'n', 's', '.')) + return SF_FORMAT_AU ; + + if ((buffer [0] == MAKE_MARKER ('f', 'a', 'p', ' ') || buffer [0] == MAKE_MARKER (' ', 'p', 'a', 'f'))) + return SF_FORMAT_PAF ; + + if (buffer [0] == MAKE_MARKER ('N', 'I', 'S', 'T')) + return SF_FORMAT_NIST ; + + if (buffer [0] == MAKE_MARKER ('C', 'r', 'e', 'a') && buffer [1] == MAKE_MARKER ('t', 'i', 'v', 'e')) + return SF_FORMAT_VOC ; + + if ((buffer [0] & MAKE_MARKER (0xFF, 0xFF, 0xF8, 0xFF)) == MAKE_MARKER (0x64, 0xA3, 0x00, 0x00) || + (buffer [0] & MAKE_MARKER (0xFF, 0xF8, 0xFF, 0xFF)) == MAKE_MARKER (0x00, 0x00, 0xA3, 0x64)) + return SF_FORMAT_IRCAM ; + + if (buffer [0] == MAKE_MARKER ('r', 'i', 'f', 'f')) + return SF_FORMAT_W64 ; + + if (buffer [0] == MAKE_MARKER (0, 0, 0x03, 0xE8) && buffer [1] == MAKE_MARKER (0, 0, 0, 1) && + buffer [2] == MAKE_MARKER (0, 0, 0, 1)) + return SF_FORMAT_MAT4 ; + + if (buffer [0] == MAKE_MARKER (0, 0, 0, 0) && buffer [1] == MAKE_MARKER (1, 0, 0, 0) && + buffer [2] == MAKE_MARKER (1, 0, 0, 0)) + return SF_FORMAT_MAT4 ; + + if (buffer [0] == MAKE_MARKER ('M', 'A', 'T', 'L') && buffer [1] == MAKE_MARKER ('A', 'B', ' ', '5')) + return SF_FORMAT_MAT5 ; + + if (buffer [0] == MAKE_MARKER ('P', 'V', 'F', '1')) + return SF_FORMAT_PVF ; + + if (buffer [0] == MAKE_MARKER ('E', 'x', 't', 'e') && buffer [1] == MAKE_MARKER ('n', 'd', 'e', 'd') && + buffer [2] == MAKE_MARKER (' ', 'I', 'n', 's')) + return SF_FORMAT_XI ; + + if (buffer [0] == MAKE_MARKER ('c', 'a', 'f', 'f') && buffer [2] == MAKE_MARKER ('d', 'e', 's', 'c')) + return SF_FORMAT_CAF ; + + if (buffer [0] == MAKE_MARKER ('O', 'g', 'g', 'S')) + return SF_FORMAT_OGG ; + + if (buffer [0] == MAKE_MARKER ('A', 'L', 'a', 'w') && buffer [1] == MAKE_MARKER ('S', 'o', 'u', 'n') + && buffer [2] == MAKE_MARKER ('d', 'F', 'i', 'l')) + return SF_FORMAT_WVE ; + + if (buffer [0] == MAKE_MARKER ('D', 'i', 'a', 'm') && buffer [1] == MAKE_MARKER ('o', 'n', 'd', 'W') + && buffer [2] == MAKE_MARKER ('a', 'r', 'e', ' ')) + return SF_FORMAT_DWD ; + + if (buffer [0] == MAKE_MARKER ('L', 'M', '8', '9') || buffer [0] == MAKE_MARKER ('5', '3', 0, 0)) + return SF_FORMAT_TXW ; + + if ((buffer [0] & MAKE_MARKER (0xFF, 0xFF, 0x80, 0xFF)) == MAKE_MARKER (0xF0, 0x7E, 0, 0x01)) + return SF_FORMAT_SDS ; + + if ((buffer [0] & MAKE_MARKER (0xFF, 0xFF, 0, 0)) == MAKE_MARKER (1, 4, 0, 0)) + return SF_FORMAT_MPC2K ; + + if (buffer [0] == MAKE_MARKER ('C', 'A', 'T', ' ') && buffer [2] == MAKE_MARKER ('R', 'E', 'X', '2')) + return SF_FORMAT_REX2 ; + + if (buffer [0] == MAKE_MARKER (0x30, 0x26, 0xB2, 0x75) && buffer [1] == MAKE_MARKER (0x8E, 0x66, 0xCF, 0x11)) + return 0 /*-SF_FORMAT_WMA-*/ ; + + /* HMM (Hidden Markov Model) Tool Kit. */ + if (buffer [2] == MAKE_MARKER (0, 2, 0, 0) && 2 * ((int64_t) BE2H_32 (buffer [0])) + 12 == psf->filelength) + return SF_FORMAT_HTK ; + + if (buffer [0] == MAKE_MARKER ('f', 'L', 'a', 'C')) + return SF_FORMAT_FLAC ; + + if (buffer [0] == MAKE_MARKER ('2', 'B', 'I', 'T')) + return SF_FORMAT_AVR ; + + if (buffer [0] == MAKE_MARKER ('R', 'F', '6', '4') && buffer [2] == MAKE_MARKER ('W', 'A', 'V', 'E')) + return SF_FORMAT_RF64 ; + + if (buffer [0] == MAKE_MARKER ('I', 'D', '3', 2) || buffer [0] == MAKE_MARKER ('I', 'D', '3', 3) + || buffer [0] == MAKE_MARKER ('I', 'D', '3', 4)) + { psf_log_printf (psf, "Found 'ID3' marker.\n") ; + if (id3_skip (psf)) + goto retry ; + return 0 ; + } ; + + /* ID3v2 tags + MPEG */ + if (psf->id3_header.len > 0 && (format = identify_mpeg (buffer [0])) != 0) + return format ; + + /* Turtle Beach SMP 16-bit */ + if (buffer [0] == MAKE_MARKER ('S', 'O', 'U', 'N') && buffer [1] == MAKE_MARKER ('D', ' ', 'S', 'A')) + return 0 ; + + /* Yamaha sampler format. */ + if (buffer [0] == MAKE_MARKER ('S', 'Y', '8', '0') || buffer [0] == MAKE_MARKER ('S', 'Y', '8', '5')) + return 0 ; + + if (buffer [0] == MAKE_MARKER ('a', 'j', 'k', 'g')) + return 0 /*-SF_FORMAT_SHN-*/ ; + + /* This must be (almost) the last one. */ + if (psf->filelength > 0 && (format = try_resource_fork (psf)) != 0) + return format ; + + /* MPEG with no ID3v2 tags. Only have the MPEG sync header for + * identification and it is quite brief, and prone to false positives. + * Check for this last, even after resource forks. */ + if (psf->id3_header.len == 0 && (format = identify_mpeg (buffer [0])) != 0) + return format ; + + return 0 ; +} /* guess_file_type */ + + +static int +validate_sfinfo (SF_INFO *sfinfo) +{ if (sfinfo->samplerate < 1) + return 0 ; + if (sfinfo->frames < 0) + return 0 ; + if ((sfinfo->channels < 1) || (sfinfo->channels > SF_MAX_CHANNELS)) + return 0 ; + if ((SF_CONTAINER (sfinfo->format)) == 0) + return 0 ; + if ((SF_CODEC (sfinfo->format)) == 0) + return 0 ; + if (sfinfo->sections < 1) + return 0 ; + return 1 ; +} /* validate_sfinfo */ + +static int +validate_psf (SF_PRIVATE *psf) +{ + if (psf->datalength < 0) + { psf_log_printf (psf, "Invalid SF_PRIVATE field : datalength == %D.\n", psf->datalength) ; + return 0 ; + } ; + if (psf->dataoffset < 0) + { psf_log_printf (psf, "Invalid SF_PRIVATE field : dataoffset == %D.\n", psf->dataoffset) ; + return 0 ; + } ; + if (psf->blockwidth && psf->blockwidth != psf->sf.channels * psf->bytewidth) + { psf_log_printf (psf, "Invalid SF_PRIVATE field : channels * bytewidth == %d.\n", + psf->sf.channels * psf->bytewidth) ; + return 0 ; + } ; + return 1 ; +} /* validate_psf */ + +static void +save_header_info (SF_PRIVATE *psf) +{ snprintf (sf_parselog, sizeof (sf_parselog), "%s", psf->parselog.buf) ; +} /* save_header_info */ + +/*============================================================================== +*/ + +static int +psf_close (SF_PRIVATE *psf) +{ uint32_t k ; + int error = 0 ; + + if (psf->codec_close) + { error = psf->codec_close (psf) ; + /* To prevent it being called in psf->container_close(). */ + psf->codec_close = NULL ; + } ; + + if (psf->container_close) + error = psf->container_close (psf) ; + + error = psf_fclose (psf) ; + psf_close_rsrc (psf) ; + + /* For an ISO C compliant implementation it is ok to free a NULL pointer. */ + free (psf->header.ptr) ; + free (psf->container_data) ; + free (psf->codec_data) ; + free (psf->interleave) ; + free (psf->dither) ; + free (psf->peak_info) ; + free (psf->broadcast_16k) ; + free (psf->loop_info) ; + free (psf->instrument) ; + free (psf->cues) ; + free (psf->channel_map) ; + free (psf->format_desc) ; + free (psf->strings.storage) ; + + if (psf->wchunks.chunks) + for (k = 0 ; k < psf->wchunks.used ; k++) + free (psf->wchunks.chunks [k].data) ; + free (psf->rchunks.chunks) ; + free (psf->wchunks.chunks) ; + free (psf->iterator) ; + free (psf->cart_16k) ; + + free (psf) ; + + return error ; +} /* psf_close */ + +SNDFILE * +psf_open_file (SF_PRIVATE *psf, SF_INFO *sfinfo) +{ int error, format ; + + sf_errno = error = 0 ; + sf_parselog [0] = 0 ; + + if (psf->error) + { error = psf->error ; + goto error_exit ; + } ; + + if (psf->file.mode != SFM_READ && psf->file.mode != SFM_WRITE && psf->file.mode != SFM_RDWR) + { error = SFE_BAD_OPEN_MODE ; + goto error_exit ; + } ; + + if (sfinfo == NULL) + { error = SFE_BAD_SF_INFO_PTR ; + goto error_exit ; + } ; + + if (psf->file.mode == SFM_READ) + { if ((SF_CONTAINER (sfinfo->format)) == SF_FORMAT_RAW) + { if (sf_format_check (sfinfo) == 0) + { error = SFE_RAW_BAD_FORMAT ; + goto error_exit ; + } ; + } + else + memset (sfinfo, 0, sizeof (SF_INFO)) ; + } ; + + memcpy (&psf->sf, sfinfo, sizeof (SF_INFO)) ; + + psf->Magick = SNDFILE_MAGICK ; + psf->norm_float = SF_TRUE ; + psf->norm_double = SF_TRUE ; + psf->dataoffset = -1 ; + psf->datalength = -1 ; + psf->read_current = -1 ; + psf->write_current = -1 ; + psf->auto_header = SF_FALSE ; + psf->rwf_endian = SF_ENDIAN_LITTLE ; + psf->seek = psf_default_seek ; + psf->float_int_mult = 0 ; + psf->float_max = -1.0 ; + + /* An attempt at a per SF_PRIVATE unique id. */ + psf->unique_id = psf_rand_int32 () ; + + psf->sf.sections = 1 ; + + psf->is_pipe = psf_is_pipe (psf) ; + + if (psf->is_pipe) + { psf->sf.seekable = SF_FALSE ; + psf->filelength = SF_COUNT_MAX ; + } + else + { psf->sf.seekable = SF_TRUE ; + + /* File is open, so get the length. */ + psf->filelength = psf_get_filelen (psf) ; + } ; + + if (psf->fileoffset > 0) + { switch (psf->file.mode) + { case SFM_READ : + if (psf->filelength < 44) + { psf_log_printf (psf, "Short filelength: %D (fileoffset: %D)\n", psf->filelength, psf->fileoffset) ; + error = SFE_BAD_OFFSET ; + goto error_exit ; + } ; + break ; + + case SFM_WRITE : + psf->fileoffset = 0 ; + psf_fseek (psf, 0, SEEK_END) ; + psf->fileoffset = psf_ftell (psf) ; + break ; + + case SFM_RDWR : + error = SFE_NO_EMBEDDED_RDWR ; + goto error_exit ; + } ; + + psf_log_printf (psf, "Embedded file offset : %D\n", psf->fileoffset) ; + } ; + + if (psf->filelength == SF_COUNT_MAX) + psf_log_printf (psf, "Length : unknown\n") ; + else + psf_log_printf (psf, "Length : %D\n", psf->filelength) ; + + if (psf->file.mode == SFM_WRITE || (psf->file.mode == SFM_RDWR && psf->filelength == 0)) + { /* If the file is being opened for write or RDWR and the file is currently + ** empty, then the SF_INFO struct must contain valid data. + */ + if ((SF_CONTAINER (psf->sf.format)) == 0) + { error = SFE_ZERO_MAJOR_FORMAT ; + goto error_exit ; + } ; + if ((SF_CODEC (psf->sf.format)) == 0) + { error = SFE_ZERO_MINOR_FORMAT ; + goto error_exit ; + } ; + + if (sf_format_check (&psf->sf) == 0) + { error = SFE_BAD_OPEN_FORMAT ; + goto error_exit ; + } ; + } + else if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_RAW) + { /* If type RAW has not been specified then need to figure out file type. */ + psf->sf.format = guess_file_type (psf) ; + + if (psf->sf.format == 0) + psf->sf.format = format_from_extension (psf) ; + } ; + + /* Prevent unnecessary seeks */ + psf->last_op = psf->file.mode ; + + /* Set bytewidth if known. */ + switch (SF_CODEC (psf->sf.format)) + { case SF_FORMAT_PCM_S8 : + case SF_FORMAT_PCM_U8 : + case SF_FORMAT_ULAW : + case SF_FORMAT_ALAW : + case SF_FORMAT_DPCM_8 : + psf->bytewidth = 1 ; + break ; + + case SF_FORMAT_PCM_16 : + case SF_FORMAT_DPCM_16 : + psf->bytewidth = 2 ; + break ; + + case SF_FORMAT_PCM_24 : + psf->bytewidth = 3 ; + break ; + + case SF_FORMAT_PCM_32 : + case SF_FORMAT_FLOAT : + psf->bytewidth = 4 ; + break ; + + case SF_FORMAT_DOUBLE : + psf->bytewidth = 8 ; + break ; + } ; + + /* Call the initialisation function for the relevant file type. */ + switch (SF_CONTAINER (psf->sf.format)) + { case SF_FORMAT_WAV : + case SF_FORMAT_WAVEX : + error = wav_open (psf) ; + break ; + + case SF_FORMAT_AIFF : + error = aiff_open (psf) ; + break ; + + case SF_FORMAT_AU : + error = au_open (psf) ; + break ; + + case SF_FORMAT_RAW : + error = raw_open (psf) ; + break ; + + case SF_FORMAT_W64 : + error = w64_open (psf) ; + break ; + + case SF_FORMAT_RF64 : + error = rf64_open (psf) ; + break ; + + /* Lite remove start */ + case SF_FORMAT_PAF : + error = paf_open (psf) ; + break ; + + case SF_FORMAT_SVX : + error = svx_open (psf) ; + break ; + + case SF_FORMAT_NIST : + error = nist_open (psf) ; + break ; + + case SF_FORMAT_IRCAM : + error = ircam_open (psf) ; + break ; + + case SF_FORMAT_VOC : + error = voc_open (psf) ; + break ; + + case SF_FORMAT_SDS : + error = sds_open (psf) ; + break ; + + case SF_FORMAT_OGG : + error = ogg_open (psf) ; + break ; + + case SF_FORMAT_TXW : + error = txw_open (psf) ; + break ; + + case SF_FORMAT_WVE : + error = wve_open (psf) ; + break ; + + case SF_FORMAT_DWD : + error = dwd_open (psf) ; + break ; + + case SF_FORMAT_MAT4 : + error = mat4_open (psf) ; + break ; + + case SF_FORMAT_MAT5 : + error = mat5_open (psf) ; + break ; + + case SF_FORMAT_PVF : + error = pvf_open (psf) ; + break ; + + case SF_FORMAT_XI : + error = xi_open (psf) ; + break ; + + case SF_FORMAT_HTK : + error = htk_open (psf) ; + break ; + + case SF_FORMAT_SD2 : + error = sd2_open (psf) ; + break ; + + case SF_FORMAT_REX2 : + error = rx2_open (psf) ; + break ; + + case SF_FORMAT_AVR : + error = avr_open (psf) ; + break ; + + case SF_FORMAT_FLAC : + error = flac_open (psf) ; + break ; + + case SF_FORMAT_CAF : + error = caf_open (psf) ; + break ; + + case SF_FORMAT_MPC2K : + error = mpc2k_open (psf) ; + break ; + + case SF_FORMAT_MPEG : + error = mpeg_open (psf) ; + break ; + + /* Lite remove end */ + + default : + error = SF_ERR_UNRECOGNISED_FORMAT ; + } ; + + if (error) + goto error_exit ; + + /* For now, check whether embedding is supported. */ + format = SF_CONTAINER (psf->sf.format) ; + if (psf->fileoffset > 0) + { switch (format) + { case SF_FORMAT_WAV : + case SF_FORMAT_WAVEX : + case SF_FORMAT_AIFF : + case SF_FORMAT_AU : + /* Actual embedded files. */ + break ; + + case SF_FORMAT_MPEG : + case SF_FORMAT_FLAC : + /* Flac with an ID3v2 header? */ + break ; + + default : + error = SFE_NO_EMBED_SUPPORT ; + goto error_exit ; + } ; + } ; + + if (psf->fileoffset > 0) + psf_log_printf (psf, "Embedded file length : %D\n", psf->filelength) ; + + if (psf->file.mode == SFM_RDWR && sf_format_check (&psf->sf) == 0) + { error = SFE_BAD_MODE_RW ; + goto error_exit ; + } ; + + if (validate_sfinfo (&psf->sf) == 0) + { psf_log_SF_INFO (psf) ; + save_header_info (psf) ; + error = SFE_BAD_SF_INFO ; + goto error_exit ; + } ; + + if (validate_psf (psf) == 0) + { save_header_info (psf) ; + error = SFE_INTERNAL ; + goto error_exit ; + } ; + + psf->read_current = 0 ; + psf->write_current = 0 ; + if (psf->file.mode == SFM_RDWR) + { psf->write_current = psf->sf.frames ; + psf->have_written = psf->sf.frames > 0 ? SF_TRUE : SF_FALSE ; + } ; + + memcpy (sfinfo, &psf->sf, sizeof (SF_INFO)) ; + + if (psf->file.mode == SFM_WRITE) + { /* Zero out these fields. */ + sfinfo->frames = 0 ; + sfinfo->sections = 0 ; + sfinfo->seekable = 0 ; + } ; + + return (SNDFILE *) psf ; + +error_exit : + sf_errno = error ; + + if (error == SFE_SYSTEM) + snprintf (sf_syserr, sizeof (sf_syserr), "%s", psf->syserr) ; + snprintf (sf_parselog, sizeof (sf_parselog), "%s", psf->parselog.buf) ; + + switch (error) + { case SF_ERR_SYSTEM : + case SF_ERR_UNSUPPORTED_ENCODING : + case SFE_UNIMPLEMENTED : + break ; + + case SFE_RAW_BAD_FORMAT : + break ; + + default : + if (psf->file.mode == SFM_READ) + { psf_log_printf (psf, "Parse error : %s\n", sf_error_number (error)) ; + error = SF_ERR_MALFORMED_FILE ; + } ; + } ; + + psf_close (psf) ; + return NULL ; +} /* psf_open_file */ + +/*============================================================================== +** Chunk getting and setting. +** This works for AIFF, CAF, RF64 and WAV. +** It doesn't work for W64 because W64 uses weird GUID style chunk markers. +*/ + +int +sf_set_chunk (SNDFILE * sndfile, const SF_CHUNK_INFO * chunk_info) +{ SF_PRIVATE *psf ; + + VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; + + if (chunk_info == NULL || chunk_info->data == NULL) + return SFE_BAD_CHUNK_PTR ; + + if (psf->set_chunk) + return psf->set_chunk (psf, chunk_info) ; + + return SFE_BAD_CHUNK_FORMAT ; +} /* sf_set_chunk */ + +SF_CHUNK_ITERATOR * +sf_get_chunk_iterator (SNDFILE * sndfile, const SF_CHUNK_INFO * chunk_info) +{ SF_PRIVATE *psf ; + + VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; + + if (chunk_info) + return psf_get_chunk_iterator (psf, chunk_info->id) ; + + return psf_get_chunk_iterator (psf, NULL) ; +} /* sf_get_chunk_iterator */ + +SF_CHUNK_ITERATOR * +sf_next_chunk_iterator (SF_CHUNK_ITERATOR * iterator) +{ SF_PRIVATE *psf ; + SNDFILE *sndfile = iterator ? iterator->sndfile : NULL ; + + VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; + + if (psf->next_chunk_iterator) + return psf->next_chunk_iterator (psf, iterator) ; + + return NULL ; +} /* sf_get_chunk_iterator_next */ + +int +sf_get_chunk_size (const SF_CHUNK_ITERATOR * iterator, SF_CHUNK_INFO * chunk_info) +{ SF_PRIVATE *psf ; + SNDFILE *sndfile = iterator ? iterator->sndfile : NULL ; + + VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; + + if (chunk_info == NULL) + return SFE_BAD_CHUNK_PTR ; + + if (psf->get_chunk_size) + return psf->get_chunk_size (psf, iterator, chunk_info) ; + + return SFE_BAD_CHUNK_FORMAT ; +} /* sf_get_chunk_size */ + +int +sf_get_chunk_data (const SF_CHUNK_ITERATOR * iterator, SF_CHUNK_INFO * chunk_info) +{ SF_PRIVATE *psf ; + SNDFILE *sndfile = iterator ? iterator->sndfile : NULL ; + + VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ; + + if (chunk_info == NULL || chunk_info->data == NULL) + return SFE_BAD_CHUNK_PTR ; + + if (psf->get_chunk_data) + return psf->get_chunk_data (psf, iterator, chunk_info) ; + + return SFE_BAD_CHUNK_FORMAT ; +} /* sf_get_chunk_data */ diff --git a/extern/libsndfile-modified/src/strings.c b/extern/libsndfile-modified/src/strings.c new file mode 100644 index 000000000..3dfe5de8b --- /dev/null +++ b/extern/libsndfile-modified/src/strings.c @@ -0,0 +1,190 @@ +/* +** Copyright (C) 2001-2016 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include + +#include "sndfile.h" +#include "common.h" + +#define STRINGS_DEBUG 0 + +int +psf_store_string (SF_PRIVATE *psf, int str_type, const char *str) +{ char new_str [128] ; + size_t str_len ; + int k, str_flags ; + + if (str == NULL) + return SFE_STR_BAD_STRING ; + + str_len = strlen (str) ; + + /* A few extra checks for write mode. */ + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { if ((psf->strings.flags & SF_STR_ALLOW_START) == 0) + return SFE_STR_NO_SUPPORT ; + if (psf->have_written && (psf->strings.flags & SF_STR_ALLOW_END) == 0) + return SFE_STR_NO_SUPPORT ; + /* Only allow zero length strings for software. */ + if (str_type != SF_STR_SOFTWARE && str_len == 0) + return SFE_STR_BAD_STRING ; + } ; + + /* Find the next free slot in table. */ + for (k = 0 ; k < SF_MAX_STRINGS ; k++) + { /* If we find a matching entry clear it. */ + if (psf->strings.data [k].type == str_type) + psf->strings.data [k].type = -1 ; + + if (psf->strings.data [k].type == 0) + break ; + } ; + + /* Determine flags */ + str_flags = SF_STR_LOCATE_START ; + if (psf->file.mode == SFM_RDWR || psf->have_written) + { if ((psf->strings.flags & SF_STR_ALLOW_END) == 0) + return SFE_STR_NO_ADD_END ; + str_flags = SF_STR_LOCATE_END ; + } ; + + /* More sanity checking. */ + if (k >= SF_MAX_STRINGS) + return SFE_STR_MAX_COUNT ; + + if (k == 0 && psf->strings.storage_used != 0) + { psf_log_printf (psf, "SFE_STR_WEIRD : k == 0 && psf->strings.storage_used != 0\n") ; + return SFE_STR_WEIRD ; + } ; + + if (k != 0 && psf->strings.storage_used == 0) + { psf_log_printf (psf, "SFE_STR_WEIRD : k != 0 && psf->strings.storage_used == 0\n") ; + return SFE_STR_WEIRD ; + } ; + + /* Special case for the first string. */ + if (k == 0) + psf->strings.storage_used = 0 ; + + switch (str_type) + { case SF_STR_SOFTWARE : + /* In write mode, want to append libsndfile-version to string. */ + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { if (strstr (str, PACKAGE_NAME) == NULL) + { /* + ** If the supplied string does not already contain a + ** libsndfile-X.Y.Z component, then add it. + */ + if (strlen (str) == 0) + snprintf (new_str, sizeof (new_str), "%s-%s", PACKAGE_NAME, PACKAGE_VERSION) ; + else + snprintf (new_str, sizeof (new_str), "%s (%s-%s)", str, PACKAGE_NAME, PACKAGE_VERSION) ; + } + else + snprintf (new_str, sizeof (new_str), "%s", str) ; + + str = new_str ; + } ; + break ; + + case SF_STR_TITLE : + case SF_STR_COPYRIGHT : + case SF_STR_ARTIST : + case SF_STR_COMMENT : + case SF_STR_DATE : + case SF_STR_ALBUM : + case SF_STR_LICENSE : + case SF_STR_TRACKNUMBER : + case SF_STR_GENRE : + break ; + + default : + psf_log_printf (psf, "%s : SFE_STR_BAD_TYPE\n", __func__) ; + return SFE_STR_BAD_TYPE ; + } ; + + /* Plus one to catch string terminator. */ + str_len = strlen (str) + 1 ; + + if (psf->strings.storage_used + str_len + 1 > psf->strings.storage_len) + { char * temp = psf->strings.storage ; + size_t newlen = 2 * psf->strings.storage_len + str_len + 1 ; + + newlen = newlen < 256 ? 256 : newlen ; + + char * new_storage = realloc(temp, newlen); + if (new_storage == NULL) + { + return SFE_MALLOC_FAILED ; + } else { + psf->strings.storage = new_storage; + } ; + + psf->strings.storage_len = newlen ; + } ; + + psf->strings.data [k].type = str_type ; + psf->strings.data [k].offset = psf->strings.storage_used ; + psf->strings.data [k].flags = str_flags ; + + memcpy (psf->strings.storage + psf->strings.storage_used, str, str_len) ; + psf->strings.storage_used += str_len ; + + psf->strings.flags |= str_flags ; + +#if STRINGS_DEBUG + printf ("storage_used : %zd / %zd\n", psf->strings.storage_used, psf->strings.storage_len) ; + psf_hexdump (psf->strings.storage, psf->strings.storage_used) ; +#endif + + return 0 ; +} /* psf_store_string */ + +int +psf_set_string (SF_PRIVATE *psf, int str_type, const char *str) +{ if (psf->file.mode == SFM_READ) + return SFE_STR_NOT_WRITE ; + + return psf_store_string (psf, str_type, str) ; +} /* psf_set_string */ + +const char* +psf_get_string (SF_PRIVATE *psf, int str_type) +{ int k ; + + for (k = 0 ; k < SF_MAX_STRINGS ; k++) + if (str_type == psf->strings.data [k].type) + return psf->strings.storage + psf->strings.data [k].offset ; + + return NULL ; +} /* psf_get_string */ + +int +psf_location_string_count (const SF_PRIVATE * psf, int location) +{ int k, count = 0 ; + + for (k = 0 ; k < SF_MAX_STRINGS ; k++) + if (psf->strings.data [k].type > 0 && psf->strings.data [k].flags & location) + count ++ ; + + return count ; +} /* psf_location_string_count */ diff --git a/extern/libsndfile-modified/src/svx.c b/extern/libsndfile-modified/src/svx.c new file mode 100644 index 000000000..342b00629 --- /dev/null +++ b/extern/libsndfile-modified/src/svx.c @@ -0,0 +1,402 @@ +/* +** Copyright (C) 1999-2017 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + + +/*------------------------------------------------------------------------------ + * Macros to handle big/little endian issues. +*/ + +#define FORM_MARKER (MAKE_MARKER ('F', 'O', 'R', 'M')) +#define SVX8_MARKER (MAKE_MARKER ('8', 'S', 'V', 'X')) +#define SV16_MARKER (MAKE_MARKER ('1', '6', 'S', 'V')) +#define VHDR_MARKER (MAKE_MARKER ('V', 'H', 'D', 'R')) +#define BODY_MARKER (MAKE_MARKER ('B', 'O', 'D', 'Y')) + +#define ATAK_MARKER (MAKE_MARKER ('A', 'T', 'A', 'K')) +#define RLSE_MARKER (MAKE_MARKER ('R', 'L', 'S', 'E')) + +#define c_MARKER (MAKE_MARKER ('(', 'c', ')', ' ')) +#define NAME_MARKER (MAKE_MARKER ('N', 'A', 'M', 'E')) +#define AUTH_MARKER (MAKE_MARKER ('A', 'U', 'T', 'H')) +#define ANNO_MARKER (MAKE_MARKER ('A', 'N', 'N', 'O')) +#define CHAN_MARKER (MAKE_MARKER ('C', 'H', 'A', 'N')) + +/*------------------------------------------------------------------------------ + * Typedefs for file chunks. +*/ + +typedef struct +{ unsigned int oneShotHiSamples, repeatHiSamples, samplesPerHiCycle ; + unsigned short samplesPerSec ; + unsigned char octave, compression ; + unsigned int volume ; +} VHDR_CHUNK ; + +enum { + HAVE_FORM = 0x01, + + HAVE_SVX = 0x02, + HAVE_VHDR = 0x04, + HAVE_BODY = 0x08 +} ; + +/*------------------------------------------------------------------------------ + * Private static functions. +*/ + +static int svx_close (SF_PRIVATE *psf) ; +static int svx_write_header (SF_PRIVATE *psf, int calc_length) ; +static int svx_read_header (SF_PRIVATE *psf) ; + +/*------------------------------------------------------------------------------ +** Public function. +*/ + +int +svx_open (SF_PRIVATE *psf) +{ int error ; + + if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0)) + { if ((error = svx_read_header (psf))) + return error ; + + psf->endian = SF_ENDIAN_BIG ; /* All SVX files are big endian. */ + + psf->blockwidth = psf->sf.channels * psf->bytewidth ; + if (psf->blockwidth) + psf->sf.frames = psf->datalength / psf->blockwidth ; + + psf_fseek (psf, psf->dataoffset, SEEK_SET) ; + } ; + + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { if (psf->is_pipe) + return SFE_NO_PIPE_WRITE ; + + if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_SVX) + return SFE_BAD_OPEN_FORMAT ; + + psf->endian = SF_ENDIAN (psf->sf.format) ; + + if (psf->endian == SF_ENDIAN_LITTLE || (CPU_IS_LITTLE_ENDIAN && psf->endian == SF_ENDIAN_CPU)) + return SFE_BAD_ENDIAN ; + + psf->endian = SF_ENDIAN_BIG ; /* All SVX files are big endian. */ + + error = svx_write_header (psf, SF_FALSE) ; + if (error) + return error ; + + psf->write_header = svx_write_header ; + } ; + + psf->container_close = svx_close ; + + if ((error = pcm_init (psf))) + return error ; + + return 0 ; +} /* svx_open */ + +/*------------------------------------------------------------------------------ +*/ + +static int +svx_read_header (SF_PRIVATE *psf) +{ VHDR_CHUNK vhdr ; + uint32_t chunk_size, marker ; + int filetype = 0, parsestage = 0, done = 0 ; + int bytecount = 0, channels ; + + if (psf->filelength > 0xFFFFFFFFLL) + psf_log_printf (psf, "Warning : filelength > 0xffffffff. This is bad!!!!\n") ; + + memset (&vhdr, 0, sizeof (vhdr)) ; + psf_binheader_readf (psf, "p", 0) ; + + /* Set default number of channels. Modify later if necessary */ + psf->sf.channels = 1 ; + + psf->sf.format = SF_FORMAT_SVX ; + + while (! done) + { psf_binheader_readf (psf, "Em4", &marker, &chunk_size) ; + + switch (marker) + { case FORM_MARKER : + if (parsestage) + return SFE_SVX_NO_FORM ; + + if (chunk_size != psf->filelength - 2 * sizeof (chunk_size)) + psf_log_printf (psf, "FORM : %u (should be %u)\n", chunk_size, (uint32_t) psf->filelength - 2 * sizeof (chunk_size)) ; + else + psf_log_printf (psf, "FORM : %u\n", chunk_size) ; + parsestage |= HAVE_FORM ; + + psf_binheader_readf (psf, "m", &marker) ; + + filetype = marker ; + psf_log_printf (psf, " %M\n", marker) ; + parsestage |= HAVE_SVX ; + break ; + + case VHDR_MARKER : + if (! (parsestage & (HAVE_FORM | HAVE_SVX))) + return SFE_SVX_NO_FORM ; + + psf_log_printf (psf, " VHDR : %d\n", chunk_size) ; + + psf_binheader_readf (psf, "E4442114", &(vhdr.oneShotHiSamples), &(vhdr.repeatHiSamples), + &(vhdr.samplesPerHiCycle), &(vhdr.samplesPerSec), &(vhdr.octave), &(vhdr.compression), + &(vhdr.volume)) ; + + psf_log_printf (psf, " OneShotHiSamples : %d\n", vhdr.oneShotHiSamples) ; + psf_log_printf (psf, " RepeatHiSamples : %d\n", vhdr.repeatHiSamples) ; + psf_log_printf (psf, " samplesPerHiCycle : %d\n", vhdr.samplesPerHiCycle) ; + psf_log_printf (psf, " Sample Rate : %d\n", vhdr.samplesPerSec) ; + psf_log_printf (psf, " Octave : %d\n", vhdr.octave) ; + + psf_log_printf (psf, " Compression : %d => ", vhdr.compression) ; + + switch (vhdr.compression) + { case 0 : psf_log_printf (psf, "None.\n") ; + break ; + case 1 : psf_log_printf (psf, "Fibonacci delta\n") ; + break ; + case 2 : psf_log_printf (psf, "Exponential delta\n") ; + break ; + } ; + + psf_log_printf (psf, " Volume : %d\n", vhdr.volume) ; + + psf->sf.samplerate = vhdr.samplesPerSec ; + + if (filetype == SVX8_MARKER) + { psf->sf.format |= SF_FORMAT_PCM_S8 ; + psf->bytewidth = 1 ; + } + else if (filetype == SV16_MARKER) + { psf->sf.format |= SF_FORMAT_PCM_16 ; + psf->bytewidth = 2 ; + } ; + + parsestage |= HAVE_VHDR ; + break ; + + case BODY_MARKER : + if (! (parsestage & HAVE_VHDR)) + return SFE_SVX_NO_BODY ; + + psf->datalength = chunk_size ; + + psf->dataoffset = psf_ftell (psf) ; + if (psf->dataoffset < 0) + return SFE_SVX_NO_BODY ; + + if (psf->datalength > psf->filelength - psf->dataoffset) + { psf_log_printf (psf, " BODY : %D (should be %D)\n", psf->datalength, psf->filelength - psf->dataoffset) ; + psf->datalength = psf->filelength - psf->dataoffset ; + } + else + psf_log_printf (psf, " BODY : %D\n", psf->datalength) ; + + parsestage |= HAVE_BODY ; + + if (! psf->sf.seekable) + break ; + + psf_fseek (psf, psf->datalength, SEEK_CUR) ; + break ; + + case NAME_MARKER : + if (! (parsestage & HAVE_SVX)) + return SFE_SVX_NO_FORM ; + + psf_log_printf (psf, " %M : %u\n", marker, chunk_size) ; + + if (strlen (psf->file.name) != chunk_size) + { if (chunk_size > sizeof (psf->file.name) - 1) + return SFE_SVX_BAD_NAME_LENGTH ; + + psf_binheader_readf (psf, "b", psf->file.name, chunk_size) ; + psf->file.name [chunk_size] = 0 ; + } + else + psf_binheader_readf (psf, "j", chunk_size) ; + break ; + + case ANNO_MARKER : + if (! (parsestage & HAVE_SVX)) + return SFE_SVX_NO_FORM ; + + psf_log_printf (psf, " %M : %u\n", marker, chunk_size) ; + + psf_binheader_readf (psf, "j", chunk_size) ; + break ; + + case CHAN_MARKER : + if (! (parsestage & HAVE_SVX)) + return SFE_SVX_NO_FORM ; + + psf_log_printf (psf, " %M : %u\n", marker, chunk_size) ; + + bytecount += psf_binheader_readf (psf, "E4", &channels) ; + + if (channels == 2 || channels == 4) + psf_log_printf (psf, " Channels : %d => mono\n", channels) ; + else if (channels == 6) + { psf->sf.channels = 2 ; + psf_log_printf (psf, " Channels : %d => stereo\n", channels) ; + } + else + psf_log_printf (psf, " Channels : %d *** assuming mono\n", channels) ; + + psf_binheader_readf (psf, "j", chunk_size - bytecount) ; + break ; + + + case AUTH_MARKER : + case c_MARKER : + if (! (parsestage & HAVE_SVX)) + return SFE_SVX_NO_FORM ; + + psf_log_printf (psf, " %M : %u\n", marker, chunk_size) ; + + psf_binheader_readf (psf, "j", chunk_size) ; + break ; + + default : + if (chunk_size >= 0xffff0000) + { done = SF_TRUE ; + psf_log_printf (psf, "*** Unknown chunk marker (%X) at position %D with length %u. Exiting parser.\n", marker, psf_ftell (psf) - 8, chunk_size) ; + break ; + } ; + + if (psf_isprint ((marker >> 24) & 0xFF) && psf_isprint ((marker >> 16) & 0xFF) + && psf_isprint ((marker >> 8) & 0xFF) && psf_isprint (marker & 0xFF)) + { psf_log_printf (psf, "%M : %u (unknown marker)\n", marker, chunk_size) ; + psf_binheader_readf (psf, "j", chunk_size) ; + break ; + } ; + if ((chunk_size = psf_ftell (psf)) & 0x03) + { psf_log_printf (psf, " Unknown chunk marker at position %d. Resynching.\n", chunk_size - 4) ; + + chunk_size = chunk_size & 3 ; + psf_binheader_readf (psf, "j", 4 - chunk_size) ; + break ; + } ; + psf_log_printf (psf, "*** Unknown chunk marker (%X) at position %D. Exiting parser.\n", marker, psf_ftell (psf) - 8) ; + done = SF_TRUE ; + } ; /* switch (marker) */ + + if (! psf->sf.seekable && (parsestage & HAVE_BODY)) + break ; + + if (psf_ftell (psf) >= psf->filelength - SIGNED_SIZEOF (chunk_size)) + break ; + } ; /* while (1) */ + + if (vhdr.compression) + return SFE_SVX_BAD_COMP ; + + if (psf->dataoffset <= 0) + return SFE_SVX_NO_DATA ; + + return 0 ; +} /* svx_read_header */ + +static int +svx_close (SF_PRIVATE *psf) +{ + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + svx_write_header (psf, SF_TRUE) ; + + return 0 ; +} /* svx_close */ + +static int +svx_write_header (SF_PRIVATE *psf, int calc_length) +{ static char annotation [] = "libsndfile by Erik de Castro Lopo\0\0\0" ; + sf_count_t current ; + + current = psf_ftell (psf) ; + + if (calc_length) + { psf->filelength = psf_get_filelen (psf) ; + + psf->datalength = psf->filelength - psf->dataoffset ; + + if (psf->dataend) + psf->datalength -= psf->filelength - psf->dataend ; + + psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ; + } ; + + psf->header.ptr [0] = 0 ; + psf->header.indx = 0 ; + psf_fseek (psf, 0, SEEK_SET) ; + + /* FORM marker and FORM size. */ + psf_binheader_writef (psf, "Etm8", BHWm (FORM_MARKER), BHW8 ((psf->filelength < 8) ? + psf->filelength * 0 : psf->filelength - 8)) ; + + psf_binheader_writef (psf, "m", BHWm ((psf->bytewidth == 1) ? SVX8_MARKER : SV16_MARKER)) ; + + /* VHDR chunk. */ + psf_binheader_writef (psf, "Em4", BHWm (VHDR_MARKER), BHW4 (sizeof (VHDR_CHUNK))) ; + /* VHDR : oneShotHiSamples, repeatHiSamples, samplesPerHiCycle */ + psf_binheader_writef (psf, "E444", BHW4 (psf->sf.frames), BHW4 (0), BHW4 (0)) ; + /* VHDR : samplesPerSec, octave, compression */ + psf_binheader_writef (psf, "E211", BHW2 (psf->sf.samplerate), BHW1 (1), BHW1 (0)) ; + /* VHDR : volume */ + psf_binheader_writef (psf, "E4", BHW4 ((psf->bytewidth == 1) ? 0xFF : 0xFFFF)) ; + + if (psf->sf.channels == 2) + psf_binheader_writef (psf, "Em44", BHWm (CHAN_MARKER), BHW4 (4), BHW4 (6)) ; + + /* Filename and annotation strings. */ + psf_binheader_writef (psf, "Emsms", BHWm (NAME_MARKER), BHWs (psf->file.name), BHWm (ANNO_MARKER), BHWs (annotation)) ; + + /* BODY marker and size. */ + psf_binheader_writef (psf, "Etm8", BHWm (BODY_MARKER), BHW8 ((psf->datalength < 0) ? + psf->datalength * 0 : psf->datalength)) ; + + psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ; + + if (psf->error) + return psf->error ; + + psf->dataoffset = psf->header.indx ; + + if (current > 0) + psf_fseek (psf, current, SEEK_SET) ; + + return psf->error ; +} /* svx_write_header */ + diff --git a/extern/libsndfile-modified/src/test_audio_detect.c b/extern/libsndfile-modified/src/test_audio_detect.c new file mode 100644 index 000000000..20926df03 --- /dev/null +++ b/extern/libsndfile-modified/src/test_audio_detect.c @@ -0,0 +1,113 @@ +/* +** Copyright (C) 2007-2011 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include + +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include +#include + +#include "common.h" +#include "sfendian.h" + +#include "test_main.h" + +static unsigned char float_le_mono [] = +{ 0x36, 0x86, 0x21, 0x44, 0xB5, 0xB4, 0x49, 0x44, 0xA2, 0xC0, 0x71, 0x44, 0x7B, 0xD1, 0x8C, 0x44, + 0x54, 0xAA, 0xA0, 0x44, 0x60, 0x67, 0xB4, 0x44, 0x22, 0x05, 0xC8, 0x44, 0x29, 0x80, 0xDB, 0x44, + 0x04, 0xD5, 0xEE, 0x44, 0x27, 0x00, 0x01, 0x45, 0x50, 0x7F, 0x0A, 0x45, 0x53, 0xE6, 0x13, 0x45, + 0x85, 0x33, 0x1D, 0x45, 0x43, 0x65, 0x26, 0x45, 0xEC, 0x79, 0x2F, 0x45, 0xE3, 0x6F, 0x38, 0x45, + 0x98, 0x45, 0x41, 0x45, 0x77, 0xF9, 0x49, 0x45, 0xF6, 0x89, 0x52, 0x45, 0x8F, 0xF5, 0x5A, 0x45, + 0xC9, 0x3A, 0x63, 0x45, 0x28, 0x58, 0x6B, 0x45, 0x3C, 0x4C, 0x73, 0x45, 0x9F, 0x15, 0x7B, 0x45, + 0x75, 0x59, 0x81, 0x45, 0x64, 0x11, 0x85, 0x45, 0xF1, 0xB1, 0x88, 0x45, 0x78, 0x3A, 0x8C, 0x45, + 0x58, 0xAA, 0x8F, 0x45, 0xF2, 0x00, 0x93, 0x45, 0xB2, 0x3D, 0x96, 0x45, 0x01, 0x60, 0x99, 0x45, + 0x50, 0x67, 0x9C, 0x45, 0x15, 0x53, 0x9F, 0x45, 0xCC, 0x22, 0xA2, 0x45, 0xF0, 0xD5, 0xA4, 0x45, + 0x07, 0x6C, 0xA7, 0x45, 0x9C, 0xE4, 0xA9, 0x45, 0x3D, 0x3F, 0xAC, 0x45, 0x7A, 0x7B, 0xAE, 0x45, + 0xF2, 0x98, 0xB0, 0x45, 0x3C, 0x97, 0xB2, 0x45, 0x02, 0x76, 0xB4, 0x45, 0xEC, 0x34, 0xB6, 0x45, + 0xA8, 0xD3, 0xB7, 0x45, 0xEB, 0x51, 0xB9, 0x45, 0x6F, 0xAF, 0xBA, 0x45, 0xF5, 0xEB, 0xBB, 0x45, + 0x41, 0x07, 0xBD, 0x45, 0x21, 0x01, 0xBE, 0x45, 0x64, 0xD9, 0xBE, 0x45, 0xE3, 0x8F, 0xBF, 0x45, + 0x7E, 0x24, 0xC0, 0x45, 0x15, 0x97, 0xC0, 0x45, 0x92, 0xE7, 0xC0, 0x45, 0xE8, 0x15, 0xC1, 0x45, + 0x7E, 0x24, 0xC0, 0x45, 0x15, 0x97, 0xC0, 0x45, 0x92, 0xE7, 0xC0, 0x45, 0xE8, 0x15, 0xC1, 0x45, + 0x7E, 0x24, 0xC0, 0x45, 0x15, 0x97, 0xC0, 0x45, 0x92, 0xE7, 0xC0, 0x45, 0xE8, 0x15, 0xC1, 0x45, +} ; + +static unsigned char int24_32_le_stereo [] = +{ + 0x00, 0xE7, 0xFB, 0xFF, 0x00, 0x7C, 0xFD, 0xFF, 0x00, 0xA2, 0xFC, 0xFF, 0x00, 0x2B, 0xFC, 0xFF, + 0x00, 0xF3, 0xFD, 0xFF, 0x00, 0x19, 0xFB, 0xFF, 0x00, 0xA5, 0xFE, 0xFF, 0x00, 0x8D, 0xFA, 0xFF, + 0x00, 0x91, 0xFF, 0xFF, 0x00, 0xB5, 0xFA, 0xFF, 0x00, 0x91, 0x00, 0x00, 0x00, 0x5E, 0xFB, 0xFF, + 0x00, 0xD9, 0x01, 0x00, 0x00, 0x82, 0xFB, 0xFF, 0x00, 0xDF, 0x03, 0x00, 0x00, 0x44, 0xFC, 0xFF, + 0x00, 0x1C, 0x05, 0x00, 0x00, 0x77, 0xFC, 0xFF, 0x00, 0x8D, 0x06, 0x00, 0x00, 0x4F, 0xFC, 0xFF, + 0x00, 0x84, 0x07, 0x00, 0x00, 0x74, 0xFC, 0xFF, 0x00, 0x98, 0x08, 0x00, 0x00, 0x33, 0xFD, 0xFF, + 0x00, 0xB9, 0x09, 0x00, 0x00, 0x48, 0xFF, 0xFF, 0x00, 0xD1, 0x0A, 0x00, 0x00, 0x10, 0x02, 0x00, + 0x00, 0x28, 0x0C, 0x00, 0x00, 0xA2, 0x05, 0x00, 0x00, 0xA7, 0x0C, 0x00, 0x00, 0x45, 0x08, 0x00, + 0x00, 0x44, 0x0D, 0x00, 0x00, 0x1A, 0x0A, 0x00, 0x00, 0x65, 0x0D, 0x00, 0x00, 0x51, 0x0B, 0x00, + 0x00, 0x8B, 0x0D, 0x00, 0x00, 0x18, 0x0B, 0x00, 0x00, 0x37, 0x0E, 0x00, 0x00, 0x24, 0x0B, 0x00, + 0x00, 0x00, 0x0F, 0x00, 0x00, 0xDD, 0x0A, 0x00, 0x00, 0x83, 0x10, 0x00, 0x00, 0x31, 0x0A, 0x00, + 0x00, 0x07, 0x12, 0x00, 0x00, 0xC0, 0x08, 0x00, 0x00, 0xF7, 0x12, 0x00, 0x00, 0x47, 0x06, 0x00, + 0x00, 0xDD, 0x12, 0x00, 0x00, 0x6A, 0x03, 0x00, 0x00, 0xD5, 0x11, 0x00, 0x00, 0x99, 0x00, 0x00, + 0x00, 0x01, 0x10, 0x00, 0x00, 0xC5, 0xFE, 0xFF, 0x00, 0xF4, 0x0D, 0x00, 0x00, 0x97, 0xFD, 0xFF, + 0x00, 0x62, 0x0B, 0x00, 0x00, 0x75, 0xFC, 0xFF, 0x00, 0xE9, 0x08, 0x00, 0x00, 0xC0, 0xFB, 0xFF, + 0x00, 0x80, 0x06, 0x00, 0x00, 0x3C, 0xFB, 0xFF, 0x00, 0xDA, 0x03, 0x00, 0x00, 0xE4, 0xFA, 0xFF, + 0x00, 0xEB, 0x01, 0x00, 0x00, 0x21, 0xFB, 0xFF, 0x00, 0x20, 0x00, 0x00, 0x00, 0xE7, 0xFB, 0xFF, +} ; + + +void +test_audio_detect (void) +{ + SF_PRIVATE psf ; + AUDIO_DETECT ad ; + int errors = 0 ; + + print_test_name ("Testing audio detect") ; + + memset (&psf, 0, sizeof (psf)) ; + + ad.endianness = SF_ENDIAN_LITTLE ; + ad.channels = 1 ; + if (audio_detect (&psf, &ad, float_le_mono, sizeof (float_le_mono)) != SF_FORMAT_FLOAT) + { puts (" float_le_mono") ; + errors ++ ; + } ; + + ad.endianness = SF_ENDIAN_LITTLE ; + ad.channels = 2 ; + if (audio_detect (&psf, &ad, int24_32_le_stereo, sizeof (int24_32_le_stereo)) != SF_FORMAT_PCM_32) + { if (errors == 0) puts ("\nFailed tests :\n") ; + puts (" int24_32_le_stereo") ; + errors ++ ; + } ; + + if (errors != 0) + { printf ("\n Errors : %d\n\n", errors) ; + exit (1) ; + } ; + + puts ("ok") ; + + return ; +} /* test_audio_detect */ diff --git a/extern/libsndfile-modified/src/test_binheader_writef.c b/extern/libsndfile-modified/src/test_binheader_writef.c new file mode 100644 index 000000000..8b1f9c1ea --- /dev/null +++ b/extern/libsndfile-modified/src/test_binheader_writef.c @@ -0,0 +1,61 @@ +/* +** Copyright (C) 2017 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include +#include + +#include "common.h" + +#include "test_main.h" + +void +test_binheader_writef (void) +{ char buffer [18] ; + SF_PRIVATE sf_private, *psf ; + int k, errors = 0 ; + + print_test_name ("Testing binheader_writef") ; + + memset (&sf_private, 0, sizeof (sf_private)) ; + + psf = &sf_private ; + for (k = 0 ; errors == 0 && k < 10 ; k++) + { psf_strlcpy (buffer, sizeof (buffer), "abcdefghijklmnop") ; + buffer [k] = 0 ; + + psf_binheader_writef (psf, "Ep", BHWp (buffer)) ; + + if ((psf->header.indx & 1) != 0) + errors = 1 ; + } ; + + free (psf->header.ptr) ; + + if (errors) + { puts ("\nExiting due to errors.\n") ; + exit (1) ; + } ; + + puts ("ok") ; +} /* test_log_printf */ + diff --git a/extern/libsndfile-modified/src/test_broadcast_var.c b/extern/libsndfile-modified/src/test_broadcast_var.c new file mode 100644 index 000000000..5ae81fb18 --- /dev/null +++ b/extern/libsndfile-modified/src/test_broadcast_var.c @@ -0,0 +1,123 @@ +/* +** Copyright (C) 2010-2012 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include + +#include "common.h" + +#include "test_main.h" + +#define BCAST_MAX 512 + +typedef SF_BROADCAST_INFO_VAR (BCAST_MAX) SF_BROADCAST_INFO_512 ; + +static void +fill_coding_history (SF_BROADCAST_INFO_512 * bi) +{ static const char *lines [] = + { "Lorem ipsum dolor sit amet,\nconsectetur adipiscing elit.", + "Donec dignissim erat\nvehicula libero condimentum\ndictum porta augue faucibus.", + "Maecenas nec turpis\nsit amet quam\nfaucibus adipiscing.", + "Mauris aliquam,\nlectus interdum\ntincidunt luctus.", + "\n\n\n\n\n\n\n\n\n\n\n\n", + "In auctor lorem\nvel est euismod\ncondimentum.", + "\n\n\n\n\n\n\n\n\n\n\n\n", + "Ut vitae magna\nid dui placerat vehicula\nin id lectus.", + "\n\n\n\n\n\n\n\n\n\n\n\n", + "Sed lacus leo,\nmolestie et luctus ac,\ntincidunt sit amet nisi.", + "\n\n\n\n\n\n\n\n\n\n\n\n", + "Sed ligula neque,\ngravida semper vulputate laoreet,\ngravida eu tellus.", + "Donec dolor dolor,\nscelerisque in consequat ornare,\ntempor nec nisl." + } ; + int k ; + + bi->coding_history [0] = 0 ; + + for (k = 0 ; strlen (bi->coding_history) < bi->coding_history_size - 1 ; k ++) + append_snprintf (bi->coding_history, bi->coding_history_size, "%s\n", lines [k % ARRAY_LEN (lines)]) ; + + return ; +} /* fill_coding_listory */ + +static void +test_broadcast_var_set (void) +{ SF_PRIVATE sf_private, *psf ; + int k ; + + psf = &sf_private ; + memset (psf, 0, sizeof (sf_private)) ; + + print_test_name ("Testing broadcast_var_set ") ; + + for (k = 64 ; k < BCAST_MAX ; k++) + { + SF_BROADCAST_INFO_512 bi ; + + memset (&bi, 0, sizeof (bi)) ; + + bi.coding_history_size = k ; + fill_coding_history (&bi) ; + bi.coding_history_size -- ; + + broadcast_var_set (psf, (SF_BROADCAST_INFO*) &bi, sizeof (bi)) ; + } ; + + if (psf->broadcast_16k != NULL) + free (psf->broadcast_16k) ; + + puts ("ok") ; +} /* test_broadcast_var_set */ + +static void +test_broadcast_var_zero (void) +{ SF_PRIVATE sf_private, *psf ; +#ifdef _MSC_VER + SF_BROADCAST_INFO_VAR (0) bi ; +#else + SF_BROADCAST_INFO_VAR () bi ; +#endif + + psf = &sf_private ; + memset (psf, 0, sizeof (sf_private)) ; + psf->file.mode = SFM_RDWR ; + + print_test_name ("Testing broadcast_var_zero ") ; + + memset (&bi, 0, sizeof (bi)) ; + + broadcast_var_set (psf, (SF_BROADCAST_INFO*) &bi, sizeof (bi)) ; + + if (psf->broadcast_16k->coding_history_size != 0) + { printf ("\n\nLine %d: coding_history_size %d should be zero.\n\n", __LINE__, psf->broadcast_16k->coding_history_size) ; + exit (1) ; + } ; + + if (psf->broadcast_16k != NULL) + free (psf->broadcast_16k) ; + + puts ("ok") ; +} /* test_broadcast_var_zero */ + +void +test_broadcast_var (void) +{ test_broadcast_var_set () ; + test_broadcast_var_zero () ; +} /* test_broadcast_var */ diff --git a/extern/libsndfile-modified/src/test_cart_var.c b/extern/libsndfile-modified/src/test_cart_var.c new file mode 100644 index 000000000..532a75587 --- /dev/null +++ b/extern/libsndfile-modified/src/test_cart_var.c @@ -0,0 +1,91 @@ +/* +** Copyright (C) 2010-2013 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include + +#include "common.h" + +#include "test_main.h" + +#define CART_MAX 512 + +typedef SF_CART_INFO_VAR (CART_MAX) SF_CART_INFO_512 ; + +static void +fill_tag_text (SF_CART_INFO_512 * ci) +{ static const char *lines [] = + { "Lorem ipsum dolor sit amet,\nconsectetur adipiscing elit.", + "Donec dignissim erat\nvehicula libero condimentum\ndictum porta augue faucibus.", + "Maecenas nec turpis\nsit amet quam\nfaucibus adipiscing.", + "Mauris aliquam,\nlectus interdum\ntincidunt luctus.", + "\n\n\n\n\n\n\n\n\n\n\n\n", + "In auctor lorem\nvel est euismod\ncondimentum.", + "\n\n\n\n\n\n\n\n\n\n\n\n", + "Ut vitae magna\nid dui placerat vehicula\nin id lectus.", + "\n\n\n\n\n\n\n\n\n\n\n\n", + "Sed lacus leo,\nmolestie et luctus ac,\ntincidunt sit amet nisi.", + "\n\n\n\n\n\n\n\n\n\n\n\n", + "Sed ligula neque,\ngravida semper vulputate laoreet,\ngravida eu tellus.", + "Donec dolor dolor,\nscelerisque in consequat ornare,\ntempor nec nisl." + } ; + int k ; + + ci->tag_text [0] = 0 ; + + for (k = 0 ; strlen (ci->tag_text) < ci->tag_text_size - 1 ; k ++) + append_snprintf (ci->tag_text, ci->tag_text_size, "%s\n", lines [k % ARRAY_LEN (lines)]) ; + + return ; +} /* fill_tag_text */ + +void +test_cart_var (void) +{ SF_PRIVATE sf_private, *psf ; + SF_CART_TIMER timer ; + int k ; + + psf = &sf_private ; + memset (psf, 0, sizeof (sf_private)) ; + + print_test_name ("Testing cart_var_set ") ; + + for (k = 64 ; k < CART_MAX ; k++) + { + SF_CART_INFO_512 ci ; + + memset (&ci, 0, sizeof (ci)) ; + + memset (&timer, 0, sizeof (timer)) ; + memcpy (ci.post_timers, &timer, sizeof (timer)) ; + + ci.tag_text_size = k ; + fill_tag_text (&ci) ; + ci.tag_text_size -- ; + + cart_var_set (psf, (SF_CART_INFO*) &ci, sizeof (ci)) ; + } ; + + if (psf->cart_16k != NULL) + free (psf->cart_16k) ; + + puts ("ok") ; +} /* test_cart_var */ diff --git a/extern/libsndfile-modified/src/test_conversions.c b/extern/libsndfile-modified/src/test_conversions.c new file mode 100644 index 000000000..f717fa58a --- /dev/null +++ b/extern/libsndfile-modified/src/test_conversions.c @@ -0,0 +1,112 @@ +/* +** Copyright (C) 2006-2016 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "test_main.h" + + +/* +** This is a bit rough, but it is the nicest way to do it. +*/ + +#define cmp_test(line, ival, tval, str) \ + if (ival != tval) \ + { printf (str, line, ival, tval) ; \ + exit (1) ; \ + } ; + +static void +conversion_test (char endian) +{ + SF_PRIVATE sf_private, *psf ; + const char * filename = "conversion.bin" ; + int64_t i64 = 0x0123456789ABCDEFLL, t64 = 0 ; + char format_str [16] ; + char test_name [64] ; + char i8 = 12, t8 = 0 ; + short i16 = 0x123, t16 = 0 ; + int i24 = 0x23456, t24 = 0 ; + int i32 = 0x0a0b0c0d, t32 = 0 ; + int bytes ; + + snprintf (format_str, sizeof (format_str), "%c12348", endian) ; + + snprintf (test_name, sizeof (test_name), "Testing %s conversions", endian == 'e' ? "little endian" : "big endian") ; + print_test_name (test_name) ; + + psf = &sf_private ; + memset (psf, 0, sizeof (sf_private)) ; + + psf->file.mode = SFM_WRITE ; + snprintf (psf->file.path, sizeof (psf->file.path), "%s", filename) ; + + if (psf_fopen (psf) != 0) + { printf ("\n\nError : failed to open file '%s' for write.\n\n", filename) ; + exit (1) ; + } ; + + psf_binheader_writef (psf, format_str, i8, i16, i24, i32, i64) ; + psf_fwrite (psf->header.ptr, 1, psf->header.indx, psf) ; + free (psf->header.ptr) ; + psf_fclose (psf) ; + + memset (psf, 0, sizeof (sf_private)) ; + + psf->file.mode = SFM_READ ; + snprintf (psf->file.path, sizeof (psf->file.path), "%s", filename) ; + + if (psf_fopen (psf) != 0) + { printf ("\n\nError : failed to open file '%s' for read.\n\n", filename) ; + exit (1) ; + } ; + + bytes = psf_binheader_readf (psf, format_str, &t8, &t16, &t24, &t32, &t64) ; + free (psf->header.ptr) ; + psf_fclose (psf) ; + + if (bytes != 18) + { printf ("\n\nLine %d : read %d bytes.\n\n", __LINE__, bytes) ; + exit (1) ; + } ; + + cmp_test (__LINE__, i8, t8, "\n\nLine %d : 8 bit int failed %d -> %d.\n\n") ; + cmp_test (__LINE__, i16, t16, "\n\nLine %d : 16 bit int failed 0x%x -> 0x%x.\n\n") ; + cmp_test (__LINE__, i24, t24, "\n\nLine %d : 24 bit int failed 0x%x -> 0x%x.\n\n") ; + cmp_test (__LINE__, i32, t32, "\n\nLine %d : 32 bit int failed 0x%x -> 0x%x.\n\n") ; + cmp_test (__LINE__, i64, t64, "\n\nLine %d : 64 bit int failed 0x%" PRIx64 "x -> 0x%" PRIx64 "x.\n\n") ; + + remove (filename) ; + puts ("ok") ; +} /* conversion_test */ + +void +test_conversions (void) +{ + conversion_test ('E') ; + conversion_test ('e') ; +} /* test_conversion */ + diff --git a/extern/libsndfile-modified/src/test_endswap.def b/extern/libsndfile-modified/src/test_endswap.def new file mode 100644 index 000000000..1d6ab1f0d --- /dev/null +++ b/extern/libsndfile-modified/src/test_endswap.def @@ -0,0 +1,40 @@ +autogen definitions test_endswap.tpl; + +int_type = { + name = short ; + value = '0x3210' ; + format = FMT_SHORT ; + } ; + +int_type = { + name = int ; + value = '0x76543210' ; + format = FMT_INT ; + } ; + +int_type = { + name = int64_t ; + value = '0x0807050540302010LL' ; + format = FMT_INT64 ; + } ; + +int_size = { + name = 16 ; + typename = int16_t ; + value = '0x4142' ; + strval = "AB" ; + } ; + +int_size = { + name = 32 ; + typename = int32_t ; + value = '0x30313233' ; + strval = "0123" ; + } ; + +int_size = { + name = 64 ; + typename = int64_t ; + value = '0x3031323334353637' ; + strval = "01234567" ; + } ; diff --git a/extern/libsndfile-modified/src/test_endswap.tpl b/extern/libsndfile-modified/src/test_endswap.tpl new file mode 100644 index 000000000..348a6be60 --- /dev/null +++ b/extern/libsndfile-modified/src/test_endswap.tpl @@ -0,0 +1,153 @@ +[+ AutoGen5 template c +] +/* +** Copyright (C) 2002-2016 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include +#include + +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include "common.h" +#include "sfendian.h" + +#include "test_main.h" + +#define FMT_SHORT "0x%04x\n" +#define FMT_INT "0x%08x\n" +#define FMT_INT64 "0x%016" PRIx64 "\n" + +/*============================================================================== +** Test functions. +*/ + +[+ FOR int_type +] +static void +dump_[+ (get "name") +]_array (const char * name, [+ (get "name") +] * data, int datalen) +{ int k ; + + printf ("%-6s : ", name) ; + for (k = 0 ; k < datalen ; k++) + printf ([+ (get "format") +], data [k]) ; + putchar ('\n') ; +} /* dump_[+ (get "name") +]_array */ + +static void +test_endswap_[+ (get "name") +] (void) +{ [+ (get "name") +] orig [4], first [4], second [4] ; + int64_t k ; + + printf (" %-40s : ", "test_endswap_[+ (get "name") +]") ; + fflush (stdout) ; + + for (k = 0 ; k < ARRAY_LEN (orig) ; k++) + orig [k] = [+ (get "value") +] + k ; + + endswap_[+ (get "name") +]_copy (first, orig, ARRAY_LEN (first)) ; + endswap_[+ (get "name") +]_copy (second, first, ARRAY_LEN (second)) ; + + if (memcmp (orig, first, sizeof (orig)) == 0) + { printf ("\n\nLine %d : test 1 : these two array should not be the same:\n\n", __LINE__) ; + dump_[+ (get "name") +]_array ("orig", orig, ARRAY_LEN (orig)) ; + dump_[+ (get "name") +]_array ("first", first, ARRAY_LEN (first)) ; + exit (1) ; + } ; + + if (memcmp (orig, second, sizeof (orig)) != 0) + { printf ("\n\nLine %d : test 2 : these two array should be the same:\n\n", __LINE__) ; + dump_[+ (get "name") +]_array ("orig", orig, ARRAY_LEN (orig)) ; + dump_[+ (get "name") +]_array ("second", second, ARRAY_LEN (second)) ; + exit (1) ; + } ; + + endswap_[+ (get "name") +]_array (first, ARRAY_LEN (first)) ; + + if (memcmp (orig, first, sizeof (orig)) != 0) + { printf ("\n\nLine %d : test 3 : these two array should be the same:\n\n", __LINE__) ; + dump_[+ (get "name") +]_array ("orig", orig, ARRAY_LEN (orig)) ; + dump_[+ (get "name") +]_array ("first", first, ARRAY_LEN (first)) ; + exit (1) ; + } ; + + endswap_[+ (get "name") +]_copy (first, orig, ARRAY_LEN (first)) ; + endswap_[+ (get "name") +]_copy (first, first, ARRAY_LEN (first)) ; + + if (memcmp (orig, first, sizeof (orig)) != 0) + { printf ("\n\nLine %d : test 4 : these two array should be the same:\n\n", __LINE__) ; + dump_[+ (get "name") +]_array ("orig", orig, ARRAY_LEN (orig)) ; + dump_[+ (get "name") +]_array ("first", first, ARRAY_LEN (first)) ; + exit (1) ; + } ; + + puts ("ok") ; +} /* test_endswap_[+ (get "name") +] */ +[+ ENDFOR int_type ++] + +[+ FOR int_size +] +static void +test_psf_put_be[+ (get "name") +] (void) +{ const char *test = "[+ (get "strval") +]" ; + uint8_t array [32] ; + int k ; + + printf (" %-40s : ", __func__) ; + fflush (stdout) ; + + for (k = 0 ; k < 10 ; k++) + { memset (array, 0, sizeof (array)) ; + + psf_put_be[+ (get "name") +] (array, k, [+ (get "value") +]) ; + if (memcmp (array + k, test, sizeof ([+ (get "typename") +])) != 0) + { printf ("\n\nLine %d : Put failed at index %d.\n", __LINE__, k) ; + exit (1) ; + } ; + if (psf_get_be[+ (get "name") +] (array, k) != [+ (get "value") +]) + { printf ("\n\nLine %d : Get failed at index %d.\n", __LINE__, k) ; + exit (1) ; + } ; + } ; + + puts ("ok") ; +} /* test_psf_put_be[+ (get "name") +] */ +[+ ENDFOR int_size ++] + +void +test_endswap (void) +{ +[+ FOR int_type ++] test_endswap_[+ (get "name") +] () ; +[+ ENDFOR int_type ++] + +[+ FOR int_size ++] test_psf_put_be[+ (get "name") +] () ; +[+ ENDFOR int_size ++] + +} /* test_endswap */ + diff --git a/extern/libsndfile-modified/src/test_file_io.c b/extern/libsndfile-modified/src/test_file_io.c new file mode 100644 index 000000000..1e5b0f568 --- /dev/null +++ b/extern/libsndfile-modified/src/test_file_io.c @@ -0,0 +1,492 @@ +/* +** Copyright (C) 2002-2011 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include + +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include +#include +#include + +#include "common.h" + +#include "test_main.h" + +static void make_data (int *data, int len, int seed) ; + +static void file_open_test (const char *filename) ; +static void file_read_write_test (const char *filename) ; +static void file_truncate_test (const char *filename) ; + +static void test_open_or_die (SF_PRIVATE *psf, int linenum) ; +static void test_close_or_die (SF_PRIVATE *psf, int linenum) ; + +static void test_write_or_die (SF_PRIVATE *psf, void *data, sf_count_t bytes, sf_count_t items, sf_count_t new_position, int linenum) ; +static void test_read_or_die (SF_PRIVATE *psf, void *data, sf_count_t bytes, sf_count_t items, sf_count_t new_position, int linenum) ; +static void test_equal_or_die (int *array1, int *array2, int len, int linenum) ; +static void test_seek_or_die (SF_PRIVATE *psf, sf_count_t offset, int whence, sf_count_t new_position, int linenum) ; +static void test_tell_or_die (SF_PRIVATE *psf, sf_count_t expected_position, int linenum) ; + + + +/*============================================================================== +** Actual test functions. +*/ + +static void +file_open_test (const char *filename) +{ SF_PRIVATE sf_data, *psf ; + int error ; + + print_test_name ("Testing file open") ; + + memset (&sf_data, 0, sizeof (sf_data)) ; + psf = &sf_data ; + + /* Ensure that the file doesn't already exist. */ + if (unlink (filename) != 0 && errno != ENOENT) + { printf ("\n\nLine %d: unlink failed (%d) : %s\n\n", __LINE__, errno, strerror (errno)) ; + exit (1) ; + } ; + + psf->file.mode = SFM_READ ; + snprintf (psf->file.path, sizeof (psf->file.path), "%s", filename) ; + + /* Test that open for read fails if the file doesn't exist. */ + error = psf_fopen (psf) ; + if (error == 0) + { printf ("\n\nLine %d: psf_fopen() should have failed.\n\n", __LINE__) ; + exit (1) ; + } ; + + /* Reset error to zero. */ + psf->error = SFE_NO_ERROR ; + + /* Test file open in write mode. */ + psf->file.mode = SFM_WRITE ; + test_open_or_die (psf, __LINE__) ; + + test_close_or_die (psf, __LINE__) ; + + unlink (psf->file.path) ; + + /* Test file open in read/write mode for a non-existant file. */ + psf->file.mode = SFM_RDWR ; + test_open_or_die (psf, __LINE__) ; + + test_close_or_die (psf, __LINE__) ; + + /* Test file open in read/write mode for an existing file. */ + psf->file.mode = SFM_RDWR ; + test_open_or_die (psf, __LINE__) ; + + test_close_or_die (psf, __LINE__) ; + + unlink (psf->file.path) ; + puts ("ok") ; +} /* file_open_test */ + +static void +file_read_write_test (const char *filename) +{ static int data_out [512] ; + static int data_in [512] ; + + SF_PRIVATE sf_data, *psf ; + sf_count_t retval ; + + /* + ** Open a new file and write two blocks of data to the file. After each + ** write, test that psf_get_filelen() returns the new length. + */ + + print_test_name ("Testing file write") ; + + memset (&sf_data, 0, sizeof (sf_data)) ; + psf = &sf_data ; + snprintf (psf->file.path, sizeof (psf->file.path), "%s", filename) ; + + /* Test file open in write mode. */ + psf->file.mode = SFM_WRITE ; + test_open_or_die (psf, __LINE__) ; + + make_data (data_out, ARRAY_LEN (data_out), 1) ; + test_write_or_die (psf, data_out, sizeof (data_out [0]), ARRAY_LEN (data_out), sizeof (data_out), __LINE__) ; + + if ((retval = psf_get_filelen (psf)) != sizeof (data_out)) + { printf ("\n\nLine %d: file length after write is not correct (%" PRId64 " should be %zd).\n\n", __LINE__, retval, sizeof (data_out)) ; + if (retval == 0) + printf ("An fsync() may be necessary before fstat() in psf_get_filelen().\n\n") ; + exit (1) ; + } ; + + make_data (data_out, ARRAY_LEN (data_out), 2) ; + test_write_or_die (psf, data_out, ARRAY_LEN (data_out), sizeof (data_out [0]), 2 * sizeof (data_out), __LINE__) ; + + if ((retval = psf_get_filelen (psf)) != 2 * sizeof (data_out)) + { printf ("\n\nLine %d: file length after write is not correct. (%" PRId64 " should be %zd)\n\n", __LINE__, retval, 2 * sizeof (data_out)) ; + exit (1) ; + } ; + + test_close_or_die (psf, __LINE__) ; + puts ("ok") ; + + /* + ** Now open the file in read mode, check the file length and check + ** that the data is correct. + */ + + print_test_name ("Testing file read") ; + + /* Test file open in write mode. */ + psf->file.mode = SFM_READ ; + test_open_or_die (psf, __LINE__) ; + + make_data (data_out, ARRAY_LEN (data_out), 1) ; + test_read_or_die (psf, data_in, 1, sizeof (data_in), sizeof (data_in), __LINE__) ; + test_equal_or_die (data_out, data_in, ARRAY_LEN (data_out), __LINE__) ; + + make_data (data_out, ARRAY_LEN (data_out), 2) ; + test_read_or_die (psf, data_in, sizeof (data_in [0]), ARRAY_LEN (data_in), 2 * sizeof (data_in), __LINE__) ; + test_equal_or_die (data_out, data_in, ARRAY_LEN (data_out), __LINE__) ; + + test_close_or_die (psf, __LINE__) ; + + puts ("ok") ; + + /* + ** Open the file in read/write mode, seek around a bit and then seek to + ** the end of the file and write another block of data (3rd block). Then + ** go back and check that all three blocks are correct. + */ + + print_test_name ("Testing file seek") ; + + /* Test file open in read/write mode. */ + psf->file.mode = SFM_RDWR ; + test_open_or_die (psf, __LINE__) ; + + test_seek_or_die (psf, 0, SEEK_SET, 0, __LINE__) ; + test_seek_or_die (psf, 0, SEEK_END, 2 * SIGNED_SIZEOF (data_out), __LINE__) ; + test_seek_or_die (psf, -1 * SIGNED_SIZEOF (data_out), SEEK_CUR, (sf_count_t) sizeof (data_out), __LINE__) ; + + test_seek_or_die (psf, SIGNED_SIZEOF (data_out), SEEK_CUR, 2 * SIGNED_SIZEOF (data_out), __LINE__) ; + make_data (data_out, ARRAY_LEN (data_out), 3) ; + test_write_or_die (psf, data_out, sizeof (data_out [0]), ARRAY_LEN (data_out), 3 * sizeof (data_out), __LINE__) ; + + test_seek_or_die (psf, 0, SEEK_SET, 0, __LINE__) ; + make_data (data_out, ARRAY_LEN (data_out), 1) ; + test_read_or_die (psf, data_in, 1, sizeof (data_in), sizeof (data_in), __LINE__) ; + test_equal_or_die (data_out, data_in, ARRAY_LEN (data_out), __LINE__) ; + + test_seek_or_die (psf, 2 * SIGNED_SIZEOF (data_out), SEEK_SET, 2 * SIGNED_SIZEOF (data_out), __LINE__) ; + make_data (data_out, ARRAY_LEN (data_out), 3) ; + test_read_or_die (psf, data_in, 1, sizeof (data_in), 3 * sizeof (data_in), __LINE__) ; + test_equal_or_die (data_out, data_in, ARRAY_LEN (data_out), __LINE__) ; + + test_seek_or_die (psf, SIGNED_SIZEOF (data_out), SEEK_SET, SIGNED_SIZEOF (data_out), __LINE__) ; + make_data (data_out, ARRAY_LEN (data_out), 2) ; + test_read_or_die (psf, data_in, 1, sizeof (data_in), 2 * sizeof (data_in), __LINE__) ; + test_equal_or_die (data_out, data_in, ARRAY_LEN (data_out), __LINE__) ; + + test_close_or_die (psf, __LINE__) ; + puts ("ok") ; + + /* + ** Now test operations with a non-zero psf->fileoffset field. This field + ** sets an artificial file start positions so that a seek to the start of + ** the file will actually be a seek to the value given by psf->fileoffset. + */ + + print_test_name ("Testing file offset") ; + + /* Test file open in read/write mode. */ + psf->file.mode = SFM_RDWR ; + psf->fileoffset = sizeof (data_out [0]) * ARRAY_LEN (data_out) ; + test_open_or_die (psf, __LINE__) ; + + if ((retval = psf_get_filelen (psf)) != 3 * sizeof (data_out)) + { printf ("\n\nLine %d: file length after write is not correct. (%" PRId64 " should be %zd)\n\n", __LINE__, retval, 3 * sizeof (data_out)) ; + exit (1) ; + } ; + + test_seek_or_die (psf, SIGNED_SIZEOF (data_out), SEEK_SET, SIGNED_SIZEOF (data_out), __LINE__) ; + make_data (data_out, ARRAY_LEN (data_out), 5) ; + test_write_or_die (psf, data_out, sizeof (data_out [0]), ARRAY_LEN (data_out), 2 * sizeof (data_out), __LINE__) ; + test_close_or_die (psf, __LINE__) ; + + /* final test with psf->fileoffset == 0. */ + + psf->file.mode = SFM_RDWR ; + psf->fileoffset = 0 ; + test_open_or_die (psf, __LINE__) ; + + if ((retval = psf_get_filelen (psf)) != 3 * sizeof (data_out)) + { printf ("\n\nLine %d: file length after write is not correct. (%" PRId64 " should be %zd)\n\n", __LINE__, retval, 3 * sizeof (data_out)) ; + exit (1) ; + } ; + + make_data (data_out, ARRAY_LEN (data_out), 1) ; + test_read_or_die (psf, data_in, 1, sizeof (data_in), sizeof (data_in), __LINE__) ; + test_equal_or_die (data_out, data_in, ARRAY_LEN (data_out), __LINE__) ; + + make_data (data_out, ARRAY_LEN (data_out), 2) ; + test_read_or_die (psf, data_in, 1, sizeof (data_in), 2 * sizeof (data_in), __LINE__) ; + test_equal_or_die (data_out, data_in, ARRAY_LEN (data_out), __LINE__) ; + + make_data (data_out, ARRAY_LEN (data_out), 5) ; + test_read_or_die (psf, data_in, 1, sizeof (data_in), 3 * sizeof (data_in), __LINE__) ; + test_equal_or_die (data_out, data_in, ARRAY_LEN (data_out), __LINE__) ; + + test_close_or_die (psf, __LINE__) ; + + puts ("ok") ; +} /* file_read_write_test */ + +static void +file_truncate_test (const char *filename) +{ SF_PRIVATE sf_data, *psf ; + unsigned char buffer [256] ; + int k ; + + /* + ** Open a new file and write two blocks of data to the file. After each + ** write, test that psf_get_filelen() returns the new length. + */ + + print_test_name ("Testing file truncate") ; + + memset (&sf_data, 0, sizeof (sf_data)) ; + memset (buffer, 0xEE, sizeof (buffer)) ; + + psf = &sf_data ; + snprintf (psf->file.path, sizeof (psf->file.path), "%s", filename) ; + + /* + ** Open the file write mode, write 0xEE data and then extend the file + ** using truncate (the extended data should be 0x00). + */ + psf->file.mode = SFM_WRITE ; + test_open_or_die (psf, __LINE__) ; + test_write_or_die (psf, buffer, sizeof (buffer) / 2, 1, sizeof (buffer) / 2, __LINE__) ; + psf_ftruncate (psf, sizeof (buffer)) ; + test_close_or_die (psf, __LINE__) ; + + /* Open the file in read mode and check the data. */ + psf->file.mode = SFM_READ ; + test_open_or_die (psf, __LINE__) ; + test_read_or_die (psf, buffer, sizeof (buffer), 1, sizeof (buffer), __LINE__) ; + test_close_or_die (psf, __LINE__) ; + + for (k = 0 ; k < SIGNED_SIZEOF (buffer) / 2 ; k++) + if (buffer [k] != 0xEE) + { printf ("\n\nLine %d : buffer [%d] = %hhu (should be 0xEE)\n\n", __LINE__, k, buffer [k]) ; + exit (1) ; + } ; + + for (k = SIGNED_SIZEOF (buffer) / 2 ; k < SIGNED_SIZEOF (buffer) ; k++) + if (buffer [k] != 0) + { printf ("\n\nLine %d : buffer [%d] = %hhu (should be 0)\n\n", __LINE__, k, buffer [k]) ; + exit (1) ; + } ; + + /* Open the file in read/write and shorten the file using truncate. */ + psf->file.mode = SFM_RDWR ; + test_open_or_die (psf, __LINE__) ; + psf_ftruncate (psf, sizeof (buffer) / 4) ; + test_close_or_die (psf, __LINE__) ; + + /* Check the file length. */ + psf->file.mode = SFM_READ ; + test_open_or_die (psf, __LINE__) ; + test_seek_or_die (psf, 0, SEEK_END, SIGNED_SIZEOF (buffer) / 4, __LINE__) ; + test_close_or_die (psf, __LINE__) ; + + puts ("ok") ; +} /* file_truncate_test */ + +static void +file_seek_with_offset_test (const char *filename) +{ SF_PRIVATE sf_data, *psf ; + sf_count_t real_end ; + const size_t fileoffset = 64 ; + + print_test_name ("Testing seek with offset") ; + + /* Open the file created by the previous test for reading. */ + memset (&sf_data, 0, sizeof (sf_data)) ; + psf = &sf_data ; + psf->file.mode = SFM_READ ; + snprintf (psf->file.path, sizeof (psf->file.path), "%s", filename) ; + test_open_or_die (psf, __LINE__) ; + + /* Gather basic info before setting offset. */ + real_end = psf_fseek (psf, 0, SEEK_END) ; + test_tell_or_die (psf, real_end, __LINE__) ; + + /* Set the fileoffset (usually in a real system this is due to an id3 tag). */ + psf->fileoffset = fileoffset ; + + /* Check tell respects offset. */ + test_tell_or_die (psf, real_end - fileoffset, __LINE__) ; + + /* Check seeking works as expected. */ + test_seek_or_die (psf, 0, SEEK_SET, 0, __LINE__) ; + test_seek_or_die (psf, 0, SEEK_CUR, 0, __LINE__) ; + test_seek_or_die (psf, 0, SEEK_CUR, 0, __LINE__) ; + test_seek_or_die (psf, 0, SEEK_END, real_end - fileoffset, __LINE__) ; + + test_close_or_die (psf, __LINE__) ; + + puts ("ok") ; +} /* file_seek_with_offset_test */ + +/*============================================================================== +** Testing helper functions. +*/ + +static void +test_open_or_die (SF_PRIVATE *psf, int linenum) +{ int error ; + + /* Test that open for read fails if the file doesn't exist. */ + error = psf_fopen (psf) ; + if (error) + { printf ("\n\nLine %d: psf_fopen() failed : %s\n\n", linenum, strerror (errno)) ; + exit (1) ; + } ; + +} /* test_open_or_die */ + +static void +test_close_or_die (SF_PRIVATE *psf, int linenum) +{ + psf_fclose (psf) ; + if (psf_file_valid (psf)) + { printf ("\n\nLine %d: psf->file.filedes should not be valid.\n\n", linenum) ; + exit (1) ; + } ; + +} /* test_close_or_die */ + +static void +test_write_or_die (SF_PRIVATE *psf, void *data, sf_count_t bytes, sf_count_t items, sf_count_t new_position, int linenum) +{ sf_count_t retval ; + + retval = psf_fwrite (data, bytes, items, psf) ; + if (retval != items) + { printf ("\n\nLine %d: psf_write() returned %" PRId64 " (should be %" PRId64 ")\n\n", linenum, retval, items) ; + exit (1) ; + } ; + + if ((retval = psf_ftell (psf)) != new_position) + { printf ("\n\nLine %d: file length after write is not correct. (%" PRId64 " should be %" PRId64 ")\n\n", linenum, retval, new_position) ; + exit (1) ; + } ; + + return ; +} /* test_write_or_die */ + +static void +test_read_or_die (SF_PRIVATE *psf, void *data, sf_count_t bytes, sf_count_t items, sf_count_t new_position, int linenum) +{ sf_count_t retval ; + + retval = psf_fread (data, bytes, items, psf) ; + if (retval != items) + { printf ("\n\nLine %d: psf_write() returned %" PRId64 " (should be %" PRId64 ")\n\n", linenum, retval, items) ; + exit (1) ; + } ; + + if ((retval = psf_ftell (psf)) != new_position) + { printf ("\n\nLine %d: file length after write is not correct. (%" PRId64 " should be %" PRId64 ")\n\n", linenum, retval, new_position) ; + exit (1) ; + } ; + + return ; +} /* test_write_or_die */ + +static void +test_seek_or_die (SF_PRIVATE *psf, sf_count_t offset, int whence, sf_count_t new_position, int linenum) +{ sf_count_t retval ; + + retval = psf_fseek (psf, offset, whence) ; + + if (retval != new_position) + { printf ("\n\nLine %d: psf_fseek() failed. New position is %" PRId64 " (should be %" PRId64 ").\n\n", + linenum, retval, new_position) ; + exit (1) ; + } ; + +} /* test_seek_or_die */ + +static void +test_tell_or_die (SF_PRIVATE *psf, sf_count_t expected_position, int linenum) +{ + sf_count_t retval ; + + retval = psf_ftell (psf) ; + + if (retval != expected_position) + { printf ("\n\nLine %d: psf_ftell() failed. Position reported as %" PRId64 " (should be %" PRId64 ").\n\n", + linenum, retval, expected_position) ; + exit (1) ; + } ; +} + +static void +test_equal_or_die (int *array1, int *array2, int len, int linenum) +{ int k ; + + for (k = 0 ; k < len ; k++) + if (array1 [k] != array2 [k]) + printf ("\n\nLine %d: error at index %d (%d != %d).\n\n", + linenum, k, array1 [k], array2 [k]) ; + + return ; +} /* test_equal_or_die */ + +static void +make_data (int *data, int len, int seed) +{ int k ; + + srand (seed * 3333333 + 14756123) ; + + for (k = 0 ; k < len ; k++) + data [k] = rand () ; + +} /* make_data */ + +void +test_file_io (void) +{ const char *filename = "file_io.dat" ; + + file_open_test (filename) ; + file_read_write_test (filename) ; + file_seek_with_offset_test (filename) ; + file_truncate_test (filename) ; + + unlink (filename) ; +} /* main */ + diff --git a/extern/libsndfile-modified/src/test_float.c b/extern/libsndfile-modified/src/test_float.c new file mode 100644 index 000000000..07879896e --- /dev/null +++ b/extern/libsndfile-modified/src/test_float.c @@ -0,0 +1,104 @@ +/* +** Copyright (C) 2006-2012 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "test_main.h" + +void +test_float_convert (void) +{ static float data [] = + { 0.0, 1.0, -1.0, 1.0 * M_PI, -1.0 * M_PI, + 1e9, -1e9, 1e-9, -1e-9, 1e-10, -1e-10, + 1e-19, -1e-19, 1e19, -1e19, 1e-20, -1e-20, + } ; + + int k ; + + print_test_name (__func__) ; + + for (k = 0 ; k < ARRAY_LEN (data) ; k++) + { unsigned char bytes [4] ; + float test ; + + float32_le_write (data [k], bytes) ; + test = float32_le_read (bytes) ; + + if (fabs (data [k] - test) > 1e-20) + { printf ("\n\nLine %d : Test %d, little endian error %.15g -> %.15g.\n\n", __LINE__, k, data [k], test) ; + exit (1) ; + } ; + + float32_be_write (data [k], bytes) ; + test = float32_be_read (bytes) ; + + if (fabs (data [k] - test) > 1e-20) + { printf ("\n\nLine %d : Test %d, big endian error %.15g -> %.15g.\n\n", __LINE__, k, data [k], test) ; + exit (1) ; + } ; + + } ; + + puts ("ok") ; +} /* test_float_convert */ + +void +test_double_convert (void) +{ static double data [] = + { 0.0, 1.0, -1.0, 1.0 * M_PI, -1.0 * M_PI, + 1e9, -1e9, 1e-9, -1e-9, 1e-10, -1e-10, + 1e-19, -1e-19, 1e19, -1e19, 1e-20, -1e-20, + } ; + + int k ; + + print_test_name (__func__) ; + + for (k = 0 ; k < ARRAY_LEN (data) ; k++) + { unsigned char bytes [8] ; + double test ; + + double64_le_write (data [k], bytes) ; + test = double64_le_read (bytes) ; + + if (fabs (data [k] - test) > 1e-20) + { printf ("\n\nLine %d : Test %d, little endian error %.15g -> %.15g.\n\n", __LINE__, k, data [k], test) ; + exit (1) ; + } ; + + double64_be_write (data [k], bytes) ; + test = double64_be_read (bytes) ; + + if (fabs (data [k] - test) > 1e-20) + { printf ("\n\nLine %d : Test %d, big endian error %.15g -> %.15g.\n\n", __LINE__, k, data [k], test) ; + exit (1) ; + } ; + + } ; + + puts ("ok") ; +} /* test_double_convert */ + diff --git a/extern/libsndfile-modified/src/test_ima_oki_adpcm.c b/extern/libsndfile-modified/src/test_ima_oki_adpcm.c new file mode 100644 index 000000000..6c937d117 --- /dev/null +++ b/extern/libsndfile-modified/src/test_ima_oki_adpcm.c @@ -0,0 +1,157 @@ +/* +** Copyright (C) 2007-2011 Erik de Castro Lopo +** Copyright (c) 2007 +** +** This library is free software; you can redistribute it and/or modify it +** under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2 of the License, or (at +** your option) any later version. +** +** This library is distributed in the hope that it will be useful, but +** WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +** General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this library. If not, write to the Free Software Foundation, +** Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA. +*/ + +#include "sfconfig.h" + +#include + +#include "test_main.h" + +#include "ima_oki_adpcm.c" + +static const unsigned char test_codes [] = +{ 0x08, 0x08, 0x04, 0x7f, 0x72, 0xf7, 0x9f, 0x7c, 0xd7, 0xbc, 0x7a, 0xa7, 0xb8, + 0x4b, 0x0b, 0x38, 0xf6, 0x9d, 0x7a, 0xd7, 0xbc, 0x7a, 0xd7, 0xa8, 0x6c, 0x81, + 0x98, 0xe4, 0x0e, 0x7a, 0xd7, 0x9e, 0x7b, 0xc7, 0xab, 0x7a, 0x85, 0xc0, 0xb3, + 0x8f, 0x58, 0xd7, 0xad, 0x7a, 0xd7, 0xad, 0x7a, 0x87, 0xd0, 0x2b, 0x0e, 0x48, + 0xd7, 0xad, 0x78, 0xf7, 0xbc, 0x7a, 0xb7, 0xa8, 0x4b, 0x88, 0x18, 0xd5, 0x8d, + 0x6a, 0xa4, 0x98, 0x08, 0x00, 0x80, 0x88, +} ; + +static const short test_pcm [] = +{ 32, 0, 32, 0, 32, 320, 880, -336, 2304, 4192, -992, 10128, 5360, -16352, + 30208, 2272, -31872, 14688, -7040, -32432, 14128, -1392, -15488, 22960, + 1232, -1584, 21488, -240, 2576, -15360, 960, -1152, -30032, 10320, 1008, + -30032, 16528, 1008, -30032, 16528, -5200, -30592, 15968, 448, -30592, + 15968, 448, -2368, 30960, 3024, -80, 8384, 704, -1616, -29168, -1232, 1872, + -32768, 13792, -1728, -32768, 13792, 4480, -32192, 14368, -7360, -32752, + 13808, -1712, -21456, 16992, 1472, -1344, 26848, -1088, 2016, -17728, 208, + -2112, -32768, 1376, -1728, -32768, 13792, -1728, -32768, 13792, -1728, + -32768, 13792, -1728, -32768, 13792, -1728, -4544, 32767, -1377, 1727, + 15823, -2113, 207, -27345, 591, -2513, -32768, 13792, -1728, -32768, 13792, + 10688, -31632, 14928, -6800, -32192, 14368, -1152, -20896, 17552, 2032, + -784, 22288, 560, -2256, -4816, 2176, 64, -21120, 9920, 6816, -24224, 16128, + 608, -13488, 9584, 272, -2544, 16, -2304, -192, 1728, -16, 1568, 128, -1184, +} ; + + +static void +test_oki_adpcm (void) +{ + IMA_OKI_ADPCM adpcm ; + unsigned char code ; + int i, j ; + + print_test_name ("Testing ima/oki encoder") ; + + ima_oki_adpcm_init (&adpcm, IMA_OKI_ADPCM_TYPE_OKI) ; + for (i = 0 ; i < ARRAY_LEN (test_codes) ; i++) + for (j = 0, code = test_codes [i] ; j < 2 ; j++, code <<= 4) + if (adpcm_decode (&adpcm, code >> 4) != test_pcm [2 * i + j]) + { printf ("\n\nFail at i = %d, j = %d.\n\n", i, j) ; + exit (1) ; + } ; + + puts ("ok") ; + + print_test_name ("Testing ima/oki decoder") ; + + ima_oki_adpcm_init (&adpcm, IMA_OKI_ADPCM_TYPE_OKI) ; + for (i = 0 ; i < ARRAY_LEN (test_pcm) - 1 ; i += 2) + { code = adpcm_encode (&adpcm, test_pcm [i]) ; + code = (code << 4) | adpcm_encode (&adpcm, test_pcm [i + 1]) ; + if (code != test_codes [i / 2]) + { printf ("\n\nFail at i = %d, %d should be %d\n\n", i, code, test_codes [i / 2]) ; + exit (1) ; + } ; + } ; + + puts ("ok") ; +} /* test_oki_adpcm */ + +static void +test_oki_adpcm_block (void) +{ + IMA_OKI_ADPCM adpcm ; + int k ; + + if (ARRAY_LEN (adpcm.pcm) < ARRAY_LEN (test_pcm)) + { printf ("\n\nLine %d : ARRAY_LEN (adpcm->pcm) > ARRAY_LEN (test_pcm) (%d > %d).\n\n", __LINE__, ARRAY_LEN (adpcm.pcm), ARRAY_LEN (test_pcm)) ; + exit (1) ; + } ; + + if (ARRAY_LEN (adpcm.codes) < ARRAY_LEN (test_codes)) + { printf ("\n\nLine %d : ARRAY_LEN (adcodes->codes) > ARRAY_LEN (test_codes).n", __LINE__) ; + exit (1) ; + } ; + + print_test_name ("Testing ima/oki block encoder") ; + + ima_oki_adpcm_init (&adpcm, IMA_OKI_ADPCM_TYPE_OKI) ; + + memcpy (adpcm.pcm, test_pcm, sizeof (adpcm.pcm [0]) * ARRAY_LEN (test_pcm)) ; + adpcm.pcm_count = ARRAY_LEN (test_pcm) ; + adpcm.code_count = 13 ; + + ima_oki_adpcm_encode_block (&adpcm) ; + + if (adpcm.code_count * 2 != ARRAY_LEN (test_pcm)) + { printf ("\n\nLine %d : %d * 2 != %d\n\n", __LINE__, adpcm.code_count * 2, ARRAY_LEN (test_pcm)) ; + exit (1) ; + } ; + + for (k = 0 ; k < ARRAY_LEN (test_codes) ; k++) + if (adpcm.codes [k] != test_codes [k]) + { printf ("\n\nLine %d : Fail at k = %d, %d should be %d\n\n", __LINE__, k, adpcm.codes [k], test_codes [k]) ; + exit (1) ; + } ; + + puts ("ok") ; + + print_test_name ("Testing ima/oki block decoder") ; + + ima_oki_adpcm_init (&adpcm, IMA_OKI_ADPCM_TYPE_OKI) ; + + memcpy (adpcm.codes, test_codes, sizeof (adpcm.codes [0]) * ARRAY_LEN (test_codes)) ; + adpcm.code_count = ARRAY_LEN (test_codes) ; + adpcm.pcm_count = 13 ; + + ima_oki_adpcm_decode_block (&adpcm) ; + + if (adpcm.pcm_count != 2 * ARRAY_LEN (test_codes)) + { printf ("\n\nLine %d : %d * 2 != %d\n\n", __LINE__, adpcm.pcm_count, 2 * ARRAY_LEN (test_codes)) ; + exit (1) ; + } ; + + for (k = 0 ; k < ARRAY_LEN (test_pcm) ; k++) + if (adpcm.pcm [k] != test_pcm [k]) + { printf ("\n\nLine %d : Fail at i = %d, %d should be %d.\n\n", __LINE__, k, adpcm.pcm [k], test_pcm [k]) ; + exit (1) ; + } ; + + puts ("ok") ; +} /* test_oki_adpcm_block */ + +void +test_ima_oki_adpcm (void) +{ + test_oki_adpcm () ; + test_oki_adpcm_block () ; +} /* main */ + diff --git a/extern/libsndfile-modified/src/test_log_printf.c b/extern/libsndfile-modified/src/test_log_printf.c new file mode 100644 index 000000000..ada623779 --- /dev/null +++ b/extern/libsndfile-modified/src/test_log_printf.c @@ -0,0 +1,125 @@ +/* +** Copyright (C) 2003-2012 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include +#include + +#include "common.h" + +#include "test_main.h" + +#define CMP_0_ARGS(line, err, fmt) \ + { psf->parselog.indx = 0 ; \ + snprintf (buffer, sizeof (buffer), (fmt)) ; \ + psf_log_printf (psf, (fmt)) ; \ + err += compare_strings_or_die (line, fmt, buffer, psf->parselog.buf) ; \ + } + +#define CMP_2_ARGS(line, err, fmt, a) \ + { psf->parselog.indx = 0 ; \ + snprintf (buffer, sizeof (buffer), (fmt), (a), (a)) ; \ + psf_log_printf (psf, (fmt), (a), (a)) ; \ + err += compare_strings_or_die (line, fmt, buffer, psf->parselog.buf) ; \ + } + +#define CMP_4_ARGS(line, err, fmt, a) \ + { psf->parselog.indx = 0 ; \ + snprintf (buffer, sizeof (buffer), (fmt), (a), (a), (a), (a)) ; \ + psf_log_printf (psf, (fmt), (a), (a), (a), (a)) ; \ + err += compare_strings_or_die (line, fmt, buffer, psf->parselog.buf) ; \ + } + +#define CMP_5_ARGS(line, err, fmt, a) \ + { psf->parselog.indx = 0 ; \ + snprintf (buffer, sizeof (buffer), (fmt), (a), (a), (a), (a), (a)) ; \ + psf_log_printf (psf, (fmt), (a), (a), (a), (a), (a)) ; \ + err += compare_strings_or_die (line, fmt, buffer, psf->parselog.buf) ; \ + } + +#define CMP_6_ARGS(line, err, fmt, a) \ + { psf->parselog.indx = 0 ; \ + snprintf (buffer, sizeof (buffer), (fmt), (a), (a), (a), (a), (a), (a)) ; \ + psf_log_printf (psf, (fmt), (a), (a), (a), (a), (a), (a)) ; \ + err += compare_strings_or_die (line, fmt, buffer, psf->parselog.buf) ; \ + } + +static int +compare_strings_or_die (int linenum, const char *fmt, const char* s1, const char* s2) +{ int errors = 0 ; +/*-puts (s1) ;puts (s2) ;-*/ + + if (strcmp (s1, s2) != 0) + { printf ("\n\nLine %d: string compare mismatch:\n\t", linenum) ; + printf ("\"%s\"\n", fmt) ; + printf ("\t\"%s\"\n\t\"%s\"\n", s1, s2) ; + errors ++ ; + } ; + + return errors ; +} /* compare_strings_or_die */ + +void +test_log_printf (void) +{ static char buffer [2048] ; + SF_PRIVATE sf_private, *psf ; + int k, errors = 0 ; + int int_values [] = { 0, 1, 12, 123, 1234, 123456, -1, -12, -123, -1234, -123456 } ; + + print_test_name ("Testing psf_log_printf") ; + + psf = &sf_private ; + memset (psf, 0, sizeof (sf_private)) ; + + CMP_0_ARGS (__LINE__, errors, " ->%%<- ") ; + + /* Test printing of ints. */ + for (k = 0 ; k < ARRAY_LEN (int_values) ; k++) + CMP_6_ARGS (__LINE__, errors, "int A : %d, % d, %4d, % 4d, %04d, % 04d", int_values [k]) ; + + for (k = 0 ; k < ARRAY_LEN (int_values) ; k++) + CMP_5_ARGS (__LINE__, errors, "int B : %+d, %+4d, %+04d, %-d, %-4d", int_values [k]) ; + + for (k = 0 ; k < ARRAY_LEN (int_values) ; k++) + CMP_2_ARGS (__LINE__, errors, "int C : %- d, %- 4d", int_values [k]) ; + + /* Test printing of unsigned ints. */ + for (k = 0 ; k < ARRAY_LEN (int_values) ; k++) + CMP_4_ARGS (__LINE__, errors, "D : %u, %4u, %04u, %0u", int_values [k]) ; + + /* Test printing of hex ints. */ + for (k = 0 ; k < ARRAY_LEN (int_values) ; k++) + CMP_4_ARGS (__LINE__, errors, "E : %X, %4X, %04X, %0X", int_values [k]) ; + + /* Test printing of strings. */ + CMP_4_ARGS (__LINE__, errors, "B %s, %3s, %8s, %-8s", "str") ; + + CMP_4_ARGS (__LINE__, errors, "B %.2s, %.8s, %-8.8s, %-4.2s", "str") ; + + if (errors) + { puts ("\nExiting due to errors.\n") ; + exit (1) ; + } ; + + puts ("ok") ; +} /* test_log_printf */ + diff --git a/extern/libsndfile-modified/src/test_main.c b/extern/libsndfile-modified/src/test_main.c new file mode 100644 index 000000000..f5a501d55 --- /dev/null +++ b/extern/libsndfile-modified/src/test_main.c @@ -0,0 +1,70 @@ +/* +** Copyright (C) 2008-2016 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#if defined (HAVE_SYS_TYPES_H) && (HAVE_SYS_TYPES_H == 1) +#include +#endif +#include +#include +#include + +#include "test_main.h" + +static void +test_file_offsets_are_64_bit (void) +{ + print_test_name ("File offsets are 64 bit") ; + + // The Windows specific code path uses the 64 bit file I/O APIs. + if (! USE_WINDOWS_API && sizeof (off_t) != 8) + { printf ("\n\nError : sizeof (off_t) is %zd (should be 8).\n\n", sizeof (off_t)) ; + exit (1) ; + } ; + + puts ("ok") ; +} /* test_file_offsets_are_64_bit */ + +int +main (void) +{ + test_file_offsets_are_64_bit () ; + test_conversions () ; + test_endswap () ; + test_float_convert () ; + test_double_convert () ; + + test_log_printf () ; + test_binheader_writef () ; + test_file_io () ; + + test_audio_detect () ; + test_ima_oki_adpcm () ; + + test_psf_strlcpy_crlf () ; + test_broadcast_var () ; + test_cart_var () ; + + test_nms_adpcm () ; + + return 0 ; +} /* main */ + diff --git a/extern/libsndfile-modified/src/test_main.h b/extern/libsndfile-modified/src/test_main.h new file mode 100644 index 000000000..d08fb2e09 --- /dev/null +++ b/extern/libsndfile-modified/src/test_main.h @@ -0,0 +1,44 @@ +/* +** Copyright (C) 2008-2016 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +static inline void +print_test_name (const char * name) +{ printf (" %-40s : ", name) ; + fflush (stdout) ; +} /* print_test_name */ + + + +void test_conversions (void) ; +void test_endswap (void) ; +void test_log_printf (void) ; +void test_binheader_writef (void) ; +void test_file_io (void) ; + +void test_float_convert (void) ; +void test_double_convert (void) ; + +void test_audio_detect (void) ; +void test_ima_oki_adpcm (void) ; + +void test_psf_strlcpy_crlf (void) ; +void test_broadcast_var (void) ; + +void test_cart_var (void) ; + +void test_nms_adpcm (void) ; diff --git a/extern/libsndfile-modified/src/test_nms_adpcm.c b/extern/libsndfile-modified/src/test_nms_adpcm.c new file mode 100644 index 000000000..8558a046d --- /dev/null +++ b/extern/libsndfile-modified/src/test_nms_adpcm.c @@ -0,0 +1,400 @@ +/* +** Copyright (C) 2007-2018 Erik de Castro Lopo +** Copyright (C) 2017-2018 Arthur Taylor +** +** This library is free software; you can redistribute it and/or modify it +** under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2 of the License, or (at +** your option) any later version. +** +** This library is distributed in the hope that it will be useful, but +** WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +** General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this library. If not, write to the Free Software Foundation, +** Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA. +*/ + +#include "sfconfig.h" + +#include + +#include "test_main.h" + +#include "nms_adpcm.c" + +static const short pcm_data_src [] = +{ 505, 743, 805, 409, 101, -552, -709, -679, + -624, -1174, -1050, 32, -401, -769, -679, 47, + -3273, -4425, -2158, -176, 824, 1057, 1245, 805, + 2414, 3282, 1739, -624, -1197, -1663, -913, 603, + 549, -614, 707, 3314, 2864, 1127, -294, -919, + -1251, -147, 30, -750, -131, 1394, 2197, 1829, + 1387, 417, 391, 533, 581, 179, -210, -210, + -884, -937, -1373, -1338, -1811, -2727, -2536, -1552, + -651, -3556, -7713, -9083, -6182, 1070, 4983, 5341, + 4596, 4682, 6488, 5197, 2401, -2702, -5261, -4036, + -1995, 463, 1056, 2436, 3238, 4395, 4478, 1130, + -2383, -4349, -4547, -3631, -1396, 1029, 2589, 3948, + 4966, 4312, 2362, 492, -1289, -2259, -1659, -597, + 239, 1433, 2353, 2512, 1763, 610, -291, -640, + 7, 132, 432, 438, -1070, -1202, -1071, -1841, + -462, 225, -4465, -11313, -10492, -4522, -2096, -7013, + -11770, -2546, 7687, 12765, 12014, 5324, 1645, 1191, + 3800, -187, -6689, -7778, -4631, 2487, 7352, 7928, + 4317, 2424, 3784, 2301, -1713, -6668, -8345, -6453, + -2303, 2269, 3232, 4114, 5054, 5054, 3768, 1060, + -1793, -3302, -2059, -86, 1153, 1690, 2869, 3841, + 3551, 1919, -197, -1391, -847, 128, 746, 1111, + 431, 559, 1086, 138, -1539, -2758, -1886, 1351, + 2407, -1883, -8356, -10999, -9917, -7329, -4295, -3209, + -11616, -15352, 1032, 12603, 13233, 9059, 4019, 1858, + 3368, 7454, -56, -8600, -7278, -818, 5478, 7039, + 5630, 1186, 1634, 5422, 2518, -3182, -8271, -7889, + -4399, -129, 3205, 2933, 3661, 5886, 6543, 3798, + 374, -2722, -3378, -1804, -24, 385, 1663, 3595, + 4749, 3865, 1402, -851, -1932, -1394, -725, -219, + 290, 658, 1074, 1638, 536, 204, -340, 408, + 1835, 1261, -2872, -4840, -5978, -8177, -7644, -6554, + -8093, -6174, -7796, -17019, -12355, 1280, 12576, 11868, + 10710, 8578, 5605, 9675, 7123, -977, -8770, -6740, + -1327, 2905, 6386, 5026, 3809, 5137, 6392, 2463, + -4924, -8830, -9572, -6122, -1608, 1677, 3379, 5660, + 8236, 7225, 4470, 295, -2628, -3572, -2107, -666, + 951, 3101, 5049, 4759, 2367, -140, -2078, -2471, + -2332, -1547, -798, 410, 1825, 3329, 3092, 352, + -3310, -3307, -1229, -415, 532, 2091, 465, -1430 +} ; + +/* pcm_data encoded as 16kbs from a known reference */ +static const unsigned short test_codes_16 [] = +{ 0x5777, 0xfff0, 0xdcd0, 0x672d, 0x1826, 0xc11c, 0x0822, 0xffee, + 0x3ddc, 0x6372, 0x0116, 0xc8d8, 0x6780, 0x8624, 0x3323, 0x33ef, + 0xd865, 0x4cd8, 0x3372, 0x1096, 0x0049, 0xa911, 0x1288, 0xa74d, + 0x3fee, 0xcc45, 0x52de, 0x6a72, 0x9118, 0xe291, 0x60a2, 0x3164, + 0x73fe, 0xeddf, 0x57b5, 0x185a, 0xe889, 0x460e, 0x2646, 0x8d87, + 0xe5ba, 0x004c +} ; + +/* pcm_data encoded as 24kbs from a known reference */ +static const unsigned short test_codes_24 [] = +{ 0x7776, 0x2fec, 0xceb0, 0xffd0, 0x3241, 0x650a, 0x0a26, 0x61ba, + 0xa10b, 0x3912, 0x39a8, 0xebfa, 0x1fff, 0x8552, 0x2342, 0x0204, + 0x454b, 0xccbb, 0x4318, 0xaa00, 0x1642, 0x3031, 0xfc8f, 0x38ff, + 0xf604, 0x4924, 0x2ddb, 0x0469, 0xbcaa, 0x83b6, 0x0049, 0x8828, + 0x2266, 0x3801, 0x873d, 0xcb86, 0x0eff, 0xef64, 0xd402, 0x44fa, + 0x2867, 0xd1d0, 0xa109, 0x2a11, 0x8a64, 0x4018, 0x1357, 0xd5a5, + 0x4bfc, 0xcbfe, 0x070a, 0x6307, 0x1858, 0x624b, 0xf9a9, 0x783b, + 0x0880, 0x1652, 0xc893, 0x641c, 0xf30d, 0x004c +} ; + +/* pcm_data encoded as 32kbs from a known reference */ +static const unsigned short test_codes_32 [] = +{ 0x7772, 0x0cdc, 0xbec2, 0xacb2, 0xff90, 0x1220, 0x551c, 0xcc84, + 0x2c47, 0x30aa, 0xa10b, 0x0663, 0x2812, 0x28a9, 0xf9ba, 0xceb9, + 0x1fec, 0x9553, 0x2361, 0x9ed8, 0x8314, 0x564b, 0xddba, 0x1346, + 0x6308, 0xab00, 0x0721, 0x2908, 0x3820, 0xf89c, 0x38ff, 0xa2bf, + 0xc535, 0x2933, 0x5de9, 0x8633, 0x8569, 0xbeca, 0x1186, 0x5528, + 0xd000, 0xaa21, 0x0473, 0x2800, 0x1112, 0xa64d, 0xdc17, 0x8eeb, + 0xccac, 0xfe74, 0xc501, 0x63f9, 0x2040, 0x3a73, 0xc9b9, 0x9188, + 0x7318, 0x0a81, 0x9a65, 0x5188, 0x00ba, 0x2256, 0xd5b6, 0x4bfa, + 0xbeac, 0xe8fe, 0x343b, 0x7117, 0x9ca4, 0x915a, 0x563d, 0xcad0, + 0xa837, 0x302a, 0x1a2a, 0x3561, 0x98a9, 0xb9b5, 0x578a, 0xc48b, + 0x25f0, 0x1000 +} ; + + +/* test_codes_16 decoded by a known reference */ +const short pcm_data_out16 [] = +{ 12, 16, 24, 36, 52, -68, -104, -156, + -224, -309, -433, 12, -449, -618, -851, 32, + -871, -1176, -1586, 60, 1172, 634, 1566, 983, + 1995, 2586, 1718, -1152, -815, -2313, -1610, 1261, + 1056, -253, 522, 1799, 2506, 1518, 72, -329, + -1510, -76, 337, -1144, 68, 1369, 2200, 1337, + 1016, 60, 405, 461, 433, 389, -36, -164, + -550, -871, -1212, -1626, -2136, -2791, -2064, -1642, + -485, -1566, -2538, -3445, -4481, 650, 4381, 3799, + 5807, 4742, 6674, 5590, 2072, -2228, -5650, -4983, + -1698, 441, 1333, 3064, 2855, 3815, 5108, 2156, + -2228, -3321, -5028, -4405, -1550, 771, 3232, 3273, + 4008, 5008, 2024, 859, -654, -2746, -1694, -136, + 68, 1409, 1759, 2453, 2016, 522, -514, -445, + 0, 305, 493, 518, -232, -1076, -1116, -1321, + -506, 365, -140, -1132, -2076, -2895, -2357, -2477, + -3325, -2859, 666, 4449, 7164, 6244, 1847, 1365, + 3827, -779, -7682, -8951, -3811, 1718, 6566, 7120, + 4674, 1959, 1819, 2032, -1104, -5220, -8518, -7626, + -2385, 2714, 3510, 3871, 4831, 4024, 4156, 1590, + -1694, -3437, -2393, 96, 959, 1847, 2775, 3638, + 3072, 1734, -204, -1730, -718, -92, 453, 807, + 220, 514, 1349, -40, -1285, -2477, -1566, 1273, + 2586, 546, -2887, -5534, -6883, -7461, -5281, -2224, + -2361, -5104, -48, 9228, 12140, 9048, 3614, 1927, + 4618, 6004, -148, -9871, -5582, -489, 6835, 6746, + 6839, 2851, 3028, 4566, 1461, -2028, -6883, -7642, + -5321, -610, 3385, 3461, 3088, 3389, 4570, 4321, + -389, -2630, -3369, -1706, -136, 220, 1594, 3024, + 4622, 4232, 1265, -943, -2273, -1638, -726, -232, + 365, 538, 995, 1530, 289, 453, -68, 12, + 1184, 1562, 92, -2558, -4859, -6277, -7096, -5461, + -4811, -6020, -8851, -12594, -11501, -943, 12927, 10449, + 8935, 10389, 5662, 5755, 9108, 1827, -10224, -7807, + -148, 3429, 7722, 5212, 4734, 3847, 5570, 3433, + -3931, -8244, -8461, -5397, -1710, 1919, 3787, 4558, + 5040, 5722, 4811, -441, -3140, -4180, -2397, -493, + 1309, 3064, 4116, 5040, 2759, -730, -2445, -2847, + -2080, -1682, -1124, 706, 2032, 3325, 3248, 425, + -3586, -2987, -1397, -188, 144, 1506, 4, -2028 +} ; + +/* test_codes_24 decoded by a known reference */ +static const short pcm_data_out24 [] = +{ 16, 32, 68, 140, 116, -232, -510, -650, + -771, -1329, -1052, -152, -317, -907, -710, -104, + -1144, -2132, -2598, -301, 662, 827, 1469, 702, + 2401, 2987, 1574, -244, -1481, -1365, -903, 738, + 369, -469, 473, 1630, 3124, 1542, -582, -1172, + -1381, -317, 4, -610, -40, 1236, 1843, 1493, + 1349, 417, 389, 630, 686, 188, -228, -168, + -742, -795, -1530, -1473, -1903, -3008, -2907, -1317, + -445, -2309, -4919, -8939, -5867, 1204, 5293, 5337, + 4871, 4562, 5602, 5104, 2485, -2337, -5594, -4240, + -1694, 867, 1281, 2622, 3638, 4228, 4654, 1405, + -1947, -4112, -4184, -3582, -1570, 1325, 2538, 4036, + 5144, 4630, 2718, 518, -1373, -2397, -1642, -453, + 349, 1566, 2558, 2493, 1927, 662, -365, -610, + -136, 188, 453, 437, -385, -1281, -1196, -1534, + -369, 265, -899, -3445, -7176, -4538, -2726, -5650, + -13152, -1694, 7040, 11489, 12224, 5971, 1971, 1779, + 3457, -373, -6040, -7714, -5008, 2594, 7658, 8156, + 4461, 2333, 4369, 2867, -1919, -7180, -8465, -6409, + -2618, 2152, 3120, 4208, 5570, 5558, 4120, 690, + -2088, -3345, -1975, -208, 1180, 1738, 2144, 3289, + 3686, 1819, -417, -1534, -875, 88, 678, 967, + 437, 558, 951, 20, -1638, -2558, -1967, 558, + 2289, 465, -4449, -11080, -8931, -6248, -4208, -3337, + -6493, -14550, -5068, 12305, 13261, 9742, 4261, 1851, + 3016, 6971, 441, -9554, -7096, -975, 5188, 6658, + 5409, 1341, 855, 6164, 1726, -2381, -7991, -7212, + -4799, -433, 3236, 3273, 3253, 4445, 6706, 3329, + 582, -2602, -3028, -1614, -152, 196, 1598, 3638, + 5144, 4016, 1586, -1004, -2016, -1401, -682, -128, + 273, 614, 963, 1614, 425, 269, -449, 277, + 1746, 1240, -1510, -4598, -6397, -8008, -7602, -7152, + -7393, -6738, -8606, -15385, -13385, 1192, 12212, 11152, + 9967, 8622, 5240, 6939, 7369, -2216, -9602, -7425, + -999, 3228, 6329, 4702, 4305, 4550, 6216, 3072, + -4983, -9313, -9437, -5586, -1987, 2088, 3184, 4662, + 8244, 6598, 4606, -277, -2718, -3188, -2321, -437, + 835, 2855, 4638, 4943, 2116, -393, -2269, -2502, + -2445, -1630, -646, 469, 1927, 3188, 2943, 502, + -3148, -3100, -1144, -642, 658, 1843, 449, -1445 +} ; + +/* test_codes_32 decoded by a known reference */ +static const short pcm_data_out32 [] = +{ 20, 96, 417, 433, 140, -506, -742, -714, + -598, -1092, -1044, 56, -445, -702, -622, 76, + -1116, -4293, -2429, -433, 606, 1196, 1357, 650, + 2465, 3040, 1730, -682, -1381, -1759, -867, 518, + 614, -698, 751, 2172, 3216, 1369, -562, -1076, + -1293, -116, -12, -803, -176, 1297, 2228, 1759, + 1257, 425, 453, 614, 622, 188, -212, -220, + -975, -951, -1441, -1309, -1698, -2578, -2405, -1650, + -590, -2293, -7052, -8506, -5907, 1100, 5192, 5305, + 4244, 4425, 6779, 5313, 2152, -2654, -5598, -3803, + -2176, 301, 1080, 2281, 3361, 4485, 4690, 1269, + -2253, -4477, -4562, -3598, -1345, 1108, 2638, 3783, + 4819, 4401, 2357, 409, -1180, -2204, -1730, -662, + 168, 1566, 2550, 2333, 1879, 485, -293, -690, + -28, 176, 445, 413, -767, -1088, -1204, -1847, + -481, 261, -1321, -8714, -10646, -4265, -1979, -7100, + -11678, -1911, 7449, 13333, 11991, 5244, 1935, 1072, + 3638, -4, -6377, -7650, -4819, 2674, 7148, 8036, + 4325, 2433, 3855, 2204, -1638, -6361, -8192, -6634, + -2184, 2144, 3357, 4164, 4783, 5168, 3835, 1100, + -1670, -3224, -2140, -144, 1120, 1755, 2530, 3626, + 3678, 1771, -281, -1289, -875, 48, 755, 1112, + 449, 546, 1140, 232, -1530, -2783, -1871, 1128, + 2216, -1899, -8606, -11333, -10140, -7546, -4357, -2979, + -6044, -14851, -3726, 13136, 13477, 9534, 3871, 1489, + 3526, 7012, 80, -8188, -7140, -1120, 5783, 7060, + 5823, 1337, 1108, 5566, 2345, -3373, -8140, -7919, + -4566, 76, 3060, 2795, 3385, 5907, 6558, 3638, + 257, -2630, -3401, -1807, -116, 349, 1610, 3417, + 4750, 3967, 1489, -907, -1923, -1385, -666, -265, + 253, 682, 1084, 1586, 538, 184, -381, 433, + 1875, 1289, -1574, -4538, -6168, -8196, -7887, -6750, + -7526, -6060, -8148, -16036, -12546, 895, 12991, 12060, + 10827, 8931, 5321, 8646, 7654, -473, -8582, -6614, + -1321, 2803, 6542, 5184, 3847, 4943, 6397, 2148, + -4999, -8799, -9614, -5931, -1574, 1546, 3493, 5397, + 7879, 6919, 4610, 160, -2538, -3582, -2052, -578, + 1060, 2987, 4843, 4791, 2421, -116, -1987, -2518, + -2333, -1534, -855, 365, 1779, 3389, 3080, 477, + -3281, -3120, -1188, -265, 638, 2224, 333, -1377 +} ; + + +static void +test_nms_adpcm_32 (void) +{ + struct nms_adpcm_state nms ; + int16_t *buffer ; + unsigned char code ; + int i, j, sl ; + + buffer = (int16_t *) malloc (sizeof (int16_t) * NMS_SAMPLES_PER_BLOCK) ; + + print_test_name ("Testing nms adpcm 32kbs encoder") ; + + nms_adpcm_codec_init (&nms, NMS32) ; + for (i = 0 ; i * NMS_BLOCK_SHORTS_32 < ARRAY_LEN (test_codes_32) ; i ++) + { /* Unpack the reference */ + nms_adpcm_block_unpack_32 (&(test_codes_32 [i * NMS_BLOCK_SHORTS_32]), buffer, NULL) ; + for (j = 0 ; j < NMS_SAMPLES_PER_BLOCK ; j++) + { sl = pcm_data_src [i * NMS_SAMPLES_PER_BLOCK + j] ; + code = nms_adpcm_encode_sample (&nms, sl) ; + if (code != buffer [j]) + { printf ("\n\nFail at sample %d (block %d, sample %d). Expected 0x%x got 0x%x\n\n", + i * NMS_SAMPLES_PER_BLOCK + j, i, j, buffer [j], code) ; + exit (1) ; + } + } + } + + puts ("ok") ; + + print_test_name ("Testing nms adpcm 32kbs decoder") ; + + nms_adpcm_codec_init (&nms, NMS32) ; + for (i = 0 ; i * NMS_BLOCK_SHORTS_32 < ARRAY_LEN (test_codes_32) ; i ++) + { /* Unpack the code */ + nms_adpcm_block_unpack_32 (&(test_codes_32 [i * NMS_BLOCK_SHORTS_32]), buffer, NULL) ; + for (j = 0 ; j < NMS_SAMPLES_PER_BLOCK ; j++) + { sl = nms_adpcm_decode_sample (&nms, buffer [j]) ; + if (sl != pcm_data_out32 [i * NMS_SAMPLES_PER_BLOCK + j]) + { printf ("\n\nFail at sample %d (block %d, sample %d). Expected %d got %d\n\n", + i * NMS_SAMPLES_PER_BLOCK + j, i, j, pcm_data_out32 [i * NMS_SAMPLES_PER_BLOCK + j], sl) ; + exit (1) ; + } + } + } + + puts ("ok") ; + + free (buffer) ; +} + + +static void +test_nms_adpcm_24 (void) +{ + struct nms_adpcm_state nms ; + int16_t *buffer ; + unsigned char code ; + int i, j, sl ; + + buffer = (int16_t *) malloc (sizeof (int16_t) * NMS_SAMPLES_PER_BLOCK) ; + + + print_test_name ("Testing nms adpcm 24kbs encoder") ; + + nms_adpcm_codec_init (&nms, NMS24) ; + for (i = 0 ; i * NMS_BLOCK_SHORTS_24 < ARRAY_LEN (test_codes_24) ; i ++) + { /* Unpack the reference */ + nms_adpcm_block_unpack_24 (&test_codes_24 [i * NMS_BLOCK_SHORTS_24], buffer, NULL) ; + for (j = 0 ; j < NMS_SAMPLES_PER_BLOCK ; j++) + { sl = pcm_data_src [i * NMS_SAMPLES_PER_BLOCK + j] ; + code = nms_adpcm_encode_sample (&nms, sl) ; + if (code != buffer [j]) + { printf ("\n\nFail at sample %d (block %d, sample %d). Expected 0x%x got 0x%x\n\n", + i * NMS_SAMPLES_PER_BLOCK + j, i, j, buffer [j], code) ; + exit (1) ; + } + } + } + + puts ("ok") ; + + + print_test_name ("Testing nms adpcm 24kbs decoder") ; + + nms_adpcm_codec_init (&nms, NMS24) ; + for (i = 0 ; i * NMS_BLOCK_SHORTS_24 < ARRAY_LEN (test_codes_24) ; i ++) + { /* Unpack the code */ + nms_adpcm_block_unpack_24 (&test_codes_24 [i * NMS_BLOCK_SHORTS_24], buffer, NULL) ; + for (j = 0 ; j < NMS_SAMPLES_PER_BLOCK ; j++) + { sl = nms_adpcm_decode_sample (&nms, buffer [j]) ; + if (sl != pcm_data_out24 [i * NMS_SAMPLES_PER_BLOCK + j]) + { printf ("\n\nFail at sample %d (block %d, sample %d). Expected %d got %d\n\n", + i * NMS_SAMPLES_PER_BLOCK + j, i, j, pcm_data_out24 [i * NMS_SAMPLES_PER_BLOCK + j], sl) ; + exit (1) ; + } + } + } + + puts ("ok") ; + + free (buffer) ; +} /* test_nms_adpcm_24 */ + +static void +test_nms_adpcm_16 (void) +{ struct nms_adpcm_state nms ; + int16_t *buffer ; + unsigned char code ; + int i, j, sl ; + + buffer = (int16_t *) malloc (sizeof (int16_t) * NMS_SAMPLES_PER_BLOCK) ; + + print_test_name ("Testing nms adpcm 16kbs encoder") ; + + nms_adpcm_codec_init (&nms, NMS16) ; + for (i = 0 ; i * NMS_BLOCK_SHORTS_16 < ARRAY_LEN (test_codes_16) ; i ++) + { /* Unpack the reference */ + nms_adpcm_block_unpack_16 (&test_codes_16 [i * NMS_BLOCK_SHORTS_16], buffer, NULL) ; + for (j = 0 ; j < NMS_SAMPLES_PER_BLOCK ; j++) + { sl = pcm_data_src [i * NMS_SAMPLES_PER_BLOCK + j] ; + code = nms_adpcm_encode_sample (&nms, sl) ; + if (code != buffer [j]) + { printf ("\n\nFail at sample %d (block %d, sample %d). Expected 0x%x got 0x%x\n\n", + i * NMS_SAMPLES_PER_BLOCK + j, i, j, buffer [j], code) ; + exit (1) ; + } + } + } + + puts ("ok") ; + + print_test_name ("Testing nms adpcm 16kbs decoder") ; + + nms_adpcm_codec_init (&nms, NMS16) ; + for (i = 0 ; i * NMS_BLOCK_SHORTS_16 < ARRAY_LEN (test_codes_16) ; i ++) + { /* Unpack the code */ + nms_adpcm_block_unpack_16 (&test_codes_16 [i * NMS_BLOCK_SHORTS_16], buffer, NULL) ; + for (j = 0 ; j < NMS_SAMPLES_PER_BLOCK ; j++) + { sl = nms_adpcm_decode_sample (&nms, buffer [j]) ; + if (sl != pcm_data_out16 [i * NMS_SAMPLES_PER_BLOCK + j]) + { printf ("\n\nFail at sample %d (block %d, sample %d). Expected %d got %d\n\n", + i * NMS_SAMPLES_PER_BLOCK + j, i, j, pcm_data_out16 [i * NMS_SAMPLES_PER_BLOCK + j], sl) ; + exit (1) ; + } + } + } + + puts ("ok") ; + + free (buffer) ; +} /* test_nms_adpcm_16 */ + +void +test_nms_adpcm (void) +{ test_nms_adpcm_32 () ; + test_nms_adpcm_24 () ; + test_nms_adpcm_16 () ; +} /* main */ + diff --git a/extern/libsndfile-modified/src/test_strncpy_crlf.c b/extern/libsndfile-modified/src/test_strncpy_crlf.c new file mode 100644 index 000000000..f21addc30 --- /dev/null +++ b/extern/libsndfile-modified/src/test_strncpy_crlf.c @@ -0,0 +1,59 @@ +/* +** Copyright (C) 2010-2012 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include + +#include "common.h" + +#include "test_main.h" + +void +test_psf_strlcpy_crlf (void) +{ const char *src = "a\nb\nc\n" ; + char *dest ; + int dest_len ; + + print_test_name ("Testing psf_strlcpy_crlf") ; + + for (dest_len = 3 ; dest_len < 30 ; dest_len++) + { dest = calloc (1, dest_len + 1) ; + if (dest == NULL) + { printf ("\n\nLine %d: calloc failed!\n\n", __LINE__) ; + exit (1) ; + } ; + + /* This value needs to be a in the [0, 127] range to avoid tripping up + ** compiles like Sun Studio 12.* + */ + dest [dest_len] = '\x5a' ; + + psf_strlcpy_crlf (dest, src, dest_len, sizeof (*src)) ; + + if (dest [dest_len] != '\x5a') + { printf ("\n\nLine %d: buffer overrun for dest_len == %d\n\n", __LINE__, dest_len) ; + exit (1) ; + } ; + + free (dest) ; + } ; + + puts ("ok") ; +} /* test_psf_strlcpy_crlf */ diff --git a/extern/libsndfile-modified/src/txw.c b/extern/libsndfile-modified/src/txw.c new file mode 100644 index 000000000..16525dfe2 --- /dev/null +++ b/extern/libsndfile-modified/src/txw.c @@ -0,0 +1,377 @@ +/* +** Copyright (C) 2002-2012 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/*=========================================================================== +** Yamaha TX16 Sampler Files. +** +** This header parser was written using information from the SoX source code +** and trial and error experimentation. The code here however is all original. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + +#if (ENABLE_EXPERIMENTAL_CODE == 0) + +int +txw_open (SF_PRIVATE *psf) +{ if (psf) + return SFE_UNIMPLEMENTED ; + return 0 ; +} /* txw_open */ + +#else + +/*------------------------------------------------------------------------------ +** Markers. +*/ + +#define TXW_DATA_OFFSET 32 + +#define TXW_LOOPED 0x49 +#define TXW_NO_LOOP 0xC9 + +/*------------------------------------------------------------------------------ +** Private static functions. +*/ + +static int txw_read_header (SF_PRIVATE *psf) ; + +static sf_count_t txw_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; +static sf_count_t txw_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; +static sf_count_t txw_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; +static sf_count_t txw_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; + +static sf_count_t txw_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ; + +/*------------------------------------------------------------------------------ +** Public functions. +*/ + +/* + * ftp://ftp.t0.or.at/pub/sound/tx16w/samples.yamaha + * ftp://ftp.t0.or.at/pub/sound/tx16w/faq/tx16w.tec + * http://www.t0.or.at/~mpakesch/tx16w/ + * + * from tx16w.c sox 12.15: (7-Oct-98) (Mark Lakata and Leigh Smith) + * char filetype[6] "LM8953" + * nulls[10], + * dummy_aeg[6] + * format 0x49 = looped, 0xC9 = non-looped + * sample_rate 1 = 33 kHz, 2 = 50 kHz, 3 = 16 kHz + * atc_length[3] if sample rate 0, [2]&0xfe = 6: 33kHz, 0x10:50, 0xf6: 16, + * depending on [5] but to heck with it + * rpt_length[3] (these are for looped samples, attack and loop lengths) + * unused[2] + */ + +typedef struct +{ unsigned char format, srate, sr2, sr3 ; + unsigned short srhash ; + unsigned int attacklen, repeatlen ; +} TXW_HEADER ; + +#define ERROR_666 666 + +int +txw_open (SF_PRIVATE *psf) +{ int error ; + + if (psf->file.mode != SFM_READ) + return SFE_UNIMPLEMENTED ; + + if ((error = txw_read_header (psf))) + return error ; + + if (psf_fseek (psf, psf->dataoffset, SEEK_SET) != psf->dataoffset) + return SFE_BAD_SEEK ; + + psf->read_short = txw_read_s ; + psf->read_int = txw_read_i ; + psf->read_float = txw_read_f ; + psf->read_double = txw_read_d ; + + psf->seek = txw_seek ; + + return 0 ; +} /* txw_open */ + +/*------------------------------------------------------------------------------ +*/ + +static int +txw_read_header (SF_PRIVATE *psf) +{ BUF_UNION ubuf ; + TXW_HEADER txwh ; + const char *strptr ; + + memset (&txwh, 0, sizeof (txwh)) ; + memset (ubuf.cbuf, 0, sizeof (ubuf.cbuf)) ; + psf_binheader_readf (psf, "pb", 0, ubuf.cbuf, 16) ; + + if (memcmp (ubuf.cbuf, "LM8953\0\0\0\0\0\0\0\0\0\0", 16) != 0) + return ERROR_666 ; + + psf_log_printf (psf, "Read only : Yamaha TX-16 Sampler (.txw)\nLM8953\n") ; + + /* Jump 6 bytes (dummp_aeg), read format, read sample rate. */ + psf_binheader_readf (psf, "j11", 6, &txwh.format, &txwh.srate) ; + + /* 8 bytes (atc_length[3], rpt_length[3], unused[2]). */ + psf_binheader_readf (psf, "e33j", &txwh.attacklen, &txwh.repeatlen, 2) ; + txwh.sr2 = (txwh.attacklen >> 16) & 0xFE ; + txwh.sr3 = (txwh.repeatlen >> 16) & 0xFE ; + txwh.attacklen &= 0x1FFFF ; + txwh.repeatlen &= 0x1FFFF ; + + switch (txwh.format) + { case TXW_LOOPED : + strptr = "looped" ; + break ; + + case TXW_NO_LOOP : + strptr = "non-looped" ; + break ; + + default : + psf_log_printf (psf, " Format : 0x%02x => ?????\n", txwh.format) ; + return ERROR_666 ; + } ; + + psf_log_printf (psf, " Format : 0x%02X => %s\n", txwh.format, strptr) ; + + strptr = NULL ; + + switch (txwh.srate) + { case 1 : + psf->sf.samplerate = 33333 ; + break ; + + case 2 : + psf->sf.samplerate = 50000 ; + break ; + + case 3 : + psf->sf.samplerate = 16667 ; + break ; + + default : + /* This is ugly and braindead. */ + txwh.srhash = ((txwh.sr2 & 0xFE) << 8) | (txwh.sr3 & 0xFE) ; + switch (txwh.srhash) + { case ((0x6 << 8) | 0x52) : + psf->sf.samplerate = 33333 ; + break ; + + case ((0x10 << 8) | 0x52) : + psf->sf.samplerate = 50000 ; + break ; + + case ((0xF6 << 8) | 0x52) : + psf->sf.samplerate = 166667 ; + break ; + + default : + strptr = " Sample Rate : Unknown : forcing to 33333\n" ; + psf->sf.samplerate = 33333 ; + break ; + } ; + } ; + + + if (strptr) + psf_log_printf (psf, strptr) ; + else if (txwh.srhash) + psf_log_printf (psf, " Sample Rate : %d (0x%X) => %d\n", txwh.srate, txwh.srhash, psf->sf.samplerate) ; + else + psf_log_printf (psf, " Sample Rate : %d => %d\n", txwh.srate, psf->sf.samplerate) ; + + if (txwh.format == TXW_LOOPED) + { psf_log_printf (psf, " Attack Len : %d\n", txwh.attacklen) ; + psf_log_printf (psf, " Repeat Len : %d\n", txwh.repeatlen) ; + } ; + + psf->dataoffset = TXW_DATA_OFFSET ; + psf->datalength = psf->filelength - TXW_DATA_OFFSET ; + psf->sf.frames = 2 * psf->datalength / 3 ; + + + if (psf->datalength % 3 == 1) + psf_log_printf (psf, "*** File seems to be truncated, %d extra bytes.\n", + (int) (psf->datalength % 3)) ; + + if (txwh.attacklen + txwh.repeatlen > psf->sf.frames) + psf_log_printf (psf, "*** File has been truncated.\n") ; + + psf->sf.format = SF_FORMAT_TXW | SF_FORMAT_PCM_16 ; + psf->sf.channels = 1 ; + psf->sf.sections = 1 ; + psf->sf.seekable = SF_TRUE ; + + return 0 ; +} /* txw_read_header */ + +static sf_count_t +txw_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + unsigned char *ucptr ; + short sample ; + int k, bufferlen, readcount, count ; + sf_count_t total = 0 ; + + bufferlen = sizeof (ubuf.cbuf) / 3 ; + bufferlen -= (bufferlen & 1) ; + while (len > 0) + { readcount = (len >= bufferlen) ? bufferlen : len ; + count = psf_fread (ubuf.cbuf, 3, readcount, psf) ; + + ucptr = ubuf.ucbuf ; + for (k = 0 ; k < readcount ; k += 2) + { sample = (ucptr [0] << 8) | (ucptr [1] & 0xF0) ; + ptr [total + k] = sample ; + sample = (ucptr [2] << 8) | ((ucptr [1] & 0xF) << 4) ; + ptr [total + k + 1] = sample ; + ucptr += 3 ; + } ; + + total += count ; + len -= readcount ; + } ; + + return total ; +} /* txw_read_s */ + +static sf_count_t +txw_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + unsigned char *ucptr ; + short sample ; + int k, bufferlen, readcount, count ; + sf_count_t total = 0 ; + + bufferlen = sizeof (ubuf.cbuf) / 3 ; + bufferlen -= (bufferlen & 1) ; + while (len > 0) + { readcount = (len >= bufferlen) ? bufferlen : len ; + count = psf_fread (ubuf.cbuf, 3, readcount, psf) ; + + ucptr = ubuf.ucbuf ; + for (k = 0 ; k < readcount ; k += 2) + { sample = (ucptr [0] << 8) | (ucptr [1] & 0xF0) ; + ptr [total + k] = sample << 16 ; + sample = (ucptr [2] << 8) | ((ucptr [1] & 0xF) << 4) ; + ptr [total + k + 1] = sample << 16 ; + ucptr += 3 ; + } ; + + total += count ; + len -= readcount ; + } ; + + return total ; +} /* txw_read_i */ + +static sf_count_t +txw_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + unsigned char *ucptr ; + short sample ; + int k, bufferlen, readcount, count ; + sf_count_t total = 0 ; + float normfact ; + + if (psf->norm_float == SF_TRUE) + normfact = 1.0 / 0x8000 ; + else + normfact = 1.0 / 0x10 ; + + bufferlen = sizeof (ubuf.cbuf) / 3 ; + bufferlen -= (bufferlen & 1) ; + while (len > 0) + { readcount = (len >= bufferlen) ? bufferlen : len ; + count = psf_fread (ubuf.cbuf, 3, readcount, psf) ; + + ucptr = ubuf.ucbuf ; + for (k = 0 ; k < readcount ; k += 2) + { sample = (ucptr [0] << 8) | (ucptr [1] & 0xF0) ; + ptr [total + k] = normfact * sample ; + sample = (ucptr [2] << 8) | ((ucptr [1] & 0xF) << 4) ; + ptr [total + k + 1] = normfact * sample ; + ucptr += 3 ; + } ; + + total += count ; + len -= readcount ; + } ; + + return total ; +} /* txw_read_f */ + +static sf_count_t +txw_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + unsigned char *ucptr ; + short sample ; + int k, bufferlen, readcount, count ; + sf_count_t total = 0 ; + double normfact ; + + if (psf->norm_double == SF_TRUE) + normfact = 1.0 / 0x8000 ; + else + normfact = 1.0 / 0x10 ; + + bufferlen = sizeof (ubuf.cbuf) / 3 ; + bufferlen -= (bufferlen & 1) ; + while (len > 0) + { readcount = (len >= bufferlen) ? bufferlen : len ; + count = psf_fread (ubuf.cbuf, 3, readcount, psf) ; + + ucptr = ubuf.ucbuf ; + for (k = 0 ; k < readcount ; k += 2) + { sample = (ucptr [0] << 8) | (ucptr [1] & 0xF0) ; + ptr [total + k] = normfact * sample ; + sample = (ucptr [2] << 8) | ((ucptr [1] & 0xF) << 4) ; + ptr [total + k + 1] = normfact * sample ; + ucptr += 3 ; + } ; + + total += count ; + len -= readcount ; + } ; + + return total ; +} /* txw_read_d */ + +static sf_count_t +txw_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) +{ if (psf && mode) + return offset ; + + return 0 ; +} /* txw_seek */ + +#endif diff --git a/extern/libsndfile-modified/src/ulaw.c b/extern/libsndfile-modified/src/ulaw.c new file mode 100644 index 000000000..ed2f8ff05 --- /dev/null +++ b/extern/libsndfile-modified/src/ulaw.c @@ -0,0 +1,1056 @@ +/* +** Copyright (C) 1999-2013 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include + +#include "sndfile.h" +#include "common.h" + +static sf_count_t ulaw_read_ulaw2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; +static sf_count_t ulaw_read_ulaw2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; +static sf_count_t ulaw_read_ulaw2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; +static sf_count_t ulaw_read_ulaw2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; + +static sf_count_t ulaw_write_s2ulaw (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; +static sf_count_t ulaw_write_i2ulaw (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; +static sf_count_t ulaw_write_f2ulaw (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; +static sf_count_t ulaw_write_d2ulaw (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; + +int +ulaw_init (SF_PRIVATE *psf) +{ + if (psf->file.mode == SFM_READ || psf->file.mode == SFM_RDWR) + { psf->read_short = ulaw_read_ulaw2s ; + psf->read_int = ulaw_read_ulaw2i ; + psf->read_float = ulaw_read_ulaw2f ; + psf->read_double = ulaw_read_ulaw2d ; + } ; + + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { psf->write_short = ulaw_write_s2ulaw ; + psf->write_int = ulaw_write_i2ulaw ; + psf->write_float = ulaw_write_f2ulaw ; + psf->write_double = ulaw_write_d2ulaw ; + } ; + + psf->bytewidth = 1 ; + psf->blockwidth = psf->sf.channels ; + + if (psf->filelength > psf->dataoffset) + psf->datalength = (psf->dataend) ? psf->dataend - psf->dataoffset : + psf->filelength - psf->dataoffset ; + else + psf->datalength = 0 ; + + psf->sf.frames = psf->blockwidth > 0 ? psf->datalength / psf->blockwidth : 0 ; + + return 0 ; +} /* ulaw_init */ + +/*============================================================================== +*/ + +static short ulaw_decode [256] = +{ -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956, + -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764, + -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412, + -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316, + -7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140, + -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092, + -3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004, + -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980, + -1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436, + -1372, -1308, -1244, -1180, -1116, -1052, -988, -924, + -876, -844, -812, -780, -748, -716, -684, -652, + -620, -588, -556, -524, -492, -460, -428, -396, + -372, -356, -340, -324, -308, -292, -276, -260, + -244, -228, -212, -196, -180, -164, -148, -132, + -120, -112, -104, -96, -88, -80, -72, -64, + -56, -48, -40, -32, -24, -16, -8, 0, + + 32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956, + 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, + 15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412, + 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316, + 7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140, + 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092, + 3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004, + 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980, + 1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436, + 1372, 1308, 1244, 1180, 1116, 1052, 988, 924, + 876, 844, 812, 780, 748, 716, 684, 652, + 620, 588, 556, 524, 492, 460, 428, 396, + 372, 356, 340, 324, 308, 292, 276, 260, + 244, 228, 212, 196, 180, 164, 148, 132, + 120, 112, 104, 96, 88, 80, 72, 64, + 56, 48, 40, 32, 24, 16, 8, 0 +} ; + +static +unsigned char ulaw_encode [8193] = +{ 0xff, 0xfe, 0xfe, 0xfd, 0xfd, 0xfc, 0xfc, 0xfb, 0xfb, 0xfa, 0xfa, 0xf9, + 0xf9, 0xf8, 0xf8, 0xf7, 0xf7, 0xf6, 0xf6, 0xf5, 0xf5, 0xf4, 0xf4, 0xf3, + 0xf3, 0xf2, 0xf2, 0xf1, 0xf1, 0xf0, 0xf0, 0xef, 0xef, 0xef, 0xef, 0xee, + 0xee, 0xee, 0xee, 0xed, 0xed, 0xed, 0xed, 0xec, 0xec, 0xec, 0xec, 0xeb, + 0xeb, 0xeb, 0xeb, 0xea, 0xea, 0xea, 0xea, 0xe9, 0xe9, 0xe9, 0xe9, 0xe8, + 0xe8, 0xe8, 0xe8, 0xe7, 0xe7, 0xe7, 0xe7, 0xe6, 0xe6, 0xe6, 0xe6, 0xe5, + 0xe5, 0xe5, 0xe5, 0xe4, 0xe4, 0xe4, 0xe4, 0xe3, 0xe3, 0xe3, 0xe3, 0xe2, + 0xe2, 0xe2, 0xe2, 0xe1, 0xe1, 0xe1, 0xe1, 0xe0, 0xe0, 0xe0, 0xe0, 0xdf, + 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xde, 0xde, 0xde, 0xde, 0xde, + 0xde, 0xde, 0xde, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdc, + 0xdc, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, + 0xdb, 0xdb, 0xdb, 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xd9, + 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, + 0xd8, 0xd8, 0xd8, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd6, + 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, + 0xd5, 0xd5, 0xd5, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd3, + 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, + 0xd2, 0xd2, 0xd2, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd0, + 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, + 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xce, + 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, + 0xce, 0xce, 0xce, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcb, + 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, + 0xcb, 0xcb, 0xcb, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, + 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, + 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc8, + 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, + 0xc8, 0xc8, 0xc8, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, + 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc5, + 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, + 0xc5, 0xc5, 0xc5, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, + 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc2, + 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, + 0xc2, 0xc2, 0xc2, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, + 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, + 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 +} ; + +static inline void +ulaw2s_array (unsigned char *buffer, int count, short *ptr) +{ for (int i = 0 ; i < count ; i++) + ptr [i] = ulaw_decode [(int) buffer [i]] ; +} /* ulaw2s_array */ + +static inline void +ulaw2i_array (unsigned char *buffer, int count, int *ptr) +{ for (int i = 0 ; i < count ; i++) + ptr [i] = ((uint32_t) ulaw_decode [buffer [i]]) << 16 ; +} /* ulaw2i_array */ + +static inline void +ulaw2f_array (unsigned char *buffer, int count, float *ptr, float normfact) +{ for (int i = 0 ; i < count ; i++) + ptr [i] = normfact * ulaw_decode [(int) buffer [i]] ; +} /* ulaw2f_array */ + +static inline void +ulaw2d_array (const unsigned char *buffer, int count, double *ptr, double normfact) +{ for (int i = 0 ; i < count ; i++) + ptr [i] = normfact * ulaw_decode [(int) buffer [i]] ; +} /* ulaw2d_array */ + +static inline void +s2ulaw_array (const short *ptr, int count, unsigned char *buffer) +{ for (int i = 0 ; i < count ; i++) + { if (ptr [i] >= 0) + buffer [i] = ulaw_encode [ptr [i] / 4] ; + else + buffer [i] = 0x7F & ulaw_encode [ptr [i] / -4] ; + } ; +} /* s2ulaw_array */ + +static inline void +i2ulaw_array (const int *ptr, int count, unsigned char *buffer) +{ for (int i = 0 ; i < count ; i++) + { if (ptr [i] == INT_MIN) + buffer [i] = ulaw_encode [INT_MAX >> (16 + 2)] ; + else if (ptr [i] >= 0) + buffer [i] = ulaw_encode [ptr [i] >> (16 + 2)] ; + else + buffer [i] = 0x7F & ulaw_encode [-ptr [i] >> (16 + 2)] ; + } ; +} /* i2ulaw_array */ + +static inline void +f2ulaw_array (const float *ptr, int count, unsigned char *buffer, float normfact) +{ for (int i = 0 ; i < count ; i++) + { if (ptr [i] >= 0) + buffer [i] = ulaw_encode [psf_lrintf (normfact * ptr [i])] ; + else + buffer [i] = 0x7F & ulaw_encode [- psf_lrintf (normfact * ptr [i])] ; + } ; +} /* f2ulaw_array */ + +static inline void +d2ulaw_array (const double *ptr, int count, unsigned char *buffer, double normfact) +{ for (int i = 0 ; i < count ; i++) + { if (!isfinite (ptr [i])) + buffer [i] = 0 ; + else if (ptr [i] >= 0) + buffer [i] = ulaw_encode [psf_lrint (normfact * ptr [i])] ; + else + buffer [i] = 0x7F & ulaw_encode [- psf_lrint (normfact * ptr [i])] ; + } ; +} /* d2ulaw_array */ + +/*============================================================================== +*/ + +static sf_count_t +ulaw_read_ulaw2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + + bufferlen = ARRAY_LEN (ubuf.ucbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.ucbuf, 1, bufferlen, psf) ; + ulaw2s_array (ubuf.ucbuf, readcount, ptr + total) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* ulaw_read_ulaw2s */ + +static sf_count_t +ulaw_read_ulaw2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + + bufferlen = ARRAY_LEN (ubuf.ucbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.ucbuf, 1, bufferlen, psf) ; + ulaw2i_array (ubuf.ucbuf, readcount, ptr + total) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* ulaw_read_ulaw2i */ + +static sf_count_t +ulaw_read_ulaw2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + float normfact ; + + normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x8000) : 1.0 ; + + bufferlen = ARRAY_LEN (ubuf.ucbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.ucbuf, 1, bufferlen, psf) ; + ulaw2f_array (ubuf.ucbuf, readcount, ptr + total, normfact) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* ulaw_read_ulaw2f */ + +static sf_count_t +ulaw_read_ulaw2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + double normfact ; + + normfact = (psf->norm_double) ? 1.0 / ((double) 0x8000) : 1.0 ; + bufferlen = ARRAY_LEN (ubuf.ucbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.ucbuf, 1, bufferlen, psf) ; + ulaw2d_array (ubuf.ucbuf, readcount, ptr + total, normfact) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* ulaw_read_ulaw2d */ + +/*============================================================================================= +*/ + +static sf_count_t +ulaw_write_s2ulaw (SF_PRIVATE *psf, const short *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + bufferlen = ARRAY_LEN (ubuf.ucbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + s2ulaw_array (ptr + total, bufferlen, ubuf.ucbuf) ; + writecount = (int) psf_fwrite (ubuf.ucbuf, 1, bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* ulaw_write_s2ulaw */ + +static sf_count_t +ulaw_write_i2ulaw (SF_PRIVATE *psf, const int *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + bufferlen = ARRAY_LEN (ubuf.ucbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + i2ulaw_array (ptr + total, bufferlen, ubuf.ucbuf) ; + writecount = (int) psf_fwrite (ubuf.ucbuf, 1, bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* ulaw_write_i2ulaw */ + +static sf_count_t +ulaw_write_f2ulaw (SF_PRIVATE *psf, const float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + float normfact ; + + /* Factor in a divide by 4. */ + normfact = (psf->norm_float == SF_TRUE) ? (0.25 * 0x7FFF) : 0.25 ; + + bufferlen = ARRAY_LEN (ubuf.ucbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + f2ulaw_array (ptr + total, bufferlen, ubuf.ucbuf, normfact) ; + writecount = (int) psf_fwrite (ubuf.ucbuf, 1, bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* ulaw_write_f2ulaw */ + +static sf_count_t +ulaw_write_d2ulaw (SF_PRIVATE *psf, const double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + double normfact ; + + /* Factor in a divide by 4. */ + normfact = (psf->norm_double) ? (0.25 * 0x7FFF) : 0.25 ; + + bufferlen = ARRAY_LEN (ubuf.ucbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + d2ulaw_array (ptr + total, bufferlen, ubuf.ucbuf, normfact) ; + writecount = (int) psf_fwrite (ubuf.ucbuf, 1, bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* ulaw_write_d2ulaw */ + diff --git a/extern/libsndfile-modified/src/version-metadata.rc.in b/extern/libsndfile-modified/src/version-metadata.rc.in new file mode 100644 index 000000000..a672e4bbe --- /dev/null +++ b/extern/libsndfile-modified/src/version-metadata.rc.in @@ -0,0 +1,31 @@ +#include + +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS +1 VERSIONINFO + FILEVERSION @WIN_RC_VERSION@,0 + PRODUCTVERSION @WIN_RC_VERSION@,0 + FILEOS VOS__WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VFT2_UNKNOWN + FILEFLAGSMASK 0x00000000 + FILEFLAGS 0x00000000 +{ + BLOCK "StringFileInfo" + { + BLOCK "040904e4" + { + VALUE "FileDescription", "A library for reading and writing audio files." + VALUE "FileVersion", "@CLEAN_VERSION@.0\0" + VALUE "Full Version", "@PACKAGE_VERSION@" + VALUE "InternalName", "libsndfile" + VALUE "LegalCopyright", "Copyright (C) 1999-2012, Licensed LGPL" + VALUE "ProductName", "libsndfile-1 DLL" + VALUE "ProductVersion", "@CLEAN_VERSION@.0\0" + VALUE "Language", "Language Neutral" + } + } + BLOCK "VarFileInfo" + { + VALUE "Translation", 0x0409, 0x04E4 + } +} diff --git a/extern/libsndfile-modified/src/voc.c b/extern/libsndfile-modified/src/voc.c new file mode 100644 index 000000000..380d3a3f1 --- /dev/null +++ b/extern/libsndfile-modified/src/voc.c @@ -0,0 +1,883 @@ +/* +** Copyright (C) 2001-2018 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/* RANT: +** The VOC file format is the most brain damaged format I have yet had to deal +** with. No one programmer could have bee stupid enough to put this together. +** Instead it looks like a series of manic, dyslexic assembly language programmers +** hacked it to fit their needs. +** Utterly woeful. +*/ + +#include "sfconfig.h" + +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + + +/*------------------------------------------------------------------------------ + * Typedefs for file chunks. +*/ + +#define VOC_MAX_SECTIONS 200 + +enum +{ VOC_TERMINATOR = 0, + VOC_SOUND_DATA = 1, + VOC_SOUND_CONTINUE = 2, + VOC_SILENCE = 3, + VOC_MARKER = 4, + VOC_ASCII = 5, + VOC_REPEAT = 6, + VOC_END_REPEAT = 7, + VOC_EXTENDED = 8, + VOC_EXTENDED_II = 9 +} ; + +typedef struct +{ int samples ; + int offset ; /* Offset of zero => silence. */ +} SND_DATA_BLOCKS ; + +typedef struct +{ unsigned int sections, section_types ; + int samplerate, channels, bitwidth ; + SND_DATA_BLOCKS blocks [VOC_MAX_SECTIONS] ; +} VOC_DATA ; + +/*------------------------------------------------------------------------------ + * Private static functions. +*/ + +static int voc_close (SF_PRIVATE *psf) ; +static int voc_write_header (SF_PRIVATE *psf, int calc_length) ; +static int voc_read_header (SF_PRIVATE *psf) ; + +static const char* voc_encoding2str (int encoding) ; + +#if 0 + +/* These functions would be required for files with more than one VOC_SOUND_DATA +** segment. Not sure whether to bother implementing this. +*/ + +static int voc_multi_init (SF_PRIVATE *psf, VOC_DATA *pvoc) ; + +static int voc_multi_read_uc2s (SF_PRIVATE *psf, short *ptr, int len) ; +static int voc_multi_read_les2s (SF_PRIVATE *psf, short *ptr, int len) ; + +static int voc_multi_read_uc2i (SF_PRIVATE *psf, int *ptr, int len) ; +static int voc_multi_read_les2i (SF_PRIVATE *psf, int *ptr, int len) ; + +static int voc_multi_read_uc2f (SF_PRIVATE *psf, float *ptr, int len) ; +static int voc_multi_read_les2f (SF_PRIVATE *psf, float *ptr, int len) ; + +static int voc_multi_read_uc2d (SF_PRIVATE *psf, double *ptr, int len) ; +static int voc_multi_read_les2d (SF_PRIVATE *psf, double *ptr, int len) ; +#endif + +/*------------------------------------------------------------------------------ +** Public function. +*/ + +int +voc_open (SF_PRIVATE *psf) +{ int subformat, error = 0 ; + + if (psf->is_pipe) + return SFE_VOC_NO_PIPE ; + + if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0)) + { if ((error = voc_read_header (psf))) + return error ; + } ; + + subformat = SF_CODEC (psf->sf.format) ; + + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_VOC) + return SFE_BAD_OPEN_FORMAT ; + + psf->endian = SF_ENDIAN_LITTLE ; + + if ((error = voc_write_header (psf, SF_FALSE))) + return error ; + + psf->write_header = voc_write_header ; + } ; + + psf->blockwidth = psf->bytewidth * psf->sf.channels ; + + psf->container_close = voc_close ; + + switch (subformat) + { case SF_FORMAT_PCM_U8 : + case SF_FORMAT_PCM_16 : + error = pcm_init (psf) ; + break ; + + case SF_FORMAT_ALAW : + error = alaw_init (psf) ; + break ; + + case SF_FORMAT_ULAW : + error = ulaw_init (psf) ; + break ; + + default : return SFE_UNIMPLEMENTED ; + } ; + + return error ; +} /* voc_open */ + +/*------------------------------------------------------------------------------ +*/ + +static int +voc_read_header (SF_PRIVATE *psf) +{ VOC_DATA *pvoc ; + char creative [20] ; + unsigned char block_type, rate_byte ; + short version, checksum, encoding, dataoffset ; + int offset ; + + /* Set position to start of file to begin reading header. */ + offset = psf_binheader_readf (psf, "pb", 0, creative, SIGNED_SIZEOF (creative)) ; + + if (creative [sizeof (creative) - 1] != 0x1A) + return SFE_VOC_NO_CREATIVE ; + + /* Terminate the string. */ + creative [sizeof (creative) - 1] = 0 ; + + if (strcmp ("Creative Voice File", creative)) + return SFE_VOC_NO_CREATIVE ; + + psf_log_printf (psf, "%s\n", creative) ; + + offset += psf_binheader_readf (psf, "e222", &dataoffset, &version, &checksum) ; + + psf->dataoffset = dataoffset ; + + psf_log_printf (psf, "dataoffset : %d\n" + "version : 0x%X\n" + "checksum : 0x%X\n", psf->dataoffset, version, checksum) ; + + if (version != 0x010A && version != 0x0114) + return SFE_VOC_BAD_VERSION ; + + if (! (psf->codec_data = malloc (sizeof (VOC_DATA)))) + return SFE_MALLOC_FAILED ; + + pvoc = (VOC_DATA*) psf->codec_data ; + + memset (pvoc, 0, sizeof (VOC_DATA)) ; + + /* Set the default encoding now. */ + psf->sf.format = SF_FORMAT_VOC ; /* Major format */ + encoding = SF_FORMAT_PCM_U8 ; /* Minor format */ + psf->endian = SF_ENDIAN_LITTLE ; + + while (1) + { char header [256] ; + unsigned size ; + short count ; + + block_type = 0 ; + offset += psf_binheader_readf (psf, "1", &block_type) ; + + switch (block_type) + { case VOC_ASCII : + offset += psf_binheader_readf (psf, "e3", &size) ; + + psf_log_printf (psf, " ASCII : %d\n", size) ; + + if (size < sizeof (header) - 1) + { offset += psf_binheader_readf (psf, "b", header, size) ; + header [size] = 0 ; + psf_log_printf (psf, " text : %s\n", header) ; + continue ; + } + + offset += psf_binheader_readf (psf, "j", size) ; + continue ; + + case VOC_REPEAT : + offset += psf_binheader_readf (psf, "e32", &size, &count) ; + psf_log_printf (psf, " Repeat : %d\n", count) ; + continue ; + + case VOC_SOUND_DATA : + case VOC_EXTENDED : + case VOC_EXTENDED_II : + break ; + + default : psf_log_printf (psf, "*** Weird block marker (%d)\n", block_type) ; + } ; + + break ; + } ; + + if (block_type == VOC_SOUND_DATA) + { unsigned char compression ; + int size ; + + offset += psf_binheader_readf (psf, "e311", &size, &rate_byte, &compression) ; + + psf->sf.samplerate = 1000000 / (256 - (rate_byte & 0xFF)) ; + + psf_log_printf (psf, " Sound Data : %d\n sr : %d => %dHz\n comp : %d\n", + size, rate_byte, psf->sf.samplerate, compression) ; + + if (offset + size - 1 > psf->filelength) + { psf_log_printf (psf, "Seems to be a truncated file.\n") ; + psf_log_printf (psf, "offset: %d size: %d sum: %d filelength: %D\n", offset, size, offset + size, psf->filelength) ; + return SFE_VOC_BAD_SECTIONS ; + } + else if (psf->filelength - offset - size > 4) + { psf_log_printf (psf, "Seems to be a multi-segment file (#1).\n") ; + psf_log_printf (psf, "offset: %d size: %d sum: %d filelength: %D\n", offset, size, offset + size, psf->filelength) ; + return SFE_VOC_BAD_SECTIONS ; + } ; + + psf->dataoffset = offset ; + psf->dataend = psf->filelength - 1 ; + + psf->sf.channels = 1 ; + psf->bytewidth = 1 ; + + psf->sf.format = SF_FORMAT_VOC | SF_FORMAT_PCM_U8 ; + + return 0 ; + } ; + + if (block_type == VOC_EXTENDED) + { unsigned char pack, stereo, compression ; + unsigned short rate_short ; + int size ; + + offset += psf_binheader_readf (psf, "e3211", &size, &rate_short, &pack, &stereo) ; + + psf_log_printf (psf, " Extended : %d\n", size) ; + if (size == 4) + psf_log_printf (psf, " size : 4\n") ; + else + psf_log_printf (psf, " size : %d (should be 4)\n", size) ; + + psf_log_printf (psf, " pack : %d\n" + " stereo : %s\n", pack, (stereo ? "yes" : "no")) ; + + if (stereo) + { psf->sf.channels = 2 ; + psf->sf.samplerate = 128000000 / (65536 - rate_short) ; + } + else + { psf->sf.channels = 1 ; + psf->sf.samplerate = 256000000 / (65536 - rate_short) ; + } ; + + psf_log_printf (psf, " sr : %d => %dHz\n", (rate_short & 0xFFFF), psf->sf.samplerate) ; + + offset += psf_binheader_readf (psf, "1", &block_type) ; + + if (block_type != VOC_SOUND_DATA) + { psf_log_printf (psf, "*** Expecting VOC_SOUND_DATA section.\n") ; + return SFE_VOC_BAD_FORMAT ; + } ; + + offset += psf_binheader_readf (psf, "e311", &size, &rate_byte, &compression) ; + + psf_log_printf (psf, " Sound Data : %d\n" + " sr : %d\n" + " comp : %d\n", size, rate_byte, compression) ; + + + if (offset + size - 1 > psf->filelength) + { psf_log_printf (psf, "Seems to be a truncated file.\n") ; + psf_log_printf (psf, "offset: %d size: %d sum: %d filelength: %D\n", offset, size, offset + size, psf->filelength) ; + return SFE_VOC_BAD_SECTIONS ; + } + else if (offset + size - 1 < psf->filelength) + { psf_log_printf (psf, "Seems to be a multi-segment file (#2).\n") ; + psf_log_printf (psf, "offset: %d size: %d sum: %d filelength: %D\n", offset, size, offset + size, psf->filelength) ; + return SFE_VOC_BAD_SECTIONS ; + } ; + + psf->dataoffset = offset ; + psf->dataend = psf->filelength - 1 ; + + psf->bytewidth = 1 ; + + psf->sf.format = SF_FORMAT_VOC | SF_FORMAT_PCM_U8 ; + + return 0 ; + } + + if (block_type == VOC_EXTENDED_II) + { unsigned char bitwidth, channels ; + int size, fourbytes ; + + offset += psf_binheader_readf (psf, "e341124", &size, &psf->sf.samplerate, + &bitwidth, &channels, &encoding, &fourbytes) ; + + if (size * 2 == psf->filelength - 39) + { int temp_size = psf->filelength - 31 ; + + psf_log_printf (psf, " Extended II : %d (SoX bug: should be %d)\n", size, temp_size) ; + size = temp_size ; + } + else + psf_log_printf (psf, " Extended II : %d\n", size) ; + + psf_log_printf (psf, " sample rate : %d\n" + " bit width : %d\n" + " channels : %d\n", psf->sf.samplerate, bitwidth, channels) ; + + if (bitwidth == 16 && encoding == 0) + { encoding = 4 ; + psf_log_printf (psf, " encoding : 0 (SoX bug: should be 4 for 16 bit signed PCM)\n") ; + } + else + psf_log_printf (psf, " encoding : %d => %s\n", encoding, voc_encoding2str (encoding)) ; + + + psf_log_printf (psf, " fourbytes : %X\n", fourbytes) ; + + psf->sf.channels = channels ; + + psf->dataoffset = offset ; + psf->dataend = psf->filelength - 1 ; + + if (size + 31 == psf->filelength + 1) + { /* Hack for reading files produced using + ** sf_command (SFC_UPDATE_HEADER_NOW). + */ + psf_log_printf (psf, "Missing zero byte at end of file.\n") ; + size = psf->filelength - 30 ; + psf->dataend = 0 ; + } + else if (size + 31 > psf->filelength) + { psf_log_printf (psf, "Seems to be a truncated file.\n") ; + size = psf->filelength - 31 ; + } + else if (size + 31 < psf->filelength) + psf_log_printf (psf, "Seems to be a multi-segment file (#3).\n") ; + + switch (encoding) + { case 0 : + psf->sf.format = SF_FORMAT_VOC | SF_FORMAT_PCM_U8 ; + psf->bytewidth = 1 ; + break ; + + case 4 : + psf->sf.format = SF_FORMAT_VOC | SF_FORMAT_PCM_16 ; + psf->bytewidth = 2 ; + break ; + + case 6 : + psf->sf.format = SF_FORMAT_VOC | SF_FORMAT_ALAW ; + psf->bytewidth = 1 ; + break ; + + case 7 : + psf->sf.format = SF_FORMAT_VOC | SF_FORMAT_ULAW ; + psf->bytewidth = 1 ; + break ; + + default : /* Unknown */ + return SFE_VOC_BAD_FORMAT ; + break ; + } ; + + } ; + + return 0 ; +} /* voc_read_header */ + +/*==================================================================================== +*/ + +static int +voc_write_header (SF_PRIVATE *psf, int calc_length) +{ sf_count_t current ; + int rate_const, subformat ; + + current = psf_ftell (psf) ; + + if (calc_length) + { psf->filelength = psf_get_filelen (psf) ; + + psf->datalength = psf->filelength - psf->dataoffset ; + if (psf->dataend) + psf->datalength -= psf->filelength - psf->dataend ; + + psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ; + } ; + + subformat = SF_CODEC (psf->sf.format) ; + /* Reset the current header length to zero. */ + psf->header.ptr [0] = 0 ; + psf->header.indx = 0 ; + psf_fseek (psf, 0, SEEK_SET) ; + + /* VOC marker and 0x1A byte. */ + psf_binheader_writef (psf, "eb1", BHWv ("Creative Voice File"), BHWz (19), BHW1 (0x1A)) ; + + /* Data offset, version and other. */ + psf_binheader_writef (psf, "e222", BHW2 (26), BHW2 (0x0114), BHW2 (0x111F)) ; + + /* Use same logic as SOX. + ** If the file is mono 8 bit data, use VOC_SOUND_DATA. + ** If the file is mono 16 bit data, use VOC_EXTENED. + ** Otherwise use VOC_EXTENED_2. + */ + + if (subformat == SF_FORMAT_PCM_U8 && psf->sf.channels == 1) + { /* samplerate = 1000000 / (256 - rate_const) ; */ + rate_const = 256 - 1000000 / psf->sf.samplerate ; + + /* First type marker, length, rate_const and compression */ + psf_binheader_writef (psf, "e1311", BHW1 (VOC_SOUND_DATA), BHW3 ((int) (psf->datalength + 1)), BHW1 (rate_const), BHW1 (0)) ; + } + else if (subformat == SF_FORMAT_PCM_U8 && psf->sf.channels == 2) + { /* sample_rate = 128000000 / (65536 - rate_short) ; */ + rate_const = 65536 - 128000000 / psf->sf.samplerate ; + + /* First write the VOC_EXTENDED section + ** marker, length, rate_const and compression + */ + psf_binheader_writef (psf, "e13211", BHW1 (VOC_EXTENDED), BHW3 (4), BHW2 (rate_const), BHW1 (0), BHW1 (1)) ; + + /* samplerate = 1000000 / (256 - rate_const) ; */ + rate_const = 256 - 1000000 / psf->sf.samplerate ; + + /* Now write the VOC_SOUND_DATA section + ** marker, length, rate_const and compression + */ + psf_binheader_writef (psf, "e1311", BHW1 (VOC_SOUND_DATA), BHW3 ((int) (psf->datalength + 1)), BHW1 (rate_const), BHW1 (0)) ; + } + else + { int length ; + + if (psf->sf.channels < 1 || psf->sf.channels > 2) + return SFE_CHANNEL_COUNT ; + + switch (subformat) + { case SF_FORMAT_PCM_U8 : + psf->bytewidth = 1 ; + length = psf->sf.frames * psf->sf.channels * psf->bytewidth + 12 ; + /* Marker, length, sample rate, bitwidth, stereo flag, encoding and fourt zero bytes. */ + psf_binheader_writef (psf, "e1341124", BHW1 (VOC_EXTENDED_II), BHW3 (length), BHW4 (psf->sf.samplerate), BHW1 (16), BHW1 (psf->sf.channels), BHW2 (4), BHW4 (0)) ; + break ; + + case SF_FORMAT_PCM_16 : + psf->bytewidth = 2 ; + length = psf->sf.frames * psf->sf.channels * psf->bytewidth + 12 ; + /* Marker, length, sample rate, bitwidth, stereo flag, encoding and fourt zero bytes. */ + psf_binheader_writef (psf, "e1341124", BHW1 (VOC_EXTENDED_II), BHW3 (length), BHW4 (psf->sf.samplerate), BHW1 (16), BHW1 (psf->sf.channels), BHW2 (4), BHW4 (0)) ; + break ; + + case SF_FORMAT_ALAW : + psf->bytewidth = 1 ; + length = psf->sf.frames * psf->sf.channels * psf->bytewidth + 12 ; + psf_binheader_writef (psf, "e1341124", BHW1 (VOC_EXTENDED_II), BHW3 (length), BHW4 (psf->sf.samplerate), BHW1 (8), BHW1 (psf->sf.channels), BHW2 (6), BHW4 (0)) ; + break ; + + case SF_FORMAT_ULAW : + psf->bytewidth = 1 ; + length = psf->sf.frames * psf->sf.channels * psf->bytewidth + 12 ; + psf_binheader_writef (psf, "e1341124", BHW1 (VOC_EXTENDED_II), BHW3 (length), BHW4 (psf->sf.samplerate), BHW1 (8), BHW1 (psf->sf.channels), BHW2 (7), BHW4 (0)) ; + break ; + + default : return SFE_UNIMPLEMENTED ; + } ; + } ; + + psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ; + + if (psf->error) + return psf->error ; + + psf->dataoffset = psf->header.indx ; + + if (current > 0) + psf_fseek (psf, current, SEEK_SET) ; + + return psf->error ; +} /* voc_write_header */ + +static int +voc_close (SF_PRIVATE *psf) +{ + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { /* Now we know for certain the length of the file we can re-write + ** correct values for the FORM, 8SVX and BODY chunks. + */ + unsigned char byte = VOC_TERMINATOR ; + + + psf_fseek (psf, 0, SEEK_END) ; + + /* Write terminator */ + psf_fwrite (&byte, 1, 1, psf) ; + + voc_write_header (psf, SF_TRUE) ; + } ; + + return 0 ; +} /* voc_close */ + +static const char* +voc_encoding2str (int encoding) +{ + switch (encoding) + { case 0 : return "8 bit unsigned PCM" ; + case 4 : return "16 bit signed PCM" ; + case 6 : return "A-law" ; + case 7 : return "u-law" ; + default : break ; + } + return "*** Unknown ***" ; +} /* voc_encoding2str */ + +/*==================================================================================== +*/ + +#if 0 +static int +voc_multi_init (SF_PRIVATE *psf, VOC_DATA *pvoc) +{ + psf->sf.frames = 0 ; + + if (pvoc->bitwidth == 8) + { psf->read_short = voc_multi_read_uc2s ; + psf->read_int = voc_multi_read_uc2i ; + psf->read_float = voc_multi_read_uc2f ; + psf->read_double = voc_multi_read_uc2d ; + return 0 ; + } ; + + if (pvoc->bitwidth == 16) + { psf->read_short = voc_multi_read_les2s ; + psf->read_int = voc_multi_read_les2i ; + psf->read_float = voc_multi_read_les2f ; + psf->read_double = voc_multi_read_les2d ; + return 0 ; + } ; + + psf_log_printf (psf, "Error : bitwith != 8 && bitwidth != 16.\n") ; + + return SFE_UNIMPLEMENTED ; +} /* voc_multi_read_int */ + +/*------------------------------------------------------------------------------------ +*/ + +static int +voc_multi_read_uc2s (SF_PRIVATE *psf, short *ptr, int len) +{ + + return 0 ; +} /* voc_multi_read_uc2s */ + +static int +voc_multi_read_les2s (SF_PRIVATE *psf, short *ptr, int len) +{ + + return 0 ; +} /* voc_multi_read_les2s */ + + +static int +voc_multi_read_uc2i (SF_PRIVATE *psf, int *ptr, int len) +{ + + return 0 ; +} /* voc_multi_read_uc2i */ + +static int +voc_multi_read_les2i (SF_PRIVATE *psf, int *ptr, int len) +{ + + return 0 ; +} /* voc_multi_read_les2i */ + + +static int +voc_multi_read_uc2f (SF_PRIVATE *psf, float *ptr, int len) +{ + + return 0 ; +} /* voc_multi_read_uc2f */ + +static int +voc_multi_read_les2f (SF_PRIVATE *psf, float *ptr, int len) +{ + + return 0 ; +} /* voc_multi_read_les2f */ + + +static int +voc_multi_read_uc2d (SF_PRIVATE *psf, double *ptr, int len) +{ + + return 0 ; +} /* voc_multi_read_uc2d */ + +static int +voc_multi_read_les2d (SF_PRIVATE *psf, double *ptr, int len) +{ + + return 0 ; +} /* voc_multi_read_les2d */ + +#endif + +/*------------------------------------------------------------------------------------ + +Creative Voice (VOC) file format +-------------------------------- + +~From: galt@dsd.es.com + +(byte numbers are hex!) + + HEADER (bytes 00-19) + Series of DATA BLOCKS (bytes 1A+) [Must end w/ Terminator Block] + +- --------------------------------------------------------------- + +HEADER: +======= + byte # Description + ------ ------------------------------------------ + 00-12 "Creative Voice File" + 13 1A (eof to abort printing of file) + 14-15 Offset of first datablock in .voc file (std 1A 00 + in Intel Notation) + 16-17 Version number (minor,major) (VOC-HDR puts 0A 01) + 18-19 1's Comp of Ver. # + 1234h (VOC-HDR puts 29 11) + +- --------------------------------------------------------------- + +DATA BLOCK: +=========== + + Data Block: TYPE(1-byte), SIZE(3-bytes), INFO(0+ bytes) + NOTE: Terminator Block is an exception -- it has only the TYPE byte. + + TYPE Description Size (3-byte int) Info + ---- ----------- ----------------- ----------------------- + 00 Terminator (NONE) (NONE) + 01 Sound data 2+length of data * + 02 Sound continue length of data Voice Data + 03 Silence 3 ** + 04 Marker 2 Marker# (2 bytes) + 05 ASCII length of string null terminated string + 06 Repeat 2 Count# (2 bytes) + 07 End repeat 0 (NONE) + 08 Extended 4 *** + + *Sound Info Format: + --------------------- + 00 Sample Rate + 01 Compression Type + 02+ Voice Data + + **Silence Info Format: + ---------------------------- + 00-01 Length of silence - 1 + 02 Sample Rate + + + ***Extended Info Format: + --------------------- + 00-01 Time Constant: Mono: 65536 - (256000000/sample_rate) + Stereo: 65536 - (25600000/(2*sample_rate)) + 02 Pack + 03 Mode: 0 = mono + 1 = stereo + + + Marker# -- Driver keeps the most recent marker in a status byte + Count# -- Number of repetitions + 1 + Count# may be 1 to FFFE for 0 - FFFD repetitions + or FFFF for endless repetitions + Sample Rate -- SR byte = 256-(1000000/sample_rate) + Length of silence -- in units of sampling cycle + Compression Type -- of voice data + 8-bits = 0 + 4-bits = 1 + 2.6-bits = 2 + 2-bits = 3 + Multi DAC = 3+(# of channels) [interesting-- + this isn't in the developer's manual] + + +--------------------------------------------------------------------------------- +Addendum submitted by Votis Kokavessis: + +After some experimenting with .VOC files I found out that there is a Data Block +Type 9, which is not covered in the VOC.TXT file. Here is what I was able to discover +about this block type: + + +TYPE: 09 +SIZE: 12 + length of data +INFO: 12 (twelve) bytes + +INFO STRUCTURE: + +Bytes 0-1: (Word) Sample Rate (e.g. 44100) +Bytes 2-3: zero (could be that bytes 0-3 are a DWord for Sample Rate) +Byte 4: Sample Size in bits (e.g. 16) +Byte 5: Number of channels (e.g. 1 for mono, 2 for stereo) +Byte 6: Unknown (equal to 4 in all files I examined) +Bytes 7-11: zero + + +-------------------------------------------------------------------------------------*/ + +/*===================================================================================== +**===================================================================================== +**===================================================================================== +**===================================================================================== +*/ + +/*------------------------------------------------------------------------ +The following is taken from the Audio File Formats FAQ dated 2-Jan-1995 +and submitted by Guido van Rossum . +-------------------------------------------------------------------------- +Creative Voice (VOC) file format +-------------------------------- + +From: galt@dsd.es.com + +(byte numbers are hex!) + + HEADER (bytes 00-19) + Series of DATA BLOCKS (bytes 1A+) [Must end w/ Terminator Block] + +- --------------------------------------------------------------- + +HEADER: +------- + byte # Description + ------ ------------------------------------------ + 00-12 "Creative Voice File" + 13 1A (eof to abort printing of file) + 14-15 Offset of first datablock in .voc file (std 1A 00 + in Intel Notation) + 16-17 Version number (minor,major) (VOC-HDR puts 0A 01) + 18-19 2's Comp of Ver. # + 1234h (VOC-HDR puts 29 11) + +- --------------------------------------------------------------- + +DATA BLOCK: +----------- + + Data Block: TYPE(1-byte), SIZE(3-bytes), INFO(0+ bytes) + NOTE: Terminator Block is an exception -- it has only the TYPE byte. + + TYPE Description Size (3-byte int) Info + ---- ----------- ----------------- ----------------------- + 00 Terminator (NONE) (NONE) + 01 Sound data 2+length of data * + 02 Sound continue length of data Voice Data + 03 Silence 3 ** + 04 Marker 2 Marker# (2 bytes) + 05 ASCII length of string null terminated string + 06 Repeat 2 Count# (2 bytes) + 07 End repeat 0 (NONE) + 08 Extended 4 *** + + *Sound Info Format: **Silence Info Format: + --------------------- ---------------------------- + 00 Sample Rate 00-01 Length of silence - 1 + 01 Compression Type 02 Sample Rate + 02+ Voice Data + + ***Extended Info Format: + --------------------- + 00-01 Time Constant: Mono: 65536 - (256000000/sample_rate) + Stereo: 65536 - (25600000/(2*sample_rate)) + 02 Pack + 03 Mode: 0 = mono + 1 = stereo + + + Marker# -- Driver keeps the most recent marker in a status byte + Count# -- Number of repetitions + 1 + Count# may be 1 to FFFE for 0 - FFFD repetitions + or FFFF for endless repetitions + Sample Rate -- SR byte = 256-(1000000/sample_rate) + Length of silence -- in units of sampling cycle + Compression Type -- of voice data + 8-bits = 0 + 4-bits = 1 + 2.6-bits = 2 + 2-bits = 3 + Multi DAC = 3+(# of channels) [interesting-- + this isn't in the developer's manual] + +Detailed description of new data blocks (VOC files version 1.20 and above): + + (Source is fax from Barry Boone at Creative Labs, 405/742-6622) + +BLOCK 8 - digitized sound attribute extension, must preceed block 1. + Used to define stereo, 8 bit audio + BYTE bBlockID; // = 8 + BYTE nBlockLen[3]; // 3 byte length + WORD wTimeConstant; // time constant = same as block 1 + BYTE bPackMethod; // same as in block 1 + BYTE bVoiceMode; // 0-mono, 1-stereo + + Data is stored left, right + +BLOCK 9 - data block that supersedes blocks 1 and 8. + Used for stereo, 16 bit. + + BYTE bBlockID; // = 9 + BYTE nBlockLen[3]; // length 12 plus length of sound + DWORD dwSamplesPerSec; // samples per second, not time const. + BYTE bBitsPerSample; // e.g., 8 or 16 + BYTE bChannels; // 1 for mono, 2 for stereo + WORD wFormat; // see below + BYTE reserved[4]; // pad to make block w/o data + // have a size of 16 bytes + + Valid values of wFormat are: + + 0x0000 8-bit unsigned PCM + 0x0001 Creative 8-bit to 4-bit ADPCM + 0x0002 Creative 8-bit to 3-bit ADPCM + 0x0003 Creative 8-bit to 2-bit ADPCM + 0x0004 16-bit signed PCM + 0x0006 CCITT a-Law + 0x0007 CCITT u-Law + 0x02000 Creative 16-bit to 4-bit ADPCM + + Data is stored left, right + +------------------------------------------------------------------------*/ diff --git a/extern/libsndfile-modified/src/vox_adpcm.c b/extern/libsndfile-modified/src/vox_adpcm.c new file mode 100644 index 000000000..e206675c0 --- /dev/null +++ b/extern/libsndfile-modified/src/vox_adpcm.c @@ -0,0 +1,400 @@ +/* +** Copyright (C) 2002-2014 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/* +** This is the OKI / Dialogic ADPCM encoder/decoder. It converts from +** 12 bit linear sample data to a 4 bit ADPCM. +*/ + +/* + * Note: some early Dialogic hardware does not always reset the ADPCM encoder + * at the start of each vox file. This can result in clipping and/or DC offset + * problems when it comes to decoding the audio. Whilst little can be done + * about the clipping, a DC offset can be removed by passing the decoded audio + * through a high-pass filter at e.g. 10Hz. + */ + +#include "sfconfig.h" + +#include +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" +#include "ima_oki_adpcm.h" + + +static sf_count_t vox_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; +static sf_count_t vox_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; +static sf_count_t vox_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; +static sf_count_t vox_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; + +static sf_count_t vox_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; +static sf_count_t vox_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; +static sf_count_t vox_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; +static sf_count_t vox_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; + +static int vox_read_block (SF_PRIVATE *psf, IMA_OKI_ADPCM *pvox, short *ptr, int len) ; + +/*------------------------------------------------------------------------------ +*/ + +static int +codec_close (SF_PRIVATE * psf) +{ + IMA_OKI_ADPCM * p = (IMA_OKI_ADPCM *) psf->codec_data ; + + if (p->errors) + psf_log_printf (psf, "*** Warning : ADPCM state errors: %d\n", p->errors) ; + return p->errors ; +} /* code_close */ + +int +vox_adpcm_init (SF_PRIVATE *psf) +{ IMA_OKI_ADPCM *pvox = NULL ; + + if (psf->file.mode == SFM_RDWR) + return SFE_BAD_MODE_RW ; + + if (psf->file.mode == SFM_WRITE && psf->sf.channels != 1) + return SFE_CHANNEL_COUNT ; + + if ((pvox = malloc (sizeof (IMA_OKI_ADPCM))) == NULL) + return SFE_MALLOC_FAILED ; + + psf->codec_data = (void*) pvox ; + memset (pvox, 0, sizeof (IMA_OKI_ADPCM)) ; + + if (psf->file.mode == SFM_WRITE) + { psf->write_short = vox_write_s ; + psf->write_int = vox_write_i ; + psf->write_float = vox_write_f ; + psf->write_double = vox_write_d ; + } + else + { psf_log_printf (psf, "Header-less OKI Dialogic ADPCM encoded file.\n") ; + psf_log_printf (psf, "Setting up for 8kHz, mono, Vox ADPCM.\n") ; + + psf->read_short = vox_read_s ; + psf->read_int = vox_read_i ; + psf->read_float = vox_read_f ; + psf->read_double = vox_read_d ; + } ; + + /* Standard sample rate chennels etc. */ + if (psf->sf.samplerate < 1) + psf->sf.samplerate = 8000 ; + psf->sf.channels = 1 ; + + psf->sf.frames = psf->filelength * 2 ; + + psf->sf.seekable = SF_FALSE ; + psf->codec_close = codec_close ; + + /* Seek back to start of data. */ + if (psf_fseek (psf, 0 , SEEK_SET) == -1) + return SFE_BAD_SEEK ; + + ima_oki_adpcm_init (pvox, IMA_OKI_ADPCM_TYPE_OKI) ; + + return 0 ; +} /* vox_adpcm_init */ + +/*============================================================================== +*/ + +static int +vox_read_block (SF_PRIVATE *psf, IMA_OKI_ADPCM *pvox, short *ptr, int len) +{ int indx = 0, k ; + + while (indx < len) + { pvox->code_count = (len - indx > IMA_OKI_ADPCM_PCM_LEN) ? IMA_OKI_ADPCM_CODE_LEN : (len - indx + 1) / 2 ; + + if ((k = (int) psf_fread (pvox->codes, 1, pvox->code_count, psf)) != pvox->code_count) + { if (psf_ftell (psf) != psf->filelength) + psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, pvox->code_count) ; + if (k == 0) + break ; + } ; + + pvox->code_count = k ; + + ima_oki_adpcm_decode_block (pvox) ; + + memcpy (&(ptr [indx]), pvox->pcm, pvox->pcm_count * sizeof (short)) ; + indx += pvox->pcm_count ; + } ; + + return indx ; +} /* vox_read_block */ + + +static sf_count_t +vox_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len) +{ IMA_OKI_ADPCM *pvox ; + int readcount, count ; + sf_count_t total = 0 ; + + if (! psf->codec_data) + return 0 ; + pvox = (IMA_OKI_ADPCM*) psf->codec_data ; + + while (len > 0) + { readcount = (len > 0x10000000) ? 0x10000000 : (int) len ; + + count = vox_read_block (psf, pvox, ptr, readcount) ; + + total += count ; + len -= count ; + if (count != readcount) + break ; + } ; + + return total ; +} /* vox_read_s */ + +static sf_count_t +vox_read_i (SF_PRIVATE *psf, int *ptr, sf_count_t len) +{ IMA_OKI_ADPCM *pvox ; + BUF_UNION ubuf ; + short *sptr ; + int k, bufferlen, readcount, count ; + sf_count_t total = 0 ; + + if (! psf->codec_data) + return 0 ; + pvox = (IMA_OKI_ADPCM*) psf->codec_data ; + + sptr = ubuf.sbuf ; + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + while (len > 0) + { readcount = (len >= bufferlen) ? bufferlen : (int) len ; + count = vox_read_block (psf, pvox, sptr, readcount) ; + for (k = 0 ; k < readcount ; k++) + ptr [total + k] = arith_shift_left (sptr [k], 16) ; + total += count ; + len -= readcount ; + if (count != readcount) + break ; + } ; + + return total ; +} /* vox_read_i */ + +static sf_count_t +vox_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) +{ IMA_OKI_ADPCM *pvox ; + BUF_UNION ubuf ; + short *sptr ; + int k, bufferlen, readcount, count ; + sf_count_t total = 0 ; + float normfact ; + + if (! psf->codec_data) + return 0 ; + pvox = (IMA_OKI_ADPCM*) psf->codec_data ; + + normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x8000) : 1.0 ; + + sptr = ubuf.sbuf ; + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + while (len > 0) + { readcount = (len >= bufferlen) ? bufferlen : (int) len ; + count = vox_read_block (psf, pvox, sptr, readcount) ; + for (k = 0 ; k < readcount ; k++) + ptr [total + k] = normfact * (float) (sptr [k]) ; + total += count ; + len -= readcount ; + if (count != readcount) + break ; + } ; + + return total ; +} /* vox_read_f */ + +static sf_count_t +vox_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) +{ IMA_OKI_ADPCM *pvox ; + BUF_UNION ubuf ; + short *sptr ; + int k, bufferlen, readcount, count ; + sf_count_t total = 0 ; + double normfact ; + + if (! psf->codec_data) + return 0 ; + pvox = (IMA_OKI_ADPCM*) psf->codec_data ; + + normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x8000) : 1.0 ; + + sptr = ubuf.sbuf ; + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + while (len > 0) + { readcount = (len >= bufferlen) ? bufferlen : (int) len ; + count = vox_read_block (psf, pvox, sptr, readcount) ; + for (k = 0 ; k < readcount ; k++) + ptr [total + k] = normfact * (double) (sptr [k]) ; + total += count ; + len -= readcount ; + if (count != readcount) + break ; + } ; + + return total ; +} /* vox_read_d */ + +/*------------------------------------------------------------------------------ +*/ + +static int +vox_write_block (SF_PRIVATE *psf, IMA_OKI_ADPCM *pvox, const short *ptr, int len) +{ int indx = 0, k ; + + while (indx < len) + { pvox->pcm_count = (len - indx > IMA_OKI_ADPCM_PCM_LEN) ? IMA_OKI_ADPCM_PCM_LEN : len - indx ; + + memcpy (pvox->pcm, &(ptr [indx]), pvox->pcm_count * sizeof (short)) ; + + ima_oki_adpcm_encode_block (pvox) ; + + if ((k = (int) psf_fwrite (pvox->codes, 1, pvox->code_count, psf)) != pvox->code_count) + psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", k, pvox->code_count) ; + + indx += pvox->pcm_count ; + } ; + + return indx ; +} /* vox_write_block */ + +static sf_count_t +vox_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len) +{ IMA_OKI_ADPCM *pvox ; + int writecount, count ; + sf_count_t total = 0 ; + + if (! psf->codec_data) + return 0 ; + pvox = (IMA_OKI_ADPCM*) psf->codec_data ; + + while (len) + { writecount = (len > 0x10000000) ? 0x10000000 : (int) len ; + + count = vox_write_block (psf, pvox, ptr, writecount) ; + + total += count ; + len -= count ; + if (count != writecount) + break ; + } ; + + return total ; +} /* vox_write_s */ + +static sf_count_t +vox_write_i (SF_PRIVATE *psf, const int *ptr, sf_count_t len) +{ IMA_OKI_ADPCM *pvox ; + BUF_UNION ubuf ; + short *sptr ; + int k, bufferlen, writecount, count ; + sf_count_t total = 0 ; + + if (! psf->codec_data) + return 0 ; + pvox = (IMA_OKI_ADPCM*) psf->codec_data ; + + sptr = ubuf.sbuf ; + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + while (len > 0) + { writecount = (len >= bufferlen) ? bufferlen : (int) len ; + for (k = 0 ; k < writecount ; k++) + sptr [k] = ptr [total + k] >> 16 ; + count = vox_write_block (psf, pvox, sptr, writecount) ; + total += count ; + len -= writecount ; + if (count != writecount) + break ; + } ; + + return total ; +} /* vox_write_i */ + +static sf_count_t +vox_write_f (SF_PRIVATE *psf, const float *ptr, sf_count_t len) +{ IMA_OKI_ADPCM *pvox ; + BUF_UNION ubuf ; + short *sptr ; + int k, bufferlen, writecount, count ; + sf_count_t total = 0 ; + float normfact ; + + if (! psf->codec_data) + return 0 ; + pvox = (IMA_OKI_ADPCM*) psf->codec_data ; + + normfact = (psf->norm_float == SF_TRUE) ? (1.0 * 0x7FFF) : 1.0 ; + + sptr = ubuf.sbuf ; + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + while (len > 0) + { writecount = (len >= bufferlen) ? bufferlen : (int) len ; + for (k = 0 ; k < writecount ; k++) + sptr [k] = psf_lrintf (normfact * ptr [total + k]) ; + count = vox_write_block (psf, pvox, sptr, writecount) ; + total += count ; + len -= writecount ; + if (count != writecount) + break ; + } ; + + return total ; +} /* vox_write_f */ + +static sf_count_t +vox_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) +{ IMA_OKI_ADPCM *pvox ; + BUF_UNION ubuf ; + short *sptr ; + int k, bufferlen, writecount, count ; + sf_count_t total = 0 ; + double normfact ; + + if (! psf->codec_data) + return 0 ; + pvox = (IMA_OKI_ADPCM*) psf->codec_data ; + + normfact = (psf->norm_double == SF_TRUE) ? (1.0 * 0x7FFF) : 1.0 ; + + sptr = ubuf.sbuf ; + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + while (len > 0) + { writecount = (len >= bufferlen) ? bufferlen : (int) len ; + for (k = 0 ; k < writecount ; k++) + sptr [k] = psf_lrint (normfact * ptr [total + k]) ; + count = vox_write_block (psf, pvox, sptr, writecount) ; + total += count ; + len -= writecount ; + if (count != writecount) + break ; + } ; + + return total ; +} /* vox_write_d */ + diff --git a/extern/libsndfile-modified/src/w64.c b/extern/libsndfile-modified/src/w64.c new file mode 100644 index 000000000..14346cd26 --- /dev/null +++ b/extern/libsndfile-modified/src/w64.c @@ -0,0 +1,640 @@ +/* +** Copyright (C) 1999-2018 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" +#include "wavlike.h" + +/*------------------------------------------------------------------------------ +** W64 files use 16 byte markers as opposed to the four byte marker of +** WAV files. +** For comparison purposes, an integer is required, so make an integer +** hash for the 16 bytes using MAKE_HASH16 macro, but also create a 16 +** byte array containing the complete 16 bytes required when writing the +** header. +*/ + +#define MAKE_HASH16(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, xa, xb, xc, xd, xe, xf) \ + ( (x0) ^ ((x1) << 1) ^ ((x2) << 2) ^ ((x3) << 3) ^ \ + ((x4) << 4) ^ ((x5) << 5) ^ ((x6) << 6) ^ ((x7) << 7) ^ \ + ((x8) << 8) ^ ((x9) << 9) ^ ((xa) << 10) ^ ((xb) << 11) ^ \ + ((xc) << 12) ^ ((xd) << 13) ^ ((xe) << 14) ^ ((xf) << 15) ) + +#define MAKE_MARKER16(name, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, xa, xb, xc, xd, xe, xf) \ + static unsigned char name [16] = { (x0), (x1), (x2), (x3), (x4), (x5), \ + (x6), (x7), (x8), (x9), (xa), (xb), (xc), (xd), (xe), (xf) } + +#define riff_HASH16 MAKE_HASH16 ('r', 'i', 'f', 'f', 0x2E, 0x91, 0xCF, 0x11, \ + 0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00) + +#define wave_HASH16 MAKE_HASH16 ('w', 'a', 'v', 'e', 0xF3, 0xAC, 0xD3, 0x11, \ + 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A) + +#define fmt_HASH16 MAKE_HASH16 ('f', 'm', 't', ' ', 0xF3, 0xAC, 0xD3, 0x11, \ + 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A) + +#define fact_HASH16 MAKE_HASH16 ('f', 'a', 'c', 't', 0xF3, 0xAC, 0xD3, 0x11, \ + 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A) + +#define data_HASH16 MAKE_HASH16 ('d', 'a', 't', 'a', 0xF3, 0xAC, 0xD3, 0x11, \ + 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A) + +#define ACID_HASH16 MAKE_HASH16 (0x6D, 0x07, 0x1C, 0xEA, 0xA3, 0xEF, 0x78, 0x4C, \ + 0x90, 0x57, 0x7F, 0x79, 0xEE, 0x25, 0x2A, 0xAE) + +#define levl_HASH16 MAKE_HASH16 (0x6c, 0x65, 0x76, 0x6c, 0xf3, 0xac, 0xd3, 0x11, \ + 0xd1, 0x8c, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A) + +#define list_HASH16 MAKE_HASH16 (0x6C, 0x69, 0x73, 0x74, 0x2F, 0x91, 0xCF, 0x11, \ + 0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00) + +#define junk_HASH16 MAKE_HASH16 (0x6A, 0x75, 0x6E, 0x6b, 0xF3, 0xAC, 0xD3, 0x11, \ + 0x8C, 0xD1, 0x00, 0xC0, 0x4f, 0x8E, 0xDB, 0x8A) + +#define bext_HASH16 MAKE_HASH16 (0x62, 0x65, 0x78, 0x74, 0xf3, 0xac, 0xd3, 0xaa, \ + 0xd1, 0x8c, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A) + +#define MARKER_HASH16 MAKE_HASH16 (0x56, 0x62, 0xf7, 0xab, 0x2d, 0x39, 0xd2, 0x11, \ + 0x86, 0xc7, 0x00, 0xc0, 0x4f, 0x8e, 0xdb, 0x8a) + +#define SUMLIST_HASH16 MAKE_HASH16 (0xBC, 0x94, 0x5F, 0x92, 0x5A, 0x52, 0xD2, 0x11, \ + 0x86, 0xDC, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A) + + +MAKE_MARKER16 (riff_MARKER16, 'r', 'i', 'f', 'f', 0x2E, 0x91, 0xCF, 0x11, + 0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00) ; + + +MAKE_MARKER16 (wave_MARKER16, 'w', 'a', 'v', 'e', 0xF3, 0xAC, 0xD3, 0x11, + 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A) ; + +MAKE_MARKER16 (fmt_MARKER16, 'f', 'm', 't', ' ', 0xF3, 0xAC, 0xD3, 0x11, + 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A) ; + +MAKE_MARKER16 (fact_MARKER16, 'f', 'a', 'c', 't', 0xF3, 0xAC, 0xD3, 0x11, + 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A) ; + +MAKE_MARKER16 (data_MARKER16, 'd', 'a', 't', 'a', 0xF3, 0xAC, 0xD3, 0x11, + 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A) ; + +enum +{ HAVE_riff = 0x01, + HAVE_wave = 0x02, + HAVE_fmt = 0x04, + HAVE_fact = 0x08, + HAVE_data = 0x20 +} ; + +/*------------------------------------------------------------------------------ + * Private static functions. + */ + +static int w64_read_header (SF_PRIVATE *psf, int *blockalign, int *framesperblock) ; +static int w64_write_header (SF_PRIVATE *psf, int calc_length) ; +static int w64_close (SF_PRIVATE *psf) ; + +/*------------------------------------------------------------------------------ +** Public function. +*/ + +int +w64_open (SF_PRIVATE *psf) +{ WAVLIKE_PRIVATE * wpriv ; + int subformat, error, blockalign = 0, framesperblock = 0 ; + + if ((wpriv = calloc (1, sizeof (WAVLIKE_PRIVATE))) == NULL) + return SFE_MALLOC_FAILED ; + psf->container_data = wpriv ; + + if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR &&psf->filelength > 0)) + { if ((error = w64_read_header (psf, &blockalign, &framesperblock))) + return error ; + } ; + + if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_W64) + return SFE_BAD_OPEN_FORMAT ; + + subformat = SF_CODEC (psf->sf.format) ; + + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { if (psf->is_pipe) + return SFE_NO_PIPE_WRITE ; + + psf->endian = SF_ENDIAN_LITTLE ; /* All W64 files are little endian. */ + + psf->blockwidth = psf->bytewidth * psf->sf.channels ; + + if (subformat == SF_FORMAT_IMA_ADPCM || subformat == SF_FORMAT_MS_ADPCM) + { blockalign = wavlike_srate2blocksize (psf->sf.samplerate * psf->sf.channels) ; + framesperblock = -1 ; + + /* + ** At this point we don't know the file length so set it stupidly high, but not + ** so high that it triggers undefined behaviour whan something is added to it. + */ + psf->filelength = SF_COUNT_MAX - 10000 ; + psf->datalength = psf->filelength ; + if (psf->sf.frames <= 0) + psf->sf.frames = (psf->blockwidth) ? psf->filelength / psf->blockwidth : psf->filelength ; + } ; + + if ((error = w64_write_header (psf, SF_FALSE))) + return error ; + + psf->write_header = w64_write_header ; + } ; + + psf->container_close = w64_close ; + + switch (subformat) + { case SF_FORMAT_PCM_U8 : + error = pcm_init (psf) ; + break ; + + case SF_FORMAT_PCM_16 : + case SF_FORMAT_PCM_24 : + case SF_FORMAT_PCM_32 : + error = pcm_init (psf) ; + break ; + + case SF_FORMAT_ULAW : + error = ulaw_init (psf) ; + break ; + + case SF_FORMAT_ALAW : + error = alaw_init (psf) ; + break ; + + /* Lite remove start */ + case SF_FORMAT_FLOAT : + error = float32_init (psf) ; + break ; + + case SF_FORMAT_DOUBLE : + error = double64_init (psf) ; + break ; + + case SF_FORMAT_IMA_ADPCM : + error = wavlike_ima_init (psf, blockalign, framesperblock) ; + break ; + + case SF_FORMAT_MS_ADPCM : + error = wavlike_msadpcm_init (psf, blockalign, framesperblock) ; + break ; + /* Lite remove end */ + + case SF_FORMAT_GSM610 : + error = gsm610_init (psf) ; + break ; + + default : return SFE_UNIMPLEMENTED ; + } ; + + return error ; +} /* w64_open */ + +/*========================================================================= +** Private functions. +*/ + +static int +w64_read_header (SF_PRIVATE *psf, int *blockalign, int *framesperblock) +{ WAVLIKE_PRIVATE *wpriv ; + WAV_FMT *wav_fmt ; + int dword = 0, marker, format = 0 ; + sf_count_t chunk_size, bytesread = 0 ; + int parsestage = 0, error, done = 0 ; + + if ((wpriv = psf->container_data) == NULL) + return SFE_INTERNAL ; + wav_fmt = &wpriv->wav_fmt ; + + /* Set position to start of file to begin reading header. */ + psf_binheader_readf (psf, "p", 0) ; + + while (! done) + { /* Each new chunk must start on an 8 byte boundary, so jump if needed. */ + if (psf->header.indx & 0x7) + psf_binheader_readf (psf, "j", 8 - (psf->header.indx & 0x7)) ; + + /* Generate hash of 16 byte marker. */ + marker = 0 ; + chunk_size = 0 ; + + bytesread = psf_binheader_readf (psf, "eh8", &marker, &chunk_size) ; + if (bytesread == 0) + break ; + switch (marker) + { case riff_HASH16 : + if (parsestage) + return SFE_W64_NO_RIFF ; + + if (psf->filelength != chunk_size) + psf_log_printf (psf, "riff : %D (should be %D)\n", chunk_size, psf->filelength) ; + else + psf_log_printf (psf, "riff : %D\n", chunk_size) ; + + parsestage |= HAVE_riff ; + + bytesread += psf_binheader_readf (psf, "h", &marker) ; + if (marker == wave_HASH16) + { if ((parsestage & HAVE_riff) != HAVE_riff) + return SFE_W64_NO_WAVE ; + psf_log_printf (psf, "wave\n") ; + parsestage |= HAVE_wave ; + } ; + chunk_size = 0 ; + break ; + + case ACID_HASH16: + psf_log_printf (psf, "Looks like an ACID file. Exiting.\n") ; + return SFE_UNIMPLEMENTED ; + + case fmt_HASH16 : + if ((parsestage & (HAVE_riff | HAVE_wave)) != (HAVE_riff | HAVE_wave)) + return SFE_WAV_NO_FMT ; + + psf_log_printf (psf, " fmt : %D\n", chunk_size) ; + + /* size of 16 byte marker and 8 byte chunk_size value. */ + chunk_size -= 24 ; + + if ((error = wavlike_read_fmt_chunk (psf, (int) chunk_size))) + return error ; + + if (chunk_size % 8) + psf_binheader_readf (psf, "j", 8 - (chunk_size % 8)) ; + + format = wav_fmt->format ; + parsestage |= HAVE_fmt ; + chunk_size = 0 ; + break ; + + case fact_HASH16: + { sf_count_t frames ; + + psf_binheader_readf (psf, "e8", &frames) ; + psf_log_printf (psf, "fact : %D\n frames : %D\n", + chunk_size, frames) ; + } ; + chunk_size = 0 ; + break ; + + + case data_HASH16 : + if ((parsestage & (HAVE_riff | HAVE_wave | HAVE_fmt)) != (HAVE_riff | HAVE_wave | HAVE_fmt)) + return SFE_W64_NO_DATA ; + + psf->dataoffset = psf_ftell (psf) ; + psf->datalength = SF_MIN (chunk_size - 24, psf->filelength - psf->dataoffset) ; + + if (chunk_size % 8) + chunk_size += 8 - (chunk_size % 8) ; + + psf_log_printf (psf, "data : %D\n", chunk_size) ; + + parsestage |= HAVE_data ; + + if (! psf->sf.seekable) + break ; + + /* Seek past data and continue reading header. */ + psf_fseek (psf, chunk_size, SEEK_CUR) ; + chunk_size = 0 ; + break ; + + case levl_HASH16 : + psf_log_printf (psf, "levl : %D\n", chunk_size) ; + break ; + + case list_HASH16 : + psf_log_printf (psf, "list : %D\n", chunk_size) ; + break ; + + case junk_HASH16 : + psf_log_printf (psf, "junk : %D\n", chunk_size) ; + break ; + + case bext_HASH16 : + psf_log_printf (psf, "bext : %D\n", chunk_size) ; + break ; + + case MARKER_HASH16 : + psf_log_printf (psf, "marker : %D\n", chunk_size) ; + break ; + + case SUMLIST_HASH16 : + psf_log_printf (psf, "summary list : %D\n", chunk_size) ; + break ; + + default : + psf_log_printf (psf, "*** Unknown chunk marker (%X) at position %D with length %D. Skipping and continuing.\n", marker, psf_ftell (psf) - 8, chunk_size) ; + break ; + } ; /* switch (dword) */ + + if (chunk_size >= psf->filelength) + { psf_log_printf (psf, "*** Chunk size %u > file length %D. Exiting parser.\n", chunk_size, psf->filelength) ; + break ; + } ; + + if (psf->sf.seekable == 0 && (parsestage & HAVE_data)) + break ; + + if (psf_ftell (psf) >= (psf->filelength - (2 * SIGNED_SIZEOF (dword)))) + break ; + + if (chunk_size > 0 && chunk_size < 0xffff0000) + { dword = chunk_size ; + psf_binheader_readf (psf, "j", dword - 24) ; + } ; + } ; /* while (1) */ + + if (psf->dataoffset <= 0) + return SFE_W64_NO_DATA ; + + if (psf->sf.channels < 1) + return SFE_CHANNEL_COUNT_ZERO ; + + if (psf->sf.channels > SF_MAX_CHANNELS) + return SFE_CHANNEL_COUNT ; + + psf->endian = SF_ENDIAN_LITTLE ; /* All W64 files are little endian. */ + + if (psf_ftell (psf) != psf->dataoffset) + psf_fseek (psf, psf->dataoffset, SEEK_SET) ; + + if (psf->blockwidth) + { if (psf->filelength - psf->dataoffset < psf->datalength) + psf->sf.frames = (psf->filelength - psf->dataoffset) / psf->blockwidth ; + else + psf->sf.frames = psf->datalength / psf->blockwidth ; + } ; + + switch (format) + { case WAVE_FORMAT_PCM : + case WAVE_FORMAT_EXTENSIBLE : + /* extensible might be FLOAT, MULAW, etc as well! */ + psf->sf.format = SF_FORMAT_W64 | u_bitwidth_to_subformat (psf->bytewidth * 8) ; + break ; + + case WAVE_FORMAT_MULAW : + psf->sf.format = (SF_FORMAT_W64 | SF_FORMAT_ULAW) ; + break ; + + case WAVE_FORMAT_ALAW : + psf->sf.format = (SF_FORMAT_W64 | SF_FORMAT_ALAW) ; + break ; + + case WAVE_FORMAT_MS_ADPCM : + psf->sf.format = (SF_FORMAT_W64 | SF_FORMAT_MS_ADPCM) ; + *blockalign = wav_fmt->msadpcm.blockalign ; + *framesperblock = wav_fmt->msadpcm.samplesperblock ; + break ; + + case WAVE_FORMAT_IMA_ADPCM : + psf->sf.format = (SF_FORMAT_W64 | SF_FORMAT_IMA_ADPCM) ; + *blockalign = wav_fmt->ima.blockalign ; + *framesperblock = wav_fmt->ima.samplesperblock ; + break ; + + case WAVE_FORMAT_GSM610 : + psf->sf.format = (SF_FORMAT_W64 | SF_FORMAT_GSM610) ; + break ; + + case WAVE_FORMAT_IEEE_FLOAT : + psf->sf.format = SF_FORMAT_W64 ; + psf->sf.format |= (psf->bytewidth == 8) ? SF_FORMAT_DOUBLE : SF_FORMAT_FLOAT ; + break ; + + default : return SFE_UNIMPLEMENTED ; + } ; + + return 0 ; +} /* w64_read_header */ + +static int +w64_write_header (SF_PRIVATE *psf, int calc_length) +{ sf_count_t fmt_size, current ; + size_t fmt_pad = 0 ; + int subformat, add_fact_chunk = SF_FALSE ; + + current = psf_ftell (psf) ; + + if (calc_length) + { psf->filelength = psf_get_filelen (psf) ; + + psf->datalength = psf->filelength - psf->dataoffset ; + if (psf->dataend) + psf->datalength -= psf->filelength - psf->dataend ; + + if (psf->bytewidth) + psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ; + } ; + + /* Reset the current header length to zero. */ + psf->header.ptr [0] = 0 ; + psf->header.indx = 0 ; + psf_fseek (psf, 0, SEEK_SET) ; + + /* riff marker, length, wave and 'fmt ' markers. */ + psf_binheader_writef (psf, "eh8hh", BHWh (riff_MARKER16), BHW8 (psf->filelength), BHWh (wave_MARKER16), BHWh (fmt_MARKER16)) ; + + subformat = SF_CODEC (psf->sf.format) ; + + switch (subformat) + { case SF_FORMAT_PCM_U8 : + case SF_FORMAT_PCM_16 : + case SF_FORMAT_PCM_24 : + case SF_FORMAT_PCM_32 : + fmt_size = 24 + 2 + 2 + 4 + 4 + 2 + 2 ; + fmt_pad = (size_t) ((fmt_size & 0x7) ? 8 - (fmt_size & 0x7) : 0) ; + fmt_size += fmt_pad ; + + /* fmt : format, channels, samplerate */ + psf_binheader_writef (psf, "e8224", BHW8 (fmt_size), BHW2 (WAVE_FORMAT_PCM), BHW2 (psf->sf.channels), BHW4 (psf->sf.samplerate)) ; + /* fmt : bytespersec */ + psf_binheader_writef (psf, "e4", BHW4 (psf->sf.samplerate * psf->bytewidth * psf->sf.channels)) ; + /* fmt : blockalign, bitwidth */ + psf_binheader_writef (psf, "e22", BHW2 (psf->bytewidth * psf->sf.channels), BHW2 (psf->bytewidth * 8)) ; + break ; + + case SF_FORMAT_FLOAT : + case SF_FORMAT_DOUBLE : + fmt_size = 24 + 2 + 2 + 4 + 4 + 2 + 2 ; + fmt_pad = (size_t) ((fmt_size & 0x7) ? 8 - (fmt_size & 0x7) : 0) ; + fmt_size += fmt_pad ; + + /* fmt : format, channels, samplerate */ + psf_binheader_writef (psf, "e8224", BHW8 (fmt_size), BHW2 (WAVE_FORMAT_IEEE_FLOAT), BHW2 (psf->sf.channels), BHW4 (psf->sf.samplerate)) ; + /* fmt : bytespersec */ + psf_binheader_writef (psf, "e4", BHW4 (psf->sf.samplerate * psf->bytewidth * psf->sf.channels)) ; + /* fmt : blockalign, bitwidth */ + psf_binheader_writef (psf, "e22", BHW2 (psf->bytewidth * psf->sf.channels), BHW2 (psf->bytewidth * 8)) ; + + add_fact_chunk = SF_TRUE ; + break ; + + case SF_FORMAT_ULAW : + fmt_size = 24 + 2 + 2 + 4 + 4 + 2 + 2 ; + fmt_pad = (size_t) ((fmt_size & 0x7) ? 8 - (fmt_size & 0x7) : 0) ; + fmt_size += fmt_pad ; + + /* fmt : format, channels, samplerate */ + psf_binheader_writef (psf, "e8224", BHW8 (fmt_size), BHW2 (WAVE_FORMAT_MULAW), BHW2 (psf->sf.channels), BHW4 (psf->sf.samplerate)) ; + /* fmt : bytespersec */ + psf_binheader_writef (psf, "e4", BHW4 (psf->sf.samplerate * psf->bytewidth * psf->sf.channels)) ; + /* fmt : blockalign, bitwidth */ + psf_binheader_writef (psf, "e22", BHW2 (psf->bytewidth * psf->sf.channels), BHW2 (8)) ; + + add_fact_chunk = SF_TRUE ; + break ; + + case SF_FORMAT_ALAW : + fmt_size = 24 + 2 + 2 + 4 + 4 + 2 + 2 ; + fmt_pad = (size_t) ((fmt_size & 0x7) ? 8 - (fmt_size & 0x7) : 0) ; + fmt_size += fmt_pad ; + + /* fmt : format, channels, samplerate */ + psf_binheader_writef (psf, "e8224", BHW8 (fmt_size), BHW2 (WAVE_FORMAT_ALAW), BHW2 (psf->sf.channels), BHW4 (psf->sf.samplerate)) ; + /* fmt : bytespersec */ + psf_binheader_writef (psf, "e4", BHW4 (psf->sf.samplerate * psf->bytewidth * psf->sf.channels)) ; + /* fmt : blockalign, bitwidth */ + psf_binheader_writef (psf, "e22", BHW2 (psf->bytewidth * psf->sf.channels), BHW2 (8)) ; + + add_fact_chunk = SF_TRUE ; + break ; + + /* Lite remove start */ + case SF_FORMAT_IMA_ADPCM : + { int blockalign, framesperblock, bytespersec ; + + blockalign = wavlike_srate2blocksize (psf->sf.samplerate * psf->sf.channels) ; + framesperblock = 2 * (blockalign - 4 * psf->sf.channels) / psf->sf.channels + 1 ; + bytespersec = (psf->sf.samplerate * blockalign) / framesperblock ; + + /* fmt chunk. */ + fmt_size = 24 + 2 + 2 + 4 + 4 + 2 + 2 + 2 + 2 ; + fmt_pad = (size_t) ((fmt_size & 0x7) ? 8 - (fmt_size & 0x7) : 0) ; + fmt_size += fmt_pad ; + + /* fmt : size, WAV format type, channels. */ + psf_binheader_writef (psf, "e822", BHW8 (fmt_size), BHW2 (WAVE_FORMAT_IMA_ADPCM), BHW2 (psf->sf.channels)) ; + + /* fmt : samplerate, bytespersec. */ + psf_binheader_writef (psf, "e44", BHW4 (psf->sf.samplerate), BHW4 (bytespersec)) ; + + /* fmt : blockalign, bitwidth, extrabytes, framesperblock. */ + psf_binheader_writef (psf, "e2222", BHW2 (blockalign), BHW2 (4), BHW2 (2), BHW2 (framesperblock)) ; + } ; + + add_fact_chunk = SF_TRUE ; + break ; + + case SF_FORMAT_MS_ADPCM : + { int blockalign, framesperblock, bytespersec, extrabytes ; + + blockalign = wavlike_srate2blocksize (psf->sf.samplerate * psf->sf.channels) ; + framesperblock = 2 + 2 * (blockalign - 7 * psf->sf.channels) / psf->sf.channels ; + bytespersec = (psf->sf.samplerate * blockalign) / framesperblock ; + + /* fmt chunk. */ + extrabytes = 2 + 2 + WAVLIKE_MSADPCM_ADAPT_COEFF_COUNT * (2 + 2) ; + fmt_size = 24 + 2 + 2 + 4 + 4 + 2 + 2 + 2 + extrabytes ; + fmt_pad = (size_t) ((fmt_size & 0x7) ? 8 - (fmt_size & 0x7) : 0) ; + fmt_size += fmt_pad ; + + /* fmt : size, W64 format type, channels. */ + psf_binheader_writef (psf, "e822", BHW8 (fmt_size), BHW2 (WAVE_FORMAT_MS_ADPCM), BHW2 (psf->sf.channels)) ; + + /* fmt : samplerate, bytespersec. */ + psf_binheader_writef (psf, "e44", BHW4 (psf->sf.samplerate), BHW4 (bytespersec)) ; + + /* fmt : blockalign, bitwidth, extrabytes, framesperblock. */ + psf_binheader_writef (psf, "e22222", BHW2 (blockalign), BHW2 (4), BHW2 (extrabytes), BHW2 (framesperblock), BHW2 (7)) ; + + wavlike_msadpcm_write_adapt_coeffs (psf) ; + } ; + + add_fact_chunk = SF_TRUE ; + break ; + /* Lite remove end */ + + case SF_FORMAT_GSM610 : + { int bytespersec ; + + bytespersec = (psf->sf.samplerate * WAVLIKE_GSM610_BLOCKSIZE) / WAVLIKE_GSM610_SAMPLES ; + + /* fmt chunk. */ + fmt_size = 24 + 2 + 2 + 4 + 4 + 2 + 2 + 2 + 2 ; + fmt_pad = (size_t) ((fmt_size & 0x7) ? 8 - (fmt_size & 0x7) : 0) ; + fmt_size += fmt_pad ; + + /* fmt : size, WAV format type, channels. */ + psf_binheader_writef (psf, "e822", BHW8 (fmt_size), BHW2 (WAVE_FORMAT_GSM610), BHW2 (psf->sf.channels)) ; + + /* fmt : samplerate, bytespersec. */ + psf_binheader_writef (psf, "e44", BHW4 (psf->sf.samplerate), BHW4 (bytespersec)) ; + + /* fmt : blockalign, bitwidth, extrabytes, framesperblock. */ + psf_binheader_writef (psf, "e2222", BHW2 (WAVLIKE_GSM610_BLOCKSIZE), BHW2 (0), BHW2 (2), BHW2 (WAVLIKE_GSM610_SAMPLES)) ; + } ; + + add_fact_chunk = SF_TRUE ; + break ; + + default : return SFE_UNIMPLEMENTED ; + } ; + + /* Pad to 8 bytes with zeros. */ + if (fmt_pad > 0) + psf_binheader_writef (psf, "z", BHWz (fmt_pad)) ; + + if (add_fact_chunk) + psf_binheader_writef (psf, "eh88", BHWh (fact_MARKER16), BHW8 ((sf_count_t) (16 + 8 + 8)), BHW8 (psf->sf.frames)) ; + + psf_binheader_writef (psf, "eh8", BHWh (data_MARKER16), BHW8 (psf->datalength + 24)) ; + psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ; + + if (psf->error) + return psf->error ; + + psf->dataoffset = psf->header.indx ; + + if (current > 0) + psf_fseek (psf, current, SEEK_SET) ; + + return psf->error ; +} /* w64_write_header */ + +static int +w64_close (SF_PRIVATE *psf) +{ + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + w64_write_header (psf, SF_TRUE) ; + + return 0 ; +} /* w64_close */ + diff --git a/extern/libsndfile-modified/src/wav.c b/extern/libsndfile-modified/src/wav.c new file mode 100644 index 000000000..b87068695 --- /dev/null +++ b/extern/libsndfile-modified/src/wav.c @@ -0,0 +1,1653 @@ +/* +** Copyright (C) 1999-2019 Erik de Castro Lopo +** Copyright (C) 2004-2005 David Viens +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" +#include "wavlike.h" + +/*------------------------------------------------------------------------------ + * Macros to handle big/little endian issues. + */ + +#define RIFF_MARKER (MAKE_MARKER ('R', 'I', 'F', 'F')) +#define RIFX_MARKER (MAKE_MARKER ('R', 'I', 'F', 'X')) +#define WAVE_MARKER (MAKE_MARKER ('W', 'A', 'V', 'E')) +#define fmt_MARKER (MAKE_MARKER ('f', 'm', 't', ' ')) +#define fact_MARKER (MAKE_MARKER ('f', 'a', 'c', 't')) + +#define cue_MARKER (MAKE_MARKER ('c', 'u', 'e', ' ')) +#define slnt_MARKER (MAKE_MARKER ('s', 'l', 'n', 't')) +#define wavl_MARKER (MAKE_MARKER ('w', 'a', 'v', 'l')) +#define plst_MARKER (MAKE_MARKER ('p', 'l', 's', 't')) +#define smpl_MARKER (MAKE_MARKER ('s', 'm', 'p', 'l')) +#define iXML_MARKER (MAKE_MARKER ('i', 'X', 'M', 'L')) +#define levl_MARKER (MAKE_MARKER ('l', 'e', 'v', 'l')) +#define MEXT_MARKER (MAKE_MARKER ('M', 'E', 'X', 'T')) +#define acid_MARKER (MAKE_MARKER ('a', 'c', 'i', 'd')) +#define strc_MARKER (MAKE_MARKER ('s', 't', 'r', 'c')) +#define afsp_MARKER (MAKE_MARKER ('a', 'f', 's', 'p')) +#define clm_MARKER (MAKE_MARKER ('c', 'l', 'm', ' ')) +#define elmo_MARKER (MAKE_MARKER ('e', 'l', 'm', 'o')) +#define FLLR_MARKER (MAKE_MARKER ('F', 'L', 'L', 'R')) + +#define minf_MARKER (MAKE_MARKER ('m', 'i', 'n', 'f')) +#define elm1_MARKER (MAKE_MARKER ('e', 'l', 'm', '1')) +#define regn_MARKER (MAKE_MARKER ('r', 'e', 'g', 'n')) +#define ovwf_MARKER (MAKE_MARKER ('o', 'v', 'w', 'f')) +#define umid_MARKER (MAKE_MARKER ('u', 'm', 'i', 'd')) +#define SyLp_MARKER (MAKE_MARKER ('S', 'y', 'L', 'p')) +#define Cr8r_MARKER (MAKE_MARKER ('C', 'r', '8', 'r')) +#define JUNK_MARKER (MAKE_MARKER ('J', 'U', 'N', 'K')) +#define PMX_MARKER (MAKE_MARKER ('_', 'P', 'M', 'X')) +#define inst_MARKER (MAKE_MARKER ('i', 'n', 's', 't')) +#define AFAn_MARKER (MAKE_MARKER ('A', 'F', 'A', 'n')) + + +/* Weird WAVPACK marker which can show up at the start of the DATA section. */ +#define wvpk_MARKER (MAKE_MARKER ('w', 'v', 'p', 'k')) +#define OggS_MARKER (MAKE_MARKER ('O', 'g', 'g', 'S')) + +/* ID3v1 trailer which can show up at the end and erronerously look like a chunk. */ +#define TAG__MARKER (MAKE_MARKER ('T', 'A', 'G', 0)) +#define TAG__MARKER_MASK (MAKE_MARKER (0xff, 0xff, 0xff, 0)) + +#define WAVLIKE_PEAK_CHUNK_SIZE(ch) (2 * sizeof (int) + ch * (sizeof (float) + sizeof (int))) + + +enum +{ HAVE_RIFF = 1 << 0, + HAVE_WAVE = 1 << 1, + HAVE_fmt = 1 << 2, + HAVE_fact = 1 << 3, + HAVE_PEAK = 1 << 4, + HAVE_data = 1 << 5, + HAVE_other = 1 << 6 +} ; + + +/* known WAVEFORMATEXTENSIBLE GUIDS */ +static const EXT_SUBFORMAT MSGUID_SUBTYPE_PCM = +{ 0x00000001, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } +} ; + +#if 0 +static const EXT_SUBFORMAT MSGUID_SUBTYPE_MS_ADPCM = +{ 0x00000002, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } +} ; +#endif + +static const EXT_SUBFORMAT MSGUID_SUBTYPE_IEEE_FLOAT = +{ 0x00000003, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } +} ; + +static const EXT_SUBFORMAT MSGUID_SUBTYPE_ALAW = +{ 0x00000006, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } +} ; + +static const EXT_SUBFORMAT MSGUID_SUBTYPE_MULAW = +{ 0x00000007, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } +} ; + +/* +** the next two are from +** http://dream.cs.bath.ac.uk/researchdev/wave-ex/bformat.html +*/ +static const EXT_SUBFORMAT MSGUID_SUBTYPE_AMBISONIC_B_FORMAT_PCM = +{ 0x00000001, 0x0721, 0x11d3, { 0x86, 0x44, 0xC8, 0xC1, 0xCA, 0x00, 0x00, 0x00 } +} ; + +static const EXT_SUBFORMAT MSGUID_SUBTYPE_AMBISONIC_B_FORMAT_IEEE_FLOAT = +{ 0x00000003, 0x0721, 0x11d3, { 0x86, 0x44, 0xC8, 0xC1, 0xCA, 0x00, 0x00, 0x00 } +} ; + + +#if 0 +/* maybe interesting one day to read the following through sf_read_raw */ +/* http://www.bath.ac.uk/~masrwd/pvocex/pvocex.html */ +static const EXT_SUBFORMAT MSGUID_SUBTYPE_PVOCEX = +{ 0x8312B9C2, 0x2E6E, 0x11d4, { 0xA8, 0x24, 0xDE, 0x5B, 0x96, 0xC3, 0xAB, 0x21 } +} ; +#endif + +/*------------------------------------------------------------------------------ +** Private static functions. +*/ + +static int wav_read_header (SF_PRIVATE *psf, int *blockalign, int *framesperblock) ; +static int wav_write_header (SF_PRIVATE *psf, int calc_length) ; + +static int wav_write_tailer (SF_PRIVATE *psf) ; +static int wav_command (SF_PRIVATE *psf, int command, void *data, int datasize) ; +static int wav_close (SF_PRIVATE *psf) ; + +static int wav_read_smpl_chunk (SF_PRIVATE *psf, uint32_t chunklen) ; +static int wav_read_acid_chunk (SF_PRIVATE *psf, uint32_t chunklen) ; + +static int wav_set_chunk (SF_PRIVATE *psf, const SF_CHUNK_INFO * chunk_info) ; +static SF_CHUNK_ITERATOR * wav_next_chunk_iterator (SF_PRIVATE *psf, SF_CHUNK_ITERATOR * iterator) ; +static int wav_get_chunk_size (SF_PRIVATE *psf, const SF_CHUNK_ITERATOR * iterator, SF_CHUNK_INFO * chunk_info) ; +static int wav_get_chunk_data (SF_PRIVATE *psf, const SF_CHUNK_ITERATOR * iterator, SF_CHUNK_INFO * chunk_info) ; + +/*------------------------------------------------------------------------------ +** Public function. +*/ + +int +wav_open (SF_PRIVATE *psf) +{ WAVLIKE_PRIVATE * wpriv ; + int format, subformat, error, blockalign = 0, framesperblock = 0 ; + + if ((wpriv = calloc (1, sizeof (WAVLIKE_PRIVATE))) == NULL) + return SFE_MALLOC_FAILED ; + psf->container_data = wpriv ; + + wpriv->wavex_ambisonic = SF_AMBISONIC_NONE ; + psf->strings.flags = SF_STR_ALLOW_START | SF_STR_ALLOW_END ; + + if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0)) + { if ((error = wav_read_header (psf, &blockalign, &framesperblock))) + return error ; + + psf->next_chunk_iterator = wav_next_chunk_iterator ; + psf->get_chunk_size = wav_get_chunk_size ; + psf->get_chunk_data = wav_get_chunk_data ; + } ; + + subformat = SF_CODEC (psf->sf.format) ; + + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { if (psf->is_pipe) + return SFE_NO_PIPE_WRITE ; + + wpriv->wavex_ambisonic = SF_AMBISONIC_NONE ; + + format = SF_CONTAINER (psf->sf.format) ; + if (format != SF_FORMAT_WAV && format != SF_FORMAT_WAVEX) + return SFE_BAD_OPEN_FORMAT ; + + psf->blockwidth = psf->bytewidth * psf->sf.channels ; + + /* RIFF WAVs are little-endian, RIFX WAVs are big-endian, default to little */ + psf->endian = SF_ENDIAN (psf->sf.format) ; + if (CPU_IS_BIG_ENDIAN && psf->endian == SF_ENDIAN_CPU) + psf->endian = SF_ENDIAN_BIG ; + else if (psf->endian != SF_ENDIAN_BIG) + psf->endian = SF_ENDIAN_LITTLE ; + + if (psf->file.mode != SFM_RDWR || psf->filelength < 44) + { psf->filelength = 0 ; + psf->datalength = 0 ; + psf->dataoffset = 0 ; + psf->sf.frames = 0 ; + } ; + +#if (ENABLE_EXPERIMENTAL_CODE == 0) + /* For now, don't support writing MPEGLAYER3 WAVs, as we can't guarentee that + ** such a file written by libsndfile would have the same length when opened again. + */ + if (subformat == SF_FORMAT_MPEG_LAYER_III) + return SFE_UNSUPPORTED_ENCODING ; +#endif + + if (subformat == SF_FORMAT_IMA_ADPCM || subformat == SF_FORMAT_MS_ADPCM) + { blockalign = wavlike_srate2blocksize (psf->sf.samplerate * psf->sf.channels) ; + framesperblock = -1 ; /* Corrected later. */ + } ; + + /* By default, add the peak chunk to floating point files. Default behaviour + ** can be switched off using sf_command (SFC_SET_PEAK_CHUNK, SF_FALSE). + */ + if (psf->file.mode == SFM_WRITE && (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE)) + { if ((psf->peak_info = peak_info_calloc (psf->sf.channels)) == NULL) + return SFE_MALLOC_FAILED ; + psf->peak_info->peak_loc = SF_PEAK_START ; + } ; + + psf->write_header = wav_write_header ; + psf->set_chunk = wav_set_chunk ; + } ; + + psf->container_close = wav_close ; + psf->command = wav_command ; + + switch (subformat) + { case SF_FORMAT_PCM_U8 : + case SF_FORMAT_PCM_16 : + case SF_FORMAT_PCM_24 : + case SF_FORMAT_PCM_32 : + error = pcm_init (psf) ; + break ; + + case SF_FORMAT_ULAW : + error = ulaw_init (psf) ; + break ; + + case SF_FORMAT_ALAW : + error = alaw_init (psf) ; + break ; + + /* Lite remove start */ + case SF_FORMAT_FLOAT : + error = float32_init (psf) ; + break ; + + case SF_FORMAT_DOUBLE : + error = double64_init (psf) ; + break ; + + case SF_FORMAT_IMA_ADPCM : + error = wavlike_ima_init (psf, blockalign, framesperblock) ; + break ; + + case SF_FORMAT_MS_ADPCM : + error = wavlike_msadpcm_init (psf, blockalign, framesperblock) ; + break ; + + case SF_FORMAT_G721_32 : + error = g72x_init (psf) ; + break ; + + case SF_FORMAT_NMS_ADPCM_16 : + case SF_FORMAT_NMS_ADPCM_24 : + case SF_FORMAT_NMS_ADPCM_32 : + error = nms_adpcm_init (psf) ; + break ; + + /* Lite remove end */ + + case SF_FORMAT_GSM610 : + error = gsm610_init (psf) ; + break ; + + case SF_FORMAT_MPEG_LAYER_III : + error = mpeg_init (psf, SF_BITRATE_MODE_CONSTANT, SF_FALSE) ; + break ; + + default : return SFE_UNIMPLEMENTED ; + } ; + + if (psf->file.mode == SFM_WRITE || (psf->file.mode == SFM_RDWR && psf->filelength == 0)) + return psf->write_header (psf, SF_FALSE) ; + + return error ; +} /* wav_open */ + +/*========================================================================= +** Private functions. +*/ + +static int +wav_read_header (SF_PRIVATE *psf, int *blockalign, int *framesperblock) +{ WAVLIKE_PRIVATE *wpriv ; + WAV_FMT *wav_fmt ; + FACT_CHUNK fact_chunk ; + uint32_t marker, chunk_size = 0, RIFFsize = 0, done = 0 ; + int parsestage = 0, error, format = 0 ; + + 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) + return SFE_INTERNAL ; + wav_fmt = &wpriv->wav_fmt ; + + /* Set position to start of file to begin reading header. */ + psf_binheader_readf (psf, "pmj", 0, &marker, -4) ; + psf->header.indx = 0 ; + + /* RIFX signifies big-endian format for all header and data to prevent + ** lots of code copying here, we'll set the psf->rwf_endian flag once here, + ** and never specify endian-ness for all other header ops/ + */ + psf->rwf_endian = (marker == RIFF_MARKER) ? SF_ENDIAN_LITTLE : SF_ENDIAN_BIG ; + + while (! done) + { size_t jump = chunk_size & 1 ; + + marker = chunk_size = 0 ; + psf_binheader_readf (psf, "jm4", jump, &marker, &chunk_size) ; + if (marker == 0) + { sf_count_t pos = psf_ftell (psf) ; + psf_log_printf (psf, "Have 0 marker at position %D (0x%x).\n", pos, pos) ; + break ; + } ; + + psf_store_read_chunk_u32 (&psf->rchunks, marker, psf_ftell (psf), chunk_size) ; + + switch (marker) + { case RIFF_MARKER : + case RIFX_MARKER : + if (parsestage) + return SFE_WAV_NO_RIFF ; + + parsestage |= HAVE_RIFF ; + + RIFFsize = chunk_size ; + + if (psf->fileoffset > 0 && psf->filelength > RIFFsize + 8) + { /* Set file length. */ + psf->filelength = RIFFsize + 8 ; + if (marker == RIFF_MARKER) + psf_log_printf (psf, "RIFF : %u\n", RIFFsize) ; + else + psf_log_printf (psf, "RIFX : %u\n", RIFFsize) ; + } + else if (psf->filelength < RIFFsize + 2 * SIGNED_SIZEOF (marker)) + { if (marker == RIFF_MARKER) + psf_log_printf (psf, "RIFF : %u (should be %D)\n", RIFFsize, psf->filelength - 2 * SIGNED_SIZEOF (marker)) ; + else + psf_log_printf (psf, "RIFX : %u (should be %D)\n", RIFFsize, psf->filelength - 2 * SIGNED_SIZEOF (marker)) ; + + RIFFsize = psf->filelength - 2 * SIGNED_SIZEOF (RIFFsize) ; + } + else + { if (marker == RIFF_MARKER) + psf_log_printf (psf, "RIFF : %u\n", RIFFsize) ; + else + psf_log_printf (psf, "RIFX : %u\n", RIFFsize) ; + } ; + + psf_binheader_readf (psf, "m", &marker) ; + if (marker != WAVE_MARKER) + return SFE_WAV_NO_WAVE ; + parsestage |= HAVE_WAVE ; + psf_log_printf (psf, "WAVE\n") ; + chunk_size = 0 ; + break ; + + case fmt_MARKER : + if ((parsestage & (HAVE_RIFF | HAVE_WAVE)) != (HAVE_RIFF | HAVE_WAVE)) + return SFE_WAV_NO_FMT ; + + /* If this file has a SECOND fmt chunk, I don't want to know about it. */ + if (parsestage & HAVE_fmt) + break ; + + parsestage |= HAVE_fmt ; + + psf_log_printf (psf, "fmt : %d\n", chunk_size) ; + + if ((error = wavlike_read_fmt_chunk (psf, chunk_size))) + return error ; + + format = wav_fmt->format ; + break ; + + case data_MARKER : + if ((parsestage & (HAVE_RIFF | HAVE_WAVE | HAVE_fmt)) != (HAVE_RIFF | HAVE_WAVE | HAVE_fmt)) + return SFE_WAV_NO_DATA ; + + if (psf->file.mode == SFM_RDWR && (parsestage & HAVE_other) != 0) + return SFE_RDWR_BAD_HEADER ; + + parsestage |= HAVE_data ; + + psf->datalength = chunk_size ; + if (psf->datalength & 1) + psf_log_printf (psf, "*** 'data' chunk should be an even number of bytes in length.\n") ; + + psf->dataoffset = psf_ftell (psf) ; + + if (psf->dataoffset > 0) + { if (chunk_size == 0 && RIFFsize == 8 && psf->filelength > 44) + { psf_log_printf (psf, "*** Looks like a WAV file which wasn't closed properly. Fixing it.\n") ; + psf->datalength = psf->filelength - psf->dataoffset ; + } ; + + if (psf->datalength > psf->filelength - psf->dataoffset) + { psf_log_printf (psf, "data : %D (should be %D)\n", psf->datalength, psf->filelength - psf->dataoffset) ; + psf->datalength = psf->filelength - psf->dataoffset ; + } + else + psf_log_printf (psf, "data : %D\n", psf->datalength) ; + + /* Only set dataend if there really is data at the end. */ + if (psf->datalength + psf->dataoffset < psf->filelength) + psf->dataend = psf->datalength + psf->dataoffset ; + + psf->datalength += chunk_size & 1 ; + chunk_size = 0 ; + } ; + + if (! psf->sf.seekable || psf->dataoffset < 0) + break ; + + /* Seek past data and continue reading header. */ + psf_fseek (psf, psf->datalength, SEEK_CUR) ; + + if (psf_ftell (psf) != psf->datalength + psf->dataoffset) + psf_log_printf (psf, "*** psf_fseek past end error ***\n") ; + break ; + + case fact_MARKER : + if ((parsestage & (HAVE_RIFF | HAVE_WAVE)) != (HAVE_RIFF | HAVE_WAVE)) + return SFE_WAV_BAD_FACT ; + + parsestage |= HAVE_fact ; + + if ((parsestage & HAVE_fmt) != HAVE_fmt) + psf_log_printf (psf, "*** Should have 'fmt ' chunk before 'fact'\n") ; + + psf_binheader_readf (psf, "4", & (fact_chunk.frames)) ; + + if (chunk_size > SIGNED_SIZEOF (fact_chunk)) + psf_binheader_readf (psf, "j", (int) (chunk_size - SIGNED_SIZEOF (fact_chunk))) ; + + if (chunk_size) + psf_log_printf (psf, "%M : %u\n", marker, chunk_size) ; + else + psf_log_printf (psf, "%M : %u (should not be zero)\n", marker, chunk_size) ; + + psf_log_printf (psf, " frames : %d\n", fact_chunk.frames) ; + break ; + + case PEAK_MARKER : + if ((parsestage & (HAVE_RIFF | HAVE_WAVE | HAVE_fmt)) != (HAVE_RIFF | HAVE_WAVE | HAVE_fmt)) + return SFE_WAV_PEAK_B4_FMT ; + + parsestage |= HAVE_PEAK ; + + psf_log_printf (psf, "%M : %u\n", marker, chunk_size) ; + if ((error = wavlike_read_peak_chunk (psf, chunk_size)) != 0) + return error ; + psf->peak_info->peak_loc = ((parsestage & HAVE_data) == 0) ? SF_PEAK_START : SF_PEAK_END ; + break ; + + case cue_MARKER : + parsestage |= HAVE_other ; + + { uint32_t thisread, bytesread, cue_count, position, offset ; + int id, chunk_id, chunk_start, block_start, cue_index ; + + bytesread = psf_binheader_readf (psf, "4", &cue_count) ; + psf_log_printf (psf, "%M : %u\n", marker, chunk_size) ; + + if (cue_count > 2500) /* 2500 is close to the largest number of cues possible because of block sizes */ + { psf_log_printf (psf, " Count : %u (skipping)\n", cue_count) ; + psf_binheader_readf (psf, "j", chunk_size - bytesread) ; + break ; + } ; + + psf_log_printf (psf, " Count : %d\n", cue_count) ; + + if (psf->cues) + { free (psf->cues) ; + psf->cues = NULL ; + } ; + + if ((psf->cues = psf_cues_alloc (cue_count)) == NULL) + return SFE_MALLOC_FAILED ; + + cue_index = 0 ; + + while (cue_count) + { + if ((thisread = psf_binheader_readf (psf, "e44m444", &id, &position, &chunk_id, &chunk_start, &block_start, &offset)) == 0) + break ; + bytesread += thisread ; + + if (cue_index < 10) /* avoid swamping log buffer with cues */ + psf_log_printf (psf, " Cue ID : %2d" + " Pos : %5u Chunk : %M" + " Chk Start : %d Blk Start : %d" + " Offset : %5d\n", + id, position, chunk_id, chunk_start, block_start, offset) ; + else if (cue_index == 10) + psf_log_printf (psf, " (Skipping)\n") ; + + psf->cues->cue_points [cue_index].indx = id ; + psf->cues->cue_points [cue_index].position = position ; + psf->cues->cue_points [cue_index].fcc_chunk = chunk_id ; + psf->cues->cue_points [cue_index].chunk_start = chunk_start ; + psf->cues->cue_points [cue_index].block_start = block_start ; + psf->cues->cue_points [cue_index].sample_offset = offset ; + psf->cues->cue_points [cue_index].name [0] = '\0' ; + cue_count -- ; + cue_index ++ ; + } ; + + if (bytesread != chunk_size) + { psf_log_printf (psf, "**** Chunk size weirdness (%d != %d)\n", chunk_size, bytesread) ; + psf_binheader_readf (psf, "j", chunk_size - bytesread) ; + } ; + } ; + break ; + + case smpl_MARKER : + parsestage |= HAVE_other ; + + psf_log_printf (psf, "smpl : %u\n", chunk_size) ; + + if ((error = wav_read_smpl_chunk (psf, chunk_size))) + return error ; + break ; + + case acid_MARKER : + parsestage |= HAVE_other ; + + psf_log_printf (psf, "acid : %u\n", chunk_size) ; + + if ((error = wav_read_acid_chunk (psf, chunk_size))) + return error ; + break ; + + case INFO_MARKER : + case LIST_MARKER : + parsestage |= HAVE_other ; + + if ((error = wavlike_subchunk_parse (psf, marker, chunk_size)) != 0) + return error ; + break ; + + case bext_MARKER : + /* + The 'bext' chunk can actually be updated, so don't need to set this. + parsestage |= HAVE_other ; + */ + if ((error = wavlike_read_bext_chunk (psf, chunk_size))) + return error ; + break ; + + case PAD_MARKER : + /* + We can eat into a 'PAD ' chunk if we need to. + parsestage |= HAVE_other ; + */ + psf_log_printf (psf, "%M : %u\n", marker, chunk_size) ; + psf_binheader_readf (psf, "j", chunk_size) ; + break ; + + case cart_MARKER: + if ((error = wavlike_read_cart_chunk (psf, chunk_size))) + return error ; + break ; + + case iXML_MARKER : /* See http://en.wikipedia.org/wiki/IXML */ + case strc_MARKER : /* Multiple of 32 bytes. */ + case afsp_MARKER : + case clm_MARKER : + case elmo_MARKER : + case levl_MARKER : + case plst_MARKER : + case minf_MARKER : + case elm1_MARKER : + case regn_MARKER : + case ovwf_MARKER : + case inst_MARKER : + case AFAn_MARKER : + case umid_MARKER : + case SyLp_MARKER : + case Cr8r_MARKER : + case JUNK_MARKER : + case PMX_MARKER : + case DISP_MARKER : + case MEXT_MARKER : + case FLLR_MARKER : + psf_log_printf (psf, "%M : %u\n", marker, chunk_size) ; + psf_binheader_readf (psf, "j", chunk_size) ; + break ; + + default : + if (chunk_size >= 0xffff0000) + { done = SF_TRUE ; + psf_log_printf (psf, "*** Unknown chunk marker (%X) at position %D with length %u. Exiting parser.\n", marker, psf_ftell (psf) - 8, chunk_size) ; + break ; + } ; + + if ((marker & TAG__MARKER_MASK) == TAG__MARKER && + psf_ftell (psf) - 8 + 128 == psf->filelength) + { psf_log_printf (psf, "*** Hit ID3v1 trailer. Exiting parser.\n") ; + chunk_size = 128 ; + done = SF_TRUE ; + parsestage |= HAVE_other ; + break ; + } ; + + if (psf_isprint ((marker >> 24) & 0xFF) && psf_isprint ((marker >> 16) & 0xFF) + && psf_isprint ((marker >> 8) & 0xFF) && psf_isprint (marker & 0xFF)) + { psf_log_printf (psf, "*** %M : %u (unknown marker)\n", marker, chunk_size) ; + psf_binheader_readf (psf, "j", chunk_size) ; + break ; + } ; + if (psf_ftell (psf) & 0x03) + { psf_log_printf (psf, " Unknown chunk marker at position %D. Resynching.\n", psf_ftell (psf) - 8) ; + psf_binheader_readf (psf, "j", -3) ; + /* File is too messed up so we prevent editing in RDWR mode here. */ + parsestage |= HAVE_other ; + break ; + } ; + psf_log_printf (psf, "*** Unknown chunk marker (%X) at position %D. Exiting parser.\n", marker, psf_ftell (psf) - 8) ; + done = SF_TRUE ; + break ; + } ; /* switch (marker) */ + + if (chunk_size >= psf->filelength) + { psf_log_printf (psf, "*** Chunk size %u > file length %D. Exiting parser.\n", chunk_size, psf->filelength) ; + break ; + } ; + + if (! psf->sf.seekable && (parsestage & HAVE_data)) + break ; + + if (psf_ftell (psf) >= psf->filelength - SIGNED_SIZEOF (chunk_size)) + { psf_log_printf (psf, "End\n") ; + break ; + } ; + } ; /* while (1) */ + + if (psf->dataoffset <= 0) + return SFE_WAV_NO_DATA ; + + if (psf->sf.channels < 1) + return SFE_CHANNEL_COUNT_ZERO ; + + if (psf->sf.channels > SF_MAX_CHANNELS) + return SFE_CHANNEL_COUNT ; + + if (format != WAVE_FORMAT_PCM && (parsestage & HAVE_fact) == 0) + psf_log_printf (psf, "**** All non-PCM format files should have a 'fact' chunk.\n") ; + + /* WAVs can be little or big endian */ + psf->endian = psf->rwf_endian ; + + psf_fseek (psf, psf->dataoffset, SEEK_SET) ; + + if (psf->is_pipe == 0) + { /* + ** Check for 'wvpk' at the start of the DATA section. Not able to + ** handle this. + */ + psf_binheader_readf (psf, "4", &marker) ; + if (marker == wvpk_MARKER || marker == OggS_MARKER) + return SFE_WAV_WVPK_DATA ; + } ; + + /* Seek to start of DATA section. */ + psf_fseek (psf, psf->dataoffset, SEEK_SET) ; + + if (psf->blockwidth) + { if (psf->filelength - psf->dataoffset < psf->datalength) + psf->sf.frames = (psf->filelength - psf->dataoffset) / psf->blockwidth ; + else + psf->sf.frames = psf->datalength / psf->blockwidth ; + } ; + + switch (format) + { case WAVE_FORMAT_EXTENSIBLE : + if (psf->sf.format == (SF_FORMAT_WAVEX | SF_FORMAT_MS_ADPCM)) + { *blockalign = wav_fmt->msadpcm.blockalign ; + *framesperblock = wav_fmt->msadpcm.samplesperblock ; + } ; + break ; + + case WAVE_FORMAT_NMS_VBXADPCM : + switch (wav_fmt->min.bitwidth) + { case 2 : + psf->sf.format = SF_FORMAT_WAV | SF_FORMAT_NMS_ADPCM_16 ; + break ; + case 3 : + psf->sf.format = SF_FORMAT_WAV | SF_FORMAT_NMS_ADPCM_24 ; + break ; + case 4 : + psf->sf.format = SF_FORMAT_WAV | SF_FORMAT_NMS_ADPCM_32 ; + break ; + + default : + return SFE_UNIMPLEMENTED ; + } + break ; + + case WAVE_FORMAT_PCM : + psf->sf.format = SF_FORMAT_WAV | u_bitwidth_to_subformat (psf->bytewidth * 8) ; + break ; + + case WAVE_FORMAT_MULAW : + case IBM_FORMAT_MULAW : + psf->sf.format = (SF_FORMAT_WAV | SF_FORMAT_ULAW) ; + break ; + + case WAVE_FORMAT_ALAW : + case IBM_FORMAT_ALAW : + psf->sf.format = (SF_FORMAT_WAV | SF_FORMAT_ALAW) ; + break ; + + case WAVE_FORMAT_MS_ADPCM : + psf->sf.format = (SF_FORMAT_WAV | SF_FORMAT_MS_ADPCM) ; + *blockalign = wav_fmt->msadpcm.blockalign ; + *framesperblock = wav_fmt->msadpcm.samplesperblock ; + break ; + + case WAVE_FORMAT_IMA_ADPCM : + psf->sf.format = (SF_FORMAT_WAV | SF_FORMAT_IMA_ADPCM) ; + *blockalign = wav_fmt->ima.blockalign ; + *framesperblock = wav_fmt->ima.samplesperblock ; + break ; + + case WAVE_FORMAT_GSM610 : + psf->sf.format = (SF_FORMAT_WAV | SF_FORMAT_GSM610) ; + break ; + + case WAVE_FORMAT_IEEE_FLOAT : + psf->sf.format = SF_FORMAT_WAV ; + psf->sf.format |= (psf->bytewidth == 8) ? SF_FORMAT_DOUBLE : SF_FORMAT_FLOAT ; + break ; + + case WAVE_FORMAT_G721_ADPCM : + psf->sf.format = SF_FORMAT_WAV | SF_FORMAT_G721_32 ; + break ; + + case WAVE_FORMAT_MPEGLAYER3 : + psf->sf.format = SF_FORMAT_WAV | SF_FORMAT_MPEG_LAYER_III ; + if (parsestage & HAVE_fact) + psf->sf.frames = fact_chunk.frames ; + break ; + + default : return SFE_UNIMPLEMENTED ; + } ; + + if (wpriv->fmt_is_broken) + wavlike_analyze (psf) ; + + /* Only set the format endian-ness if its non-standard big-endian. */ + if (psf->endian == SF_ENDIAN_BIG) + psf->sf.format |= SF_ENDIAN_BIG ; + + return 0 ; +} /* wav_read_header */ + +static int +wav_write_fmt_chunk (SF_PRIVATE *psf) +{ int subformat, fmt_size, add_fact_chunk = 0 ; + + subformat = SF_CODEC (psf->sf.format) ; + + switch (subformat) + { case SF_FORMAT_PCM_U8 : + case SF_FORMAT_PCM_16 : + case SF_FORMAT_PCM_24 : + case SF_FORMAT_PCM_32 : + fmt_size = 2 + 2 + 4 + 4 + 2 + 2 ; + + /* fmt : format, channels, samplerate */ + psf_binheader_writef (psf, "4224", BHW4 (fmt_size), BHW2 (WAVE_FORMAT_PCM), BHW2 (psf->sf.channels), BHW4 (psf->sf.samplerate)) ; + /* fmt : bytespersec */ + psf_binheader_writef (psf, "4", BHW4 (psf->sf.samplerate * psf->bytewidth * psf->sf.channels)) ; + /* fmt : blockalign, bitwidth */ + psf_binheader_writef (psf, "22", BHW2 (psf->bytewidth * psf->sf.channels), BHW2 (psf->bytewidth * 8)) ; + break ; + + case SF_FORMAT_FLOAT : + case SF_FORMAT_DOUBLE : + fmt_size = 2 + 2 + 4 + 4 + 2 + 2 ; + + /* fmt : format, channels, samplerate */ + psf_binheader_writef (psf, "4224", BHW4 (fmt_size), BHW2 (WAVE_FORMAT_IEEE_FLOAT), BHW2 (psf->sf.channels), BHW4 (psf->sf.samplerate)) ; + /* fmt : bytespersec */ + psf_binheader_writef (psf, "4", BHW4 (psf->sf.samplerate * psf->bytewidth * psf->sf.channels)) ; + /* fmt : blockalign, bitwidth */ + psf_binheader_writef (psf, "22", BHW2 (psf->bytewidth * psf->sf.channels), BHW2 (psf->bytewidth * 8)) ; + + add_fact_chunk = SF_TRUE ; + break ; + + case SF_FORMAT_ULAW : + fmt_size = 2 + 2 + 4 + 4 + 2 + 2 + 2 ; + + /* fmt : format, channels, samplerate */ + psf_binheader_writef (psf, "4224", BHW4 (fmt_size), BHW2 (WAVE_FORMAT_MULAW), BHW2 (psf->sf.channels), BHW4 (psf->sf.samplerate)) ; + /* fmt : bytespersec */ + psf_binheader_writef (psf, "4", BHW4 (psf->sf.samplerate * psf->bytewidth * psf->sf.channels)) ; + /* fmt : blockalign, bitwidth, extrabytes */ + psf_binheader_writef (psf, "222", BHW2 (psf->bytewidth * psf->sf.channels), BHW2 (8), BHW2 (0)) ; + + add_fact_chunk = SF_TRUE ; + break ; + + case SF_FORMAT_ALAW : + fmt_size = 2 + 2 + 4 + 4 + 2 + 2 + 2 ; + + /* fmt : format, channels, samplerate */ + psf_binheader_writef (psf, "4224", BHW4 (fmt_size), BHW2 (WAVE_FORMAT_ALAW), BHW2 (psf->sf.channels), BHW4 (psf->sf.samplerate)) ; + /* fmt : bytespersec */ + psf_binheader_writef (psf, "4", BHW4 (psf->sf.samplerate * psf->bytewidth * psf->sf.channels)) ; + /* fmt : blockalign, bitwidth, extrabytes */ + psf_binheader_writef (psf, "222", BHW2 (psf->bytewidth * psf->sf.channels), BHW2 (8), BHW2 (0)) ; + + add_fact_chunk = SF_TRUE ; + break ; + + /* Lite remove start */ + case SF_FORMAT_IMA_ADPCM : + { int blockalign, framesperblock, bytespersec ; + + blockalign = wavlike_srate2blocksize (psf->sf.samplerate * psf->sf.channels) ; + framesperblock = 2 * (blockalign - 4 * psf->sf.channels) / psf->sf.channels + 1 ; + bytespersec = (psf->sf.samplerate * blockalign) / framesperblock ; + + /* fmt chunk. */ + fmt_size = 2 + 2 + 4 + 4 + 2 + 2 + 2 + 2 ; + + /* fmt : size, WAV format type, channels, samplerate, bytespersec */ + psf_binheader_writef (psf, "42244", BHW4 (fmt_size), BHW2 (WAVE_FORMAT_IMA_ADPCM), + BHW2 (psf->sf.channels), BHW4 (psf->sf.samplerate), BHW4 (bytespersec)) ; + + /* fmt : blockalign, bitwidth, extrabytes, framesperblock. */ + psf_binheader_writef (psf, "2222", BHW2 (blockalign), BHW2 (4), BHW2 (2), BHW2 (framesperblock)) ; + } ; + + add_fact_chunk = SF_TRUE ; + break ; + + case SF_FORMAT_MS_ADPCM : + { int blockalign, framesperblock, bytespersec, extrabytes ; + + blockalign = wavlike_srate2blocksize (psf->sf.samplerate * psf->sf.channels) ; + framesperblock = 2 + 2 * (blockalign - 7 * psf->sf.channels) / psf->sf.channels ; + bytespersec = (psf->sf.samplerate * blockalign) / framesperblock ; + + /* fmt chunk. */ + extrabytes = 2 + 2 + WAVLIKE_MSADPCM_ADAPT_COEFF_COUNT * (2 + 2) ; + fmt_size = 2 + 2 + 4 + 4 + 2 + 2 + 2 + extrabytes ; + + /* fmt : size, WAV format type, channels. */ + psf_binheader_writef (psf, "422", BHW4 (fmt_size), BHW2 (WAVE_FORMAT_MS_ADPCM), BHW2 (psf->sf.channels)) ; + + /* fmt : samplerate, bytespersec. */ + psf_binheader_writef (psf, "44", BHW4 (psf->sf.samplerate), BHW4 (bytespersec)) ; + + /* fmt : blockalign, bitwidth, extrabytes, framesperblock. */ + psf_binheader_writef (psf, "22222", BHW2 (blockalign), BHW2 (4), BHW2 (extrabytes), BHW2 (framesperblock), BHW2 (7)) ; + + wavlike_msadpcm_write_adapt_coeffs (psf) ; + } ; + + add_fact_chunk = SF_TRUE ; + break ; + + + case SF_FORMAT_G721_32 : + /* fmt chunk. */ + fmt_size = 2 + 2 + 4 + 4 + 2 + 2 + 2 + 2 ; + + /* fmt : size, WAV format type, channels, samplerate, bytespersec */ + psf_binheader_writef (psf, "42244", BHW4 (fmt_size), BHW2 (WAVE_FORMAT_G721_ADPCM), + BHW2 (psf->sf.channels), BHW4 (psf->sf.samplerate), BHW4 (psf->sf.samplerate * psf->sf.channels / 2)) ; + + /* fmt : blockalign, bitwidth, extrabytes, auxblocksize. */ + psf_binheader_writef (psf, "2222", BHW2 (64), BHW2 (4), BHW2 (2), BHW2 (0)) ; + + add_fact_chunk = SF_TRUE ; + break ; + + case SF_FORMAT_NMS_ADPCM_16 : + case SF_FORMAT_NMS_ADPCM_24 : + case SF_FORMAT_NMS_ADPCM_32 : + { int bytespersec, blockalign, bitwidth ; + + bitwidth = subformat == SF_FORMAT_NMS_ADPCM_16 ? 2 : subformat == SF_FORMAT_NMS_ADPCM_24 ? 3 : 4 ; + blockalign = 20 * bitwidth + 2 ; + bytespersec = psf->sf.samplerate * blockalign / 160 ; + + /* fmt chunk. */ + fmt_size = 2 + 2 + 4 + 4 + 2 + 2 ; + + /* fmt : format, channels, samplerate */ + psf_binheader_writef (psf, "4224", BHW4 (fmt_size), BHW2 (WAVE_FORMAT_NMS_VBXADPCM), + BHW2 (psf->sf.channels), BHW4 (psf->sf.samplerate)) ; + /* fmt : bytespersec, blockalign, bitwidth */ + psf_binheader_writef (psf, "422", BHW4 (bytespersec), BHW2 (blockalign), BHW2 (bitwidth)) ; + + add_fact_chunk = SF_TRUE ; + break ; + } + + /* Lite remove end */ + + case SF_FORMAT_GSM610 : + { int blockalign, framesperblock, bytespersec ; + + blockalign = WAVLIKE_GSM610_BLOCKSIZE ; + framesperblock = WAVLIKE_GSM610_SAMPLES ; + bytespersec = (psf->sf.samplerate * blockalign) / framesperblock ; + + /* fmt chunk. */ + fmt_size = 2 + 2 + 4 + 4 + 2 + 2 + 2 + 2 ; + + /* fmt : size, WAV format type, channels. */ + psf_binheader_writef (psf, "422", BHW4 (fmt_size), BHW2 (WAVE_FORMAT_GSM610), BHW2 (psf->sf.channels)) ; + + /* fmt : samplerate, bytespersec. */ + psf_binheader_writef (psf, "44", BHW4 (psf->sf.samplerate), BHW4 (bytespersec)) ; + + /* fmt : blockalign, bitwidth, extrabytes, framesperblock. */ + psf_binheader_writef (psf, "2222", BHW2 (blockalign), BHW2 (0), BHW2 (2), BHW2 (framesperblock)) ; + } ; + + add_fact_chunk = SF_TRUE ; + break ; + +#if (ENABLE_EXPERIMENTAL_CODE == 0) + case SF_FORMAT_MPEG_LAYER_III : + { int bytespersec, blockalign, flags, blocksize, samplesperblock, codecdelay ; + + /* Intended to be set as the average sample rate. + ** TODO: Maybe re-write this on close with final average + ** byterate? */ + bytespersec = psf->byterate (psf) ; + + /* Average block size. Info only I think. */ + blocksize = (1152 * bytespersec) / psf->sf.samplerate ; + + /* Can be set to block size IFF the block size is + ** constant, set to 1 otherwise. Constant sized + ** MPEG block streams are uncommon (CBR @ 32kHz and + ** 48kHz only. Meh. */ + blockalign = 1 ; + + /* TODO: Only flags defined are padding-type. I /think/ + ** Lame does ISO style padding by default, which has a + ** flag value of 0. + */ + flags = 0 ; + + /* Should only vary per MPEG 1.0/2.0 vs '2.5'. + ** TODO: Move this out to MPEG specific place? */ + samplesperblock = psf->sf.samplerate >= 32000 ? 1152 : 576 ; + + /* Set as 0 if unknown. + ** TODO: Plumb this cleanly from Lame. + */ + codecdelay = 0 ; + + /* fmt chunk. */ + fmt_size = 2 + 2 + 4 + 4 + 2 + 2 + 2 + 2 + 4 + 2 + 2 + 2 ; + + /* fmt : size, WAV format type, channels. */ + psf_binheader_writef (psf, "422", BHW4 (fmt_size), BHW2 (WAVE_FORMAT_MPEGLAYER3), BHW2 (psf->sf.channels)) ; + + /* fmt : samplerate, bytespersec. */ + psf_binheader_writef (psf, "44", BHW4 (psf->sf.samplerate), BHW4 (bytespersec)) ; + + /* fmt : blockalign, bitwidth, extrabytes, id. */ + psf_binheader_writef (psf, "2222", BHW2 (blockalign), BHW2 (0), BHW2 (12), BHW2 (1)) ; + + /* fmt : flags, blocksize, samplesperblock, codecdelay */ + psf_binheader_writef (psf, "4222", BHW4 (flags), BHW2 (blocksize), BHW2 (samplesperblock), BHW2 (codecdelay)) ; + } ; + + add_fact_chunk = SF_TRUE ; + break ; +#endif + + default : return SFE_UNIMPLEMENTED ; + } ; + + if (add_fact_chunk) + psf_binheader_writef (psf, "tm48", BHWm (fact_MARKER), BHW4 (4), BHW8 (psf->sf.frames)) ; + + return 0 ; +} /* wav_write_fmt_chunk */ + +static int +wavex_write_fmt_chunk (SF_PRIVATE *psf) +{ WAVLIKE_PRIVATE *wpriv ; + int subformat, fmt_size ; + + if ((wpriv = psf->container_data) == NULL) + return SFE_INTERNAL ; + + subformat = SF_CODEC (psf->sf.format) ; + + /* initial section (same for all, it appears) */ + switch (subformat) + { case SF_FORMAT_PCM_U8 : + case SF_FORMAT_PCM_16 : + case SF_FORMAT_PCM_24 : + case SF_FORMAT_PCM_32 : + case SF_FORMAT_FLOAT : + case SF_FORMAT_DOUBLE : + case SF_FORMAT_ULAW : + case SF_FORMAT_ALAW : + fmt_size = 2 + 2 + 4 + 4 + 2 + 2 + 2 + 2 + 4 + 4 + 2 + 2 + 8 ; + + /* fmt : format, channels, samplerate */ + psf_binheader_writef (psf, "4224", BHW4 (fmt_size), BHW2 (WAVE_FORMAT_EXTENSIBLE), BHW2 (psf->sf.channels), BHW4 (psf->sf.samplerate)) ; + /* fmt : bytespersec */ + psf_binheader_writef (psf, "4", BHW4 (psf->sf.samplerate * psf->bytewidth * psf->sf.channels)) ; + /* fmt : blockalign, bitwidth */ + psf_binheader_writef (psf, "22", BHW2 (psf->bytewidth * psf->sf.channels), BHW2 (psf->bytewidth * 8)) ; + + /* cbSize 22 is sizeof (WAVEFORMATEXTENSIBLE) - sizeof (WAVEFORMATEX) */ + psf_binheader_writef (psf, "2", BHW2 (22)) ; + + /* wValidBitsPerSample, for our use same as bitwidth as we use it fully */ + psf_binheader_writef (psf, "2", BHW2 (psf->bytewidth * 8)) ; + + /* For an Ambisonic file set the channel mask to zero. + ** Otherwise use a default based on the channel count. + */ + if (wpriv->wavex_ambisonic != SF_AMBISONIC_NONE) + psf_binheader_writef (psf, "4", BHW4 (0)) ; + else if (wpriv->wavex_channelmask != 0) + psf_binheader_writef (psf, "4", BHW4 (wpriv->wavex_channelmask)) ; + else + { /* + ** Ok some liberty is taken here to use the most commonly used channel masks + ** instead of "no mapping". If you really want to use "no mapping" for 8 channels and less + ** please don't use wavex. (otherwise we'll have to create a new SF_COMMAND) + */ + switch (psf->sf.channels) + { case 1 : /* center channel mono */ + psf_binheader_writef (psf, "4", BHW4 (0x4)) ; + break ; + + case 2 : /* front left and right */ + psf_binheader_writef (psf, "4", BHW4 (0x1 | 0x2)) ; + break ; + + case 4 : /* Quad */ + psf_binheader_writef (psf, "4", BHW4 (0x1 | 0x2 | 0x10 | 0x20)) ; + break ; + + case 6 : /* 5.1 */ + psf_binheader_writef (psf, "4", BHW4 (0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20)) ; + break ; + + case 8 : /* 7.1 */ + psf_binheader_writef (psf, "4", BHW4 (0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20 | 0x40 | 0x80)) ; + break ; + + default : /* 0 when in doubt , use direct out, ie NO mapping*/ + psf_binheader_writef (psf, "4", BHW4 (0x0)) ; + break ; + } ; + } ; + break ; + + case SF_FORMAT_MS_ADPCM : /* Todo, GUID exists might have different header as per wav_write_header */ + default : + return SFE_UNIMPLEMENTED ; + } ; + + /* GUID section, different for each */ + + switch (subformat) + { case SF_FORMAT_PCM_U8 : + case SF_FORMAT_PCM_16 : + case SF_FORMAT_PCM_24 : + case SF_FORMAT_PCM_32 : + wavlike_write_guid (psf, wpriv->wavex_ambisonic == SF_AMBISONIC_NONE ? + &MSGUID_SUBTYPE_PCM : &MSGUID_SUBTYPE_AMBISONIC_B_FORMAT_PCM) ; + break ; + + case SF_FORMAT_FLOAT : + case SF_FORMAT_DOUBLE : + wavlike_write_guid (psf, wpriv->wavex_ambisonic == SF_AMBISONIC_NONE ? + &MSGUID_SUBTYPE_IEEE_FLOAT : &MSGUID_SUBTYPE_AMBISONIC_B_FORMAT_IEEE_FLOAT) ; + break ; + + case SF_FORMAT_ULAW : + wavlike_write_guid (psf, &MSGUID_SUBTYPE_MULAW) ; + break ; + + case SF_FORMAT_ALAW : + wavlike_write_guid (psf, &MSGUID_SUBTYPE_ALAW) ; + break ; + +#if 0 + /* This is dead code due to return in previous switch statement. */ + case SF_FORMAT_MS_ADPCM : /* todo, GUID exists */ + wavlike_write_guid (psf, &MSGUID_SUBTYPE_MS_ADPCM) ; + break ; + return SFE_UNIMPLEMENTED ; +#endif + + default : return SFE_UNIMPLEMENTED ; + } ; + + psf_binheader_writef (psf, "tm48", BHWm (fact_MARKER), BHW4 (4), BHW8 (psf->sf.frames)) ; + + return 0 ; +} /* wavex_write_fmt_chunk */ + + +static int +wav_write_header (SF_PRIVATE *psf, int calc_length) +{ sf_count_t current ; + int error, has_data = SF_FALSE ; + + current = psf_ftell (psf) ; + + if (current > psf->dataoffset) + has_data = SF_TRUE ; + + if (calc_length) + { psf->filelength = psf_get_filelen (psf) ; + + psf->datalength = psf->filelength - psf->dataoffset ; + + if (psf->dataend) + psf->datalength -= psf->filelength - psf->dataend ; + else if (psf->bytewidth > 0 && psf->sf.seekable == SF_TRUE) + psf->datalength = psf->sf.frames * psf->bytewidth * psf->sf.channels ; + } ; + + /* Reset the current header length to zero. */ + psf->header.ptr [0] = 0 ; + psf->header.indx = 0 ; + psf_fseek (psf, 0, SEEK_SET) ; + + /* + ** RIFX signifies big-endian format for all header and data. + ** To prevent lots of code copying here, we'll set the psf->rwf_endian flag + ** once here, and never specify endian-ness for all other header operations. + */ + + /* RIFF/RIFX marker, length, WAVE and 'fmt ' markers. */ + + if (psf->endian == SF_ENDIAN_LITTLE) + psf_binheader_writef (psf, "etm8", BHWm (RIFF_MARKER), BHW8 ((psf->filelength < 8) ? 8 : SF_MIN(psf->filelength - 8, UINT32_MAX))) ; + else + psf_binheader_writef (psf, "Etm8", BHWm (RIFX_MARKER), BHW8 ((psf->filelength < 8) ? 8 : SF_MIN(psf->filelength - 8, UINT32_MAX))) ; + + /* WAVE and 'fmt ' markers. */ + psf_binheader_writef (psf, "mm", BHWm (WAVE_MARKER), BHWm (fmt_MARKER)) ; + + /* Write the 'fmt ' chunk. */ + switch (SF_CONTAINER (psf->sf.format)) + { case SF_FORMAT_WAV : + if ((error = wav_write_fmt_chunk (psf)) != 0) + return error ; + break ; + + case SF_FORMAT_WAVEX : + if ((error = wavex_write_fmt_chunk (psf)) != 0) + return error ; + break ; + + default : + return SFE_UNIMPLEMENTED ; + } ; + + /* The LIST/INFO chunk. */ + if (psf->strings.flags & SF_STR_LOCATE_START) + wavlike_write_strings (psf, SF_STR_LOCATE_START) ; + + if (psf->peak_info != NULL && psf->peak_info->peak_loc == SF_PEAK_START) + wavlike_write_peak_chunk (psf) ; + + if (psf->broadcast_16k != NULL) + wavlike_write_bext_chunk (psf) ; + + if (psf->cart_16k != NULL) + wavlike_write_cart_chunk (psf) ; + + if (psf->cues != NULL) + { uint32_t k ; + + psf_binheader_writef (psf, "em44", BHWm (cue_MARKER), BHW4 (4 + psf->cues->cue_count * 6 * 4), BHW4 (psf->cues->cue_count)) ; + + for (k = 0 ; k < psf->cues->cue_count ; k++) + psf_binheader_writef (psf, "e44m444", BHW4 (psf->cues->cue_points [k].indx), BHW4 (psf->cues->cue_points [k].position), + BHWm (psf->cues->cue_points [k].fcc_chunk), BHW4 (psf->cues->cue_points [k].chunk_start), + BHW4 (psf->cues->cue_points [k].block_start), BHW4 (psf->cues->cue_points [k].sample_offset)) ; + } ; + + if (psf->instrument != NULL) + { int tmp ; + double dtune = (double) (0x40000000) / 25.0 ; + + psf_binheader_writef (psf, "m4", BHWm (smpl_MARKER), BHW4 (9 * 4 + psf->instrument->loop_count * 6 * 4)) ; + psf_binheader_writef (psf, "44", BHW4 (0), BHW4 (0)) ; /* Manufacturer zero is everyone */ + tmp = (int) (1.0e9 / psf->sf.samplerate) ; /* Sample period in nano seconds */ + psf_binheader_writef (psf, "44", BHW4 (tmp), BHW4 (psf->instrument->basenote)) ; + tmp = (uint32_t) (psf->instrument->detune * dtune + 0.5) ; + psf_binheader_writef (psf, "4", BHW4 (tmp)) ; + psf_binheader_writef (psf, "44", BHW4 (0), BHW4 (0)) ; /* SMTPE format */ + psf_binheader_writef (psf, "44", BHW4 (psf->instrument->loop_count), BHW4 (0)) ; + + /* Make sure we don't read past the loops array end. */ + if (psf->instrument->loop_count > ARRAY_LEN (psf->instrument->loops)) + psf->instrument->loop_count = ARRAY_LEN (psf->instrument->loops) ; + + for (tmp = 0 ; tmp < psf->instrument->loop_count ; tmp++) + { int type ; + + type = psf->instrument->loops [tmp].mode ; + type = (type == SF_LOOP_FORWARD ? 0 : type == SF_LOOP_BACKWARD ? 2 : type == SF_LOOP_ALTERNATING ? 1 : 32) ; + + psf_binheader_writef (psf, "44", BHW4 (tmp), BHW4 (type)) ; + psf_binheader_writef (psf, "44", BHW4 (psf->instrument->loops [tmp].start), BHW4 (psf->instrument->loops [tmp].end - 1)) ; + psf_binheader_writef (psf, "44", BHW4 (0), BHW4 (psf->instrument->loops [tmp].count)) ; + } ; + } ; + + /* Write custom headers. */ + if (psf->wchunks.used > 0) + wavlike_write_custom_chunks (psf) ; + + if (psf->header.indx + 16 < psf->dataoffset) + { /* Add PAD data if necessary. */ + size_t k = psf->dataoffset - (psf->header.indx + 16) ; + psf_binheader_writef (psf, "m4z", BHWm (PAD_MARKER), BHW4 (k), BHWz (k)) ; + } ; + + psf_binheader_writef (psf, "tm8", BHWm (data_MARKER), BHW8 (SF_MIN(psf->datalength, UINT32_MAX))) ; + psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ; + if (psf->error) + return psf->error ; + + if (has_data && psf->dataoffset != psf->header.indx) + { psf_log_printf (psf, "Oooops : has_data && psf->dataoffset != psf->header.indx\n") ; + return psf->error = SFE_INTERNAL ; + } ; + + psf->dataoffset = psf->header.indx ; + + if (! has_data) + psf_fseek (psf, psf->dataoffset, SEEK_SET) ; + else if (current > 0) + psf_fseek (psf, current, SEEK_SET) ; + + return psf->error ; +} /* wav_write_header */ + + +static int +wav_write_tailer (SF_PRIVATE *psf) +{ + /* Reset the current header buffer length to zero. */ + psf->header.ptr [0] = 0 ; + psf->header.indx = 0 ; + + if (psf->bytewidth > 0 && psf->sf.seekable == SF_TRUE) + { psf->datalength = psf->sf.frames * psf->bytewidth * psf->sf.channels ; + psf->dataend = psf->dataoffset + psf->datalength ; + } ; + + if (psf->dataend > 0) + psf_fseek (psf, psf->dataend, SEEK_SET) ; + else + psf->dataend = psf_fseek (psf, 0, SEEK_END) ; + + if (psf->dataend & 1) + psf_binheader_writef (psf, "z", BHWz (1)) ; + + /* Add a PEAK chunk if requested. */ + if (psf->peak_info != NULL && psf->peak_info->peak_loc == SF_PEAK_END) + wavlike_write_peak_chunk (psf) ; + + if (psf->strings.flags & SF_STR_LOCATE_END) + wavlike_write_strings (psf, SF_STR_LOCATE_END) ; + + /* Write the tailer. */ + if (psf->header.indx > 0) + psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ; + + return 0 ; +} /* wav_write_tailer */ + +static int +wav_close (SF_PRIVATE *psf) +{ + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { wav_write_tailer (psf) ; + + if (psf->file.mode == SFM_RDWR) + { sf_count_t current = psf_ftell (psf) ; + + /* + ** If the mode is RDWR and the current position is less than the + ** filelength, truncate the file. + */ + + if (current < psf->filelength) + { psf_ftruncate (psf, current) ; + psf->filelength = current ; + } ; + } ; + + psf->write_header (psf, SF_TRUE) ; + } ; + + return 0 ; +} /* wav_close */ + +static int +wav_command (SF_PRIVATE *psf, int command, void * UNUSED (data), int datasize) +{ WAVLIKE_PRIVATE *wpriv ; + + if ((wpriv = psf->container_data) == NULL) + return SFE_INTERNAL ; + + switch (command) + { case SFC_WAVEX_SET_AMBISONIC : + if ((SF_CONTAINER (psf->sf.format)) == SF_FORMAT_WAVEX) + { if (datasize == SF_AMBISONIC_NONE) + wpriv->wavex_ambisonic = SF_AMBISONIC_NONE ; + else if (datasize == SF_AMBISONIC_B_FORMAT) + wpriv->wavex_ambisonic = SF_AMBISONIC_B_FORMAT ; + else + return 0 ; + } ; + return wpriv->wavex_ambisonic ; + + case SFC_WAVEX_GET_AMBISONIC : + return wpriv->wavex_ambisonic ; + + case SFC_SET_CHANNEL_MAP_INFO : + wpriv->wavex_channelmask = wavlike_gen_channel_mask (psf->channel_map, psf->sf.channels) ; + return (wpriv->wavex_channelmask != 0) ; + + default : + break ; + } ; + + return 0 ; +} /* wav_command */ + +static int +wav_read_smpl_chunk (SF_PRIVATE *psf, uint32_t chunklen) +{ char buffer [512] ; + uint32_t thisread, bytesread = 0, dword, sampler_data, loop_count, actually_loop_count = 0 ; + uint32_t note, pitch, start, end, type = -1, count ; + int j, k ; + + chunklen += (chunklen & 1) ; + + bytesread += psf_binheader_readf (psf, "4", &dword) ; + psf_log_printf (psf, " Manufacturer : %X\n", dword) ; + + bytesread += psf_binheader_readf (psf, "4", &dword) ; + psf_log_printf (psf, " Product : %u\n", dword) ; + + bytesread += psf_binheader_readf (psf, "4", &dword) ; + psf_log_printf (psf, " Period : %u nsec\n", dword) ; + + bytesread += psf_binheader_readf (psf, "4", ¬e) ; + psf_log_printf (psf, " Midi Note : %u\n", note) ; + + bytesread += psf_binheader_readf (psf, "4", &pitch) ; + if (pitch != 0) + { snprintf (buffer, sizeof (buffer), "%f", + (1.0 * 0x80000000) / ((uint32_t) pitch)) ; + psf_log_printf (psf, " Pitch Fract. : %s\n", buffer) ; + } + else + psf_log_printf (psf, " Pitch Fract. : 0\n") ; + + bytesread += psf_binheader_readf (psf, "4", &dword) ; + psf_log_printf (psf, " SMPTE Format : %u\n", dword) ; + + bytesread += psf_binheader_readf (psf, "4", &dword) ; + snprintf (buffer, sizeof (buffer), "%02"PRIu32 ":%02"PRIu32 ":%02"PRIu32 + " %02"PRIu32 "", (dword >> 24) & 0x7F, (dword >> 16) & 0x7F, + (dword >> 8) & 0x7F, dword & 0x7F) ; + psf_log_printf (psf, " SMPTE Offset : %s\n", buffer) ; + + bytesread += psf_binheader_readf (psf, "4", &loop_count) ; + psf_log_printf (psf, " Loop Count : %u\n", loop_count) ; + + if (loop_count == 0 && chunklen == bytesread) + return 0 ; + + /* Sampler Data holds the number of data bytes after the CUE chunks which + ** is not actually CUE data. Display value after CUE data. + */ + bytesread += psf_binheader_readf (psf, "4", &sampler_data) ; + + if (psf->instrument) + { psf_log_printf (psf, " Found more than one SMPL chunk, using last one.\n") ; + free (psf->instrument) ; + psf->instrument = NULL ; + } ; + if ((psf->instrument = psf_instrument_alloc ()) == NULL) + return SFE_MALLOC_FAILED ; + + psf->instrument->loop_count = loop_count ; + + for (j = 0 ; loop_count > 0 && chunklen - bytesread >= 24 ; j ++) + { if ((thisread = psf_binheader_readf (psf, "4", &dword)) == 0) + break ; + bytesread += thisread ; + psf_log_printf (psf, " Cue ID : %2u", dword) ; + + bytesread += psf_binheader_readf (psf, "4", &type) ; + psf_log_printf (psf, " Type : %2u", type) ; + + bytesread += psf_binheader_readf (psf, "4", &start) ; + psf_log_printf (psf, " Start : %5u", start) ; + + bytesread += psf_binheader_readf (psf, "4", &end) ; + psf_log_printf (psf, " End : %5u", end) ; + + bytesread += psf_binheader_readf (psf, "4", &dword) ; + psf_log_printf (psf, " Fraction : %5u", dword) ; + + bytesread += psf_binheader_readf (psf, "4", &count) ; + psf_log_printf (psf, " Count : %5u\n", count) ; + + if (j < ARRAY_LEN (psf->instrument->loops)) + { psf->instrument->loops [j].start = start ; + psf->instrument->loops [j].end = end + 1 ; + psf->instrument->loops [j].count = count ; + + switch (type) + { case 0 : + psf->instrument->loops [j].mode = SF_LOOP_FORWARD ; + break ; + case 1 : + psf->instrument->loops [j].mode = SF_LOOP_ALTERNATING ; + break ; + case 2 : + psf->instrument->loops [j].mode = SF_LOOP_BACKWARD ; + break ; + default: + psf->instrument->loops [j].mode = SF_LOOP_NONE ; + break ; + } ; + } ; + actually_loop_count ++ ; + } ; + + if (actually_loop_count > ARRAY_LEN (psf->instrument->loops)) + { + psf_log_printf (psf, "*** Warning, actual Loop Points count exceeds %u, changing Loop Count from %u to %u\n", ARRAY_LEN (psf->instrument->loops), loop_count, ARRAY_LEN (psf->instrument->loops)) ; + psf->instrument->loop_count = ARRAY_LEN (psf->instrument->loops) ; + } + else if (loop_count != actually_loop_count) + { psf_log_printf (psf, "*** Warning, actual Loop Points count != Loop Count, changing Loop Count from %u to %u\n", loop_count, actually_loop_count) ; + psf->instrument->loop_count = actually_loop_count ; + } ; + + if (chunklen - bytesread == 0) + { if (sampler_data != 0) + psf_log_printf (psf, " Sampler Data : %u (should be 0)\n", sampler_data) ; + else + psf_log_printf (psf, " Sampler Data : %u\n", sampler_data) ; + } + else + { if (sampler_data != chunklen - bytesread) + { psf_log_printf (psf, " Sampler Data : %u (should have been %u)\n", sampler_data, chunklen - bytesread) ; + sampler_data = chunklen - bytesread ; + } + else + psf_log_printf (psf, " Sampler Data : %u\n", sampler_data) ; + + psf_log_printf (psf, " ") ; + for (k = 0 ; k < (int) sampler_data ; k++) + { char ch ; + + if (k > 0 && (k % 20) == 0) + psf_log_printf (psf, "\n ") ; + + if ((thisread = psf_binheader_readf (psf, "1", &ch)) == 0) + break ; + bytesread += thisread ; + psf_log_printf (psf, "%02X ", ch & 0xFF) ; + } ; + + psf_log_printf (psf, "\n") ; + } ; + + psf->instrument->basenote = note ; + psf->instrument->detune = (int8_t) (pitch / (0x40000000 / 25.0) + 0.5) ; + psf->instrument->gain = 1 ; + psf->instrument->velocity_lo = psf->instrument->key_lo = 0 ; + psf->instrument->velocity_hi = psf->instrument->key_hi = 127 ; + + return 0 ; +} /* wav_read_smpl_chunk */ + +/* +** The acid chunk goes a little something like this: +** +** 4 bytes 'acid' +** 4 bytes (int) length of chunk starting at next byte +** +** 4 bytes (int) type of file: +** this appears to be a bit mask,however some combinations +** are probably impossible and/or qualified as "errors" +** +** 0x01 On: One Shot Off: Loop +** 0x02 On: Root note is Set Off: No root +** 0x04 On: Stretch is On, Off: Strech is OFF +** 0x08 On: Disk Based Off: Ram based +** 0x10 On: ?????????? Off: ????????? (Acidizer puts that ON) +** +** 2 bytes (short) root note +** if type 0x10 is OFF : [C,C#,(...),B] -> [0x30 to 0x3B] +** if type 0x10 is ON : [C,C#,(...),B] -> [0x3C to 0x47] +** (both types fit on same MIDI pitch albeit different octaves, so who cares) +** +** 2 bytes (short) ??? always set to 0x8000 +** 4 bytes (float) ??? seems to be always 0 +** 4 bytes (int) number of beats +** 2 bytes (short) meter denominator //always 4 in SF/ACID +** 2 bytes (short) meter numerator //always 4 in SF/ACID +** //are we sure about the order?? usually its num/denom +** 4 bytes (float) tempo +** +*/ + +static int +wav_read_acid_chunk (SF_PRIVATE *psf, uint32_t chunklen) +{ char buffer [512] ; + uint32_t bytesread = 0 ; + int beats, flags ; + short rootnote, q1, meter_denom, meter_numer ; + float q2, tempo ; + + chunklen += (chunklen & 1) ; + + bytesread += psf_binheader_readf (psf, "422f", &flags, &rootnote, &q1, &q2) ; + + snprintf (buffer, sizeof (buffer), "%f", q2) ; + + psf_log_printf (psf, " Flags : 0x%04x (%s,%s,%s,%s,%s)\n", flags, + (flags & 0x01) ? "OneShot" : "Loop", + (flags & 0x02) ? "RootNoteValid" : "RootNoteInvalid", + (flags & 0x04) ? "StretchOn" : "StretchOff", + (flags & 0x08) ? "DiskBased" : "RAMBased", + (flags & 0x10) ? "??On" : "??Off") ; + + psf_log_printf (psf, " Root note : 0x%x\n ???? : 0x%04x\n ???? : %s\n", + rootnote, q1, buffer) ; + + bytesread += psf_binheader_readf (psf, "422f", &beats, &meter_denom, &meter_numer, &tempo) ; + snprintf (buffer, sizeof (buffer), "%f", tempo) ; + psf_log_printf (psf, " Beats : %d\n Meter : %d/%d\n Tempo : %s\n", + beats, meter_numer, meter_denom, buffer) ; + + psf_binheader_readf (psf, "j", chunklen - bytesread) ; + + if (psf->loop_info) + { psf_log_printf (psf, " Found existing loop info, using last one.\n") ; + free (psf->loop_info) ; + psf->loop_info = NULL ; + } ; + if ((psf->loop_info = calloc (1, sizeof (SF_LOOP_INFO))) == NULL) + return SFE_MALLOC_FAILED ; + + psf->loop_info->time_sig_num = meter_numer ; + psf->loop_info->time_sig_den = meter_denom ; + psf->loop_info->loop_mode = (flags & 0x01) ? SF_LOOP_NONE : SF_LOOP_FORWARD ; + psf->loop_info->num_beats = beats ; + psf->loop_info->bpm = tempo ; + psf->loop_info->root_key = (flags & 0x02) ? rootnote : -1 ; + + return 0 ; +} /* wav_read_acid_chunk */ + +/*============================================================================== +*/ + +static int +wav_set_chunk (SF_PRIVATE *psf, const SF_CHUNK_INFO * chunk_info) +{ return psf_save_write_chunk (&psf->wchunks, chunk_info) ; +} /* wav_set_chunk */ + +static SF_CHUNK_ITERATOR * +wav_next_chunk_iterator (SF_PRIVATE *psf, SF_CHUNK_ITERATOR * iterator) +{ return psf_next_chunk_iterator (&psf->rchunks, iterator) ; +} /* wav_next_chunk_iterator */ + +static int +wav_get_chunk_size (SF_PRIVATE *psf, const SF_CHUNK_ITERATOR * iterator, SF_CHUNK_INFO * chunk_info) +{ int indx ; + + if ((indx = psf_find_read_chunk_iterator (&psf->rchunks, iterator)) < 0) + return SFE_UNKNOWN_CHUNK ; + + chunk_info->datalen = psf->rchunks.chunks [indx].len ; + + return SFE_NO_ERROR ; +} /* wav_get_chunk_size */ + +static int +wav_get_chunk_data (SF_PRIVATE *psf, const SF_CHUNK_ITERATOR * iterator, SF_CHUNK_INFO * chunk_info) +{ int indx ; + sf_count_t pos ; + + if ((indx = psf_find_read_chunk_iterator (&psf->rchunks, iterator)) < 0) + return SFE_UNKNOWN_CHUNK ; + + if (chunk_info->data == NULL) + return SFE_BAD_CHUNK_DATA_PTR ; + + chunk_info->id_size = psf->rchunks.chunks [indx].id_size ; + memcpy (chunk_info->id, psf->rchunks.chunks [indx].id, sizeof (chunk_info->id) / sizeof (*chunk_info->id)) ; + + pos = psf_ftell (psf) ; + psf_fseek (psf, psf->rchunks.chunks [indx].offset, SEEK_SET) ; + psf_fread (chunk_info->data, SF_MIN (chunk_info->datalen, psf->rchunks.chunks [indx].len), 1, psf) ; + psf_fseek (psf, pos, SEEK_SET) ; + + return SFE_NO_ERROR ; +} /* wav_get_chunk_data */ diff --git a/extern/libsndfile-modified/src/wavlike.c b/extern/libsndfile-modified/src/wavlike.c new file mode 100644 index 000000000..7acdc80e7 --- /dev/null +++ b/extern/libsndfile-modified/src/wavlike.c @@ -0,0 +1,1371 @@ +/* +** Copyright (C) 1999-2020 Erik de Castro Lopo +** Copyright (C) 2004-2005 David Viens +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" +#include "wavlike.h" + + +#define WAV_BEXT_MIN_CHUNK_SIZE 602 +#define WAV_BEXT_MAX_CHUNK_SIZE (10 * 1024) + +#define WAV_CART_MIN_CHUNK_SIZE 2048 +#define WAV_CART_MAX_CHUNK_SIZE 0xffffffff + + +static int exif_subchunk_parse (SF_PRIVATE *psf, uint32_t length) ; + + +/* Known WAVEFORMATEXTENSIBLE GUIDS. */ +static const EXT_SUBFORMAT MSGUID_SUBTYPE_PCM = +{ 0x00000001, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } +} ; + +static const EXT_SUBFORMAT MSGUID_SUBTYPE_MS_ADPCM = +{ 0x00000002, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } +} ; + +static const EXT_SUBFORMAT MSGUID_SUBTYPE_IEEE_FLOAT = +{ 0x00000003, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } +} ; + +static const EXT_SUBFORMAT MSGUID_SUBTYPE_ALAW = +{ 0x00000006, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } +} ; + +static const EXT_SUBFORMAT MSGUID_SUBTYPE_MULAW = +{ 0x00000007, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } +} ; + +/* +** the next two are from +** http://dream.cs.bath.ac.uk/researchdev/wave-ex/bformat.html +*/ + +static const EXT_SUBFORMAT MSGUID_SUBTYPE_AMBISONIC_B_FORMAT_PCM = +{ 0x00000001, 0x0721, 0x11d3, { 0x86, 0x44, 0xc8, 0xc1, 0xca, 0x00, 0x00, 0x00 } +} ; + +static const EXT_SUBFORMAT MSGUID_SUBTYPE_AMBISONIC_B_FORMAT_IEEE_FLOAT = +{ 0x00000003, 0x0721, 0x11d3, { 0x86, 0x44, 0xc8, 0xc1, 0xca, 0x00, 0x00, 0x00 } +} ; + + +#if 0 +/* maybe interesting one day to read the following through sf_read_raw */ +/* http://www.bath.ac.uk/~masrwd/pvocex/pvocex.html */ +static const EXT_SUBFORMAT MSGUID_SUBTYPE_PVOCEX = +{ 0x8312b9c2, 0x2e6e, 0x11d4, { 0xa8, 0x24, 0xde, 0x5b, 0x96, 0xc3, 0xab, 0x21 } +} ; +#endif + +/* This stores which bit in dwChannelMask maps to which channel */ +static const struct chanmap_s +{ int id ; + const char * name ; +} channel_mask_bits [] = +{ /* WAVEFORMATEXTENSIBLE doesn't distuingish FRONT_LEFT from LEFT */ + { SF_CHANNEL_MAP_LEFT, "L" }, + { SF_CHANNEL_MAP_RIGHT, "R" }, + { SF_CHANNEL_MAP_CENTER, "C" }, + { SF_CHANNEL_MAP_LFE, "LFE" }, + { SF_CHANNEL_MAP_REAR_LEFT, "Ls" }, + { SF_CHANNEL_MAP_REAR_RIGHT, "Rs" }, + { SF_CHANNEL_MAP_FRONT_LEFT_OF_CENTER, "Lc" }, + { SF_CHANNEL_MAP_FRONT_RIGHT_OF_CENTER, "Rc" }, + { SF_CHANNEL_MAP_REAR_CENTER, "Cs" }, + { SF_CHANNEL_MAP_SIDE_LEFT, "Sl" }, + { SF_CHANNEL_MAP_SIDE_RIGHT, "Sr" }, + { SF_CHANNEL_MAP_TOP_CENTER, "Tc" }, + { SF_CHANNEL_MAP_TOP_FRONT_LEFT, "Tfl" }, + { SF_CHANNEL_MAP_TOP_FRONT_CENTER, "Tfc" }, + { SF_CHANNEL_MAP_TOP_FRONT_RIGHT, "Tfr" }, + { SF_CHANNEL_MAP_TOP_REAR_LEFT, "Trl" }, + { SF_CHANNEL_MAP_TOP_REAR_CENTER, "Trc" }, + { SF_CHANNEL_MAP_TOP_REAR_RIGHT, "Trr" }, +} ; + +/*------------------------------------------------------------------------------ + * Private static functions. + */ + +static int +wavex_guid_equal (const EXT_SUBFORMAT * first, const EXT_SUBFORMAT * second) +{ return !memcmp (first, second, sizeof (EXT_SUBFORMAT)) ; +} /* wavex_guid_equal */ + + + +int +wavlike_read_fmt_chunk (SF_PRIVATE *psf, int fmtsize) +{ WAVLIKE_PRIVATE * wpriv ; + WAV_FMT *wav_fmt ; + int bytesread, k, bytespersec = 0 ; + + if ((wpriv = psf->container_data) == NULL) + return SFE_INTERNAL ; + wav_fmt = &wpriv->wav_fmt ; + + memset (wav_fmt, 0, sizeof (WAV_FMT)) ; + + if (fmtsize < 16) + return SFE_WAV_FMT_SHORT ; + + /* assume psf->rwf_endian is already properly set */ + + /* Read the minimal WAV file header here. */ + bytesread = psf_binheader_readf (psf, "224422", + &(wav_fmt->format), &(wav_fmt->min.channels), + &(wav_fmt->min.samplerate), &(wav_fmt->min.bytespersec), + &(wav_fmt->min.blockalign), &(wav_fmt->min.bitwidth)) ; + + psf_log_printf (psf, " Format : 0x%X => %s\n", wav_fmt->format, wavlike_format_str (wav_fmt->format)) ; + psf_log_printf (psf, " Channels : %d\n", wav_fmt->min.channels) ; + psf_log_printf (psf, " Sample Rate : %d\n", wav_fmt->min.samplerate) ; + + if (wav_fmt->format == WAVE_FORMAT_PCM && wav_fmt->min.blockalign == 0 + && wav_fmt->min.bitwidth > 0 && wav_fmt->min.channels > 0) + { wav_fmt->min.blockalign = wav_fmt->min.bitwidth / 8 + (wav_fmt->min.bitwidth % 8 > 0 ? 1 : 0) ; + wav_fmt->min.blockalign *= wav_fmt->min.channels ; + psf_log_printf (psf, " Block Align : 0 (should be %d)\n", wav_fmt->min.blockalign) ; + } + else + psf_log_printf (psf, " Block Align : %d\n", wav_fmt->min.blockalign) ; + + if (wav_fmt->format == WAVE_FORMAT_PCM && wav_fmt->min.bitwidth == 24 && + wav_fmt->min.blockalign == 4 * wav_fmt->min.channels) + { psf_log_printf (psf, " Bit Width : 24\n") ; + + psf_log_printf (psf, "\n" + " Ambiguous information in 'fmt ' chunk. Possibile file types:\n" + " 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" + "\n") ; + + wpriv->fmt_is_broken = 1 ; + } + else if (wav_fmt->min.bitwidth == 0) + { switch (wav_fmt->format) + { case WAVE_FORMAT_GSM610 : + case WAVE_FORMAT_IPP_ITU_G_723_1 : + case WAVE_FORMAT_MPEGLAYER3 : + psf_log_printf (psf, " Bit Width : %d\n", wav_fmt->min.bitwidth) ; + break ; + default : + psf_log_printf (psf, " Bit Width : %d (should not be 0)\n", wav_fmt->min.bitwidth) ; + } + } + else + { switch (wav_fmt->format) + { case WAVE_FORMAT_GSM610 : + case WAVE_FORMAT_IPP_ITU_G_723_1 : + case WAVE_FORMAT_MPEGLAYER3 : + psf_log_printf (psf, " Bit Width : %d (should be 0)\n", wav_fmt->min.bitwidth) ; + break ; + default : + psf_log_printf (psf, " Bit Width : %d\n", wav_fmt->min.bitwidth) ; + } + } ; + + psf->sf.samplerate = wav_fmt->min.samplerate ; + psf->sf.frames = 0 ; /* Correct this when reading data chunk. */ + psf->sf.channels = wav_fmt->min.channels ; + + switch (wav_fmt->format) + { case WAVE_FORMAT_PCM : + case WAVE_FORMAT_IEEE_FLOAT : + bytespersec = wav_fmt->min.samplerate * wav_fmt->min.blockalign ; + if (wav_fmt->min.bytespersec != (unsigned) bytespersec) + psf_log_printf (psf, " Bytes/sec : %d (should be %d)\n", wav_fmt->min.bytespersec, bytespersec) ; + else + psf_log_printf (psf, " Bytes/sec : %d\n", wav_fmt->min.bytespersec) ; + + psf->bytewidth = BITWIDTH2BYTES (wav_fmt->min.bitwidth) ; + break ; + + case WAVE_FORMAT_ALAW : + case WAVE_FORMAT_MULAW : + if (wav_fmt->min.bytespersec != wav_fmt->min.samplerate * wav_fmt->min.blockalign) + psf_log_printf (psf, " Bytes/sec : %d (should be %d)\n", wav_fmt->min.bytespersec, wav_fmt->min.samplerate * wav_fmt->min.blockalign) ; + else + psf_log_printf (psf, " Bytes/sec : %d\n", wav_fmt->min.bytespersec) ; + + psf->bytewidth = 1 ; + if (fmtsize >= 18) + { bytesread += psf_binheader_readf (psf, "2", &(wav_fmt->size20.extrabytes)) ; + psf_log_printf (psf, " Extra Bytes : %d\n", wav_fmt->size20.extrabytes) ; + } ; + break ; + + case WAVE_FORMAT_IMA_ADPCM : + if (wav_fmt->min.bitwidth != 4) + return SFE_WAV_ADPCM_NOT4BIT ; + if (wav_fmt->min.channels < 1 || wav_fmt->min.channels > 2) + return SFE_WAV_ADPCM_CHANNELS ; + + bytesread += psf_binheader_readf (psf, "22", &(wav_fmt->ima.extrabytes), &(wav_fmt->ima.samplesperblock)) ; + psf_log_printf (psf, " Extra Bytes : %d\n", wav_fmt->ima.extrabytes) ; + if (wav_fmt->ima.samplesperblock < 1) + { psf_log_printf (psf, " Samples/Block : %d (should be > 0)\n", wav_fmt->ima.samplesperblock) ; + return SFE_WAV_ADPCM_SAMPLES ; + } + else + psf_log_printf (psf, " Samples/Block : %d\n", wav_fmt->ima.samplesperblock) ; + + bytespersec = (wav_fmt->ima.samplerate * wav_fmt->ima.blockalign) / wav_fmt->ima.samplesperblock ; + if (wav_fmt->ima.bytespersec != (unsigned) bytespersec) + psf_log_printf (psf, " Bytes/sec : %d (should be %d)\n", wav_fmt->ima.bytespersec, bytespersec) ; + else + psf_log_printf (psf, " Bytes/sec : %d\n", wav_fmt->ima.bytespersec) ; + + break ; + + case WAVE_FORMAT_MS_ADPCM : + if (wav_fmt->msadpcm.bitwidth != 4) + return SFE_WAV_ADPCM_NOT4BIT ; + if (wav_fmt->msadpcm.channels < 1 || wav_fmt->msadpcm.channels > 2) + return SFE_WAV_ADPCM_CHANNELS ; + + bytesread += psf_binheader_readf (psf, "222", &(wav_fmt->msadpcm.extrabytes), + &(wav_fmt->msadpcm.samplesperblock), &(wav_fmt->msadpcm.numcoeffs)) ; + + psf_log_printf (psf, " Extra Bytes : %d\n", wav_fmt->msadpcm.extrabytes) ; + if (wav_fmt->ima.samplesperblock < 1) + { psf_log_printf (psf, " Samples/Block : %d (should be > 0)\n", wav_fmt->ima.samplesperblock) ; + return SFE_WAV_ADPCM_SAMPLES ; + } + else + psf_log_printf (psf, " Samples/Block : %d\n", wav_fmt->ima.samplesperblock) ; + + bytespersec = (wav_fmt->min.samplerate * wav_fmt->min.blockalign) / wav_fmt->msadpcm.samplesperblock ; + if (wav_fmt->min.bytespersec == (unsigned) bytespersec) + psf_log_printf (psf, " Bytes/sec : %d\n", wav_fmt->min.bytespersec) ; + else if (wav_fmt->min.bytespersec == (wav_fmt->min.samplerate / wav_fmt->msadpcm.samplesperblock) * wav_fmt->min.blockalign) + psf_log_printf (psf, " Bytes/sec : %d (should be %d (MS BUG!))\n", wav_fmt->min.bytespersec, bytespersec) ; + else + psf_log_printf (psf, " Bytes/sec : %d (should be %d)\n", wav_fmt->min.bytespersec, bytespersec) ; + + if (wav_fmt->msadpcm.numcoeffs > ARRAY_LEN (wav_fmt->msadpcm.coeffs)) + { psf_log_printf (psf, " No. of Coeffs : %d (should be <= %d)\n", wav_fmt->msadpcm.numcoeffs, ARRAY_LEN (wav_fmt->msadpcm.coeffs)) ; + wav_fmt->msadpcm.numcoeffs = ARRAY_LEN (wav_fmt->msadpcm.coeffs) ; + } + else + psf_log_printf (psf, " No. of Coeffs : %d\n", wav_fmt->msadpcm.numcoeffs) ; + + psf_log_printf (psf, " Index Coeffs1 Coeffs2\n") ; + for (k = 0 ; k < wav_fmt->msadpcm.numcoeffs ; k++) + { char buffer [128] ; + + bytesread += + psf_binheader_readf (psf, "22", &(wav_fmt->msadpcm.coeffs [k].coeff1), &(wav_fmt->msadpcm.coeffs [k].coeff2)) ; + snprintf (buffer, sizeof (buffer), " %2d %7d %7d\n", k, wav_fmt->msadpcm.coeffs [k].coeff1, wav_fmt->msadpcm.coeffs [k].coeff2) ; + psf_log_printf (psf, buffer) ; + } ; + break ; + + case WAVE_FORMAT_GSM610 : + if (wav_fmt->gsm610.channels != 1 || wav_fmt->gsm610.blockalign != 65) + return SFE_WAV_GSM610_FORMAT ; + + bytesread += + psf_binheader_readf (psf, "22", &(wav_fmt->gsm610.extrabytes), &(wav_fmt->gsm610.samplesperblock)) ; + + if (wav_fmt->gsm610.samplesperblock != 320) + return SFE_WAV_GSM610_FORMAT ; + + bytespersec = (wav_fmt->gsm610.samplerate * wav_fmt->gsm610.blockalign) / wav_fmt->gsm610.samplesperblock ; + if (wav_fmt->gsm610.bytespersec != (unsigned) bytespersec) + psf_log_printf (psf, " Bytes/sec : %d (should be %d)\n", wav_fmt->gsm610.bytespersec, bytespersec) ; + else + psf_log_printf (psf, " Bytes/sec : %d\n", wav_fmt->gsm610.bytespersec) ; + + psf_log_printf (psf, " Extra Bytes : %d\n", wav_fmt->gsm610.extrabytes) ; + psf_log_printf (psf, " Samples/Block : %d\n", wav_fmt->gsm610.samplesperblock) ; + break ; + + case WAVE_FORMAT_MPEGLAYER3 : + bytesread += psf_binheader_readf (psf, "24222", &(wav_fmt->mpeg3.extrabytes), + &(wav_fmt->mpeg3.id), &(wav_fmt->mpeg3.flags), &(wav_fmt->mpeg3.blocksize), + &(wav_fmt->mpeg3.samplesperblock), &(wav_fmt->mpeg3.codecdelay)) ; + + psf_log_printf (psf, " Bytes/sec : %d\n", wav_fmt->mpeg3.bytespersec) ; + psf_log_printf (psf, " Extra Bytes : %d\n", wav_fmt->mpeg3.extrabytes) ; + if (wav_fmt->mpeg3.id != 1) + psf_log_printf (psf, " ID : %d (unknown, should be 1)\n", wav_fmt->mpeg3.id) ; + else + psf_log_printf (psf, " ID : MPEGLAYER3_ID_MPEG\n") ; + psf_log_printf (psf, " Flags : 0x%08x\n", wav_fmt->mpeg3.flags) ; + psf_log_printf (psf, " Block Size : %d\n", wav_fmt->mpeg3.blocksize) ; + psf_log_printf (psf, " Samples/Block : %d\n", wav_fmt->mpeg3.samplesperblock) ; + psf_log_printf (psf, " Codec Delay : %d samples\n", wav_fmt->mpeg3.codecdelay) ; + break ; + + case WAVE_FORMAT_EXTENSIBLE : + if (wav_fmt->ext.bytespersec != wav_fmt->ext.samplerate * wav_fmt->ext.blockalign) + psf_log_printf (psf, " Bytes/sec : %d (should be %d)\n", wav_fmt->ext.bytespersec, wav_fmt->ext.samplerate * wav_fmt->ext.blockalign) ; + else + psf_log_printf (psf, " Bytes/sec : %d\n", wav_fmt->ext.bytespersec) ; + + bytesread += + psf_binheader_readf (psf, "224", &(wav_fmt->ext.extrabytes), &(wav_fmt->ext.validbits), + &(wav_fmt->ext.channelmask)) ; + + psf_log_printf (psf, " Valid Bits : %d\n", wav_fmt->ext.validbits) ; + + if (wav_fmt->ext.channelmask == 0) + psf_log_printf (psf, " Channel Mask : 0x0 (should not be zero)\n") ; + else + { char buffer [512] ; + unsigned bit ; + + wpriv->wavex_channelmask = wav_fmt->ext.channelmask ; + + /* It's probably wise to ignore the channel mask if it is all zero */ + free (psf->channel_map) ; + + if ((psf->channel_map = calloc (psf->sf.channels, sizeof (psf->channel_map [0]))) == NULL) + return SFE_MALLOC_FAILED ; + + /* Terminate the buffer we're going to append_snprintf into. */ + buffer [0] = 0 ; + + for (bit = k = 0 ; bit < ARRAY_LEN (channel_mask_bits) && k < psf->sf.channels ; bit++) + { + if (wav_fmt->ext.channelmask & (1 << bit)) + { if (k > psf->sf.channels) + { psf_log_printf (psf, "*** More channel map bits than there are channels.\n") ; + break ; + } ; + + psf->channel_map [k++] = channel_mask_bits [bit].id ; + append_snprintf (buffer, sizeof (buffer), "%s, ", channel_mask_bits [bit].name) ; + } ; + } ; + + /* Remove trailing ", ". */ + bit = strlen (buffer) ; + if (bit >= 2) + { buffer [--bit] = 0 ; + buffer [--bit] = 0 ; + } ; + + if (k != psf->sf.channels) + { psf_log_printf (psf, " Channel Mask : 0x%X\n", wav_fmt->ext.channelmask) ; + psf_log_printf (psf, "*** Less channel map bits than there are channels.\n") ; + } + else + psf_log_printf (psf, " Channel Mask : 0x%X (%s)\n", wav_fmt->ext.channelmask, buffer) ; + } ; + + bytesread += psf_binheader_readf (psf, "422", &(wav_fmt->ext.esf.esf_field1), &(wav_fmt->ext.esf.esf_field2), &(wav_fmt->ext.esf.esf_field3)) ; + + /* compare the esf_fields with each known GUID? and print? */ + psf_log_printf (psf, " Subformat\n") ; + psf_log_printf (psf, " esf_field1 : 0x%X\n", wav_fmt->ext.esf.esf_field1) ; + psf_log_printf (psf, " esf_field2 : 0x%X\n", wav_fmt->ext.esf.esf_field2) ; + psf_log_printf (psf, " esf_field3 : 0x%X\n", wav_fmt->ext.esf.esf_field3) ; + psf_log_printf (psf, " esf_field4 : ") ; + for (k = 0 ; k < 8 ; k++) + { bytesread += psf_binheader_readf (psf, "1", &(wav_fmt->ext.esf.esf_field4 [k])) ; + psf_log_printf (psf, "0x%X ", wav_fmt->ext.esf.esf_field4 [k] & 0xFF) ; + } ; + psf_log_printf (psf, "\n") ; + psf->bytewidth = BITWIDTH2BYTES (wav_fmt->ext.bitwidth) ; + + /* Compare GUIDs for known ones. */ + if (wavex_guid_equal (&wav_fmt->ext.esf, &MSGUID_SUBTYPE_PCM)) + { psf->sf.format = SF_FORMAT_WAVEX | u_bitwidth_to_subformat (psf->bytewidth * 8) ; + psf_log_printf (psf, " format : pcm\n") ; + } + else if (wavex_guid_equal (&wav_fmt->ext.esf, &MSGUID_SUBTYPE_MS_ADPCM)) + { psf->sf.format = (SF_FORMAT_WAVEX | SF_FORMAT_MS_ADPCM) ; + psf_log_printf (psf, " format : ms adpcm\n") ; + } + else if (wavex_guid_equal (&wav_fmt->ext.esf, &MSGUID_SUBTYPE_IEEE_FLOAT)) + { psf->sf.format = SF_FORMAT_WAVEX | ((psf->bytewidth == 8) ? SF_FORMAT_DOUBLE : SF_FORMAT_FLOAT) ; + psf_log_printf (psf, " format : IEEE float\n") ; + } + else if (wavex_guid_equal (&wav_fmt->ext.esf, &MSGUID_SUBTYPE_ALAW)) + { psf->sf.format = (SF_FORMAT_WAVEX | SF_FORMAT_ALAW) ; + psf_log_printf (psf, " format : A-law\n") ; + } + else if (wavex_guid_equal (&wav_fmt->ext.esf, &MSGUID_SUBTYPE_MULAW)) + { psf->sf.format = (SF_FORMAT_WAVEX | SF_FORMAT_ULAW) ; + psf_log_printf (psf, " format : u-law\n") ; + } + else if (wavex_guid_equal (&wav_fmt->ext.esf, &MSGUID_SUBTYPE_AMBISONIC_B_FORMAT_PCM)) + { psf->sf.format = SF_FORMAT_WAVEX | u_bitwidth_to_subformat (psf->bytewidth * 8) ; + psf_log_printf (psf, " format : pcm (Ambisonic B)\n") ; + wpriv->wavex_ambisonic = SF_AMBISONIC_B_FORMAT ; + } + else if (wavex_guid_equal (&wav_fmt->ext.esf, &MSGUID_SUBTYPE_AMBISONIC_B_FORMAT_IEEE_FLOAT)) + { psf->sf.format = SF_FORMAT_WAVEX | ((psf->bytewidth == 8) ? SF_FORMAT_DOUBLE : SF_FORMAT_FLOAT) ; + psf_log_printf (psf, " format : IEEE float (Ambisonic B)\n") ; + wpriv->wavex_ambisonic = SF_AMBISONIC_B_FORMAT ; + } + else + return SFE_UNIMPLEMENTED ; + + break ; + + case WAVE_FORMAT_G721_ADPCM : + psf_log_printf (psf, " Bytes/sec : %d\n", wav_fmt->g72x.bytespersec) ; + if (fmtsize >= 20) + { bytesread += psf_binheader_readf (psf, "22", &(wav_fmt->g72x.extrabytes), &(wav_fmt->g72x.auxblocksize)) ; + if (wav_fmt->g72x.extrabytes == 0) + psf_log_printf (psf, " Extra Bytes : %d (should be 2)\n", wav_fmt->g72x.extrabytes) ; + else + psf_log_printf (psf, " Extra Bytes : %d\n", wav_fmt->g72x.extrabytes) ; + psf_log_printf (psf, " Aux Blk Size : %d\n", wav_fmt->g72x.auxblocksize) ; + } + else if (fmtsize == 18) + { bytesread += psf_binheader_readf (psf, "2", &(wav_fmt->g72x.extrabytes)) ; + psf_log_printf (psf, " Extra Bytes : %d%s\n", wav_fmt->g72x.extrabytes, wav_fmt->g72x.extrabytes != 0 ? " (should be 0)" : "") ; + } + else + psf_log_printf (psf, "*** 'fmt ' chunk should be bigger than this!\n") ; + break ; + + case WAVE_FORMAT_NMS_VBXADPCM : + if (wav_fmt->min.channels != 1 || wav_fmt->min.bitwidth < 2 || wav_fmt->min.bitwidth * 20 + 2 != wav_fmt->min.blockalign) + return SFE_WAV_NMS_FORMAT ; + + bytespersec = (wav_fmt->min.samplerate * wav_fmt->min.blockalign) / 160 ; + if (wav_fmt->min.bytespersec == (unsigned) bytespersec) + psf_log_printf (psf, " Bytes/sec : %d\n", wav_fmt->min.bytespersec) ; + else + psf_log_printf (psf, " Bytes/sec : %d (should be %d)\n", wav_fmt->min.bytespersec, bytespersec) ; + if (fmtsize >= 18) + { bytesread += psf_binheader_readf (psf, "2", &(wav_fmt->size20.extrabytes)) ; + psf_log_printf (psf, " Extra Bytes : %d\n", wav_fmt->size20.extrabytes) ; + } ; + break ; + + default : + psf_log_printf (psf, "*** No 'fmt ' chunk dumper for this format!\n") ; + return SFE_WAV_BAD_FMT ; + } ; + + if (bytesread > fmtsize) + { psf_log_printf (psf, "*** wavlike_read_fmt_chunk (bytesread > fmtsize)\n") ; + return SFE_WAV_BAD_FMT ; + } + else + psf_binheader_readf (psf, "j", fmtsize - bytesread) ; + + psf->blockwidth = wav_fmt->min.channels * psf->bytewidth ; + + return 0 ; +} /* wavlike_read_fmt_chunk */ + +void +wavlike_write_guid (SF_PRIVATE *psf, const EXT_SUBFORMAT * subformat) +{ + psf_binheader_writef (psf, "422b", BHW4 (subformat->esf_field1), + BHW2 (subformat->esf_field2), BHW2 (subformat->esf_field3), + BHWv (subformat->esf_field4), BHWz (8)) ; +} /* wavlike_write_guid */ + + +int +wavlike_gen_channel_mask (const int *chan_map, int channels) +{ int chan, mask = 0, bit = -1, last_bit = -1 ; + + if (chan_map == NULL) + return 0 ; + + for (chan = 0 ; chan < channels ; chan ++) + { int k ; + + for (k = bit + 1 ; k < ARRAY_LEN (channel_mask_bits) ; k++) + if (chan_map [chan] == channel_mask_bits [k].id) + { bit = k ; + break ; + } ; + + /* Check for bad sequence. */ + if (bit <= last_bit) + return 0 ; + + mask += 1 << bit ; + last_bit = bit ; + } ; + + return mask ; +} /* wavlike_gen_channel_mask */ + +void +wavlike_analyze (SF_PRIVATE *psf) +{ unsigned char buffer [4096] ; + AUDIO_DETECT ad ; + int format = 0 ; + + if (psf->is_pipe) + { psf_log_printf (psf, "*** Error : Reading from a pipe. Can't analyze data section to figure out real data format.\n\n") ; + return ; + } ; + + psf_log_printf (psf, "---------------------------------------------------\n" + "Format is known to be broken. Using detection code.\n") ; + + /* Code goes here. */ + ad.endianness = SF_ENDIAN_LITTLE ; + ad.channels = psf->sf.channels ; + + psf_fseek (psf, 3 * 4 * 50, SEEK_SET) ; + + while (psf_fread (buffer, 1, sizeof (buffer), psf) == sizeof (buffer)) + { format = audio_detect (psf, &ad, buffer, sizeof (buffer)) ; + if (format != 0) + break ; + } ; + + /* Seek to start of DATA section. */ + psf_fseek (psf, psf->dataoffset, SEEK_SET) ; + + if (format == 0) + { psf_log_printf (psf, "wavlike_analyze : detection failed.\n") ; + return ; + } ; + + switch (format) + { case SF_FORMAT_PCM_32 : + case SF_FORMAT_FLOAT : + psf_log_printf (psf, "wavlike_analyze : found format : 0x%X\n", format) ; + psf->sf.format = (psf->sf.format & ~SF_FORMAT_SUBMASK) + format ; + psf->bytewidth = 4 ; + psf->blockwidth = psf->sf.channels * psf->bytewidth ; + break ; + + case SF_FORMAT_PCM_24 : + psf_log_printf (psf, "wavlike_analyze : found format : 0x%X\n", format) ; + psf->sf.format = (psf->sf.format & ~SF_FORMAT_SUBMASK) + format ; + psf->bytewidth = 3 ; + psf->blockwidth = psf->sf.channels * psf->bytewidth ; + break ; + + default : + psf_log_printf (psf, "wavlike_analyze : unhandled format : 0x%X\n", format) ; + break ; + } ; + + return ; +} /* wavlike_analyze */ + +/*============================================================================== +*/ + +typedef struct +{ int ID ; + const char *name ; +} WAV_FORMAT_DESC ; + +#define STR(x) #x +#define FORMAT_TYPE(x) { x, STR (x) } + +static WAV_FORMAT_DESC wave_descs [] = +{ FORMAT_TYPE (WAVE_FORMAT_PCM), + FORMAT_TYPE (WAVE_FORMAT_MS_ADPCM), + FORMAT_TYPE (WAVE_FORMAT_IEEE_FLOAT), + FORMAT_TYPE (WAVE_FORMAT_VSELP), + FORMAT_TYPE (WAVE_FORMAT_IBM_CVSD), + FORMAT_TYPE (WAVE_FORMAT_ALAW), + FORMAT_TYPE (WAVE_FORMAT_MULAW), + FORMAT_TYPE (WAVE_FORMAT_OKI_ADPCM), + FORMAT_TYPE (WAVE_FORMAT_IMA_ADPCM), + FORMAT_TYPE (WAVE_FORMAT_MEDIASPACE_ADPCM), + FORMAT_TYPE (WAVE_FORMAT_SIERRA_ADPCM), + FORMAT_TYPE (WAVE_FORMAT_G723_ADPCM), + FORMAT_TYPE (WAVE_FORMAT_DIGISTD), + FORMAT_TYPE (WAVE_FORMAT_DIGIFIX), + FORMAT_TYPE (WAVE_FORMAT_DIALOGIC_OKI_ADPCM), + FORMAT_TYPE (WAVE_FORMAT_MEDIAVISION_ADPCM), + FORMAT_TYPE (WAVE_FORMAT_CU_CODEC), + FORMAT_TYPE (WAVE_FORMAT_YAMAHA_ADPCM), + FORMAT_TYPE (WAVE_FORMAT_SONARC), + FORMAT_TYPE (WAVE_FORMAT_DSPGROUP_TRUESPEECH), + FORMAT_TYPE (WAVE_FORMAT_ECHOSC1), + FORMAT_TYPE (WAVE_FORMAT_AUDIOFILE_AF36), + FORMAT_TYPE (WAVE_FORMAT_APTX), + FORMAT_TYPE (WAVE_FORMAT_AUDIOFILE_AF10), + FORMAT_TYPE (WAVE_FORMAT_PROSODY_1612), + FORMAT_TYPE (WAVE_FORMAT_LRC), + FORMAT_TYPE (WAVE_FORMAT_DOLBY_AC2), + FORMAT_TYPE (WAVE_FORMAT_GSM610), + FORMAT_TYPE (WAVE_FORMAT_MSNAUDIO), + FORMAT_TYPE (WAVE_FORMAT_ANTEX_ADPCME), + FORMAT_TYPE (WAVE_FORMAT_CONTROL_RES_VQLPC), + FORMAT_TYPE (WAVE_FORMAT_DIGIREAL), + FORMAT_TYPE (WAVE_FORMAT_DIGIADPCM), + FORMAT_TYPE (WAVE_FORMAT_CONTROL_RES_CR10), + FORMAT_TYPE (WAVE_FORMAT_NMS_VBXADPCM), + FORMAT_TYPE (WAVE_FORMAT_ROLAND_RDAC), + FORMAT_TYPE (WAVE_FORMAT_ECHOSC3), + FORMAT_TYPE (WAVE_FORMAT_ROCKWELL_ADPCM), + FORMAT_TYPE (WAVE_FORMAT_ROCKWELL_DIGITALK), + FORMAT_TYPE (WAVE_FORMAT_XEBEC), + FORMAT_TYPE (WAVE_FORMAT_G721_ADPCM), + FORMAT_TYPE (WAVE_FORMAT_G728_CELP), + FORMAT_TYPE (WAVE_FORMAT_MSG723), + FORMAT_TYPE (WAVE_FORMAT_MPEG), + FORMAT_TYPE (WAVE_FORMAT_RT24), + FORMAT_TYPE (WAVE_FORMAT_PAC), + FORMAT_TYPE (WAVE_FORMAT_MPEGLAYER3), + FORMAT_TYPE (WAVE_FORMAT_LUCENT_G723), + FORMAT_TYPE (WAVE_FORMAT_CIRRUS), + FORMAT_TYPE (WAVE_FORMAT_ESPCM), + FORMAT_TYPE (WAVE_FORMAT_VOXWARE), + FORMAT_TYPE (WAVE_FORMAT_CANOPUS_ATRAC), + FORMAT_TYPE (WAVE_FORMAT_G726_ADPCM), + FORMAT_TYPE (WAVE_FORMAT_G722_ADPCM), + FORMAT_TYPE (WAVE_FORMAT_DSAT), + FORMAT_TYPE (WAVE_FORMAT_DSAT_DISPLAY), + FORMAT_TYPE (WAVE_FORMAT_VOXWARE_BYTE_ALIGNED), + FORMAT_TYPE (WAVE_FORMAT_VOXWARE_AC8), + FORMAT_TYPE (WAVE_FORMAT_VOXWARE_AC10), + FORMAT_TYPE (WAVE_FORMAT_VOXWARE_AC16), + FORMAT_TYPE (WAVE_FORMAT_VOXWARE_AC20), + FORMAT_TYPE (WAVE_FORMAT_VOXWARE_RT24), + FORMAT_TYPE (WAVE_FORMAT_VOXWARE_RT29), + FORMAT_TYPE (WAVE_FORMAT_VOXWARE_RT29HW), + FORMAT_TYPE (WAVE_FORMAT_VOXWARE_VR12), + FORMAT_TYPE (WAVE_FORMAT_VOXWARE_VR18), + FORMAT_TYPE (WAVE_FORMAT_VOXWARE_TQ40), + FORMAT_TYPE (WAVE_FORMAT_SOFTSOUND), + FORMAT_TYPE (WAVE_FORMAT_VOXARE_TQ60), + FORMAT_TYPE (WAVE_FORMAT_MSRT24), + FORMAT_TYPE (WAVE_FORMAT_G729A), + FORMAT_TYPE (WAVE_FORMAT_MVI_MV12), + FORMAT_TYPE (WAVE_FORMAT_DF_G726), + FORMAT_TYPE (WAVE_FORMAT_DF_GSM610), + FORMAT_TYPE (WAVE_FORMAT_ONLIVE), + FORMAT_TYPE (WAVE_FORMAT_SBC24), + FORMAT_TYPE (WAVE_FORMAT_DOLBY_AC3_SPDIF), + FORMAT_TYPE (WAVE_FORMAT_ZYXEL_ADPCM), + FORMAT_TYPE (WAVE_FORMAT_PHILIPS_LPCBB), + FORMAT_TYPE (WAVE_FORMAT_PACKED), + FORMAT_TYPE (WAVE_FORMAT_RHETOREX_ADPCM), + FORMAT_TYPE (IBM_FORMAT_MULAW), + FORMAT_TYPE (IBM_FORMAT_ALAW), + FORMAT_TYPE (IBM_FORMAT_ADPCM), + FORMAT_TYPE (WAVE_FORMAT_VIVO_G723), + FORMAT_TYPE (WAVE_FORMAT_VIVO_SIREN), + FORMAT_TYPE (WAVE_FORMAT_DIGITAL_G723), + FORMAT_TYPE (WAVE_FORMAT_CREATIVE_ADPCM), + FORMAT_TYPE (WAVE_FORMAT_CREATIVE_FASTSPEECH8), + FORMAT_TYPE (WAVE_FORMAT_CREATIVE_FASTSPEECH10), + FORMAT_TYPE (WAVE_FORMAT_QUARTERDECK), + FORMAT_TYPE (WAVE_FORMAT_FM_TOWNS_SND), + FORMAT_TYPE (WAVE_FORMAT_BZV_DIGITAL), + FORMAT_TYPE (WAVE_FORMAT_VME_VMPCM), + FORMAT_TYPE (WAVE_FORMAT_OLIGSM), + FORMAT_TYPE (WAVE_FORMAT_OLIADPCM), + FORMAT_TYPE (WAVE_FORMAT_OLICELP), + FORMAT_TYPE (WAVE_FORMAT_OLISBC), + FORMAT_TYPE (WAVE_FORMAT_OLIOPR), + FORMAT_TYPE (WAVE_FORMAT_LH_CODEC), + FORMAT_TYPE (WAVE_FORMAT_NORRIS), + FORMAT_TYPE (WAVE_FORMAT_SOUNDSPACE_MUSICOMPRESS), + FORMAT_TYPE (WAVE_FORMAT_DVM), + FORMAT_TYPE (WAVE_FORMAT_INTERWAV_VSC112), + FORMAT_TYPE (WAVE_FORMAT_IPP_ITU_G_723_1), + FORMAT_TYPE (WAVE_FORMAT_EXTENSIBLE), +} ; + +char const* +wavlike_format_str (int k) +{ int lower, upper, mid ; + + lower = -1 ; + upper = sizeof (wave_descs) / sizeof (WAV_FORMAT_DESC) ; + + /* binary search */ + if ((wave_descs [0].ID <= k) && (k <= wave_descs [upper - 1].ID)) + { + while (lower + 1 < upper) + { mid = (upper + lower) / 2 ; + + if (k == wave_descs [mid].ID) + return wave_descs [mid].name ; + if (k < wave_descs [mid].ID) + upper = mid ; + else + lower = mid ; + } ; + } ; + + return "Unknown format" ; +} /* wavlike_format_str */ + +int +wavlike_srate2blocksize (int srate_chan_product) +{ if (srate_chan_product < 12000) + return 256 ; + if (srate_chan_product < 23000) + return 512 ; + if (srate_chan_product < 44000) + return 1024 ; + return 2048 ; +} /* srate2blocksize */ + +int +wavlike_read_bext_chunk (SF_PRIVATE *psf, uint32_t chunksize) +{ + SF_BROADCAST_INFO_16K * b ; + uint32_t bytes = 0 ; + + if (chunksize < WAV_BEXT_MIN_CHUNK_SIZE) + { psf_log_printf (psf, "bext : %u (should be >= %d)\n", chunksize, WAV_BEXT_MIN_CHUNK_SIZE) ; + psf_binheader_readf (psf, "j", chunksize) ; + return 0 ; + } ; + + if (chunksize > WAV_BEXT_MAX_CHUNK_SIZE) + { psf_log_printf (psf, "bext : %u (should be < %d)\n", chunksize, WAV_BEXT_MAX_CHUNK_SIZE) ; + psf_binheader_readf (psf, "j", chunksize) ; + return 0 ; + } ; + + if (chunksize >= sizeof (SF_BROADCAST_INFO_16K)) + { psf_log_printf (psf, "bext : %u too big to be handled\n", chunksize) ; + psf_binheader_readf (psf, "j", chunksize) ; + return 0 ; + } ; + + psf_log_printf (psf, "bext : %u\n", chunksize) ; + + if (!psf->broadcast_16k) + { psf->broadcast_16k = broadcast_var_alloc () ; + if (!psf->broadcast_16k) + { psf->error = SFE_MALLOC_FAILED ; + return psf->error ; + } + } + else + { psf_log_printf (psf, "bext : found more than one bext chunk, using last one.\n") ; + memset (psf->broadcast_16k, 0, sizeof (SF_BROADCAST_INFO_16K)) ; + } + + b = psf->broadcast_16k ; + + bytes += psf_binheader_readf (psf, "b", b->description, sizeof (b->description)) ; + bytes += psf_binheader_readf (psf, "b", b->originator, sizeof (b->originator)) ; + bytes += psf_binheader_readf (psf, "b", b->originator_reference, sizeof (b->originator_reference)) ; + bytes += psf_binheader_readf (psf, "b", b->origination_date, sizeof (b->origination_date)) ; + bytes += psf_binheader_readf (psf, "b", b->origination_time, sizeof (b->origination_time)) ; + bytes += psf_binheader_readf (psf, "442", &b->time_reference_low, &b->time_reference_high, &b->version) ; + bytes += psf_binheader_readf (psf, "b", &b->umid, sizeof (b->umid)) ; + bytes += psf_binheader_readf (psf, "22", &b->loudness_value, &b->loudness_range) ; + bytes += psf_binheader_readf (psf, "222", &b->max_true_peak_level, &b->max_momentary_loudness, &b->max_shortterm_loudness) ; + bytes += psf_binheader_readf (psf, "j", 180) ; + + if (chunksize > WAV_BEXT_MIN_CHUNK_SIZE) + { /* File has coding history data. */ + + b->coding_history_size = chunksize - WAV_BEXT_MIN_CHUNK_SIZE ; + + /* We do not parse the coding history */ + bytes += psf_binheader_readf (psf, "b", BHWv (b->coding_history), BHWz (b->coding_history_size)) ; + } ; + + if (bytes < chunksize) + psf_binheader_readf (psf, "j", BHWj (chunksize - bytes)) ; + + return 0 ; +} /* wavlike_read_bext_chunk */ + +int +wavlike_write_bext_chunk (SF_PRIVATE *psf) +{ SF_BROADCAST_INFO_16K *b ; + + if (psf->broadcast_16k == NULL) + return -1 ; + + b = psf->broadcast_16k ; + + psf_binheader_writef (psf, "m4", BHWm (bext_MARKER), BHW4 (WAV_BEXT_MIN_CHUNK_SIZE + b->coding_history_size)) ; + + /* + ** Note that it is very important that the field widths of the SF_BROADCAST_INFO + ** struct match those of the bext chunk fields. + */ + + psf_binheader_writef (psf, "b", BHWv (b->description), BHWz (sizeof (b->description))) ; + psf_binheader_writef (psf, "b", BHWv (b->originator), BHWz (sizeof (b->originator))) ; + psf_binheader_writef (psf, "b", BHWv (b->originator_reference), BHWz (sizeof (b->originator_reference))) ; + psf_binheader_writef (psf, "b", BHWv (b->origination_date), BHWz (sizeof (b->origination_date))) ; + psf_binheader_writef (psf, "b", BHWv (b->origination_time), BHWz (sizeof (b->origination_time))) ; + psf_binheader_writef (psf, "442", BHW4 (b->time_reference_low), BHW4 (b->time_reference_high), BHW2 (b->version)) ; + psf_binheader_writef (psf, "b", BHWv (b->umid), BHWz (sizeof (b->umid))) ; + psf_binheader_writef (psf, "22", BHW2 (b->loudness_value), BHW2 (b->loudness_range)) ; + psf_binheader_writef (psf, "222", BHW2 (b->max_true_peak_level), BHW2 (b->max_momentary_loudness), BHW2 (b->max_shortterm_loudness)) ; + psf_binheader_writef (psf, "z", BHWz (180)) ; + + if (b->coding_history_size > 0) + psf_binheader_writef (psf, "b", BHWv (b->coding_history), BHWz (b->coding_history_size)) ; + + return 0 ; +} /* wavlike_write_bext_chunk */ + +int +wavlike_read_cart_chunk (SF_PRIVATE *psf, uint32_t chunksize) +{ SF_CART_INFO_16K *c ; + uint32_t bytes = 0 ; + int k ; + + if (chunksize < WAV_CART_MIN_CHUNK_SIZE) + { psf_log_printf (psf, "cart : %u (should be >= %d)\n", chunksize, WAV_CART_MIN_CHUNK_SIZE) ; + psf_binheader_readf (psf, "j", chunksize) ; + return 0 ; + } ; + if (chunksize > WAV_CART_MAX_CHUNK_SIZE) + { psf_log_printf (psf, "cart : %u (should be < %d)\n", chunksize, WAV_CART_MAX_CHUNK_SIZE) ; + psf_binheader_readf (psf, "j", chunksize) ; + return 0 ; + } ; + + /* + ** SF_CART_INFO_16K has an extra field 'tag_text_size' that isn't part + ** of the chunk, so don't include it in the size check. + */ + if (chunksize >= sizeof (SF_CART_INFO_16K) - 4) + { psf_log_printf (psf, "cart : %u too big to be handled\n", chunksize) ; + psf_binheader_readf (psf, "j", chunksize) ; + return 0 ; + } ; + + psf_log_printf (psf, "cart : %u\n", chunksize) ; + + if (psf->cart_16k) + { psf_log_printf (psf, " Found more than one cart chunk, using last one.\n") ; + free (psf->cart_16k) ; + psf->cart_16k = NULL ; + } ; + + if ((psf->cart_16k = cart_var_alloc ()) == NULL) + { psf->error = SFE_MALLOC_FAILED ; + return psf->error ; + } ; + + c = psf->cart_16k ; + bytes += psf_binheader_readf (psf, "b", c->version, sizeof (c->version)) ; + bytes += psf_binheader_readf (psf, "b", c->title, sizeof (c->title)) ; + bytes += psf_binheader_readf (psf, "b", c->artist, sizeof (c->artist)) ; + bytes += psf_binheader_readf (psf, "b", c->cut_id, sizeof (c->cut_id)) ; + bytes += psf_binheader_readf (psf, "b", c->client_id, sizeof (c->client_id)) ; + bytes += psf_binheader_readf (psf, "b", c->category, sizeof (c->category)) ; + bytes += psf_binheader_readf (psf, "b", c->classification, sizeof (c->classification)) ; + bytes += psf_binheader_readf (psf, "b", c->out_cue, sizeof (c->out_cue)) ; + bytes += psf_binheader_readf (psf, "b", c->start_date, sizeof (c->start_date)) ; + bytes += psf_binheader_readf (psf, "b", c->start_time, sizeof (c->start_time)) ; + bytes += psf_binheader_readf (psf, "b", c->end_date, sizeof (c->end_date)) ; + bytes += psf_binheader_readf (psf, "b", c->end_time, sizeof (c->end_time)) ; + bytes += psf_binheader_readf (psf, "b", c->producer_app_id, sizeof (c->producer_app_id)) ; + bytes += psf_binheader_readf (psf, "b", c->producer_app_version, sizeof (c->producer_app_version)) ; + bytes += psf_binheader_readf (psf, "b", c->user_def, sizeof (c->user_def)) ; + bytes += psf_binheader_readf (psf, "e4", &c->level_reference, sizeof (c->level_reference)) ; + + for (k = 0 ; k < ARRAY_LEN (c->post_timers) ; k++) + bytes += psf_binheader_readf (psf, "b4", &c->post_timers [k].usage, make_size_t (4), &c->post_timers [k].value) ; + + bytes += psf_binheader_readf (psf, "b", c->reserved, sizeof (c->reserved)) ; + bytes += psf_binheader_readf (psf, "b", c->url, sizeof (c->url)) ; + + if (chunksize > WAV_CART_MIN_CHUNK_SIZE) + { /* File has tag text. */ + c->tag_text_size = chunksize - WAV_CART_MIN_CHUNK_SIZE ; + bytes += psf_binheader_readf (psf, "b", c->tag_text, make_size_t (c->tag_text_size)) ; + } ; + + if (bytes < chunksize) + psf_log_printf (psf, " %d trailing bytes in cart chunk.\n", chunksize - bytes) ; + + return 0 ; +} /* wavlike_read_cart_chunk */ + +int +wavlike_write_cart_chunk (SF_PRIVATE *psf) +{ SF_CART_INFO_16K *c ; + int k ; + + if (psf->cart_16k == NULL) + return -1 ; + + c = psf->cart_16k ; + psf_binheader_writef (psf, "m4", BHWm (cart_MARKER), BHW4 (WAV_CART_MIN_CHUNK_SIZE + c->tag_text_size)) ; + /* + ** Note that it is very important that the field widths of the SF_CART_INFO + ** struct match those of the cart chunk fields. + */ + psf_binheader_writef (psf, "b", BHWv (c->version), BHWz (sizeof (c->version))) ; + psf_binheader_writef (psf, "b", BHWv (c->title), BHWz (sizeof (c->title))) ; + psf_binheader_writef (psf, "b", BHWv (c->artist), BHWz (sizeof (c->artist))) ; + psf_binheader_writef (psf, "b", BHWv (c->cut_id), BHWz (sizeof (c->cut_id))) ; + psf_binheader_writef (psf, "b", BHWv (c->client_id), BHWz (sizeof (c->client_id))) ; + psf_binheader_writef (psf, "b", BHWv (c->category), BHWz (sizeof (c->category))) ; + psf_binheader_writef (psf, "b", BHWv (c->classification), BHWz (sizeof (c->classification))) ; + psf_binheader_writef (psf, "b", BHWv (c->out_cue), BHWz (sizeof (c->out_cue))) ; + psf_binheader_writef (psf, "b", BHWv (c->start_date), BHWz (sizeof (c->start_date))) ; + psf_binheader_writef (psf, "b", BHWv (c->start_time), BHWz (sizeof (c->start_time))) ; + psf_binheader_writef (psf, "b", BHWv (c->end_date), BHWz (sizeof (c->end_date))) ; + psf_binheader_writef (psf, "b", BHWv (c->end_time), BHWz (sizeof (c->end_time))) ; + psf_binheader_writef (psf, "b", BHWv (c->producer_app_id), BHWz (sizeof (c->producer_app_id))) ; + psf_binheader_writef (psf, "b", BHWv (c->producer_app_version), BHWz (sizeof (c->producer_app_version))) ; + psf_binheader_writef (psf, "b", BHWv (c->user_def), BHWz (sizeof (c->user_def))) ; + psf_binheader_writef (psf, "e4", BHW4 (c->level_reference)) ; + + for (k = 0 ; k < ARRAY_LEN (c->post_timers) ; k++) + psf_binheader_writef (psf, "b4", BHWv (c->post_timers [k].usage), BHWz (4), BHW4 (c->post_timers [k].value)) ; + + psf_binheader_writef (psf, "z", BHWz (sizeof (c->reserved))) ; // just write zeros, we don't have any other use for it + psf_binheader_writef (psf, "b", BHWv (c->url), BHWz (sizeof (c->url))) ; + + if (c->tag_text_size > 0) + psf_binheader_writef (psf, "b", BHWv (c->tag_text), BHWz (c->tag_text_size)) ; + + return 0 ; +} /* wavlike_write_cart_chunk */ + +int +wavlike_subchunk_parse (SF_PRIVATE *psf, int chunk, uint32_t chunk_length) +{ sf_count_t current_pos ; + char buffer [2048] ; + uint32_t chunk_size, bytesread = 0 ; + + current_pos = psf_fseek (psf, 0, SEEK_CUR) ; + + if (chunk_length <= 8) + { /* This case is for broken files generated by PEAK. */ + psf_log_printf (psf, "%M : %u (weird length)\n", chunk, chunk_length) ; + psf_binheader_readf (psf, "mj", &chunk, chunk_length - 4) ; + psf_log_printf (psf, " %M\n", chunk) ; + return 0 ; + } ; + + if (current_pos + chunk_length > psf->filelength) + { psf_log_printf (psf, "%M : %u (should be %d)\n", chunk, chunk_length, (int) (psf->filelength - current_pos)) ; + chunk_length = psf->filelength - current_pos ; + } + else + psf_log_printf (psf, "%M : %u\n", chunk, chunk_length) ; + + while (bytesread < chunk_length) + { uint32_t thisread ; + + if ((thisread = psf_binheader_readf (psf, "m", &chunk)) == 0) + break ; + bytesread += thisread ; + + switch (chunk) + { case adtl_MARKER : + case INFO_MARKER : + /* These markers don't contain anything, not even a chunk length. */ + psf_log_printf (psf, " %M\n", chunk) ; + continue ; + + case exif_MARKER : + psf_log_printf (psf, " %M\n", chunk) ; + if (chunk_length > bytesread) + bytesread += exif_subchunk_parse (psf, chunk_length - bytesread) ; + continue ; + + case data_MARKER : + psf_log_printf (psf, " %M inside a LIST block??? Backing out.\n", chunk) ; + /* Jump back four bytes and return to caller. */ + psf_binheader_readf (psf, "j", -4) ; + return 0 ; + + case 0 : + /* + ** Four zero bytes where a marker was expected. Assume this means + ** the rest of the chunk is garbage. + */ + psf_log_printf (psf, " *** Found weird-ass zero marker. Jumping to end of chunk.\n") ; + goto cleanup_subchunk_parse ; + + default : + break ; + } ; + + switch (chunk) + { case ISFT_MARKER : + case ICOP_MARKER : + case IARL_MARKER : + case IART_MARKER : + case ICMT_MARKER : + case ICRD_MARKER : + case IENG_MARKER : + case IGNR_MARKER : + case INAM_MARKER : + case IPRD_MARKER : + case ISBJ_MARKER : + case ISRC_MARKER : + case IAUT_MARKER : + case ITRK_MARKER : + bytesread += psf_binheader_readf (psf, "4", &chunk_size) ; + chunk_size += (chunk_size & 1) ; + if (chunk_size >= SIGNED_SIZEOF (buffer) || bytesread + chunk_size > chunk_length) + { psf_log_printf (psf, " *** %M : %u (too big)\n", chunk, chunk_size) ; + goto cleanup_subchunk_parse ; + } ; + + bytesread += psf_binheader_readf (psf, "b", buffer, chunk_size) ; + buffer [chunk_size] = 0 ; + psf_log_printf (psf, " %M : %s\n", chunk, buffer) ; + break ; + + case labl_MARKER : + { int mark_id ; + + bytesread += psf_binheader_readf (psf, "44", &chunk_size, &mark_id) ; + chunk_size -= 4 ; + chunk_size += (chunk_size & 1) ; + if (chunk_size < 1 || chunk_size >= SIGNED_SIZEOF (buffer) || bytesread + chunk_size > chunk_length) + { psf_log_printf (psf, " *** %M : %u (too big)\n", chunk, chunk_size) ; + goto cleanup_subchunk_parse ; + } ; + + bytesread += psf_binheader_readf (psf, "b", buffer, chunk_size) ; + buffer [chunk_size] = 0 ; + + if (mark_id < 10) /* avoid swamping log buffer with labels */ + psf_log_printf (psf, " %M : %u : %s\n", chunk, mark_id, buffer) ; + else if (mark_id == 10) + psf_log_printf (psf, " (Skipping)\n") ; + + if (psf->cues) + { unsigned int i = 0 ; + + /* find id to store label */ + while (i < psf->cues->cue_count && psf->cues->cue_points [i].indx != mark_id) + i++ ; + + if (i < psf->cues->cue_count) + memcpy (psf->cues->cue_points [i].name, buffer, sizeof (psf->cues->cue_points [i].name)) ; + } ; + } ; + break ; + + case DISP_MARKER : + case ltxt_MARKER : + case note_MARKER : + bytesread += psf_binheader_readf (psf, "4", &chunk_size) ; + chunk_size += (chunk_size & 1) ; + if (chunk_size >= SIGNED_SIZEOF (buffer) || bytesread + chunk_size > chunk_length) + { psf_log_printf (psf, " *** %M : %u (too big)\n", chunk, chunk_size) ; + goto cleanup_subchunk_parse ; + } ; + + psf_log_printf (psf, " %M : %u\n", chunk, chunk_size) ; + goto cleanup_subchunk_parse ; + + default : + bytesread += psf_binheader_readf (psf, "4", &chunk_size) ; + chunk_size += (chunk_size & 1) ; + if (bytesread + chunk_size > chunk_length) + { psf_log_printf (psf, " *** %M : %u (too big)\n", chunk, chunk_size) ; + goto cleanup_subchunk_parse ; + } + else + { psf_log_printf (psf, " %M : %u\n", chunk, chunk_size) ; + bytesread += psf_binheader_readf (psf, "j", chunk_size) ; + } ; + break ; + } ; + + switch (chunk) + { case ISFT_MARKER : + psf_store_string (psf, SF_STR_SOFTWARE, buffer) ; + break ; + case ICOP_MARKER : + psf_store_string (psf, SF_STR_COPYRIGHT, buffer) ; + break ; + case INAM_MARKER : + psf_store_string (psf, SF_STR_TITLE, buffer) ; + break ; + case IART_MARKER : + psf_store_string (psf, SF_STR_ARTIST, buffer) ; + break ; + case ICMT_MARKER : + psf_store_string (psf, SF_STR_COMMENT, buffer) ; + break ; + case ICRD_MARKER : + psf_store_string (psf, SF_STR_DATE, buffer) ; + break ; + case IGNR_MARKER : + psf_store_string (psf, SF_STR_GENRE, buffer) ; + break ; + case IPRD_MARKER : + psf_store_string (psf, SF_STR_ALBUM, buffer) ; + break ; + case ITRK_MARKER : + psf_store_string (psf, SF_STR_TRACKNUMBER, buffer) ; + break ; + } ; + } ; + +cleanup_subchunk_parse : + + if (chunk_length > bytesread) + bytesread += psf_binheader_readf (psf, "j", chunk_length - bytesread) ; + + return 0 ; +} /* wavlike_subchunk_parse */ + +void +wavlike_write_strings (SF_PRIVATE *psf, int location) +{ int k, prev_head_index, saved_head_index ; + + if (psf_location_string_count (psf, location) == 0) + return ; + + prev_head_index = psf->header.indx + 4 ; + + psf_binheader_writef (psf, "m4m", BHWm (LIST_MARKER), BHW4 (0xBADBAD), BHWm (INFO_MARKER)) ; + + for (k = 0 ; k < SF_MAX_STRINGS ; k++) + { if (psf->strings.data [k].type == 0) + break ; + if (psf->strings.data [k].type < 0 || psf->strings.data [k].flags != location) + continue ; + + switch (psf->strings.data [k].type) + { case SF_STR_SOFTWARE : + psf_binheader_writef (psf, "ms", BHWm (ISFT_MARKER), BHWs (psf->strings.storage + psf->strings.data [k].offset)) ; + break ; + + case SF_STR_TITLE : + psf_binheader_writef (psf, "ms", BHWm (INAM_MARKER), BHWs (psf->strings.storage + psf->strings.data [k].offset)) ; + break ; + + case SF_STR_COPYRIGHT : + psf_binheader_writef (psf, "ms", BHWm (ICOP_MARKER), BHWs (psf->strings.storage + psf->strings.data [k].offset)) ; + break ; + + case SF_STR_ARTIST : + psf_binheader_writef (psf, "ms", BHWm (IART_MARKER), BHWs (psf->strings.storage + psf->strings.data [k].offset)) ; + break ; + + case SF_STR_COMMENT : + psf_binheader_writef (psf, "ms", BHWm (ICMT_MARKER), BHWs (psf->strings.storage + psf->strings.data [k].offset)) ; + break ; + + case SF_STR_DATE : + psf_binheader_writef (psf, "ms", BHWm (ICRD_MARKER), BHWs (psf->strings.storage + psf->strings.data [k].offset)) ; + break ; + + case SF_STR_GENRE : + psf_binheader_writef (psf, "ms", BHWm (IGNR_MARKER), BHWs (psf->strings.storage + psf->strings.data [k].offset)) ; + break ; + + case SF_STR_ALBUM : + psf_binheader_writef (psf, "ms", BHWm (IPRD_MARKER), BHWs (psf->strings.storage + psf->strings.data [k].offset)) ; + break ; + + case SF_STR_TRACKNUMBER : + psf_binheader_writef (psf, "ms", BHWm (ITRK_MARKER), BHWs (psf->strings.storage + psf->strings.data [k].offset)) ; + break ; + + default : + break ; + } ; + } ; + + saved_head_index = psf->header.indx ; + psf->header.indx = prev_head_index ; + psf_binheader_writef (psf, "4", BHW4 (saved_head_index - prev_head_index - 4)) ; + psf->header.indx = saved_head_index ; + +} /* wavlike_write_strings */ + +int +wavlike_read_peak_chunk (SF_PRIVATE * psf, size_t chunk_size) +{ char buffer [256] ; + uint32_t uk ; + + if (chunk_size != WAVLIKE_PEAK_CHUNK_SIZE (psf->sf.channels)) + { psf_binheader_readf (psf, "j", chunk_size) ; + psf_log_printf (psf, "*** File PEAK chunk size doesn't fit with number of channels (%d).\n", psf->sf.channels) ; + return SFE_WAV_BAD_PEAK ; + } ; + + if (psf->peak_info) + { psf_log_printf (psf, "*** Found existing peak info, using last one.\n") ; + free (psf->peak_info) ; + psf->peak_info = NULL ; + } ; + if ((psf->peak_info = peak_info_calloc (psf->sf.channels)) == NULL) + return SFE_MALLOC_FAILED ; + + /* read in rest of PEAK chunk. */ + psf_binheader_readf (psf, "44", & (psf->peak_info->version), & (psf->peak_info->timestamp)) ; + + if (psf->peak_info->version != 1) + psf_log_printf (psf, " version : %d *** (should be version 1)\n", psf->peak_info->version) ; + else + psf_log_printf (psf, " version : %d\n", psf->peak_info->version) ; + + psf_log_printf (psf, " time stamp : %d\n", psf->peak_info->timestamp) ; + psf_log_printf (psf, " Ch Position Value\n") ; + + for (uk = 0 ; uk < (uint32_t) psf->sf.channels ; uk++) + { float value ; + uint32_t position ; + + psf_binheader_readf (psf, "f4", &value, &position) ; + psf->peak_info->peaks [uk].value = value ; + psf->peak_info->peaks [uk].position = position ; + + snprintf (buffer, sizeof (buffer), " %2d %-12" PRId64 " %g\n", + uk, psf->peak_info->peaks [uk].position, psf->peak_info->peaks [uk].value) ; + buffer [sizeof (buffer) - 1] = 0 ; + psf_log_printf (psf, "%s", buffer) ; + } ; + + return 0 ; +} /* wavlike_read_peak_chunk */ + +void +wavlike_write_peak_chunk (SF_PRIVATE * psf) +{ int k ; + + if (psf->peak_info == NULL) + return ; + + psf_binheader_writef (psf, "m4", BHWm (PEAK_MARKER), BHW4 (WAVLIKE_PEAK_CHUNK_SIZE (psf->sf.channels))) ; + psf_binheader_writef (psf, "44", BHW4 (1), BHW4 (time (NULL))) ; + for (k = 0 ; k < psf->sf.channels ; k++) + psf_binheader_writef (psf, "ft8", BHWf (psf->peak_info->peaks [k].value), BHW8 (psf->peak_info->peaks [k].position)) ; +} /* wavlike_write_peak_chunk */ + +/*============================================================================== +*/ + +static int +exif_fill_and_sink (SF_PRIVATE *psf, char* buf, size_t bufsz, size_t toread) +{ + size_t bytesread = 0 ; + + buf [0] = 0 ; + bufsz -= 1 ; + if (toread < bufsz) + bufsz = toread ; + bytesread = psf_binheader_readf (psf, "b", buf, bufsz) ; + buf [bufsz] = 0 ; + + if (bytesread == bufsz && toread > bufsz) + bytesread += psf_binheader_readf (psf, "j", toread - bufsz) ; + + return bytesread ; +} /* exif_fill_and_sink */ + +/* +** Exif specification for audio files, at JEITA CP-3451 Exif 2.2 section 5 +** (Exif Audio File Specification) http://www.exif.org/Exif2-2.PDF +*/ +static int +exif_subchunk_parse (SF_PRIVATE *psf, uint32_t length) +{ uint32_t marker, dword = 0, vmajor = -1, vminor = -1, bytesread = 0 ; + char buf [4096] ; + int thisread ; + + while (bytesread < length) + { + if ((thisread = psf_binheader_readf (psf, "m", &marker)) == 0) + break ; + bytesread += thisread ; + + switch (marker) + { + case 0 : /* camera padding? */ + break ; + + case ever_MARKER : + bytesread += psf_binheader_readf (psf, "j4", 4, &dword) ; + vmajor = 10 * (((dword >> 24) & 0xff) - '0') + (((dword >> 16) & 0xff) - '0') ; + vminor = 10 * (((dword >> 8) & 0xff) - '0') + ((dword & 0xff) - '0') ; + psf_log_printf (psf, " EXIF Version : %u.%02u\n", vmajor, vminor) ; + break ; + + case olym_MARKER : + bytesread += psf_binheader_readf (psf, "4", &dword) ; + psf_log_printf (psf, "%M : %u\n", marker, dword) ; + if (dword > length || bytesread + dword > length) + break ; + dword += (dword & 1) ; + bytesread += psf_binheader_readf (psf, "j", dword) ; + break ; + + case emnt_MARKER : /* design information: null-terminated string */ + case emdl_MARKER : /* model name ; null-terminated string */ + case ecor_MARKER : /* manufacturer: null-terminated string */ + case etim_MARKER : /* creation time: null-terminated string in the format "hour:minute:second.subsecond" */ + case erel_MARKER : /* relation info: null-terminated string (filename) */ + case eucm_MARKER : /* user comment: 4-byte size follows, then possibly unicode data */ + bytesread += psf_binheader_readf (psf, "4", &dword) ; + bytesread += sizeof (dword) ; + dword += (dword & 1) ; + + if (dword >= sizeof (buf)) + { psf_log_printf (psf, "*** Marker '%M' is too big %u\n\n", marker, dword) ; + return bytesread ; + } ; + + bytesread += exif_fill_and_sink (psf, buf, sizeof (buf), dword) ; + + /* BAD - don't know what's going on here -- maybe a bug in the camera */ + /* field should be NULL-terminated but there's no room for it with the reported number */ + /* example output: emdl : 8 (EX-Z1050) */ + if (marker == emdl_MARKER && dword == strlen (buf) /* should be >= strlen+1*/) + { psf_log_printf (psf, " *** field size too small for string (sinking 2 bytes)\n") ; + bytesread += psf_binheader_readf (psf, "j", 2) ; + } ; + + psf_log_printf (psf, " %M : %u (%s)\n", marker, dword, buf) ; + if (dword > length) + return bytesread ; + break ; + + default : + psf_log_printf (psf, " *** %M (%u): -- ignored --\n", marker, marker) ; + break ; + } ; + } ; + + return bytesread ; +} /* exif_subchunk_parse */ + +void +wavlike_write_custom_chunks (SF_PRIVATE * psf) +{ uint32_t k ; + + for (k = 0 ; k < psf->wchunks.used ; k++) + psf_binheader_writef (psf, "m4b", BHWm (psf->wchunks.chunks [k].mark32), BHW4 (psf->wchunks.chunks [k].len), + BHWv (psf->wchunks.chunks [k].data), BHWz (psf->wchunks.chunks [k].len)) ; + +} /* wavlike_write_custom_chunks */ diff --git a/extern/libsndfile-modified/src/wavlike.h b/extern/libsndfile-modified/src/wavlike.h new file mode 100644 index 000000000..686287d8a --- /dev/null +++ b/extern/libsndfile-modified/src/wavlike.h @@ -0,0 +1,374 @@ +/* +** Copyright (C) 1999-2016 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/* This file contains definitions commong to WAV and W64 files. */ + + +#ifndef WAVLIKE_H_INCLUDED +#define WAVLIKE_H_INCLUDED + +/*------------------------------------------------------------------------------ +** Chunk markers. +*/ + +#define adtl_MARKER MAKE_MARKER ('a', 'd', 't', 'l') +#define bext_MARKER MAKE_MARKER ('b', 'e', 'x', 't') +#define cart_MARKER MAKE_MARKER ('c', 'a', 'r', 't') +#define data_MARKER MAKE_MARKER ('d', 'a', 't', 'a') +#define labl_MARKER MAKE_MARKER ('l', 'a', 'b', 'l') +#define ltxt_MARKER MAKE_MARKER ('l', 't', 'x', 't') +#define note_MARKER MAKE_MARKER ('n', 'o', 't', 'e') +#define DISP_MARKER MAKE_MARKER ('D', 'I', 'S', 'P') +#define INFO_MARKER MAKE_MARKER ('I', 'N', 'F', 'O') +#define LIST_MARKER MAKE_MARKER ('L', 'I', 'S', 'T') +#define PAD_MARKER MAKE_MARKER ('P', 'A', 'D', ' ') +#define PEAK_MARKER MAKE_MARKER ('P', 'E', 'A', 'K') + +#define ISFT_MARKER MAKE_MARKER ('I', 'S', 'F', 'T') +#define ICRD_MARKER MAKE_MARKER ('I', 'C', 'R', 'D') +#define ICOP_MARKER MAKE_MARKER ('I', 'C', 'O', 'P') +#define IARL_MARKER MAKE_MARKER ('I', 'A', 'R', 'L') +#define IART_MARKER MAKE_MARKER ('I', 'A', 'R', 'T') +#define INAM_MARKER MAKE_MARKER ('I', 'N', 'A', 'M') +#define IENG_MARKER MAKE_MARKER ('I', 'E', 'N', 'G') +#define IGNR_MARKER MAKE_MARKER ('I', 'G', 'N', 'R') +#define ICOP_MARKER MAKE_MARKER ('I', 'C', 'O', 'P') +#define IPRD_MARKER MAKE_MARKER ('I', 'P', 'R', 'D') +#define ISRC_MARKER MAKE_MARKER ('I', 'S', 'R', 'C') +#define ISBJ_MARKER MAKE_MARKER ('I', 'S', 'B', 'J') +#define ICMT_MARKER MAKE_MARKER ('I', 'C', 'M', 'T') +#define IAUT_MARKER MAKE_MARKER ('I', 'A', 'U', 'T') +#define ITRK_MARKER MAKE_MARKER ('I', 'T', 'R', 'K') + +#define exif_MARKER MAKE_MARKER ('e', 'x', 'i', 'f') +#define ever_MARKER MAKE_MARKER ('e', 'v', 'e', 'r') +#define etim_MARKER MAKE_MARKER ('e', 't', 'i', 'm') +#define ecor_MARKER MAKE_MARKER ('e', 'c', 'o', 'r') +#define emdl_MARKER MAKE_MARKER ('e', 'm', 'd', 'l') +#define emnt_MARKER MAKE_MARKER ('e', 'm', 'n', 't') +#define erel_MARKER MAKE_MARKER ('e', 'r', 'e', 'l') +#define eucm_MARKER MAKE_MARKER ('e', 'u', 'c', 'm') +#define olym_MARKER MAKE_MARKER ('o', 'l', 'y', 'm') + +/*------------------------------------------------------------------------------ +** List of known WAV format tags +*/ + +enum +{ + /* keep sorted for wavlike_format_str() */ + WAVE_FORMAT_UNKNOWN = 0x0000, /* Microsoft Corporation */ + WAVE_FORMAT_PCM = 0x0001, /* Microsoft PCM format */ + WAVE_FORMAT_MS_ADPCM = 0x0002, /* Microsoft ADPCM */ + WAVE_FORMAT_IEEE_FLOAT = 0x0003, /* Micrososft 32 bit float format */ + WAVE_FORMAT_VSELP = 0x0004, /* Compaq Computer Corporation */ + WAVE_FORMAT_IBM_CVSD = 0x0005, /* IBM Corporation */ + WAVE_FORMAT_ALAW = 0x0006, /* Microsoft Corporation */ + WAVE_FORMAT_MULAW = 0x0007, /* Microsoft Corporation */ + WAVE_FORMAT_OKI_ADPCM = 0x0010, /* OKI */ + WAVE_FORMAT_IMA_ADPCM = 0x0011, /* Intel Corporation */ + WAVE_FORMAT_MEDIASPACE_ADPCM = 0x0012, /* Videologic */ + WAVE_FORMAT_SIERRA_ADPCM = 0x0013, /* Sierra Semiconductor Corp */ + WAVE_FORMAT_G723_ADPCM = 0x0014, /* Antex Electronics Corporation */ + WAVE_FORMAT_DIGISTD = 0x0015, /* DSP Solutions, Inc. */ + WAVE_FORMAT_DIGIFIX = 0x0016, /* DSP Solutions, Inc. */ + WAVE_FORMAT_DIALOGIC_OKI_ADPCM = 0x0017, /* Dialogic Corporation */ + WAVE_FORMAT_MEDIAVISION_ADPCM = 0x0018, /* Media Vision, Inc. */ + WAVE_FORMAT_CU_CODEC = 0x0019, /* Hewlett-Packard Company */ + WAVE_FORMAT_YAMAHA_ADPCM = 0x0020, /* Yamaha Corporation of America */ + WAVE_FORMAT_SONARC = 0x0021, /* Speech Compression */ + WAVE_FORMAT_DSPGROUP_TRUESPEECH = 0x0022, /* DSP Group, Inc */ + WAVE_FORMAT_ECHOSC1 = 0x0023, /* Echo Speech Corporation */ + WAVE_FORMAT_AUDIOFILE_AF36 = 0x0024, /* Audiofile, Inc. */ + WAVE_FORMAT_APTX = 0x0025, /* Audio Processing Technology */ + WAVE_FORMAT_AUDIOFILE_AF10 = 0x0026, /* Audiofile, Inc. */ + WAVE_FORMAT_PROSODY_1612 = 0x0027, /* Aculab plc */ + WAVE_FORMAT_LRC = 0x0028, /* Merging Technologies S.A. */ + WAVE_FORMAT_DOLBY_AC2 = 0x0030, /* Dolby Laboratories */ + WAVE_FORMAT_GSM610 = 0x0031, /* Microsoft Corporation */ + WAVE_FORMAT_MSNAUDIO = 0x0032, /* Microsoft Corporation */ + WAVE_FORMAT_ANTEX_ADPCME = 0x0033, /* Antex Electronics Corporation */ + WAVE_FORMAT_CONTROL_RES_VQLPC = 0x0034, /* Control Resources Limited */ + WAVE_FORMAT_DIGIREAL = 0x0035, /* DSP Solutions, Inc. */ + WAVE_FORMAT_DIGIADPCM = 0x0036, /* DSP Solutions, Inc. */ + WAVE_FORMAT_CONTROL_RES_CR10 = 0x0037, /* Control Resources Limited */ + WAVE_FORMAT_NMS_VBXADPCM = 0x0038, /* Natural MicroSystems */ + WAVE_FORMAT_ROLAND_RDAC = 0x0039, /* Roland */ + WAVE_FORMAT_ECHOSC3 = 0x003A, /* Echo Speech Corporation */ + WAVE_FORMAT_ROCKWELL_ADPCM = 0x003B, /* Rockwell International */ + WAVE_FORMAT_ROCKWELL_DIGITALK = 0x003C, /* Rockwell International */ + WAVE_FORMAT_XEBEC = 0x003D, /* Xebec Multimedia Solutions Limited */ + WAVE_FORMAT_G721_ADPCM = 0x0040, /* Antex Electronics Corporation */ + WAVE_FORMAT_G728_CELP = 0x0041, /* Antex Electronics Corporation */ + WAVE_FORMAT_MSG723 = 0x0042, /* Microsoft Corporation */ + WAVE_FORMAT_MPEG = 0x0050, /* Microsoft Corporation */ + WAVE_FORMAT_RT24 = 0x0052, /* InSoft Inc. */ + WAVE_FORMAT_PAC = 0x0053, /* InSoft Inc. */ + WAVE_FORMAT_MPEGLAYER3 = 0x0055, /* MPEG 3 Layer 1 */ + WAVE_FORMAT_LUCENT_G723 = 0x0059, /* Lucent Technologies */ + WAVE_FORMAT_CIRRUS = 0x0060, /* Cirrus Logic */ + WAVE_FORMAT_ESPCM = 0x0061, /* ESS Technology */ + WAVE_FORMAT_VOXWARE = 0x0062, /* Voxware Inc */ + WAVE_FORMAT_CANOPUS_ATRAC = 0x0063, /* Canopus, Co., Ltd. */ + WAVE_FORMAT_G726_ADPCM = 0x0064, /* APICOM */ + WAVE_FORMAT_G722_ADPCM = 0x0065, /* APICOM */ + WAVE_FORMAT_DSAT = 0x0066, /* Microsoft Corporation */ + WAVE_FORMAT_DSAT_DISPLAY = 0x0067, /* Microsoft Corporation */ + WAVE_FORMAT_VOXWARE_BYTE_ALIGNED = 0x0069, /* Voxware Inc. */ + WAVE_FORMAT_VOXWARE_AC8 = 0x0070, /* Voxware Inc. */ + WAVE_FORMAT_VOXWARE_AC10 = 0x0071, /* Voxware Inc. */ + WAVE_FORMAT_VOXWARE_AC16 = 0x0072, /* Voxware Inc. */ + WAVE_FORMAT_VOXWARE_AC20 = 0x0073, /* Voxware Inc. */ + WAVE_FORMAT_VOXWARE_RT24 = 0x0074, /* Voxware Inc. */ + WAVE_FORMAT_VOXWARE_RT29 = 0x0075, /* Voxware Inc. */ + WAVE_FORMAT_VOXWARE_RT29HW = 0x0076, /* Voxware Inc. */ + WAVE_FORMAT_VOXWARE_VR12 = 0x0077, /* Voxware Inc. */ + WAVE_FORMAT_VOXWARE_VR18 = 0x0078, /* Voxware Inc. */ + WAVE_FORMAT_VOXWARE_TQ40 = 0x0079, /* Voxware Inc. */ + WAVE_FORMAT_SOFTSOUND = 0x0080, /* Softsound, Ltd. */ + WAVE_FORMAT_VOXARE_TQ60 = 0x0081, /* Voxware Inc. */ + WAVE_FORMAT_MSRT24 = 0x0082, /* Microsoft Corporation */ + WAVE_FORMAT_G729A = 0x0083, /* AT&T Laboratories */ + WAVE_FORMAT_MVI_MV12 = 0x0084, /* Motion Pixels */ + WAVE_FORMAT_DF_G726 = 0x0085, /* DataFusion Systems (Pty) (Ltd) */ + WAVE_FORMAT_DF_GSM610 = 0x0086, /* DataFusion Systems (Pty) (Ltd) */ + /* removed because duplicate */ + /* WAVE_FORMAT_ISIAUDIO = 0x0088, */ /* Iterated Systems, Inc. */ + WAVE_FORMAT_ONLIVE = 0x0089, /* OnLive! Technologies, Inc. */ + WAVE_FORMAT_SBC24 = 0x0091, /* Siemens Business Communications Systems */ + WAVE_FORMAT_DOLBY_AC3_SPDIF = 0x0092, /* Sonic Foundry */ + WAVE_FORMAT_ZYXEL_ADPCM = 0x0097, /* ZyXEL Communications, Inc. */ + WAVE_FORMAT_PHILIPS_LPCBB = 0x0098, /* Philips Speech Processing */ + WAVE_FORMAT_PACKED = 0x0099, /* Studer Professional Audio AG */ + WAVE_FORMAT_RHETOREX_ADPCM = 0x0100, /* Rhetorex, Inc. */ + + /* removed because of the following */ + /* WAVE_FORMAT_IRAT = 0x0101,*/ /* BeCubed Software Inc. */ + + /* these three are unofficial */ + IBM_FORMAT_MULAW = 0x0101, /* IBM mu-law format */ + IBM_FORMAT_ALAW = 0x0102, /* IBM a-law format */ + IBM_FORMAT_ADPCM = 0x0103, /* IBM AVC Adaptive Differential PCM format */ + + WAVE_FORMAT_VIVO_G723 = 0x0111, /* Vivo Software */ + WAVE_FORMAT_VIVO_SIREN = 0x0112, /* Vivo Software */ + WAVE_FORMAT_DIGITAL_G723 = 0x0123, /* Digital Equipment Corporation */ + WAVE_FORMAT_CREATIVE_ADPCM = 0x0200, /* Creative Labs, Inc */ + WAVE_FORMAT_CREATIVE_FASTSPEECH8 = 0x0202, /* Creative Labs, Inc */ + WAVE_FORMAT_CREATIVE_FASTSPEECH10 = 0x0203, /* Creative Labs, Inc */ + WAVE_FORMAT_QUARTERDECK = 0x0220, /* Quarterdeck Corporation */ + WAVE_FORMAT_FM_TOWNS_SND = 0x0300, /* Fujitsu Corporation */ + WAVE_FORMAT_BZV_DIGITAL = 0x0400, /* Brooktree Corporation */ + WAVE_FORMAT_VME_VMPCM = 0x0680, /* AT&T Labs, Inc. */ + WAVE_FORMAT_OLIGSM = 0x1000, /* Ing C. Olivetti & C., S.p.A. */ + WAVE_FORMAT_OLIADPCM = 0x1001, /* Ing C. Olivetti & C., S.p.A. */ + WAVE_FORMAT_OLICELP = 0x1002, /* Ing C. Olivetti & C., S.p.A. */ + WAVE_FORMAT_OLISBC = 0x1003, /* Ing C. Olivetti & C., S.p.A. */ + WAVE_FORMAT_OLIOPR = 0x1004, /* Ing C. Olivetti & C., S.p.A. */ + WAVE_FORMAT_LH_CODEC = 0x1100, /* Lernout & Hauspie */ + WAVE_FORMAT_NORRIS = 0x1400, /* Norris Communications, Inc. */ + /* removed because duplicate */ + /* WAVE_FORMAT_ISIAUDIO = 0x1401, */ /* AT&T Labs, Inc. */ + WAVE_FORMAT_SOUNDSPACE_MUSICOMPRESS = 0x1500, /* AT&T Labs, Inc. */ + WAVE_FORMAT_DVM = 0x2000, /* FAST Multimedia AG */ + WAVE_FORMAT_INTERWAV_VSC112 = 0x7150, /* ????? */ + + WAVE_FORMAT_IPP_ITU_G_723_1 = 0x7230, /* Intel Performance Primitives g723 codec. */ + + WAVE_FORMAT_EXTENSIBLE = 0xFFFE +} ; + +typedef struct +{ unsigned short format ; + unsigned short channels ; + unsigned int samplerate ; + unsigned int bytespersec ; + unsigned short blockalign ; + unsigned short bitwidth ; +} MIN_WAV_FMT ; + +typedef struct +{ unsigned short format ; + unsigned short channels ; + unsigned int samplerate ; + unsigned int bytespersec ; + unsigned short blockalign ; + unsigned short bitwidth ; + unsigned short extrabytes ; + unsigned short dummy ; +} WAV_FMT_SIZE20 ; + +typedef struct +{ unsigned short format ; + unsigned short channels ; + unsigned int samplerate ; + unsigned int bytespersec ; + unsigned short blockalign ; + unsigned short bitwidth ; + unsigned short extrabytes ; + unsigned short samplesperblock ; + unsigned short numcoeffs ; + struct + { short coeff1 ; + short coeff2 ; + } coeffs [7] ; +} MS_ADPCM_WAV_FMT ; + +typedef struct +{ unsigned short format ; + unsigned short channels ; + unsigned int samplerate ; + unsigned int bytespersec ; + unsigned short blockalign ; + unsigned short bitwidth ; + unsigned short extrabytes ; + unsigned short samplesperblock ; +} IMA_ADPCM_WAV_FMT ; + +typedef struct +{ unsigned short format ; + unsigned short channels ; + unsigned int samplerate ; + unsigned int bytespersec ; + unsigned short blockalign ; + unsigned short bitwidth ; + unsigned short extrabytes ; + unsigned short auxblocksize ; +} G72x_ADPCM_WAV_FMT ; + + +typedef struct +{ unsigned short format ; + unsigned short channels ; + unsigned int samplerate ; + unsigned int bytespersec ; + unsigned short blockalign ; + unsigned short bitwidth ; + unsigned short extrabytes ; + unsigned short samplesperblock ; +} GSM610_WAV_FMT ; + +typedef struct +{ unsigned short format ; + unsigned short channels ; + unsigned int samplerate ; + unsigned int bytespersec ; + unsigned short blockalign ; + unsigned short bitwidth ; + unsigned short extrabytes ; + unsigned short id ; + unsigned int flags ; + unsigned short blocksize ; + unsigned short samplesperblock ; + unsigned short codecdelay ; +} MPEGLAYER3_WAV_FMT ; + +typedef struct +{ unsigned int esf_field1 ; + unsigned short esf_field2 ; + unsigned short esf_field3 ; + unsigned char esf_field4 [8] ; +} EXT_SUBFORMAT ; + +typedef struct +{ unsigned short format ; + unsigned short channels ; + unsigned int samplerate ; + unsigned int bytespersec ; + unsigned short blockalign ; + unsigned short bitwidth ; + unsigned short extrabytes ; + unsigned short validbits ; + unsigned int channelmask ; + EXT_SUBFORMAT esf ; +} EXTENSIBLE_WAV_FMT ; + +typedef union +{ unsigned short format ; + MIN_WAV_FMT min ; + IMA_ADPCM_WAV_FMT ima ; + MS_ADPCM_WAV_FMT msadpcm ; + G72x_ADPCM_WAV_FMT g72x ; + EXTENSIBLE_WAV_FMT ext ; + GSM610_WAV_FMT gsm610 ; + MPEGLAYER3_WAV_FMT mpeg3 ; + WAV_FMT_SIZE20 size20 ; + char padding [512] ; +} WAV_FMT ; + +typedef struct +{ int frames ; +} FACT_CHUNK ; + +typedef struct +{ /* For ambisonic commands */ + int wavex_ambisonic ; + unsigned wavex_channelmask ; + + /* Set to true when 'fmt ' chunk is ambiguous.*/ + int fmt_is_broken ; + WAV_FMT wav_fmt ; + + /* + ** Set to true when RF64 should be converted back to RIFF when writing the + ** header. + */ + int rf64_downgrade ; +} WAVLIKE_PRIVATE ; + +#define WAVLIKE_GSM610_BLOCKSIZE 65 +#define WAVLIKE_GSM610_SAMPLES 320 + +#define WAVLIKE_PEAK_CHUNK_SIZE(ch) (2 * sizeof (int) + ch * (sizeof (float) + sizeof (int))) + +/*------------------------------------------------------------------------------------ +** Functions defined in wav_ms_adpcm.c +*/ + +#define WAVLIKE_MSADPCM_ADAPT_COEFF_COUNT 7 + +void wavlike_msadpcm_write_adapt_coeffs (SF_PRIVATE *psf) ; + +/*------------------------------------------------------------------------------------ +** Functions defined in wavlike.c +*/ + +char const* wavlike_format_str (int k) ; + +int wavlike_srate2blocksize (int srate_chan_product) ; +int wavlike_read_fmt_chunk (SF_PRIVATE *psf, int fmtsize) ; +void wavlike_write_guid (SF_PRIVATE *psf, const EXT_SUBFORMAT * subformat) ; +void wavlike_analyze (SF_PRIVATE *psf) ; +int wavlike_gen_channel_mask (const int *chan_map, int channels) ; + +int wavlike_read_bext_chunk (SF_PRIVATE *psf, uint32_t chunksize) ; +int wavlike_write_bext_chunk (SF_PRIVATE *psf) ; + +int wavlike_read_cart_chunk (SF_PRIVATE *psf, uint32_t chunksize) ; +int wavlike_write_cart_chunk (SF_PRIVATE *psf) ; + +int wavlike_subchunk_parse (SF_PRIVATE *psf, int chunk, uint32_t length) ; +void wavlike_write_strings (SF_PRIVATE *psf, int location) ; + +int wavlike_read_peak_chunk (SF_PRIVATE * psf, size_t chunk_size) ; +void wavlike_write_peak_chunk (SF_PRIVATE * psf) ; + +void wavlike_write_custom_chunks (SF_PRIVATE * psf) ; + +#endif + diff --git a/extern/libsndfile-modified/src/windows.c b/extern/libsndfile-modified/src/windows.c new file mode 100644 index 000000000..c11ed9b4b --- /dev/null +++ b/extern/libsndfile-modified/src/windows.c @@ -0,0 +1,70 @@ +/* +** Copyright (C) 2009-2017 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/* +** This needs to be a separate file so that we don't have to include +** elsewhere (too many symbol clashes). +*/ + + +#include "sfconfig.h" + +#if OS_IS_WIN32 +#include + +#include "sndfile.h" +#include "common.h" + +extern int sf_errno ; + +SNDFILE* +sf_wchar_open (LPCWSTR wpath, int mode, SF_INFO *sfinfo) +{ SF_PRIVATE *psf ; + char utf8name [SF_BUFFER_LEN] ; + DWORD dwError ; + + if ((psf = psf_allocate ()) == NULL) + { sf_errno = SFE_MALLOC_FAILED ; + return NULL ; + } ; + + psf_init_files (psf) ; + + if (WideCharToMultiByte (CP_UTF8, 0, wpath, -1, utf8name, sizeof (utf8name), NULL, NULL) == 0) + { dwError = GetLastError () ; + if (dwError == ERROR_INSUFFICIENT_BUFFER) + sf_errno = SFE_FILENAME_TOO_LONG ; + else + sf_errno = SF_ERR_UNSUPPORTED_ENCODING ; + + sf_close (psf) ; + + return NULL ; + } ; + + psf_log_printf (psf, "File : '%s' (utf-8 converted from ucs-2)\n", utf8name) ; + + psf_copy_filename (psf, utf8name) ; + psf->file.mode = mode ; + + psf->error = psf_fopen (psf) ; + + return psf_open_file (psf, sfinfo) ; +} /* sf_wchar_open */ + +#endif diff --git a/extern/libsndfile-modified/src/wve.c b/extern/libsndfile-modified/src/wve.c new file mode 100644 index 000000000..4b9fc8aa7 --- /dev/null +++ b/extern/libsndfile-modified/src/wve.c @@ -0,0 +1,209 @@ +/* +** Copyright (C) 2002-2017 Erik de Castro Lopo +** Copyright (C) 2007 Reuben Thomas +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + +/*------------------------------------------------------------------------------ +** Macros to handle big/little endian issues, and other magic numbers. +*/ + +#define ALAW_MARKER MAKE_MARKER ('A', 'L', 'a', 'w') +#define SOUN_MARKER MAKE_MARKER ('S', 'o', 'u', 'n') +#define DFIL_MARKER MAKE_MARKER ('d', 'F', 'i', 'l') +#define ESSN_MARKER MAKE_MARKER ('e', '*', '*', '\0') +#define PSION_VERSION ((unsigned short) 3856) +#define PSION_DATAOFFSET 0x20 + +/*------------------------------------------------------------------------------ +** Private static functions. +*/ + +static int wve_read_header (SF_PRIVATE *psf) ; +static int wve_write_header (SF_PRIVATE *psf, int calc_length) ; +static int wve_close (SF_PRIVATE *psf) ; + +/*------------------------------------------------------------------------------ +** Public function. +*/ + +int +wve_open (SF_PRIVATE *psf) +{ int error = 0 ; + + if (psf->is_pipe) + return SFE_WVE_NO_PIPE ; + + if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0)) + { if ((error = wve_read_header (psf))) + return error ; + } ; + + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_WVE) + return SFE_BAD_OPEN_FORMAT ; + + psf->endian = SF_ENDIAN_BIG ; + + if ((error = wve_write_header (psf, SF_FALSE))) + return error ; + + psf->write_header = wve_write_header ; + } ; + + psf->blockwidth = psf->bytewidth * psf->sf.channels ; + + psf->container_close = wve_close ; + + error = alaw_init (psf) ; + + return error ; +} /* wve_open */ + +/*------------------------------------------------------------------------------ +*/ + +static int +wve_read_header (SF_PRIVATE *psf) +{ int marker ; + unsigned short version, padding, repeats, trash ; + unsigned datalength ; + + /* Set position to start of file to begin reading header. */ + psf_binheader_readf (psf, "pm", 0, &marker) ; + if (marker != ALAW_MARKER) + { psf_log_printf (psf, "Could not find '%M'\n", ALAW_MARKER) ; + return SFE_WVE_NOT_WVE ; + } ; + + psf_binheader_readf (psf, "m", &marker) ; + if (marker != SOUN_MARKER) + { psf_log_printf (psf, "Could not find '%M'\n", SOUN_MARKER) ; + return SFE_WVE_NOT_WVE ; + } ; + + psf_binheader_readf (psf, "m", &marker) ; + if (marker != DFIL_MARKER) + { psf_log_printf (psf, "Could not find '%M'\n", DFIL_MARKER) ; + return SFE_WVE_NOT_WVE ; + } ; + + psf_binheader_readf (psf, "m", &marker) ; + if (marker != ESSN_MARKER) + { psf_log_printf (psf, "Could not find '%M'\n", ESSN_MARKER) ; + return SFE_WVE_NOT_WVE ; + } ; + + psf_binheader_readf (psf, "E2", &version) ; + + psf_log_printf (psf, "Psion Palmtop Alaw (.wve)\n" + " Sample Rate : 8000\n" + " Channels : 1\n" + " Encoding : A-law\n") ; + + if (version != PSION_VERSION) + psf_log_printf (psf, "Psion version %d should be %d\n", version, PSION_VERSION) ; + + psf_binheader_readf (psf, "E4", &datalength) ; + psf->dataoffset = PSION_DATAOFFSET ; + if (datalength != psf->filelength - psf->dataoffset) + { psf->datalength = psf->filelength - psf->dataoffset ; + psf_log_printf (psf, "Data length %d should be %D\n", datalength, psf->datalength) ; + } + else + psf->datalength = datalength ; + + psf_binheader_readf (psf, "E22222", &padding, &repeats, &trash, &trash, &trash) ; + + psf->sf.format = SF_FORMAT_WVE | SF_FORMAT_ALAW ; + psf->sf.samplerate = 8000 ; + psf->sf.frames = psf->datalength ; + psf->sf.channels = 1 ; + + return SFE_NO_ERROR ; +} /* wve_read_header */ + +/*------------------------------------------------------------------------------ +*/ + +static int +wve_write_header (SF_PRIVATE *psf, int calc_length) +{ sf_count_t current ; + unsigned datalen ; + + current = psf_ftell (psf) ; + + if (calc_length) + { psf->filelength = psf_get_filelen (psf) ; + + psf->datalength = psf->filelength - psf->dataoffset ; + if (psf->dataend) + psf->datalength -= psf->filelength - psf->dataend ; + + psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ; + } ; + + /* Reset the current header length to zero. */ + psf->header.ptr [0] = 0 ; + psf->header.indx = 0 ; + psf_fseek (psf, 0, SEEK_SET) ; + + /* Write header. */ + datalen = psf->datalength ; + psf_binheader_writef (psf, "Emmmm", BHWm (ALAW_MARKER), BHWm (SOUN_MARKER), BHWm (DFIL_MARKER), BHWm (ESSN_MARKER)) ; + psf_binheader_writef (psf, "E2422222", BHW2 (PSION_VERSION), BHW4 (datalen), BHW2 (0), BHW2 (0), BHW2 (0), BHW2 (0), BHW2 (0)) ; + psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ; + + if (psf->sf.channels != 1) + return SFE_CHANNEL_COUNT ; + + if (psf->error) + return psf->error ; + + psf->dataoffset = psf->header.indx ; + + if (current > 0) + psf_fseek (psf, current, SEEK_SET) ; + + return psf->error ; +} /* wve_write_header */ + +/*------------------------------------------------------------------------------ +*/ + +static int +wve_close (SF_PRIVATE *psf) +{ + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { /* Now we know for certain the length of the file we can re-write + ** the header. + */ + wve_write_header (psf, SF_TRUE) ; + } ; + + return 0 ; +} /* wve_close */ diff --git a/extern/libsndfile-modified/src/xi.c b/extern/libsndfile-modified/src/xi.c new file mode 100644 index 000000000..e8169471e --- /dev/null +++ b/extern/libsndfile-modified/src/xi.c @@ -0,0 +1,1223 @@ +/* +** Copyright (C) 2003-2017 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU Lesser General Public License as published by +** the Free Software Foundation; either version 2.1 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU Lesser General Public License for more details. +** +** You should have received a copy of the GNU Lesser General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include +#include +#include + +#include "sndfile.h" +#include "sfendian.h" +#include "common.h" + +#define MAX_XI_SAMPLES 16 + +/*------------------------------------------------------------------------------ +** Private static functions and tyepdefs. +*/ + +typedef struct +{ /* Warning, this filename is NOT nul terminated. */ + char filename [22] ; + char software [20] ; + char sample_name [22] ; + + int loop_begin, loop_end ; + int sample_flags ; + + /* Data for encoder and decoder. */ + short last_16 ; +} XI_PRIVATE ; + +static int xi_close (SF_PRIVATE *psf) ; +static int xi_write_header (SF_PRIVATE *psf, int calc_length) ; +static int xi_read_header (SF_PRIVATE *psf) ; +static int dpcm_init (SF_PRIVATE *psf) ; + + +static sf_count_t dpcm_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ; + +/*------------------------------------------------------------------------------ +** Public function. +*/ + +int +xi_open (SF_PRIVATE *psf) +{ XI_PRIVATE *pxi ; + int subformat, error = 0 ; + + if (psf->is_pipe) + return SFE_XI_NO_PIPE ; + + if (psf->codec_data) + pxi = psf->codec_data ; + else if ((pxi = calloc (1, sizeof (XI_PRIVATE))) == NULL) + return SFE_MALLOC_FAILED ; + + psf->codec_data = pxi ; + + if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR && psf->filelength > 0)) + { if ((error = xi_read_header (psf))) + return error ; + } ; + + subformat = SF_CODEC (psf->sf.format) ; + + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_XI) + return SFE_BAD_OPEN_FORMAT ; + + psf->endian = SF_ENDIAN_LITTLE ; + psf->sf.channels = 1 ; /* Always mono */ + psf->sf.samplerate = 44100 ; /* Always */ + + /* Set up default instrument and software name. */ + memcpy (pxi->filename, "Default Name ", sizeof (pxi->filename)) ; + memcpy (pxi->software, PACKAGE_NAME "-" PACKAGE_VERSION " ", sizeof (pxi->software)) ; + + memset (pxi->sample_name, 0, sizeof (pxi->sample_name)) ; + snprintf (pxi->sample_name, sizeof (pxi->sample_name), "%s", "Sample #1") ; + + pxi->sample_flags = (subformat == SF_FORMAT_DPCM_16) ? 16 : 0 ; + + if (xi_write_header (psf, SF_FALSE)) + return psf->error ; + + psf->write_header = xi_write_header ; + } ; + + psf->container_close = xi_close ; + psf->seek = dpcm_seek ; + + psf->sf.seekable = SF_FALSE ; + + psf->blockwidth = psf->bytewidth * psf->sf.channels ; + + switch (subformat) + { case SF_FORMAT_DPCM_8 : /* 8-bit differential PCM. */ + case SF_FORMAT_DPCM_16 : /* 16-bit differential PCM. */ + error = dpcm_init (psf) ; + break ; + + default : break ; + } ; + + return error ; +} /* xi_open */ + +/*------------------------------------------------------------------------------ +*/ + +static int +xi_close (SF_PRIVATE * UNUSED (psf)) +{ + return 0 ; +} /* xi_close */ + +/*============================================================================== +*/ + +static sf_count_t dpcm_read_dsc2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; +static sf_count_t dpcm_read_dsc2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; +static sf_count_t dpcm_read_dsc2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; +static sf_count_t dpcm_read_dsc2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; + +static sf_count_t dpcm_write_s2dsc (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; +static sf_count_t dpcm_write_i2dsc (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; +static sf_count_t dpcm_write_f2dsc (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; +static sf_count_t dpcm_write_d2dsc (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; + +static sf_count_t dpcm_read_dles2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; +static sf_count_t dpcm_read_dles2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; +static sf_count_t dpcm_read_dles2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; +static sf_count_t dpcm_read_dles2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; + +static sf_count_t dpcm_write_s2dles (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; +static sf_count_t dpcm_write_i2dles (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; +static sf_count_t dpcm_write_f2dles (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; +static sf_count_t dpcm_write_d2dles (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; + +static int +dpcm_init (SF_PRIVATE *psf) +{ if (psf->bytewidth == 0 || psf->sf.channels == 0) + return SFE_INTERNAL ; + + psf->blockwidth = psf->bytewidth * psf->sf.channels ; + + if (psf->file.mode == SFM_READ || psf->file.mode == SFM_RDWR) + { switch (psf->bytewidth) + { case 1 : + psf->read_short = dpcm_read_dsc2s ; + psf->read_int = dpcm_read_dsc2i ; + psf->read_float = dpcm_read_dsc2f ; + psf->read_double = dpcm_read_dsc2d ; + break ; + case 2 : + psf->read_short = dpcm_read_dles2s ; + psf->read_int = dpcm_read_dles2i ; + psf->read_float = dpcm_read_dles2f ; + psf->read_double = dpcm_read_dles2d ; + break ; + default : + psf_log_printf (psf, "dpcm_init() returning SFE_UNIMPLEMENTED\n") ; + return SFE_UNIMPLEMENTED ; + } ; + } ; + + if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) + { switch (psf->bytewidth) + { case 1 : + psf->write_short = dpcm_write_s2dsc ; + psf->write_int = dpcm_write_i2dsc ; + psf->write_float = dpcm_write_f2dsc ; + psf->write_double = dpcm_write_d2dsc ; + break ; + case 2 : + psf->write_short = dpcm_write_s2dles ; + psf->write_int = dpcm_write_i2dles ; + psf->write_float = dpcm_write_f2dles ; + psf->write_double = dpcm_write_d2dles ; + break ; + default : + psf_log_printf (psf, "dpcm_init() returning SFE_UNIMPLEMENTED\n") ; + return SFE_UNIMPLEMENTED ; + } ; + } ; + + psf->filelength = psf_get_filelen (psf) ; + psf->datalength = (psf->dataend) ? psf->dataend - psf->dataoffset : + psf->filelength - psf->dataoffset ; + psf->sf.frames = psf->datalength / psf->blockwidth ; + + return 0 ; +} /* dpcm_init */ + +/*============================================================================== +*/ + +static sf_count_t +dpcm_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) +{ BUF_UNION ubuf ; + XI_PRIVATE *pxi ; + int total, bufferlen, len ; + + if ((pxi = psf->codec_data) == NULL) + return SFE_INTERNAL ; + + if (psf->datalength < 0 || psf->dataoffset < 0) + { psf->error = SFE_BAD_SEEK ; + return PSF_SEEK_ERROR ; + } ; + + if (offset == 0) + { psf_fseek (psf, psf->dataoffset, SEEK_SET) ; + pxi->last_16 = 0 ; + return 0 ; + } ; + + if (offset < 0 || offset > psf->sf.frames) + { psf->error = SFE_BAD_SEEK ; + return PSF_SEEK_ERROR ; + } ; + + if (mode != SFM_READ) + { /* What to do about write??? */ + psf->error = SFE_BAD_SEEK ; + return PSF_SEEK_ERROR ; + } ; + + psf_fseek (psf, psf->dataoffset, SEEK_SET) ; + + if ((SF_CODEC (psf->sf.format)) == SF_FORMAT_DPCM_16) + { total = offset ; + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + while (total > 0) + { len = (total > bufferlen) ? bufferlen : total ; + total -= (int) dpcm_read_dles2s (psf, ubuf.sbuf, len) ; + } ; + } + else + { total = offset ; + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + while (total > 0) + { len = (total > bufferlen) ? bufferlen : total ; + total -= (int) dpcm_read_dsc2s (psf, ubuf.sbuf, len) ; + } ; + } ; + + return offset ; +} /* dpcm_seek */ + + +static int +xi_write_header (SF_PRIVATE *psf, int UNUSED (calc_length)) +{ XI_PRIVATE *pxi ; + sf_count_t current ; + const char *string ; + + if ((pxi = psf->codec_data) == NULL) + return SFE_INTERNAL ; + + current = psf_ftell (psf) ; + + /* Reset the current header length to zero. */ + psf->header.ptr [0] = 0 ; + psf->header.indx = 0 ; + psf_fseek (psf, 0, SEEK_SET) ; + + string = "Extended Instrument: " ; + psf_binheader_writef (psf, "b", BHWv (string), BHWz (strlen (string))) ; + psf_binheader_writef (psf, "b1", BHWv (pxi->filename), BHWz (sizeof (pxi->filename)), BHW1 (0x1A)) ; + + /* Write software version and two byte XI version. */ + psf_binheader_writef (psf, "eb2", BHWv (pxi->software), BHWz (sizeof (pxi->software)), BHW2 ((1 << 8) + 2)) ; + + /* + ** Jump note numbers (96), volume envelope (48), pan envelope (48), + ** volume points (1), pan points (1) + */ + psf_binheader_writef (psf, "z", BHWz ((size_t) (96 + 48 + 48 + 1 + 1))) ; + + /* Jump volume loop (3 bytes), pan loop (3), envelope flags (3), vibrato (3) + ** fade out (2), 22 unknown bytes, and then write sample_count (2 bytes). + */ + psf_binheader_writef (psf, "ez2z2", BHWz ((size_t) (4 * 3)), BHW2 (0x1234), BHWz (22), BHW2 (1)) ; + + pxi->loop_begin = 0 ; + pxi->loop_end = 0 ; + + psf_binheader_writef (psf, "et844", BHW8 (psf->sf.frames), BHW4 (pxi->loop_begin), BHW4 (pxi->loop_end)) ; + + /* volume, fine tune, flags, pan, note, namelen */ + psf_binheader_writef (psf, "111111", BHW1 (128), BHW1 (0), BHW1 (pxi->sample_flags), BHW1 (128), BHW1 (0), BHW1 (strlen (pxi->sample_name))) ; + + psf_binheader_writef (psf, "b", BHWv (pxi->sample_name), BHWz (sizeof (pxi->sample_name))) ; + + /* Header construction complete so write it out. */ + psf_fwrite (psf->header.ptr, psf->header.indx, 1, psf) ; + + if (psf->error) + return psf->error ; + + psf->dataoffset = psf->header.indx ; + + if (current > 0) + psf_fseek (psf, current, SEEK_SET) ; + + return psf->error ; +} /* xi_write_header */ + +static int +xi_read_header (SF_PRIVATE *psf) +{ char buffer [64], name [32] ; + short version, fade_out, sample_count ; + int k, loop_begin, loop_end ; + int sample_sizes [MAX_XI_SAMPLES] ; + + psf_binheader_readf (psf, "pb", 0, buffer, 21) ; + + memset (sample_sizes, 0, sizeof (sample_sizes)) ; + + buffer [20] = 0 ; + if (strcmp (buffer, "Extended Instrument:") != 0) + return SFE_XI_BAD_HEADER ; + + memset (buffer, 0, sizeof (buffer)) ; + psf_binheader_readf (psf, "b", buffer, 23) ; + + if (buffer [22] != 0x1A) + return SFE_XI_BAD_HEADER ; + + buffer [22] = 0 ; + for (k = 21 ; k >= 0 && buffer [k] == ' ' ; k --) + buffer [k] = 0 ; + + psf_log_printf (psf, "Extended Instrument : %s\n", buffer) ; + psf_store_string (psf, SF_STR_TITLE, buffer) ; + + psf_binheader_readf (psf, "be2", buffer, 20, &version) ; + buffer [19] = 0 ; + for (k = 18 ; k >= 0 && buffer [k] == ' ' ; k --) + buffer [k] = 0 ; + + psf_log_printf (psf, "Software : %s\nVersion : %d.%02d\n", buffer, version / 256, version % 256) ; + psf_store_string (psf, SF_STR_SOFTWARE, buffer) ; + + /* Jump note numbers (96), volume envelope (48), pan envelope (48), + ** volume points (1), pan points (1) + */ + psf_binheader_readf (psf, "j", 96 + 48 + 48 + 1 + 1) ; + + psf_binheader_readf (psf, "b", buffer, 12) ; + psf_log_printf (psf, "Volume Loop\n sustain : %u\n begin : %u\n end : %u\n", + buffer [0], buffer [1], buffer [2]) ; + psf_log_printf (psf, "Pan Loop\n sustain : %u\n begin : %u\n end : %u\n", + buffer [3], buffer [4], buffer [5]) ; + psf_log_printf (psf, "Envelope Flags\n volume : 0x%X\n pan : 0x%X\n", + buffer [6] & 0xFF, buffer [7] & 0xFF) ; + + psf_log_printf (psf, "Vibrato\n type : %u\n sweep : %u\n depth : %u\n rate : %u\n", + buffer [8], buffer [9], buffer [10], buffer [11]) ; + + /* + ** Read fade_out then jump reserved (2 bytes) and ???? (20 bytes) and + ** sample_count. + */ + psf_binheader_readf (psf, "e2j2", &fade_out, 2 + 20, &sample_count) ; + psf_log_printf (psf, "Fade out : %d\n", fade_out) ; + + /* XI file can contain up to 16 samples. */ + if (sample_count > MAX_XI_SAMPLES) + return SFE_XI_EXCESS_SAMPLES ; + + if (psf->instrument == NULL && (psf->instrument = psf_instrument_alloc ()) == NULL) + return SFE_MALLOC_FAILED ; + + psf->instrument->basenote = 0 ; + /* Log all data for each sample. */ + for (k = 0 ; k < sample_count ; k++) + { psf_binheader_readf (psf, "e444", &(sample_sizes [k]), &loop_begin, &loop_end) ; + + /* Read 5 know bytes, 1 unknown byte and 22 name bytes. */ + psf_binheader_readf (psf, "bb", buffer, 6, name, 22) ; + name [21] = 0 ; + + psf_log_printf (psf, "Sample #%d\n name : %s\n", k + 1, name) ; + + psf_log_printf (psf, " size : %d\n", sample_sizes [k]) ; + + psf_log_printf (psf, " loop\n begin : %d\n end : %d\n", loop_begin, loop_end) ; + + psf_log_printf (psf, " volume : %u\n f. tune : %d\n flags : 0x%02X ", + buffer [0] & 0xFF, buffer [1] & 0xFF, buffer [2] & 0xFF) ; + + psf_log_printf (psf, " (") ; + if (buffer [2] & 1) + psf_log_printf (psf, " Loop") ; + if (buffer [2] & 2) + psf_log_printf (psf, " PingPong") ; + psf_log_printf (psf, (buffer [2] & 16) ? " 16bit" : " 8bit") ; + psf_log_printf (psf, " )\n") ; + + psf_log_printf (psf, " pan : %u\n note : %d\n namelen : %d\n", + buffer [3] & 0xFF, buffer [4], buffer [5]) ; + + psf->instrument->basenote = buffer [4] ; + if (buffer [2] & 1) + { psf->instrument->loop_count = 1 ; + psf->instrument->loops [0].mode = (buffer [2] & 2) ? SF_LOOP_ALTERNATING : SF_LOOP_FORWARD ; + psf->instrument->loops [0].start = loop_begin ; + psf->instrument->loops [0].end = loop_end ; + } ; + + if (k != 0) + continue ; + + if (buffer [2] & 16) + { psf->sf.format = SF_FORMAT_XI | SF_FORMAT_DPCM_16 ; + psf->bytewidth = 2 ; + } + else + { psf->sf.format = SF_FORMAT_XI | SF_FORMAT_DPCM_8 ; + psf->bytewidth = 1 ; + } ; + } ; + + while (sample_count > 1 && sample_sizes [sample_count - 1] == 0) + sample_count -- ; + + /* Currently, we can only handle 1 sample per file. */ + + if (sample_count > 2) + { psf_log_printf (psf, "*** Sample count is less than 16 but more than 1.\n") ; + psf_log_printf (psf, " sample count : %d sample_sizes [%d] : %d\n", + sample_count, sample_count - 1, sample_sizes [sample_count - 1]) ; + return SFE_XI_EXCESS_SAMPLES ; + } ; + + psf->datalength = sample_sizes [0] ; + + psf->dataoffset = psf_ftell (psf) ; + if (psf->dataoffset < 0) + { psf_log_printf (psf, "*** Bad Data Offset : %D\n", psf->dataoffset) ; + return SFE_BAD_OFFSET ; + } ; + psf_log_printf (psf, "Data Offset : %D\n", psf->dataoffset) ; + + if (psf->dataoffset + psf->datalength > psf->filelength) + { psf_log_printf (psf, "*** File seems to be truncated. Should be at least %D bytes long.\n", + psf->dataoffset + sample_sizes [0]) ; + psf->datalength = psf->filelength - psf->dataoffset ; + } ; + + if (psf_fseek (psf, psf->dataoffset, SEEK_SET) != psf->dataoffset) + return SFE_BAD_SEEK ; + + psf->endian = SF_ENDIAN_LITTLE ; + psf->sf.channels = 1 ; /* Always mono */ + psf->sf.samplerate = 44100 ; /* Always */ + + psf->blockwidth = psf->sf.channels * psf->bytewidth ; + + if (! psf->sf.frames && psf->blockwidth) + psf->sf.frames = (psf->filelength - psf->dataoffset) / psf->blockwidth ; + + psf->instrument->gain = 1 ; + psf->instrument->velocity_lo = psf->instrument->key_lo = 0 ; + psf->instrument->velocity_hi = psf->instrument->key_hi = 127 ; + + return 0 ; +} /* xi_read_header */ + +/*============================================================================== +*/ + +static void dsc2s_array (XI_PRIVATE *pxi, signed char *src, int count, short *dest) ; +static void dsc2i_array (XI_PRIVATE *pxi, signed char *src, int count, int *dest) ; +static void dsc2f_array (XI_PRIVATE *pxi, signed char *src, int count, float *dest, float normfact) ; +static void dsc2d_array (XI_PRIVATE *pxi, signed char *src, int count, double *dest, double normfact) ; + +static void dles2s_array (XI_PRIVATE *pxi, short *src, int count, short *dest) ; +static void dles2i_array (XI_PRIVATE *pxi, short *src, int count, int *dest) ; +static void dles2f_array (XI_PRIVATE *pxi, short *src, int count, float *dest, float normfact) ; +static void dles2d_array (XI_PRIVATE *pxi, short *src, int count, double *dest, double normfact) ; + +static sf_count_t +dpcm_read_dsc2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + XI_PRIVATE *pxi ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + + if ((pxi = psf->codec_data) == NULL) + return 0 ; + + bufferlen = ARRAY_LEN (ubuf.ucbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.scbuf, sizeof (signed char), bufferlen, psf) ; + dsc2s_array (pxi, ubuf.scbuf, readcount, ptr + total) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* dpcm_read_dsc2s */ + +static sf_count_t +dpcm_read_dsc2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + XI_PRIVATE *pxi ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + + if ((pxi = psf->codec_data) == NULL) + return 0 ; + + bufferlen = ARRAY_LEN (ubuf.ucbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.scbuf, sizeof (signed char), bufferlen, psf) ; + dsc2i_array (pxi, ubuf.scbuf, readcount, ptr + total) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* dpcm_read_dsc2i */ + +static sf_count_t +dpcm_read_dsc2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + XI_PRIVATE *pxi ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + float normfact ; + + if ((pxi = psf->codec_data) == NULL) + return 0 ; + + normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x80) : 1.0 ; + + bufferlen = ARRAY_LEN (ubuf.ucbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.scbuf, sizeof (signed char), bufferlen, psf) ; + dsc2f_array (pxi, ubuf.scbuf, readcount, ptr + total, normfact) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* dpcm_read_dsc2f */ + +static sf_count_t +dpcm_read_dsc2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + XI_PRIVATE *pxi ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + double normfact ; + + if ((pxi = psf->codec_data) == NULL) + return 0 ; + + normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x80) : 1.0 ; + + bufferlen = ARRAY_LEN (ubuf.ucbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.scbuf, sizeof (signed char), bufferlen, psf) ; + dsc2d_array (pxi, ubuf.scbuf, readcount, ptr + total, normfact) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* dpcm_read_dsc2d */ + +/*------------------------------------------------------------------------------ +*/ + +static sf_count_t +dpcm_read_dles2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + XI_PRIVATE *pxi ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + + if ((pxi = psf->codec_data) == NULL) + return 0 ; + + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.sbuf, sizeof (short), bufferlen, psf) ; + dles2s_array (pxi, ubuf.sbuf, readcount, ptr + total) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* dpcm_read_dles2s */ + +static sf_count_t +dpcm_read_dles2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + XI_PRIVATE *pxi ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + + if ((pxi = psf->codec_data) == NULL) + return 0 ; + + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.sbuf, sizeof (short), bufferlen, psf) ; + dles2i_array (pxi, ubuf.sbuf, readcount, ptr + total) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* dpcm_read_dles2i */ + +static sf_count_t +dpcm_read_dles2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + XI_PRIVATE *pxi ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + float normfact ; + + if ((pxi = psf->codec_data) == NULL) + return 0 ; + + normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x8000) : 1.0 ; + + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.sbuf, sizeof (short), bufferlen, psf) ; + dles2f_array (pxi, ubuf.sbuf, readcount, ptr + total, normfact) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* dpcm_read_dles2f */ + +static sf_count_t +dpcm_read_dles2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + XI_PRIVATE *pxi ; + int bufferlen, readcount ; + sf_count_t total = 0 ; + double normfact ; + + if ((pxi = psf->codec_data) == NULL) + return 0 ; + + normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x8000) : 1.0 ; + + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + readcount = (int) psf_fread (ubuf.sbuf, sizeof (short), bufferlen, psf) ; + dles2d_array (pxi, ubuf.sbuf, readcount, ptr + total, normfact) ; + total += readcount ; + if (readcount < bufferlen) + break ; + len -= readcount ; + } ; + + return total ; +} /* dpcm_read_dles2d */ + +/*============================================================================== +*/ + +static void s2dsc_array (XI_PRIVATE *pxi, const short *src, signed char *dest, int count) ; +static void i2dsc_array (XI_PRIVATE *pxi, const int *src, signed char *dest, int count) ; +static void f2dsc_array (XI_PRIVATE *pxi, const float *src, signed char *dest, int count, float normfact) ; +static void d2dsc_array (XI_PRIVATE *pxi, const double *src, signed char *dest, int count, double normfact) ; + +static void s2dles_array (XI_PRIVATE *pxi, const short *src, short *dest, int count) ; +static void i2dles_array (XI_PRIVATE *pxi, const int *src, short *dest, int count) ; +static void f2dles_array (XI_PRIVATE *pxi, const float *src, short *dest, int count, float normfact) ; +static void d2dles_array (XI_PRIVATE *pxi, const double *src, short *dest, int count, double normfact) ; + + +static sf_count_t +dpcm_write_s2dsc (SF_PRIVATE *psf, const short *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + XI_PRIVATE *pxi ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + if ((pxi = psf->codec_data) == NULL) + return 0 ; + + bufferlen = ARRAY_LEN (ubuf.ucbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + s2dsc_array (pxi, ptr + total, ubuf.scbuf, bufferlen) ; + writecount = (int) psf_fwrite (ubuf.scbuf, sizeof (signed char), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* dpcm_write_s2dsc */ + +static sf_count_t +dpcm_write_i2dsc (SF_PRIVATE *psf, const int *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + XI_PRIVATE *pxi ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + if ((pxi = psf->codec_data) == NULL) + return 0 ; + + bufferlen = ARRAY_LEN (ubuf.ucbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + i2dsc_array (pxi, ptr + total, ubuf.scbuf, bufferlen) ; + writecount = (int) psf_fwrite (ubuf.scbuf, sizeof (signed char), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* dpcm_write_i2dsc */ + +static sf_count_t +dpcm_write_f2dsc (SF_PRIVATE *psf, const float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + XI_PRIVATE *pxi ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + float normfact ; + + if ((pxi = psf->codec_data) == NULL) + return 0 ; + + normfact = (psf->norm_float == SF_TRUE) ? (1.0 * 0x7F) : 1.0 ; + + bufferlen = ARRAY_LEN (ubuf.ucbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + f2dsc_array (pxi, ptr + total, ubuf.scbuf, bufferlen, normfact) ; + writecount = (int) psf_fwrite (ubuf.scbuf, sizeof (signed char), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* dpcm_write_f2dsc */ + +static sf_count_t +dpcm_write_d2dsc (SF_PRIVATE *psf, const double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + XI_PRIVATE *pxi ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + double normfact ; + + if ((pxi = psf->codec_data) == NULL) + return 0 ; + + normfact = (psf->norm_double == SF_TRUE) ? (1.0 * 0x7F) : 1.0 ; + + bufferlen = ARRAY_LEN (ubuf.ucbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + d2dsc_array (pxi, ptr + total, ubuf.scbuf, bufferlen, normfact) ; + writecount = (int) psf_fwrite (ubuf.scbuf, sizeof (signed char), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* dpcm_write_d2dsc */ + + +static sf_count_t +dpcm_write_s2dles (SF_PRIVATE *psf, const short *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + XI_PRIVATE *pxi ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + if ((pxi = psf->codec_data) == NULL) + return 0 ; + + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + s2dles_array (pxi, ptr + total, ubuf.sbuf, bufferlen) ; + writecount = (int) psf_fwrite (ubuf.sbuf, sizeof (short), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* dpcm_write_s2dles */ + +static sf_count_t +dpcm_write_i2dles (SF_PRIVATE *psf, const int *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + XI_PRIVATE *pxi ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + + if ((pxi = psf->codec_data) == NULL) + return 0 ; + + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + i2dles_array (pxi, ptr + total, ubuf.sbuf, bufferlen) ; + writecount = (int) psf_fwrite (ubuf.sbuf, sizeof (short), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* dpcm_write_i2dles */ + +static sf_count_t +dpcm_write_f2dles (SF_PRIVATE *psf, const float *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + XI_PRIVATE *pxi ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + float normfact ; + + if ((pxi = psf->codec_data) == NULL) + return 0 ; + + normfact = (psf->norm_float == SF_TRUE) ? (1.0 * 0x7FFF) : 1.0 ; + + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + f2dles_array (pxi, ptr + total, ubuf.sbuf, bufferlen, normfact) ; + writecount = (int) psf_fwrite (ubuf.sbuf, sizeof (short), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* dpcm_write_f2dles */ + +static sf_count_t +dpcm_write_d2dles (SF_PRIVATE *psf, const double *ptr, sf_count_t len) +{ BUF_UNION ubuf ; + XI_PRIVATE *pxi ; + int bufferlen, writecount ; + sf_count_t total = 0 ; + double normfact ; + + if ((pxi = psf->codec_data) == NULL) + return 0 ; + + normfact = (psf->norm_double == SF_TRUE) ? (1.0 * 0x7FFF) : 1.0 ; + + bufferlen = ARRAY_LEN (ubuf.sbuf) ; + + while (len > 0) + { if (len < bufferlen) + bufferlen = (int) len ; + d2dles_array (pxi, ptr + total, ubuf.sbuf, bufferlen, normfact) ; + writecount = (int) psf_fwrite (ubuf.sbuf, sizeof (short), bufferlen, psf) ; + total += writecount ; + if (writecount < bufferlen) + break ; + len -= writecount ; + } ; + + return total ; +} /* dpcm_write_d2dles */ + + +/*============================================================================== +*/ + +static void +dsc2s_array (XI_PRIVATE *pxi, signed char *src, int count, short *dest) +{ signed char last_val ; + int k ; + + last_val = pxi->last_16 >> 8 ; + + for (k = 0 ; k < count ; k++) + { last_val += src [k] ; + dest [k] = arith_shift_left (last_val, 8) ; + } ; + + pxi->last_16 = arith_shift_left (last_val, 8) ; +} /* dsc2s_array */ + +static void +dsc2i_array (XI_PRIVATE *pxi, signed char *src, int count, int *dest) +{ signed char last_val ; + int k ; + + last_val = pxi->last_16 >> 8 ; + + for (k = 0 ; k < count ; k++) + { last_val += src [k] ; + dest [k] = arith_shift_left (last_val, 24) ; + } ; + + pxi->last_16 = arith_shift_left (last_val, 8) ; +} /* dsc2i_array */ + +static void +dsc2f_array (XI_PRIVATE *pxi, signed char *src, int count, float *dest, float normfact) +{ signed char last_val ; + int k ; + + last_val = pxi->last_16 >> 8 ; + + for (k = 0 ; k < count ; k++) + { last_val += src [k] ; + dest [k] = last_val * normfact ; + } ; + + pxi->last_16 = arith_shift_left (last_val, 8) ; +} /* dsc2f_array */ + +static void +dsc2d_array (XI_PRIVATE *pxi, signed char *src, int count, double *dest, double normfact) +{ signed char last_val ; + int k ; + + last_val = pxi->last_16 >> 8 ; + + for (k = 0 ; k < count ; k++) + { last_val += src [k] ; + dest [k] = last_val * normfact ; + } ; + + pxi->last_16 = arith_shift_left (last_val, 8) ; +} /* dsc2d_array */ + +/*------------------------------------------------------------------------------ +*/ + +static void +s2dsc_array (XI_PRIVATE *pxi, const short *src, signed char *dest, int count) +{ signed char last_val, current ; + int k ; + + last_val = pxi->last_16 >> 8 ; + + for (k = 0 ; k < count ; k++) + { current = src [k] >> 8 ; + dest [k] = current - last_val ; + last_val = current ; + } ; + + pxi->last_16 = arith_shift_left (last_val, 8) ; +} /* s2dsc_array */ + +static void +i2dsc_array (XI_PRIVATE *pxi, const int *src, signed char *dest, int count) +{ signed char last_val, current ; + int k ; + + last_val = pxi->last_16 >> 8 ; + + for (k = 0 ; k < count ; k++) + { current = src [k] >> 24 ; + dest [k] = current - last_val ; + last_val = current ; + } ; + + pxi->last_16 = arith_shift_left (last_val, 8) ; +} /* i2dsc_array */ + +static void +f2dsc_array (XI_PRIVATE *pxi, const float *src, signed char *dest, int count, float normfact) +{ signed char last_val, current ; + int k ; + + last_val = pxi->last_16 >> 8 ; + + for (k = 0 ; k < count ; k++) + { current = psf_lrintf (src [k] * normfact) ; + dest [k] = current - last_val ; + last_val = current ; + } ; + + pxi->last_16 = arith_shift_left (last_val, 8) ; +} /* f2dsc_array */ + +static void +d2dsc_array (XI_PRIVATE *pxi, const double *src, signed char *dest, int count, double normfact) +{ signed char last_val, current ; + int k ; + + last_val = pxi->last_16 >> 8 ; + + for (k = 0 ; k < count ; k++) + { current = psf_lrint (src [k] * normfact) ; + dest [k] = current - last_val ; + last_val = current ; + } ; + + pxi->last_16 = arith_shift_left (last_val, 8) ; +} /* d2dsc_array */ + +/*============================================================================== +*/ + +static void +dles2s_array (XI_PRIVATE *pxi, short *src, int count, short *dest) +{ short last_val ; + int k ; + + last_val = pxi->last_16 ; + + for (k = 0 ; k < count ; k++) + { last_val += LE2H_16 (src [k]) ; + dest [k] = last_val ; + } ; + + pxi->last_16 = last_val ; +} /* dles2s_array */ + +static void +dles2i_array (XI_PRIVATE *pxi, short *src, int count, int *dest) +{ short last_val ; + int k ; + + last_val = pxi->last_16 ; + + for (k = 0 ; k < count ; k++) + { last_val += LE2H_16 (src [k]) ; + dest [k] = arith_shift_left (last_val, 16) ; + } ; + + pxi->last_16 = last_val ; +} /* dles2i_array */ + +static void +dles2f_array (XI_PRIVATE *pxi, short *src, int count, float *dest, float normfact) +{ short last_val ; + int k ; + + last_val = pxi->last_16 ; + + for (k = 0 ; k < count ; k++) + { last_val += LE2H_16 (src [k]) ; + dest [k] = last_val * normfact ; + } ; + + pxi->last_16 = last_val ; +} /* dles2f_array */ + +static void +dles2d_array (XI_PRIVATE *pxi, short *src, int count, double *dest, double normfact) +{ short last_val ; + int k ; + + last_val = pxi->last_16 ; + + for (k = 0 ; k < count ; k++) + { last_val += LE2H_16 (src [k]) ; + dest [k] = last_val * normfact ; + } ; + + pxi->last_16 = last_val ; +} /* dles2d_array */ + +/*------------------------------------------------------------------------------ +*/ + +static void +s2dles_array (XI_PRIVATE *pxi, const short *src, short *dest, int count) +{ short diff, last_val ; + int k ; + + last_val = pxi->last_16 ; + + for (k = 0 ; k < count ; k++) + { diff = src [k] - last_val ; + dest [k] = LE2H_16 (diff) ; + last_val = src [k] ; + } ; + + pxi->last_16 = last_val ; +} /* s2dles_array */ + +static void +i2dles_array (XI_PRIVATE *pxi, const int *src, short *dest, int count) +{ short diff, last_val ; + int k ; + + last_val = pxi->last_16 ; + + for (k = 0 ; k < count ; k++) + { diff = (src [k] >> 16) - last_val ; + dest [k] = LE2H_16 (diff) ; + last_val = src [k] >> 16 ; + } ; + + pxi->last_16 = last_val ; +} /* i2dles_array */ + +static void +f2dles_array (XI_PRIVATE *pxi, const float *src, short *dest, int count, float normfact) +{ short diff, last_val, current ; + int k ; + + last_val = pxi->last_16 ; + + for (k = 0 ; k < count ; k++) + { current = psf_lrintf (src [k] * normfact) ; + diff = current - last_val ; + dest [k] = LE2H_16 (diff) ; + last_val = current ; + } ; + + pxi->last_16 = last_val ; +} /* f2dles_array */ + +static void +d2dles_array (XI_PRIVATE *pxi, const double *src, short *dest, int count, double normfact) +{ short diff, last_val, current ; + int k ; + + last_val = pxi->last_16 ; + + for (k = 0 ; k < count ; k++) + { current = psf_lrint (src [k] * normfact) ; + diff = current - last_val ; + dest [k] = LE2H_16 (diff) ; + last_val = current ; + } ; + + pxi->last_16 = last_val ; +} /* d2dles_array */ diff --git a/extern/libsndfile-modified/tests/aiff_rw_test.c b/extern/libsndfile-modified/tests/aiff_rw_test.c new file mode 100644 index 000000000..54eec4ba9 --- /dev/null +++ b/extern/libsndfile-modified/tests/aiff_rw_test.c @@ -0,0 +1,169 @@ +/* +** Copyright (C) 2003-2017 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif +#include +#include + + +#include + +#include "utils.h" + + +static unsigned char aifc_data [] = +{ 'F' , 'O' , 'R' , 'M' , + 0x00, 0x00, 0x01, 0xE8, /* FORM length */ + + 'A' , 'I' , 'F' , 'C' , + 0x43, 0x4F, 0x4D, 0x4D, /* COMM */ + 0x00, 0x00, 0x00, 0x26, /* COMM length */ + 0x00, 0x01, 0x00, 0x00, 0x00, 0xAE, 0x00, 0x10, 0x40, 0x0D, 0xAC, 0x44, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4E, 0x4F, 0x4E, 0x45, 0x0D, 'N' , + 'o' , 't' , ' ' , 'c' , 'o' , 'm' , 'p' , 'r' , 'e' , 's' , 's' , 'e' , + 'd' , 0x00, + + 'F' , 'V' , 'E' , 'R' , 0x00, 0x00, 0x00, 0x04, 0xA2, 0x80, 0x51, 0x40, + + /* A 'MARK' chunk. */ + 'M' , 'A' , 'R' , 'K' , 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 'A' , + 0x00, 0x02, 0x00, 0x00, 0x11, 0x3A, 0x02, 'B' , 'C' , 0x00, + 0x00, 0x03, 0x00, 0x00, 0x22, 0x74, 0x03, 'D' , 'E' , 'F', + 0x00, 0x04, 0x00, 0x00, 0x33, 0xAE, 0x04, 'G' , 'H' , 'I', 'J' , 0x00, + 0x00, 0x05, 0x00, 0x00, 0x44, 0xE8, 0x05, 'K' , 'L' , 'M', 'N' , 'O' , + + 'S' , 'S' , 'N' , 'D' , + 0x00, 0x00, 0x01, 0x64, /* SSND length */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xE0, 0xFF, 0xDB, 0xFF, 0xD0, 0xFF, 0xD5, 0xFF, 0xD6, 0xFF, 0xD0, + 0xFF, 0xBF, 0xFF, 0xBE, 0xFF, 0xB9, 0xFF, 0xC8, 0xFF, 0xBF, 0xFF, 0xD5, + 0xFF, 0xC3, 0xFF, 0xBF, 0xFF, 0xB3, 0xFF, 0xBE, 0xFF, 0xB4, 0xFF, 0xAD, + 0xFF, 0xAC, 0xFF, 0xAF, 0xFF, 0xB9, 0xFF, 0xB3, 0xFF, 0xA4, 0xFF, 0xA5, + 0xFF, 0x93, 0xFF, 0x95, 0xFF, 0x97, 0xFF, 0x98, 0xFF, 0x99, 0xFF, 0x9E, + 0xFF, 0x90, 0xFF, 0x80, 0xFF, 0x81, 0xFF, 0x7C, 0xFF, 0x80, 0xFF, 0x7C, + 0xFF, 0x72, 0xFF, 0x72, 0xFF, 0x6C, 0xFF, 0x75, 0xFF, 0x6E, 0xFF, 0x6F, + 0xFF, 0x66, 0xFF, 0x62, 0xFF, 0x5C, 0xFF, 0x64, 0xFF, 0x50, 0xFF, 0x56, + 0xFF, 0x56, 0xFF, 0x4A, 0xFF, 0x4A, 0xFF, 0x49, 0xFF, 0x44, 0xFF, 0x49, + 0xFF, 0x3B, 0xFF, 0x3F, 0xFF, 0x48, 0xFF, 0x46, 0xFF, 0x42, 0xFF, 0x49, + 0xFF, 0x43, 0xFF, 0x36, 0xFF, 0x40, 0xFF, 0x35, 0xFF, 0x3F, 0xFF, 0x36, + 0xFF, 0x37, 0xFF, 0x2E, 0xFF, 0x23, 0xFF, 0x23, 0xFF, 0x21, 0xFF, 0x1F, + 0xFF, 0x25, 0xFF, 0x2C, 0xFF, 0x1E, 0xFF, 0x22, 0xFF, 0x24, 0xFF, 0x2B, + 0xFF, 0x35, 0xFF, 0x27, 0xFF, 0x2E, 0xFF, 0x21, 0xFF, 0x18, 0xFF, 0x21, + 0xFF, 0x20, 0xFF, 0x0F, 0xFF, 0x21, 0xFF, 0x1A, 0xFF, 0x10, 0xFF, 0x09, + 0xFF, 0x1E, 0xFF, 0x19, 0xFF, 0x21, 0xFF, 0x13, 0xFF, 0x1B, 0xFF, 0x18, + 0xFF, 0x21, 0xFF, 0x0F, 0xFF, 0x1A, 0xFF, 0x16, 0xFF, 0x21, 0xFF, 0x1B, + 0xFF, 0x1B, 0xFF, 0x23, 0xFF, 0x1A, 0xFF, 0x21, 0xFF, 0x26, 0xFF, 0x23, + 0xFF, 0x26, 0xFF, 0x27, 0xFF, 0x30, 0xFF, 0x27, 0xFF, 0x2F, 0xFF, 0x28, + 0xFF, 0x2C, 0xFF, 0x27, 0xFF, 0x33, 0xFF, 0x29, 0xFF, 0x33, 0xFF, 0x3A, + 0xFF, 0x42, 0xFF, 0x3B, 0xFF, 0x4D, 0xFF, 0x4B, 0xFF, 0x4D, 0xFF, 0x4A, + 0xFF, 0x67, 0xFF, 0x77, 0xFF, 0x73, 0xFF, 0x7B, 0xFF, 0xDE, 0xFF, 0xAD, + 0x00, 0x4A, 0x00, 0x63, 0xEC, 0x8C, 0x03, 0xBB, 0x0E, 0xE4, 0x08, 0xF2, + 0x00, 0x70, 0xE3, 0xD1, 0xE5, 0xE4, 0x01, 0x6E, 0x0A, 0x67, 0x1C, 0x74, + 0xF8, 0x8E, 0x10, 0x7B, 0xEA, 0x3C, 0x09, 0x87, 0x1B, 0x24, 0xEF, 0x05, + 0x17, 0x76, 0x0D, 0x5B, 0x02, 0x43, 0xF5, 0xEF, 0x0C, 0x1D, 0xF7, 0x61, + 0x05, 0x95, 0x0B, 0xC2, 0xF1, 0x69, 0x1A, 0xA1, 0xEC, 0x75, 0xF4, 0x11, + 0x13, 0x4F, 0x13, 0x71, 0xFA, 0x33, 0xEC, 0x32, 0xC8, 0xCF, 0x05, 0xB0, + 0x0B, 0x61, 0x33, 0x19, 0xCE, 0x37, 0xEF, 0xD4, 0x21, 0x9D, 0xFA, 0xAE, +} ; + +static void rw_test (const char *filename) ; + +int +main (void) +{ const char *filename = "rw.aifc" ; + + print_test_name ("aiff_rw_test", filename) ; + + dump_data_to_file (filename, aifc_data, sizeof (aifc_data)) ; + + rw_test (filename) ; + + unlink (filename) ; + + puts ("ok") ; + return 0 ; +} /* main */ + +/*============================================================================== +*/ + +static void +rw_test (const char *filename) +{ SNDFILE *file ; + SF_INFO sfinfo_rd, sfinfo_rw ; + + memset (&sfinfo_rd, 0, sizeof (sfinfo_rd)) ; + memset (&sfinfo_rw, 0, sizeof (sfinfo_rw)) ; + + /* Open the file in read only mode and fill in the SF_INFO struct. */ + if ((file = sf_open (filename, SFM_READ, &sfinfo_rd)) == NULL) + { printf ("\n\nLine %d : sf_open SFM_READ failed : %s\n\n", __LINE__, sf_strerror (NULL)) ; + exit (1) ; + } ; + check_log_buffer_or_die (file, __LINE__) ; + sf_close (file) ; + + /* Now open read/write and close the file. */ + if ((file = sf_open (filename, SFM_RDWR, &sfinfo_rw)) == NULL) + { printf ("\n\nLine %d : sf_open SFM_RDWR failed : %s\n\n", __LINE__, sf_strerror (NULL)) ; + exit (1) ; + } ; + check_log_buffer_or_die (file, __LINE__) ; + sf_close (file) ; + + /* Open again as read only again and fill in a new SF_INFO struct. */ + memset (&sfinfo_rw, 0, sizeof (sfinfo_rw)) ; + if ((file = sf_open (filename, SFM_READ, &sfinfo_rw)) == NULL) + { printf ("\n\nLine %d : sf_open SFM_RDWR failed : %s\n\n", __LINE__, sf_strerror (NULL)) ; + exit (1) ; + } ; + check_log_buffer_or_die (file, __LINE__) ; + sf_close (file) ; + + /* Now compare the two. */ + if (sfinfo_rd.format != sfinfo_rw.format) + { printf ("\n\nLine %d : format mismatch (0x%08X != 0x%08X).\n\n", __LINE__, + sfinfo_rd.format, sfinfo_rw.format) ; + exit (1) ; + } ; + + if (sfinfo_rd.channels != sfinfo_rw.channels) + { printf ("\n\nLine %d : channel count mismatch (%d != %d).\n\n", __LINE__, + sfinfo_rd.channels, sfinfo_rw.channels) ; + exit (1) ; + } ; + + if (sfinfo_rd.frames != sfinfo_rw.frames) + { printf ("\n\nLine %d : frame count mismatch (rd %" PRId64 " != rw %" PRId64 ").\n\n", __LINE__, + sfinfo_rd.frames, sfinfo_rw.frames) ; + exit (1) ; + } ; + + return ; +} /* rw_test */ + diff --git a/extern/libsndfile-modified/tests/alaw_test.c b/extern/libsndfile-modified/tests/alaw_test.c new file mode 100644 index 000000000..01b3dc4f5 --- /dev/null +++ b/extern/libsndfile-modified/tests/alaw_test.c @@ -0,0 +1,238 @@ +/* +** Copyright (C) 1999-2012 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include + +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include + +#include "utils.h" + +#define BUFFER_SIZE (65536) + +static unsigned char alaw_encode (int sample) ; +static int alaw_decode (unsigned int alawbyte) ; + +static short short_buffer [BUFFER_SIZE] ; +static unsigned char alaw_buffer [BUFFER_SIZE] ; + +int +main (void) +{ SNDFILE *file ; + SF_INFO sfinfo ; + const char *filename ; + int k ; + + print_test_name ("alaw_test", "encoder") ; + + filename = "alaw_test.raw" ; + + sf_info_setup (&sfinfo, SF_FORMAT_RAW | SF_FORMAT_ALAW, 44100, 1) ; + + if ((file = sf_open (filename, SFM_WRITE, &sfinfo)) == NULL) + { printf ("sf_open_write failed with error : ") ; + fflush (stdout) ; + puts (sf_strerror (NULL)) ; + exit (1) ; + } ; + + /* Generate a file containing all possible 16 bit sample values + ** and write it to disk as alaw encoded.frames. + */ + + for (k = 0 ; k < 0x10000 ; k++) + short_buffer [k] = k & 0xFFFF ; + + sf_write_short (file, short_buffer, BUFFER_SIZE) ; + sf_close (file) ; + + /* Now open that file and compare the alaw encoded sample values + ** with what they should be. + */ + + if ((file = sf_open (filename, SFM_READ, &sfinfo)) == NULL) + { printf ("sf_open_write failed with error : ") ; + puts (sf_strerror (NULL)) ; + exit (1) ; + } ; + + check_log_buffer_or_die (file, __LINE__) ; + + if (sf_read_raw (file, alaw_buffer, BUFFER_SIZE) != BUFFER_SIZE) + { printf ("sf_read_raw : ") ; + puts (sf_strerror (file)) ; + exit (1) ; + } ; + + for (k = 0 ; k < 0x10000 ; k++) + if (alaw_encode (short_buffer [k]) != alaw_buffer [k]) + { printf ("Encoder error : sample #%d (0x%02X should be 0x%02X)\n", k, alaw_buffer [k], alaw_encode (short_buffer [k])) ; + exit (1) ; + } ; + + sf_close (file) ; + + puts ("ok") ; + + print_test_name ("alaw_test", "decoder") ; + /* Now generate a file containing all possible 8 bit encoded + ** sample values and write it to disk as alaw encoded.frames. + */ + + if (! (file = sf_open (filename, SFM_WRITE, &sfinfo))) + { printf ("sf_open_write failed with error : ") ; + puts (sf_strerror (NULL)) ; + exit (1) ; + } ; + + for (k = 0 ; k < 256 ; k++) + alaw_buffer [k] = k & 0xFF ; + + sf_write_raw (file, alaw_buffer, 256) ; + sf_close (file) ; + + /* Now open that file and compare the alaw decoded sample values + ** with what they should be. + */ + + if (! (file = sf_open (filename, SFM_READ, &sfinfo))) + { printf ("sf_open_write failed with error : ") ; + puts (sf_strerror (NULL)) ; + exit (1) ; + } ; + + check_log_buffer_or_die (file, __LINE__) ; + + if (sf_read_short (file, short_buffer, 256) != 256) + { printf ("sf_read_short : ") ; + puts (sf_strerror (file)) ; + exit (1) ; + } ; + + + for (k = 0 ; k < 256 ; k++) + if (short_buffer [k] != alaw_decode (alaw_buffer [k])) + { printf ("Decoder error : sample #%d (0x%02X should be 0x%02X)\n", k, short_buffer [k], alaw_decode (alaw_buffer [k])) ; + exit (1) ; + } ; + + sf_close (file) ; + + puts ("ok") ; + + unlink (filename) ; + + return 0 ; +} /* main */ + + +/*================================================================================= +** The following routines came from the sox-12.15 (Sound eXcahcnge) distribution. +** +** This code is not compiled into libsndfile. It is only used to test the +** libsndfile lookup tables for correctness. +** +** I have included the original authors comments. +*/ + +/* +** A-law routines by Graeme W. Gill. +** Date: 93/5/7 +** +** References: +** 1) CCITT Recommendation G.711 +** +*/ + +#define ACLIP 31744 + +static +unsigned char alaw_encode (int sample) +{ static int exp_lut [128] = + { 1, 1, 2, 2, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7 + } ; + + int sign, exponent, mantissa ; + unsigned char Alawbyte ; + + /* Get the sample into sign-magnitude. */ + sign = ((~sample) >> 8) & 0x80 ; /* set aside the sign */ + if (sign == 0) + sample = -sample ; /* get magnitude */ + if (sample > ACLIP) + sample = ACLIP ; /* clip the magnitude */ + + /* Convert from 16 bit linear to ulaw. */ + if (sample >= 256) + { exponent = exp_lut [(sample >> 8) & 0x7F] ; + mantissa = (sample >> (exponent + 3)) & 0x0F ; + Alawbyte = ((exponent << 4) | mantissa) ; + } + else + Alawbyte = (sample >> 4) ; + + Alawbyte ^= (sign ^ 0x55) ; + + return Alawbyte ; +} /* alaw_encode */ + +static +int alaw_decode (unsigned int Alawbyte) +{ static int exp_lut [8] = { 0, 264, 528, 1056, 2112, 4224, 8448, 16896 } ; + int sign, exponent, mantissa, sample ; + + Alawbyte ^= 0x55 ; + sign = (Alawbyte & 0x80) ; + Alawbyte &= 0x7f ; /* get magnitude */ + if (Alawbyte >= 16) + { exponent = (Alawbyte >> 4) & 0x07 ; + mantissa = Alawbyte & 0x0F ; + sample = exp_lut [exponent] + (mantissa << (exponent + 3)) ; + } + else + sample = (Alawbyte << 4) + 8 ; + if (sign == 0) + sample = -sample ; + + return sample ; +} /* alaw_decode */ + diff --git a/extern/libsndfile-modified/tests/benchmark-0.0.28 b/extern/libsndfile-modified/tests/benchmark-0.0.28 new file mode 100644 index 000000000..2d2b06f9b --- /dev/null +++ b/extern/libsndfile-modified/tests/benchmark-0.0.28 @@ -0,0 +1,40 @@ +erikd@coltrane > tests/benchmark +Benchmarking libsndfile-0.0.28 +------------------------------ +Each test takes a little over 5 seconds. + + Raw write PCM_16 : 30660117 samples per sec + Raw read PCM_16 : 62788982 samples per sec + +Native endian I/O : + Write short to PCM_16 : 83.37% of raw write + Read short from PCM_16 : 83.17% of raw read + Write int to PCM_24 : 30.78% of raw write + Read int from PCM_24 : 32.96% of raw read + Write int to PCM_32 : 42.05% of raw write + Read int from PCM_32 : 41.11% of raw read + Write float to PCM_16 : 17.75% of raw write + Read float from PCM_16 : 43.27% of raw read + Write float to PCM_24 : 15.30% of raw write + Read float from PCM_24 : 28.09% of raw read + Write float to PCM_32 : 14.55% of raw write + Read float from PCM_32 : 34.65% of raw read + Write float to FLOAT : 28.98% of raw write + Read float from FLOAT : 56.71% of raw read + +Endian swapped I/O : + Write short to PCM_16 : 43.39% of raw write + Read short from PCM_16 : 49.12% of raw read + Write int to PCM_24 : 29.65% of raw write + Read int from PCM_24 : 33.66% of raw read + Write int to PCM_32 : 19.62% of raw write + Read int from PCM_32 : 21.97% of raw read + Write float to PCM_16 : 17.63% of raw write + Read float from PCM_16 : 31.43% of raw read + Write float to PCM_24 : 14.91% of raw write + Read float from PCM_24 : 27.99% of raw read + Write float to PCM_32 : 13.69% of raw write + Read float from PCM_32 : 22.23% of raw read + Write float to FLOAT : 19.25% of raw write + Read float from FLOAT : 25.66% of raw read + diff --git a/extern/libsndfile-modified/tests/benchmark-1.0.0 b/extern/libsndfile-modified/tests/benchmark-1.0.0 new file mode 100644 index 000000000..292283641 --- /dev/null +++ b/extern/libsndfile-modified/tests/benchmark-1.0.0 @@ -0,0 +1,35 @@ +Benchmarking libsndfile-1.0.0 +----------------------------- +Each test takes a little over 5 seconds. + + Raw write PCM_16 : 31084269 samples per sec + Raw read PCM_16 : 63597065 samples per sec + +Native endian I/O : + Write short to PCM_16 : 83.19% of raw write + Read short from PCM_16 : 82.93% of raw read + Write int to PCM_24 : 31.12% of raw write + Read int from PCM_24 : 37.90% of raw read + Write float to PCM_16 : 37.00% of raw write + Read float from PCM_16 : 45.53% of raw read + Write float to PCM_24 : 29.08% of raw write + Read float from PCM_24 : 28.48% of raw read + Write float to PCM_32 : 22.08% of raw write + Read float from PCM_32 : 31.21% of raw read + Write float to FLOAT : 28.70% of raw write + Read float from FLOAT : 56.32% of raw read + +Endian swapped I/O : + Write short to PCM_16 : 22.08% of raw write + Read short from PCM_16 : 23.20% of raw read + Write int to PCM_24 : 30.96% of raw write + Read int from PCM_24 : 37.76% of raw read + Write float to PCM_16 : 35.82% of raw write + Read float from PCM_16 : 22.61% of raw read + Write float to PCM_24 : 27.70% of raw write + Read float from PCM_24 : 28.37% of raw read + Write float to PCM_32 : 20.77% of raw write + Read float from PCM_32 : 23.46% of raw read + Write float to FLOAT : 15.03% of raw write + Read float from FLOAT : 15.43% of raw read + diff --git a/extern/libsndfile-modified/tests/benchmark-1.0.0rc2 b/extern/libsndfile-modified/tests/benchmark-1.0.0rc2 new file mode 100644 index 000000000..770224672 --- /dev/null +++ b/extern/libsndfile-modified/tests/benchmark-1.0.0rc2 @@ -0,0 +1,31 @@ +Benchmarking libsndfile-1.0.0rc2 +-------------------------------- +Each test takes a little over 5 seconds. + + Raw write PCM_16 : 31638069 samples per sec + Raw read PCM_16 : 62788982 samples per sec + +Native endian I/O : + Write short to PCM_16 : 82.37% of raw write + Read short from PCM_16 : 82.17% of raw read + Write int to PCM_24 : 30.80% of raw write + Read int from PCM_24 : 37.95% of raw read + Write float to PCM_16 : 36.22% of raw write + Read float from PCM_16 : 23.32% of raw read + Write float to PCM_24 : 28.41% of raw write + Read float from PCM_24 : 28.41% of raw read + Write float to FLOAT : 28.41% of raw write + Read float from FLOAT : 57.50% of raw read + +Endian swapped I/O : + Write short to PCM_16 : 21.73% of raw write + Read short from PCM_16 : 23.37% of raw read + Write int to PCM_24 : 31.02% of raw write + Read int from PCM_24 : 38.24% of raw read + Write float to PCM_16 : 35.51% of raw write + Read float from PCM_16 : 19.16% of raw read + Write float to PCM_24 : 27.37% of raw write + Read float from PCM_24 : 28.74% of raw read + Write float to FLOAT : 15.11% of raw write + Read float from FLOAT : 15.60% of raw read + diff --git a/extern/libsndfile-modified/tests/benchmark-1.0.18pre16-hendrix b/extern/libsndfile-modified/tests/benchmark-1.0.18pre16-hendrix new file mode 100644 index 000000000..951bc56d2 --- /dev/null +++ b/extern/libsndfile-modified/tests/benchmark-1.0.18pre16-hendrix @@ -0,0 +1,38 @@ +Benchmarking libsndfile-1.0.18pre15 +----------------------------------- +Each test takes a little over 5 seconds. + + Raw write PCM_16 : 103189885 samples per sec + Raw read PCM_16 : 660854036 samples per sec + +Native endian I/O : + Write short to PCM_16 : 95.08% of raw write + Read short from PCM_16 : 96.39% of raw read + Write int to PCM_24 : 54.55% of raw write + Read int from PCM_24 : 28.50% of raw read + Write int to PCM_32 : 46.97% of raw write + Read int from PCM_32 : 39.98% of raw read + Write float to PCM_16 : 60.85% of raw write + Read float from PCM_16 : 27.79% of raw read + Write float to PCM_24 : 46.23% of raw write + Read float from PCM_24 : 22.62% of raw read + Write float to PCM_32 : 35.38% of raw write + Read float from PCM_32 : 24.18% of raw read + Write float to FLOAT : 47.73% of raw write + Read float from FLOAT : 40.62% of raw read + +Endian swapped I/O : + Write short to PCM_16 : 79.98% of raw write + Read short from PCM_16 : 49.27% of raw read + Write int to PCM_24 : 53.80% of raw write + Read int from PCM_24 : 28.50% of raw read + Write int to PCM_32 : 41.68% of raw write + Read int from PCM_32 : 25.89% of raw read + Write float to PCM_16 : 61.03% of raw write + Read float from PCM_16 : 27.74% of raw read + Write float to PCM_24 : 45.10% of raw write + Read float from PCM_24 : 22.43% of raw read + Write float to PCM_32 : 35.24% of raw write + Read float from PCM_32 : 22.37% of raw read + Write float to FLOAT : 42.01% of raw write + Read float from FLOAT : 28.98% of raw read diff --git a/extern/libsndfile-modified/tests/benchmark-1.0.18pre16-mingus b/extern/libsndfile-modified/tests/benchmark-1.0.18pre16-mingus new file mode 100644 index 000000000..fa0584e14 --- /dev/null +++ b/extern/libsndfile-modified/tests/benchmark-1.0.18pre16-mingus @@ -0,0 +1,38 @@ +Benchmarking libsndfile-1.0.18pre15 +----------------------------------- +Each test takes a little over 5 seconds. + + Raw write PCM_16 : 178237074 samples per sec + Raw read PCM_16 : 368885269 samples per sec + +Native endian I/O : + Write short to PCM_16 : 98.84% of raw write + Read short from PCM_16 : 147.10% of raw read + Write int to PCM_24 : 33.74% of raw write + Read int from PCM_24 : 30.82% of raw read + Write int to PCM_32 : 48.34% of raw write + Read int from PCM_32 : 62.43% of raw read + Write float to PCM_16 : 41.86% of raw write + Read float from PCM_16 : 36.73% of raw read + Write float to PCM_24 : 28.38% of raw write + Read float from PCM_24 : 19.50% of raw read + Write float to PCM_32 : 23.68% of raw write + Read float from PCM_32 : 28.76% of raw read + Write float to FLOAT : 47.21% of raw write + Read float from FLOAT : 60.85% of raw read + +Endian swapped I/O : + Write short to PCM_16 : 54.94% of raw write + Read short from PCM_16 : 59.03% of raw read + Write int to PCM_24 : 33.40% of raw write + Read int from PCM_24 : 31.98% of raw read + Write int to PCM_32 : 30.89% of raw write + Read int from PCM_32 : 33.68% of raw read + Write float to PCM_16 : 41.61% of raw write + Read float from PCM_16 : 26.76% of raw read + Write float to PCM_24 : 25.75% of raw write + Read float from PCM_24 : 19.84% of raw read + Write float to PCM_32 : 21.29% of raw write + Read float from PCM_32 : 21.78% of raw read + Write float to FLOAT : 30.82% of raw write + Read float from FLOAT : 35.04% of raw read diff --git a/extern/libsndfile-modified/tests/benchmark-1.0.6pre10-coltrane b/extern/libsndfile-modified/tests/benchmark-1.0.6pre10-coltrane new file mode 100644 index 000000000..12f71a8a7 --- /dev/null +++ b/extern/libsndfile-modified/tests/benchmark-1.0.6pre10-coltrane @@ -0,0 +1,39 @@ +Benchmarking libsndfile-1.0.6pre10 +---------------------------------- +Each test takes a little over 5 seconds. + + Raw write PCM_16 : 28845961 samples per sec + Raw read PCM_16 : 63471874 samples per sec + +Native endian I/O : + Write short to PCM_16 : 86.21% of raw write + Read short from PCM_16 : 82.60% of raw read + Write int to PCM_24 : 34.89% of raw write + Read int from PCM_24 : 37.26% of raw read + Write int to PCM_32 : 43.36% of raw write + Read int from PCM_32 : 41.30% of raw read + Write float to PCM_16 : 43.02% of raw write + Read float from PCM_16 : 43.99% of raw read + Write float to PCM_24 : 32.72% of raw write + Read float from PCM_24 : 28.21% of raw read + Write float to PCM_32 : 25.92% of raw write + Read float from PCM_32 : 30.98% of raw read + Write float to FLOAT : 46.65% of raw write + Read float from FLOAT : 56.66% of raw read + +Endian swapped I/O : + Write short to PCM_16 : 54.53% of raw write + Read short from PCM_16 : 56.32% of raw read + Write int to PCM_24 : 35.28% of raw write + Read int from PCM_24 : 37.33% of raw read + Write int to PCM_32 : 26.21% of raw write + Read int from PCM_32 : 23.51% of raw read + Write float to PCM_16 : 41.39% of raw write + Read float from PCM_16 : 23.56% of raw read + Write float to PCM_24 : 30.86% of raw write + Read float from PCM_24 : 28.27% of raw read + Write float to PCM_32 : 23.83% of raw write + Read float from PCM_32 : 20.54% of raw read + Write float to FLOAT : 27.26% of raw write + Read float from FLOAT : 29.04% of raw read + diff --git a/extern/libsndfile-modified/tests/benchmark-1.0.6pre10-miles b/extern/libsndfile-modified/tests/benchmark-1.0.6pre10-miles new file mode 100644 index 000000000..fffdb8463 --- /dev/null +++ b/extern/libsndfile-modified/tests/benchmark-1.0.6pre10-miles @@ -0,0 +1,39 @@ +Benchmarking libsndfile-1.0.6pre10 +---------------------------------- +Each test takes a little over 5 seconds. + + Raw write PCM_16 : 40092612 samples per sec + Raw read PCM_16 : 42382563 samples per sec + +Native endian I/O : + Write short to PCM_16 : 61.90% of raw write + Read short from PCM_16 : 100.20% of raw read + Write int to PCM_24 : 28.69% of raw write + Read int from PCM_24 : 33.62% of raw read + Write int to PCM_32 : 31.14% of raw write + Read int from PCM_32 : 51.04% of raw read + Write float to PCM_16 : 25.57% of raw write + Read float from PCM_16 : 28.17% of raw read + Write float to PCM_24 : 23.59% of raw write + Read float from PCM_24 : 24.14% of raw read + Write float to PCM_32 : 18.00% of raw write + Read float from PCM_32 : 22.59% of raw read + Write float to FLOAT : 31.32% of raw write + Read float from FLOAT : 51.54% of raw read + +Endian swapped I/O : + Write short to PCM_16 : 42.81% of raw write + Read short from PCM_16 : 54.58% of raw read + Write int to PCM_24 : 29.28% of raw write + Read int from PCM_24 : 33.43% of raw read + Write int to PCM_32 : 22.21% of raw write + Read int from PCM_32 : 27.24% of raw read + Write float to PCM_16 : 25.76% of raw write + Read float from PCM_16 : 26.84% of raw read + Write float to PCM_24 : 23.71% of raw write + Read float from PCM_24 : 24.10% of raw read + Write float to PCM_32 : 18.47% of raw write + Read float from PCM_32 : 21.45% of raw read + Write float to FLOAT : 22.46% of raw write + Read float from FLOAT : 29.72% of raw read + diff --git a/extern/libsndfile-modified/tests/benchmark-latest-coltrane b/extern/libsndfile-modified/tests/benchmark-latest-coltrane new file mode 100644 index 000000000..97ce29a8a --- /dev/null +++ b/extern/libsndfile-modified/tests/benchmark-latest-coltrane @@ -0,0 +1,75 @@ +erikd@coltrane > cat tests/benchmark-0.0.28 +Benchmarking libsndfile-0.0.28 +------------------------------ +Each test takes a little over 5 seconds. + + Raw write PCM_16 : 31022959 samples per sec + Raw read PCM_16 : 63471874 samples per sec + +Native endian I/O : + Write short to PCM_16 : 83.19% of raw write + Read short from PCM_16 : 82.28% of raw read + Write int to PCM_24 : 30.81% of raw write + Read int from PCM_24 : 32.92% of raw read + Write float to PCM_16 : 17.70% of raw write + Read float from PCM_16 : 43.64% of raw read + Write float to PCM_24 : 15.09% of raw write + Read float from PCM_24 : 27.79% of raw read + Write float to PCM_32 : 14.32% of raw write + Read float from PCM_32 : 34.42% of raw read + Write float to FLOAT : 28.64% of raw write + Read float from FLOAT : 56.77% of raw read + +Endian swapped I/O : + Write short to PCM_16 : 44.04% of raw write + Read short from PCM_16 : 49.46% of raw read + Write int to PCM_24 : 28.92% of raw write + Read int from PCM_24 : 33.10% of raw read + Write float to PCM_16 : 17.30% of raw write + Read float from PCM_16 : 31.46% of raw read + Write float to PCM_24 : 14.62% of raw write + Read float from PCM_24 : 27.64% of raw read + Write float to PCM_32 : 13.65% of raw write + Read float from PCM_32 : 22.41% of raw read + Write float to FLOAT : 19.13% of raw write + Read float from FLOAT : 26.21% of raw read + +erikd@coltrane > tests/benchmark +Benchmarking libsndfile-1.0.0 +----------------------------- +Each test takes a little over 5 seconds. + + Raw write PCM_16 : 29884416 samples per sec + Raw read PCM_16 : 63347175 samples per sec + +Native endian I/O : + Write short to PCM_16 : 88.24% of raw write + Read short from PCM_16 : 82.76% of raw read + Write int to PCM_24 : 34.95% of raw write + Read int from PCM_24 : 37.17% of raw read + Write int to PCM_32 : 43.86% of raw write + Read int from PCM_32 : 41.22% of raw read + Write float to PCM_16 : 42.07% of raw write + Read float from PCM_16 : 44.25% of raw read + Write float to PCM_24 : 32.43% of raw write + Read float from PCM_24 : 28.93% of raw read + Write float to PCM_32 : 25.60% of raw write + Read float from PCM_32 : 31.10% of raw read + Write float to FLOAT : 45.55% of raw write + Read float from FLOAT : 57.41% of raw read + +Endian swapped I/O : + Write short to PCM_16 : 43.46% of raw write + Read short from PCM_16 : 43.99% of raw read + Write int to PCM_24 : 35.09% of raw write + Read int from PCM_24 : 37.34% of raw read + Write int to PCM_32 : 24.05% of raw write + Read int from PCM_32 : 19.74% of raw read + Write float to PCM_16 : 40.25% of raw write + Read float from PCM_16 : 32.15% of raw read + Write float to PCM_24 : 31.02% of raw write + Read float from PCM_24 : 28.82% of raw read + Write float to PCM_32 : 23.54% of raw write + Read float from PCM_32 : 23.65% of raw read + Write float to FLOAT : 24.87% of raw write + Read float from FLOAT : 20.28% of raw read diff --git a/extern/libsndfile-modified/tests/benchmark.def b/extern/libsndfile-modified/tests/benchmark.def new file mode 100644 index 000000000..382bf3b1a --- /dev/null +++ b/extern/libsndfile-modified/tests/benchmark.def @@ -0,0 +1,17 @@ +autogen definitions benchmark.tpl; + +data_type = { + type_name = short ; + multiplier = "32700.0" ; + }; + +data_type = { + type_name = int ; + multiplier = "32700.0 * (1 << 16)" ; + }; + +data_type = { + type_name = float ; + multiplier = "1.0" ; + }; + diff --git a/extern/libsndfile-modified/tests/benchmark.tpl b/extern/libsndfile-modified/tests/benchmark.tpl new file mode 100644 index 000000000..14b22e2e2 --- /dev/null +++ b/extern/libsndfile-modified/tests/benchmark.tpl @@ -0,0 +1,360 @@ +[+ AutoGen5 template c +] +/* +** Copyright (C) 2002-2012 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include + +#if HAVE_UNISTD_H +#include +#endif + +#if (HAVE_DECL_S_IRGRP == 0) +#include +#endif + +#include +#include +#include +#include +#include + +#include + +#ifndef M_PI +#define M_PI 3.14159265358979323846264338 +#endif + +/* +** Neat solution to the Win32/OS2 binary file flage requirement. +** If O_BINARY isn't already defined by the inclusion of the system +** headers, set it to zero. +*/ +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#define WRITE_FLAGS (O_WRONLY | O_CREAT | O_TRUNC | O_BINARY) +#define READ_FLAGS (O_RDONLY | O_BINARY) + +#if (defined (WIN32) || defined (_WIN32) || defined (__OS2__)) + #define WRITE_PERMS 0777 +#else + #define WRITE_PERMS (S_IRUSR | S_IWUSR | S_IRGRP) +#endif + +#define BUFFER_SIZE (1 << 18) +#define BLOCK_COUNT (30) +#define TEST_DURATION (5) /* 5 Seconds. */ + +typedef struct +{ double write_rate ; + double read_rate ; +} PERF_STATS ; + +static void *data = NULL ; + +static void calc_raw_performance (PERF_STATS *stats) ; + +[+ FOR data_type ++]static void calc_[+ (get "type_name") +]_performance (int format, double read_rate, double write_rate) ; +[+ ENDFOR data_type ++] + +static int cpu_is_big_endian (void) ; + +static const char* get_subtype_str (int subtype) ; + +int +main (int argc, char *argv []) +{ PERF_STATS stats ; + char buffer [256] = "Benchmarking " ; + int format_major ; + + if (! (data = malloc (BUFFER_SIZE * sizeof (double)))) + { perror ("Error : malloc failed") ; + exit (1) ; + } ; + + sf_command (NULL, SFC_GET_LIB_VERSION, buffer + strlen (buffer), sizeof (buffer) - strlen (buffer)) ; + + puts (buffer) ; + memset (buffer, '-', strlen (buffer)) ; + puts (buffer) ; + printf ("Each test takes a little over %d seconds.\n\n", TEST_DURATION) ; + + calc_raw_performance (&stats) ; + + if (argc < 2 || strcmp ("--native-only", argv [1]) == 0) + { puts ("\nNative endian I/O :") ; + format_major = cpu_is_big_endian () ? SF_FORMAT_AIFF : SF_FORMAT_WAV ; + + calc_short_performance (format_major | SF_FORMAT_PCM_16, stats.read_rate, stats.write_rate) ; + calc_int_performance (format_major | SF_FORMAT_PCM_24, stats.read_rate, stats.write_rate) ; + calc_int_performance (format_major | SF_FORMAT_PCM_32, stats.read_rate, stats.write_rate) ; + calc_float_performance (format_major | SF_FORMAT_PCM_16, stats.read_rate, stats.write_rate) ; + calc_float_performance (format_major | SF_FORMAT_PCM_24, stats.read_rate, stats.write_rate) ; + calc_float_performance (format_major | SF_FORMAT_PCM_32, stats.read_rate, stats.write_rate) ; + calc_float_performance (format_major | SF_FORMAT_FLOAT , stats.read_rate, stats.write_rate) ; + } ; + + if (argc < 2 || strcmp ("--swap-only", argv [1]) == 0) + { puts ("\nEndian swapped I/O :") ; + format_major = cpu_is_big_endian () ? SF_FORMAT_WAV : SF_FORMAT_AIFF ; + + calc_short_performance (format_major | SF_FORMAT_PCM_16, stats.read_rate, stats.write_rate) ; + calc_int_performance (format_major | SF_FORMAT_PCM_24, stats.read_rate, stats.write_rate) ; + calc_int_performance (format_major | SF_FORMAT_PCM_32, stats.read_rate, stats.write_rate) ; + calc_float_performance (format_major | SF_FORMAT_PCM_16, stats.read_rate, stats.write_rate) ; + calc_float_performance (format_major | SF_FORMAT_PCM_24, stats.read_rate, stats.write_rate) ; + calc_float_performance (format_major | SF_FORMAT_PCM_32, stats.read_rate, stats.write_rate) ; + calc_float_performance (format_major | SF_FORMAT_FLOAT , stats.read_rate, stats.write_rate) ; + } ; + + puts ("") ; + + free (data) ; + + return 0 ; +} /* main */ + +/*============================================================================== +*/ + +static void +calc_raw_performance (PERF_STATS *stats) +{ clock_t start_clock, clock_time ; + int fd, k, byte_count, retval, op_count ; + const char *filename ; + + filename = "benchmark.dat" ; + + byte_count = BUFFER_SIZE * sizeof (short) ; + + /* Collect write stats */ + printf (" Raw write PCM_16 : ") ; + fflush (stdout) ; + + clock_time = 0 ; + op_count = 0 ; + start_clock = clock () ; + + while (clock_time < (CLOCKS_PER_SEC * TEST_DURATION)) + { if ((fd = open (filename, WRITE_FLAGS, WRITE_PERMS)) < 0) + { printf ("Error : not able to open file : %s\n", filename) ; + perror ("") ; + exit (1) ; + } ; + + for (k = 0 ; k < BLOCK_COUNT ; k++) + { if ((retval = write (fd, data, byte_count)) != byte_count) + { printf ("Error : write returned %d (should have been %d)\n", retval, byte_count) ; + exit (1) ; + } ; + } ; + + close (fd) ; + + clock_time = clock () - start_clock ; + op_count ++ ; + } ; + + stats->write_rate = (1.0 * BUFFER_SIZE) * BLOCK_COUNT * op_count ; + stats->write_rate *= (1.0 * CLOCKS_PER_SEC) / clock_time ; + printf ("%10.0f samples per sec\n", stats->write_rate) ; + + /* Collect read stats */ + printf (" Raw read PCM_16 : ") ; + fflush (stdout) ; + + clock_time = 0 ; + op_count = 0 ; + start_clock = clock () ; + + while (clock_time < (CLOCKS_PER_SEC * TEST_DURATION)) + { if ((fd = open (filename, READ_FLAGS)) < 0) + { printf ("Error : not able to open file : %s\n", filename) ; + perror ("") ; + exit (1) ; + } ; + + for (k = 0 ; k < BLOCK_COUNT ; k++) + { if ((retval = read (fd, data, byte_count)) != byte_count) + { printf ("Error : write returned %d (should have been %d)\n", retval, byte_count) ; + exit (1) ; + } ; + } ; + + close (fd) ; + + clock_time = clock () - start_clock ; + op_count ++ ; + } ; + + stats->read_rate = (1.0 * BUFFER_SIZE) * BLOCK_COUNT * op_count ; + stats->read_rate *= (1.0 * CLOCKS_PER_SEC) / clock_time ; + printf ("%10.0f samples per sec\n", stats->read_rate) ; + + unlink (filename) ; +} /* calc_raw_performance */ + +/*------------------------------------------------------------------------------ +*/ + +[+ FOR data_type ++]static void +calc_[+ (get "type_name") +]_performance (int format, double read_rate, double write_rate) +{ SNDFILE *file ; + SF_INFO sfinfo ; + clock_t start_clock, clock_time ; + double performance ; + int k, item_count, retval, op_count ; + const char* subtype ; + [+ (get "type_name") +] *[+ (get "type_name") +]_data ; + const char *filename ; + + filename = "benchmark.dat" ; + subtype = get_subtype_str (format & SF_FORMAT_SUBMASK) ; + + [+ (get "type_name") +]_data = data ; + item_count = BUFFER_SIZE ; + for (k = 0 ; k < item_count ; k++) + [+ (get "type_name") +]_data [k] = [+ (get "multiplier") +] * sin (2 * M_PI * k / 32000.0) ; + + /* Collect write stats */ + printf (" Write %-5s to %s : ", "[+ (get "type_name") +]", subtype) ; + fflush (stdout) ; + + sfinfo.channels = 1 ; + sfinfo.format = format ; + sfinfo.frames = 1 ; + sfinfo.samplerate = 32000 ; + + clock_time = 0 ; + op_count = 0 ; + start_clock = clock () ; + + while (clock_time < (CLOCKS_PER_SEC * TEST_DURATION)) + { if (! (file = sf_open (filename, SFM_WRITE, &sfinfo))) + { printf ("Error : not able to open file : %s\n", filename) ; + perror ("") ; + exit (1) ; + } ; + + /* Turn off the addition of a PEAK chunk. */ + sf_command (file, SFC_SET_ADD_PEAK_CHUNK, NULL, SF_FALSE) ; + + for (k = 0 ; k < BLOCK_COUNT ; k++) + { if ((retval = sf_write_[+ (get "type_name") +] (file, [+ (get "type_name") +]_data, item_count)) != item_count) + { printf ("Error : sf_write_short returned %d (should have been %d)\n", retval, item_count) ; + exit (1) ; + } ; + } ; + + sf_close (file) ; + + clock_time = clock () - start_clock ; + op_count ++ ; + } ; + + performance = (1.0 * BUFFER_SIZE) * BLOCK_COUNT * op_count ; + performance *= (1.0 * CLOCKS_PER_SEC) / clock_time ; + printf ("%6.2f%% of raw write\n", 100.0 * performance / write_rate) ; + + /* Collect read stats */ + printf (" Read %-5s from %s : ", "[+ (get "type_name") +]", subtype) ; + fflush (stdout) ; + + clock_time = 0 ; + op_count = 0 ; + start_clock = clock () ; + + while (clock_time < (CLOCKS_PER_SEC * TEST_DURATION)) + { if (! (file = sf_open (filename, SFM_READ, &sfinfo))) + { printf ("Error : not able to open file : %s\n", filename) ; + perror ("") ; + exit (1) ; + } ; + + for (k = 0 ; k < BLOCK_COUNT ; k++) + { if ((retval = sf_read_[+ (get "type_name") +] (file, [+ (get "type_name") +]_data, item_count)) != item_count) + { printf ("Error : write returned %d (should have been %d)\n", retval, item_count) ; + exit (1) ; + } ; + } ; + + sf_close (file) ; + + clock_time = clock () - start_clock ; + op_count ++ ; + } ; + + performance = (1.0 * item_count) * BLOCK_COUNT * op_count ; + performance *= (1.0 * CLOCKS_PER_SEC) / clock_time ; + printf ("%6.2f%% of raw read\n", 100.0 * performance / read_rate) ; + + unlink (filename) ; + +} /* calc_[+ (get "type_name") +]_performance */ +[+ ENDFOR data_type ++] + +/*============================================================================== +*/ + +static int +cpu_is_big_endian (void) +{ unsigned char *cptr ; + int endtest ; + + endtest = 0x12345678 ; + + cptr = (unsigned char*) (&endtest) ; + + if (cptr [0] == 0x12 && cptr [1] == 0x34 && cptr [3] == 0x78) + return SF_TRUE ; + + return SF_FALSE ; +} /* cpu_is_big_endian */ + +static const char* +get_subtype_str (int subtype) +{ switch (subtype) + { case SF_FORMAT_PCM_16 : + return "PCM_16" ; + + case SF_FORMAT_PCM_24 : + return "PCM_24" ; + + case SF_FORMAT_PCM_32 : + return "PCM_32" ; + + case SF_FORMAT_FLOAT : + return "FLOAT " ; + + case SF_FORMAT_DOUBLE : + return "DOUBLE" ; + + default : break ; + } ; + + return "UNKNOWN" ; +} /* get_subtype_str */ + diff --git a/extern/libsndfile-modified/tests/channel_test.c b/extern/libsndfile-modified/tests/channel_test.c new file mode 100644 index 000000000..a69cd32db --- /dev/null +++ b/extern/libsndfile-modified/tests/channel_test.c @@ -0,0 +1,138 @@ +/* +** Copyright (C) 2001-2015 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include +#include +#include + +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include + +#include + +#include "utils.h" + +#define BUFFER_LEN (1 << 10) +#define LOG_BUFFER_SIZE 1024 + +static void channel_test (void) ; +static double max_diff (const float *a, const float *b, unsigned int len, unsigned int * position) ; + +int +main (void) // int argc, char *argv []) +{ channel_test () ; + return 0 ; +} /* main */ + +/*============================================================================================ +** Here are the test functions. +*/ + +static void +channel_test (void) +{ static float float_data [1024] ; + static float read_float [1024] ; + static int read_int [1024] ; + static short read_short [1024] ; + unsigned int ch, k, position = 0 ; + + gen_windowed_sine_float (float_data, ARRAY_LEN (float_data), 0.9) ; + + for (ch = 1 ; ch <= 8 ; ch++) + { SNDFILE *file ; + SF_INFO wsfinfo, rsfinfo ; + sf_count_t wframes = ARRAY_LEN (float_data) / ch ; + double maxdiff ; + char filename [256] ; + + snprintf (filename, sizeof (filename), "chan_%d.wav", ch) ; + print_test_name (__func__, filename) ; + + sf_info_setup (&wsfinfo, SF_FORMAT_WAV | SF_FORMAT_FLOAT, 48000, ch) ; + sf_info_clear (&rsfinfo) ; + + /* Write the test file. */ + file = test_open_file_or_die (filename, SFM_WRITE, &wsfinfo, SF_FALSE, __LINE__) ; + test_writef_float_or_die (file, 0, float_data, wframes, __LINE__) ; + sf_close (file) ; + + /* Read it as float and test. */ + file = test_open_file_or_die (filename, SFM_READ, &rsfinfo, SF_FALSE, __LINE__) ; + exit_if_true (rsfinfo.frames == 0, + "\n\nLine %d : Frames in file %" PRId64 ".\n\n", __LINE__, rsfinfo.frames) ; + exit_if_true (wframes != rsfinfo.frames, + "\n\nLine %d : Wrote %" PRId64 ", read %" PRId64 " frames.\n\n", __LINE__, wframes, rsfinfo.frames) ; + + sf_command (file, SFC_SET_SCALE_FLOAT_INT_READ, NULL, SF_TRUE) ; + + test_readf_float_or_die (file, 0, read_float, rsfinfo.frames, __LINE__) ; + compare_float_or_die (float_data, read_float, ch * rsfinfo.frames, __LINE__) ; + + /* Read it as short and test. */ + test_seek_or_die (file, 0, SEEK_SET, 0, ch, __LINE__) ; + test_readf_short_or_die (file, 0, read_short, rsfinfo.frames, __LINE__) ; + + for (k = 0 ; k < ARRAY_LEN (read_float) ; k++) + read_float [k] = read_short [k] * (0.9 / 0x8000) ; + + maxdiff = max_diff (float_data, read_float, ch * rsfinfo.frames, &position) ; + exit_if_true (maxdiff > 0.5, "\n\nLine %d : Max diff is %f at index %u\n\n", __LINE__, maxdiff, position) ; + + /* Read it as int and test. */ + test_seek_or_die (file, 0, SEEK_SET, 0, ch, __LINE__) ; + test_readf_int_or_die (file, 0, read_int, rsfinfo.frames, __LINE__) ; + + for (k = 0 ; k < ARRAY_LEN (read_float) ; k++) + read_float [k] = read_int [k] * (0.9 / 0x80000000) ; + + maxdiff = max_diff (float_data, read_float, ch * rsfinfo.frames, &position) ; + exit_if_true (maxdiff > 0.5, "\n\nLine %d : Max diff is %f at index %u\n\n", __LINE__, maxdiff, position) ; + + sf_close (file) ; + unlink (filename) ; + printf ("ok\n") ; + } ; + + return ; +} /* channel_test */ + +static double +max_diff (const float *a, const float *b, unsigned int len, unsigned int * position) +{ double mdiff = 0.0, diff ; + unsigned int k ; + + for (k = 0 ; k < len ; k++) + { diff = fabs (a [k] - b [k]) ; + if (diff > mdiff) + { mdiff = diff ; + *position = k ; + } ; + } ; + + return mdiff ; +} /* max_diff */ diff --git a/extern/libsndfile-modified/tests/checksum_test.c b/extern/libsndfile-modified/tests/checksum_test.c new file mode 100644 index 000000000..4b37b3d37 --- /dev/null +++ b/extern/libsndfile-modified/tests/checksum_test.c @@ -0,0 +1,129 @@ +/* +** Copyright (C) 2008-2017 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include + +#include + +#include "utils.h" + +#define SAMPLE_RATE 8000 + +typedef struct +{ int enc_fmt ; + + const char * enc_name ; + const char * dec_name ; + + uint64_t enc_cksum ; + uint64_t dec_cksum ; +} CHECKSUM ; + +static CHECKSUM +checksum_orig [] = +{ + { SF_FORMAT_RAW | SF_FORMAT_ULAW, + "checksum.ulaw", "cksum_ulaw.pcm16", + 0xbd99d34ccbe2fLL, 0xda82168ed82e9LL + }, + { SF_FORMAT_RAW | SF_FORMAT_ALAW, + "checksum.alaw", "cksum_alaw.pcm16", + 0x0004afddc0fcf4bdLL, 0x2e7320230b88LL + }, + { SF_FORMAT_RAW | SF_FORMAT_GSM610, + "checksum.gsm", "cksum_gsm.pcm16", + 0xa06a3faaaf684LL, 0x2d7ff668efeb9LL + }, + { SF_FORMAT_RAW | SF_FORMAT_VOX_ADPCM, + "checksum.vox", "cksum_vox.pcm16", + 0x7c9d7afdb96a1LL, 0xe540df74a4b14LL + }, +} ; + +static void checksum_test (const CHECKSUM * cksum) ; + +static float orig [1 << 14] ; +static short data [1 << 14] ; + +int +main (void) +{ unsigned k ; + + gen_windowed_sine_float (orig, ARRAY_LEN (orig), 0.9) ; + + for (k = 0 ; k < ARRAY_LEN (checksum_orig) ; k++) + checksum_test (&checksum_orig [k]) ; + + return 0 ; +} /* main */ + +/*============================================================================== +*/ + +static void +checksum_test (const CHECKSUM * cksum) +{ SNDFILE * file ; + SF_INFO info ; + + print_test_name (__func__, cksum->enc_name) ; + + memset (&info, 0, sizeof (info)) ; + info.format = cksum->enc_fmt ; + info.channels = 1 ; + info.samplerate = SAMPLE_RATE ; + + file = test_open_file_or_die (cksum->enc_name, SFM_WRITE, &info, 0, __LINE__) ; + test_write_float_or_die (file, 0, orig, ARRAY_LEN (orig), __LINE__) ; + sf_close (file) ; + + check_file_hash_or_die (cksum->enc_name, cksum->enc_cksum, __LINE__) ; + puts ("ok") ; + + /*------------------------------------------------------------------------*/ + + print_test_name (__func__, cksum->dec_name) ; + + info.format = cksum->enc_fmt ; + info.channels = 1 ; + info.samplerate = SAMPLE_RATE ; + + file = test_open_file_or_die (cksum->enc_name, SFM_READ, &info, 0, __LINE__) ; + test_read_short_or_die (file, 0, data, ARRAY_LEN (data), __LINE__) ; + sf_close (file) ; + + info.format = SF_ENDIAN_LITTLE | SF_FORMAT_RAW | SF_FORMAT_PCM_16 ; + info.channels = 1 ; + info.samplerate = SAMPLE_RATE ; + + file = test_open_file_or_die (cksum->dec_name, SFM_WRITE, &info, 0, __LINE__) ; + test_write_short_or_die (file, 0, data, ARRAY_LEN (data), __LINE__) ; + sf_close (file) ; + + check_file_hash_or_die (cksum->dec_name, cksum->dec_cksum, __LINE__) ; + + remove (cksum->enc_name) ; + remove (cksum->dec_name) ; + + puts ("ok") ; +} /* checksum_test */ + diff --git a/extern/libsndfile-modified/tests/chunk_test.c b/extern/libsndfile-modified/tests/chunk_test.c new file mode 100644 index 000000000..0e358e811 --- /dev/null +++ b/extern/libsndfile-modified/tests/chunk_test.c @@ -0,0 +1,446 @@ +/* +** Copyright (C) 2003-2016 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include + +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include + +#include "sfendian.h" +#include "utils.h" + +#define BUFFER_LEN (1 << 10) +#define LOG_BUFFER_SIZE 1024 + +static void chunk_test (const char *filename, int format) ; +static void wav_subchunk_test (unsigned int chunk_size) ; +static void large_free_test (const char *filename, int format, unsigned int chunk_size) ; + +int +main (int argc, char *argv []) +{ int do_all = 0 ; + int test_count = 0, k ; + + if (argc != 2) + { printf ("Usage : %s \n", argv [0]) ; + printf (" Where is one of the following:\n") ; + printf (" wav - test adding chunks to WAV files\n") ; + printf (" aiff - test adding chunks to AIFF files\n") ; + printf (" caf - test adding chunks to CAF files\n") ; + printf (" rf64 - test adding chunks to RF64 files\n") ; + printf (" all - perform all tests\n") ; + exit (1) ; + } ; + + do_all = ! strcmp (argv [1], "all") ; + + if (do_all || ! strcmp (argv [1], "wav")) + { chunk_test ("chunks_pcm16.wav", SF_FORMAT_WAV | SF_FORMAT_PCM_16) ; + chunk_test ("chunks_pcm16.rifx", SF_ENDIAN_BIG | SF_FORMAT_WAV | SF_FORMAT_PCM_16) ; + chunk_test ("chunks_pcm16.wavex", SF_FORMAT_WAVEX | SF_FORMAT_PCM_16) ; + + for (k = 100 ; k < 10000 ; k *= 4) + wav_subchunk_test (k) ; + + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "aiff")) + { chunk_test ("chunks_pcm16.aiff", SF_FORMAT_AIFF | SF_FORMAT_PCM_16) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "caf")) + { chunk_test ("chunks_pcm16.caf", SF_FORMAT_CAF | SF_FORMAT_PCM_16) ; + chunk_test ("chunks_alac.caf", SF_FORMAT_CAF | SF_FORMAT_ALAC_16) ; + large_free_test ("large_free.caf", SF_FORMAT_CAF | SF_FORMAT_PCM_16, 100) ; + large_free_test ("large_free.caf", SF_FORMAT_CAF | SF_FORMAT_PCM_16, 20000) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "rf64")) + { chunk_test ("chunks_pcm16.rf64", SF_FORMAT_RF64 | SF_FORMAT_PCM_16) ; + test_count++ ; + } ; + + if (test_count == 0) + { printf ("Mono : ************************************\n") ; + printf ("Mono : * No '%s' test defined.\n", argv [1]) ; + printf ("Mono : ************************************\n") ; + return 1 ; + } ; + + return 0 ; +} /* main */ + + +/*============================================================================================ +** Here are the test functions. +*/ + +static void +chunk_test_helper (const char *filename, int format, const char * testdata) +{ SNDFILE *file ; + SF_INFO sfinfo ; + SF_CHUNK_INFO chunk_info ; + SF_CHUNK_ITERATOR * iterator ; + uint32_t length_before ; + int err, allow_fd ; + + switch (format & SF_FORMAT_SUBMASK) + { case SF_FORMAT_ALAC_16 : + allow_fd = SF_FALSE ; + break ; + default : + allow_fd = SF_TRUE ; + break ; + } ; + + sfinfo.samplerate = 44100 ; + sfinfo.channels = 1 ; + sfinfo.frames = 0 ; + sfinfo.format = format ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, allow_fd, __LINE__) ; + + /* Set up the chunk to write. */ + memset (&chunk_info, 0, sizeof (chunk_info)) ; + snprintf (chunk_info.id, sizeof (chunk_info.id), "Test") ; + chunk_info.id_size = 4 ; + chunk_info.data = strdup (testdata) ; + chunk_info.datalen = (unsigned int) strlen (chunk_info.data) ; + + length_before = chunk_info.datalen ; + + err = sf_set_chunk (file, &chunk_info) ; + exit_if_true ( + err != SF_ERR_NO_ERROR, + "\n\nLine %d : sf_set_chunk returned for testdata '%s' : %s\n\n", __LINE__, testdata, sf_error_number (err) + ) ; + + memset (chunk_info.data, 0, chunk_info.datalen) ; + free (chunk_info.data) ; + + sf_close (file) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, allow_fd, __LINE__) ; + + memset (&chunk_info, 0, sizeof (chunk_info)) ; + snprintf (chunk_info.id, sizeof (chunk_info.id), "Test") ; + chunk_info.id_size = 4 ; + + iterator = sf_get_chunk_iterator (file, &chunk_info) ; + err = sf_get_chunk_size (iterator, &chunk_info) ; + exit_if_true ( + err != SF_ERR_NO_ERROR, + "\n\nLine %d : sf_get_chunk_size returned for testdata '%s' : %s\n\n", __LINE__, testdata, sf_error_number (err) + ) ; + + exit_if_true ( + length_before > chunk_info.datalen || chunk_info.datalen - length_before > 4, + "\n\nLine %d : testdata '%s' : Bad chunk length %u (previous length %u)\n\n", __LINE__, testdata, chunk_info.datalen, length_before + ) ; + + chunk_info.data = malloc (chunk_info.datalen) ; + err = sf_get_chunk_data (iterator, &chunk_info) ; + exit_if_true ( + err != SF_ERR_NO_ERROR, + "\n\nLine %d : sf_get_chunk_size returned for testdata '%s' : %s\n\n", __LINE__, testdata, sf_error_number (err) + ) ; + + exit_if_true ( + memcmp (testdata, chunk_info.data, length_before), + "\n\nLine %d : Data compare failed.\n %s\n %s\n\n", __LINE__, testdata, (char*) chunk_info.data + ) ; + + free (chunk_info.data) ; + + sf_close (file) ; + unlink (filename) ; +} /* chunk_test_helper */ + +static void +multichunk_test_helper (const char *filename, int format, const char * testdata [], size_t testdata_len) +{ SNDFILE *file ; + SF_INFO sfinfo ; + SF_CHUNK_INFO chunk_info ; + SF_CHUNK_ITERATOR * iterator ; + uint32_t length_before [16] ; + int err, allow_fd ; + size_t i ; + + + exit_if_true ( + ARRAY_LEN (length_before) < testdata_len, + "\n\nLine %d : Bad array length.\n\n", __LINE__ + ) ; + + + sfinfo.samplerate = 44100 ; + sfinfo.channels = 1 ; + sfinfo.frames = 0 ; + sfinfo.format = format ; + + switch (format & SF_FORMAT_SUBMASK) + { case SF_FORMAT_ALAC_16 : + allow_fd = SF_FALSE ; + break ; + default : + allow_fd = SF_TRUE ; + break ; + } ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, allow_fd, __LINE__) ; + + /* Set up the chunk to write. */ + for (i = 0 ; i < testdata_len ; i++) + { memset (&chunk_info, 0, sizeof (chunk_info)) ; + snprintf (chunk_info.id, sizeof (chunk_info.id), "Test") ; + chunk_info.id_size = 4 ; + + chunk_info.data = strdup (testdata [i]) ; + chunk_info.datalen = (unsigned int) strlen (chunk_info.data) ; + + length_before [i] = chunk_info.datalen ; + + err = sf_set_chunk (file, &chunk_info) ; + exit_if_true ( + err != SF_ERR_NO_ERROR, + "\n\nLine %d : sf_set_chunk returned for testdata[%d] '%s' : %s\n\n", __LINE__, (int) i, testdata [i], sf_error_number (err) + ) ; + + memset (chunk_info.data, 0, chunk_info.datalen) ; + free (chunk_info.data) ; + } + + sf_close (file) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, allow_fd, __LINE__) ; + + memset (&chunk_info, 0, sizeof (chunk_info)) ; + snprintf (chunk_info.id, sizeof (chunk_info.id), "Test") ; + chunk_info.id_size = 4 ; + + iterator = sf_get_chunk_iterator (file, &chunk_info) ; + + i = 0 ; + while (iterator) + { memset (&chunk_info, 0, sizeof (chunk_info)) ; + err = sf_get_chunk_size (iterator, &chunk_info) ; + exit_if_true ( + i > testdata_len, + "\n\nLine %d : iterated to chunk #%d, but only %d chunks have been written\n\n", __LINE__, (int) i, (int) testdata_len + ) ; + + exit_if_true ( + err != SF_ERR_NO_ERROR, + "\n\nLine %d : sf_get_chunk_size returned for testdata[%d] '%s' : %s\n\n", __LINE__, (int) i, testdata [i], sf_error_number (err) + ) ; + + exit_if_true ( + length_before [i] > chunk_info.datalen || chunk_info.datalen - length_before [i] > 4, + "\n\nLine %d : testdata[%d] '%s' : Bad chunk length %u (previous length %u)\n\n", __LINE__, (int) i, testdata [i], chunk_info.datalen, length_before [i] + ) ; + + chunk_info.data = malloc (chunk_info.datalen) ; + err = sf_get_chunk_data (iterator, &chunk_info) ; + exit_if_true ( + err != SF_ERR_NO_ERROR, + "\n\nLine %d : sf_get_chunk_size returned for testdata[%d] '%s' : %s\n\n", __LINE__, (int) i, testdata [i], sf_error_number (err) + ) ; + + exit_if_true ( + 4 != chunk_info.id_size, + "\n\nLine %d : testdata[%d] : Bad ID length %u (previous length %u)\n\n", __LINE__, (int) i, chunk_info.id_size, 4 + ) ; + exit_if_true ( + memcmp ("Test", chunk_info.id, 4), + "\n\nLine %d : ID compare failed at %d.\n %s\n %s\n\n", __LINE__, (int) i, "Test", (char*) chunk_info.id + ) ; + + exit_if_true ( + memcmp (testdata [i], chunk_info.data, length_before [i]), + "\n\nLine %d : Data compare failed at %d.\n %s\n %s\n\n", __LINE__, (int) i, testdata [i], (char*) chunk_info.data + ) ; + + free (chunk_info.data) ; + iterator = sf_next_chunk_iterator (iterator) ; + i++ ; + } + + sf_close (file) ; + unlink (filename) ; +} /* multichunk_test_helper */ + + +static void +chunk_test (const char *filename, int format) +{ const char* testdata [] = + { "There can be only one.", "", "A", "AB", "ABC", "ABCD", "ABCDE" } ; + uint32_t k ; + + print_test_name (__func__, filename) ; + + for (k = 0 ; k < ARRAY_LEN (testdata) ; k++) + chunk_test_helper (filename, format, testdata [k]) ; + + multichunk_test_helper (filename, format, testdata, ARRAY_LEN (testdata)) ; + + puts ("ok") ; +} /* chunk_test */ + + +static void +wav_subchunk_test (unsigned int chunk_size) +{ SNDFILE * file ; + SF_INFO sfinfo ; + SF_CHUNK_INFO chunk_info ; + char filename [256] ; + char chunk_data [10240] ; + short audio [16] ; + int err, value ; + + snprintf (filename, sizeof (filename), "subchunk_%04u.wav", chunk_size) ; + print_test_name (__func__, filename) ; + + exit_if_true (sizeof (chunk_data) < chunk_size, "\n\nLine %d : sizeof (data) < chunk_size\n\n", __LINE__) ; + + memset (chunk_data, 53, sizeof (chunk_data)) ; + chunk_data [chunk_size] = 0 ; + + /* Fill in the chunk data. */ + value = MAKE_MARKER ('a', 'd', 't', 'l') ; + memcpy (chunk_data, &value, sizeof (value)) ; + value = MAKE_MARKER ('n', 'o', 't', 'e') ; + memcpy (chunk_data + 4, &value, sizeof (value)) ; + value = H2LE_32 (chunk_size - 12) ; + memcpy (chunk_data + 8, &value, sizeof (value)) ; + + sfinfo.samplerate = 44100 ; + sfinfo.channels = 1 ; + sfinfo.frames = 0 ; + sfinfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + + /* Set up the chunk to write. */ + memset (&chunk_info, 0, sizeof (chunk_info)) ; + snprintf (chunk_info.id, sizeof (chunk_info.id), "LIST") ; + chunk_info.id_size = 4 ; + chunk_info.data = chunk_data ; + chunk_info.datalen = (unsigned int) chunk_size ; + + err = sf_set_chunk (file, &chunk_info) ; + exit_if_true ( + err != SF_ERR_NO_ERROR, + "\n\nLine %d : sf_set_chunk returned for testdata : %s\n\n", __LINE__, sf_error_number (err) + ) ; + + memset (chunk_info.data, 0, chunk_info.datalen) ; + + /* Add some audio data. */ + memset (audio, 0, sizeof (audio)) ; + sf_write_short (file, audio, ARRAY_LEN (audio)) ; + + sf_close (file) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + + exit_if_true ( + sfinfo.frames != ARRAY_LEN (audio), + "\n\nLine %d : Incorrect sample count (%d should be %d)\n", __LINE__, (int) sfinfo.frames, (int) ARRAY_LEN (audio) + ) ; + + if (chunk_size < 512) + check_log_buffer_or_die (file, __LINE__) ; + + sf_close (file) ; + + unlink (filename) ; + puts ("ok") ; +} /* wav_subchunk_test */ + +static void +large_free_test (const char *filename, int format, unsigned int chunk_size) +{ SNDFILE * file ; + SF_INFO sfinfo ; + SF_CHUNK_INFO chunk_info ; + char chunk_data [20002] ; + short audio [16] ; + int err ; + + print_test_name (__func__, filename) ; + + exit_if_true (sizeof (chunk_data) <= chunk_size, "\n\nLine %d : sizeof (data) < chunk_size\n\n", __LINE__) ; + + memset (chunk_data, 53, sizeof (chunk_data)) ; + chunk_data [chunk_size] = 0 ; + + sfinfo.samplerate = 44100 ; + sfinfo.channels = 1 ; + sfinfo.frames = 0 ; + sfinfo.format = format ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + + /* Set up the chunk to write. */ + memset (&chunk_info, 0, sizeof (chunk_info)) ; + snprintf (chunk_info.id, sizeof (chunk_info.id), "free") ; + chunk_info.id_size = 4 ; + chunk_info.data = chunk_data ; + chunk_info.datalen = chunk_size ; + + err = sf_set_chunk (file, &chunk_info) ; + exit_if_true ( + err != SF_ERR_NO_ERROR, + "\n\nLine %d : sf_set_chunk returned for testdata : %s\n\n", __LINE__, sf_error_number (err) + ) ; + + memset (chunk_info.data, 0, chunk_info.datalen) ; + + /* Add some audio data. */ + memset (audio, 0, sizeof (audio)) ; + sf_write_short (file, audio, ARRAY_LEN (audio)) ; + + sf_close (file) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + + exit_if_true ( + sfinfo.frames != ARRAY_LEN (audio), + "\n\nLine %d : Incorrect sample count (%d should be %d)\n", __LINE__, (int) sfinfo.frames, (int) ARRAY_LEN (audio) + ) ; + + if (chunk_size < 512) + check_log_buffer_or_die (file, __LINE__) ; + + sf_close (file) ; + + unlink (filename) ; + puts ("ok") ; +} /* large_free_test */ diff --git a/extern/libsndfile-modified/tests/command_test.c b/extern/libsndfile-modified/tests/command_test.c new file mode 100644 index 000000000..86cbcfb39 --- /dev/null +++ b/extern/libsndfile-modified/tests/command_test.c @@ -0,0 +1,1806 @@ +/* +** Copyright (C) 2001-2019 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include +#include +#include + +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include + +#include + +#include "sfendian.h" +#include "utils.h" + +#define BUFFER_LEN (1 << 10) +#define LOG_BUFFER_SIZE 1024 +#define data_MARKER MAKE_MARKER ('d', 'a', 't', 'a') + +static void float_norm_test (const char *filename) ; +static void double_norm_test (const char *filename) ; +static void format_tests (void) ; +static void calc_peak_test (int filetype, const char *filename, int channels) ; +static void truncate_test (const char *filename, int filetype) ; +static void instrument_test (const char *filename, int filetype) ; +static void cue_test (const char *filename, int filetype) ; +static void cue_test_var (const char *filename, int filetype, int count) ; +static void channel_map_test (const char *filename, int filetype) ; +static void current_sf_info_test (const char *filename) ; +static void raw_needs_endswap_test (const char *filename, int filetype) ; + +static void broadcast_test (const char *filename, int filetype) ; +static void broadcast_rdwr_test (const char *filename, int filetype) ; +static void broadcast_coding_history_test (const char *filename) ; +static void broadcast_coding_history_size (const char *filename) ; + +/* Cart Chunk tests */ +static void cart_test (const char *filename, int filetype) ; +static void cart_rdwr_test (const char *filename, int filetype) ; + +/* Force the start of this buffer to be double aligned. Sparc-solaris will +** choke if its not. +*/ + +static int int_data [BUFFER_LEN] ; +static float float_data [BUFFER_LEN] ; +static double double_data [BUFFER_LEN] ; + +int +main (int argc, char *argv []) +{ int do_all = 0 ; + int test_count = 0 ; + + if (argc != 2) + { printf ("Usage : %s \n", argv [0]) ; + printf (" Where is one of the following:\n") ; + printf (" ver - test sf_command (SFC_GETLIB_VERSION)\n") ; + printf (" norm - test floating point normalisation\n") ; + printf (" format - test format string commands\n") ; + printf (" peak - test peak calculation\n") ; + printf (" trunc - test file truncation\n") ; + printf (" inst - test set/get of SF_INSTRUMENT.\n") ; + printf (" cue - test set/get of SF_CUES.\n") ; + printf (" chanmap - test set/get of channel map data..\n") ; + printf (" bext - test set/get of SF_BROADCAST_INFO.\n") ; + printf (" bextch - test set/get of SF_BROADCAST_INFO coding_history.\n") ; + printf (" cart - test set/get of SF_CART_INFO.\n") ; + printf (" rawend - test SFC_RAW_NEEDS_ENDSWAP.\n") ; + printf (" all - perform all tests\n") ; + exit (1) ; + } ; + + do_all = ! strcmp (argv [1], "all") ; + + if (do_all || strcmp (argv [1], "ver") == 0) + { char buffer [128] ; + + print_test_name ("version_test", "(none)") ; + buffer [0] = 0 ; + sf_command (NULL, SFC_GET_LIB_VERSION, buffer, sizeof (buffer)) ; + if (strlen (buffer) < 1) + { printf ("Line %d: could not retrieve lib version.\n", __LINE__) ; + exit (1) ; + } ; + puts ("ok") ; + test_count ++ ; + } ; + + if (do_all || strcmp (argv [1], "norm") == 0) + { /* Preliminary float/double normalisation tests. More testing + ** is done in the program 'floating_point_test'. + */ + float_norm_test ("cmd_float.wav") ; + double_norm_test ("cmd_double.wav") ; + test_count ++ ; + } ; + + if (do_all || strcmp (argv [1], "peak") == 0) + { calc_peak_test (SF_ENDIAN_BIG | SF_FORMAT_RAW, "be-peak.raw", 1) ; + calc_peak_test (SF_ENDIAN_LITTLE | SF_FORMAT_RAW, "le-peak.raw", 1) ; + calc_peak_test (SF_ENDIAN_BIG | SF_FORMAT_RAW, "be-peak.raw", 7) ; + calc_peak_test (SF_ENDIAN_LITTLE | SF_FORMAT_RAW, "le-peak.raw", 7) ; + test_count ++ ; + } ; + + if (do_all || ! strcmp (argv [1], "format")) + { format_tests () ; + test_count ++ ; + } ; + + if (do_all || strcmp (argv [1], "trunc") == 0) + { truncate_test ("truncate.raw", SF_FORMAT_RAW | SF_FORMAT_PCM_32) ; + truncate_test ("truncate.au" , SF_FORMAT_AU | SF_FORMAT_PCM_16) ; + test_count ++ ; + } ; + + if (do_all || strcmp (argv [1], "inst") == 0) + { instrument_test ("instrument.wav", SF_FORMAT_WAV | SF_FORMAT_PCM_16) ; + /*-instrument_test ("instrument.aiff" , SF_FORMAT_AIFF | SF_FORMAT_PCM_24) ;-*/ + /*-instrument_test ("instrument.xi", SF_FORMAT_XI | SF_FORMAT_DPCM_16) ;-*/ + test_count ++ ; + } ; + + if (do_all || strcmp (argv [1], "cue") == 0) + { /* 2500 is close to the largest number of cues possible because of block sizes (enforced in aiff.c, wav.c) */ + int cuecounts [] = { 0, 1, 10, 100, 101, 1000, 1001, 2500 } ; + unsigned int i ; + + cue_test ("cue.wav", SF_FORMAT_WAV | SF_FORMAT_PCM_16) ; + cue_test ("cue.aiff" , SF_FORMAT_AIFF | SF_FORMAT_PCM_24) ; + + for (i = 0 ; i < ARRAY_LEN (cuecounts) ; i++) + { cue_test_var ("cue.wav", SF_FORMAT_WAV | SF_FORMAT_PCM_16, cuecounts [i]) ; + cue_test_var ("cue.aiff", SF_FORMAT_AIFF | SF_FORMAT_PCM_24, cuecounts [i]) ; + } ; + + test_count ++ ; + } ; + + if (do_all || strcmp (argv [1], "current_sf_info") == 0) + { current_sf_info_test ("current.wav") ; + test_count ++ ; + } ; + + if (do_all || strcmp (argv [1], "bext") == 0) + { broadcast_test ("broadcast.wav", SF_FORMAT_WAV | SF_FORMAT_PCM_16) ; + broadcast_rdwr_test ("broadcast.wav", SF_FORMAT_WAV | SF_FORMAT_PCM_16) ; + + broadcast_test ("broadcast.wavex", SF_FORMAT_WAVEX | SF_FORMAT_PCM_16) ; + broadcast_rdwr_test ("broadcast.wavex", SF_FORMAT_WAVEX | SF_FORMAT_PCM_16) ; + + broadcast_test ("broadcast.rf64", SF_FORMAT_RF64 | SF_FORMAT_PCM_16) ; + broadcast_rdwr_test ("broadcast.rf64", SF_FORMAT_RF64 | SF_FORMAT_PCM_16) ; + test_count ++ ; + } ; + + if (do_all || strcmp (argv [1], "cart") == 0) + { cart_test ("cart.wav", SF_FORMAT_WAV | SF_FORMAT_PCM_16) ; + cart_rdwr_test ("cart.wav", SF_FORMAT_WAV | SF_FORMAT_PCM_16) ; + cart_test ("cart.rf64", SF_FORMAT_RF64 | SF_FORMAT_PCM_16) ; + cart_rdwr_test ("cart.rf64", SF_FORMAT_RF64 | SF_FORMAT_PCM_16) ; + test_count ++ ; + } ; + + if (do_all || strcmp (argv [1], "bextch") == 0) + { broadcast_coding_history_test ("coding_history.wav") ; + broadcast_coding_history_size ("coding_hist_size.wav") ; + test_count ++ ; + } ; + + if (do_all || strcmp (argv [1], "chanmap") == 0) + { channel_map_test ("chanmap.wavex", SF_FORMAT_WAVEX | SF_FORMAT_PCM_16) ; + channel_map_test ("chanmap.rf64", SF_FORMAT_RF64 | SF_FORMAT_PCM_16) ; + channel_map_test ("chanmap.aifc" , SF_FORMAT_AIFF | SF_FORMAT_PCM_16) ; + channel_map_test ("chanmap.caf" , SF_FORMAT_CAF | SF_FORMAT_PCM_16) ; + test_count ++ ; + } ; + + if (do_all || strcmp (argv [1], "rawend") == 0) + { raw_needs_endswap_test ("raw_end.wav", SF_FORMAT_WAV) ; + raw_needs_endswap_test ("raw_end.wavex", SF_FORMAT_WAVEX) ; + raw_needs_endswap_test ("raw_end.rifx", SF_ENDIAN_BIG | SF_FORMAT_WAV) ; + raw_needs_endswap_test ("raw_end.aiff", SF_FORMAT_AIFF) ; + raw_needs_endswap_test ("raw_end.aiff_le", SF_ENDIAN_LITTLE | SF_FORMAT_AIFF) ; + test_count ++ ; + } ; + + if (test_count == 0) + { printf ("Mono : ************************************\n") ; + printf ("Mono : * No '%s' test defined.\n", argv [1]) ; + printf ("Mono : ************************************\n") ; + return 1 ; + } ; + + return 0 ; +} /* main */ + +/*============================================================================================ +** Here are the test functions. +*/ + +static void +float_norm_test (const char *filename) +{ SNDFILE *file ; + SF_INFO sfinfo ; + unsigned int k ; + + print_test_name ("float_norm_test", filename) ; + + sfinfo.samplerate = 44100 ; + sfinfo.format = (SF_FORMAT_RAW | SF_FORMAT_PCM_16) ; + sfinfo.channels = 1 ; + sfinfo.frames = BUFFER_LEN ; + + /* Create float_data with all values being less than 1.0. */ + for (k = 0 ; k < BUFFER_LEN / 2 ; k++) + float_data [k] = (k + 5) / (2.0f * BUFFER_LEN) ; + for (k = BUFFER_LEN / 2 ; k < BUFFER_LEN ; k++) + float_data [k] = (float) (k + 5) ; + + if (! (file = sf_open (filename, SFM_WRITE, &sfinfo))) + { printf ("Line %d: sf_open_write failed with error : ", __LINE__) ; + fflush (stdout) ; + puts (sf_strerror (NULL)) ; + exit (1) ; + } ; + + /* Normalisation is on by default so no need to do anything here. */ + + if ((k = (unsigned int) sf_write_float (file, float_data, BUFFER_LEN / 2)) != BUFFER_LEN / 2) + { printf ("Line %d: sf_write_float failed with short write (%d ->%d)\n", __LINE__, BUFFER_LEN, k) ; + exit (1) ; + } ; + + /* Turn normalisation off. */ + sf_command (file, SFC_SET_NORM_FLOAT, NULL, SF_FALSE) ; + + if ((k = (unsigned int) sf_write_float (file, float_data + BUFFER_LEN / 2, BUFFER_LEN / 2)) != BUFFER_LEN / 2) + { printf ("Line %d: sf_write_float failed with short write (%d ->%d)\n", __LINE__, BUFFER_LEN, k) ; + exit (1) ; + } ; + + sf_close (file) ; + + /* sfinfo struct should still contain correct data. */ + if (! (file = sf_open (filename, SFM_READ, &sfinfo))) + { printf ("Line %d: sf_open_read failed with error : ", __LINE__) ; + fflush (stdout) ; + puts (sf_strerror (NULL)) ; + exit (1) ; + } ; + + if (sfinfo.format != (SF_FORMAT_RAW | SF_FORMAT_PCM_16)) + { printf ("Line %d: Returned format incorrect (0x%08X => 0x%08X).\n", __LINE__, (SF_FORMAT_RAW | SF_FORMAT_PCM_16), sfinfo.format) ; + exit (1) ; + } ; + + if (sfinfo.frames != BUFFER_LEN) + { printf ("\n\nLine %d: Incorrect number of.frames in file. (%d => %" PRId64 ")\n", __LINE__, BUFFER_LEN, sfinfo.frames) ; + exit (1) ; + } ; + + if (sfinfo.channels != 1) + { printf ("Line %d: Incorrect number of channels in file.\n", __LINE__) ; + exit (1) ; + } ; + + /* Read float_data and check that it is normalised (ie default). */ + if ((k = (unsigned int) sf_read_float (file, float_data, BUFFER_LEN)) != BUFFER_LEN) + { printf ("\n\nLine %d: sf_read_float failed with short read (%d ->%d)\n", __LINE__, BUFFER_LEN, k) ; + exit (1) ; + } ; + + for (k = 0 ; k < BUFFER_LEN ; k++) + if (float_data [k] >= 1.0) + { printf ("\n\nLine %d: float_data [%d] == %f which is greater than 1.0\n", __LINE__, k, float_data [k]) ; + exit (1) ; + } ; + + /* Seek to start of file, turn normalisation off, read float_data and check again. */ + sf_seek (file, 0, SEEK_SET) ; + sf_command (file, SFC_SET_NORM_FLOAT, NULL, SF_FALSE) ; + + if ((k = (unsigned int) sf_read_float (file, float_data, BUFFER_LEN)) != BUFFER_LEN) + { printf ("\n\nLine %d: sf_read_float failed with short read (%d ->%d)\n", __LINE__, BUFFER_LEN, k) ; + exit (1) ; + } ; + + for (k = 0 ; k < BUFFER_LEN ; k++) + if (float_data [k] < 1.0) + { printf ("\n\nLine %d: float_data [%d] == %f which is less than 1.0\n", __LINE__, k, float_data [k]) ; + exit (1) ; + } ; + + /* Seek to start of file, turn normalisation on, read float_data and do final check. */ + sf_seek (file, 0, SEEK_SET) ; + sf_command (file, SFC_SET_NORM_FLOAT, NULL, SF_TRUE) ; + + if ((k = (unsigned int) sf_read_float (file, float_data, BUFFER_LEN)) != BUFFER_LEN) + { printf ("\n\nLine %d: sf_read_float failed with short read (%d ->%d)\n", __LINE__, BUFFER_LEN, k) ; + exit (1) ; + } ; + + for (k = 0 ; k < BUFFER_LEN ; k++) + if (float_data [k] > 1.0) + { printf ("\n\nLine %d: float_data [%d] == %f which is greater than 1.0\n", __LINE__, k, float_data [k]) ; + exit (1) ; + } ; + + + sf_close (file) ; + + unlink (filename) ; + + printf ("ok\n") ; +} /* float_norm_test */ + +static void +double_norm_test (const char *filename) +{ SNDFILE *file ; + SF_INFO sfinfo ; + unsigned int k ; + + print_test_name ("double_norm_test", filename) ; + + sfinfo.samplerate = 44100 ; + sfinfo.format = (SF_FORMAT_RAW | SF_FORMAT_PCM_16) ; + sfinfo.channels = 1 ; + sfinfo.frames = BUFFER_LEN ; + + /* Create double_data with all values being less than 1.0. */ + for (k = 0 ; k < BUFFER_LEN / 2 ; k++) + double_data [k] = (k + 5) / (2.0 * BUFFER_LEN) ; + for (k = BUFFER_LEN / 2 ; k < BUFFER_LEN ; k++) + double_data [k] = (k + 5) ; + + if (! (file = sf_open (filename, SFM_WRITE, &sfinfo))) + { printf ("Line %d: sf_open_write failed with error : ", __LINE__) ; + fflush (stdout) ; + puts (sf_strerror (NULL)) ; + exit (1) ; + } ; + + /* Normailsation is on by default so no need to do anything here. */ + /*-sf_command (file, "set-norm-double", "true", 0) ;-*/ + + if ((k = (unsigned int) sf_write_double (file, double_data, BUFFER_LEN / 2)) != BUFFER_LEN / 2) + { printf ("Line %d: sf_write_double failed with short write (%d ->%d)\n", __LINE__, BUFFER_LEN, k) ; + exit (1) ; + } ; + + /* Turn normalisation off. */ + sf_command (file, SFC_SET_NORM_DOUBLE, NULL, SF_FALSE) ; + + if ((k = (unsigned int) sf_write_double (file, double_data + BUFFER_LEN / 2, BUFFER_LEN / 2)) != BUFFER_LEN / 2) + { printf ("Line %d: sf_write_double failed with short write (%d ->%d)\n", __LINE__, BUFFER_LEN, k) ; + exit (1) ; + } ; + + sf_close (file) ; + + if (! (file = sf_open (filename, SFM_READ, &sfinfo))) + { printf ("Line %d: sf_open_read failed with error : ", __LINE__) ; + fflush (stdout) ; + puts (sf_strerror (NULL)) ; + exit (1) ; + } ; + + if (sfinfo.format != (SF_FORMAT_RAW | SF_FORMAT_PCM_16)) + { printf ("Line %d: Returned format incorrect (0x%08X => 0x%08X).\n", __LINE__, (SF_FORMAT_RAW | SF_FORMAT_PCM_16), sfinfo.format) ; + exit (1) ; + } ; + + if (sfinfo.frames != BUFFER_LEN) + { printf ("\n\nLine %d: Incorrect number of.frames in file. (%d => %" PRId64 ")\n", __LINE__, BUFFER_LEN, sfinfo.frames) ; + exit (1) ; + } ; + + if (sfinfo.channels != 1) + { printf ("Line %d: Incorrect number of channels in file.\n", __LINE__) ; + exit (1) ; + } ; + + /* Read double_data and check that it is normalised (ie default). */ + if ((k = (unsigned int) sf_read_double (file, double_data, BUFFER_LEN)) != BUFFER_LEN) + { printf ("\n\nLine %d: sf_read_double failed with short read (%d ->%d)\n", __LINE__, BUFFER_LEN, k) ; + exit (1) ; + } ; + + for (k = 0 ; k < BUFFER_LEN ; k++) + if (double_data [k] >= 1.0) + { printf ("\n\nLine %d: double_data [%d] == %f which is greater than 1.0\n", __LINE__, k, double_data [k]) ; + exit (1) ; + } ; + + /* Seek to start of file, turn normalisation off, read double_data and check again. */ + sf_seek (file, 0, SEEK_SET) ; + sf_command (file, SFC_SET_NORM_DOUBLE, NULL, SF_FALSE) ; + + if ((k = (unsigned int) sf_read_double (file, double_data, BUFFER_LEN)) != BUFFER_LEN) + { printf ("\n\nLine %d: sf_read_double failed with short read (%d ->%d)\n", __LINE__, BUFFER_LEN, k) ; + exit (1) ; + } ; + + for (k = 0 ; k < BUFFER_LEN ; k++) + if (double_data [k] < 1.0) + { printf ("\n\nLine %d: double_data [%d] == %f which is less than 1.0\n", __LINE__, k, double_data [k]) ; + exit (1) ; + } ; + + /* Seek to start of file, turn normalisation on, read double_data and do final check. */ + sf_seek (file, 0, SEEK_SET) ; + sf_command (file, SFC_SET_NORM_DOUBLE, NULL, SF_TRUE) ; + + if ((k = (unsigned int) sf_read_double (file, double_data, BUFFER_LEN)) != BUFFER_LEN) + { printf ("\n\nLine %d: sf_read_double failed with short read (%d ->%d)\n", __LINE__, BUFFER_LEN, k) ; + exit (1) ; + } ; + + for (k = 0 ; k < BUFFER_LEN ; k++) + if (double_data [k] > 1.0) + { printf ("\n\nLine %d: double_data [%d] == %f which is greater than 1.0\n", __LINE__, k, double_data [k]) ; + exit (1) ; + } ; + + + sf_close (file) ; + + unlink (filename) ; + + printf ("ok\n") ; +} /* double_norm_test */ + +static void +format_tests (void) +{ SF_FORMAT_INFO format_info ; + SF_INFO sfinfo ; + const char *last_name ; + int k, count ; + + print_test_name ("format_tests", "(null)") ; + + /* Clear out SF_INFO struct and set channels > 0. */ + memset (&sfinfo, 0, sizeof (sfinfo)) ; + sfinfo.channels = 1 ; + + /* First test simple formats. */ + + sf_command (NULL, SFC_GET_SIMPLE_FORMAT_COUNT, &count, sizeof (int)) ; + + if (count < 0 || count > 30) + { printf ("Line %d: Weird count.\n", __LINE__) ; + exit (1) ; + } ; + + format_info.format = 0 ; + sf_command (NULL, SFC_GET_SIMPLE_FORMAT, &format_info, sizeof (format_info)) ; + + last_name = format_info.name ; + for (k = 1 ; k < count ; k ++) + { format_info.format = k ; + sf_command (NULL, SFC_GET_SIMPLE_FORMAT, &format_info, sizeof (format_info)) ; + if (strcmp (last_name, format_info.name) >= 0) + { printf ("\n\nLine %d: format names out of sequence `%s' < `%s'.\n", __LINE__, last_name, format_info.name) ; + exit (1) ; + } ; + sfinfo.format = format_info.format ; + + if (! sf_format_check (&sfinfo)) + { printf ("\n\nLine %d: sf_format_check failed.\n", __LINE__) ; + printf (" Name : %s\n", format_info.name) ; + printf (" Format : 0x%X\n", sfinfo.format) ; + printf (" Channels : 0x%X\n", sfinfo.channels) ; + printf (" Sample Rate : 0x%X\n", sfinfo.samplerate) ; + exit (1) ; + } ; + last_name = format_info.name ; + } ; + format_info.format = 666 ; + sf_command (NULL, SFC_GET_SIMPLE_FORMAT, &format_info, sizeof (format_info)) ; + + /* Now test major formats. */ + sf_command (NULL, SFC_GET_FORMAT_MAJOR_COUNT, &count, sizeof (int)) ; + + if (count < 0 || count > 30) + { printf ("Line %d: Weird count.\n", __LINE__) ; + exit (1) ; + } ; + + format_info.format = 0 ; + sf_command (NULL, SFC_GET_FORMAT_MAJOR, &format_info, sizeof (format_info)) ; + + last_name = format_info.name ; + for (k = 1 ; k < count ; k ++) + { format_info.format = k ; + sf_command (NULL, SFC_GET_FORMAT_MAJOR, &format_info, sizeof (format_info)) ; + if (strcmp (last_name, format_info.name) >= 0) + { printf ("\n\nLine %d: format names out of sequence (%d) `%s' < `%s'.\n", __LINE__, k, last_name, format_info.name) ; + exit (1) ; + } ; + + last_name = format_info.name ; + } ; + format_info.format = 666 ; + sf_command (NULL, SFC_GET_FORMAT_MAJOR, &format_info, sizeof (format_info)) ; + + /* Now test subtype formats. */ + sf_command (NULL, SFC_GET_FORMAT_SUBTYPE_COUNT, &count, sizeof (int)) ; + + if (count < 0 || count > 33) + { printf ("Line %d: Weird count.\n", __LINE__) ; + exit (1) ; + } ; + + format_info.format = 0 ; + sf_command (NULL, SFC_GET_FORMAT_SUBTYPE, &format_info, sizeof (format_info)) ; + + last_name = format_info.name ; + for (k = 1 ; k < count ; k ++) + { format_info.format = k ; + sf_command (NULL, SFC_GET_FORMAT_SUBTYPE, &format_info, sizeof (format_info)) ; + } ; + format_info.format = 666 ; + sf_command (NULL, SFC_GET_FORMAT_SUBTYPE, &format_info, sizeof (format_info)) ; + + + printf ("ok\n") ; +} /* format_tests */ + +static void +calc_peak_test (int filetype, const char *filename, int channels) +{ SNDFILE *file ; + SF_INFO sfinfo ; + char label [128] ; + int k, format ; + sf_count_t buffer_len, frame_count ; + double peak ; + + snprintf (label, sizeof (label), "calc_peak_test (%d channels)", channels) ; + print_test_name (label, filename) ; + + format = filetype | SF_FORMAT_PCM_16 ; + + buffer_len = BUFFER_LEN - (BUFFER_LEN % channels) ; + frame_count = buffer_len / channels ; + + sfinfo.samplerate = 44100 ; + sfinfo.format = format ; + sfinfo.channels = channels ; + sfinfo.frames = frame_count ; + + /* Create double_data with max value of 0.5. */ + for (k = 0 ; k < buffer_len ; k++) + double_data [k] = (k + 1) / (2.0 * buffer_len) ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + + test_writef_double_or_die (file, 0, double_data, frame_count, __LINE__) ; + + sf_close (file) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + + if (sfinfo.format != format) + { printf ("Line %d: Returned format incorrect (0x%08X => 0x%08X).\n", __LINE__, format, sfinfo.format) ; + exit (1) ; + } ; + + if (sfinfo.frames != frame_count) + { printf ("\n\nLine %d: Incorrect number of frames in file. (%" PRId64 " => %" PRId64 ")\n", __LINE__, frame_count, sfinfo.frames) ; + exit (1) ; + } ; + + if (sfinfo.channels != channels) + { printf ("Line %d: Incorrect number of channels in file.\n", __LINE__) ; + exit (1) ; + } ; + + sf_command (file, SFC_CALC_SIGNAL_MAX, &peak, sizeof (peak)) ; + if (fabs (peak - (1 << 14)) > 1.0) + { printf ("Line %d : Peak value should be %d (is %f).\n", __LINE__, (1 << 14), peak) ; + exit (1) ; + } ; + + sf_command (file, SFC_CALC_NORM_SIGNAL_MAX, &peak, sizeof (peak)) ; + if (fabs (peak - 0.5) > 4e-5) + { printf ("Line %d : Peak value should be %f (is %f).\n", __LINE__, 0.5, peak) ; + exit (1) ; + } ; + + sf_close (file) ; + + format = (filetype | SF_FORMAT_FLOAT) ; + sfinfo.samplerate = 44100 ; + sfinfo.format = format ; + sfinfo.channels = channels ; + sfinfo.frames = frame_count ; + + /* Create double_data with max value of 0.5. */ + for (k = 0 ; k < buffer_len ; k++) + double_data [k] = (k + 1) / (2.0 * buffer_len) ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + + test_writef_double_or_die (file, 0, double_data, frame_count, __LINE__) ; + + sf_close (file) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + + if (sfinfo.format != format) + { printf ("Line %d: Returned format incorrect (0x%08X => 0x%08X).\n", __LINE__, format, sfinfo.format) ; + exit (1) ; + } ; + + if (sfinfo.frames != frame_count) + { printf ("\n\nLine %d: Incorrect number of.frames in file. (%" PRId64 " => %" PRId64 ")\n", __LINE__, frame_count, sfinfo.frames) ; + exit (1) ; + } ; + + if (sfinfo.channels != channels) + { printf ("Line %d: Incorrect number of channels in file.\n", __LINE__) ; + exit (1) ; + } ; + + sf_command (file, SFC_CALC_SIGNAL_MAX, &peak, sizeof (peak)) ; + if (fabs (peak - 0.5) > 1e-5) + { printf ("Line %d : Peak value should be %f (is %f).\n", __LINE__, 0.5, peak) ; + exit (1) ; + } ; + + sf_command (file, SFC_CALC_NORM_SIGNAL_MAX, &peak, sizeof (peak)) ; + if (fabs (peak - 0.5) > 1e-5) + { printf ("Line %d : Peak value should be %f (is %f).\n", __LINE__, 0.5, peak) ; + exit (1) ; + } ; + + sf_close (file) ; + + unlink (filename) ; + + printf ("ok\n") ; +} /* calc_peak_test */ + +static void +truncate_test (const char *filename, int filetype) +{ SNDFILE *file ; + SF_INFO sfinfo ; + sf_count_t len ; + + print_test_name ("truncate_test", filename) ; + + sfinfo.samplerate = 11025 ; + sfinfo.format = filetype ; + sfinfo.channels = 2 ; + + file = test_open_file_or_die (filename, SFM_RDWR, &sfinfo, SF_TRUE, __LINE__) ; + + test_write_int_or_die (file, 0, int_data, BUFFER_LEN, __LINE__) ; + + len = 100 ; + if (sf_command (file, SFC_FILE_TRUNCATE, &len, sizeof (len))) + { printf ("Line %d: sf_command (SFC_FILE_TRUNCATE) returned error.\n", __LINE__) ; + exit (1) ; + } ; + + test_seek_or_die (file, 0, SEEK_CUR, len, 2, __LINE__) ; + test_seek_or_die (file, 0, SEEK_END, len, 2, __LINE__) ; + + sf_close (file) ; + + unlink (filename) ; + puts ("ok") ; +} /* truncate_test */ + +/*------------------------------------------------------------------------------ +*/ + +static void +instrumet_rw_test (const char *filename) +{ SNDFILE *sndfile ; + SF_INFO sfinfo ; + SF_INSTRUMENT inst ; + memset (&sfinfo, 0, sizeof (SF_INFO)) ; + + sndfile = test_open_file_or_die (filename, SFM_RDWR, &sfinfo, SF_FALSE, __LINE__) ; + + if (sf_command (sndfile, SFC_GET_INSTRUMENT, &inst, sizeof (inst)) == SF_TRUE) + { inst.basenote = 22 ; + + if (sf_command (sndfile, SFC_SET_INSTRUMENT, &inst, sizeof (inst)) == SF_TRUE) + printf ("Sucess: [%s] updated\n", filename) ; + else + printf ("Error: SFC_SET_INSTRUMENT on [%s] [%s]\n", filename, sf_strerror (sndfile)) ; + } + else + printf ("Error: SFC_GET_INSTRUMENT on [%s] [%s]\n", filename, sf_strerror (sndfile)) ; + + + if (sf_command (sndfile, SFC_UPDATE_HEADER_NOW, NULL, 0) != 0) + printf ("Error: SFC_UPDATE_HEADER_NOW on [%s] [%s]\n", filename, sf_strerror (sndfile)) ; + + sf_write_sync (sndfile) ; + sf_close (sndfile) ; + + return ; +} /* instrumet_rw_test */ + +static void +instrument_test (const char *filename, int filetype) +{ static SF_INSTRUMENT write_inst = + { 2, /* gain */ + 3, /* detune */ + 4, /* basenote */ + 5, 6, /* key low and high */ + 7, 8, /* velocity low and high */ + 2, /* loop_count */ + { { 801, 2, 3, 0 }, + { 801, 3, 4, 0 }, + } + } ; + SF_INSTRUMENT read_inst ; + SNDFILE *file ; + SF_INFO sfinfo ; + + print_test_name ("instrument_test", filename) ; + + sfinfo.samplerate = 11025 ; + sfinfo.format = filetype ; + sfinfo.channels = 1 ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + if (sf_command (file, SFC_SET_INSTRUMENT, &write_inst, sizeof (write_inst)) == SF_FALSE) + { printf ("\n\nLine %d : sf_command (SFC_SET_INSTRUMENT) failed.\n\n", __LINE__) ; + exit (1) ; + } ; + test_write_double_or_die (file, 0, double_data, BUFFER_LEN, __LINE__) ; + sf_close (file) ; + + memset (&read_inst, 0, sizeof (read_inst)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + if (sf_command (file, SFC_GET_INSTRUMENT, &read_inst, sizeof (read_inst)) == SF_FALSE) + { printf ("\n\nLine %d : sf_command (SFC_GET_INSTRUMENT) failed.\n\n", __LINE__) ; + exit (1) ; + return ; + } ; + check_log_buffer_or_die (file, __LINE__) ; + sf_close (file) ; + + if ((filetype & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV) + { /* + ** For all the fields that WAV doesn't support, modify the + ** write_inst struct to hold the default value that the WAV + ** module should hold. + */ + write_inst.key_lo = write_inst.velocity_lo = 0 ; + write_inst.key_hi = write_inst.velocity_hi = 127 ; + write_inst.gain = 1 ; + } ; + + if ((filetype & SF_FORMAT_TYPEMASK) == SF_FORMAT_XI) + { /* + ** For all the fields that XI doesn't support, modify the + ** write_inst struct to hold the default value that the XI + ** module should hold. + */ + write_inst.basenote = 0 ; + write_inst.detune = 0 ; + write_inst.key_lo = write_inst.velocity_lo = 0 ; + write_inst.key_hi = write_inst.velocity_hi = 127 ; + write_inst.gain = 1 ; + } ; + + if (memcmp (&write_inst, &read_inst, sizeof (write_inst)) != 0) + { printf ("\n\nLine %d : instrument comparison failed.\n\n", __LINE__) ; + printf ("W Base Note : %u\n" + " Detune : %u\n" + " Low Note : %u\tHigh Note : %u\n" + " Low Vel. : %u\tHigh Vel. : %u\n" + " Gain : %d\tCount : %d\n" + " mode : %d\n" + " start : %d\tend : %d\tcount :%d\n" + " mode : %d\n" + " start : %d\tend : %d\tcount :%d\n\n", + write_inst.basenote, + write_inst.detune, + write_inst.key_lo, write_inst.key_hi, + write_inst.velocity_lo, write_inst.velocity_hi, + write_inst.gain, write_inst.loop_count, + write_inst.loops [0].mode, write_inst.loops [0].start, + write_inst.loops [0].end, write_inst.loops [0].count, + write_inst.loops [1].mode, write_inst.loops [1].start, + write_inst.loops [1].end, write_inst.loops [1].count) ; + printf ("R Base Note : %u\n" + " Detune : %u\n" + " Low Note : %u\tHigh Note : %u\n" + " Low Vel. : %u\tHigh Vel. : %u\n" + " Gain : %d\tCount : %d\n" + " mode : %d\n" + " start : %d\tend : %d\tcount :%d\n" + " mode : %d\n" + " start : %d\tend : %d\tcount :%d\n\n", + read_inst.basenote, + read_inst.detune, + read_inst.key_lo, read_inst.key_hi, + read_inst.velocity_lo, read_inst.velocity_hi, + read_inst.gain, read_inst.loop_count, + read_inst.loops [0].mode, read_inst.loops [0].start, + read_inst.loops [0].end, read_inst.loops [0].count, + read_inst.loops [1].mode, read_inst.loops [1].start, + read_inst.loops [1].end, read_inst.loops [1].count) ; + + if ((filetype & SF_FORMAT_TYPEMASK) != SF_FORMAT_XI) + exit (1) ; + } ; + + if (0) instrumet_rw_test (filename) ; + + unlink (filename) ; + puts ("ok") ; +} /* instrument_test */ + +static void +print_cue (SF_CUES *cue, int i) +{ + printf (" indx[%d] : %d\n" + " position : %u\n" + " fcc_chunk : %x\n" + " chunk_start : %d\n" + " block_start : %d\n" + " sample_offset : %u\n" + " name : %s\n", + i, + cue->cue_points [i].indx, + cue->cue_points [i].position, + cue->cue_points [i].fcc_chunk, + cue->cue_points [i].chunk_start, + cue->cue_points [i].block_start, + cue->cue_points [i].sample_offset, + cue->cue_points [i].name) ; +} + +static int +cue_compare (SF_CUES *write_cue, SF_CUES *read_cue, size_t cue_size, int line) +{ + if (memcmp (write_cue, read_cue, cue_size) != 0) + { + printf ("\n\nLine %d : cue comparison failed.\n\n", line) ; + printf ("W Cue count : %d\n", write_cue->cue_count) ; + if (write_cue->cue_count > 0) + print_cue (write_cue, 0) ; + if (write_cue->cue_count > 2) /* print last if at least 2 */ + print_cue (write_cue, write_cue->cue_count - 1) ; + + printf ("R Cue count : %d\n", read_cue->cue_count) ; + if (read_cue->cue_count > 0) + print_cue (read_cue, 0) ; + if (read_cue->cue_count > 2) /* print last if at least 2 */ + print_cue (read_cue, read_cue->cue_count - 1) ; + + return SF_FALSE ; + } ; + + return SF_TRUE ; +} /* cue_compare */ + +static void +cue_rw_test (const char *filename) +{ SNDFILE *sndfile ; + SF_INFO sfinfo ; + SF_CUES cues ; + memset (&sfinfo, 0, sizeof (SF_INFO)) ; + + sndfile = test_open_file_or_die (filename, SFM_RDWR, &sfinfo, SF_FALSE, __LINE__) ; + + exit_if_true ( + sf_command (sndfile, SFC_GET_CUE_COUNT, &cues.cue_count, sizeof (cues.cue_count)) != SF_TRUE, + "\nLine %d: SFC_GET_CUE_COUNT command failed.\n\n", __LINE__ + ) ; + + exit_if_true ( + cues.cue_count != 3, + "\nLine %d: Expected cue_count (%u) to be 3.\n\n", __LINE__, cues.cue_count + ) ; + + if (sf_command (sndfile, SFC_GET_CUE, &cues, sizeof (cues)) == SF_TRUE) + { cues.cue_points [1].sample_offset = 3 ; + + if (sf_command (sndfile, SFC_SET_CUE, &cues, sizeof (cues)) == SF_TRUE) + printf ("Sucess: [%s] updated\n", filename) ; + else + printf ("Error: SFC_SET_CUE on [%s] [%s]\n", filename, sf_strerror (sndfile)) ; + } + else + printf ("Error: SFC_GET_CUE on [%s] [%s]\n", filename, sf_strerror (sndfile)) ; + + + if (sf_command (sndfile, SFC_UPDATE_HEADER_NOW, NULL, 0) != 0) + printf ("Error: SFC_UPDATE_HEADER_NOW on [%s] [%s]\n", filename, sf_strerror (sndfile)) ; + + sf_write_sync (sndfile) ; + sf_close (sndfile) ; + + return ; +} /* cue_rw_test */ + +static void +cue_test (const char *filename, int filetype) +{ SF_CUES write_cue ; + SF_CUES read_cue ; + SNDFILE *file ; + SF_INFO sfinfo ; + + if (filetype == (SF_FORMAT_WAV | SF_FORMAT_PCM_16)) + { write_cue = (SF_CUES) + { 2, /* cue_count */ + { { 1, 0, data_MARKER, 0, 0, 1, "" }, + { 2, 0, data_MARKER, 0, 0, 2, "" }, + } + } ; + } + else + { write_cue = (SF_CUES) + { 2, /* cue_count */ + { { 1, 0, data_MARKER, 0, 0, 1, "Cue1" }, + { 2, 0, data_MARKER, 0, 0, 2, "Cue2" }, + } + } ; + } + + print_test_name ("cue_test", filename) ; + + sfinfo.samplerate = 11025 ; + sfinfo.format = filetype ; + sfinfo.channels = 1 ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + if (sf_command (file, SFC_SET_CUE, &write_cue, sizeof (write_cue)) == SF_FALSE) + { printf ("\n\nLine %d : sf_command (SFC_SET_CUE) failed.\n\n", __LINE__) ; + exit (1) ; + } ; + test_write_double_or_die (file, 0, double_data, BUFFER_LEN, __LINE__) ; + sf_close (file) ; + + memset (&read_cue, 0, sizeof (read_cue)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + if (sf_command (file, SFC_GET_CUE, &read_cue, sizeof (read_cue)) == SF_FALSE) + { printf ("\n\nLine %d : sf_command (SFC_GET_CUE) failed.\n\n", __LINE__) ; + exit (1) ; + return ; + } ; + check_log_buffer_or_die (file, __LINE__) ; + sf_close (file) ; + + if (cue_compare (&write_cue, &read_cue, sizeof (write_cue), __LINE__) == SF_FALSE) + exit (1) ; + + if (0) cue_rw_test (filename) ; + + unlink (filename) ; + puts ("ok") ; +} /* cue_test */ + +/* calculate size of SF_CUES struct given number of cues */ +#define SF_CUES_SIZE(count) (sizeof (uint32_t) + sizeof (SF_CUE_POINT) * (count)) + +static void +cue_test_var (const char *filename, int filetype, int count) +{ size_t cues_size = SF_CUES_SIZE (count) ; + SF_CUES *write_cue = calloc (1, cues_size) ; + SF_CUES *read_cue = calloc (1, cues_size) ; + SNDFILE *file ; + SF_INFO sfinfo ; + char name [40] ; + int i ; + + snprintf (name, sizeof (name), "cue_test_var %d", count) ; + print_test_name (name, filename) ; + + if (write_cue == NULL || read_cue == NULL) + { printf ("ok (can't alloc)\n") ; + return ; + } ; + + write_cue->cue_count = count ; + for (i = 0 ; i < count ; i++) + { write_cue->cue_points [i] = (SF_CUE_POINT) { i, 0, data_MARKER, 0, 0, i, "" } ; + if (filetype == (SF_FORMAT_AIFF | SF_FORMAT_PCM_24)) + snprintf (write_cue->cue_points [i].name, sizeof (write_cue->cue_points [i].name), "Cue%03d", i) ; + } ; + + sfinfo.samplerate = 11025 ; + sfinfo.format = filetype ; + sfinfo.channels = 1 ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + if (sf_command (file, SFC_SET_CUE, write_cue, (int) cues_size) == SF_FALSE) + { printf ("\n\nLine %d : sf_command (SFC_SET_CUE) failed with %d cues, datasize %zu --> error: %s\n\n", __LINE__, count, cues_size, sf_strerror (file)) ; + exit (1) ; + } ; + test_write_double_or_die (file, 0, double_data, BUFFER_LEN, __LINE__) ; + sf_close (file) ; + + memset (read_cue, 0, cues_size) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + + if (sf_command (file, SFC_GET_CUE, read_cue, (int) cues_size) == SF_FALSE) + { printf ("\n\nLine %d : sf_command (SFC_GET_CUE) failed with %d cues, datasize %zu --> error: %s\n\n", __LINE__, count, cues_size, sf_strerror (file)) ; + exit (1) ; + } ; + check_log_buffer_or_die (file, __LINE__) ; + sf_close (file) ; + + if (cue_compare (write_cue, read_cue, cues_size, __LINE__) == SF_FALSE) + { printf ("\n\nLine %d : cue_compare failed.\n\n", __LINE__) ; + exit (1) ; + } ; + + free (write_cue) ; + free (read_cue) ; + unlink (filename) ; + puts ("ok") ; +} /* cue_test_var */ + +static void +current_sf_info_test (const char *filename) +{ SNDFILE *outfile, *infile ; + SF_INFO outinfo, ininfo ; + + print_test_name ("current_sf_info_test", filename) ; + + outinfo.samplerate = 44100 ; + outinfo.format = (SF_FORMAT_WAV | SF_FORMAT_PCM_16) ; + outinfo.channels = 1 ; + outinfo.frames = 0 ; + + outfile = test_open_file_or_die (filename, SFM_WRITE, &outinfo, SF_TRUE, __LINE__) ; + sf_command (outfile, SFC_SET_UPDATE_HEADER_AUTO, NULL, 0) ; + + exit_if_true (outinfo.frames != 0, + "\n\nLine %d : Initial sfinfo.frames is not zero.\n\n", __LINE__ + ) ; + + test_write_double_or_die (outfile, 0, double_data, BUFFER_LEN, __LINE__) ; + sf_command (outfile, SFC_GET_CURRENT_SF_INFO, &outinfo, sizeof (outinfo)) ; + + exit_if_true (outinfo.frames != BUFFER_LEN, + "\n\nLine %d : Initial sfinfo.frames (%" PRId64 ") should be %d.\n\n", __LINE__, + outinfo.frames, BUFFER_LEN + ) ; + + /* Read file making sure no channel map exists. */ + memset (&ininfo, 0, sizeof (ininfo)) ; + infile = test_open_file_or_die (filename, SFM_READ, &ininfo, SF_TRUE, __LINE__) ; + + test_write_double_or_die (outfile, 0, double_data, BUFFER_LEN, __LINE__) ; + + sf_command (infile, SFC_GET_CURRENT_SF_INFO, &ininfo, sizeof (ininfo)) ; + + exit_if_true (ininfo.frames != BUFFER_LEN, + "\n\nLine %d : Initial sfinfo.frames (%" PRId64 ") should be %d.\n\n", __LINE__, + ininfo.frames, BUFFER_LEN + ) ; + + sf_close (outfile) ; + sf_close (infile) ; + + unlink (filename) ; + puts ("ok") ; +} /* current_sf_info_test */ + +static void +broadcast_test (const char *filename, int filetype) +{ static SF_BROADCAST_INFO bc_write, bc_read ; + SNDFILE *file ; + SF_INFO sfinfo ; + int errors = 0 ; + + print_test_name ("broadcast_test", filename) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + sfinfo.samplerate = 11025 ; + sfinfo.format = filetype ; + sfinfo.channels = 1 ; + + memset (&bc_write, 0, sizeof (bc_write)) ; + + snprintf (bc_write.description, sizeof (bc_write.description), "Test description") ; + snprintf (bc_write.originator, sizeof (bc_write.originator), "Test originator") ; + snprintf (bc_write.originator_reference, sizeof (bc_write.originator_reference), "%08x-%08x", (unsigned int) time (NULL), (unsigned int) (~ time (NULL))) ; + snprintf (bc_write.origination_date, sizeof (bc_write.origination_date), "%d/%02d/%02d", 2006, 3, 30) ; + snprintf (bc_write.origination_time, sizeof (bc_write.origination_time), "%02d:%02d:%02d", 20, 27, 0) ; + snprintf (bc_write.umid, sizeof (bc_write.umid), "Some umid") ; + bc_write.coding_history_size = 0 ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + if (sf_command (file, SFC_SET_BROADCAST_INFO, &bc_write, sizeof (bc_write)) == SF_FALSE) + { printf ("\n\nLine %d : sf_command (SFC_SET_BROADCAST_INFO) failed.\n\n", __LINE__) ; + exit (1) ; + } ; + test_write_double_or_die (file, 0, double_data, BUFFER_LEN, __LINE__) ; + sf_close (file) ; + + memset (&bc_read, 0, sizeof (bc_read)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + if (sf_command (file, SFC_GET_BROADCAST_INFO, &bc_read, sizeof (bc_read)) == SF_FALSE) + { printf ("\n\nLine %d : sf_command (SFC_GET_BROADCAST_INFO) failed.\n\n", __LINE__) ; + exit (1) ; + return ; + } ; + check_log_buffer_or_die (file, __LINE__) ; + sf_close (file) ; + + if (bc_read.version != 2) + { printf ("\n\nLine %d : Read bad version number %d.\n\n", __LINE__, bc_read.version) ; + exit (1) ; + return ; + } ; + + bc_read.version = bc_write.version = 0 ; + + if (memcmp (bc_write.description, bc_read.description, sizeof (bc_write.description)) != 0) + { printf ("\n\nLine %d : description mismatch :\n\twrite : '%s'\n\tread : '%s'\n\n", __LINE__, bc_write.description, bc_read.description) ; + errors ++ ; + } ; + + if (memcmp (bc_write.originator, bc_read.originator, sizeof (bc_write.originator)) != 0) + { printf ("\n\nLine %d : originator mismatch :\n\twrite : '%s'\n\tread : '%s'\n\n", __LINE__, bc_write.originator, bc_read.originator) ; + errors ++ ; + } ; + + if (memcmp (bc_write.originator_reference, bc_read.originator_reference, sizeof (bc_write.originator_reference)) != 0) + { printf ("\n\nLine %d : originator_reference mismatch :\n\twrite : '%s'\n\tread : '%s'\n\n", __LINE__, bc_write.originator_reference, bc_read.originator_reference) ; + errors ++ ; + } ; + + if (memcmp (bc_write.origination_date, bc_read.origination_date, sizeof (bc_write.origination_date)) != 0) + { printf ("\n\nLine %d : origination_date mismatch :\n\twrite : '%s'\n\tread : '%s'\n\n", __LINE__, bc_write.origination_date, bc_read.origination_date) ; + errors ++ ; + } ; + + if (memcmp (bc_write.origination_time, bc_read.origination_time, sizeof (bc_write.origination_time)) != 0) + { printf ("\n\nLine %d : origination_time mismatch :\n\twrite : '%s'\n\tread : '%s'\n\n", __LINE__, bc_write.origination_time, bc_read.origination_time) ; + errors ++ ; + } ; + + if (memcmp (bc_write.umid, bc_read.umid, sizeof (bc_write.umid)) != 0) + { printf ("\n\nLine %d : umid mismatch :\n\twrite : '%s'\n\tread : '%s'\n\n", __LINE__, bc_write.umid, bc_read.umid) ; + errors ++ ; + } ; + + if (errors) + exit (1) ; + + unlink (filename) ; + puts ("ok") ; +} /* broadcast_test */ + +static void +broadcast_rdwr_test (const char *filename, int filetype) +{ SF_BROADCAST_INFO binfo ; + SNDFILE *file ; + SF_INFO sfinfo ; + sf_count_t frames ; + + print_test_name (__func__, filename) ; + + create_short_sndfile (filename, filetype, 2) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + memset (&binfo, 0, sizeof (binfo)) ; + + snprintf (binfo.description, sizeof (binfo.description), "Test description") ; + snprintf (binfo.originator, sizeof (binfo.originator), "Test originator") ; + snprintf (binfo.originator_reference, sizeof (binfo.originator_reference), "%08x-%08x", (unsigned int) time (NULL), (unsigned int) (~ time (NULL))) ; + snprintf (binfo.origination_date, sizeof (binfo.origination_date), "%d/%02d/%02d", 2006, 3, 30) ; + snprintf (binfo.origination_time, sizeof (binfo.origination_time), "%02d:%02d:%02d", 20, 27, 0) ; + snprintf (binfo.umid, sizeof (binfo.umid), "Some umid") ; + binfo.coding_history_size = 0 ; + + file = test_open_file_or_die (filename, SFM_RDWR, &sfinfo, SF_TRUE, __LINE__) ; + frames = sfinfo.frames ; + if (sf_command (file, SFC_SET_BROADCAST_INFO, &binfo, sizeof (binfo)) != SF_FALSE) + { printf ("\n\nLine %d : sf_command (SFC_SET_BROADCAST_INFO) should have failed but didn't.\n\n", __LINE__) ; + exit (1) ; + } ; + sf_close (file) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + sf_close (file) ; + exit_if_true (frames != sfinfo.frames, "\n\nLine %d : Frame count %" PRId64 " should be %" PRId64 ".\n", __LINE__, sfinfo.frames, frames) ; + + unlink (filename) ; + puts ("ok") ; +} /* broadcast_rdwr_test */ + +static void +check_coding_history_newlines (const char *filename) +{ static SF_BROADCAST_INFO bc_write, bc_read ; + SNDFILE *file ; + SF_INFO sfinfo ; + unsigned k ; + + sfinfo.samplerate = 22050 ; + sfinfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 ; + sfinfo.channels = 1 ; + + memset (&bc_write, 0, sizeof (bc_write)) ; + + snprintf (bc_write.description, sizeof (bc_write.description), "Test description") ; + snprintf (bc_write.originator, sizeof (bc_write.originator), "Test originator") ; + snprintf (bc_write.originator_reference, sizeof (bc_write.originator_reference), "%08x-%08x", (unsigned int) time (NULL), (unsigned int) (~ time (NULL))) ; + snprintf (bc_write.origination_date, sizeof (bc_write.origination_date), "%d/%02d/%02d", 2006, 3, 30) ; + snprintf (bc_write.origination_time, sizeof (bc_write.origination_time), "%02d:%02d:%02d", 20, 27, 0) ; + snprintf (bc_write.umid, sizeof (bc_write.umid), "Some umid") ; + bc_write.coding_history_size = snprintf (bc_write.coding_history, sizeof (bc_write.coding_history), "This has\nUnix\nand\rMac OS9\rline endings.\nLast line") ; ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + if (sf_command (file, SFC_SET_BROADCAST_INFO, &bc_write, sizeof (bc_write)) == SF_FALSE) + { printf ("\n\nLine %d : sf_command (SFC_SET_BROADCAST_INFO) failed.\n\n", __LINE__) ; + exit (1) ; + } ; + + test_write_double_or_die (file, 0, double_data, BUFFER_LEN, __LINE__) ; + sf_close (file) ; + + memset (&bc_read, 0, sizeof (bc_read)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + if (sf_command (file, SFC_GET_BROADCAST_INFO, &bc_read, sizeof (bc_read)) == SF_FALSE) + { printf ("\n\nLine %d : sf_command (SFC_SET_BROADCAST_INFO) failed.\n\n", __LINE__) ; + exit (1) ; + } ; + check_log_buffer_or_die (file, __LINE__) ; + sf_close (file) ; + + if (bc_read.coding_history_size == 0) + { printf ("\n\nLine %d : missing coding history.\n\n", __LINE__) ; + exit (1) ; + } ; + + if (strstr (bc_read.coding_history, "Last line") == NULL) + { printf ("\n\nLine %d : coding history truncated.\n\n", __LINE__) ; + exit (1) ; + } ; + + for (k = 1 ; k < bc_read.coding_history_size ; k++) + { if (bc_read.coding_history [k] == '\n' && bc_read.coding_history [k - 1] != '\r') + { printf ("\n\nLine %d : '\\n' without '\\r' before.\n\n", __LINE__) ; + exit (1) ; + } ; + + if (bc_read.coding_history [k] == '\r' && bc_read.coding_history [k + 1] != '\n') + { printf ("\n\nLine %d : '\\r' without '\\n' after.\n\n", __LINE__) ; + exit (1) ; + } ; + + if (bc_read.coding_history [k] == 0 && k < bc_read.coding_history_size - 1) + { printf ("\n\nLine %d : '\\0' within coding history at index %d of %d.\n\n", __LINE__, k, bc_read.coding_history_size) ; + exit (1) ; + } ; + } ; + + return ; +} /* check_coding_history_newlines */ + +static void +broadcast_coding_history_test (const char *filename) +{ static SF_BROADCAST_INFO bc_write, bc_read ; + SNDFILE *file ; + SF_INFO sfinfo ; + const char *default_history = "A=PCM,F=22050,W=16,M=mono" ; + const char *supplied_history = + "A=PCM,F=44100,W=24,M=mono,T=other\r\n" + "A=PCM,F=22050,W=16,M=mono,T=yet_another\r\n" ; + + print_test_name ("broadcast_coding_history_test", filename) ; + + sfinfo.samplerate = 22050 ; + sfinfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 ; + sfinfo.channels = 1 ; + + memset (&bc_write, 0, sizeof (bc_write)) ; + + snprintf (bc_write.description, sizeof (bc_write.description), "Test description") ; + snprintf (bc_write.originator, sizeof (bc_write.originator), "Test originator") ; + snprintf (bc_write.originator_reference, sizeof (bc_write.originator_reference), "%08x-%08x", (unsigned int) time (NULL), (unsigned int) (~ time (NULL))) ; + snprintf (bc_write.origination_date, sizeof (bc_write.origination_date), "%d/%02d/%02d", 2006, 3, 30) ; + snprintf (bc_write.origination_time, sizeof (bc_write.origination_time), "%02d:%02d:%02d", 20, 27, 0) ; + snprintf (bc_write.umid, sizeof (bc_write.umid), "Some umid") ; + /* Coding history will be filled in by the library. */ + bc_write.coding_history_size = 0 ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + if (sf_command (file, SFC_SET_BROADCAST_INFO, &bc_write, sizeof (bc_write)) == SF_FALSE) + { printf ("\n\nLine %d : sf_command (SFC_SET_BROADCAST_INFO) failed.\n\n", __LINE__) ; + exit (1) ; + } ; + + test_write_double_or_die (file, 0, double_data, BUFFER_LEN, __LINE__) ; + sf_close (file) ; + + memset (&bc_read, 0, sizeof (bc_read)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + if (sf_command (file, SFC_GET_BROADCAST_INFO, &bc_read, sizeof (bc_read)) == SF_FALSE) + { printf ("\n\nLine %d : sf_command (SFC_SET_BROADCAST_INFO) failed.\n\n", __LINE__) ; + exit (1) ; + } ; + check_log_buffer_or_die (file, __LINE__) ; + sf_close (file) ; + + if (bc_read.coding_history_size == 0) + { printf ("\n\nLine %d : missing coding history.\n\n", __LINE__) ; + exit (1) ; + } ; + + if (bc_read.coding_history_size < strlen (default_history) || memcmp (bc_read.coding_history, default_history, strlen (default_history)) != 0) + { printf ("\n\n" + "Line %d : unexpected coding history '%.*s',\n" + " should be '%s'\n\n", __LINE__, bc_read.coding_history_size, bc_read.coding_history, default_history) ; + exit (1) ; + } ; + + bc_write.coding_history_size = (uint32_t) strlen (supplied_history) ; + bc_write.coding_history_size = snprintf (bc_write.coding_history, sizeof (bc_write.coding_history), "%s", supplied_history) ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + if (sf_command (file, SFC_SET_BROADCAST_INFO, &bc_write, sizeof (bc_write)) == SF_FALSE) + { printf ("\n\nLine %d : sf_command (SFC_SET_BROADCAST_INFO) failed.\n\n", __LINE__) ; + exit (1) ; + } ; + + test_write_double_or_die (file, 0, double_data, BUFFER_LEN, __LINE__) ; + sf_close (file) ; + + memset (&bc_read, 0, sizeof (bc_read)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + if (sf_command (file, SFC_GET_BROADCAST_INFO, &bc_read, sizeof (bc_read)) == SF_FALSE) + { printf ("\n\nLine %d : sf_command (SFC_SET_BROADCAST_INFO) failed.\n\n", __LINE__) ; + exit (1) ; + } ; + + check_log_buffer_or_die (file, __LINE__) ; + sf_close (file) ; + + if (strstr (bc_read.coding_history, supplied_history) != bc_read.coding_history) + { printf ("\n\nLine %d : unexpected coding history :\n" + "----------------------------------------------------\n%s" + "----------------------------------------------------\n" + "should be this :\n" + "----------------------------------------------------\n%s" + "----------------------------------------------------\n" + "with one more line at the end.\n\n", + __LINE__, bc_read.coding_history, supplied_history) ; + exit (1) ; + } ; + + check_coding_history_newlines (filename) ; + + unlink (filename) ; + puts ("ok") ; +} /* broadcast_coding_history_test */ + +/*============================================================================== +*/ + +static void +broadcast_coding_history_size (const char *filename) +{ /* SF_BROADCAST_INFO struct with coding_history field of 1024 bytes. */ + static SF_BROADCAST_INFO_VAR (1024) bc_write ; + static SF_BROADCAST_INFO_VAR (1024) bc_read ; + SNDFILE *file ; + SF_INFO sfinfo ; + int k ; + + print_test_name (__func__, filename) ; + + sfinfo.samplerate = 22050 ; + sfinfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 ; + sfinfo.channels = 1 ; + + memset (&bc_write, 0, sizeof (bc_write)) ; + + snprintf (bc_write.description, sizeof (bc_write.description), "Test description") ; + snprintf (bc_write.originator, sizeof (bc_write.originator), "Test originator") ; + snprintf (bc_write.originator_reference, sizeof (bc_write.originator_reference), "%08x-%08x", (unsigned int) time (NULL), (unsigned int) (~ time (NULL))) ; + snprintf (bc_write.origination_date, sizeof (bc_write.origination_date), "%d/%02d/%02d", 2006, 3, 30) ; + snprintf (bc_write.origination_time, sizeof (bc_write.origination_time), "%02d:%02d:%02d", 20, 27, 0) ; + snprintf (bc_write.umid, sizeof (bc_write.umid), "Some umid") ; + bc_write.coding_history_size = 0 ; + + for (k = 0 ; bc_write.coding_history_size < 512 ; k++) + { snprintf (bc_write.coding_history + bc_write.coding_history_size, + sizeof (bc_write.coding_history) - bc_write.coding_history_size, "line %4d\n", k) ; + bc_write.coding_history_size = (uint32_t) strlen (bc_write.coding_history) ; + } ; + + exit_if_true (bc_write.coding_history_size < 512, + "\n\nLine %d : bc_write.coding_history_size (%d) should be > 512.\n\n", __LINE__, bc_write.coding_history_size) ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + if (sf_command (file, SFC_SET_BROADCAST_INFO, &bc_write, sizeof (bc_write)) == SF_FALSE) + { printf ("\n\nLine %d : sf_command (SFC_SET_BROADCAST_INFO) failed.\n\n", __LINE__) ; + exit (1) ; + } ; + + test_write_double_or_die (file, 0, double_data, BUFFER_LEN, __LINE__) ; + sf_close (file) ; + + memset (&bc_read, 0, sizeof (bc_read)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + if (sf_command (file, SFC_GET_BROADCAST_INFO, &bc_read, sizeof (bc_read)) == SF_FALSE) + { printf ("\n\nLine %d : sf_command (SFC_SET_BROADCAST_INFO) failed.\n\n", __LINE__) ; + exit (1) ; + } ; + check_log_buffer_or_die (file, __LINE__) ; + sf_close (file) ; + + exit_if_true (bc_read.coding_history_size < 512, + "\n\nLine %d : unexpected coding history size %d (should be > 512).\n\n", __LINE__, bc_read.coding_history_size) ; + + exit_if_true (strstr (bc_read.coding_history, "libsndfile") == NULL, + "\n\nLine %d : coding history incomplete (should contain 'libsndfile').\n\n", __LINE__) ; + + unlink (filename) ; + puts ("ok") ; +} /* broadcast_coding_history_size */ + +/*============================================================================== +*/ +static void +cart_test (const char *filename, int filetype) +{ static SF_CART_INFO ca_write, ca_read ; + SNDFILE *file ; + SF_INFO sfinfo ; + int errors = 0 ; + + print_test_name ("cart_test", filename) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + sfinfo.samplerate = 11025 ; + sfinfo.format = filetype ; + sfinfo.channels = 1 ; + memset (&ca_write, 0, sizeof (ca_write)) ; + + // example test data + snprintf (ca_write.artist, sizeof (ca_write.artist), "Test artist") ; + snprintf (ca_write.version, sizeof (ca_write.version), "Test version") ; + snprintf (ca_write.cut_id, sizeof (ca_write.cut_id), "Test cut ID") ; + snprintf (ca_write.client_id, sizeof (ca_write.client_id), "Test client ID") ; + snprintf (ca_write.category, sizeof (ca_write.category), "Test category") ; + snprintf (ca_write.classification, sizeof (ca_write.classification), "Test classification") ; + snprintf (ca_write.out_cue, sizeof (ca_write.out_cue), "Test out cue") ; + snprintf (ca_write.start_date, sizeof (ca_write.start_date), "%d/%02d/%02d", 2006, 3, 30) ; + snprintf (ca_write.start_time, sizeof (ca_write.start_time), "%02d:%02d:%02d", 20, 27, 0) ; + snprintf (ca_write.end_date, sizeof (ca_write.end_date), "%d/%02d/%02d", 2006, 3, 30) ; + snprintf (ca_write.end_time, sizeof (ca_write.end_time), "%02d:%02d:%02d", 20, 27, 0) ; + snprintf (ca_write.producer_app_id, sizeof (ca_write.producer_app_id), "Test producer app id") ; + snprintf (ca_write.producer_app_version, sizeof (ca_write.producer_app_version), "Test producer app version") ; + snprintf (ca_write.user_def, sizeof (ca_write.user_def), "test user def test test") ; + ca_write.level_reference = 42 ; + snprintf (ca_write.url, sizeof (ca_write.url), "http://www.test.com/test_url") ; + snprintf (ca_write.tag_text, sizeof (ca_write.tag_text), "tag text test! \r\n") ; // must be terminated \r\n to be valid + ca_write.tag_text_size = (uint32_t) strlen (ca_write.tag_text) ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + if (sf_command (file, SFC_SET_CART_INFO, &ca_write, sizeof (ca_write)) == SF_FALSE) + exit (1) ; + + test_write_double_or_die (file, 0, double_data, BUFFER_LEN, __LINE__) ; + sf_close (file) ; + + memset (&ca_read, 0, sizeof (ca_read)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + if (sf_command (file, SFC_GET_CART_INFO, &ca_read, sizeof (ca_read)) == SF_FALSE) + { printf ("\n\nLine %d : sf_command (SFC_GET_CART_INFO) failed.\n\n", __LINE__) ; + exit (1) ; + return ; + } ; + check_log_buffer_or_die (file, __LINE__) ; + sf_close (file) ; + + + if (memcmp (ca_write.artist, ca_read.artist, sizeof (ca_write.artist)) != 0) + { printf ("\n\nLine %d : artist mismatch :\n\twrite : '%s'\n\tread : '%s'\n\n", __LINE__, ca_write.artist, ca_read.artist) ; + errors ++ ; + } ; + + if (memcmp (ca_write.version, ca_read.version, sizeof (ca_write.version)) != 0) + { printf ("\n\nLine %d : version mismatch :\n\twrite : '%s'\n\tread : '%s'\n\n", __LINE__, ca_write.version, ca_read.version) ; + errors ++ ; + } ; + + if (memcmp (ca_write.title, ca_read.title, sizeof (ca_write.title)) != 0) + { printf ("\n\nLine %d : title mismatch :\n\twrite : '%s'\n\tread : '%s'\n\n", __LINE__, ca_write.title, ca_read.title) ; + errors ++ ; + } ; + + if (memcmp (ca_write.cut_id, ca_read.cut_id, sizeof (ca_write.cut_id)) != 0) + { printf ("\n\nLine %d : cut_id mismatch :\n\twrite : '%s'\n\tread : '%s'\n\n", __LINE__, ca_write.cut_id, ca_read.cut_id) ; + errors ++ ; + } ; + + if (memcmp (ca_write.client_id, ca_read.client_id, sizeof (ca_write.client_id)) != 0) + { printf ("\n\nLine %d : client_id mismatch :\n\twrite : '%s'\n\tread : '%s'\n\n", __LINE__, ca_write.client_id, ca_read.client_id) ; + errors ++ ; + } ; + + if (memcmp (ca_write.category, ca_read.category, sizeof (ca_write.category)) != 0) + { printf ("\n\nLine %d : category mismatch :\n\twrite : '%s'\n\tread : '%s'\n\n", __LINE__, ca_write.category, ca_read.category) ; + errors ++ ; + } ; + + if (memcmp (ca_write.out_cue, ca_read.out_cue, sizeof (ca_write.out_cue)) != 0) + { printf ("\n\nLine %d : out_cue mismatch :\n\twrite : '%s'\n\tread : '%s'\n\n", __LINE__, ca_write.out_cue, ca_read.out_cue) ; + errors ++ ; + } ; + + if (memcmp (ca_write.start_date, ca_read.start_date, sizeof (ca_write.start_date)) != 0) + { printf ("\n\nLine %d : start_date mismatch :\n\twrite : '%s'\n\tread : '%s'\n\n", __LINE__, ca_write.start_date, ca_read.start_date) ; + errors ++ ; + } ; + + + if (memcmp (ca_write.start_time, ca_read.start_time, sizeof (ca_write.start_time)) != 0) + { printf ("\n\nLine %d : start_time mismatch :\n\twrite : '%s'\n\tread : '%s'\n\n", __LINE__, ca_write.start_time, ca_read.start_time) ; + errors ++ ; + } ; + + + if (memcmp (ca_write.end_date, ca_read.end_date, sizeof (ca_write.end_date)) != 0) + { printf ("\n\nLine %d : end_date mismatch :\n\twrite : '%s'\n\tread : '%s'\n\n", __LINE__, ca_write.end_date, ca_read.end_date) ; + errors ++ ; + } ; + + + if (memcmp (ca_write.end_time, ca_read.end_time, sizeof (ca_write.end_time)) != 0) + { printf ("\n\nLine %d : end_time mismatch :\n\twrite : '%s'\n\tread : '%s'\n\n", __LINE__, ca_write.end_time, ca_read.end_time) ; + errors ++ ; + } ; + + + if (memcmp (ca_write.producer_app_id, ca_read.producer_app_id, sizeof (ca_write.producer_app_id)) != 0) + { printf ("\n\nLine %d : producer_app_id mismatch :\n\twrite : '%s'\n\tread : '%s'\n\n", __LINE__, ca_write.producer_app_id, ca_read.producer_app_id) ; + errors ++ ; + } ; + + + if (memcmp (ca_write.producer_app_version, ca_read.producer_app_version, sizeof (ca_write.producer_app_version)) != 0) + { printf ("\n\nLine %d : producer_app_version mismatch :\n\twrite : '%s'\n\tread : '%s'\n\n", __LINE__, ca_write.producer_app_version, ca_read.producer_app_version) ; + errors ++ ; + } ; + + + if (memcmp (ca_write.user_def, ca_read.user_def, sizeof (ca_write.user_def)) != 0) + { printf ("\n\nLine %d : user_def mismatch :\n\twrite : '%s'\n\tread : '%s'\n\n", __LINE__, ca_write.user_def, ca_read.user_def) ; + errors ++ ; + } ; + + + if (ca_write.level_reference != ca_read.level_reference) + { printf ("\n\nLine %d : level_reference mismatch :\n\twrite : '%d'\n\tread : '%d'\n\n", __LINE__, ca_write.level_reference, ca_read.level_reference) ; + errors ++ ; + } ; + + // TODO: make this more helpful + if (memcmp (ca_write.post_timers, ca_read.post_timers, sizeof (ca_write.post_timers)) != 0) + { printf ("\n\nLine %d : post_timers mismatch :\n'\n\n", __LINE__) ; + errors ++ ; + } ; + + if (memcmp (ca_write.url, ca_read.url, sizeof (ca_write.url)) != 0) + { printf ("\n\nLine %d : url mismatch :\n\twrite : '%s'\n\tread : '%s'\n\n", __LINE__, ca_write.url, ca_read.url) ; + errors ++ ; + } ; + + + if (memcmp (ca_write.tag_text, ca_read.tag_text, (size_t) (ca_read.tag_text_size)) != 0) + { printf ("\n\nLine %d : tag_text mismatch :\n\twrite : '%s'\n\tread : '%s'\n\n", __LINE__, ca_write.tag_text, ca_read.tag_text) ; + errors ++ ; + } ; + + + if (errors) + exit (1) ; + + unlink (filename) ; + puts ("ok") ; +} /* cart_test */ + +static void +cart_rdwr_test (const char *filename, int filetype) +{ SF_CART_INFO cinfo ; + SNDFILE *file ; + SF_INFO sfinfo ; + sf_count_t frames ; + + print_test_name (__func__, filename) ; + + create_short_sndfile (filename, filetype, 2) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + memset (&cinfo, 0, sizeof (cinfo)) ; + + snprintf (cinfo.artist, sizeof (cinfo.artist), "Test artist") ; + snprintf (cinfo.version, sizeof (cinfo.version), "Test version") ; + snprintf (cinfo.cut_id, sizeof (cinfo.cut_id), "Test cut ID") ; + snprintf (cinfo.client_id, sizeof (cinfo.client_id), "Test client ID") ; + snprintf (cinfo.category, sizeof (cinfo.category), "Test category") ; + snprintf (cinfo.classification, sizeof (cinfo.classification), "Test classification") ; + snprintf (cinfo.out_cue, sizeof (cinfo.out_cue), "Test out cue") ; + snprintf (cinfo.start_date, sizeof (cinfo.start_date), "%d/%02d/%02d", 2006, 3, 30) ; + snprintf (cinfo.start_time, sizeof (cinfo.start_time), "%02d:%02d:%02d", 20, 27, 0) ; + snprintf (cinfo.end_date, sizeof (cinfo.end_date), "%d/%02d/%02d", 2006, 3, 30) ; + snprintf (cinfo.end_time, sizeof (cinfo.end_time), "%02d:%02d:%02d", 20, 27, 0) ; + snprintf (cinfo.producer_app_id, sizeof (cinfo.producer_app_id), "Test producer app id") ; + snprintf (cinfo.producer_app_version, sizeof (cinfo.producer_app_version), "Test producer app version") ; + snprintf (cinfo.user_def, sizeof (cinfo.user_def), "test user def test test") ; + cinfo.level_reference = 42 ; + snprintf (cinfo.url, sizeof (cinfo.url), "http://www.test.com/test_url") ; + snprintf (cinfo.tag_text, sizeof (cinfo.tag_text), "tag text test!\r\n") ; + cinfo.tag_text_size = (uint32_t) strlen (cinfo.tag_text) ; + + file = test_open_file_or_die (filename, SFM_RDWR, &sfinfo, SF_TRUE, __LINE__) ; + frames = sfinfo.frames ; + if (sf_command (file, SFC_SET_CART_INFO, &cinfo, sizeof (cinfo)) != SF_FALSE) + { printf ("\n\nLine %d : sf_command (SFC_SET_CART_INFO) should have failed but didn't.\n\n", __LINE__) ; + exit (1) ; + } ; + sf_close (file) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + sf_close (file) ; + exit_if_true (frames != sfinfo.frames, "\n\nLine %d : Frame count %" PRId64 " should be %" PRId64 ".\n", __LINE__, sfinfo.frames, frames) ; + + unlink (filename) ; + puts ("ok") ; +} /* cart_rdwr_test */ + +/*============================================================================== +*/ + +static void +channel_map_test (const char *filename, int filetype) +{ SNDFILE *file ; + SF_INFO sfinfo ; + int channel_map_read [4], channel_map_write [4] = + { SF_CHANNEL_MAP_LEFT, SF_CHANNEL_MAP_RIGHT, SF_CHANNEL_MAP_LFE, + SF_CHANNEL_MAP_REAR_CENTER + } ; + + print_test_name ("channel_map_test", filename) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + sfinfo.samplerate = 11025 ; + sfinfo.format = filetype ; + sfinfo.channels = ARRAY_LEN (channel_map_read) ; + + switch (filetype & SF_FORMAT_TYPEMASK) + { /* WAVEX and RF64 have a default channel map, even if you don't specify one. */ + case SF_FORMAT_WAVEX : + case SF_FORMAT_RF64 : + /* Write file without channel map. */ + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + test_write_double_or_die (file, 0, double_data, BUFFER_LEN, __LINE__) ; + sf_close (file) ; + + /* Read file making default channel map exists. */ + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + exit_if_true ( + sf_command (file, SFC_GET_CHANNEL_MAP_INFO, channel_map_read, sizeof (channel_map_read)) == SF_FALSE, + "\n\nLine %d : sf_command (SFC_GET_CHANNEL_MAP_INFO) should not have failed.\n\n", __LINE__ + ) ; + check_log_buffer_or_die (file, __LINE__) ; + sf_close (file) ; + break ; + + default : + break ; + } ; + + /* Write file with a channel map. */ + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + exit_if_true ( + sf_command (file, SFC_SET_CHANNEL_MAP_INFO, channel_map_write, sizeof (channel_map_write)) == SF_FALSE, + "\n\nLine %d : sf_command (SFC_SET_CHANNEL_MAP_INFO) failed.\n\n", __LINE__ + ) ; + test_write_double_or_die (file, 0, double_data, BUFFER_LEN, __LINE__) ; + sf_close (file) ; + + /* Read file making sure no channel map exists. */ + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + exit_if_true ( + sf_command (file, SFC_GET_CHANNEL_MAP_INFO, channel_map_read, sizeof (channel_map_read)) != SF_TRUE, + "\n\nLine %d : sf_command (SFC_GET_CHANNEL_MAP_INFO) failed.\n\n", __LINE__ + ) ; + check_log_buffer_or_die (file, __LINE__) ; + sf_close (file) ; + + exit_if_true ( + memcmp (channel_map_read, channel_map_write, sizeof (channel_map_read)) != 0, + "\n\nLine %d : Channel map read does not match channel map written.\n\n", __LINE__ + ) ; + + unlink (filename) ; + puts ("ok") ; +} /* channel_map_test */ + +static void +raw_needs_endswap_test (const char *filename, int filetype) +{ static int subtypes [] = + { SF_FORMAT_FLOAT, SF_FORMAT_DOUBLE, + SF_FORMAT_PCM_16, SF_FORMAT_PCM_24, SF_FORMAT_PCM_32 + } ; + SNDFILE *file ; + SF_INFO sfinfo ; + unsigned k ; + int needs_endswap ; + + print_test_name (__func__, filename) ; + + for (k = 0 ; k < ARRAY_LEN (subtypes) ; k++) + { + if (filetype == (SF_ENDIAN_LITTLE | SF_FORMAT_AIFF)) + switch (subtypes [k]) + { /* Little endian AIFF does not AFAIK support fl32 and fl64. */ + case SF_FORMAT_FLOAT : + case SF_FORMAT_DOUBLE : + continue ; + default : + break ; + } ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + sfinfo.samplerate = 11025 ; + sfinfo.format = filetype | subtypes [k] ; + sfinfo.channels = 1 ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + test_write_double_or_die (file, 0, double_data, BUFFER_LEN, __LINE__) ; + sf_close (file) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + + needs_endswap = sf_command (file, SFC_RAW_DATA_NEEDS_ENDSWAP, NULL, 0) ; + + switch (filetype) + { case SF_FORMAT_WAV : + case SF_FORMAT_WAVEX : + case SF_FORMAT_AIFF | SF_ENDIAN_LITTLE : + exit_if_true (needs_endswap != CPU_IS_BIG_ENDIAN, + "\n\nLine %d : SFC_RAW_DATA_NEEDS_ENDSWAP failed for (%d | %d).\n\n", __LINE__, filetype, k) ; + break ; + + case SF_FORMAT_AIFF : + case SF_FORMAT_WAV | SF_ENDIAN_BIG : + exit_if_true (needs_endswap != CPU_IS_LITTLE_ENDIAN, + "\n\nLine %d : SFC_RAW_DATA_NEEDS_ENDSWAP failed for (%d | %d).\n\n", __LINE__, filetype, k) ; + break ; + + default : + printf ("\n\nLine %d : bad format value %d.\n\n", __LINE__, filetype) ; + exit (1) ; + break ; + } ; + + sf_close (file) ; + } ; + + unlink (filename) ; + puts ("ok") ; +} /* raw_needs_endswap_test */ diff --git a/extern/libsndfile-modified/tests/compression_size_test.c b/extern/libsndfile-modified/tests/compression_size_test.c new file mode 100644 index 000000000..b7dae300b --- /dev/null +++ b/extern/libsndfile-modified/tests/compression_size_test.c @@ -0,0 +1,234 @@ +/* +** Copyright (C) 2007-2016 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include + +#include + +#include "utils.h" +#include "dft_cmp.h" + +#define SAMPLE_RATE 16000 +#define DATA_LENGTH (SAMPLE_RATE) + +static const char CMP_TEST_PREFIX[] = "cmp" ; + +static float data_out [DATA_LENGTH] ; + +static inline float +max_float (float a, float b) +{ return a > b ? a : b ; +} /* max_float */ + +static void +vorbis_test (void) +{ static float float_data [DFT_DATA_LENGTH] ; + const char * filename = "vorbis_test.oga" ; + SNDFILE * file ; + SF_INFO sfinfo ; + float max_abs = 0.0 ; + unsigned k ; + + get_unique_test_name (&filename, CMP_TEST_PREFIX) ; + + print_test_name ("vorbis_test", filename) ; + + /* Generate float data. */ + gen_windowed_sine_float (float_data, ARRAY_LEN (float_data), 1.0) ; + + /* Set up output file type. */ + memset (&sfinfo, 0, sizeof (sfinfo)) ; + sfinfo.format = SF_FORMAT_OGG | SF_FORMAT_VORBIS ; + sfinfo.channels = 1 ; + sfinfo.samplerate = SAMPLE_RATE ; + + /* Write the output file. */ + + /* The Vorbis encoder has a bug on PowerPC and X86-64 with sample rates + ** <= 22050. Increasing the sample rate to 32000 avoids triggering it. + ** See https://trac.xiph.org/ticket/1229 + */ + if ((file = sf_open (filename, SFM_WRITE, &sfinfo)) == NULL) + { const char * errstr ; + + errstr = sf_strerror (NULL) ; + if (strstr (errstr, "Sample rate chosen is known to trigger a Vorbis") == NULL) + { printf ("Line %d: sf_open (SFM_WRITE) failed : %s\n", __LINE__, errstr) ; + dump_log_buffer (NULL) ; + exit (1) ; + } ; + + printf ("\n Sample rate -> 32kHz ") ; + sfinfo.samplerate = 32000 ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + } ; + + test_write_float_or_die (file, 0, float_data, ARRAY_LEN (float_data), __LINE__) ; + sf_close (file) ; + + memset (float_data, 0, sizeof (float_data)) ; + + /* Read the file back in again. */ + memset (&sfinfo, 0, sizeof (sfinfo)) ; + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + test_read_float_or_die (file, 0, float_data, ARRAY_LEN (float_data), __LINE__) ; + sf_close (file) ; + + for (k = 0 ; k < ARRAY_LEN (float_data) ; k ++) + max_abs = max_float (max_abs, fabsf (float_data [k])) ; + + exit_if_true (max_abs > 1.023, + "\n\nLine %d : max_abs %f should be < 1.023.\n\n", __LINE__, max_abs) ; + + puts ("ok") ; + unlink (filename) ; +} /* vorbis_test */ + +static void +compression_size_test (int format, const char * filename) +{ /* + ** Encode two files, one at quality 0.3 and one at quality 0.5 and then + ** make sure that the quality 0.3 files is the smaller of the two. + */ + char q3_fname [64] ; + char q6_fname [64] ; + char test_name [64] ; + + SNDFILE *q3_file, *q6_file ; + SF_INFO sfinfo ; + int q3_size, q6_size ; + double quality ; + int k ; + + get_unique_test_name (&filename, CMP_TEST_PREFIX) ; + + snprintf (q3_fname, sizeof (q3_fname), "q3_%s", filename) ; + snprintf (q6_fname, sizeof (q6_fname), "q6_%s", filename) ; + + snprintf (test_name, sizeof (test_name), "q[36]_%s", filename) ; + print_test_name (__func__, test_name) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + /* Set up output file type. */ + sfinfo.format = format ; + sfinfo.channels = 1 ; + sfinfo.samplerate = SAMPLE_RATE ; + + /* Write the output file. */ + q3_file = test_open_file_or_die (q3_fname, SFM_WRITE, &sfinfo, SF_FALSE, __LINE__) ; + q6_file = test_open_file_or_die (q6_fname, SFM_WRITE, &sfinfo, SF_FALSE, __LINE__) ; + + quality = 0.3 ; + sf_command (q3_file, SFC_SET_VBR_ENCODING_QUALITY, &quality, sizeof (quality)) ; + quality = 0.6 ; + sf_command (q6_file, SFC_SET_VBR_ENCODING_QUALITY, &quality, sizeof (quality)) ; + + for (k = 0 ; k < 5 ; k++) + { gen_lowpass_signal_float (data_out, ARRAY_LEN (data_out)) ; + test_write_float_or_die (q3_file, 0, data_out, ARRAY_LEN (data_out), __LINE__) ; + test_write_float_or_die (q6_file, 0, data_out, ARRAY_LEN (data_out), __LINE__) ; + } ; + + sf_close (q3_file) ; + sf_close (q6_file) ; + + q3_size = (int) file_length (q3_fname) ; + q6_size = (int) file_length (q6_fname) ; + + exit_if_true (q3_size >= q6_size, + "\n\nLine %d : q3 size (%d) >= q6 size (%d)\n\n", __LINE__, q3_size, q6_size) ; + + puts ("ok") ; + unlink (q3_fname) ; + unlink (q6_fname) ; +} /* compression_size_test */ + + + +int +main (int argc, char *argv []) +{ int all_tests = 0, tests = 0 ; + + if (argc != 2) + { printf ( + "Usage : %s \n" + " Where is one of:\n" + " vorbis - test Ogg/Vorbis\n" + " flac - test FLAC\n" + " opus - test Opus\n" + " mpeg - test mpeg\n" + " all - perform all tests\n", + argv [0]) ; + exit (0) ; + } ; + + if (strcmp (argv [1], "all") == 0) + all_tests = 1 ; + + if (all_tests || strcmp (argv [1], "vorbis") == 0) + { if (HAVE_EXTERNAL_XIPH_LIBS) + { vorbis_test () ; + compression_size_test (SF_FORMAT_OGG | SF_FORMAT_VORBIS, "vorbis.oga") ; + tests ++ ; + } + else + puts (" No Ogg Vorbis tests because support was not compiled in.") ; + } ; + + if (all_tests || strcmp (argv [1], "flac") == 0) + { if (HAVE_EXTERNAL_XIPH_LIBS) + { compression_size_test (SF_FORMAT_FLAC | SF_FORMAT_PCM_16, "pcm16.flac") ; + tests ++ ; + } + else + puts (" No FLAC tests because support was not compiled in.") ; + } ; + + if (all_tests || strcmp (argv [1], "opus") == 0) + { if (HAVE_EXTERNAL_XIPH_LIBS) + { compression_size_test (SF_FORMAT_OGG | SF_FORMAT_OPUS, "opus.opus") ; + tests ++ ; + } + else + puts (" No Opus tests because support was not compiled in.") ; + } ; + + if (all_tests || strcmp (argv [1], "mpeg") == 0) + { if (HAVE_MPEG) + { compression_size_test (SF_FORMAT_MPEG | SF_FORMAT_MPEG_LAYER_III, "mpeg.mp3") ; + tests ++ ; + } + else + puts (" No MPEG tests because support was not compiled in.") ; + } ; + + return 0 ; +} /* main */ diff --git a/extern/libsndfile-modified/tests/cpp_test.cc b/extern/libsndfile-modified/tests/cpp_test.cc new file mode 100644 index 000000000..e05a73709 --- /dev/null +++ b/extern/libsndfile-modified/tests/cpp_test.cc @@ -0,0 +1,315 @@ +/* +** Copyright (C) 2006-2012 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include + +#include + +#include "utils.h" + +static short sbuffer [100] ; +static int ibuffer [100] ; +static float fbuffer [100] ; +static double dbuffer [100] ; + +static void +ceeplusplus_wchar_test (void) +{ +#if 0 + LPCWSTR filename = L"wchar_test.wav" ; + + print_test_name (__func__, "ceeplusplus_wchar_test.wav") ; + + /* Use this scope to make sure the created file is closed. */ + { + SndfileHandle file (filename, SFM_WRITE, SF_FORMAT_WAV | SF_FORMAT_PCM_16, 2, 44100) ; + + if (file.refCount () != 1) + { printf ("\n\n%s %d : Error : Reference count (%d) should be 1.\n\n", __func__, __LINE__, file.refCount ()) ; + exit (1) ; + } ; + + /* This should check that the file did in fact get created with a + ** wchar_t * filename. + */ + exit_if_true ( + GetFileAttributesW (filename) == INVALID_FILE_ATTRIBUTES, + "\n\nLine %d : GetFileAttributes failed.\n\n", __LINE__ + ) ; + } + + /* Use this because the file was created with CreateFileW. */ + DeleteFileW (filename) ; + + puts ("ok") ; +#endif +} /* ceeplusplus_wchar_test */ + + + +static void +create_file (const char * filename, int format) +{ SndfileHandle file ; + + if (file.refCount () != 0) + { printf ("\n\n%s %d : Error : Reference count (%d) should be zero.\n\n", __func__, __LINE__, file.refCount ()) ; + exit (1) ; + } ; + + file = SndfileHandle (filename, SFM_WRITE, format, 2, 48000) ; + + if (file.refCount () != 1) + { printf ("\n\n%s %d : Error : Reference count (%d) should be 1.\n\n", __func__, __LINE__, file.refCount ()) ; + exit (1) ; + } ; + + file.setString (SF_STR_TITLE, filename) ; + + /* Item write. */ + file.write (sbuffer, ARRAY_LEN (sbuffer)) ; + file.write (ibuffer, ARRAY_LEN (ibuffer)) ; + file.write (fbuffer, ARRAY_LEN (fbuffer)) ; + file.write (dbuffer, ARRAY_LEN (dbuffer)) ; + + /* Frame write. */ + file.writef (sbuffer, ARRAY_LEN (sbuffer) / file.channels ()) ; + file.writef (ibuffer, ARRAY_LEN (ibuffer) / file.channels ()) ; + file.writef (fbuffer, ARRAY_LEN (fbuffer) / file.channels ()) ; + file.writef (dbuffer, ARRAY_LEN (dbuffer) / file.channels ()) ; + + /* RAII takes care of the SndfileHandle. */ +} /* create_file */ + +static void +check_title (const SndfileHandle & file, const char * filename) +{ const char *title = NULL ; + + title = file.getString (SF_STR_TITLE) ; + + if (title == NULL) + { printf ("\n\n%s %d : Error : No title for %s.\n\n", __func__, __LINE__, filename) ; + exit (1) ; + } ; + + if (strcmp (filename, title) != 0) + { printf ("\n\n%s %d : Error : title '%s' should be '%s'\n\n", __func__, __LINE__, title, filename) ; + exit (1) ; + } ; + + return ; +} /* check_title */ + +static void +read_file (const char * filename, int format) +{ SndfileHandle file ; + sf_count_t count ; + + if (file) + { printf ("\n\n%s %d : Error : should not be here.\n\n", __func__, __LINE__) ; + exit (1) ; + } ; + + file = SndfileHandle (filename) ; + + if (1) + { SndfileHandle file2 = file ; + + if (file.refCount () != 2 || file2.refCount () != 2) + { printf ("\n\n%s %d : Error : Reference count (%d) should be two.\n\n", __func__, __LINE__, file.refCount ()) ; + exit (1) ; + } ; + } ; + + if (file.refCount () != 1) + { printf ("\n\n%s %d : Error : Reference count (%d) should be one.\n\n", __func__, __LINE__, file.refCount ()) ; + exit (1) ; + } ; + + if (! file) + { printf ("\n\n%s %d : Error : should not be here.\n\n", __func__, __LINE__) ; + exit (1) ; + } ; + + if (file.format () != format) + { printf ("\n\n%s %d : Error : format 0x%08x should be 0x%08x.\n\n", __func__, __LINE__, file.format (), format) ; + exit (1) ; + } ; + + if (file.channels () != 2) + { printf ("\n\n%s %d : Error : channels %d should be 2.\n\n", __func__, __LINE__, file.channels ()) ; + exit (1) ; + } ; + + if (file.frames () != ARRAY_LEN (sbuffer) * 4) + { printf ("\n\n%s %d : Error : frames %ld should be %lu.\n\n", __func__, __LINE__, + (long) file.frames (), (long) ARRAY_LEN (sbuffer) * 4 / 2) ; + exit (1) ; + } ; + + switch (format & SF_FORMAT_TYPEMASK) + { case SF_FORMAT_AU : + break ; + + default : + check_title (file, filename) ; + break ; + } ; + + /* Item read. */ + file.read (sbuffer, ARRAY_LEN (sbuffer)) ; + file.read (ibuffer, ARRAY_LEN (ibuffer)) ; + file.read (fbuffer, ARRAY_LEN (fbuffer)) ; + file.read (dbuffer, ARRAY_LEN (dbuffer)) ; + + /* Frame read. */ + file.readf (sbuffer, ARRAY_LEN (sbuffer) / file.channels ()) ; + file.readf (ibuffer, ARRAY_LEN (ibuffer) / file.channels ()) ; + file.readf (fbuffer, ARRAY_LEN (fbuffer) / file.channels ()) ; + file.readf (dbuffer, ARRAY_LEN (dbuffer) / file.channels ()) ; + + count = file.seek (file.frames () - 10, SEEK_SET) ; + if (count != file.frames () - 10) + { printf ("\n\n%s %d : Error : offset (%ld) should be %ld\n\n", __func__, __LINE__, + (long) count, (long) (file.frames () - 10)) ; + exit (1) ; + } ; + + count = file.read (sbuffer, ARRAY_LEN (sbuffer)) ; + if (count != 10 * file.channels ()) + { printf ("\n\n%s %d : Error : count (%ld) should be %ld\n\n", __func__, __LINE__, + (long) count, (long) (10 * file.channels ())) ; + exit (1) ; + } ; + + /* RAII takes care of the SndfileHandle. */ +} /* read_file */ + +static void +ceeplusplus_test (const char *filename, int format) +{ + print_test_name ("ceeplusplus_test", filename) ; + + create_file (filename, format) ; + read_file (filename, format) ; + + remove (filename) ; + puts ("ok") ; +} /* ceeplusplus_test */ + +static void +ceeplusplus_extra_test (void) +{ SndfileHandle file ; + const char * filename = "bad_file_name.wav" ; + int error ; + + print_test_name ("ceeplusplus_extra_test", filename) ; + + file = SndfileHandle (filename) ; + + error = file.error () ; + if (error == 0) + { printf ("\n\n%s %d : error should not be zero.\n\n", __func__, __LINE__) ; + exit (1) ; + } ; + + if (file.strError () == NULL) + { printf ("\n\n%s %d : strError should not return NULL.\n\n", __func__, __LINE__) ; + exit (1) ; + } ; + + if (file.seek (0, SEEK_SET) != 0) + { printf ("\n\n%s %d : bad seek ().\n\n", __func__, __LINE__) ; + exit (1) ; + } ; + + puts ("ok") ; +} /* ceeplusplus_extra_test */ + + +static void +ceeplusplus_rawhandle_test (const char *filename) +{ + SNDFILE* handle ; + { + SndfileHandle file (filename) ; + handle = file.rawHandle () ; + sf_read_float (handle, fbuffer, ARRAY_LEN (fbuffer)) ; + } +} /* ceeplusplus_rawhandle_test */ + +static void +ceeplusplus_takeOwnership_test (const char *filename) +{ + SNDFILE* handle ; + { + SndfileHandle file (filename) ; + handle = file.takeOwnership () ; + } + + if (sf_read_float (handle, fbuffer, ARRAY_LEN (fbuffer)) <= 0) + { printf ("\n\n%s %d : error when taking ownership of handle.\n\n", __func__, __LINE__) ; + exit (1) ; + } + + if (sf_close (handle) != 0) + { printf ("\n\n%s %d : cannot close file.\n\n", __func__, __LINE__) ; + exit (1) ; + } + + SndfileHandle file (filename) ; + SndfileHandle file2 (file) ; + + if (file2.takeOwnership ()) + { printf ("\n\n%s %d : taking ownership of shared handle is not allowed.\n\n", __func__, __LINE__) ; + exit (1) ; + } +} /* ceeplusplus_takeOwnership_test */ + +static void +ceeplusplus_handle_test (const char *filename, int format) +{ + print_test_name ("ceeplusplus_handle_test", filename) ; + + create_file (filename, format) ; + + if (0) ceeplusplus_rawhandle_test (filename) ; + ceeplusplus_takeOwnership_test (filename) ; + + remove (filename) ; + puts ("ok") ; +} /* ceeplusplus_test */ + +int +main (void) +{ + ceeplusplus_test ("cpp_test.wav", SF_FORMAT_WAV | SF_FORMAT_PCM_16) ; + ceeplusplus_test ("cpp_test.aiff", SF_FORMAT_AIFF | SF_FORMAT_PCM_S8) ; + ceeplusplus_test ("cpp_test.au", SF_FORMAT_AU | SF_FORMAT_FLOAT) ; + + ceeplusplus_extra_test () ; + ceeplusplus_handle_test ("cpp_test.wav", SF_FORMAT_WAV | SF_FORMAT_PCM_16) ; + + ceeplusplus_wchar_test () ; + + return 0 ; +} /* main */ + diff --git a/extern/libsndfile-modified/tests/cue_test.c b/extern/libsndfile-modified/tests/cue_test.c new file mode 100644 index 000000000..d2fdae4bb --- /dev/null +++ b/extern/libsndfile-modified/tests/cue_test.c @@ -0,0 +1,135 @@ + +#include "sfconfig.h" + +#include +#include +#include +#include + + +static void * +get_cues (const char *filename, double *sr) +{ + SNDFILE *file; + SF_INFO sfinfo; + + unsigned int err, size; + uint32_t count = 0; + SF_CUES_VAR(0) *info; + + if ((file = sf_open(filename, SFM_READ, &sfinfo)) == NULL) + { + printf("can't open file '%s'\n", filename); + exit(1); + } + + printf("\n---- get cues of file '%s'\n", filename); + + if ((err = sf_command(file, SFC_GET_CUE_COUNT, &count, sizeof(uint32_t))) == SF_FALSE) + { + if (sf_error(file)) + { + printf("can't get cue info size for file '%s' (arg size %lu), err %s\n", + filename, sizeof(uint32_t), sf_strerror(file)); + exit(2); + } + else + printf("no cue info for file '%s'\n", filename); + return NULL; + } + + size = sizeof(*info) + count * sizeof(SF_CUE_POINT); + printf("number of cues %d size %d\n", count, size); + + if (!(info = malloc(size))) + return NULL; + + if (sf_command(file, SFC_GET_CUE, info, size) == SF_FALSE) + { + printf("can't get cue info of size %d for file '%s' error %s\n", + size, filename, sf_strerror(file)); + exit(3); + } + + *sr = sfinfo.samplerate; + sf_close(file); + + return info; +} + + +static void +test_cues (const char *filename) +{ + unsigned int i; + double sr; + SF_CUES_VAR(0) *info = get_cues(filename, &sr); + + if (info == NULL) + exit(1); + + for (i = 0; i < info->cue_count; i++) + { + int pos = info->cue_points[i].position; + double t = (double) pos / sr; + double expected = i < 8 ? (double) i / 3. : 10. / 3.; + double error = (double) fabs(t - expected); + + printf("cue %02d: markerID %02d position %6d offset %6d (time %.3f expected %.3f diff %f) label '%s'\n", + i, info->cue_points[i].indx, pos, info->cue_points[i].sample_offset, t, expected, error, info->cue_points[i].name); + + if (error > 0.025) + exit(4); + } + + free(info); +} + +static void +print_cues (const char *filename) +{ + unsigned int i; + double sr; + SF_CUES_VAR(0) *info = get_cues(filename, &sr); + + if (info == NULL) + exit(1); + + for (i = 0; i < info->cue_count; i++) + { + int pos = info->cue_points[i].position; + int indx = info->cue_points[i].indx; + int cstart = info->cue_points[i].chunk_start; + int bstart = info->cue_points[i].block_start; + int offset = info->cue_points[i].sample_offset; + const char *name = info->cue_points[i].name; + double t = (double) pos / sr; + + if (cstart != 0 || bstart != 0) + printf("cue %02d time %7.3f: markerID %02d position %8d chunk_start %d block_start %d offset %8d label '%s'\n", + i, t, indx, pos, offset, cstart, bstart, name); + else + printf("cue %02d time %7.3f: markerID %02d position %8d offset %8d label '%s'\n", + i, t, indx, pos, offset, name); + } + + free(info); +} + + +int +main (int argc, char **argv) +{ + int i; + + if (argc > 1) + for (i = 1; i < argc; i++) + print_cues(argv[i]); + else + { + test_cues("clickpluck24.wav"); + test_cues("clickpluck.wav"); + test_cues("clickpluck.aiff"); + } + return 0; +} diff --git a/extern/libsndfile-modified/tests/dft_cmp.c b/extern/libsndfile-modified/tests/dft_cmp.c new file mode 100644 index 000000000..03bd4646d --- /dev/null +++ b/extern/libsndfile-modified/tests/dft_cmp.c @@ -0,0 +1,151 @@ +/* +** Copyright (C) 2002-2015 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include + +#include "dft_cmp.h" +#include "utils.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846264338 +#endif + +#define DFT_SPEC_LENGTH (DFT_DATA_LENGTH / 2) + +static void dft_magnitude (const double *data, double *spectrum) ; +static double calc_max_spectral_difference (const double *spec1, const double *spec2) ; + +/*-------------------------------------------------------------------------------- +** Public functions. +*/ + +double +dft_cmp_float (int linenum, const float *in_data, const float *test_data, int len, double target_snr, int allow_exit) +{ static double orig [DFT_DATA_LENGTH] ; + static double test [DFT_DATA_LENGTH] ; + unsigned k ; + + if (len != DFT_DATA_LENGTH) + { printf ("Error (line %d) : dft_cmp_float : Bad input array length.\n", linenum) ; + return 1 ; + } ; + + for (k = 0 ; k < ARRAY_LEN (orig) ; k++) + { test [k] = test_data [k] ; + orig [k] = in_data [k] ; + } ; + + return dft_cmp_double (linenum, orig, test, len, target_snr, allow_exit) ; +} /* dft_cmp_float */ + +double +dft_cmp_double (int linenum, const double *orig, const double *test, int len, double target_snr, int allow_exit) +{ static double orig_spec [DFT_SPEC_LENGTH] ; + static double test_spec [DFT_SPEC_LENGTH] ; + double snr ; + + if (! orig || ! test) + { printf ("Error (line %d) : dft_cmp_double : Bad input arrays.\n", linenum) ; + return 1 ; + } ; + + if (len != DFT_DATA_LENGTH) + { printf ("Error (line %d) : dft_cmp_double : Bad input array length.\n", linenum) ; + return 1 ; + } ; + + dft_magnitude (orig, orig_spec) ; + dft_magnitude (test, test_spec) ; + + snr = calc_max_spectral_difference (orig_spec, test_spec) ; + + if (snr > target_snr) + { printf ("\n\nLine %d: Actual SNR (% 4.1f) > target SNR (% 4.1f).\n\n", linenum, snr, target_snr) ; + oct_save_double (orig, test, len) ; + if (allow_exit) + exit (1) ; + } ; + + if (snr < -500.0) + snr = -500.0 ; + + return snr ; +} /* dft_cmp_double */ + +/*-------------------------------------------------------------------------------- +** Quick dirty calculation of magnitude spectrum for real valued data using +** Discrete Fourier Transform. Since the data is real, the DFT is only +** calculated for positive frequencies. +*/ + +static void +dft_magnitude (const double *data, double *spectrum) +{ static double cos_angle [DFT_DATA_LENGTH] = { 0.0 } ; + static double sin_angle [DFT_DATA_LENGTH] ; + + double real_part, imag_part ; + int k, n ; + + /* If sine and cosine tables haven't been initialised, do so. */ + if (cos_angle [0] == 0.0) + for (n = 0 ; n < DFT_DATA_LENGTH ; n++) + { cos_angle [n] = cos (2.0 * M_PI * n / DFT_DATA_LENGTH) ; + sin_angle [n] = -1.0 * sin (2.0 * M_PI * n / DFT_DATA_LENGTH) ; + } ; + + /* DFT proper. Since the data is real, only generate a half spectrum. */ + for (k = 1 ; k < DFT_SPEC_LENGTH ; k++) + { real_part = 0.0 ; + imag_part = 0.0 ; + + for (n = 0 ; n < DFT_DATA_LENGTH ; n++) + { real_part += data [n] * cos_angle [(k * n) % DFT_DATA_LENGTH] ; + imag_part += data [n] * sin_angle [(k * n) % DFT_DATA_LENGTH] ; + } ; + + spectrum [k] = sqrt (real_part * real_part + imag_part * imag_part) ; + } ; + + spectrum [DFT_SPEC_LENGTH - 1] = 0.0 ; + + spectrum [0] = spectrum [1] = spectrum [2] = 0.0 ; + + return ; +} /* dft_magnitude */ + +static double +calc_max_spectral_difference (const double *orig, const double *test) +{ double orig_max = 0.0, max_diff = 0.0 ; + int k ; + + for (k = 0 ; k < DFT_SPEC_LENGTH ; k++) + { if (orig_max < orig [k]) + orig_max = orig [k] ; + if (max_diff < fabs (orig [k] - test [k])) + max_diff = fabs (orig [k] - test [k]) ; + } ; + + if (max_diff < 1e-25) + return -500.0 ; + + return 20.0 * log10 (max_diff / orig_max) ; +} /* calc_max_spectral_difference */ diff --git a/extern/libsndfile-modified/tests/dft_cmp.h b/extern/libsndfile-modified/tests/dft_cmp.h new file mode 100644 index 000000000..faa5fe0a6 --- /dev/null +++ b/extern/libsndfile-modified/tests/dft_cmp.h @@ -0,0 +1,25 @@ +/* +** Copyright (C) 2002-2015 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + + +#define DFT_DATA_LENGTH (8192) + +double dft_cmp_float (int linenum, const float *orig, const float *test, int len, double tolerance, int allow_exit) ; + +double dft_cmp_double (int linenum, const double *orig, const double *test, int len, double tolerance, int allow_exit) ; + diff --git a/extern/libsndfile-modified/tests/dither_test.c b/extern/libsndfile-modified/tests/dither_test.c new file mode 100644 index 000000000..c0928440c --- /dev/null +++ b/extern/libsndfile-modified/tests/dither_test.c @@ -0,0 +1,184 @@ +/* +** Copyright (C) 2003-2013 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + + +#include "sfconfig.h" +#include +#include +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif +#include +#include + +#include + +#include "utils.h" + +#define BUFFER_LEN (1 << 16) +#define LOG_BUFFER_SIZE 1024 + +static void dither_test (const char *filename, int filetype) ; + +/* Force the start of this buffer to be double aligned. Sparc-solaris will +** choke if its not. +*/ +static short data_out [BUFFER_LEN] ; + +int +main (int argc, char *argv []) +{ int do_all = 0 ; + int test_count = 0 ; + + if (argc != 2) + { printf ("Usage : %s \n", argv [0]) ; + printf (" Where is one of the following:\n") ; + printf (" wav - test WAV file peak chunk\n") ; + printf (" aiff - test AIFF file PEAK chunk\n") ; + printf (" all - perform all tests\n") ; + exit (1) ; + } ; + + do_all = ! strcmp (argv [1], "all") ; + + if (do_all || ! strcmp (argv [1], "wav")) + { dither_test ("dither.wav", SF_FORMAT_WAV | SF_FORMAT_PCM_U8) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "aiff")) + { dither_test ("dither.aiff", SF_FORMAT_AIFF | SF_FORMAT_PCM_S8) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "au")) + { dither_test ("dither.au", SF_FORMAT_AU | SF_FORMAT_PCM_S8) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "svx")) + { dither_test ("dither.svx", SF_FORMAT_SVX | SF_FORMAT_PCM_S8) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "nist")) + { dither_test ("dither.nist", SF_FORMAT_NIST | SF_FORMAT_PCM_S8) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "paf")) + { dither_test ("dither.paf", SF_FORMAT_PAF | SF_FORMAT_PCM_S8) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "ircam")) + { dither_test ("dither.ircam", SF_FORMAT_IRCAM | SF_FORMAT_PCM_S8) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "voc")) + { dither_test ("dither.voc", SF_FORMAT_VOC | SF_FORMAT_PCM_S8) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "w64")) + { dither_test ("dither.w64", SF_FORMAT_W64 | SF_FORMAT_PCM_S8) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "mat4")) + { dither_test ("dither.mat4", SF_FORMAT_MAT4 | SF_FORMAT_PCM_S8) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "mat5")) + { dither_test ("dither.mat5", SF_FORMAT_MAT5 | SF_FORMAT_PCM_S8) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "pvf")) + { dither_test ("dither.pvf", SF_FORMAT_PVF | SF_FORMAT_PCM_S8) ; + test_count++ ; + } ; + + if (test_count == 0) + { printf ("Mono : ************************************\n") ; + printf ("Mono : * No '%s' test defined.\n", argv [1]) ; + printf ("Mono : ************************************\n") ; + return 1 ; + } ; + + return 0 ; +} /* main */ + + +/*============================================================================================ +** Here are the test functions. +*/ + +static void +dither_test (const char *filename, int filetype) +{ SNDFILE *file ; + SF_INFO sfinfo ; + SF_DITHER_INFO dither ; + + print_test_name ("dither_test", filename) ; + + sfinfo.samplerate = 44100 ; + sfinfo.format = filetype ; + sfinfo.channels = 1 ; + sfinfo.frames = 0 ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + + /* Check for old version of the dither API. */ + if (sf_command (file, SFC_SET_DITHER_ON_WRITE, NULL, SF_TRUE) == 0) + { printf ("\n\nLine %d: Should have an error here but don't.\n\n", __LINE__) ; + exit (1) ; + } ; + + memset (&dither, 0, sizeof (dither)) ; + dither.type = SFD_WHITE ; + dither.level = 0 ; + + if (sf_command (file, SFC_SET_DITHER_ON_WRITE, &dither, sizeof (dither)) != 0) + { printf ("\n\nLine %d: sf_command (SFC_SET_DITHER_ON_WRITE) returned error : %s\n\n", + __LINE__, sf_strerror (file)) ; + exit (1) ; + } ; + + /* Write data to file. */ + test_write_short_or_die (file, 0, data_out, BUFFER_LEN, __LINE__) ; + test_seek_or_die (file, 0, SEEK_SET, 0, sfinfo.channels, __LINE__) ; + + sf_close (file) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + + if (sfinfo.frames != BUFFER_LEN) + { printf ("\n\nLine %d: Bad frame count %d (should be %d)\n\n", __LINE__, (int) sfinfo.frames, BUFFER_LEN) ; + } ; + + sf_close (file) ; + /*-unlink (filename) ;-*/ + + puts ("ok") ; +} /* dither_test */ + diff --git a/extern/libsndfile-modified/tests/dwvw_test.c b/extern/libsndfile-modified/tests/dwvw_test.c new file mode 100644 index 000000000..0c92f874d --- /dev/null +++ b/extern/libsndfile-modified/tests/dwvw_test.c @@ -0,0 +1,111 @@ +/* +** Copyright (C) 2002-2014 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include + +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include + +#include "utils.h" + +#define BUFFER_SIZE (10000) + +#ifndef M_PI +#define M_PI 3.14159265358979323846264338 +#endif + +static void dwvw_test (const char *filename, int format, int bit_width) ; + +int +main (void) +{ + dwvw_test ("dwvw12.raw", SF_FORMAT_RAW | SF_FORMAT_DWVW_12, 12) ; + dwvw_test ("dwvw16.raw", SF_FORMAT_RAW | SF_FORMAT_DWVW_16, 16) ; + dwvw_test ("dwvw24.raw", SF_FORMAT_RAW | SF_FORMAT_DWVW_24, 24) ; + + return 0 ; +} /* main */ + +static void +dwvw_test (const char *filename, int format, int bit_width) +{ static int write_buf [BUFFER_SIZE] ; + static int read_buf [BUFFER_SIZE] ; + + SNDFILE *file ; + SF_INFO sfinfo ; + double value ; + int k, bit_mask ; + + srand (123456) ; + + /* Only want to grab the top bit_width bits. */ + bit_mask = arith_shift_left (-1, 32 - bit_width) ; + + print_test_name ("dwvw_test", filename) ; + + sf_info_setup (&sfinfo, format, 44100, 1) ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + + /* Generate random.frames. */ + for (k = 0 ; k < BUFFER_SIZE / 2 ; k++) + { value = 0x7FFFFFFF * sin (123.0 / sfinfo.samplerate * 2 * k * M_PI) ; + write_buf [k] = bit_mask & lrint (value) ; + } ; + + for ( ; k < BUFFER_SIZE ; k++) + write_buf [k] = bit_mask & (arith_shift_left (rand (), 11) ^ (rand () >> 11)) ; + + sf_write_int (file, write_buf, BUFFER_SIZE) ; + sf_close (file) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + + if ((k = (int) sf_read_int (file, read_buf, BUFFER_SIZE)) != BUFFER_SIZE) + { printf ("Error (line %d) : Only read %d/%d.frames.\n", __LINE__, k, BUFFER_SIZE) ; + exit (1) ; + } + + for (k = 0 ; k < BUFFER_SIZE ; k++) + { if (read_buf [k] != write_buf [k]) + { printf ("Error (line %d) : %d != %d at position %d/%d\n", __LINE__, + write_buf [k] >> (32 - bit_width), read_buf [k] >> (32 - bit_width), + k, BUFFER_SIZE) ; + oct_save_int (write_buf, read_buf, BUFFER_SIZE) ; + exit (1) ; + } ; + } ; + + sf_close (file) ; + + unlink (filename) ; + printf ("ok\n") ; + + return ; +} /* dwvw_test */ + diff --git a/extern/libsndfile-modified/tests/error_test.c b/extern/libsndfile-modified/tests/error_test.c new file mode 100644 index 000000000..9cdabf4ea --- /dev/null +++ b/extern/libsndfile-modified/tests/error_test.c @@ -0,0 +1,314 @@ +/* +** Copyright (C) 1999-2018 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include + +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include + +#include "utils.h" + +#define BUFFER_SIZE (1 << 15) +#define SHORT_BUFFER (256) + +static void +error_number_test (void) +{ const char *noerror, *errstr ; + int k ; + + print_test_name ("error_number_test", "") ; + + noerror = sf_error_number (0) ; + + for (k = 1 ; k < 300 ; k++) + { errstr = sf_error_number (k) ; + + /* Test for termination condition. */ + if (errstr == noerror) + break ; + + /* Test for error. */ + if (strstr (errstr, "This is a bug in libsndfile.")) + { printf ("\n\nError : error number %d : %s\n\n\n", k, errstr) ; + exit (1) ; + } ; + } ; + + + puts ("ok") ; + return ; +} /* error_number_test */ + +static void +error_value_test (void) +{ static unsigned char aiff_data [0x1b0] = + { 'F' , 'O' , 'R' , 'M' , + 0x00, 0x00, 0x01, 0xA8, /* FORM length */ + + 'A' , 'I' , 'F' , 'C' , + } ; + + const char *filename = "error.aiff" ; + SNDFILE *file ; + SF_INFO sfinfo ; + int error_num ; + + print_test_name ("error_value_test", filename) ; + + dump_data_to_file (filename, aiff_data, sizeof (aiff_data)) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + file = sf_open (filename, SFM_READ, &sfinfo) ; + if (file != NULL) + { printf ("\n\nLine %d : Should not have been able to open this file.\n\n", __LINE__) ; + exit (1) ; + } ; + + if ((error_num = sf_error (NULL)) <= 1 || error_num > 300) + { printf ("\n\nLine %d : Should not have had an error number of %d.\n\n", __LINE__, error_num) ; + exit (1) ; + } ; + + remove (filename) ; + puts ("ok") ; + return ; +} /* error_value_test */ + +static void +no_file_test (const char * filename) +{ SNDFILE *sndfile ; + SF_INFO sfinfo ; + + print_test_name (__func__, filename) ; + + unlink (filename) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + sndfile = sf_open (filename, SFM_READ, &sfinfo) ; + + exit_if_true (sndfile != NULL, "\n\nLine %d : should not have received a valid SNDFILE* pointer.\n", __LINE__) ; + + unlink (filename) ; + puts ("ok") ; +} /* no_file_test */ + +static void +zero_length_test (const char *filename) +{ SNDFILE *sndfile ; + SF_INFO sfinfo ; + FILE *file ; + + print_test_name (__func__, filename) ; + + /* Create a zero length file. */ + file = fopen (filename, "w") ; + exit_if_true (file == NULL, "\n\nLine %d : fopen ('%s') failed.\n", __LINE__, filename) ; + fclose (file) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + sndfile = sf_open (filename, SFM_READ, &sfinfo) ; + + exit_if_true (sndfile != NULL, "\n\nLine %d : should not have received a valid SNDFILE* pointer.\n", __LINE__) ; + + exit_if_true (0 && sf_error (NULL) != SF_ERR_UNRECOGNISED_FORMAT, + "\n\nLine %3d : Error : %s\n should be : %s\n", __LINE__, + sf_strerror (NULL), sf_error_number (SF_ERR_UNRECOGNISED_FORMAT)) ; + + unlink (filename) ; + puts ("ok") ; +} /* zero_length_test */ + +static void +bad_wav_test (const char * filename) +{ SNDFILE *sndfile ; + SF_INFO sfinfo ; + + FILE *file ; + const char data [] = "RIFF WAVEfmt " ; + + print_test_name (__func__, filename) ; + + if ((file = fopen (filename, "w")) == NULL) + { printf ("\n\nLine %d : fopen returned NULL.\n", __LINE__) ; + exit (1) ; + } ; + + exit_if_true (fwrite (data, sizeof (data), 1, file) != 1, "\n\nLine %d : fwrite failed.\n", __LINE__) ; + fclose (file) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + sndfile = sf_open (filename, SFM_READ, &sfinfo) ; + + if (sndfile) + { printf ("\n\nLine %d : should not have received a valid SNDFILE* pointer.\n", __LINE__) ; + exit (1) ; + } ; + + unlink (filename) ; + puts ("ok") ; +} /* bad_wav_test */ + +static void +wav_list_recover_test (const char * filename) +{ SNDFILE *sndfile ; + SF_INFO sfinfo ; + + FILE *file ; + const char data [] = + "RIFF" "J\000\000\000" + "WAVE" "fmt " "\020\000\000\000" "\001\000\001\000D\254\000\000\210X\001\000\002\000\020\000" + "LIST" "\014\000\000\000" "test" "\010\000\000\000" "1234" /* test is 4 bytes short inside LIST container */ + "data" "\004\000\000\000" "abcd" ; + + print_test_name (__func__, filename) ; + + if ((file = fopen (filename, "w")) == NULL) + { printf ("\n\nLine %d : fopen returned NULL.\n", __LINE__) ; + exit (1) ; + } ; + + exit_if_true (fwrite (data, sizeof (data) - 1, 1, file) != 1, "\n\nLine %d : fwrite failed.\n", __LINE__) ; + fclose (file) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + sndfile = sf_open (filename, SFM_READ, &sfinfo) ; + + if (!sndfile) + { printf ("\n\nLine %d : expected recovery from bogus LIST content.\n", __LINE__) ; + exit (1) ; + } ; + + if (sfinfo.frames != 2) + { printf ("\n\nLine %d : Should have read data chunk with 2 stereo frames, got %ld.\n\n", __LINE__, (long)sfinfo.frames) ; + exit (1) ; + } ; + + unlink (filename) ; + puts ("ok") ; +} /* wav_list_recover_test */ + +static void +error_close_test (void) +{ static short buffer [SHORT_BUFFER] ; + const char *filename = "error_close.wav" ; + SNDFILE *sndfile ; + SF_INFO sfinfo ; + FILE *file ; + + print_test_name (__func__, filename) ; + + /* Open a FILE* from which we will extract a file descriptor. */ + if ((file = fopen (filename, "w")) == NULL) + { printf ("\n\nLine %d : fopen returned NULL.\n", __LINE__) ; + exit (1) ; + } ; + + /* Set parameters for writing the file. */ + memset (&sfinfo, 0, sizeof (sfinfo)) ; + sfinfo.channels = 1 ; + sfinfo.samplerate = 44100 ; + sfinfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 ; + + sndfile = sf_open_fd (fileno (file), SFM_WRITE, &sfinfo, SF_TRUE) ; + if (sndfile == NULL) + { printf ("\n\nLine %d : sf_open_fd failed : %s\n", __LINE__, sf_strerror (NULL)) ; + exit (1) ; + } ; + + test_write_short_or_die (sndfile, 0, buffer, ARRAY_LEN (buffer), __LINE__) ; + + /* Now close the fd associated with file before calling sf_close. */ + fclose (file) ; + + if (sf_close (sndfile) == 0) + { + printf ("\n\nLine %d : sf_close should not have returned zero.\n", __LINE__) ; +#if OS_IS_WIN32 + printf ("\nHowever, this is a known bug on windows platform so we'll ignore it.\n\n") ; +#else + exit (1) ; +#endif + } ; + + unlink (filename) ; + puts ("ok") ; +} /* error_close_test */ + +static void +unrecognised_test (void) +{ const char *filename = "unrecognised.bin" ; + SNDFILE *sndfile ; + SF_INFO sfinfo ; + FILE *file ; + int k ; + + print_test_name (__func__, filename) ; + + file = fopen (filename, "wb") ; + exit_if_true (file == NULL, + "\n\nLine %d : fopen ('%s') failed : %s\n", __LINE__, filename, strerror (errno) + ) ; + fputs ("Unrecognised file", file) ; + fclose (file) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + sndfile = sf_open (filename, SFM_READ, &sfinfo) ; + + exit_if_true (sndfile != NULL, + "\n\nLine %d : SNDFILE* pointer (%p) should be NULL.\n", __LINE__, (void *) sndfile + ) ; + + k = sf_error (sndfile) ; + exit_if_true (k != SF_ERR_UNRECOGNISED_FORMAT, + "\n\nLine %d : error (%d) should have been SF_ERR_UNRECOGNISED_FORMAT (%d).\n", + __LINE__, k, SF_ERR_UNRECOGNISED_FORMAT + ) ; + + unlink (filename) ; + puts ("ok") ; +} /* unrecognised_test */ + +int +main (void) +{ + error_number_test () ; + error_value_test () ; + + error_close_test () ; + + no_file_test ("no_file.wav") ; + zero_length_test ("zero_length.wav") ; + bad_wav_test ("bad_wav.wav") ; + wav_list_recover_test ("list_recover.wav") ; + + unrecognised_test () ; + + return 0 ; +} /* main */ + diff --git a/extern/libsndfile-modified/tests/external_libs_test.c b/extern/libsndfile-modified/tests/external_libs_test.c new file mode 100644 index 000000000..0c6fcf8e4 --- /dev/null +++ b/extern/libsndfile-modified/tests/external_libs_test.c @@ -0,0 +1,204 @@ +/* +** Copyright (C) 2008-2017 Erik de Castro Lopo +** +** This program is free software ; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation ; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY ; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program ; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include + +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include + +#include "utils.h" + +static void major_format_test (void) ; +static void subtype_format_test (void) ; +static void simple_format_test (void) ; +static void flac_subset_test (void) ; + +int +main (void) +{ + major_format_test () ; + subtype_format_test () ; + simple_format_test () ; + + if (HAVE_EXTERNAL_XIPH_LIBS) + flac_subset_test () ; + + return 0 ; +} /* main */ + +static void +major_format_test (void) +{ SF_FORMAT_INFO info ; + int have_ogg = 0, have_flac = 0 ; + int m, major_count ; + + print_test_name (__func__, NULL) ; + + sf_command (NULL, SFC_GET_FORMAT_MAJOR_COUNT, &major_count, sizeof (int)) ; + + for (m = 0 ; m < major_count ; m++) + { info.format = m ; + sf_command (NULL, SFC_GET_FORMAT_MAJOR, &info, sizeof (info)) ; + + have_flac = info.format == SF_FORMAT_FLAC ? 1 : have_flac ; + have_ogg = info.format == SF_FORMAT_OGG ? 1 : have_ogg ; + } ; + + if (HAVE_EXTERNAL_XIPH_LIBS) + { exit_if_true (have_flac == 0, "\n\nLine %d : FLAC should be available.\n\n", __LINE__) ; + exit_if_true (have_ogg == 0, "\n\nLine %d : Ogg/Vorbis should be available.\n\n", __LINE__) ; + } + else + { exit_if_true (have_flac, "\n\nLine %d : FLAC should not be available.\n\n", __LINE__) ; + exit_if_true (have_ogg, "\n\nLine %d : Ogg/Vorbis should not be available.\n\n", __LINE__) ; + } ; + + puts ("ok") ; +} /* major_format_test */ + +static void +subtype_format_test (void) +{ SF_FORMAT_INFO info ; + int have_vorbis = 0 , have_opus = 0 ; + int s, subtype_count ; + + print_test_name (__func__, NULL) ; + + sf_command (NULL, SFC_GET_FORMAT_SUBTYPE_COUNT, &subtype_count, sizeof (int)) ; + + for (s = 0 ; s < subtype_count ; s++) + { info.format = s ; + sf_command (NULL, SFC_GET_FORMAT_SUBTYPE, &info, sizeof (info)) ; + + have_vorbis = info.format == SF_FORMAT_VORBIS ? 1 : have_vorbis ; + have_opus = info.format == SF_FORMAT_OPUS ? 1 : have_opus ; + } ; + + if (HAVE_EXTERNAL_XIPH_LIBS) + { exit_if_true (have_vorbis == 0, "\n\nLine %d : Ogg/Vorbis should be available.\n\n", __LINE__) ; + exit_if_true (have_opus == 0, "\n\nLine %d : Ogg/Opus should be available.\n\n", __LINE__) ; + } + else + { exit_if_true (have_vorbis, "\n\nLine %d : Ogg/Vorbis should not be available.\n\n", __LINE__) ; + exit_if_true (have_opus, "\n\nLine %d : Ogg/Opus should not be available.\n\n", __LINE__) ; + } ; + + puts ("ok") ; +} /* subtype_format_test */ + +static void +simple_format_test (void) +{ SF_FORMAT_INFO info ; + int have_flac = 0, have_ogg = 0, have_vorbis = 0, have_opus = 0 ; + int s, simple_count ; + + print_test_name (__func__, NULL) ; + + sf_command (NULL, SFC_GET_SIMPLE_FORMAT_COUNT, &simple_count, sizeof (int)) ; + + for (s = 0 ; s < simple_count ; s++) + { info.format = s ; + sf_command (NULL, SFC_GET_SIMPLE_FORMAT, &info, sizeof (info)) ; + + switch (info.format & SF_FORMAT_TYPEMASK) + { case SF_FORMAT_FLAC : + have_flac = 1 ; + break ; + + case SF_FORMAT_OGG : + have_ogg = 1 ; + break ; + + default : + break ; + } ; + + switch (info.format & SF_FORMAT_SUBMASK) + { case SF_FORMAT_VORBIS : + have_vorbis = 1 ; + break ; + + case SF_FORMAT_OPUS : + have_opus = 1 ; + break ; + + default : + break ; + } ; + + } ; + + if (HAVE_EXTERNAL_XIPH_LIBS) + { exit_if_true (have_flac == 0, "\n\nLine %d : FLAC should be available.\n\n", __LINE__) ; + exit_if_true (have_ogg == 0, "\n\nLine %d : Ogg/Vorbis should be available.\n\n", __LINE__) ; + exit_if_true (have_vorbis == 0, "\n\nLine %d : Ogg/Vorbis should be available.\n\n", __LINE__) ; + exit_if_true (have_opus == 0, "\n\nLine %d : Ogg/Opus should be available.\n\n", __LINE__) ; + } + else + { exit_if_true (have_flac, "\n\nLine %d : FLAC should not be available.\n\n", __LINE__) ; + exit_if_true (have_ogg, "\n\nLine %d : Ogg/Vorbis should not be available.\n\n", __LINE__) ; + exit_if_true (have_vorbis, "\n\nLine %d : Ogg/Vorbis should not be available.\n\n", __LINE__) ; + exit_if_true (have_opus, "\n\nLine %d : Ogg/Opus should not be available.\n\n", __LINE__) ; + } ; + + puts ("ok") ; +} /* simple_format_test */ + +static void +flac_subset_test (void) +{ float whatever [256] ; + SNDFILE *file ; + SF_INFO sfinfo ; + sf_count_t rc ; + int samplerate ; + const char *filename = "subset_test.flac" ; + + /* For some formats (like FLAC) the headers are written *just* before the + ** first bit of audio data. This test makes sure errors in that process + ** are caught. + */ + + print_test_name (__func__, NULL) ; + + for (samplerate = 65536 ; samplerate < 655350 ; samplerate *= 4) + { sfinfo.samplerate = samplerate ; + sfinfo.channels = 1 ; + sfinfo.frames = 0 ; + sfinfo.format = SF_FORMAT_FLAC | SF_FORMAT_PCM_16 ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + rc = sf_write_float (file, whatever, ARRAY_LEN (whatever)) ; + unlink (filename) ; + exit_if_true (rc != 0, "\n\nLine %d : return code (%d) should be 0.\n\n", __LINE__, (int) rc) ; + + sf_close (file) ; + } ; + + puts ("ok") ; +} /* flac_subset_test */ + diff --git a/extern/libsndfile-modified/tests/fix_this.c b/extern/libsndfile-modified/tests/fix_this.c new file mode 100644 index 000000000..5c697ea81 --- /dev/null +++ b/extern/libsndfile-modified/tests/fix_this.c @@ -0,0 +1,334 @@ +/* +** Copyright (C) 1999-2014 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif +#include +#include + +#include + +#include "utils.h" + +#define BUFFER_SIZE (1 << 14) +#define SAMPLE_RATE (11025) + +#ifndef M_PI +#define M_PI 3.14159265358979323846264338 +#endif + +static void lcomp_test_int (const char *str, const char *filename, int filetype, double margin) ; + +static int error_function (double data, double orig, double margin) ; +static int decay_response (int k) ; + +static void gen_signal_double (double *data, double scale, int datalen) ; + +/* Force the start of these buffers to be double aligned. Sparc-solaris will +** choke if they are not. +*/ + +typedef union +{ double d [BUFFER_SIZE + 1] ; + int i [BUFFER_SIZE + 1] ; +} BUFFER ; + +static BUFFER data_buffer ; +static BUFFER orig_buffer ; + +int +main (void) +{ const char *filename = "test.au" ; + + lcomp_test_int ("au_g721", filename, SF_ENDIAN_BIG | SF_FORMAT_AU | SF_FORMAT_G721_32, 0.06) ; + + return 0 ; +} /* main */ + +/*============================================================================================ +** Here are the test functions. +*/ + +static void +lcomp_test_int (const char *str, const char *filename, int filetype, double margin) +{ SNDFILE *file ; + SF_INFO sfinfo ; + int k, m, *orig, *data ; + sf_count_t datalen, seekpos ; + int64_t sum_abs ; + double scale ; + + printf ("\nThis is program is not part of the libsndfile test suite.\n\n") ; + + printf (" lcomp_test_int : %s ... ", str) ; + fflush (stdout) ; + + datalen = BUFFER_SIZE ; + + scale = 1.0 * 0x10000 ; + + data = data_buffer.i ; + orig = orig_buffer.i ; + + gen_signal_double (orig_buffer.d, 32000.0 * scale, datalen) ; + for (k = 0 ; k < datalen ; k++) + orig [k] = orig_buffer.d [k] ; + + + sfinfo.samplerate = SAMPLE_RATE ; + sfinfo.frames = 123456789 ; /* Ridiculous value. */ + sfinfo.channels = 1 ; + sfinfo.format = filetype ; + + if (! (file = sf_open (filename, SFM_WRITE, &sfinfo))) + { printf ("sf_open_write failed with error : ") ; + puts (sf_strerror (NULL)) ; + exit (1) ; + } ; + + if ((k = sf_writef_int (file, orig, datalen)) != datalen) + { printf ("sf_writef_int failed with short write (%" PRId64 " => %d).\n", datalen, k) ; + exit (1) ; + } ; + sf_close (file) ; + + memset (data, 0, datalen * sizeof (int)) ; + + if ((filetype & SF_FORMAT_TYPEMASK) != SF_FORMAT_RAW) + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + if (! (file = sf_open (filename, SFM_READ, &sfinfo))) + { printf ("sf_open_read failed with error : ") ; + puts (sf_strerror (NULL)) ; + exit (1) ; + } ; + + if ((sfinfo.format & (SF_FORMAT_TYPEMASK | SF_FORMAT_SUBMASK)) != (filetype & (SF_FORMAT_TYPEMASK | SF_FORMAT_SUBMASK))) + { printf ("Line %d: Returned format incorrect (0x%08X => 0x%08X).\n", __LINE__, filetype, sfinfo.format) ; + exit (1) ; + } ; + + if (sfinfo.frames < datalen) + { printf ("Too few.frames in file. (%" PRId64 " should be a little more than %" PRId64 ")\n", datalen, sfinfo.frames) ; + exit (1) ; + } ; + + if (sfinfo.frames > (datalen + datalen / 2)) + { printf ("Too many.frames in file. (%" PRId64 " should be a little more than %" PRId64 ")\n", datalen, sfinfo.frames) ; + exit (1) ; + } ; + + if (sfinfo.channels != 1) + { printf ("Incorrect number of channels in file.\n") ; + exit (1) ; + } ; + + check_log_buffer_or_die (file, __LINE__) ; + + if ((k = sf_readf_int (file, data, datalen)) != datalen) + { printf ("Line %d: short read (%d should be %" PRId64 ").\n", __LINE__, k, datalen) ; + exit (1) ; + } ; + + sum_abs = 0 ; + for (k = 0 ; k < datalen ; k++) + { if (error_function (data [k] / scale, orig [k] / scale, margin)) + { printf ("Line %d: Incorrect sample (#%d : %f should be %f).\n", __LINE__, k, data [k] / scale, orig [k] / scale) ; + oct_save_int (orig, data, datalen) ; + exit (1) ; + } ; + sum_abs += abs (data [k]) ; + } ; + + if (sum_abs < 1.0) + { printf ("Line %d: Signal is all zeros.\n", __LINE__) ; + exit (1) ; + } ; + + if ((k = sf_readf_int (file, data, datalen)) != sfinfo.frames - datalen) + { printf ("Line %d: Incorrect read length (%" PRId64 " should be %d).\n", __LINE__, sfinfo.frames - datalen, k) ; + exit (1) ; + } ; + + /* This check is only for block based encoders which must append silence + ** to the end of a file so as to fill out a block. + */ + if ((sfinfo.format & SF_FORMAT_SUBMASK) != SF_FORMAT_MS_ADPCM) + for (k = 0 ; k < sfinfo.frames - datalen ; k++) + if (ABS (data [k] / scale) > decay_response (k)) + { printf ("Line %d : Incorrect sample B (#%d : abs (%d) should be < %d).\n", __LINE__, k, data [k], decay_response (k)) ; + exit (1) ; + } ; + + if (! sfinfo.seekable) + { printf ("ok\n") ; + return ; + } ; + + /* Now test sf_seek function. */ + + if ((k = sf_seek (file, 0, SEEK_SET)) != 0) + { printf ("Line %d: Seek to start of file failed (%d).\n", __LINE__, k) ; + exit (1) ; + } ; + + for (m = 0 ; m < 3 ; m++) + { int n ; + + if ((k = sf_readf_int (file, data, 11)) != 11) + { printf ("Line %d: Incorrect read length (11 => %d).\n", __LINE__, k) ; + exit (1) ; + } ; + + for (k = 0 ; k < 11 ; k++) + if (error_function (data [k] / scale, orig [k + m * 11] / scale, margin)) + { printf ("Line %d: Incorrect sample (m = %d) (#%d : %d => %d).\n", __LINE__, m, k + m * 11, orig [k + m * 11], data [k]) ; + for (n = 0 ; n < 1 ; n++) + printf ("%d ", data [n]) ; + printf ("\n") ; + exit (1) ; + } ; + } ; + + seekpos = BUFFER_SIZE / 10 ; + + /* Check seek from start of file. */ + if ((k = sf_seek (file, seekpos, SEEK_SET)) != seekpos) + { printf ("Seek to start of file + %" PRId64 " failed (%d).\n", seekpos, k) ; + exit (1) ; + } ; + + if ((k = sf_readf_int (file, data, 1)) != 1) + { printf ("Line %d: sf_readf_int (file, data, 1) returned %d.\n", __LINE__, k) ; + exit (1) ; + } ; + + if (error_function ((double) data [0], (double) orig [seekpos], margin)) + { printf ("Line %d: sf_seek (SEEK_SET) followed by sf_readf_int failed (%d, %d).\n", __LINE__, orig [1], data [0]) ; + exit (1) ; + } ; + + if ((k = sf_seek (file, 0, SEEK_CUR)) != seekpos + 1) + { printf ("Line %d: sf_seek (SEEK_CUR) with 0 offset failed (%d should be %" PRId64 ")\n", __LINE__, k, seekpos + 1) ; + exit (1) ; + } ; + + seekpos = sf_seek (file, 0, SEEK_CUR) + BUFFER_SIZE / 5 ; + k = sf_seek (file, BUFFER_SIZE / 5, SEEK_CUR) ; + sf_readf_int (file, data, 1) ; + if (error_function ((double) data [0], (double) orig [seekpos], margin) || k != seekpos) + { printf ("Line %d: sf_seek (forwards, SEEK_CUR) followed by sf_readf_int failed (%d, %d) (%d, %" PRId64 ").\n", __LINE__, data [0], orig [seekpos], k, seekpos + 1) ; + exit (1) ; + } ; + + seekpos = sf_seek (file, 0, SEEK_CUR) - 20 ; + /* Check seek backward from current position. */ + k = sf_seek (file, -20, SEEK_CUR) ; + sf_readf_int (file, data, 1) ; + if (error_function ((double) data [0], (double) orig [seekpos], margin) || k != seekpos) + { printf ("sf_seek (backwards, SEEK_CUR) followed by sf_readf_int failed (%d, %d) (%d, %" PRId64 ").\n", data [0], orig [seekpos], k, seekpos) ; + exit (1) ; + } ; + + /* Check that read past end of file returns number of items. */ + sf_seek (file, (int) sfinfo.frames, SEEK_SET) ; + + if ((k = sf_readf_int (file, data, datalen)) != 0) + { printf ("Line %d: Return value from sf_readf_int past end of file incorrect (%d).\n", __LINE__, k) ; + exit (1) ; + } ; + + /* Check seek backward from end. */ + if ((k = sf_seek (file, 5 - (int) sfinfo.frames, SEEK_END)) != 5) + { printf ("sf_seek (SEEK_END) returned %d instead of %d.\n", k, 5) ; + exit (1) ; + } ; + + sf_readf_int (file, data, 1) ; + if (error_function (data [0] / scale, orig [5] / scale, margin)) + { printf ("Line %d: sf_seek (SEEK_END) followed by sf_readf_short failed (%d should be %d).\n", __LINE__, data [0], orig [5]) ; + exit (1) ; + } ; + + sf_close (file) ; + + printf ("ok\n") ; +} /* lcomp_test_int */ + +/*======================================================================================== +** Auxiliary functions +*/ + +#define SIGNAL_MAXVAL 30000.0 +#define DECAY_COUNT 800 + +static int +decay_response (int k) +{ if (k < 1) + return (int) (1.2 * SIGNAL_MAXVAL) ; + if (k > DECAY_COUNT) + return 0 ; + return (int) (1.2 * SIGNAL_MAXVAL * (DECAY_COUNT - k) / (1.0 * DECAY_COUNT)) ; +} /* decay_response */ + +static void +gen_signal_double (double *data, double scale, int datalen) +{ int k, ramplen ; + double amp = 0.0 ; + + ramplen = datalen / 18 ; + + for (k = 0 ; k < datalen ; k++) + { if (k <= ramplen) + amp = scale * k / ((double) ramplen) ; + else if (k > datalen - ramplen) + amp = scale * (datalen - k) / ((double) ramplen) ; + + data [k] = amp * (0.4 * sin (33.3 * 2.0 * M_PI * ((double) (k + 1)) / ((double) SAMPLE_RATE)) + + 0.3 * cos (201.1 * 2.0 * M_PI * ((double) (k + 1)) / ((double) SAMPLE_RATE))) ; + } ; + + return ; +} /* gen_signal_double */ + +static int +error_function (double data, double orig, double margin) +{ double error ; + + if (fabs (orig) <= 500.0) + error = fabs (fabs (data) - fabs (orig)) / 2000.0 ; + else if (fabs (orig) <= 1000.0) + error = fabs (data - orig) / 3000.0 ; + else + error = fabs (data - orig) / fabs (orig) ; + + if (error > margin) + { printf ("\n\n*******************\nError : %f\n", error) ; + return 1 ; + } ; + return 0 ; +} /* error_function */ + diff --git a/extern/libsndfile-modified/tests/floating_point_test.def b/extern/libsndfile-modified/tests/floating_point_test.def new file mode 100644 index 000000000..e368ddf45 --- /dev/null +++ b/extern/libsndfile-modified/tests/floating_point_test.def @@ -0,0 +1,32 @@ +autogen definitions floating_point_test.tpl; + +endian_type = { + end_name = little ; + end_type = SF_ENDIAN_LITTLE ; + } ; + +endian_type = { + end_name = big ; + end_type = SF_ENDIAN_BIG ; + } ; + +float_type = { + float_name = float ; + minor_type = SF_FORMAT_FLOAT ; + } ; + +float_type = { + float_name = double ; + minor_type = SF_FORMAT_DOUBLE ; + } ; + +int_type = { + int_name = short ; + int_max = "0x7FFF" ; + } ; + +int_type = { + int_name = int ; + int_max = "0x7FFFFFFF" ; + } ; + diff --git a/extern/libsndfile-modified/tests/floating_point_test.tpl b/extern/libsndfile-modified/tests/floating_point_test.tpl new file mode 100644 index 000000000..9651391cc --- /dev/null +++ b/extern/libsndfile-modified/tests/floating_point_test.tpl @@ -0,0 +1,380 @@ +[+ AutoGen5 template c +] +/* +** Copyright (C) 1999-2017 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include +#include + +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include + +#include "dft_cmp.h" +#include "utils.h" + +#define SAMPLE_RATE 16000 + +static const char FPT_TEST_PREFIX[] = "fpt" ; + +static void float_scaled_test (const char *filename, int allow_exit, int replace_float, int filetype, double target_snr) ; +static void double_scaled_test (const char *filename, int allow_exit, int replace_float, int filetype, double target_snr) ; + +[+ FOR float_type +][+ FOR int_type +][+ FOR endian_type ++]static void [+ (get "float_name") +]_[+ (get "int_name") +]_[+ (get "end_name") +]_test (const char * filename, int replace_float) ; +[+ ENDFOR endian_type +][+ ENDFOR int_type +][+ ENDFOR float_type ++] + +static double double_data [DFT_DATA_LENGTH] ; +static double double_test [DFT_DATA_LENGTH] ; + +static float float_data [DFT_DATA_LENGTH] ; +static float float_test [DFT_DATA_LENGTH] ; + +static double double_data [DFT_DATA_LENGTH] ; +static short short_data [DFT_DATA_LENGTH] ; +static int int_data [DFT_DATA_LENGTH] ; + +int +main (int argc, char *argv []) +{ int allow_exit = 1 ; + + if (argc == 2 && ! strstr (argv [1], "no-exit")) + allow_exit = 0 ; + +#if (HAVE_LRINTF == 0) + puts ("*** Cannot run this test on this platform because it lacks lrintf().") ; + exit (0) ; +#endif + + /* Float tests. */ + float_scaled_test ("float.raw", allow_exit, SF_FALSE, SF_ENDIAN_LITTLE | SF_FORMAT_RAW | SF_FORMAT_FLOAT, + OS_IS_OPENBSD ? -98.0 : -163.0) ; + + /* Test both signed and unsigned 8 bit files. */ + float_scaled_test ("pcm_s8.raw", allow_exit, SF_FALSE, SF_FORMAT_RAW | SF_FORMAT_PCM_S8, -39.0) ; + float_scaled_test ("pcm_u8.raw", allow_exit, SF_FALSE, SF_FORMAT_RAW | SF_FORMAT_PCM_U8, -39.0) ; + + float_scaled_test ("pcm_16.raw", allow_exit, SF_FALSE, SF_ENDIAN_BIG | SF_FORMAT_RAW | SF_FORMAT_PCM_16, -87.0) ; + float_scaled_test ("pcm_24.raw", allow_exit, SF_FALSE, SF_ENDIAN_LITTLE | SF_FORMAT_RAW | SF_FORMAT_PCM_24, -138.0) ; + float_scaled_test ("pcm_32.raw", allow_exit, SF_FALSE, SF_ENDIAN_BIG | SF_FORMAT_RAW | SF_FORMAT_PCM_32, -163.0) ; + + float_scaled_test ("ulaw.raw", allow_exit, SF_FALSE, SF_FORMAT_RAW | SF_FORMAT_ULAW, -50.0) ; + float_scaled_test ("alaw.raw", allow_exit, SF_FALSE, SF_FORMAT_RAW | SF_FORMAT_ALAW, -49.0) ; + + float_scaled_test ("ima_adpcm.wav", allow_exit, SF_FALSE, SF_FORMAT_WAV | SF_FORMAT_IMA_ADPCM, -47.0) ; + float_scaled_test ("ms_adpcm.wav" , allow_exit, SF_FALSE, SF_FORMAT_WAV | SF_FORMAT_MS_ADPCM, -40.0) ; + float_scaled_test ("gsm610.raw" , allow_exit, SF_FALSE, SF_FORMAT_RAW | SF_FORMAT_GSM610, -33.0) ; + + float_scaled_test ("g721_32.au", allow_exit, SF_FALSE, SF_FORMAT_AU | SF_FORMAT_G721_32, -32.3) ; + float_scaled_test ("g723_24.au", allow_exit, SF_FALSE, SF_FORMAT_AU | SF_FORMAT_G723_24, -32.3) ; + float_scaled_test ("g723_40.au", allow_exit, SF_FALSE, SF_FORMAT_AU | SF_FORMAT_G723_40, -40.0) ; + + /* PAF files do not use the same encoding method for 24 bit PCM data as other file + ** formats so we need to explicitly test it here. + */ + float_scaled_test ("le_paf_24.paf", allow_exit, SF_FALSE, SF_ENDIAN_LITTLE | SF_FORMAT_PAF | SF_FORMAT_PCM_24, -149.0) ; + float_scaled_test ("be_paf_24.paf", allow_exit, SF_FALSE, SF_ENDIAN_BIG | SF_FORMAT_PAF | SF_FORMAT_PCM_24, -149.0) ; + + float_scaled_test ("dwvw_12.raw", allow_exit, SF_FALSE, SF_FORMAT_RAW | SF_FORMAT_DWVW_12, -64.0) ; + float_scaled_test ("dwvw_16.raw", allow_exit, SF_FALSE, SF_FORMAT_RAW | SF_FORMAT_DWVW_16, -92.0) ; + float_scaled_test ("dwvw_24.raw", allow_exit, SF_FALSE, SF_FORMAT_RAW | SF_FORMAT_DWVW_24, -151.0) ; + + float_scaled_test ("adpcm.vox", allow_exit, SF_FALSE, SF_FORMAT_RAW | SF_FORMAT_VOX_ADPCM, -40.0) ; + + float_scaled_test ("dpcm_16.xi", allow_exit, SF_FALSE, SF_FORMAT_XI | SF_FORMAT_DPCM_16, -90.0) ; + float_scaled_test ("dpcm_8.xi" , allow_exit, SF_FALSE, SF_FORMAT_XI | SF_FORMAT_DPCM_8 , -41.0) ; + + float_scaled_test ("pcm_s8.sds", allow_exit, SF_FALSE, SF_FORMAT_SDS | SF_FORMAT_PCM_S8, -89.0) ; + float_scaled_test ("pcm_16.sds", allow_exit, SF_FALSE, SF_FORMAT_SDS | SF_FORMAT_PCM_16, -132.0) ; + float_scaled_test ("pcm_24.sds", allow_exit, SF_FALSE, SF_FORMAT_SDS | SF_FORMAT_PCM_24, -170.0) ; + + float_scaled_test ("alac_16.caf", allow_exit, SF_FALSE, SF_FORMAT_CAF | SF_FORMAT_ALAC_16, -90.0) ; + float_scaled_test ("alac_32.caf", allow_exit, SF_FALSE, SF_FORMAT_CAF | SF_FORMAT_ALAC_32, -76.0) ; + float_scaled_test ("alac_24.caf", allow_exit, SF_FALSE, SF_FORMAT_CAF | SF_FORMAT_ALAC_24, -153.0) ; + float_scaled_test ("alac_20.caf", allow_exit, SF_FALSE, SF_FORMAT_CAF | SF_FORMAT_ALAC_20, -125.0) ; + +#if HAVE_EXTERNAL_XIPH_LIBS + float_scaled_test ("flac_8.flac", allow_exit, SF_FALSE, SF_FORMAT_FLAC | SF_FORMAT_PCM_S8, -39.0) ; + float_scaled_test ("flac_16.flac", allow_exit, SF_FALSE, SF_FORMAT_FLAC | SF_FORMAT_PCM_16, -87.0) ; + float_scaled_test ("flac_24.flac", allow_exit, SF_FALSE, SF_FORMAT_FLAC | SF_FORMAT_PCM_24, -138.0) ; + + float_scaled_test ("vorbis.oga", allow_exit, SF_FALSE, SF_FORMAT_OGG | SF_FORMAT_VORBIS, -31.0) ; + + float_scaled_test ("opus.opus", allow_exit, SF_FALSE, SF_FORMAT_OGG | SF_FORMAT_OPUS, -32.0) ; +#endif + +#if HAVE_MPEG + float_scaled_test ("mpeg.mp3", allow_exit, SF_FALSE, SF_FORMAT_MPEG | SF_FORMAT_MPEG_LAYER_III, -52.0) ; +#endif + + float_scaled_test ("replace_float.raw", allow_exit, SF_TRUE, SF_ENDIAN_LITTLE | SF_FORMAT_RAW | SF_FORMAT_FLOAT, -163.0) ; + + /*============================================================================== + ** Double tests. + */ + + double_scaled_test ("double.raw", allow_exit, SF_FALSE, SF_FORMAT_RAW | SF_FORMAT_DOUBLE, -201.0) ; + + /* Test both signed (AIFF) and unsigned (WAV) 8 bit files. */ + double_scaled_test ("pcm_s8.raw", allow_exit, SF_FALSE, SF_FORMAT_RAW | SF_FORMAT_PCM_S8, -39.0) ; + double_scaled_test ("pcm_u8.raw", allow_exit, SF_FALSE, SF_FORMAT_RAW | SF_FORMAT_PCM_U8, -39.0) ; + + double_scaled_test ("pcm_16.raw", allow_exit, SF_FALSE, SF_FORMAT_RAW | SF_FORMAT_PCM_16, -87.0) ; + double_scaled_test ("pcm_24.raw", allow_exit, SF_FALSE, SF_FORMAT_RAW | SF_FORMAT_PCM_24, -135.0) ; + double_scaled_test ("pcm_32.raw", allow_exit, SF_FALSE, SF_FORMAT_RAW | SF_FORMAT_PCM_32, -184.0) ; + + double_scaled_test ("ulaw.raw", allow_exit, SF_FALSE, SF_FORMAT_RAW | SF_FORMAT_ULAW, -50.0) ; + double_scaled_test ("alaw.raw", allow_exit, SF_FALSE, SF_FORMAT_RAW | SF_FORMAT_ALAW, -49.0) ; + + double_scaled_test ("ima_adpcm.wav", allow_exit, SF_FALSE, SF_FORMAT_WAV | SF_FORMAT_IMA_ADPCM, -47.0) ; + double_scaled_test ("ms_adpcm.wav" , allow_exit, SF_FALSE, SF_FORMAT_WAV | SF_FORMAT_MS_ADPCM, -40.0) ; + double_scaled_test ("gsm610.raw" , allow_exit, SF_FALSE, SF_FORMAT_RAW | SF_FORMAT_GSM610, -33.0) ; + + double_scaled_test ("g721_32.au", allow_exit, SF_FALSE, SF_FORMAT_AU | SF_FORMAT_G721_32, -32.3) ; + double_scaled_test ("g723_24.au", allow_exit, SF_FALSE, SF_FORMAT_AU | SF_FORMAT_G723_24, -32.3) ; + double_scaled_test ("g723_40.au", allow_exit, SF_FALSE, SF_FORMAT_AU | SF_FORMAT_G723_40, -40.0) ; + + /* 24 bit PCM PAF files tested here. */ + double_scaled_test ("be_paf_24.paf", allow_exit, SF_FALSE, SF_ENDIAN_BIG | SF_FORMAT_PAF | SF_FORMAT_PCM_24, -151.0) ; + double_scaled_test ("le_paf_24.paf", allow_exit, SF_FALSE, SF_ENDIAN_LITTLE | SF_FORMAT_PAF | SF_FORMAT_PCM_24, -151.0) ; + + double_scaled_test ("dwvw_12.raw", allow_exit, SF_FALSE, SF_FORMAT_RAW | SF_FORMAT_DWVW_12, -64.0) ; + double_scaled_test ("dwvw_16.raw", allow_exit, SF_FALSE, SF_FORMAT_RAW | SF_FORMAT_DWVW_16, -92.0) ; + double_scaled_test ("dwvw_24.raw", allow_exit, SF_FALSE, SF_FORMAT_RAW | SF_FORMAT_DWVW_24, -151.0) ; + + double_scaled_test ("adpcm.vox" , allow_exit, SF_FALSE, SF_FORMAT_RAW | SF_FORMAT_VOX_ADPCM, -40.0) ; + + double_scaled_test ("dpcm_16.xi", allow_exit, SF_FALSE, SF_FORMAT_XI | SF_FORMAT_DPCM_16, -90.0) ; + double_scaled_test ("dpcm_8.xi" , allow_exit, SF_FALSE, SF_FORMAT_XI | SF_FORMAT_DPCM_8 , -41.0) ; + + double_scaled_test ("pcm_s8.sds", allow_exit, SF_FALSE, SF_FORMAT_SDS | SF_FORMAT_PCM_S8, -89.0) ; + double_scaled_test ("pcm_16.sds", allow_exit, SF_FALSE, SF_FORMAT_SDS | SF_FORMAT_PCM_16, -132.0) ; + double_scaled_test ("pcm_24.sds", allow_exit, SF_FALSE, SF_FORMAT_SDS | SF_FORMAT_PCM_24, -180.0) ; + + double_scaled_test ("alac_16.caf", allow_exit, SF_FALSE, SF_FORMAT_CAF | SF_FORMAT_ALAC_16, -90.0) ; + double_scaled_test ("alac_20.caf", allow_exit, SF_FALSE, SF_FORMAT_CAF | SF_FORMAT_ALAC_20, -125.0) ; + double_scaled_test ("alac_24.caf", allow_exit, SF_FALSE, SF_FORMAT_CAF | SF_FORMAT_ALAC_24, -153.0) ; + double_scaled_test ("alac_32.caf", allow_exit, SF_FALSE, SF_FORMAT_CAF | SF_FORMAT_ALAC_32, -186.0) ; + +#if HAVE_EXTERNAL_XIPH_LIBS + double_scaled_test ("flac_8.flac", allow_exit, SF_FALSE, SF_FORMAT_FLAC | SF_FORMAT_PCM_S8, -39.0) ; + double_scaled_test ("flac_16.flac", allow_exit, SF_FALSE, SF_FORMAT_FLAC | SF_FORMAT_PCM_16, -87.0) ; + double_scaled_test ("flac_24.flac", allow_exit, SF_FALSE, SF_FORMAT_FLAC | SF_FORMAT_PCM_24, -138.0) ; + + double_scaled_test ("vorbis.oga", allow_exit, SF_FALSE, SF_FORMAT_OGG | SF_FORMAT_VORBIS, -29.0) ; + double_scaled_test ("opus.opus", allow_exit, SF_FALSE, SF_FORMAT_OGG | SF_FORMAT_OPUS, -32.0) ; +#endif + +#if HAVE_MPEG + double_scaled_test ("mpeg.mp3", allow_exit, SF_FALSE, SF_FORMAT_MPEG | SF_FORMAT_MPEG_LAYER_III, -52.0) ; +#endif + + double_scaled_test ("replace_double.raw", allow_exit, SF_TRUE, SF_FORMAT_RAW | SF_FORMAT_DOUBLE, -201.0) ; + + putchar ('\n') ; + /* Float int tests. */ +[+ FOR float_type +][+ FOR int_type +][+ FOR endian_type +] +[+ (get "float_name") +]_[+ (get "int_name") +]_[+ (get "end_name") +]_test ("[+ (get "float_name") +]_[+ (get "int_name") +]_[+ (get "end_name") +].au", SF_FALSE) ; +[+ (get "float_name") +]_[+ (get "int_name") +]_[+ (get "end_name") +]_test ("[+ (get "float_name") +]_[+ (get "int_name") +]_[+ (get "end_name") +]_replace.au", SF_TRUE) ; +[+ ENDFOR endian_type +][+ ENDFOR int_type +][+ ENDFOR float_type +] + + return 0 ; +} /* main */ + +/*============================================================================================ + * Here are the test functions. + */ + +static void +float_scaled_test (const char *filename, int allow_exit, int replace_float, int filetype, double target_snr) +{ SNDFILE *file ; + SF_INFO sfinfo ; + double snr ; + int byterate ; + + get_unique_test_name (&filename, FPT_TEST_PREFIX) ; + print_test_name ("float_scaled_test", filename) ; + + gen_windowed_sine_float (float_data, DFT_DATA_LENGTH, 0.9999) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + sfinfo.samplerate = SAMPLE_RATE ; + sfinfo.frames = DFT_DATA_LENGTH ; + sfinfo.channels = 1 ; + sfinfo.format = filetype ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + sf_command (file, SFC_TEST_IEEE_FLOAT_REPLACE, NULL, replace_float) ; + + test_write_float_or_die (file, 0, float_data, DFT_DATA_LENGTH, __LINE__) ; + + sf_close (file) ; + + memset (float_test, 0, sizeof (float_test)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + sf_command (file, SFC_TEST_IEEE_FLOAT_REPLACE, NULL, replace_float) ; + + exit_if_true (sfinfo.format != filetype, "\n\nLine %d: Returned format incorrect (0x%08X => 0x%08X).\n", __LINE__, filetype, sfinfo.format) ; + exit_if_true (sfinfo.frames < DFT_DATA_LENGTH, "\n\nLine %d: Incorrect number of frames in file (too short). (%" PRId64 " should be %d)\n", __LINE__, sfinfo.frames, DFT_DATA_LENGTH) ; + exit_if_true (sfinfo.channels != 1, "\n\nLine %d: Incorrect number of channels in file.\n", __LINE__) ; + + check_log_buffer_or_die (file, __LINE__) ; + + test_read_float_or_die (file, 0, float_test, DFT_DATA_LENGTH, __LINE__) ; + + byterate = sf_current_byterate (file) ; + exit_if_true (byterate <= 0, "\n\nLine %d: byterate is zero.\n", __LINE__) ; + + sf_close (file) ; + + snr = dft_cmp_float (__LINE__, float_data, float_test, DFT_DATA_LENGTH, target_snr, allow_exit) ; + + exit_if_true (snr > target_snr, "% 6.1fdB SNR\n\n Error : should be better than % 6.1fdB\n\n", snr, target_snr) ; + + printf ("% 6.1fdB SNR ... ok\n", snr) ; + + unlink (filename) ; + + return ; +} /* float_scaled_test */ + +static void +double_scaled_test (const char *filename, int allow_exit, int replace_float, int filetype, double target_snr) +{ SNDFILE *file ; + SF_INFO sfinfo ; + double snr ; + int byterate ; + + get_unique_test_name (&filename, FPT_TEST_PREFIX) ; + print_test_name ("double_scaled_test", filename) ; + + gen_windowed_sine_double (double_data, DFT_DATA_LENGTH, 0.9999) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + sfinfo.samplerate = SAMPLE_RATE ; + sfinfo.frames = DFT_DATA_LENGTH ; + sfinfo.channels = 1 ; + sfinfo.format = filetype ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + sf_command (file, SFC_TEST_IEEE_FLOAT_REPLACE, NULL, replace_float) ; + + test_write_double_or_die (file, 0, double_data, DFT_DATA_LENGTH, __LINE__) ; + + sf_close (file) ; + + memset (double_test, 0, sizeof (double_test)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + sf_command (file, SFC_TEST_IEEE_FLOAT_REPLACE, NULL, replace_float) ; + + exit_if_true (sfinfo.format != filetype, "\n\nLine %d: Returned format incorrect (0x%08X => 0x%08X).\n", __LINE__, filetype, sfinfo.format) ; + exit_if_true (sfinfo.frames < DFT_DATA_LENGTH, "\n\nLine %d: Incorrect number of frames in file (too short). (%" PRId64 " should be %d)\n", __LINE__, sfinfo.frames, DFT_DATA_LENGTH) ; + exit_if_true (sfinfo.channels != 1, "\n\nLine %d: Incorrect number of channels in file.\n", __LINE__) ; + + check_log_buffer_or_die (file, __LINE__) ; + + test_read_double_or_die (file, 0, double_test, DFT_DATA_LENGTH, __LINE__) ; + + byterate = sf_current_byterate (file) ; + exit_if_true (byterate <= 0, "\n\nLine %d: byterate is zero.\n", __LINE__) ; + + sf_close (file) ; + + snr = dft_cmp_double (__LINE__, double_data, double_test, DFT_DATA_LENGTH, target_snr, allow_exit) ; + + exit_if_true (snr > target_snr, "% 6.1fdB SNR\n\n Error : should be better than % 6.1fdB\n\n", snr, target_snr) ; + + printf ("% 6.1fdB SNR ... ok\n", snr) ; + + unlink (filename) ; + + return ; +} /* double_scaled_test */ + +/*============================================================================== +*/ + +[+ FOR float_type +][+ FOR int_type +][+ FOR endian_type ++] +static void +[+ (get "float_name") +]_[+ (get "int_name") +]_[+ (get "end_name") +]_test (const char * filename, int replace_float) +{ SNDFILE *file ; + SF_INFO sfinfo ; + int max ; + unsigned k ; + + get_unique_test_name (&filename, FPT_TEST_PREFIX) ; + print_test_name ("[+ (get "float_name") +]_[+ (get "int_name") +]_[+ (get "end_name") +]_test", filename) ; + + gen_windowed_sine_[+ (get "float_name") +] ([+ (get "float_name") +]_data, ARRAY_LEN ([+ (get "float_name") +]_data), 0.9999) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + sfinfo.samplerate = SAMPLE_RATE ; + sfinfo.frames = ARRAY_LEN ([+ (get "int_name") +]_data) ; + sfinfo.channels = 1 ; + sfinfo.format = [+ (get "end_type") +] | SF_FORMAT_AU | [+ (get "minor_type") +] ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + sf_command (file, SFC_TEST_IEEE_FLOAT_REPLACE, NULL, replace_float) ; + test_write_[+ (get "float_name") +]_or_die (file, 0, [+ (get "float_name") +]_data, ARRAY_LEN ([+ (get "float_name") +]_data), __LINE__) ; + sf_close (file) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + sf_command (file, SFC_TEST_IEEE_FLOAT_REPLACE, NULL, replace_float) ; + + if (sfinfo.frames != ARRAY_LEN ([+ (get "float_name") +]_data)) + { printf ("\n\nLine %d: Incorrect number of frames in file (too short). (%" PRId64 " should be %d)\n", __LINE__, sfinfo.frames, DFT_DATA_LENGTH) ; + exit (1) ; + } ; + + if (sfinfo.channels != 1) + { printf ("\n\nLine %d: Incorrect number of channels in file.\n", __LINE__) ; + exit (1) ; + } ; + + sf_command (file, SFC_SET_SCALE_FLOAT_INT_READ, NULL, SF_TRUE) ; + + test_read_[+ (get "int_name") +]_or_die (file, 0, [+ (get "int_name") +]_data, ARRAY_LEN ([+ (get "int_name") +]_data), __LINE__) ; + sf_close (file) ; + + max = 0 ; + for (k = 0 ; k < ARRAY_LEN ([+ (get "int_name") +]_data) ; k++) + if (abs ([+ (get "int_name") +]_data [k]) > max) + max = abs ([+ (get "int_name") +]_data [k]) ; + + if (1.0 * abs (max - [+ (get "int_max") +]) / [+ (get "int_max") +] > 0.01) + { printf ("\n\nLine %d: Bad maximum (%d should be %d).\n\n", __LINE__, max, [+ (get "int_max") +]) ; + exit (1) ; + } ; + + unlink (filename) ; + puts ("ok") ; +} /* [+ (get "float_name") +]_[+ (get "int_name") +]_[+ (get "end_name") +]_test */ +[+ ENDFOR endian_type +][+ ENDFOR int_type +][+ ENDFOR float_type +] + diff --git a/extern/libsndfile-modified/tests/format_check_test.c b/extern/libsndfile-modified/tests/format_check_test.c new file mode 100644 index 000000000..2e76679a4 --- /dev/null +++ b/extern/libsndfile-modified/tests/format_check_test.c @@ -0,0 +1,166 @@ +/* +** Copyright (C) 2011-2017 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include + +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include "sndfile.h" +#include "utils.h" + +static void format_error_test (void) ; +static void format_combo_test (void) ; + +int +main (void) +{ + format_error_test () ; + format_combo_test () ; + + return 0 ; +} /* main */ + +/*============================================================================== +*/ + +static void +format_error_test (void) +{ const char *filename = "format-error.wav" ; + SNDFILE *file ; + SF_INFO info ; + + print_test_name (__func__, NULL) ; + + memset (&info, 0, sizeof (info)) ; + info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 ; + info.channels = 1 ; + info.samplerate = 44100 ; + + info.format = SF_FORMAT_WAV ; + file = sf_open (filename, SFM_WRITE, &info) ; + exit_if_true (file != NULL, "\n\nLine %d : Format should not be valid.\n\n", __LINE__) ; + exit_if_true ( + strstr (sf_strerror (NULL), "minor format") == NULL, + "\n\nLine %d : Error string should reference bad 'minor format'.\n\n", __LINE__ + ) ; + + info.format = SF_FORMAT_PCM_16 ; + file = sf_open (filename, SFM_WRITE, &info) ; + exit_if_true (file != NULL, "\n\nLine %d : Format should not be valid.\n\n", __LINE__) ; + exit_if_true ( + strstr (sf_strerror (NULL), "major format") == NULL, + "\n\nLine %d : Error string should reference bad 'major format'.\n\n", __LINE__ + ) ; + + unlink (filename) ; + puts ("ok") ; +} /* format_error_test */ + +static void +format_combo_test (void) +{ int container_max, codec_max, cont, codec ; + + print_test_name (__func__, NULL) ; + + sf_command (NULL, SFC_GET_FORMAT_MAJOR_COUNT, &container_max, sizeof (container_max)) ; + sf_command (NULL, SFC_GET_FORMAT_SUBTYPE_COUNT, &codec_max, sizeof (codec_max)) ; + + for (cont = 0 ; cont < container_max + 10 ; cont ++) + { SF_FORMAT_INFO major_fmt_info ; + + memset (&major_fmt_info, 0, sizeof (major_fmt_info)) ; + major_fmt_info.format = cont ; + (void) sf_command (NULL, SFC_GET_FORMAT_MAJOR, &major_fmt_info, sizeof (major_fmt_info)) ; + + for (codec = 0 ; codec < codec_max + 10 ; codec ++) + { SF_FORMAT_INFO subtype_fmt_info ; + SNDFILE * sndfile ; + SF_INFO info ; + char filename [128] ; + int subtype_is_valid, check_is_valid ; + + memset (&info, 0, sizeof (info)) ; + memset (&subtype_fmt_info, 0, sizeof (subtype_fmt_info)) ; + subtype_fmt_info.format = codec ; + subtype_is_valid = sf_command (NULL, SFC_GET_FORMAT_SUBTYPE, &subtype_fmt_info, sizeof (subtype_fmt_info)) == 0 ; + + /* Opus only works with a fixed set of sample rates. */ + if (subtype_fmt_info.format == SF_FORMAT_OPUS) + sf_info_setup (&info, major_fmt_info.format | subtype_fmt_info.format, 24000, 1) ; + else + sf_info_setup (&info, major_fmt_info.format | subtype_fmt_info.format, 22050, 1) ; + + check_is_valid = sf_format_check (&info) ; + + exit_if_true ( + NOT (subtype_is_valid) && check_is_valid, + "\n\nLine %d : Subtype is not valid but checks ok.\n", + __LINE__ + ) ; + + /* Only have decode, not encode support for MPEG Layer I and II */ + if (subtype_fmt_info.format == SF_FORMAT_MPEG_LAYER_I || + subtype_fmt_info.format == SF_FORMAT_MPEG_LAYER_II) + continue ; + + /* MPEG Layer III in WAV is decode only currently */ + if (subtype_fmt_info.format == SF_FORMAT_MPEG_LAYER_III && + major_fmt_info.format == SF_FORMAT_WAV) + continue ; + + snprintf (filename, sizeof (filename), "format-check.%s", major_fmt_info.extension) ; + + sndfile = sf_open (filename, SFM_WRITE, &info) ; + + sf_close (sndfile) ; + unlink (filename) ; + + if (major_fmt_info.extension != NULL && strcmp (major_fmt_info.extension, "sd2") == 0) + { snprintf (filename, sizeof (filename), "._format-check.%s", major_fmt_info.extension) ; + unlink (filename) ; + } ; + + exit_if_true ( + sndfile && NOT (check_is_valid), + "\n\nError : Format was not valid but file opened correctly.\n" + " Container : %s\n" + " Codec : %s\n\n", + major_fmt_info.name, subtype_fmt_info.name + ) ; + + exit_if_true ( + NOT (sndfile) && check_is_valid, + "\n\nError : Format was valid but file failed to open.\n" + " Container : %s\n" + " Codec : %s\n\n", + major_fmt_info.name, subtype_fmt_info.name + ) ; + } ; + } ; + + puts ("ok") ; +} /* format_combo_test */ + diff --git a/extern/libsndfile-modified/tests/generate.c b/extern/libsndfile-modified/tests/generate.c new file mode 100644 index 000000000..b49b2718b --- /dev/null +++ b/extern/libsndfile-modified/tests/generate.c @@ -0,0 +1,75 @@ +/* +** Copyright (C) 2007-2012 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include + +#include + +#include "utils.h" +#include "generate.h" + +#define SF_MAX(x, y) ((x) > (y) ? (x) : (y)) + +static float crappy_snare (float *output, int len, int offset, float gain, float maxabs) ; + +void +generate_file (const char * filename, int format, int len) +{ float * output ; + float maxabs = 0.0 ; + + output = calloc (len, sizeof (float)) ; + + maxabs = crappy_snare (output, len, 0, 0.95f, maxabs) ; + maxabs = crappy_snare (output, len, len / 4, 0.85f, maxabs) ; + maxabs = crappy_snare (output, len, 2 * len / 4, 0.85f, maxabs) ; + crappy_snare (output, len, 3 * len / 4, 0.85f, maxabs) ; + + write_mono_file (filename, format, 44100, output, len) ; + + free (output) ; +} /* generate_file */ + +static inline float +rand_float (void) +{ return rand () / (0.5f * (float) RAND_MAX) - 1.0f ; +} /* rand_float */ + +static float +crappy_snare (float *output, int len, int offset, float gain, float maxabs) +{ int k ; + float env = 0.0f ; + + for (k = offset ; k < len && env < gain ; k++) + { env += 0.03f ; + output [k] += env * rand_float () ; + maxabs = SF_MAX (maxabs, fabsf (output [k])) ; + } ; + + for ( ; k < len && env > 1e-8 ; k++) + { env *= 0.995f ; + output [k] += env * rand_float () ; + maxabs = SF_MAX (maxabs, fabsf (output [k])) ; + } ; + + return maxabs ; +} /* crappy_snare */ diff --git a/extern/libsndfile-modified/tests/generate.h b/extern/libsndfile-modified/tests/generate.h new file mode 100644 index 000000000..709ea6119 --- /dev/null +++ b/extern/libsndfile-modified/tests/generate.h @@ -0,0 +1,19 @@ +/* +** Copyright (C) 2007-2011 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +void generate_file (const char * filename, int format, int len) ; diff --git a/extern/libsndfile-modified/tests/header_test.def b/extern/libsndfile-modified/tests/header_test.def new file mode 100644 index 000000000..959703ef0 --- /dev/null +++ b/extern/libsndfile-modified/tests/header_test.def @@ -0,0 +1,22 @@ +autogen definitions header_test.tpl; + +data_type = { + name = "short" ; + format = "SF_FORMAT_PCM_16" ; + } ; + +data_type = { + name = "int" ; + format = "SF_FORMAT_PCM_32" ; + } ; + +data_type = { + name = "float" ; + format = "SF_FORMAT_FLOAT" ; + } ; + +data_type = { + name = "double" ; + format = "SF_FORMAT_DOUBLE" ; + } ; + diff --git a/extern/libsndfile-modified/tests/header_test.tpl b/extern/libsndfile-modified/tests/header_test.tpl new file mode 100644 index 000000000..b02fbef86 --- /dev/null +++ b/extern/libsndfile-modified/tests/header_test.tpl @@ -0,0 +1,583 @@ +[+ AutoGen5 template c +] +/* +** Copyright (C) 2001-2017 Erik de Castro Lopo +** +** This program is free software ; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation ; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY ; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program ; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include +#include + +#include + +#if HAVE_UNISTD_H +#include +#endif + +#if (HAVE_DECL_S_IRGRP == 0) +#include +#endif + +#if (defined (WIN32) || defined (_WIN32)) +#include +#include +#endif + +#include + +#include "utils.h" + +#define BUFFER_LEN (1 << 10) +#define LOG_BUFFER_SIZE 1024 + +static void update_header_test (const char *filename, int typemajor) ; +static void update_header_before_write_test (const char *filename, int typemajor) ; + +[+ FOR data_type ++]static void update_seek_[+ (get "name") +]_test (const char *filename, int filetype) ; +[+ ENDFOR data_type ++] + +static void extra_header_test (const char *filename, int filetype) ; + +static void header_shrink_test (const char *filename, int filetype) ; + +/* Force the start of this buffer to be double aligned. Sparc-solaris will +** choke if its not. +*/ +static int data_out [BUFFER_LEN] ; +static int data_in [BUFFER_LEN] ; + +int +main (int argc, char *argv []) +{ int do_all = 0 ; + int test_count = 0 ; + + if (argc != 2) + { printf ("Usage : %s \n", argv [0]) ; + printf (" Where is one of the following:\n") ; + printf (" wav - test WAV file peak chunk\n") ; + printf (" aiff - test AIFF file PEAK chunk\n") ; + printf (" all - perform all tests\n") ; + exit (1) ; + } ; + + do_all= !strcmp (argv [1], "all") ; + + if (do_all || ! strcmp (argv [1], "wav")) + { update_header_test ("header.wav", SF_FORMAT_WAV) ; + update_seek_short_test ("header_short.wav", SF_FORMAT_WAV) ; + update_seek_int_test ("header_int.wav", SF_FORMAT_WAV) ; + update_seek_float_test ("header_float.wav", SF_FORMAT_WAV) ; + update_seek_double_test ("header_double.wav", SF_FORMAT_WAV) ; + header_shrink_test ("header_shrink.wav", SF_FORMAT_WAV) ; + extra_header_test ("extra.wav", SF_FORMAT_WAV) ; + + update_header_test ("header.wavex", SF_FORMAT_WAVEX) ; + update_seek_short_test ("header_short.wavex", SF_FORMAT_WAVEX) ; + update_seek_int_test ("header_int.wavex", SF_FORMAT_WAVEX) ; + update_seek_float_test ("header_float.wavex", SF_FORMAT_WAVEX) ; + update_seek_double_test ("header_double.wavex", SF_FORMAT_WAVEX) ; + header_shrink_test ("header_shrink.wavex", SF_FORMAT_WAVEX) ; + extra_header_test ("extra.wavex", SF_FORMAT_WAVEX) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "aiff")) + { update_header_test ("header.aiff", SF_FORMAT_AIFF) ; + update_seek_short_test ("header_short.aiff", SF_FORMAT_AIFF) ; + update_seek_int_test ("header_int.aiff", SF_FORMAT_AIFF) ; + update_seek_float_test ("header_float.aiff", SF_FORMAT_AIFF) ; + update_seek_double_test ("header_double.aiff", SF_FORMAT_AIFF) ; + header_shrink_test ("header_shrink.aiff", SF_FORMAT_AIFF) ; + extra_header_test ("extra.aiff", SF_FORMAT_AIFF) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "au")) + { update_header_test ("header.au", SF_FORMAT_AU) ; + update_seek_short_test ("header_short.au", SF_FORMAT_AU) ; + update_seek_int_test ("header_int.au", SF_FORMAT_AU) ; + update_seek_float_test ("header_float.au", SF_FORMAT_AU) ; + update_seek_double_test ("header_double.au", SF_FORMAT_AU) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "caf")) + { update_header_test ("header.caf", SF_FORMAT_CAF) ; + update_seek_short_test ("header_short.caf", SF_FORMAT_CAF) ; + update_seek_int_test ("header_int.caf", SF_FORMAT_CAF) ; + update_seek_float_test ("header_float.caf", SF_FORMAT_CAF) ; + update_seek_double_test ("header_double.caf", SF_FORMAT_CAF) ; + /* extra_header_test ("extra.caf", SF_FORMAT_CAF) ; */ + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "nist")) + { update_header_test ("header.nist", SF_FORMAT_NIST) ; + update_seek_short_test ("header_short.nist", SF_FORMAT_NIST) ; + update_seek_int_test ("header_int.nist", SF_FORMAT_NIST) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "paf")) + { update_header_test ("header.paf", SF_FORMAT_PAF) ; + update_seek_short_test ("header_short.paf", SF_FORMAT_PAF) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "ircam")) + { update_header_test ("header.ircam", SF_FORMAT_IRCAM) ; + update_seek_short_test ("header_short.ircam", SF_FORMAT_IRCAM) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "w64")) + { update_header_test ("header.w64", SF_FORMAT_W64) ; + update_seek_short_test ("header_short.w64", SF_FORMAT_W64) ; + update_seek_int_test ("header_int.w64", SF_FORMAT_W64) ; + update_seek_float_test ("header_float.w64", SF_FORMAT_W64) ; + update_seek_double_test ("header_double.w64", SF_FORMAT_W64) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "rf64")) + { update_header_test ("header.rf64", SF_FORMAT_RF64) ; + update_seek_short_test ("header_short.rf64", SF_FORMAT_RF64) ; + update_seek_int_test ("header_int.rf64", SF_FORMAT_RF64) ; + update_seek_float_test ("header_float.rf64", SF_FORMAT_RF64) ; + update_seek_double_test ("header_double.rf64", SF_FORMAT_RF64) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "mat4")) + { update_header_test ("header.mat4", SF_FORMAT_MAT4) ; + update_seek_short_test ("header_short.mat4", SF_FORMAT_MAT4) ; + update_seek_int_test ("header_int.mat4", SF_FORMAT_MAT4) ; + update_seek_float_test ("header_float.mat4", SF_FORMAT_MAT4) ; + update_seek_double_test ("header_double.mat4", SF_FORMAT_MAT4) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "mat5")) + { update_header_test ("header.mat5", SF_FORMAT_MAT5) ; + update_seek_short_test ("header_short.mat5", SF_FORMAT_MAT5) ; + update_seek_int_test ("header_int.mat5", SF_FORMAT_MAT5) ; + update_seek_float_test ("header_float.mat5", SF_FORMAT_MAT5) ; + update_seek_double_test ("header_double.mat5", SF_FORMAT_MAT5) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "pvf")) + { update_header_test ("header.pvf", SF_FORMAT_PVF) ; + update_seek_short_test ("header_short.pvf", SF_FORMAT_PVF) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "avr")) + { update_header_test ("header.avr", SF_FORMAT_AVR) ; + update_seek_short_test ("header_short.avr", SF_FORMAT_AVR) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "htk")) + { update_header_test ("header.htk", SF_FORMAT_HTK) ; + update_seek_short_test ("header_short.htk", SF_FORMAT_HTK) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "svx")) + { update_header_test ("header.svx", SF_FORMAT_SVX) ; + update_seek_short_test ("header_short.svx", SF_FORMAT_SVX) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "voc")) + { update_header_test ("header.voc", SF_FORMAT_VOC) ; + /*-update_seek_short_test ("header_short.voc", SF_FORMAT_VOC) ;-*/ + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "sds")) + { update_header_test ("header.sds", SF_FORMAT_SDS) ; + /*-update_seek_short_test ("header_short.sds", SF_FORMAT_SDS) ;-*/ + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "mpc2k")) + { update_header_test ("header.mpc", SF_FORMAT_MPC2K) ; + update_seek_short_test ("header_short.mpc", SF_FORMAT_MPC2K) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "flac")) + { if (HAVE_EXTERNAL_XIPH_LIBS) + update_header_before_write_test ("header.flac", SF_FORMAT_FLAC) ; + else + puts (" No FLAC tests because FLAC support was not compiled in.") ; + test_count++ ; + } ; + + if (test_count == 0) + { printf ("Mono : ************************************\n") ; + printf ("Mono : * No '%s' test defined.\n", argv [1]) ; + printf ("Mono : ************************************\n") ; + return 1 ; + } ; + + return 0 ; +} /* main */ + + +/*============================================================================================ +** Here are the test functions. +*/ + +static void +update_header_sub (const char *filename, int typemajor, int write_mode) +{ SNDFILE *outfile, *infile ; + SF_INFO sfinfo ; + int k ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + sfinfo.samplerate = 44100 ; + sfinfo.format = (typemajor | SF_FORMAT_PCM_16) ; + sfinfo.channels = 1 ; + + outfile = test_open_file_or_die (filename, write_mode, &sfinfo, SF_TRUE, __LINE__) ; + + for (k = 0 ; k < BUFFER_LEN ; k++) + data_out [k] = k + 1 ; + test_write_int_or_die (outfile, 0, data_out, BUFFER_LEN, __LINE__) ; + + if (typemajor != SF_FORMAT_HTK) + { /* The HTK header is not correct when the file is first written. */ + infile = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + sf_close (infile) ; + } ; + + sf_command (outfile, SFC_UPDATE_HEADER_NOW, NULL, 0) ; + + /* + ** Open file and check log buffer for an error. If header update failed + ** the the log buffer will contain errors. + */ + infile = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + check_log_buffer_or_die (infile, __LINE__) ; + + if (sfinfo.frames < BUFFER_LEN || sfinfo.frames > BUFFER_LEN + 50) + { printf ("\n\nLine %d : Incorrect sample count (%" PRId64 " should be %d)\n", __LINE__, sfinfo.frames, BUFFER_LEN) ; + dump_log_buffer (infile) ; + exit (1) ; + } ; + + test_read_int_or_die (infile, 0, data_in, BUFFER_LEN, __LINE__) ; + for (k = 0 ; k < BUFFER_LEN ; k++) + if (data_out [k] != k + 1) + printf ("Error : line %d\n", __LINE__) ; + + sf_close (infile) ; + + /* Set auto update on. */ + sf_command (outfile, SFC_SET_UPDATE_HEADER_AUTO, NULL, SF_TRUE) ; + + /* Write more data_out. */ + for (k = 0 ; k < BUFFER_LEN ; k++) + data_out [k] = k + 2 ; + test_write_int_or_die (outfile, 0, data_out, BUFFER_LEN, __LINE__) ; + + /* Open file again and make sure no errors in log buffer. */ + infile = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + check_log_buffer_or_die (infile, __LINE__) ; + + if (sfinfo.frames < 2 * BUFFER_LEN || sfinfo.frames > 2 * BUFFER_LEN + 50) + { printf ("\n\nLine %d : Incorrect sample count (%" PRId64 " should be %d)\n", __LINE__, sfinfo.frames, 2 * BUFFER_LEN) ; + dump_log_buffer (infile) ; + exit (1) ; + } ; + + sf_close (infile) ; + + sf_close (outfile) ; + + unlink (filename) ; +} /* update_header_sub */ + +static void +update_header_test (const char *filename, int typemajor) +{ + print_test_name ("update_header_test", filename) ; + + update_header_sub (filename, typemajor, SFM_WRITE) ; + update_header_sub (filename, typemajor, SFM_RDWR) ; + + unlink (filename) ; + puts ("ok") ; +} /* update_header_test */ + +static void +update_header_before_write_test (const char *filename, int typemajor) +{ + SNDFILE *outfile ; + SF_INFO sfinfo ; + int k ; + + print_test_name ("update_header_before_write", filename) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + sfinfo.samplerate = 44100 ; + sfinfo.format = (typemajor | SF_FORMAT_PCM_16) ; + sfinfo.channels = 1 ; + + outfile = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + + /* FLAC can only write the header once; if the first call to sf_write() will + ** also attempt to write the header, it fails. FLAC-specific regression + */ + sf_command (outfile, SFC_UPDATE_HEADER_NOW, NULL, 0) ; + + for (k = 0 ; k < BUFFER_LEN ; k++) + data_out [k] = k + 1 ; + test_write_int_or_die (outfile, 0, data_out, BUFFER_LEN, __LINE__) ; + + sf_close (outfile) ; + unlink (filename) ; + puts ("ok") ; +} /* update_header_before_write_test */ + +/*============================================================================== +*/ + +[+ FOR data_type ++]static void +update_seek_[+ (get "name") +]_test (const char *filename, int filetype) +{ SNDFILE *outfile, *infile ; + SF_INFO sfinfo ; + sf_count_t frames ; + [+ (get "name") +] buffer [8] ; + int k ; + + print_test_name ("update_seek_[+ (get "name") +]_test", filename) ; + + memset (buffer, 0, sizeof (buffer)) ; + + /* Create sound outfile with no data. */ + memset (&sfinfo, 0, sizeof (sfinfo)) ; + sfinfo.format = filetype | [+ (get "format") +] ; + sfinfo.samplerate = 48000 ; + sfinfo.channels = 2 ; + + if (sf_format_check (&sfinfo) == SF_FALSE) + sfinfo.channels = 1 ; + + outfile = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + sf_close (outfile) ; + + /* Open again for read/write. */ + outfile = test_open_file_or_die (filename, SFM_RDWR, &sfinfo, SF_TRUE, __LINE__) ; + + /* + ** In auto header update mode, seeking to the end of the file with + ** SEEK_SET will fail from the 2nd seek on. seeking to 0, SEEK_END + ** will seek to 0 anyway + */ + if (sf_command (outfile, SFC_SET_UPDATE_HEADER_AUTO, NULL, SF_TRUE) == 0) + { printf ("\n\nError : sf_command (SFC_SET_UPDATE_HEADER_AUTO) return error : %s\n\n", sf_strerror (outfile)) ; + exit (1) ; + } ; + + /* Now write some frames. */ + frames = ARRAY_LEN (buffer) / sfinfo.channels ; + + for (k = 0 ; k < 6 ; k++) + { test_seek_or_die (outfile, k * frames, SEEK_SET, k * frames, sfinfo.channels, __LINE__) ; + test_seek_or_die (outfile, 0, SEEK_END, k * frames, sfinfo.channels, __LINE__) ; + + /* Open file again and make sure no errors in log buffer. */ + infile = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + check_log_buffer_or_die (infile, __LINE__) ; + sf_close (infile) ; + + if (sfinfo.frames != k * frames) + { printf ("\n\nLine %d : Incorrect sample count (%" PRId64 " should be %" PRId64 ")\n", __LINE__, sfinfo.frames, k + frames) ; + dump_log_buffer (infile) ; + exit (1) ; + } ; + + if ((k & 1) == 0) + test_write_[+ (get "name") +]_or_die (outfile, k, buffer, sfinfo.channels * frames, __LINE__) ; + else + test_writef_[+ (get "name") +]_or_die (outfile, k, buffer, frames, __LINE__) ; + } ; + + sf_close (outfile) ; + unlink (filename) ; + + puts ("ok") ; + return ; +} /* update_seek_[+ (get "name") +]_test */ + +[+ ENDFOR data_type ++] + +static void +header_shrink_test (const char *filename, int filetype) +{ SNDFILE *outfile, *infile ; + SF_INFO sfinfo ; + sf_count_t frames ; + float buffer [8], bufferin [8] ; + + print_test_name ("header_shrink_test", filename) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + sfinfo.samplerate = 44100 ; + sfinfo.format = filetype | SF_FORMAT_FLOAT ; + sfinfo.channels = 1 ; + + memset (buffer, 0xA0, sizeof (buffer)) ; + + /* Now write some frames. */ + frames = ARRAY_LEN (buffer) / sfinfo.channels ; + + /* Test the file with extra header data. */ + outfile = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_FALSE, __LINE__) ; + + sf_command (outfile, SFC_SET_ADD_PEAK_CHUNK, NULL, SF_TRUE) ; + sf_command (outfile, SFC_UPDATE_HEADER_NOW, NULL, SF_FALSE) ; + sf_command (outfile, SFC_SET_ADD_PEAK_CHUNK, NULL, SF_FALSE) ; + + test_writef_float_or_die (outfile, 0, buffer, frames, __LINE__) ; + sf_close (outfile) ; + + /* Open again for read. */ + infile = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + + test_readf_float_or_die (infile, 0, bufferin, frames, __LINE__) ; + sf_close (infile) ; + + compare_float_or_die (buffer, bufferin, frames, __LINE__) ; + + unlink (filename) ; + puts ("ok") ; + return ; +} /* header_shrink_test */ + + +static void +extra_header_test (const char *filename, int filetype) +{ SNDFILE *outfile, *infile ; + SF_INFO sfinfo ; + sf_count_t frames ; + short buffer [8] ; + int k = 0 ; + + print_test_name ("extra_header_test", filename) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + sfinfo.samplerate = 44100 ; + sfinfo.format = (filetype | SF_FORMAT_PCM_16) ; + sfinfo.channels = 1 ; + + memset (buffer, 0xA0, sizeof (buffer)) ; + + /* Now write some frames. */ + frames = ARRAY_LEN (buffer) / sfinfo.channels ; + + /* Test the file with extra header data. */ + outfile = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, [+ (tpl-file-line "%2$d") +]) ; + sf_set_string (outfile, SF_STR_TITLE, filename) ; + test_writef_short_or_die (outfile, k, buffer, frames, [+ (tpl-file-line "%2$d") +]) ; + sf_set_string (outfile, SF_STR_COPYRIGHT, "(c) 1980 Erik") ; + sf_close (outfile) ; + +#if 1 + /* + ** Erik de Castro Lopo May 23 2004. + ** + ** This file has extra string data in the header and therefore cannot + ** currently be opened in SFM_RDWR mode. This is fixable, but its in + ** a part of the code I don't want to fiddle with until the Ogg/Vorbis + ** integration is done. + */ + + if ((infile = sf_open (filename, SFM_RDWR, &sfinfo)) != NULL) + { printf ("\n\nError : should not be able to open this file in SFM_RDWR.\n\n") ; + exit (1) ; + } ; + + unlink (filename) ; + puts ("ok") ; + return ; +#else + + hexdump_file (filename, 0, 100000) ; + + /* Open again for read/write. */ + outfile = test_open_file_or_die (filename, SFM_RDWR, &sfinfo, [+ (tpl-file-line "%2$d") +]) ; + + /* + ** In auto header update mode, seeking to the end of the file with + ** SEEK_SET will fail from the 2nd seek on. seeking to 0, SEEK_END + ** will seek to 0 anyway + */ + if (sf_command (outfile, SFC_SET_UPDATE_HEADER_AUTO, NULL, SF_TRUE) == 0) + { printf ("\n\nError : sf_command (SFC_SET_UPDATE_HEADER_AUTO) return error : %s\n\n", sf_strerror (outfile)) ; + exit (1) ; + } ; + + /* Now write some frames. */ + frames = ARRAY_LEN (buffer) / sfinfo.channels ; + + for (k = 1 ; k < 6 ; k++) + { + printf ("\n*** pass %d\n", k) ; + memset (buffer, 0xA0 + k, sizeof (buffer)) ; + + + test_seek_or_die (outfile, k * frames, SEEK_SET, k * frames, sfinfo.channels, [+ (tpl-file-line "%2$d") +]) ; + test_seek_or_die (outfile, 0, SEEK_END, k * frames, sfinfo.channels, [+ (tpl-file-line "%2$d") +]) ; + + /* Open file again and make sure no errors in log buffer. */ + if (0) + { infile = test_open_file_or_die (filename, SFM_READ, &sfinfo, [+ (tpl-file-line "%2$d") +]) ; + check_log_buffer_or_die (infile, [+ (tpl-file-line "%2$d") +]) ; + sf_close (infile) ; + } ; + + if (sfinfo.frames != k * frames) + { printf ("\n\nLine %d : Incorrect sample count (%" PRId64 " should be %" PRId64 ")\n", [+ (tpl-file-line "%2$d") +], sfinfo.frames, k + frames) ; + dump_log_buffer (infile) ; + exit (1) ; + } ; + + if ((k & 1) == 0) + test_write_short_or_die (outfile, k, buffer, sfinfo.channels * frames, [+ (tpl-file-line "%2$d") +]) ; + else + test_writef_short_or_die (outfile, k, buffer, frames, [+ (tpl-file-line "%2$d") +]) ; + hexdump_file (filename, 0, 100000) ; + } ; + + sf_close (outfile) ; + unlink (filename) ; + + puts ("ok") ; + return ; +#endif +} /* extra_header_test */ diff --git a/extern/libsndfile-modified/tests/headerless_test.c b/extern/libsndfile-modified/tests/headerless_test.c new file mode 100644 index 000000000..86aa6db9a --- /dev/null +++ b/extern/libsndfile-modified/tests/headerless_test.c @@ -0,0 +1,187 @@ +/* +** Copyright (C) 1999-2012 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include +#include + +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include + +#include "utils.h" + +#define BUFFER_SIZE (2000) + +static void old_test (void) ; +static void headerless_test (const char * filename, int format, int expected) ; + +int +main (void) +{ + old_test () ; + + headerless_test ("headerless.vox", SF_FORMAT_VOX_ADPCM, SF_FORMAT_RAW | SF_FORMAT_VOX_ADPCM) ; + headerless_test ("headerless.gsm", SF_FORMAT_GSM610, SF_FORMAT_RAW | SF_FORMAT_GSM610) ; + + headerless_test ("headerless.snd", SF_FORMAT_ULAW, SF_FORMAT_RAW | SF_FORMAT_ULAW) ; + headerless_test ("headerless.au" , SF_FORMAT_ULAW, SF_FORMAT_RAW | SF_FORMAT_ULAW) ; + + return 0 ; +} /* main */ + +static void +headerless_test (const char * filename, int format, int expected) +{ static short buffer [BUFFER_SIZE] ; + SNDFILE *file ; + SF_INFO sfinfo ; + int k ; + + format &= SF_FORMAT_SUBMASK ; + + print_test_name (__func__, filename) ; + + for (k = 0 ; k < BUFFER_SIZE ; k++) + buffer [k] = k ; + + sfinfo.samplerate = 8000 ; + sfinfo.frames = 0 ; + sfinfo.channels = 1 ; + sfinfo.format = SF_FORMAT_RAW | format ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + + if ((k = (int) sf_write_short (file, buffer, BUFFER_SIZE)) != BUFFER_SIZE) + { printf ("Line %d: sf_write_short failed with short write (%d => %d).\n", __LINE__, BUFFER_SIZE, k) ; + fflush (stdout) ; + puts (sf_strerror (file)) ; + exit (1) ; + } ; + + sf_close (file) ; + + memset (buffer, 0, sizeof (buffer)) ; + + /* We should be able to detect these so clear sfinfo. */ + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + + if (sfinfo.format != expected) + { printf ("Line %d: Returned format incorrect (0x%08X => 0x%08X).\n", __LINE__, expected, sfinfo.format) ; + exit (1) ; + } ; + + if (sfinfo.frames < BUFFER_SIZE) + { printf ("Line %d: Incorrect number of.frames in file. (%d => %" PRId64 ")\n", __LINE__, BUFFER_SIZE, sfinfo.frames) ; + exit (1) ; + } ; + + if (sfinfo.channels != 1) + { printf ("Line %d: Incorrect number of channels in file.\n", __LINE__) ; + exit (1) ; + } ; + + check_log_buffer_or_die (file, __LINE__) ; + + sf_close (file) ; + + printf ("ok\n") ; + unlink (filename) ; +} /* headerless_test */ + +static void +old_test (void) +{ static short buffer [BUFFER_SIZE] ; + SNDFILE *file ; + SF_INFO sfinfo ; + int k, filetype ; + const char *filename = "headerless.wav" ; + + print_test_name (__func__, "") ; + + for (k = 0 ; k < BUFFER_SIZE ; k++) + buffer [k] = k ; + + filetype = SF_FORMAT_WAV | SF_FORMAT_PCM_16 ; + + sfinfo.samplerate = 32000 ; + sfinfo.frames = 123456789 ; /* Wrong length. Library should correct this on sf_close. */ + sfinfo.channels = 1 ; + sfinfo.format = filetype ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + + if ((k = (int) sf_write_short (file, buffer, BUFFER_SIZE)) != BUFFER_SIZE) + { printf ("Line %d: sf_write_short failed with short write (%d => %d).\n", __LINE__, BUFFER_SIZE, k) ; + fflush (stdout) ; + puts (sf_strerror (file)) ; + exit (1) ; + } ; + + sf_close (file) ; + + memset (buffer, 0, sizeof (buffer)) ; + + /* Read as RAW but get the bit width and endian-ness correct. */ + sfinfo.format = filetype = SF_ENDIAN_LITTLE | SF_FORMAT_RAW | SF_FORMAT_PCM_16 ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + + if (sfinfo.format != filetype) + { printf ("Line %d: Returned format incorrect (0x%08X => 0x%08X).\n", __LINE__, filetype, sfinfo.format) ; + exit (1) ; + } ; + + if (sfinfo.frames < BUFFER_SIZE) + { printf ("Line %d: Incorrect number of.frames in file. (%d => %" PRId64 ")\n", __LINE__, BUFFER_SIZE, sfinfo.frames) ; + exit (1) ; + } ; + + if (sfinfo.channels != 1) + { printf ("Line %d: Incorrect number of channels in file.\n", __LINE__) ; + exit (1) ; + } ; + + check_log_buffer_or_die (file, __LINE__) ; + + if ((k = (int) sf_read_short (file, buffer, BUFFER_SIZE)) != BUFFER_SIZE) + { printf ("Line %d: short read (%d).\n", __LINE__, k) ; + exit (1) ; + } ; + + for (k = 0 ; k < BUFFER_SIZE - 22 ; k++) + if (buffer [k + 22] != k) + { printf ("Line %d: Incorrect sample (#%d : 0x%x => 0x%x).\n", __LINE__, k, k, buffer [k]) ; + exit (1) ; + } ; + + sf_close (file) ; + + printf ("ok\n") ; + unlink (filename) ; +} /* old_test */ + diff --git a/extern/libsndfile-modified/tests/largefile_test.c b/extern/libsndfile-modified/tests/largefile_test.c new file mode 100644 index 000000000..4c97c90b2 --- /dev/null +++ b/extern/libsndfile-modified/tests/largefile_test.c @@ -0,0 +1,85 @@ +/* +** Copyright (C) 2006-2011 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include + +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include + +#include "utils.h" + +#define BUFFER_LEN (1024 * 1024) +#define BUFFER_COUNT (768) + +static void largefile_test (int filetype, const char * filename) ; + +int +main (void) +{ + largefile_test (SF_FORMAT_WAV, "largefile.wav") ; + largefile_test (SF_FORMAT_AIFF, "largefile.aiff") ; + + return 0 ; +} /* main */ + +static void +largefile_test (int filetype, const char * filename) +{ static float data [BUFFER_LEN] ; + SNDFILE *file ; + SF_INFO sfinfo ; + int k ; + + print_test_name ("largefile_test", filename) ; + + sfinfo.samplerate = 44100 ; + sfinfo.channels = 2 ; + sfinfo.frames = 0 ; + sfinfo.format = (filetype | SF_FORMAT_PCM_32) ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + + for (k = 0 ; k < BUFFER_COUNT ; k++) + test_write_float_or_die (file, k, data, BUFFER_LEN, __LINE__) ; + + sf_close (file) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + + if ((sfinfo.frames * sfinfo.channels) / BUFFER_LEN != BUFFER_COUNT) + { printf ("\n\nLine %d : bad frame count.\n", __LINE__) ; + exit (1) ; + } ; + + sf_close (file) ; + + unlink (filename) ; + puts ("ok") ; + + + return ; +} /* largefile_test */ + diff --git a/extern/libsndfile-modified/tests/locale_test.c b/extern/libsndfile-modified/tests/locale_test.c new file mode 100644 index 000000000..932c72efb --- /dev/null +++ b/extern/libsndfile-modified/tests/locale_test.c @@ -0,0 +1,168 @@ +/* +** Copyright (C) 2005-2011 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include + +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#if HAVE_LOCALE_H +#include +#endif + +#if OS_IS_WIN32 +#include +#endif + +#include "sndfile.h" +#include "utils.h" + +static void utf8_test (void) ; +static void wchar_test (void) ; + +int +main (void) +{ + utf8_test () ; + wchar_test () ; + + return 0 ; +} /* main */ + +/*============================================================================== +*/ + +static void +wchar_test (void) +{ +#if OS_IS_WIN32 + SNDFILE * file ; + SF_INFO info ; + LPCWSTR filename = L"test.wav" ; + + print_test_name (__func__, "test.wav") ; + + info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 ; + info.channels = 1 ; + info.samplerate = 44100 ; + + file = sf_wchar_open (filename, SFM_WRITE, &info) ; + exit_if_true (file == NULL, "\n\nLine %d : sf_wchar_open failed : %s\n\n", __LINE__, sf_strerror (NULL)) ; + sf_close (file) ; + + /* This should check that the file did in fact get created with a + ** wchar_t * filename. + */ + exit_if_true ( + GetFileAttributesW (filename) == INVALID_FILE_ATTRIBUTES, + "\n\nLine %d : GetFileAttributes failed.\n\n", __LINE__ + ) ; + + /* Use this because the file was created with CreateFileW. */ + DeleteFileW (filename) ; + + puts ("ok") ; +#endif +} /* wchar_test */ + +/*============================================================================== +*/ + +typedef struct +{ const char *locale ; + int utf8 ; + const char *filename ; + int width ; +} LOCALE_DATA ; + +static void locale_test (const LOCALE_DATA * locdata) ; + +static void +utf8_test (void) +{ LOCALE_DATA ldata [] = + { { "de_DE", 1, "F\303\274\303\237e.au", 7 }, + { "en_AU", 1, "kangaroo.au", 11 }, + { "POSIX", 0, "posix.au", 8 }, + { "pt_PT", 1, "concei\303\247\303\243o.au", 12 }, + +#if OS_IS_WIN32 == 0 + { "ja_JP", 1, "\343\201\212\343\201\257\343\202\210\343\201\206\343\201\224\343\201\226\343\201\204\343\201\276\343\201\231.au", 21 }, +#endif + + { "vi_VN", 1, "qu\341\273\221c ng\341\273\257.au", 11 }, + { NULL, 0, NULL, 0 } + } ; + int k ; + + for (k = 0 ; ldata [k].locale != NULL ; k++) + locale_test (ldata + k) ; +} /* utf8_test */ + + +static void +locale_test (const LOCALE_DATA * ldata) +{ +#if (HAVE_LOCALE_H == 0 || HAVE_SETLOCALE == 0) + locname = filename = NULL ; + width = 0 ; + return ; +#else + const short wdata [] = { 1, 2, 3, 4, 5, 6, 7, 8 } ; + short rdata [ARRAY_LEN (wdata)] ; + const char *old_locale ; + char utf8_locname [32] ; + SNDFILE *file ; + SF_INFO sfinfo ; + + snprintf (utf8_locname, sizeof (utf8_locname), "%s%s", ldata->locale, ldata->utf8 ? ".UTF-8" : "") ; + + /* Change the locale saving the old one. */ + if ((old_locale = setlocale (LC_CTYPE, utf8_locname)) == NULL) + return ; + + printf (" locale_test %-8s : %s %*c ", ldata->locale, ldata->filename, 24 - ldata->width, ' ') ; + fflush (stdout) ; + + sfinfo.format = SF_FORMAT_AU | SF_FORMAT_PCM_16 ; + sfinfo.channels = 1 ; + sfinfo.samplerate = 44100 ; + + file = test_open_file_or_die (ldata->filename, SFM_WRITE, &sfinfo, 0, __LINE__) ; + test_write_short_or_die (file, 0, wdata, ARRAY_LEN (wdata), __LINE__) ; + sf_close (file) ; + + file = test_open_file_or_die (ldata->filename, SFM_READ, &sfinfo, 0, __LINE__) ; + test_read_short_or_die (file, 0, rdata, ARRAY_LEN (rdata), __LINE__) ; + sf_close (file) ; + + unlink (ldata->filename) ; + + /* Restore old locale. */ + setlocale (LC_CTYPE, old_locale) ; + + puts ("ok") ; +#endif +} /* locale_test */ + diff --git a/extern/libsndfile-modified/tests/long_read_write_test.c b/extern/libsndfile-modified/tests/long_read_write_test.c new file mode 100644 index 000000000..0629caef1 --- /dev/null +++ b/extern/libsndfile-modified/tests/long_read_write_test.c @@ -0,0 +1,272 @@ +/* +** Copyright (C) 2015-2016 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include +#include + +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include + +#include "dft_cmp.h" +#include "utils.h" + +#define BUFFER_LENGTH 10000 +#define SAMPLE_RATE 44010 + +static void short_lrw_test (const char *filename, int filetype, const short * output, int out_len) ; +static void int_lrw_test (const char *filename, int filetype, const int * output, int out_len) ; +static void float_lrw_test (const char *filename, int filetype, const float * output, int out_len) ; +static void double_lrw_test (const char *filename, int filetype, const double * output, int out_len) ; + + +static short short_data [BUFFER_LENGTH] ; +static int int_data [BUFFER_LENGTH] ; +static float float_data [BUFFER_LENGTH] ; +static double double_data [BUFFER_LENGTH] ; + +int +main (int argc, char *argv []) +{ int do_all ; + size_t k ; + + if (argc != 2) + { printf ("Usage : %s \n", argv [0]) ; + printf (" Where is one of the following:\n") ; + printf (" alac - test CAF/ALAC file functions\n") ; + printf (" all - perform all tests\n") ; + exit (1) ; + } ; + + for (k = 0 ; k < ARRAY_LEN (short_data) ; k++) + { int value = k / 32 ; + int_data [k] = (value & 1 ? -1 : 1) * value ; + short_data [k] = int_data [k] ; + float_data [k] = int_data [k] / 32000.0f ; + double_data [k] = int_data [k] / 32000.0 ; + } + + do_all = ! strcmp (argv [1], "all") ; + + if (do_all || strcmp (argv [1], "alac") == 0) + { short_lrw_test ("alac.caf", SF_FORMAT_CAF | SF_FORMAT_ALAC_16, short_data, ARRAY_LEN (short_data)) ; + int_lrw_test ("alac.caf", SF_FORMAT_CAF | SF_FORMAT_ALAC_32, int_data, ARRAY_LEN (int_data)) ; + float_lrw_test ("alac.caf", SF_FORMAT_CAF | SF_FORMAT_ALAC_32, float_data, ARRAY_LEN (float_data)) ; + double_lrw_test ("alac.caf", SF_FORMAT_CAF | SF_FORMAT_ALAC_32, double_data, ARRAY_LEN (double_data)) ; + } ; + + return 0 ; +} /* main */ + +/*============================================================================================ + * Here are the test functions. + */ + +static void +short_lrw_test (const char *filename, int filetype, const short * output, int out_len) +{ SNDFILE *file ; + SF_INFO sfinfo ; + int k ; + short input [BUFFER_LENGTH] ; + + print_test_name ("short_lrw_test", filename) ; + + exit_if_true (BUFFER_LENGTH > out_len, "\n\nLine %d: Bad array length.\n", __LINE__) ; + + sfinfo.samplerate = SAMPLE_RATE ; + sfinfo.frames = out_len ; + sfinfo.channels = 1 ; + sfinfo.format = filetype ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + + test_write_short_or_die (file, 0, output, out_len, __LINE__) ; + + sf_close (file) ; + + memset (input, 0, sizeof (input)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + + exit_if_true (sfinfo.format != filetype, "\n\nLine %d: Returned format incorrect (0x%08X => 0x%08X).\n", __LINE__, filetype, sfinfo.format) ; + exit_if_true (sfinfo.frames < out_len, "\n\nLine %d: Incorrect number of frames in file (too short). (%" PRId64 " should be %d)\n", __LINE__, sfinfo.frames, DFT_DATA_LENGTH) ; + exit_if_true (sfinfo.channels != 1, "\n\nLine %d: Incorrect number of channels in file.\n", __LINE__) ; + + check_log_buffer_or_die (file, __LINE__) ; + + test_read_short_or_die (file, 0, input, out_len, __LINE__) ; + + sf_close (file) ; + + for (k = 0 ; k < out_len ; k++) + exit_if_true (input [k] != output [k], + "\n\nLine: %d: Error on input %d, expected %d, got %d\n", __LINE__, k, output [k], input [k]) ; + + puts ("ok") ; + unlink (filename) ; + + return ; +} /* short_lrw_test */ + +static void +int_lrw_test (const char *filename, int filetype, const int * output, int out_len) +{ SNDFILE *file ; + SF_INFO sfinfo ; + int k ; + int input [BUFFER_LENGTH] ; + + print_test_name ("int_lrw_test", filename) ; + + exit_if_true (BUFFER_LENGTH > out_len, "\n\nLine %d: Bad array length.\n", __LINE__) ; + + sfinfo.samplerate = SAMPLE_RATE ; + sfinfo.frames = out_len ; + sfinfo.channels = 1 ; + sfinfo.format = filetype ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + + test_write_int_or_die (file, 0, output, out_len, __LINE__) ; + + sf_close (file) ; + + memset (input, 0, sizeof (input)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + + exit_if_true (sfinfo.format != filetype, "\n\nLine %d: Returned format incorrect (0x%08X => 0x%08X).\n", __LINE__, filetype, sfinfo.format) ; + exit_if_true (sfinfo.frames < out_len, "\n\nLine %d: Incorrect number of frames in file (too int). (%" PRId64 " should be %d)\n", __LINE__, sfinfo.frames, DFT_DATA_LENGTH) ; + exit_if_true (sfinfo.channels != 1, "\n\nLine %d: Incorrect number of channels in file.\n", __LINE__) ; + + check_log_buffer_or_die (file, __LINE__) ; + + test_read_int_or_die (file, 0, input, out_len, __LINE__) ; + + sf_close (file) ; + + for (k = 0 ; k < out_len ; k++) + exit_if_true (input [k] != output [k], + "\n\nLine: %d: Error on input %d, expected %d, got %d\n", __LINE__, k, output [k], input [k]) ; + + puts ("ok") ; + unlink (filename) ; + + return ; +} /* int_lrw_test */ + +static void +float_lrw_test (const char *filename, int filetype, const float * output, int out_len) +{ SNDFILE *file ; + SF_INFO sfinfo ; + int k ; + float input [BUFFER_LENGTH] ; + + print_test_name ("float_lrw_test", filename) ; + + exit_if_true (BUFFER_LENGTH > out_len, "\n\nLine %d: Bad array length.\n", __LINE__) ; + + sfinfo.samplerate = SAMPLE_RATE ; + sfinfo.frames = out_len ; + sfinfo.channels = 1 ; + sfinfo.format = filetype ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + + test_write_float_or_die (file, 0, output, out_len, __LINE__) ; + + sf_close (file) ; + + memset (input, 0, sizeof (input)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + + exit_if_true (sfinfo.format != filetype, "\n\nLine %d: Returned format incorrect (0x%08X => 0x%08X).\n", __LINE__, filetype, sfinfo.format) ; + exit_if_true (sfinfo.frames < out_len, "\n\nLine %d: Incorrect number of frames in file (too float). (%" PRId64 " should be %d)\n", __LINE__, sfinfo.frames, DFT_DATA_LENGTH) ; + exit_if_true (sfinfo.channels != 1, "\n\nLine %d: Incorrect number of channels in file.\n", __LINE__) ; + + check_log_buffer_or_die (file, __LINE__) ; + + test_read_float_or_die (file, 0, input, out_len, __LINE__) ; + + sf_close (file) ; + + for (k = 0 ; k < out_len ; k++) + exit_if_true (fabs (input [k] - output [k]) > 0.00001, + "\n\nLine: %d: Error on input %d, expected %f, got %f\n", __LINE__, k, output [k], input [k]) ; + + puts ("ok") ; + unlink (filename) ; + + return ; +} /* float_lrw_test */ + +static void +double_lrw_test (const char *filename, int filetype, const double * output, int out_len) +{ SNDFILE *file ; + SF_INFO sfinfo ; + int k ; + double input [BUFFER_LENGTH] ; + + print_test_name ("double_lrw_test", filename) ; + + exit_if_true (BUFFER_LENGTH > out_len, "\n\nLine %d: Bad array length.\n", __LINE__) ; + + sfinfo.samplerate = SAMPLE_RATE ; + sfinfo.frames = out_len ; + sfinfo.channels = 1 ; + sfinfo.format = filetype ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + + test_write_double_or_die (file, 0, output, out_len, __LINE__) ; + + sf_close (file) ; + + memset (input, 0, sizeof (input)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + + exit_if_true (sfinfo.format != filetype, "\n\nLine %d: Returned format incorrect (0x%08X => 0x%08X).\n", __LINE__, filetype, sfinfo.format) ; + exit_if_true (sfinfo.frames < out_len, "\n\nLine %d: Incorrect number of frames in file (too double). (%" PRId64 " should be %d)\n", __LINE__, sfinfo.frames, DFT_DATA_LENGTH) ; + exit_if_true (sfinfo.channels != 1, "\n\nLine %d: Incorrect number of channels in file.\n", __LINE__) ; + + check_log_buffer_or_die (file, __LINE__) ; + + test_read_double_or_die (file, 0, input, out_len, __LINE__) ; + + sf_close (file) ; + + for (k = 0 ; k < out_len ; k++) + exit_if_true (fabs (input [k] - output [k]) > 0.00001, + "\n\nLine: %d: Error on input %d, expected %f, got %f\n", __LINE__, k, output [k], input [k]) ; + + puts ("ok") ; + unlink (filename) ; + + return ; +} /* double_lrw_test */ + diff --git a/extern/libsndfile-modified/tests/lossy_comp_test.c b/extern/libsndfile-modified/tests/lossy_comp_test.c new file mode 100644 index 000000000..928032135 --- /dev/null +++ b/extern/libsndfile-modified/tests/lossy_comp_test.c @@ -0,0 +1,2634 @@ +/* +** Copyright (C) 1999-2016 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include +#include + + +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include + +#include "utils.h" + +#define BUFFER_SIZE (1 << 14) +#define SAMPLE_RATE 11025 + +#ifndef M_PI +#define M_PI 3.14159265358979323846264338 +#endif + +#define LCT_MAX(x, y) ((x) > (y) ? (x) : (y)) + +static const char LCT_TEST_PREFIX[] = "lct" ; + +static void lcomp_test_short (const char *filename, int filetype, int chan, double margin) ; +static void lcomp_test_int (const char *filename, int filetype, int chan, double margin) ; +static void lcomp_test_float (const char *filename, int filetype, int chan, double margin) ; +static void lcomp_test_double (const char *filename, int filetype, int chan, double margin) ; + +static void sdlcomp_test_short (const char *filename, int filetype, int chan, double margin) ; +static void sdlcomp_test_int (const char *filename, int filetype, int chan, double margin) ; +static void sdlcomp_test_float (const char *filename, int filetype, int chan, double margin) ; +static void sdlcomp_test_double (const char *filename, int filetype, int chan, double margin) ; + +static void read_raw_test (const char *filename, int filetype, int chan) ; + +static int error_function (double data, double orig, double margin) ; +static int decay_response (int k) ; + +static void gen_signal_double (double *data, double scale, int channels, int datalen) ; + +static void smoothed_diff_short (short *data, unsigned int datalen) ; +static void smoothed_diff_int (int *data, unsigned int datalen) ; +static void smoothed_diff_float (float *data, unsigned int datalen) ; +static void smoothed_diff_double (double *data, unsigned int datalen) ; + +static void check_comment (SNDFILE * file, int format, int lineno) ; + +static int is_lossy (int filetype) ; + +static int check_opus_version (SNDFILE *file) ; + +/* +** Force the start of these buffers to be double aligned. Sparc-solaris will +** choke if they are not. +*/ +typedef union +{ double d [BUFFER_SIZE + 1] ; + float f [BUFFER_SIZE + 1] ; + int i [BUFFER_SIZE + 1] ; + short s [BUFFER_SIZE + 1] ; + char c [BUFFER_SIZE + 1] ; +} BUFFER ; + +static BUFFER data_buffer ; +static BUFFER orig_buffer ; +static BUFFER smooth_buffer ; + +static const char *long_comment = + "This is really quite a long comment. It is designed to be long enough " + "to screw up the encoders and decoders if the file container format does " + "not handle things correctly. If everything is working correctly, the " + "decoder will only decode the actual audio data, and not this string at " + "the end of the file." ; + +int +main (int argc, char *argv []) +{ int do_all = 0 ; + int test_count = 0 ; + + if (argc != 2) + { printf ("Usage : %s \n", argv [0]) ; + printf (" Where is one of the following:\n") ; + printf (" wav_ima - test IMA ADPCM WAV file functions\n") ; + printf (" wav_msadpcm - test MS ADPCM WAV file functions\n") ; + printf (" wav_gsm610 - test GSM 6.10 WAV file functions\n") ; + printf (" wav_ulaw - test u-law WAV file functions\n") ; + printf (" wav_alaw - test A-law WAV file functions\n") ; + printf (" wve - test Psion WVE file functions\n") ; + printf (" all - perform all tests\n") ; + exit (1) ; + } ; + + do_all = ! strcmp (argv [1], "all") ; + + if (do_all || strcmp (argv [1], "wav_pcm") == 0) + { /* This is just a sanity test for PCM encoding. */ + lcomp_test_short ("pcm.wav", SF_FORMAT_WAV | SF_FORMAT_PCM_16, 2, 1e-50) ; + lcomp_test_int ("pcm.wav", SF_FORMAT_WAV | SF_FORMAT_PCM_32, 2, 1e-50) ; + lcomp_test_short ("pcm.rifx", SF_ENDIAN_BIG | SF_FORMAT_WAV | SF_FORMAT_PCM_16, 2, 1e-50) ; + lcomp_test_int ("pcm.rifx", SF_ENDIAN_BIG | SF_FORMAT_WAV | SF_FORMAT_PCM_32, 2, 1e-50) ; + /* Lite remove start */ + lcomp_test_float ("pcm.wav", SF_FORMAT_WAV | SF_FORMAT_FLOAT, 2, 1e-50) ; + lcomp_test_double ("pcm.wav", SF_FORMAT_WAV | SF_FORMAT_DOUBLE, 2, 1e-50) ; + /* Lite remove end */ + + read_raw_test ("pcm.wav", SF_FORMAT_WAV | SF_FORMAT_PCM_U8, 2) ; + test_count++ ; + } ; + + /* For all the rest, if the file format supports more than 1 channel, use stereo. */ + /* Lite remove start */ + if (do_all || strcmp (argv [1], "wav_ima") == 0) + { lcomp_test_short ("ima.wav", SF_FORMAT_WAV | SF_FORMAT_IMA_ADPCM, 2, 0.18) ; + lcomp_test_int ("ima.wav", SF_FORMAT_WAV | SF_FORMAT_IMA_ADPCM, 2, 0.65) ; + lcomp_test_float ("ima.wav", SF_FORMAT_WAV | SF_FORMAT_IMA_ADPCM, 2, 0.18) ; + lcomp_test_double ("ima.wav", SF_FORMAT_WAV | SF_FORMAT_IMA_ADPCM, 2, 0.18) ; + + lcomp_test_short ("ima.rifx", SF_ENDIAN_BIG | SF_FORMAT_WAV | SF_FORMAT_IMA_ADPCM, 2, 0.18) ; + lcomp_test_int ("ima.rifx", SF_ENDIAN_BIG | SF_FORMAT_WAV | SF_FORMAT_IMA_ADPCM, 2, 0.18) ; + lcomp_test_float ("ima.rifx", SF_ENDIAN_BIG | SF_FORMAT_WAV | SF_FORMAT_IMA_ADPCM, 2, 0.18) ; + lcomp_test_double ("ima.rifx", SF_ENDIAN_BIG | SF_FORMAT_WAV | SF_FORMAT_IMA_ADPCM, 2, 0.18) ; + + sdlcomp_test_short ("ima.wav", SF_FORMAT_WAV | SF_FORMAT_IMA_ADPCM, 2, 0.18) ; + sdlcomp_test_int ("ima.wav", SF_FORMAT_WAV | SF_FORMAT_IMA_ADPCM, 2, 0.18) ; + sdlcomp_test_float ("ima.wav", SF_FORMAT_WAV | SF_FORMAT_IMA_ADPCM, 2, 0.18) ; + sdlcomp_test_double ("ima.wav", SF_FORMAT_WAV | SF_FORMAT_IMA_ADPCM, 2, 0.18) ; + test_count++ ; + } ; + + if (do_all || strcmp (argv [1], "wav_msadpcm") == 0) + { lcomp_test_short ("msadpcm.wav", SF_FORMAT_WAV | SF_FORMAT_MS_ADPCM, 2, 0.36) ; + lcomp_test_int ("msadpcm.wav", SF_FORMAT_WAV | SF_FORMAT_MS_ADPCM, 2, 0.36) ; + lcomp_test_float ("msadpcm.wav", SF_FORMAT_WAV | SF_FORMAT_MS_ADPCM, 2, 0.36) ; + lcomp_test_double ("msadpcm.wav", SF_FORMAT_WAV | SF_FORMAT_MS_ADPCM, 2, 0.36) ; + + lcomp_test_short ("msadpcm.rifx", SF_ENDIAN_BIG | SF_FORMAT_WAV | SF_FORMAT_MS_ADPCM, 2, 0.36) ; + lcomp_test_int ("msadpcm.rifx", SF_ENDIAN_BIG | SF_FORMAT_WAV | SF_FORMAT_MS_ADPCM, 2, 0.36) ; + lcomp_test_float ("msadpcm.rifx", SF_ENDIAN_BIG | SF_FORMAT_WAV | SF_FORMAT_MS_ADPCM, 2, 0.36) ; + lcomp_test_double ("msadpcm.rifx", SF_ENDIAN_BIG | SF_FORMAT_WAV | SF_FORMAT_MS_ADPCM, 2, 0.36) ; + + sdlcomp_test_short ("msadpcm.wav", SF_FORMAT_WAV | SF_FORMAT_MS_ADPCM, 2, 0.36) ; + sdlcomp_test_int ("msadpcm.wav", SF_FORMAT_WAV | SF_FORMAT_MS_ADPCM, 2, 0.36) ; + sdlcomp_test_float ("msadpcm.wav", SF_FORMAT_WAV | SF_FORMAT_MS_ADPCM, 2, 0.36) ; + sdlcomp_test_double ("msadpcm.wav", SF_FORMAT_WAV | SF_FORMAT_MS_ADPCM, 2, 0.36) ; + + test_count++ ; + } ; + + if (do_all || strcmp (argv [1], "wav_g721") == 0) + { printf ("**** Fix this later : error bound should be 0.06 ****\n") ; + lcomp_test_short ("g721.wav", SF_FORMAT_WAV | SF_FORMAT_G721_32, 1, 0.7) ; + lcomp_test_int ("g721.wav", SF_FORMAT_WAV | SF_FORMAT_G721_32, 1, 0.7) ; + + lcomp_test_short ("g721.rifx", SF_ENDIAN_BIG | SF_FORMAT_WAV | SF_FORMAT_G721_32, 1, 0.7) ; + lcomp_test_int ("g721.rifx", SF_ENDIAN_BIG | SF_FORMAT_WAV | SF_FORMAT_G721_32, 1, 0.7) ; + + test_count++ ; + } ; + /* Lite remove end */ + + if (do_all || strcmp (argv [1], "wav_ulaw") == 0) + { lcomp_test_short ("ulaw.wav", SF_FORMAT_WAV | SF_FORMAT_ULAW, 2, 0.04) ; + lcomp_test_int ("ulaw.wav", SF_FORMAT_WAV | SF_FORMAT_ULAW, 2, 0.04) ; + + lcomp_test_short ("ulaw.rifx", SF_ENDIAN_BIG | SF_FORMAT_WAV | SF_FORMAT_ULAW, 2, 0.04) ; + lcomp_test_int ("ulaw.rifx", SF_ENDIAN_BIG | SF_FORMAT_WAV | SF_FORMAT_ULAW, 2, 0.04) ; + + /* Lite remove start */ + lcomp_test_float ("ulaw.wav", SF_FORMAT_WAV | SF_FORMAT_ULAW, 2, 0.04) ; + lcomp_test_double ("ulaw.wav", SF_FORMAT_WAV | SF_FORMAT_ULAW, 2, 0.04) ; + /* Lite remove end */ + + read_raw_test ("ulaw.wav", SF_FORMAT_WAV | SF_FORMAT_ULAW, 2) ; + test_count++ ; + } ; + + if (do_all || strcmp (argv [1], "wav_alaw") == 0) + { lcomp_test_short ("alaw.wav", SF_FORMAT_WAV | SF_FORMAT_ALAW, 2, 0.04) ; + lcomp_test_int ("alaw.wav", SF_FORMAT_WAV | SF_FORMAT_ALAW, 2, 0.04) ; + /* Lite remove start */ + lcomp_test_float ("alaw.wav", SF_FORMAT_WAV | SF_FORMAT_ALAW, 2, 0.04) ; + lcomp_test_double ("alaw.wav", SF_FORMAT_WAV | SF_FORMAT_ALAW, 2, 0.04) ; + /* Lite remove end */ + + read_raw_test ("alaw.wav", SF_FORMAT_WAV | SF_FORMAT_ALAW, 2) ; + test_count++ ; + } ; + + if (do_all || strcmp (argv [1], "wav_gsm610") == 0) + { /* Don't do lcomp_test_XXX as the errors are too big. */ + sdlcomp_test_short ("gsm610.wav", SF_FORMAT_WAV | SF_FORMAT_GSM610, 1, 0.24) ; + sdlcomp_test_int ("gsm610.wav", SF_FORMAT_WAV | SF_FORMAT_GSM610, 1, 0.24) ; + + sdlcomp_test_short ("gsm610.rifx", SF_ENDIAN_BIG | SF_FORMAT_WAV | SF_FORMAT_GSM610, 1, 0.24) ; + sdlcomp_test_int ("gsm610.rifx", SF_ENDIAN_BIG | SF_FORMAT_WAV | SF_FORMAT_GSM610, 1, 0.24) ; + + /* Lite remove start */ + sdlcomp_test_float ("gsm610.wav", SF_FORMAT_WAV | SF_FORMAT_GSM610, 1, 0.24) ; + sdlcomp_test_double ("gsm610.wav", SF_FORMAT_WAV | SF_FORMAT_GSM610, 1, 0.24) ; + /* Lite remove end */ + test_count++ ; + } ; + + /* Lite remove start */ + if (do_all || strcmp (argv [1], "wav_nmsadpcm") == 0) + { lcomp_test_short ("nms_16.wav", SF_FORMAT_WAV | SF_FORMAT_NMS_ADPCM_16, 1, 0.37) ; + lcomp_test_int ("nms_16.wav", SF_FORMAT_WAV | SF_FORMAT_NMS_ADPCM_16, 1, 0.31) ; + lcomp_test_float ("nms_16.wav", SF_FORMAT_WAV | SF_FORMAT_NMS_ADPCM_16, 1, 0.34) ; + lcomp_test_double ("nms_16.wav", SF_FORMAT_WAV | SF_FORMAT_NMS_ADPCM_16, 1, 0.34) ; + + lcomp_test_short ("nms_24.wav", SF_FORMAT_WAV | SF_FORMAT_NMS_ADPCM_24, 1, 0.15) ; + lcomp_test_int ("nms_24.wav", SF_FORMAT_WAV | SF_FORMAT_NMS_ADPCM_24, 1, 0.10) ; + lcomp_test_float ("nms_24.wav", SF_FORMAT_WAV | SF_FORMAT_NMS_ADPCM_24, 1, 0.14) ; + lcomp_test_double ("nms_24.wav", SF_FORMAT_WAV | SF_FORMAT_NMS_ADPCM_24, 1, 0.14) ; + + lcomp_test_short ("nms_32.wav", SF_FORMAT_WAV | SF_FORMAT_NMS_ADPCM_32, 1, 0.036) ; + lcomp_test_int ("nms_32.wav", SF_FORMAT_WAV | SF_FORMAT_NMS_ADPCM_32, 1, 0.045) ; + lcomp_test_float ("nms_32.wav", SF_FORMAT_WAV | SF_FORMAT_NMS_ADPCM_32, 1, 0.035) ; + lcomp_test_double ("nms_32.wav", SF_FORMAT_WAV | SF_FORMAT_NMS_ADPCM_32, 1, 0.035) ; + + sdlcomp_test_short ("nms_16.wav", SF_FORMAT_WAV | SF_FORMAT_NMS_ADPCM_16, 1, 0.16) ; + sdlcomp_test_int ("nms_16.wav", SF_FORMAT_WAV | SF_FORMAT_NMS_ADPCM_16, 1, 0.16) ; + sdlcomp_test_float ("nms_16.wav", SF_FORMAT_WAV | SF_FORMAT_NMS_ADPCM_16, 1, 0.16) ; + sdlcomp_test_double ("nms_16.wav", SF_FORMAT_WAV | SF_FORMAT_NMS_ADPCM_16, 1, 0.16) ; + + sdlcomp_test_short ("nms_24.wav", SF_FORMAT_WAV | SF_FORMAT_NMS_ADPCM_24, 1, 0.06) ; + sdlcomp_test_int ("nms_24.wav", SF_FORMAT_WAV | SF_FORMAT_NMS_ADPCM_24, 1, 0.06) ; + sdlcomp_test_float ("nms_24.wav", SF_FORMAT_WAV | SF_FORMAT_NMS_ADPCM_24, 1, 0.06) ; + sdlcomp_test_double ("nms_24.wav", SF_FORMAT_WAV | SF_FORMAT_NMS_ADPCM_24, 1, 0.06) ; + + sdlcomp_test_short ("nms_32.wav", SF_FORMAT_WAV | SF_FORMAT_NMS_ADPCM_32, 1, 0.017) ; + sdlcomp_test_int ("nms_32.wav", SF_FORMAT_WAV | SF_FORMAT_NMS_ADPCM_32, 1, 0.018) ; + sdlcomp_test_float ("nms_32.wav", SF_FORMAT_WAV | SF_FORMAT_NMS_ADPCM_32, 1, 0.018) ; + sdlcomp_test_double ("nms_32.wav", SF_FORMAT_WAV | SF_FORMAT_NMS_ADPCM_32, 1, 0.018) ; + + test_count++ ; + } ; + /* Lite remove end */ + + if (do_all || strcmp (argv [1], "aiff_ulaw") == 0) + { lcomp_test_short ("ulaw.aiff", SF_FORMAT_AIFF | SF_FORMAT_ULAW, 2, 0.04) ; + lcomp_test_int ("ulaw.aiff", SF_FORMAT_AIFF | SF_FORMAT_ULAW, 2, 0.04) ; + /* Lite remove start */ + lcomp_test_float ("ulaw.aiff", SF_FORMAT_AIFF | SF_FORMAT_ULAW, 2, 0.04) ; + lcomp_test_double ("ulaw.aiff", SF_FORMAT_AIFF | SF_FORMAT_ULAW, 2, 0.04) ; + /* Lite remove end */ + + read_raw_test ("ulaw.aiff", SF_FORMAT_AIFF | SF_FORMAT_ULAW, 2) ; + test_count++ ; + } ; + + if (do_all || strcmp (argv [1], "aiff_alaw") == 0) + { lcomp_test_short ("alaw.aiff", SF_FORMAT_AIFF | SF_FORMAT_ALAW, 2, 0.04) ; + lcomp_test_int ("alaw.aiff", SF_FORMAT_AIFF | SF_FORMAT_ALAW, 2, 0.04) ; + /* Lite remove start */ + lcomp_test_float ("alaw.aiff", SF_FORMAT_AIFF | SF_FORMAT_ALAW, 2, 0.04) ; + lcomp_test_double ("alaw.aiff", SF_FORMAT_AIFF | SF_FORMAT_ALAW, 2, 0.04) ; + /* Lite remove end */ + + read_raw_test ("alaw.aiff", SF_FORMAT_AIFF | SF_FORMAT_ALAW, 2) ; + test_count++ ; + } ; + + if (do_all || strcmp (argv [1], "aiff_gsm610") == 0) + { /* Don't do lcomp_test_XXX as the errors are too big. */ + sdlcomp_test_short ("gsm610.aiff", SF_FORMAT_AIFF | SF_FORMAT_GSM610, 1, 0.24) ; + sdlcomp_test_int ("gsm610.aiff", SF_FORMAT_AIFF | SF_FORMAT_GSM610, 1, 0.24) ; + /* Lite remove start */ + sdlcomp_test_float ("gsm610.aiff", SF_FORMAT_AIFF | SF_FORMAT_GSM610, 1, 0.24) ; + sdlcomp_test_double ("gsm610.aiff", SF_FORMAT_AIFF | SF_FORMAT_GSM610, 1, 0.24) ; + /* Lite remove end */ + test_count++ ; + } ; + + if (strcmp (argv [1], "aiff_ima") == 0) + { lcomp_test_short ("ima.aiff", SF_FORMAT_AIFF | SF_FORMAT_IMA_ADPCM, 2, 0.18) ; + lcomp_test_int ("ima.aiff", SF_FORMAT_AIFF | SF_FORMAT_IMA_ADPCM, 2, 0.18) ; + /* Lite remove start */ + lcomp_test_float ("ima.aiff", SF_FORMAT_AIFF | SF_FORMAT_IMA_ADPCM, 2, 0.18) ; + lcomp_test_double ("ima.aiff", SF_FORMAT_AIFF | SF_FORMAT_IMA_ADPCM, 2, 0.18) ; + /* Lite remove end */ + } ; + + if (do_all || strcmp (argv [1], "au_ulaw") == 0) + { lcomp_test_short ("ulaw.au", SF_ENDIAN_BIG | SF_FORMAT_AU | SF_FORMAT_ULAW, 2, 0.04) ; + lcomp_test_int ("ulaw.au", SF_ENDIAN_LITTLE | SF_FORMAT_AU | SF_FORMAT_ULAW, 2, 0.04) ; + /* Lite remove start */ + lcomp_test_float ("ulaw.au", SF_ENDIAN_LITTLE | SF_FORMAT_AU | SF_FORMAT_ULAW, 2, 0.04) ; + lcomp_test_double ("ulaw.au", SF_ENDIAN_BIG | SF_FORMAT_AU | SF_FORMAT_ULAW, 2, 0.04) ; + /* Lite remove end */ + test_count++ ; + } ; + + if (do_all || strcmp (argv [1], "au_alaw") == 0) + { lcomp_test_short ("alaw.au", SF_ENDIAN_LITTLE | SF_FORMAT_AU | SF_FORMAT_ALAW, 2, 0.04) ; + lcomp_test_int ("alaw.au", SF_ENDIAN_BIG | SF_FORMAT_AU | SF_FORMAT_ALAW, 2, 0.04) ; + /* Lite remove start */ + lcomp_test_float ("alaw.au", SF_ENDIAN_BIG | SF_FORMAT_AU | SF_FORMAT_ALAW, 2, 0.04) ; + lcomp_test_double ("alaw.au", SF_ENDIAN_LITTLE | SF_FORMAT_AU | SF_FORMAT_ALAW, 2, 0.04) ; + /* Lite remove end */ + test_count++ ; + } ; + + /* Lite remove start */ + if (do_all || strcmp (argv [1], "au_g721") == 0) + { printf ("**** Fix this later : error bound should be 0.06 ****\n") ; + lcomp_test_short ("g721.au", SF_ENDIAN_LITTLE | SF_FORMAT_AU | SF_FORMAT_G721_32, 1, 0.7) ; + lcomp_test_int ("g721.au", SF_ENDIAN_BIG | SF_FORMAT_AU | SF_FORMAT_G721_32, 1, 0.7) ; + lcomp_test_float ("g721.au", SF_ENDIAN_LITTLE | SF_FORMAT_AU | SF_FORMAT_G721_32, 1, 0.7) ; + lcomp_test_double ("g721.au", SF_ENDIAN_BIG | SF_FORMAT_AU | SF_FORMAT_G721_32, 1, 0.7) ; + +/*- sdlcomp_test_short ("g721.au", SF_ENDIAN_BIG | SF_FORMAT_AU | SF_FORMAT_G721_32, 1, 0.07) ; + sdlcomp_test_int ("g721.au", SF_ENDIAN_LITTLE | SF_FORMAT_AU | SF_FORMAT_G721_32, 1, 0.07) ; + sdlcomp_test_float ("g721.au", SF_ENDIAN_BIG | SF_FORMAT_AU | SF_FORMAT_G721_32, 1, 0.07) ; + sdlcomp_test_double ("g721.au", SF_ENDIAN_LITTLE | SF_FORMAT_AU | SF_FORMAT_G721_32, 1, 0.12) ; +-*/ + test_count++ ; + } ; + + if (do_all || strcmp (argv [1], "au_g723") == 0) + { printf ("**** Fix this later : error bound should be 0.16 ****\n") ; + lcomp_test_short ("g723_24.au", SF_ENDIAN_LITTLE | SF_FORMAT_AU | SF_FORMAT_G723_24, 1, 0.7) ; + lcomp_test_int ("g723_24.au", SF_ENDIAN_BIG | SF_FORMAT_AU | SF_FORMAT_G723_24, 1, 0.7) ; + lcomp_test_float ("g723_24.au", SF_ENDIAN_LITTLE | SF_FORMAT_AU | SF_FORMAT_G723_24, 1, 0.7) ; + lcomp_test_double ("g723_24.au", SF_ENDIAN_BIG | SF_FORMAT_AU | SF_FORMAT_G723_24, 1, 0.7) ; + + lcomp_test_short ("g723_40.au", SF_ENDIAN_LITTLE | SF_FORMAT_AU | SF_FORMAT_G723_40, 1, 0.85) ; + lcomp_test_int ("g723_40.au", SF_ENDIAN_BIG | SF_FORMAT_AU | SF_FORMAT_G723_40, 1, 0.84) ; + lcomp_test_float ("g723_40.au", SF_ENDIAN_LITTLE | SF_FORMAT_AU | SF_FORMAT_G723_40, 1, 0.86) ; + lcomp_test_double ("g723_40.au", SF_ENDIAN_BIG | SF_FORMAT_AU | SF_FORMAT_G723_40, 1, 0.86) ; + +/*- sdlcomp_test_short ("g723.au", SF_ENDIAN_BIG | SF_FORMAT_AU | SF_FORMAT_G723_24, 1, 0.15) ; + sdlcomp_test_int ("g723.au", SF_ENDIAN_LITTLE | SF_FORMAT_AU | SF_FORMAT_G723_24, 1, 0.15) ; + sdlcomp_test_float ("g723.au", SF_ENDIAN_BIG | SF_FORMAT_AU | SF_FORMAT_G723_24, 1, 0.15) ; + sdlcomp_test_double ("g723.au", SF_ENDIAN_LITTLE | SF_FORMAT_AU | SF_FORMAT_G723_24, 1, 0.15) ; +-*/ + test_count++ ; + } ; + /* Lite remove end */ + + if (do_all || strcmp (argv [1], "caf_ulaw") == 0) + { lcomp_test_short ("ulaw.caf", SF_FORMAT_CAF | SF_FORMAT_ULAW, 2, 0.04) ; + lcomp_test_int ("ulaw.caf", SF_FORMAT_CAF | SF_FORMAT_ULAW, 2, 0.04) ; + /* Lite remove start */ + lcomp_test_float ("ulaw.caf", SF_FORMAT_CAF | SF_FORMAT_ULAW, 2, 0.04) ; + lcomp_test_double ("ulaw.caf", SF_FORMAT_CAF | SF_FORMAT_ULAW, 2, 0.04) ; + /* Lite remove end */ + + read_raw_test ("ulaw.caf", SF_FORMAT_CAF | SF_FORMAT_ULAW, 2) ; + test_count++ ; + } ; + + if (do_all || strcmp (argv [1], "caf_alaw") == 0) + { lcomp_test_short ("alaw.caf", SF_FORMAT_CAF | SF_FORMAT_ALAW, 2, 0.04) ; + lcomp_test_int ("alaw.caf", SF_FORMAT_CAF | SF_FORMAT_ALAW, 2, 0.04) ; + /* Lite remove start */ + lcomp_test_float ("alaw.caf", SF_FORMAT_CAF | SF_FORMAT_ALAW, 2, 0.04) ; + lcomp_test_double ("alaw.caf", SF_FORMAT_CAF | SF_FORMAT_ALAW, 2, 0.04) ; + /* Lite remove end */ + + read_raw_test ("alaw.caf", SF_FORMAT_CAF | SF_FORMAT_ALAW, 2) ; + test_count++ ; + } ; + + + if (do_all || strcmp (argv [1], "raw_ulaw") == 0) + { lcomp_test_short ("ulaw.raw", SF_ENDIAN_LITTLE | SF_FORMAT_RAW | SF_FORMAT_ULAW, 2, 0.04) ; + lcomp_test_int ("ulaw.raw", SF_ENDIAN_BIG | SF_FORMAT_RAW | SF_FORMAT_ULAW, 2, 0.04) ; + /* Lite remove start */ + lcomp_test_float ("ulaw.raw", SF_ENDIAN_LITTLE | SF_FORMAT_RAW | SF_FORMAT_ULAW, 2, 0.04) ; + lcomp_test_double ("ulaw.raw", SF_ENDIAN_BIG | SF_FORMAT_RAW | SF_FORMAT_ULAW, 2, 0.04) ; + /* Lite remove end */ + test_count++ ; + } ; + + if (do_all || strcmp (argv [1], "raw_alaw") == 0) + { lcomp_test_short ("alaw.raw", SF_ENDIAN_LITTLE | SF_FORMAT_RAW | SF_FORMAT_ALAW, 2, 0.04) ; + lcomp_test_int ("alaw.raw", SF_ENDIAN_BIG | SF_FORMAT_RAW | SF_FORMAT_ALAW, 2, 0.04) ; + /* Lite remove start */ + lcomp_test_float ("alaw.raw", SF_ENDIAN_LITTLE | SF_FORMAT_RAW | SF_FORMAT_ALAW, 2, 0.04) ; + lcomp_test_double ("alaw.raw", SF_ENDIAN_BIG | SF_FORMAT_RAW | SF_FORMAT_ALAW, 2, 0.04) ; + /* Lite remove end */ + test_count++ ; + } ; + + if (do_all || strcmp (argv [1], "raw_gsm610") == 0) + { /* Don't do lcomp_test_XXX as the errors are too big. */ + sdlcomp_test_short ("raw.gsm", SF_FORMAT_RAW | SF_FORMAT_GSM610, 1, 0.24) ; + sdlcomp_test_int ("raw.gsm", SF_FORMAT_RAW | SF_FORMAT_GSM610, 1, 0.24) ; + sdlcomp_test_float ("raw.gsm", SF_FORMAT_RAW | SF_FORMAT_GSM610, 1, 0.24) ; + sdlcomp_test_double ("raw.gsm", SF_FORMAT_RAW | SF_FORMAT_GSM610, 1, 0.24) ; + test_count++ ; + } ; + + /* Lite remove start */ + if (do_all || strcmp (argv [1], "raw_nmsadpcm") == 0) + { lcomp_test_short ("raw.vce16", SF_FORMAT_RAW | SF_FORMAT_NMS_ADPCM_16, 1, 0.37) ; + lcomp_test_int ("raw.vce16", SF_FORMAT_RAW | SF_FORMAT_NMS_ADPCM_16, 1, 0.31) ; + lcomp_test_float ("raw.vce16", SF_FORMAT_RAW | SF_FORMAT_NMS_ADPCM_16, 1, 0.34) ; + lcomp_test_double ("raw.vce16", SF_FORMAT_RAW | SF_FORMAT_NMS_ADPCM_16, 1, 0.34) ; + + lcomp_test_short ("raw.vce24", SF_FORMAT_RAW | SF_FORMAT_NMS_ADPCM_24, 1, 0.15) ; + lcomp_test_int ("raw.vce24", SF_FORMAT_RAW | SF_FORMAT_NMS_ADPCM_24, 1, 0.10) ; + lcomp_test_float ("raw.vce24", SF_FORMAT_RAW | SF_FORMAT_NMS_ADPCM_24, 1, 0.14) ; + lcomp_test_double ("raw.vce24", SF_FORMAT_RAW | SF_FORMAT_NMS_ADPCM_24, 1, 0.14) ; + + lcomp_test_short ("raw.vce32", SF_FORMAT_RAW | SF_FORMAT_NMS_ADPCM_32, 1, 0.036) ; + lcomp_test_int ("raw.vce32", SF_FORMAT_RAW | SF_FORMAT_NMS_ADPCM_32, 1, 0.045) ; + lcomp_test_float ("raw.vce32", SF_FORMAT_RAW | SF_FORMAT_NMS_ADPCM_32, 1, 0.035) ; + lcomp_test_double ("raw.vce32", SF_FORMAT_RAW | SF_FORMAT_NMS_ADPCM_32, 1, 0.035) ; + + sdlcomp_test_short ("raw.vce16", SF_FORMAT_RAW | SF_FORMAT_NMS_ADPCM_16, 1, 0.16) ; + sdlcomp_test_int ("raw.vce16", SF_FORMAT_RAW | SF_FORMAT_NMS_ADPCM_16, 1, 0.16) ; + sdlcomp_test_float ("raw.vce16", SF_FORMAT_RAW | SF_FORMAT_NMS_ADPCM_16, 1, 0.16) ; + sdlcomp_test_double ("raw.vce16", SF_FORMAT_RAW | SF_FORMAT_NMS_ADPCM_16, 1, 0.16) ; + + sdlcomp_test_short ("raw.vce24", SF_FORMAT_RAW | SF_FORMAT_NMS_ADPCM_24, 1, 0.06) ; + sdlcomp_test_int ("raw.vce24", SF_FORMAT_RAW | SF_FORMAT_NMS_ADPCM_24, 1, 0.06) ; + sdlcomp_test_float ("raw.vce24", SF_FORMAT_RAW | SF_FORMAT_NMS_ADPCM_24, 1, 0.06) ; + sdlcomp_test_double ("raw.vce24", SF_FORMAT_RAW | SF_FORMAT_NMS_ADPCM_24, 1, 0.06) ; + + sdlcomp_test_short ("raw.vce32", SF_FORMAT_RAW | SF_FORMAT_NMS_ADPCM_32, 1, 0.017) ; + sdlcomp_test_int ("raw.vce32", SF_FORMAT_RAW | SF_FORMAT_NMS_ADPCM_32, 1, 0.018) ; + sdlcomp_test_float ("raw.vce32", SF_FORMAT_RAW | SF_FORMAT_NMS_ADPCM_32, 1, 0.018) ; + sdlcomp_test_double ("raw.vce32", SF_FORMAT_RAW | SF_FORMAT_NMS_ADPCM_32, 1, 0.018) ; + + test_count++ ; + } ; + /* Lite remove end */ + + if (do_all || strcmp (argv [1], "ogg_vorbis") == 0) + { if (HAVE_EXTERNAL_XIPH_LIBS) + { /* Don't do lcomp_test_XXX as the errors are too big. */ + sdlcomp_test_short ("vorbis.oga", SF_FORMAT_OGG | SF_FORMAT_VORBIS, 1, 0.30) ; + sdlcomp_test_int ("vorbis.oga", SF_FORMAT_OGG | SF_FORMAT_VORBIS, 1, 0.30) ; + sdlcomp_test_float ("vorbis.oga", SF_FORMAT_OGG | SF_FORMAT_VORBIS, 1, 0.30) ; + sdlcomp_test_double ("vorbis.oga", SF_FORMAT_OGG | SF_FORMAT_VORBIS, 1, 0.30) ; + } + else + puts (" No Ogg/Vorbis tests because Ogg/Vorbis support was not compiled in.") ; + + test_count++ ; + } ; + + if (do_all || strcmp (argv [1], "ogg_opus") == 0) + { if (HAVE_EXTERNAL_XIPH_LIBS) + { /* Don't do lcomp_test_XXX as the errors are too big. */ + sdlcomp_test_short ("opus.opus", SF_FORMAT_OGG | SF_FORMAT_OPUS, 1, 0.57) ; + sdlcomp_test_int ("opus.opus", SF_FORMAT_OGG | SF_FORMAT_OPUS, 1, 0.54) ; + sdlcomp_test_float ("opus.opus", SF_FORMAT_OGG | SF_FORMAT_OPUS, 1, 0.55) ; + sdlcomp_test_double ("opus.opus", SF_FORMAT_OGG | SF_FORMAT_OPUS, 1, 0.55) ; + } + else + puts (" No Ogg/Opus tests because Ogg/Opus support was not compiled in.") ; + + test_count++ ; + } ; + + /* Lite remove start */ + if (do_all || strcmp (argv [1], "ircam_ulaw") == 0) + { lcomp_test_short ("ulaw.ircam", SF_ENDIAN_LITTLE | SF_FORMAT_IRCAM | SF_FORMAT_ULAW, 2, 0.04) ; + lcomp_test_int ("ulaw.ircam", SF_ENDIAN_BIG | SF_FORMAT_IRCAM | SF_FORMAT_ULAW, 2, 0.04) ; + lcomp_test_float ("ulaw.ircam", SF_ENDIAN_LITTLE | SF_FORMAT_IRCAM | SF_FORMAT_ULAW, 2, 0.04) ; + lcomp_test_double ("ulaw.ircam", SF_ENDIAN_BIG | SF_FORMAT_IRCAM | SF_FORMAT_ULAW, 2, 0.04) ; + test_count++ ; + } ; + + if (do_all || strcmp (argv [1], "ircam_alaw") == 0) + { lcomp_test_short ("alaw.ircam", SF_ENDIAN_LITTLE | SF_FORMAT_IRCAM | SF_FORMAT_ALAW, 2, 0.04) ; + lcomp_test_int ("alaw.ircam", SF_ENDIAN_BIG | SF_FORMAT_IRCAM | SF_FORMAT_ALAW, 2, 0.04) ; + lcomp_test_float ("alaw.ircam", SF_ENDIAN_LITTLE | SF_FORMAT_IRCAM | SF_FORMAT_ALAW, 2, 0.04) ; + lcomp_test_double ("alaw.ircam", SF_ENDIAN_BIG | SF_FORMAT_IRCAM | SF_FORMAT_ALAW, 2, 0.04) ; + test_count++ ; + } ; + + if (do_all || strcmp (argv [1], "nist_ulaw") == 0) + { lcomp_test_short ("ulaw.nist", SF_ENDIAN_LITTLE | SF_FORMAT_NIST | SF_FORMAT_ULAW, 2, 0.04) ; + lcomp_test_int ("ulaw.nist", SF_ENDIAN_BIG | SF_FORMAT_NIST | SF_FORMAT_ULAW, 2, 0.04) ; + lcomp_test_float ("ulaw.nist", SF_ENDIAN_LITTLE | SF_FORMAT_NIST | SF_FORMAT_ULAW, 2, 0.04) ; + lcomp_test_double ("ulaw.nist", SF_ENDIAN_BIG | SF_FORMAT_NIST | SF_FORMAT_ULAW, 2, 0.04) ; + test_count++ ; + } ; + + if (do_all || strcmp (argv [1], "nist_alaw") == 0) + { lcomp_test_short ("alaw.nist", SF_ENDIAN_LITTLE | SF_FORMAT_NIST | SF_FORMAT_ALAW, 2, 0.04) ; + lcomp_test_int ("alaw.nist", SF_ENDIAN_BIG | SF_FORMAT_NIST | SF_FORMAT_ALAW, 2, 0.04) ; + lcomp_test_float ("alaw.nist", SF_ENDIAN_LITTLE | SF_FORMAT_NIST | SF_FORMAT_ALAW, 2, 0.04) ; + lcomp_test_double ("alaw.nist", SF_ENDIAN_BIG | SF_FORMAT_NIST | SF_FORMAT_ALAW, 2, 0.04) ; + test_count++ ; + } ; + + if (do_all || strcmp (argv [1], "voc_ulaw") == 0) + { lcomp_test_short ("ulaw.voc", SF_FORMAT_VOC | SF_FORMAT_ULAW, 2, 0.04) ; + lcomp_test_int ("ulaw.voc", SF_FORMAT_VOC | SF_FORMAT_ULAW, 2, 0.04) ; + lcomp_test_float ("ulaw.voc", SF_FORMAT_VOC | SF_FORMAT_ULAW, 2, 0.04) ; + lcomp_test_double ("ulaw.voc", SF_FORMAT_VOC | SF_FORMAT_ULAW, 2, 0.04) ; + test_count++ ; + } ; + + if (do_all || strcmp (argv [1], "voc_alaw") == 0) + { lcomp_test_short ("alaw.voc", SF_FORMAT_VOC | SF_FORMAT_ALAW, 2, 0.04) ; + lcomp_test_int ("alaw.voc", SF_FORMAT_VOC | SF_FORMAT_ALAW, 2, 0.04) ; + lcomp_test_float ("alaw.voc", SF_FORMAT_VOC | SF_FORMAT_ALAW, 2, 0.04) ; + lcomp_test_double ("alaw.voc", SF_FORMAT_VOC | SF_FORMAT_ALAW, 2, 0.04) ; + test_count++ ; + } ; + /* Lite remove end */ + + if (do_all || strcmp (argv [1], "w64_ulaw") == 0) + { lcomp_test_short ("ulaw.w64", SF_FORMAT_W64 | SF_FORMAT_ULAW, 2, 0.04) ; + lcomp_test_int ("ulaw.w64", SF_FORMAT_W64 | SF_FORMAT_ULAW, 2, 0.04) ; + /* Lite remove start */ + lcomp_test_float ("ulaw.w64", SF_FORMAT_W64 | SF_FORMAT_ULAW, 2, 0.04) ; + lcomp_test_double ("ulaw.w64", SF_FORMAT_W64 | SF_FORMAT_ULAW, 2, 0.04) ; + /* Lite remove end */ + + read_raw_test ("ulaw.w64", SF_FORMAT_W64 | SF_FORMAT_ULAW, 2) ; + test_count++ ; + } ; + + if (do_all || strcmp (argv [1], "w64_alaw") == 0) + { lcomp_test_short ("alaw.w64", SF_FORMAT_W64 | SF_FORMAT_ALAW, 2, 0.04) ; + lcomp_test_int ("alaw.w64", SF_FORMAT_W64 | SF_FORMAT_ALAW, 2, 0.04) ; + /* Lite remove start */ + lcomp_test_float ("alaw.w64", SF_FORMAT_W64 | SF_FORMAT_ALAW, 2, 0.04) ; + lcomp_test_double ("alaw.w64", SF_FORMAT_W64 | SF_FORMAT_ALAW, 2, 0.04) ; + /* Lite remove end */ + + read_raw_test ("alaw.w64", SF_FORMAT_W64 | SF_FORMAT_ALAW, 2) ; + test_count++ ; + } ; + + /* Lite remove start */ + if (do_all || strcmp (argv [1], "w64_ima") == 0) + { lcomp_test_short ("ima.w64", SF_FORMAT_W64 | SF_FORMAT_IMA_ADPCM, 2, 0.18) ; + lcomp_test_int ("ima.w64", SF_FORMAT_W64 | SF_FORMAT_IMA_ADPCM, 2, 0.18) ; + lcomp_test_float ("ima.w64", SF_FORMAT_W64 | SF_FORMAT_IMA_ADPCM, 2, 0.18) ; + lcomp_test_double ("ima.w64", SF_FORMAT_W64 | SF_FORMAT_IMA_ADPCM, 2, 0.18) ; + + sdlcomp_test_short ("ima.w64", SF_FORMAT_W64 | SF_FORMAT_IMA_ADPCM, 2, 0.18) ; + sdlcomp_test_int ("ima.w64", SF_FORMAT_W64 | SF_FORMAT_IMA_ADPCM, 2, 0.18) ; + sdlcomp_test_float ("ima.w64", SF_FORMAT_W64 | SF_FORMAT_IMA_ADPCM, 2, 0.18) ; + sdlcomp_test_double ("ima.w64", SF_FORMAT_W64 | SF_FORMAT_IMA_ADPCM, 2, 0.18) ; + test_count++ ; + } ; + + if (do_all || strcmp (argv [1], "w64_msadpcm") == 0) + { lcomp_test_short ("msadpcm.w64", SF_FORMAT_W64 | SF_FORMAT_MS_ADPCM, 2, 0.36) ; + lcomp_test_int ("msadpcm.w64", SF_FORMAT_W64 | SF_FORMAT_MS_ADPCM, 2, 0.36) ; + lcomp_test_float ("msadpcm.w64", SF_FORMAT_W64 | SF_FORMAT_MS_ADPCM, 2, 0.36) ; + lcomp_test_double ("msadpcm.w64", SF_FORMAT_W64 | SF_FORMAT_MS_ADPCM, 2, 0.36) ; + + sdlcomp_test_short ("msadpcm.w64", SF_FORMAT_W64 | SF_FORMAT_MS_ADPCM, 2, 0.36) ; + sdlcomp_test_int ("msadpcm.w64", SF_FORMAT_W64 | SF_FORMAT_MS_ADPCM, 2, 0.36) ; + sdlcomp_test_float ("msadpcm.w64", SF_FORMAT_W64 | SF_FORMAT_MS_ADPCM, 2, 0.36) ; + sdlcomp_test_double ("msadpcm.w64", SF_FORMAT_W64 | SF_FORMAT_MS_ADPCM, 2, 0.36) ; + test_count++ ; + } ; + + if (do_all || strcmp (argv [1], "wve") == 0) + { lcomp_test_short ("psion.wve", SF_FORMAT_WVE | SF_FORMAT_ALAW, 1, 0.04) ; + lcomp_test_int ("psion.wve", SF_FORMAT_WVE | SF_FORMAT_ALAW, 1, 0.04) ; + /* Lite remove start */ + lcomp_test_float ("psion.wve", SF_FORMAT_WVE | SF_FORMAT_ALAW, 1, 0.04) ; + lcomp_test_double ("psion.wve", SF_FORMAT_WVE | SF_FORMAT_ALAW, 1, 0.04) ; + /* Lite remove end */ + test_count++ ; + } ; + + /* Lite remove end */ + + if (do_all || strcmp (argv [1], "w64_gsm610") == 0) + { /* Don't do lcomp_test_XXX as the errors are too big. */ + sdlcomp_test_short ("gsm610.w64", SF_FORMAT_W64 | SF_FORMAT_GSM610, 1, 0.2) ; + sdlcomp_test_int ("gsm610.w64", SF_FORMAT_W64 | SF_FORMAT_GSM610, 1, 0.2) ; + /* Lite remove start */ + sdlcomp_test_float ("gsm610.w64", SF_FORMAT_W64 | SF_FORMAT_GSM610, 1, 0.2) ; + sdlcomp_test_double ("gsm610.w64", SF_FORMAT_W64 | SF_FORMAT_GSM610, 1, 0.2) ; + /* Lite remove end */ + test_count++ ; + } ; + + /* Lite remove start */ + if (do_all || strcmp (argv [1], "vox_adpcm") == 0) + { lcomp_test_short ("adpcm.vox", SF_FORMAT_RAW | SF_FORMAT_VOX_ADPCM, 1, 0.17) ; + lcomp_test_int ("adpcm.vox", SF_FORMAT_RAW | SF_FORMAT_VOX_ADPCM, 1, 0.17) ; + lcomp_test_float ("adpcm.vox", SF_FORMAT_RAW | SF_FORMAT_VOX_ADPCM, 1, 0.17) ; + lcomp_test_double ("adpcm.vox", SF_FORMAT_RAW | SF_FORMAT_VOX_ADPCM, 1, 0.17) ; + + sdlcomp_test_short ("adpcm.vox", SF_FORMAT_RAW | SF_FORMAT_VOX_ADPCM, 1, 0.072) ; + sdlcomp_test_int ("adpcm.vox", SF_FORMAT_RAW | SF_FORMAT_VOX_ADPCM, 1, 0.072) ; + sdlcomp_test_float ("adpcm.vox", SF_FORMAT_RAW | SF_FORMAT_VOX_ADPCM, 1, 0.072) ; + sdlcomp_test_double ("adpcm.vox", SF_FORMAT_RAW | SF_FORMAT_VOX_ADPCM, 1, 0.072) ; + test_count++ ; + } ; + + if (do_all || strcmp (argv [1], "xi_dpcm") == 0) + { lcomp_test_short ("8bit.xi", SF_FORMAT_XI | SF_FORMAT_DPCM_8, 1, 0.25) ; + lcomp_test_int ("8bit.xi", SF_FORMAT_XI | SF_FORMAT_DPCM_8, 1, 0.25) ; + + lcomp_test_short ("16bit.xi", SF_FORMAT_XI | SF_FORMAT_DPCM_16, 1, 0.002) ; + lcomp_test_int ("16bit.xi", SF_FORMAT_XI | SF_FORMAT_DPCM_16, 1, 0.002) ; + lcomp_test_float ("16bit.xi", SF_FORMAT_XI | SF_FORMAT_DPCM_16, 1, 0.002) ; + lcomp_test_double ("16bit.xi", SF_FORMAT_XI | SF_FORMAT_DPCM_16, 1, 0.002) ; + test_count++ ; + } ; + /* Lite remove end */ + + if (test_count == 0) + { printf ("************************************\n") ; + printf ("* No '%s' test defined.\n", argv [1]) ; + printf ("************************************\n") ; + return 1 ; + } ; + + return 0 ; +} /* main */ + +/*============================================================================================ +** Here are the test functions. +*/ + +static void +lcomp_test_short (const char *filename, int filetype, int channels, double margin) +{ SNDFILE *file ; + SF_INFO sfinfo ; + int k, m, seekpos, half_max_abs ; + sf_count_t datalen ; + short *orig, *data ; + + get_unique_test_name (&filename, LCT_TEST_PREFIX) ; + print_test_name ("lcomp_test_short", filename) ; + + datalen = BUFFER_SIZE / channels ; + + data = data_buffer.s ; + orig = orig_buffer.s ; + + gen_signal_double (orig_buffer.d, 32000.0, channels, (int) datalen) ; + for (k = 0 ; k < channels * datalen ; k++) + orig [k] = (short) (orig_buffer.d [k]) ; + + sfinfo.samplerate = SAMPLE_RATE ; + sfinfo.frames = 123456789 ; /* Ridiculous value. */ + sfinfo.channels = channels ; + sfinfo.format = filetype ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_FALSE, __LINE__) ; + test_writef_short_or_die (file, 0, orig, datalen, __LINE__) ; + sf_set_string (file, SF_STR_COMMENT, long_comment) ; + sf_close (file) ; + + memset (data, 0, datalen * sizeof (short)) ; + + if ((filetype & SF_FORMAT_TYPEMASK) != SF_FORMAT_RAW) + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + + if ((sfinfo.format & (SF_FORMAT_TYPEMASK | SF_FORMAT_SUBMASK)) != (filetype & (SF_FORMAT_TYPEMASK | SF_FORMAT_SUBMASK))) + { printf ("\n\nLine %d: Returned format incorrect (0x%08X => 0x%08X).\n", __LINE__, filetype, sfinfo.format) ; + exit (1) ; + } ; + + if (sfinfo.frames < datalen / channels) + { printf ("Too few frames in file. (%" PRId64 " should be a little more than %" PRId64 ")\n", sfinfo.frames, datalen) ; + exit (1) ; + } ; + + if (sfinfo.frames > (datalen + datalen / 20)) + { printf ("Too many frames in file. (%" PRId64 " should be a little more than %" PRId64 ")\n", sfinfo.frames, datalen) ; + exit (1) ; + } ; + + if (sfinfo.channels != channels) + { printf ("Incorrect number of channels in file.\n") ; + exit (1) ; + } ; + + check_log_buffer_or_die (file, __LINE__) ; + + check_comment (file, filetype, __LINE__) ; + + test_readf_short_or_die (file, 0, data, datalen, __LINE__) ; + + half_max_abs = 0 ; + for (k = 0 ; k < datalen ; k++) + { if (error_function (data [k], orig [k], margin)) + { printf ("\n\nLine %d: Incorrect sample A (#%d : %d should be %d).\n", __LINE__, k, data [k], orig [k]) ; + oct_save_short (orig, data, (int) datalen) ; + exit (1) ; + } ; + half_max_abs = LCT_MAX (half_max_abs, abs (data [k] / 2)) ; + } ; + + if (half_max_abs < 1.0) + { printf ("\n\nLine %d: Signal is all zeros.\n", __LINE__) ; + exit (1) ; + } ; + + if ((k = (int) sf_readf_short (file, data, datalen)) != sfinfo.frames - datalen) + { printf ("\n\nLine %d: Incorrect read length (%" PRId64 " should be %d).\n", __LINE__, + channels * sfinfo.frames - datalen, k) ; + exit (1) ; + } ; + + /* This check is only for block based encoders which must append silence + ** to the end of a file so as to fill out a block. + */ + for (k = 0 ; k < sfinfo.frames - datalen ; k++) + if (abs (data [channels * k]) > decay_response (channels * k)) + { printf ("\n\nLine %d : Incorrect sample B (#%d : abs (%d) should be < %d).\n", __LINE__, channels * k, data [channels * k], decay_response (channels * k)) ; + exit (1) ; + } ; + + if (! sfinfo.seekable) + { sf_close (file) ; + unlink (filename) ; + printf ("ok\n") ; + return ; + } ; + + /* Now test sf_seek function. */ + + if ((k = (int) sf_seek (file, 0, SEEK_SET)) != 0) + { printf ("\n\nLine %d: Seek to start of file failed (%d).\n", __LINE__, k) ; + exit (1) ; + } ; + + for (m = 0 ; m < 3 ; m++) + { test_readf_short_or_die (file, m, data, 11, __LINE__) ; + + for (k = 0 ; k < channels * 11 ; k++) + if (error_function (1.0 * data [k], 1.0 * orig [k + channels * m * 11], margin)) + { printf ("\n\nLine %d: Incorrect sample (m = %d) (#%d : %d => %d).\n", __LINE__, m, k + channels * m * 11, orig [k + channels * m * 11], data [k]) ; + for (m = 0 ; m < channels ; m++) + printf ("%d ", data [m]) ; + printf ("\n") ; + exit (1) ; + } ; + } ; + + seekpos = BUFFER_SIZE / 10 ; + + /* Check seek from start of file. */ + if ((k = (int) sf_seek (file, seekpos, SEEK_SET)) != seekpos) + { printf ("Seek to start of file + %d failed (%d).\n", seekpos, k) ; + exit (1) ; + } ; + + test_readf_short_or_die (file, 0, data, 1, __LINE__) ; + + if (error_function (1.0 * data [0], 1.0 * orig [seekpos * channels], margin)) + { printf ("\n\nLine %d: sf_seek (SEEK_SET) followed by sf_readf_short failed (%d, %d).\n", __LINE__, orig [1], data [0]) ; + exit (1) ; + } ; + + if ((k = (int) sf_seek (file, 0, SEEK_CUR)) != seekpos + 1) + { printf ("\n\nLine %d: sf_seek (SEEK_CUR) with 0 offset failed (%d should be %d)\n", __LINE__, k, seekpos + 1) ; + exit (1) ; + } ; + + seekpos = (int) sf_seek (file, 0, SEEK_CUR) + BUFFER_SIZE / 5 ; + k = (int) sf_seek (file, BUFFER_SIZE / 5, SEEK_CUR) ; + test_readf_short_or_die (file, 0, data, 1, __LINE__) ; + if (error_function (1.0 * data [0], 1.0 * orig [seekpos * channels], margin) || k != seekpos) + { printf ("\n\nLine %d: sf_seek (forwards, SEEK_CUR) followed by sf_readf_short failed (%d, %d) (%d, %d).\n", __LINE__, data [0], orig [seekpos * channels], k, seekpos + 1) ; + oct_save_short (orig, data, (int) datalen) ; + exit (1) ; + } ; + + seekpos = (int) sf_seek (file, 0, SEEK_CUR) - 20 ; + /* Check seek backward from current position. */ + k = (int) sf_seek (file, -20, SEEK_CUR) ; + test_readf_short_or_die (file, 0, data, 1, __LINE__) ; + if (error_function (1.0 * data [0], 1.0 * orig [seekpos * channels], margin) || k != seekpos) + { printf ("\nLine %d: sf_seek (backwards, SEEK_CUR) followed by sf_readf_short failed (%d, %d) (%d, %d).\n", __LINE__, data [0], orig [seekpos * channels], k, seekpos) ; + exit (1) ; + } ; + + /* Check that read past end of file returns number of items. */ + sf_seek (file, sfinfo.frames, SEEK_SET) ; + + if ((k = (int) sf_readf_short (file, data, datalen)) != 0) + { printf ("\n\nLine %d: Return value from sf_readf_short past end of file incorrect (%d).\n", __LINE__, k) ; + exit (1) ; + } ; + + /* Check seek backward from end. */ + if ((k = (int) sf_seek (file, 5 - sfinfo.frames, SEEK_END)) != 5) + { printf ("\n\nLine %d: sf_seek (SEEK_END) returned %d instead of %d.\n", __LINE__, k, 5) ; + exit (1) ; + } ; + + test_readf_short_or_die (file, 0, data, 1, __LINE__) ; + if (error_function (1.0 * data [0], 1.0 * orig [5 * channels], margin)) + { printf ("\nLine %d: sf_seek (SEEK_END) followed by sf_readf_short failed (%d should be %d).\n", __LINE__, data [0], orig [5 * channels]) ; + exit (1) ; + } ; + + sf_close (file) ; + + unlink (filename) ; + printf ("ok\n") ; +} /* lcomp_test_short */ + +/*-------------------------------------------------------------------------------------------- +*/ + +static void +lcomp_test_int (const char *filename, int filetype, int channels, double margin) +{ SNDFILE *file ; + SF_INFO sfinfo ; + int k, m, half_max_abs ; + sf_count_t datalen, seekpos ; + double scale, max_val ; + int *orig, *data ; + + get_unique_test_name (&filename, LCT_TEST_PREFIX) ; + print_test_name ("lcomp_test_int", filename) ; + + datalen = BUFFER_SIZE / channels ; + + if (is_lossy (filetype)) + { scale = 1.0 * 0x10000 ; + max_val = 32000.0 * scale ; + } + else + { scale = 1.0 ; + max_val = 0x7fffffff * scale ; + } ; + + data = data_buffer.i ; + orig = orig_buffer.i ; + + gen_signal_double (orig_buffer.d, max_val, channels, (int) datalen) ; + + for (k = 0 ; k < channels * datalen ; k++) + orig [k] = lrint (orig_buffer.d [k]) ; + + sfinfo.samplerate = SAMPLE_RATE ; + sfinfo.frames = 123456789 ; /* Ridiculous value. */ + sfinfo.channels = channels ; + sfinfo.format = filetype ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_FALSE, __LINE__) ; + test_writef_int_or_die (file, 0, orig, datalen, __LINE__) ; + sf_set_string (file, SF_STR_COMMENT, long_comment) ; + sf_close (file) ; + + memset (data, 0, datalen * sizeof (int)) ; + + if ((filetype & SF_FORMAT_TYPEMASK) != SF_FORMAT_RAW) + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + + if ((sfinfo.format & (SF_FORMAT_TYPEMASK | SF_FORMAT_SUBMASK)) != (filetype & (SF_FORMAT_TYPEMASK | SF_FORMAT_SUBMASK))) + { printf ("\n\nLine %d: Returned format incorrect (0x%08X => 0x%08X).\n", __LINE__, filetype, sfinfo.format) ; + exit (1) ; + } ; + + if (sfinfo.frames < datalen / channels) + { printf ("Too few.frames in file. (%" PRId64 " should be a little more than %" PRId64 ")\n", datalen, sfinfo.frames) ; + exit (1) ; + } ; + + if (sfinfo.frames > (datalen + datalen / 20)) + { printf ("Too many.frames in file. (%" PRId64 " should be a little more than %" PRId64 ")\n", datalen, sfinfo.frames) ; + exit (1) ; + } ; + + if (sfinfo.channels != channels) + { printf ("Incorrect number of channels in file.\n") ; + exit (1) ; + } ; + + check_log_buffer_or_die (file, __LINE__) ; + + check_comment (file, filetype, __LINE__) ; + + test_readf_int_or_die (file, 0, data, datalen, __LINE__) ; + + half_max_abs = 0 ; + for (k = 0 ; k < datalen ; k++) + { if (error_function (data [k] / scale, orig [k] / scale, margin)) + { printf ("\nLine %d: Incorrect sample (#%d : %f should be %f).\n", __LINE__, k, data [k] / scale, orig [k] / scale) ; + oct_save_int (orig, data, (int) datalen) ; + exit (1) ; + } ; + half_max_abs = LCT_MAX (half_max_abs, abs (data [k] / 2)) ; + } ; + + if (half_max_abs < 1.0) + { printf ("\n\nLine %d: Signal is all zeros (%d, 0x%X).\n", __LINE__, half_max_abs, half_max_abs) ; + exit (1) ; + } ; + + if ((k = (int) sf_readf_int (file, data, datalen)) != sfinfo.frames - datalen) + { printf ("\n\nLine %d: Incorrect read length (%" PRId64 " should be %d).\n", __LINE__, + channels * sfinfo.frames - datalen, k) ; + exit (1) ; + } ; + + /* This check is only for block based encoders which must append silence + ** to the end of a file so as to fill out a block. + */ + if ((sfinfo.format & SF_FORMAT_SUBMASK) != SF_FORMAT_MS_ADPCM) + for (k = 0 ; k < sfinfo.frames - datalen ; k++) + if (ABS (data [channels * k] / scale) > decay_response (channels * k)) + { printf ("\n\nLine %d : Incorrect sample B (#%d : abs (%d) should be < %d).\n", __LINE__, channels * k, data [channels * k], decay_response (channels * k)) ; + exit (1) ; + } ; + + if (! sfinfo.seekable) + { sf_close (file) ; + unlink (filename) ; + printf ("ok\n") ; + return ; + } ; + + /* Now test sf_seek function. */ + + if ((k = (int) sf_seek (file, 0, SEEK_SET)) != 0) + { printf ("\n\nLine %d: Seek to start of file failed (%d).\n", __LINE__, k) ; + exit (1) ; + } ; + + for (m = 0 ; m < 3 ; m++) + { test_readf_int_or_die (file, m, data, 11, __LINE__) ; + + for (k = 0 ; k < channels * 11 ; k++) + if (error_function (data [k] / scale, orig [k + channels * m * 11] / scale, margin)) + { printf ("\nLine %d: Incorrect sample (m = %d) (#%d : %d => %d).\n", __LINE__, m, k + channels * m * 11, orig [k + channels * m * 11], data [k]) ; + for (m = 0 ; m < channels ; m++) + printf ("%d ", data [m]) ; + printf ("\n") ; + exit (1) ; + } ; + } ; + + seekpos = BUFFER_SIZE / 10 ; + + /* Check seek from start of file. */ + if ((k = (int) sf_seek (file, seekpos, SEEK_SET)) != seekpos) + { printf ("Seek to start of file + %" PRId64 " failed (%d).\n", seekpos, k) ; + exit (1) ; + } ; + + test_readf_int_or_die (file, 0, data, 1, __LINE__) ; + + if (error_function (1.0 * data [0], 1.0 * orig [seekpos * channels], margin)) + { printf ("\nLine %d: sf_seek (SEEK_SET) followed by sf_readf_int failed (%d, %d).\n", __LINE__, orig [1], data [0]) ; + exit (1) ; + } ; + + if ((k = (int) sf_seek (file, 0, SEEK_CUR)) != seekpos + 1) + { printf ("\n\nLine %d: sf_seek (SEEK_CUR) with 0 offset failed (%d should be %" PRId64 ")\n", __LINE__, k, seekpos + 1) ; + exit (1) ; + } ; + + seekpos = sf_seek (file, 0, SEEK_CUR) + BUFFER_SIZE / 5 ; + k = (int) sf_seek (file, BUFFER_SIZE / 5, SEEK_CUR) ; + test_readf_int_or_die (file, 0, data, 1, __LINE__) ; + if (error_function (1.0 * data [0], 1.0 * orig [seekpos * channels], margin) || k != seekpos) + { printf ("\nLine %d: sf_seek (forwards, SEEK_CUR) followed by sf_readf_int failed (%d, %d) (%d, %" PRId64 ").\n", __LINE__, data [0], orig [seekpos * channels], k, seekpos + 1) ; + exit (1) ; + } ; + + seekpos = sf_seek (file, 0, SEEK_CUR) - 20 ; + /* Check seek backward from current position. */ + k = (int) sf_seek (file, -20, SEEK_CUR) ; + test_readf_int_or_die (file, 0, data, 1, __LINE__) ; + if (error_function (1.0 * data [0], 1.0 * orig [seekpos * channels], margin) || k != seekpos) + { printf ("\nLine %d: sf_seek (backwards, SEEK_CUR) followed by sf_readf_int failed (%d, %d) (%d, %" PRId64 ").\n", __LINE__, data [0], orig [seekpos * channels], k, seekpos) ; + exit (1) ; + } ; + + /* Check that read past end of file returns number of items. */ + sf_seek (file, sfinfo.frames, SEEK_SET) ; + + if ((k = (int) sf_readf_int (file, data, datalen)) != 0) + { printf ("\n\nLine %d: Return value from sf_readf_int past end of file incorrect (%d).\n", __LINE__, k) ; + exit (1) ; + } ; + + /* Check seek backward from end. */ + if ((k = (int) sf_seek (file, 5 - sfinfo.frames, SEEK_END)) != 5) + { printf ("\n\nLine %d: sf_seek (SEEK_END) returned %d instead of %d.\n", __LINE__, k, 5) ; + exit (1) ; + } ; + + test_readf_int_or_die (file, 0, data, 1, __LINE__) ; + if (error_function (data [0] / scale, orig [5 * channels] / scale, margin)) + { printf ("\nLine %d: sf_seek (SEEK_END) followed by sf_readf_short failed (%d should be %d).\n", __LINE__, data [0], orig [5]) ; + exit (1) ; + } ; + + sf_close (file) ; + + unlink (filename) ; + printf ("ok\n") ; +} /* lcomp_test_int */ + +/*-------------------------------------------------------------------------------------------- +*/ + +static void +lcomp_test_float (const char *filename, int filetype, int channels, double margin) +{ SNDFILE *file ; + SF_INFO sfinfo ; + int k, m, seekpos ; + sf_count_t datalen ; + float *orig, *data ; + double half_max_abs ; + + get_unique_test_name (&filename, LCT_TEST_PREFIX) ; + print_test_name ("lcomp_test_float", filename) ; + + datalen = BUFFER_SIZE / channels ; + + data = data_buffer.f ; + orig = orig_buffer.f ; + + gen_signal_double (orig_buffer.d, 32000.0, channels, (int) datalen) ; + for (k = 0 ; k < channels * datalen ; k++) + orig [k] = (float) orig_buffer.d [k] ; + + sfinfo.samplerate = SAMPLE_RATE ; + sfinfo.frames = 123456789 ; /* Ridiculous value. */ + sfinfo.channels = channels ; + sfinfo.format = filetype ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_FALSE, __LINE__) ; + sf_command (file, SFC_SET_NORM_FLOAT, NULL, SF_FALSE) ; + test_writef_float_or_die (file, 0, orig, datalen, __LINE__) ; + sf_set_string (file, SF_STR_COMMENT, long_comment) ; + sf_close (file) ; + + memset (data, 0, datalen * sizeof (float)) ; + + if ((filetype & SF_FORMAT_TYPEMASK) != SF_FORMAT_RAW) + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + + if ((sfinfo.format & (SF_FORMAT_TYPEMASK | SF_FORMAT_SUBMASK)) != (filetype & (SF_FORMAT_TYPEMASK | SF_FORMAT_SUBMASK))) + { printf ("\n\nLine %d: Returned format incorrect (0x%08X => 0x%08X).\n", __LINE__, filetype, sfinfo.format) ; + exit (1) ; + } ; + + if (sfinfo.frames < datalen / channels) + { printf ("Too few.frames in file. (%" PRId64 " should be a little more than %" PRId64 ")\n", datalen, sfinfo.frames) ; + exit (1) ; + } ; + + if (sfinfo.frames > (datalen + datalen / 20)) + { printf ("Too many.frames in file. (%" PRId64 " should be a little more than %" PRId64 ")\n", datalen, sfinfo.frames) ; + exit (1) ; + } ; + + if (sfinfo.channels != channels) + { printf ("Incorrect number of channels in file.\n") ; + exit (1) ; + } ; + + check_comment (file, filetype, __LINE__) ; + + sf_command (file, SFC_SET_NORM_FLOAT, NULL, SF_FALSE) ; + + check_log_buffer_or_die (file, __LINE__) ; + + check_comment (file, filetype, __LINE__) ; + + sf_command (file, SFC_SET_NORM_FLOAT, NULL, SF_FALSE) ; + + test_readf_float_or_die (file, 0, data, datalen, __LINE__) ; + + half_max_abs = 0.0 ; + for (k = 0 ; k < datalen ; k++) + { if (error_function (data [k], orig [k], margin)) + { printf ("\nLine %d: Incorrect sample A (#%d : %f should be %f).\n", __LINE__, k, data [k], orig [k]) ; + oct_save_float (orig, data, (int) datalen) ; + exit (1) ; + } ; + half_max_abs = LCT_MAX (half_max_abs, fabs (0.5 * data [k])) ; + } ; + + if (half_max_abs < 1.0) + { printf ("\n\nLine %d: Signal is all zeros.\n", __LINE__) ; + exit (1) ; + } ; + + if ((k = (int) sf_readf_float (file, data, datalen)) != sfinfo.frames - datalen) + { printf ("\n\nLine %d: Incorrect read length (%" PRId64 " should be %d).\n", __LINE__, + channels * sfinfo.frames - datalen, k) ; + exit (1) ; + } ; + + /* This check is only for block based encoders which must append silence + ** to the end of a file so as to fill out a block. + */ + if ((sfinfo.format & SF_FORMAT_SUBMASK) != SF_FORMAT_MS_ADPCM) + for (k = 0 ; k < sfinfo.frames - datalen ; k++) + if (ABS (data [channels * k]) > decay_response (channels * k)) + { printf ("\n\nLine %d : Incorrect sample B (#%d : abs (%f) should be < %d).\n", __LINE__, channels * k, data [channels * k], decay_response (channels * k)) ; + exit (1) ; + } ; + + if (! sfinfo.seekable) + { sf_close (file) ; + unlink (filename) ; + printf ("ok\n") ; + return ; + } ; + + /* Now test sf_seek function. */ + + if ((k = (int) sf_seek (file, 0, SEEK_SET)) != 0) + { printf ("\n\nLine %d: Seek to start of file failed (%d).\n", __LINE__, k) ; + exit (1) ; + } ; + + for (m = 0 ; m < 3 ; m++) + { test_readf_float_or_die (file, 0, data, 11, __LINE__) ; + + for (k = 0 ; k < channels * 11 ; k++) + if (error_function (data [k], orig [k + channels * m * 11], margin)) + { printf ("\nLine %d: Incorrect sample (m = %d) (#%d : %f => %f).\n", __LINE__, m, k + channels * m * 11, orig [k + channels * m * 11], data [k]) ; + for (m = 0 ; m < channels ; m++) + printf ("%f ", data [m]) ; + printf ("\n") ; + exit (1) ; + } ; + } ; + + seekpos = BUFFER_SIZE / 10 ; + + /* Check seek from start of file. */ + if ((k = (int) sf_seek (file, seekpos, SEEK_SET)) != seekpos) + { printf ("Seek to start of file + %d failed (%d).\n", seekpos, k) ; + exit (1) ; + } ; + + test_readf_float_or_die (file, 0, data, 1, __LINE__) ; + + if (error_function (data [0], orig [seekpos * channels], margin)) + { printf ("\nLine %d: sf_seek (SEEK_SET) followed by sf_readf_float failed (%f, %f).\n", __LINE__, orig [1], data [0]) ; + exit (1) ; + } ; + + if ((k = (int) sf_seek (file, 0, SEEK_CUR)) != seekpos + 1) + { printf ("\n\nLine %d: sf_seek (SEEK_CUR) with 0 offset failed (%d should be %d)\n", __LINE__, k, seekpos + 1) ; + exit (1) ; + } ; + + seekpos = (int) sf_seek (file, 0, SEEK_CUR) + BUFFER_SIZE / 5 ; + k = (int) sf_seek (file, BUFFER_SIZE / 5, SEEK_CUR) ; + test_readf_float_or_die (file, 0, data, 1, __LINE__) ; + if (error_function (data [0], orig [seekpos * channels], margin) || k != seekpos) + { printf ("\nLine %d: sf_seek (forwards, SEEK_CUR) followed by sf_readf_float failed (%f, %f) (%d, %d).\n", __LINE__, data [0], orig [seekpos * channels], k, seekpos + 1) ; + exit (1) ; + } ; + + seekpos = (int) sf_seek (file, 0, SEEK_CUR) - 20 ; + /* Check seek backward from current position. */ + k = (int) sf_seek (file, -20, SEEK_CUR) ; + test_readf_float_or_die (file, 0, data, 1, __LINE__) ; + if (error_function (data [0], orig [seekpos * channels], margin) || k != seekpos) + { printf ("\nLine %d: sf_seek (backwards, SEEK_CUR) followed by sf_readf_float failed (%f, %f) (%d, %d).\n", __LINE__, data [0], orig [seekpos * channels], k, seekpos) ; + exit (1) ; + } ; + + /* Check that read past end of file returns number of items. */ + sf_seek (file, sfinfo.frames, SEEK_SET) ; + + if ((k = (int) sf_readf_float (file, data, datalen)) != 0) + { printf ("\n\nLine %d: Return value from sf_readf_float past end of file incorrect (%d).\n", __LINE__, k) ; + exit (1) ; + } ; + + /* Check seek backward from end. */ + if ((k = (int) sf_seek (file, 5 - sfinfo.frames, SEEK_END)) != 5) + { printf ("\n\nLine %d: sf_seek (SEEK_END) returned %d instead of %d.\n", __LINE__, k, 5) ; + exit (1) ; + } ; + + test_readf_float_or_die (file, 0, data, 1, __LINE__) ; + if (error_function (data [0], orig [5 * channels], margin)) + { printf ("\nLine %d: sf_seek (SEEK_END) followed by sf_readf_short failed (%f should be %f).\n", __LINE__, data [0], orig [5 * channels]) ; + exit (1) ; + } ; + + sf_close (file) ; + + unlink (filename) ; + printf ("ok\n") ; +} /* lcomp_test_float */ + +/*-------------------------------------------------------------------------------------------- +*/ + +static void +lcomp_test_double (const char *filename, int filetype, int channels, double margin) +{ SNDFILE *file ; + SF_INFO sfinfo ; + int k, m, seekpos ; + sf_count_t datalen ; + double *orig, *data ; + double half_max_abs ; + + get_unique_test_name (&filename, LCT_TEST_PREFIX) ; + print_test_name ("lcomp_test_double", filename) ; + + datalen = BUFFER_SIZE / channels ; + + data = data_buffer.d ; + orig = orig_buffer.d ; + + gen_signal_double (orig_buffer.d, 32000.0, channels, (int) datalen) ; + for (k = 0 ; k < channels * datalen ; k++) + orig [k] = orig_buffer.d [k] ; + + sfinfo.samplerate = SAMPLE_RATE ; + sfinfo.frames = 123456789 ; /* Ridiculous value. */ + sfinfo.channels = channels ; + sfinfo.format = filetype ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_FALSE, __LINE__) ; + sf_command (file, SFC_SET_NORM_DOUBLE, NULL, SF_FALSE) ; + test_writef_double_or_die (file, 0, orig, datalen, __LINE__) ; + sf_set_string (file, SF_STR_COMMENT, long_comment) ; + sf_close (file) ; + + memset (data, 0, datalen * sizeof (double)) ; + + if ((filetype & SF_FORMAT_TYPEMASK) != SF_FORMAT_RAW) + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + + if ((sfinfo.format & (SF_FORMAT_TYPEMASK | SF_FORMAT_SUBMASK)) != (filetype & (SF_FORMAT_TYPEMASK | SF_FORMAT_SUBMASK))) + { printf ("\n\nLine %d: Returned format incorrect (0x%08X => 0x%08X).\n", __LINE__, filetype, sfinfo.format) ; + exit (1) ; + } ; + + if (sfinfo.frames < datalen / channels) + { printf ("Too few.frames in file. (%" PRId64 " should be a little more than %" PRId64 ")\n", datalen, sfinfo.frames) ; + exit (1) ; + } ; + + if (sfinfo.frames > (datalen + datalen / 20)) + { printf ("Too many.frames in file. (%" PRId64 " should be a little more than %" PRId64 ")\n", datalen, sfinfo.frames) ; + exit (1) ; + } ; + + if (sfinfo.channels != channels) + { printf ("Incorrect number of channels in file.\n") ; + exit (1) ; + } ; + + check_comment (file, filetype, __LINE__) ; + + sf_command (file, SFC_SET_NORM_DOUBLE, NULL, SF_FALSE) ; + + check_log_buffer_or_die (file, __LINE__) ; + + check_comment (file, filetype, __LINE__) ; + + sf_command (file, SFC_SET_NORM_DOUBLE, NULL, SF_FALSE) ; + + test_readf_double_or_die (file, 0, data, datalen, __LINE__) ; + + half_max_abs = 0.0 ; + for (k = 0 ; k < datalen ; k++) + { if (error_function (data [k], orig [k], margin)) + { printf ("\nLine %d: Incorrect sample A (#%d : %f should be %f).\n", __LINE__, k, data [k], orig [k]) ; + oct_save_double (orig, data, (int) datalen) ; + exit (1) ; + } ; + half_max_abs = LCT_MAX (half_max_abs, ABS (0.5 * data [k])) ; + } ; + + if (half_max_abs < 1.0) + { printf ("\n\nLine %d: Signal is all zeros.\n", __LINE__) ; + exit (1) ; + } ; + + if ((k = (int) sf_readf_double (file, data, datalen)) != sfinfo.frames - datalen) + { printf ("\n\nLine %d: Incorrect read length (%" PRId64 " should be %d).\n", __LINE__, + channels * sfinfo.frames - datalen, k) ; + exit (1) ; + } ; + + /* This check is only for block based encoders which must append silence + ** to the end of a file so as to fill out a block. + */ + if ((sfinfo.format & SF_FORMAT_SUBMASK) != SF_FORMAT_MS_ADPCM) + for (k = 0 ; k < sfinfo.frames - datalen ; k++) + if (ABS (data [channels * k]) > decay_response (channels * k)) + { printf ("\n\nLine %d : Incorrect sample B (#%d : abs (%f) should be < %d).\n", __LINE__, channels * k, data [channels * k], decay_response (channels * k)) ; + exit (1) ; + } ; + + if (! sfinfo.seekable) + { sf_close (file) ; + unlink (filename) ; + printf ("ok\n") ; + return ; + } ; + + /* Now test sf_seek function. */ + + if ((k = (int) sf_seek (file, 0, SEEK_SET)) != 0) + { printf ("\n\nLine %d: Seek to start of file failed (%d).\n", __LINE__, k) ; + exit (1) ; + } ; + + for (m = 0 ; m < 3 ; m++) + { test_readf_double_or_die (file, m, data, 11, __LINE__) ; + + for (k = 0 ; k < channels * 11 ; k++) + if (error_function (data [k], orig [k + channels * m * 11], margin)) + { printf ("\nLine %d: Incorrect sample (m = %d) (#%d : %f => %f).\n", __LINE__, m, k + channels * m * 11, orig [k + channels * m * 11], data [k]) ; + for (m = 0 ; m < channels ; m++) + printf ("%f ", data [m]) ; + printf ("\n") ; + exit (1) ; + } ; + } ; + + seekpos = BUFFER_SIZE / 10 ; + + /* Check seek from start of file. */ + if ((k = (int) sf_seek (file, seekpos, SEEK_SET)) != seekpos) + { printf ("Seek to start of file + %d failed (%d).\n", seekpos, k) ; + exit (1) ; + } ; + + test_readf_double_or_die (file, 0, data, 1, __LINE__) ; + + if (error_function (data [0], orig [seekpos * channels], margin)) + { printf ("\nLine %d: sf_seek (SEEK_SET) followed by sf_readf_double failed (%f, %f).\n", __LINE__, orig [1], data [0]) ; + exit (1) ; + } ; + + if ((k = (int) sf_seek (file, 0, SEEK_CUR)) != seekpos + 1) + { printf ("\n\nLine %d: sf_seek (SEEK_CUR) with 0 offset failed (%d should be %d)\n", __LINE__, k, seekpos + 1) ; + exit (1) ; + } ; + + seekpos = (int) sf_seek (file, 0, SEEK_CUR) + BUFFER_SIZE / 5 ; + k = (int) sf_seek (file, BUFFER_SIZE / 5, SEEK_CUR) ; + test_readf_double_or_die (file, 0, data, 1, __LINE__) ; + if (error_function (data [0], orig [seekpos * channels], margin) || k != seekpos) + { printf ("\nLine %d: sf_seek (forwards, SEEK_CUR) followed by sf_readf_double failed (%f, %f) (%d, %d).\n", __LINE__, data [0], orig [seekpos * channels], k, seekpos + 1) ; + exit (1) ; + } ; + + seekpos = (int) sf_seek (file, 0, SEEK_CUR) - 20 ; + /* Check seek backward from current position. */ + k = (int) sf_seek (file, -20, SEEK_CUR) ; + test_readf_double_or_die (file, 0, data, 1, __LINE__) ; + if (error_function (data [0], orig [seekpos * channels], margin) || k != seekpos) + { printf ("\nLine %d: sf_seek (backwards, SEEK_CUR) followed by sf_readf_double failed (%f, %f) (%d, %d).\n", __LINE__, data [0], orig [seekpos * channels], k, seekpos) ; + exit (1) ; + } ; + + /* Check that read past end of file returns number of items. */ + sf_seek (file, sfinfo.frames, SEEK_SET) ; + + if ((k = (int) sf_readf_double (file, data, datalen)) != 0) + { printf ("\n\nLine %d: Return value from sf_readf_double past end of file incorrect (%d).\n", __LINE__, k) ; + exit (1) ; + } ; + + /* Check seek backward from end. */ + if ((k = (int) sf_seek (file, 5 - sfinfo.frames, SEEK_END)) != 5) + { printf ("\n\nLine %d: sf_seek (SEEK_END) returned %d instead of %d.\n", __LINE__, k, 5) ; + exit (1) ; + } ; + + test_readf_double_or_die (file, 0, data, 1, __LINE__) ; + if (error_function (data [0], orig [5 * channels], margin)) + { printf ("\nLine %d: sf_seek (SEEK_END) followed by sf_readf_short failed (%f should be %f).\n", __LINE__, data [0], orig [5 * channels]) ; + exit (1) ; + } ; + + sf_close (file) ; + + unlink (filename) ; + printf ("ok\n") ; +} /* lcomp_test_double */ + +/*======================================================================================== +** Smoothed differential loss compression tests. +*/ + +static void +sdlcomp_test_short (const char *filename, int filetype, int channels, double margin) +{ SNDFILE *file ; + SF_INFO sfinfo ; + int k, m, seekpos, half_max_abs ; + sf_count_t datalen ; + short *orig, *data, *smooth ; + +channels = 1 ; + + get_unique_test_name (&filename, LCT_TEST_PREFIX) ; + print_test_name ("sdlcomp_test_short", filename) ; + + datalen = BUFFER_SIZE ; + + orig = orig_buffer.s ; + data = data_buffer.s ; + smooth = smooth_buffer.s ; + + gen_signal_double (orig_buffer.d, 32000.0, channels, (int) datalen) ; + for (k = 0 ; k < datalen ; k++) + orig [k] = (short) lrint (orig_buffer.d [k]) ; + + sfinfo.samplerate = SAMPLE_RATE ; + sfinfo.frames = 123456789 ; /* Ridiculous value. */ + sfinfo.channels = channels ; + sfinfo.format = filetype ; + + /* The Vorbis encoder has a bug on PowerPC and X86-64 with sample rates + ** <= 22050. Increasing the sample rate to 32000 avoids triggering it. + ** See https://trac.xiph.org/ticket/1229 + ** + ** Opus only supports discrete sample rates. Choose supported 12000. + */ + if ((file = sf_open (filename, SFM_WRITE, &sfinfo)) == NULL) + { const char * errstr ; + + errstr = sf_strerror (NULL) ; + if (strstr (errstr, "Sample rate chosen is known to trigger a Vorbis") != NULL) + { printf ("\n Sample rate -> 32kHz ") ; + sfinfo.samplerate = 32000 ; + } + else if (strstr (errstr, "Opus only supports sample rates of") != NULL) + { printf ("\n Sample rate -> 12kHz ") ; + sfinfo.samplerate = 12000 ; + } + else + { printf ("Line %d: sf_open_fd (SFM_WRITE) failed : %s\n", __LINE__, errstr) ; + dump_log_buffer (NULL) ; + exit (1) ; + } ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + } ; + + if ((filetype & SF_FORMAT_SUBMASK) == SF_FORMAT_OPUS && !check_opus_version (file)) + { sf_close (file) ; + unlink (filename) ; + return ; + } ; + + test_write_short_or_die (file, 0, orig, datalen, __LINE__) ; + sf_set_string (file, SF_STR_COMMENT, long_comment) ; + sf_close (file) ; + + memset (data, 0, datalen * sizeof (short)) ; + + if ((filetype & SF_FORMAT_TYPEMASK) != SF_FORMAT_RAW) + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + + if (sfinfo.format != filetype) + { printf ("\n\nLine %d: Returned format incorrect (0x%08X => 0x%08X).\n", __LINE__, filetype, sfinfo.format) ; + exit (1) ; + } ; + + if (sfinfo.frames < datalen / channels) + { printf ("Too few.frames in file. (%" PRId64 " should be a little more than %" PRId64 ")\n", datalen, sfinfo.frames) ; + exit (1) ; + } ; + + if (sfinfo.frames > (datalen + 400)) + { printf ("Too many.frames in file. (%" PRId64 " should be a little more than %" PRId64 ")\n", sfinfo.frames, datalen) ; + exit (1) ; + } ; + + if (sfinfo.channels != channels) + { printf ("Incorrect number of channels in file.\n") ; + exit (1) ; + } ; + + check_comment (file, filetype, __LINE__) ; + + sf_command (file, SFC_SET_NORM_FLOAT, NULL, SF_FALSE) ; + + check_log_buffer_or_die (file, __LINE__) ; + + test_readf_short_or_die (file, 0, data, datalen, __LINE__) ; + + memcpy (smooth, orig, datalen * sizeof (short)) ; + smoothed_diff_short (data, (unsigned int) datalen) ; + smoothed_diff_short (smooth, (unsigned int) datalen) ; + + half_max_abs = 0 ; + for (k = 0 ; k < datalen ; k++) + { if (error_function (1.0 * data [k], 1.0 * smooth [k], margin)) + { printf ("\nLine %d: Incorrect sample (#%d : %d should be %d).\n", __LINE__, k, data [k], smooth [k]) ; + oct_save_short (orig, smooth, (int) datalen) ; + exit (1) ; + } ; + half_max_abs = (int) (LCT_MAX (half_max_abs, ABS (0.5 * data [k]))) ; + } ; + + if (half_max_abs < 1) + { printf ("\n\nLine %d: Signal is all zeros.\n", __LINE__) ; + exit (1) ; + } ; + + if ((k = (int) sf_read_short (file, data, datalen)) != sfinfo.frames - datalen) + { printf ("\n\nLine %d: Incorrect read length (%d should be %" PRId64 ").\n", __LINE__, k, sfinfo.frames - datalen) ; + exit (1) ; + } ; + + if ((sfinfo.format & SF_FORMAT_SUBMASK) != SF_FORMAT_MS_ADPCM && + (sfinfo.format & SF_FORMAT_SUBMASK) != SF_FORMAT_GSM610) + for (k = 0 ; k < sfinfo.frames - datalen ; k++) + if (ABS (data [k]) > decay_response (k)) + { printf ("\n\nLine %d: Incorrect sample (#%" PRId64 " : abs (%d) should be < %d).\n", __LINE__, datalen + k, data [k], decay_response (k)) ; + exit (1) ; + } ; + + /* Now test sf_seek function. */ + if (sfinfo.seekable) + { if ((k = (int) sf_seek (file, 0, SEEK_SET)) != 0) + { printf ("\n\nLine %d: Seek to start of file failed (%d).\n", __LINE__, k) ; + exit (1) ; + } ; + + for (m = 0 ; m < 3 ; m++) + { test_readf_short_or_die (file, m, data, datalen / 7, __LINE__) ; + + smoothed_diff_short (data, (unsigned int) (datalen / 7)) ; + memcpy (smooth, orig + m * datalen / 7, datalen / 7 * sizeof (short)) ; + smoothed_diff_short (smooth, (unsigned int) (datalen / 7)) ; + + for (k = 0 ; k < datalen / 7 ; k++) + if (error_function (1.0 * data [k], 1.0 * smooth [k], margin)) + { printf ("\nLine %d: Incorrect sample C (#%d (%" PRId64 ") : %d => %d).\n", __LINE__, k, k + m * (datalen / 7), smooth [k], data [k]) ; + for (m = 0 ; m < 10 ; m++) + printf ("%d ", data [k]) ; + printf ("\n") ; + exit (1) ; + } ; + } ; /* for (m = 0 ; m < 3 ; m++) */ + + seekpos = BUFFER_SIZE / 10 ; + + /* Check seek from start of file. */ + if ((k = (int) sf_seek (file, seekpos, SEEK_SET)) != seekpos) + { printf ("Seek to start of file + %d failed (%d).\n", seekpos, k) ; + exit (1) ; + } ; + test_readf_short_or_die (file, 0, data, 1, __LINE__) ; + + if (error_function (1.0 * data [0], 1.0 * orig [seekpos * channels], margin)) + { printf ("\nLine %d: sf_seek (SEEK_SET) followed by sf_read_short failed (%d, %d).\n", __LINE__, orig [1], data [0]) ; + exit (1) ; + } ; + + if ((k = (int) sf_seek (file, 0, SEEK_CUR)) != seekpos + 1) + { printf ("\n\nLine %d: sf_seek (SEEK_CUR) with 0 offset failed (%d should be %d)\n", __LINE__, k, seekpos + 1) ; + exit (1) ; + } ; + + seekpos = (int) sf_seek (file, 0, SEEK_CUR) + BUFFER_SIZE / 5 ; + k = (int) sf_seek (file, BUFFER_SIZE / 5, SEEK_CUR) ; + test_readf_short_or_die (file, 0, data, 1, __LINE__) ; + if (error_function (1.0 * data [0], 1.0 * orig [seekpos * channels], margin) || k != seekpos) + { printf ("\nLine %d: sf_seek (forwards, SEEK_CUR) followed by sf_read_short failed (%d, %d) (%d, %d).\n", __LINE__, data [0], orig [seekpos * channels], k, seekpos + 1) ; + exit (1) ; + } ; + + seekpos = (int) sf_seek (file, 0, SEEK_CUR) - 20 ; + /* Check seek backward from current position. */ + k = (int) sf_seek (file, -20, SEEK_CUR) ; + test_readf_short_or_die (file, 0, data, 1, __LINE__) ; + if (error_function (1.0 * data [0], 1.0 * orig [seekpos * channels], margin) || k != seekpos) + { printf ("\nLine %d: sf_seek (backwards, SEEK_CUR) followed by sf_read_short failed (%d, %d) (%d, %d).\n", __LINE__, data [0], orig [seekpos * channels], k, seekpos) ; + exit (1) ; + } ; + + /* Check that read past end of file returns number of items. */ + sf_seek (file, sfinfo.frames, SEEK_SET) ; + + if ((k = (int) sf_read_short (file, data, datalen)) != 0) + { printf ("\n\nLine %d: Return value from sf_read_short past end of file incorrect (%d).\n", __LINE__, k) ; + exit (1) ; + } ; + + /* Check seek backward from end. */ + + if ((k = (int) sf_seek (file, 5 - sfinfo.frames, SEEK_END)) != 5) + { printf ("\n\nLine %d: sf_seek (SEEK_END) returned %d instead of %d.\n", __LINE__, k, 5) ; + exit (1) ; + } ; + + test_read_short_or_die (file, 0, data, channels, __LINE__) ; + if (error_function (1.0 * data [0], 1.0 * orig [5 * channels], margin)) + { printf ("\nLine %d: sf_seek (SEEK_END) followed by sf_read_short failed (%d should be %d).\n", __LINE__, data [0], orig [5 * channels]) ; + exit (1) ; + } ; + } /* if (sfinfo.seekable) */ + + sf_close (file) ; + + unlink (filename) ; + printf ("ok\n") ; +} /* sdlcomp_test_short */ + +static void +sdlcomp_test_int (const char *filename, int filetype, int channels, double margin) +{ SNDFILE *file ; + SF_INFO sfinfo ; + int k, m, seekpos, half_max_abs ; + sf_count_t datalen ; + int *orig, *data, *smooth ; + double scale ; + +channels = 1 ; + + get_unique_test_name (&filename, LCT_TEST_PREFIX) ; + print_test_name ("sdlcomp_test_int", filename) ; + + datalen = BUFFER_SIZE ; + scale = 1.0 * 0x10000 ; + + orig = orig_buffer.i ; + data = data_buffer.i ; + smooth = smooth_buffer.i ; + + gen_signal_double (orig_buffer.d, 32000.0 * scale, channels, (int) datalen) ; + for (k = 0 ; k < datalen ; k++) + orig [k] = lrint (orig_buffer.d [k]) ; + + sfinfo.samplerate = SAMPLE_RATE ; + sfinfo.frames = 123456789 ; /* Ridiculous value. */ + sfinfo.channels = channels ; + sfinfo.format = filetype ; + + /* The Vorbis encoder has a bug on PowerPC and X86-64 with sample rates + ** <= 22050. Increasing the sample rate to 32000 avoids triggering it. + ** See https://trac.xiph.org/ticket/1229 + ** + ** Opus only supports discrete sample rates. Choose supported 12000. + */ + if ((file = sf_open (filename, SFM_WRITE, &sfinfo)) == NULL) + { const char * errstr ; + + errstr = sf_strerror (NULL) ; + if (strstr (errstr, "Sample rate chosen is known to trigger a Vorbis") != NULL) + { printf ("\n Sample rate -> 32kHz ") ; + sfinfo.samplerate = 32000 ; + } + else if (strstr (errstr, "Opus only supports sample rates of") != NULL) + { printf ("\n Sample rate -> 12kHz ") ; + sfinfo.samplerate = 12000 ; + } + else + { printf ("Line %d: sf_open_fd (SFM_WRITE) failed : %s\n", __LINE__, errstr) ; + dump_log_buffer (NULL) ; + exit (1) ; + } ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + } ; + + if ((filetype & SF_FORMAT_SUBMASK) == SF_FORMAT_OPUS && !check_opus_version (file)) + { sf_close (file) ; + unlink (filename) ; + return ; + } ; + + test_writef_int_or_die (file, 0, orig, datalen, __LINE__) ; + sf_set_string (file, SF_STR_COMMENT, long_comment) ; + sf_close (file) ; + + memset (data, 0, datalen * sizeof (int)) ; + + if ((filetype & SF_FORMAT_TYPEMASK) != SF_FORMAT_RAW) + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + + if (sfinfo.format != filetype) + { printf ("Returned format incorrect (0x%08X => 0x%08X).\n", filetype, sfinfo.format) ; + exit (1) ; + } ; + + if (sfinfo.frames < datalen / channels) + { printf ("Too few.frames in file. (%" PRId64 " should be a little more than %" PRId64 ")\n", datalen, sfinfo.frames) ; + exit (1) ; + } ; + + if (sfinfo.frames > (datalen + 400)) + { printf ("Too many.frames in file. (%" PRId64 " should be a little more than %" PRId64 ")\n", sfinfo.frames, datalen) ; + exit (1) ; + } ; + + if (sfinfo.channels != channels) + { printf ("Incorrect number of channels in file.\n") ; + exit (1) ; + } ; + + check_log_buffer_or_die (file, __LINE__) ; + + test_readf_int_or_die (file, 0, data, datalen, __LINE__) ; + + memcpy (smooth, orig, datalen * sizeof (int)) ; + smoothed_diff_int (data, (unsigned int) datalen) ; + smoothed_diff_int (smooth, (unsigned int) datalen) ; + + half_max_abs = abs (data [0] >> 16) ; + for (k = 1 ; k < datalen ; k++) + { if (error_function (data [k] / scale, smooth [k] / scale, margin)) + { printf ("\nLine %d: Incorrect sample (#%d : %d should be %d).\n", __LINE__, k, data [k], smooth [k]) ; + oct_save_int (orig, smooth, (int) datalen) ; + exit (1) ; + } ; + half_max_abs = LCT_MAX (half_max_abs, abs (data [k] / 2)) ; + } ; + + if (half_max_abs < 1) + { printf ("\n\nLine %d: Signal is all zeros.\n", __LINE__) ; + exit (1) ; + } ; + + if ((k = (int) sf_readf_int (file, data, datalen)) != sfinfo.frames - datalen) + { printf ("\n\nLine %d: Incorrect read length (%d should be %" PRId64 ").\n", __LINE__, k, sfinfo.frames - datalen) ; + exit (1) ; + } ; + + if ((sfinfo.format & SF_FORMAT_SUBMASK) != SF_FORMAT_IMA_ADPCM && + (sfinfo.format & SF_FORMAT_SUBMASK) != SF_FORMAT_MS_ADPCM && + (sfinfo.format & SF_FORMAT_SUBMASK) != SF_FORMAT_GSM610 && + (sfinfo.format & SF_FORMAT_SUBMASK) != SF_FORMAT_G721_32 && + (sfinfo.format & SF_FORMAT_SUBMASK) != SF_FORMAT_G723_24 && + (sfinfo.format & SF_FORMAT_SUBMASK) != SF_FORMAT_NMS_ADPCM_16 && + (sfinfo.format & SF_FORMAT_SUBMASK) != SF_FORMAT_NMS_ADPCM_24 && + (sfinfo.format & SF_FORMAT_SUBMASK) != SF_FORMAT_NMS_ADPCM_32) + for (k = 0 ; k < sfinfo.frames - datalen ; k++) + if (abs (data [k]) > decay_response (k)) + { printf ("\n\nLine %d: Incorrect sample (#%" PRId64 " : abs (%d) should be < %d).\n", __LINE__, datalen + k, data [k], decay_response (k)) ; + exit (1) ; + } ; + + /* Now test sf_seek function. */ + if (sfinfo.seekable) + { if ((k = (int) sf_seek (file, 0, SEEK_SET)) != 0) + { printf ("\n\nLine %d: Seek to start of file failed (%d).\n", __LINE__, k) ; + exit (1) ; + } ; + + for (m = 0 ; m < 3 ; m++) + { test_readf_int_or_die (file, m, data, datalen / 7, __LINE__) ; + + smoothed_diff_int (data, (unsigned int) (datalen / 7)) ; + memcpy (smooth, orig + m * datalen / 7, datalen / 7 * sizeof (int)) ; + smoothed_diff_int (smooth, (unsigned int) (datalen / 7)) ; + + for (k = 0 ; k < datalen / 7 ; k++) + if (error_function (data [k] / scale, smooth [k] / scale, margin)) + { printf ("\nLine %d: Incorrect sample (#%d (%" PRId64 ") : %d => %d).\n", __LINE__, k, k + m * (datalen / 7), smooth [k], data [k]) ; + for (m = 0 ; m < 10 ; m++) + printf ("%d ", data [k]) ; + printf ("\n") ; + exit (1) ; + } ; + } ; /* for (m = 0 ; m < 3 ; m++) */ + + seekpos = BUFFER_SIZE / 10 ; + + /* Check seek from start of file. */ + if ((k = (int) sf_seek (file, seekpos, SEEK_SET)) != seekpos) + { printf ("Seek to start of file + %d failed (%d).\n", seekpos, k) ; + exit (1) ; + } ; + test_readf_int_or_die (file, 0, data, 1, __LINE__) ; + + if (error_function (1.0 * data [0], 1.0 * orig [seekpos * channels], margin)) + { printf ("\nLine %d: sf_seek (SEEK_SET) followed by sf_readf_int failed (%d, %d).\n", __LINE__, orig [1], data [0]) ; + exit (1) ; + } ; + + if ((k = (int) sf_seek (file, 0, SEEK_CUR)) != seekpos + 1) + { printf ("\n\nLine %d: sf_seek (SEEK_CUR) with 0 offset failed (%d should be %d)\n", __LINE__, k, seekpos + 1) ; + exit (1) ; + } ; + + seekpos = (int) sf_seek (file, 0, SEEK_CUR) + BUFFER_SIZE / 5 ; + k = (int) sf_seek (file, BUFFER_SIZE / 5, SEEK_CUR) ; + test_readf_int_or_die (file, 0, data, 1, __LINE__) ; + if (error_function (1.0 * data [0], 1.0 * orig [seekpos * channels], margin) || k != seekpos) + { printf ("\nLine %d: sf_seek (forwards, SEEK_CUR) followed by sf_readf_int failed (%d, %d) (%d, %d).\n", __LINE__, data [0], orig [seekpos * channels], k, seekpos + 1) ; + exit (1) ; + } ; + + seekpos = (int) sf_seek (file, 0, SEEK_CUR) - 20 ; + /* Check seek backward from current position. */ + k = (int) sf_seek (file, -20, SEEK_CUR) ; + test_readf_int_or_die (file, 0, data, 1, __LINE__) ; + if (error_function (1.0 * data [0], 1.0 * orig [seekpos * channels], margin) || k != seekpos) + { printf ("\nLine %d: sf_seek (backwards, SEEK_CUR) followed by sf_readf_int failed (%d, %d) (%d, %d).\n", __LINE__, data [0], orig [seekpos * channels], k, seekpos) ; + exit (1) ; + } ; + + /* Check that read past end of file returns number of items. */ + sf_seek (file, sfinfo.frames, SEEK_SET) ; + + if ((k = (int) sf_readf_int (file, data, datalen)) != 0) + { printf ("\n\nLine %d: Return value from sf_readf_int past end of file incorrect (%d).\n", __LINE__, k) ; + exit (1) ; + } ; + + /* Check seek backward from end. */ + + if ((k = (int) sf_seek (file, 5 - sfinfo.frames, SEEK_END)) != 5) + { printf ("\n\nLine %d: sf_seek (SEEK_END) returned %d instead of %d.\n", __LINE__, k, 5) ; + exit (1) ; + } ; + + test_readf_int_or_die (file, 0, data, 1, __LINE__) ; + if (error_function (data [0] / scale, orig [5] / scale, margin)) + { printf ("\nLine %d: sf_seek (SEEK_END) followed by sf_readf_int failed (%d should be %d).\n", __LINE__, data [0], orig [5]) ; + exit (1) ; + } ; + } /* if (sfinfo.seekable) */ + + sf_close (file) ; + + unlink (filename) ; + printf ("ok\n") ; +} /* sdlcomp_test_int */ + +static void +sdlcomp_test_float (const char *filename, int filetype, int channels, double margin) +{ SNDFILE *file ; + SF_INFO sfinfo ; + int k, m, seekpos ; + sf_count_t datalen ; + float *orig, *data, *smooth ; + double half_max_abs , scale ; + +channels = 1 ; + + get_unique_test_name (&filename, LCT_TEST_PREFIX) ; + print_test_name ("sdlcomp_test_float", filename) ; + + switch ((filetype & SF_FORMAT_SUBMASK)) + { case SF_FORMAT_VORBIS : + /* Vorbis starts to loose fidelity with floating point values outside + ** the range of approximately [-2000.0, 2000.0] (Determined + ** experimentally, not know if it is a limitation of Vorbis or + ** libvorbis.) + */ + scale = 16.0 ; /* 32000/16 = 2000 */ + break ; + + case SF_FORMAT_OPUS : + /* The Opus spec says that non-normalized floating point value + ** support (extended dynamic range in its terms) is optional and + ** cannot be relied upon. + */ + scale = 32000.0 ; /* 32000/32000 = 1 */ + break ; + + default : + scale = 1.0 ; + break ; + } ; + + datalen = BUFFER_SIZE ; + + orig = orig_buffer.f ; + data = data_buffer.f ; + smooth = smooth_buffer.f ; + + gen_signal_double (orig_buffer.d, 32000.0 / scale, channels, (int) datalen) ; + for (k = 0 ; k < datalen ; k++) + orig [k] = (float) orig_buffer.d [k] ; + + sfinfo.samplerate = SAMPLE_RATE ; + sfinfo.frames = 123456789 ; /* Ridiculous value. */ + sfinfo.channels = channels ; + sfinfo.format = filetype ; + + + /* The Vorbis encoder has a bug on PowerPC and X86-64 with sample rates + ** <= 22050. Increasing the sample rate to 32000 avoids triggering it. + ** See https://trac.xiph.org/ticket/1229 + ** + ** Opus only supports discrete sample rates. Choose supported 12000. + */ + if ((file = sf_open (filename, SFM_WRITE, &sfinfo)) == NULL) + { const char * errstr ; + + errstr = sf_strerror (NULL) ; + if (strstr (errstr, "Sample rate chosen is known to trigger a Vorbis") != NULL) + { printf ("\n Sample rate -> 32kHz ") ; + sfinfo.samplerate = 32000 ; + } + else if (strstr (errstr, "Opus only supports sample rates of") != NULL) + { printf ("\n Sample rate -> 12kHz ") ; + sfinfo.samplerate = 12000 ; + } + else + { printf ("Line %d: sf_open_fd (SFM_WRITE) failed : %s\n", __LINE__, errstr) ; + dump_log_buffer (NULL) ; + exit (1) ; + } ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + } ; + + if ((filetype & SF_FORMAT_SUBMASK) == SF_FORMAT_OPUS && !check_opus_version (file)) + { sf_close (file) ; + unlink (filename) ; + return ; + } ; + + sf_command (file, SFC_SET_NORM_FLOAT, NULL, SF_FALSE) ; + test_write_float_or_die (file, 0, orig, datalen, __LINE__) ; + sf_set_string (file, SF_STR_COMMENT, long_comment) ; + sf_close (file) ; + + memset (data, 0, datalen * sizeof (float)) ; + + if ((filetype & SF_FORMAT_TYPEMASK) != SF_FORMAT_RAW) + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + + if ((sfinfo.format & (SF_FORMAT_TYPEMASK | SF_FORMAT_SUBMASK)) != (filetype & (SF_FORMAT_TYPEMASK | SF_FORMAT_SUBMASK))) + { printf ("\n\nLine %d: Returned format incorrect (0x%08X => 0x%08X).\n", __LINE__, filetype, sfinfo.format) ; + exit (1) ; + } ; + + if (sfinfo.frames < datalen / channels) + { printf ("Too few.frames in file. (%" PRId64 " should be a little more than %" PRId64 ")\n", datalen, sfinfo.frames) ; + exit (1) ; + } ; + + if (sfinfo.frames > (datalen + 400)) + { printf ("Too many.frames in file. (%" PRId64 " should be a little more than %" PRId64 ")\n", sfinfo.frames, datalen) ; + exit (1) ; + } ; + + if (sfinfo.channels != channels) + { printf ("Incorrect number of channels in file.\n") ; + exit (1) ; + } ; + + check_comment (file, filetype, __LINE__) ; + + sf_command (file, SFC_SET_NORM_FLOAT, NULL, SF_FALSE) ; + + check_log_buffer_or_die (file, __LINE__) ; + + test_read_float_or_die (file, 0, data, datalen, __LINE__) ; + + memcpy (smooth, orig, datalen * sizeof (float)) ; + smoothed_diff_float (data, (unsigned int) datalen) ; + smoothed_diff_float (smooth, (unsigned int) datalen) ; + + half_max_abs = fabs (data [0]) ; + for (k = 1 ; k < datalen ; k++) + { if (error_function (data [k] * scale, smooth [k] * scale, margin)) + { printf ("\nLine %d: Incorrect sample (#%d : %d should be %d).\n", __LINE__, k, (int) (data [k] * scale), (int) (smooth [k] * scale)) ; + oct_save_float (orig, smooth, (int) datalen) ; + exit (1) ; + } ; + half_max_abs = LCT_MAX (half_max_abs, ABS (0.5 * data [k] * scale)) ; + } ; + + if (half_max_abs <= 0.0) + { printf ("\n\nLine %d: Signal is all zeros.\n", __LINE__) ; + printf ("half_max_abs : % 10.6f\n", half_max_abs) ; + exit (1) ; + } ; + + if ((k = (int) sf_read_float (file, data, datalen)) != sfinfo.frames - datalen) + { printf ("\n\nLine %d: Incorrect read length (%d should be %" PRId64 ").\n", __LINE__, k, sfinfo.frames - datalen) ; + exit (1) ; + } ; + + if ((sfinfo.format & SF_FORMAT_SUBMASK) != SF_FORMAT_MS_ADPCM && + (sfinfo.format & SF_FORMAT_SUBMASK) != SF_FORMAT_GSM610) + for (k = 0 ; k < sfinfo.frames - datalen ; k++) + if (ABS (data [k]) > decay_response (k)) + { printf ("\n\nLine %d: Incorrect sample (#%" PRId64 " : abs (%d) should be < %d).\n", __LINE__, datalen + k, (int) data [k], (int) decay_response (k)) ; + exit (1) ; + } ; + + /* Now test sf_seek function. */ + if (sfinfo.seekable) + { if ((k = (int) sf_seek (file, 0, SEEK_SET)) != 0) + { printf ("\n\nLine %d: Seek to start of file failed (%d).\n", __LINE__, k) ; + exit (1) ; + } ; + + for (m = 0 ; m < 3 ; m++) + { test_read_float_or_die (file, 0, data, datalen / 7, __LINE__) ; + + smoothed_diff_float (data, (unsigned int) (datalen / 7)) ; + memcpy (smooth, orig + m * datalen / 7, datalen / 7 * sizeof (float)) ; + smoothed_diff_float (smooth, (unsigned int) (datalen / 7)) ; + + for (k = 0 ; k < datalen / 7 ; k++) + if (error_function (data [k] * scale, smooth [k] * scale, margin)) + { printf ("\nLine %d: Incorrect sample C (#%d (%" PRId64 ") : %d => %d).\n", __LINE__, k, k + m * (datalen / 7), (int) (smooth [k] * scale), (int) (data [k] * scale)) ; + for (m = 0 ; m < 10 ; m++) + printf ("%d ", (int) data [k]) ; + printf ("\n") ; + exit (1) ; + } ; + } ; /* for (m = 0 ; m < 3 ; m++) */ + + seekpos = BUFFER_SIZE / 10 ; + + /* Check seek from start of file. */ + if ((k = (int) sf_seek (file, seekpos, SEEK_SET)) != seekpos) + { printf ("Seek to start of file + %d failed (%d).\n", seekpos, k) ; + exit (1) ; + } ; + test_read_float_or_die (file, 0, data, channels, __LINE__) ; + + if (error_function (data [0] * scale, orig [seekpos * channels] * scale, margin)) + { printf ("\nLine %d: sf_seek (SEEK_SET) followed by sf_read_float failed (%d, %d).\n", __LINE__, (int) (orig [1] * scale), (int) (data [0] * scale)) ; + exit (1) ; + } ; + + if ((k = (int) sf_seek (file, 0, SEEK_CUR)) != seekpos + 1) + { printf ("\n\nLine %d: sf_seek (SEEK_CUR) with 0 offset failed (%d should be %d)\n", __LINE__, k, seekpos + 1) ; + exit (1) ; + } ; + + seekpos = (int) sf_seek (file, 0, SEEK_CUR) + BUFFER_SIZE / 5 ; + k = (int) sf_seek (file, BUFFER_SIZE / 5, SEEK_CUR) ; + test_read_float_or_die (file, 0, data, channels, __LINE__) ; + if (error_function (data [0] * scale, orig [seekpos * channels] * scale, margin) || k != seekpos) + { printf ("\nLine %d: sf_seek (forwards, SEEK_CUR) followed by sf_read_float failed (%d, %d) (%d, %d).\n", __LINE__, (int) (data [0] * scale), (int) (orig [seekpos * channels] * scale), k, seekpos + 1) ; + exit (1) ; + } ; + + seekpos = (int) sf_seek (file, 0, SEEK_CUR) - 20 ; + /* Check seek backward from current position. */ + k = (int) sf_seek (file, -20, SEEK_CUR) ; + test_read_float_or_die (file, 0, data, channels, __LINE__) ; + if (error_function (data [0] * scale, orig [seekpos * channels] * scale, margin) || k != seekpos) + { printf ("\nLine %d: sf_seek (backwards, SEEK_CUR) followed by sf_read_float failed (%d, %d) (%d, %d).\n", __LINE__, (int) (data [0] * scale), (int) (orig [seekpos * channels] * scale), k, seekpos) ; + exit (1) ; + } ; + + /* Check that read past end of file returns number of items. */ + sf_seek (file, sfinfo.frames, SEEK_SET) ; + + if ((k = (int) sf_read_float (file, data, datalen)) != 0) + { printf ("\n\nLine %d: Return value from sf_read_float past end of file incorrect (%d).\n", __LINE__, k) ; + exit (1) ; + } ; + + /* Check seek backward from end. */ + + if ((k = (int) sf_seek (file, 5 - sfinfo.frames, SEEK_END)) != 5) + { printf ("\n\nLine %d: sf_seek (SEEK_END) returned %d instead of %d.\n", __LINE__, k, 5) ; + exit (1) ; + } ; + + test_read_float_or_die (file, 0, data, channels, __LINE__) ; + if (error_function (data [0] * scale, orig [5 * channels] * scale, margin)) + { printf ("\nLine %d: sf_seek (SEEK_END) followed by sf_read_float failed (%f should be %f).\n", __LINE__, data [0] * scale, orig [5 * channels] * scale) ; + exit (1) ; + } ; + } /* if (sfinfo.seekable) */ + + sf_close (file) ; + + unlink (filename) ; + printf ("ok\n") ; +} /* sdlcomp_test_float */ + +static void +sdlcomp_test_double (const char *filename, int filetype, int channels, double margin) +{ SNDFILE *file ; + SF_INFO sfinfo ; + int k, m, seekpos ; + sf_count_t datalen ; + double *orig, *data, *smooth, half_max_abs, scale ; + +channels = 1 ; + + get_unique_test_name (&filename, LCT_TEST_PREFIX) ; + print_test_name ("sdlcomp_test_double", filename) ; + + switch ((filetype & SF_FORMAT_SUBMASK)) + { case SF_FORMAT_VORBIS : + /* Vorbis starts to loose fidelity with floating point values outside + ** the range of approximately [-2000.0, 2000.0] (Determined + ** experimentally, not know if it is a limitation of Vorbis or + ** libvorbis.) + */ + scale = 16.0 ; /* 32000/16 = 2000 */ + break ; + + case SF_FORMAT_OPUS : + /* The Opus spec says that non-normalized floating point value + ** support (extended dynamic range in its terms) is optional and + ** cannot be relied upon. + */ + scale = 32000.0 ; /* 32000/32000 = 1 */ + break ; + + default : + scale = 1.0 ; + break ; + } ; + + datalen = BUFFER_SIZE ; + + orig = orig_buffer.d ; + data = data_buffer.d ; + smooth = smooth_buffer.d ; + + gen_signal_double (orig_buffer.d, 32000.0 / scale, channels, (int) datalen) ; + + sfinfo.samplerate = SAMPLE_RATE ; + sfinfo.frames = 123456789 ; /* Ridiculous value. */ + sfinfo.channels = channels ; + sfinfo.format = filetype ; + + /* The Vorbis encoder has a bug on PowerPC and X86-64 with sample rates + ** <= 22050. Increasing the sample rate to 32000 avoids triggering it. + ** See https://trac.xiph.org/ticket/1229 + ** + ** Opus only supports discrete sample rates. Choose supported 12000. + */ + if ((file = sf_open (filename, SFM_WRITE, &sfinfo)) == NULL) + { const char * errstr ; + + errstr = sf_strerror (NULL) ; + if (strstr (errstr, "Sample rate chosen is known to trigger a Vorbis") != NULL) + { printf ("\n Sample rate -> 32kHz ") ; + sfinfo.samplerate = 32000 ; + } + else if (strstr (errstr, "Opus only supports sample rates of") != NULL) + { printf ("\n Sample rate -> 12kHz ") ; + sfinfo.samplerate = 12000 ; + } + else + { printf ("Line %d: sf_open_fd (SFM_WRITE) failed : %s\n", __LINE__, errstr) ; + dump_log_buffer (NULL) ; + exit (1) ; + } ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + } ; + + if ((filetype & SF_FORMAT_SUBMASK) == SF_FORMAT_OPUS && !check_opus_version (file)) + { sf_close (file) ; + unlink (filename) ; + return ; + } ; + + sf_command (file, SFC_SET_NORM_DOUBLE, NULL, SF_FALSE) ; + test_write_double_or_die (file, 0, orig, datalen, __LINE__) ; + sf_set_string (file, SF_STR_COMMENT, long_comment) ; + sf_close (file) ; + + memset (data, 0, datalen * sizeof (double)) ; + + if ((filetype & SF_FORMAT_TYPEMASK) != SF_FORMAT_RAW) + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + + if (sfinfo.format != filetype) + { printf ("Returned format incorrect (0x%08X => 0x%08X).\n", filetype, sfinfo.format) ; + exit (1) ; + } ; + + if (sfinfo.frames < datalen / channels) + { printf ("Too few.frames in file. (%" PRId64 " should be a little more than %" PRId64 ")\n", datalen, sfinfo.frames) ; + exit (1) ; + } ; + + if (sfinfo.frames > (datalen + 400)) + { printf ("Too many.frames in file. (%" PRId64 " should be a little more than %" PRId64 ")\n", sfinfo.frames, datalen) ; + exit (1) ; + } ; + + if (sfinfo.channels != channels) + { printf ("Incorrect number of channels in file.\n") ; + exit (1) ; + } ; + + check_comment (file, filetype, __LINE__) ; + + check_comment (file, filetype, __LINE__) ; + + sf_command (file, SFC_SET_NORM_DOUBLE, NULL, SF_FALSE) ; + + check_log_buffer_or_die (file, __LINE__) ; + + test_read_double_or_die (file, 0, data, datalen, __LINE__) ; + + memcpy (smooth, orig, datalen * sizeof (double)) ; + smoothed_diff_double (data, (unsigned int) datalen) ; + smoothed_diff_double (smooth, (unsigned int) datalen) ; + + half_max_abs = 0.0 ; + for (k = 0 ; k < datalen ; k++) + { if (error_function (data [k] * scale, smooth [k] * scale, margin)) + { printf ("\n\nLine %d: Incorrect sample (#%d : %d should be %d).\n", __LINE__, k, (int) (data [k] * scale), (int) (smooth [k] * scale)) ; + oct_save_double (orig, smooth, (int) datalen) ; + exit (1) ; + } ; + half_max_abs = LCT_MAX (half_max_abs, 0.5 * fabs (data [k] * scale)) ; + } ; + + if (half_max_abs < 1.0) + { printf ("\n\nLine %d: Signal is all zeros.\n", __LINE__) ; + exit (1) ; + } ; + + if ((k = (int) sf_read_double (file, data, datalen)) != sfinfo.frames - datalen) + { printf ("\n\nLine %d: Incorrect read length (%d should be %" PRId64 ").\n", __LINE__, k, sfinfo.frames - datalen) ; + exit (1) ; + } ; + + if ((sfinfo.format & SF_FORMAT_SUBMASK) != SF_FORMAT_MS_ADPCM && + (sfinfo.format & SF_FORMAT_SUBMASK) != SF_FORMAT_GSM610) + for (k = 0 ; k < sfinfo.frames - datalen ; k++) + if (ABS (data [k]) > decay_response (k)) + { printf ("\n\nLine %d: Incorrect sample (#%" PRId64 " : abs (%d) should be < %d).\n", __LINE__, datalen + k, (int) data [k], (int) decay_response (k)) ; + exit (1) ; + } ; + + /* Now test sf_seek function. */ + if (sfinfo.seekable) + { if ((k = (int) sf_seek (file, 0, SEEK_SET)) != 0) + { printf ("\n\nLine %d: Seek to start of file failed (%d).\n", __LINE__, k) ; + exit (1) ; + } ; + + for (m = 0 ; m < 3 ; m++) + { test_read_double_or_die (file, m, data, datalen / 7, __LINE__) ; + + smoothed_diff_double (data, (unsigned int) (datalen / 7)) ; + memcpy (smooth, orig + m * datalen / 7, datalen / 7 * sizeof (double)) ; + smoothed_diff_double (smooth, (unsigned int) (datalen / 7)) ; + + for (k = 0 ; k < datalen / 7 ; k++) + if (error_function (data [k] * scale, smooth [k] * scale, margin)) + { printf ("\nLine %d: Incorrect sample C (#%d (%" PRId64 ") : %d => %d).\n", __LINE__, k, k + m * (datalen / 7), (int) (smooth [k] * scale), (int) (data [k] * scale)) ; + for (m = 0 ; m < 10 ; m++) + printf ("%d ", (int) data [k]) ; + printf ("\n") ; + exit (1) ; + } ; + } ; /* for (m = 0 ; m < 3 ; m++) */ + + seekpos = BUFFER_SIZE / 10 ; + + /* Check seek from start of file. */ + if ((k = (int) sf_seek (file, seekpos, SEEK_SET)) != seekpos) + { printf ("Seek to start of file + %d failed (%d).\n", seekpos, k) ; + exit (1) ; + } ; + test_read_double_or_die (file, 0, data, channels, __LINE__) ; + + if (error_function (data [0] * scale, orig [seekpos * channels] * scale, margin)) + { printf ("\nLine %d: sf_seek (SEEK_SET) followed by sf_read_double failed (%d, %d).\n", __LINE__, (int) (orig [1] * scale), (int) (data [0] * scale)) ; + exit (1) ; + } ; + + if ((k = (int) sf_seek (file, 0, SEEK_CUR)) != seekpos + 1) + { printf ("\n\nLine %d: sf_seek (SEEK_CUR) with 0 offset failed (%d should be %d)\n", __LINE__, k, seekpos + 1) ; + exit (1) ; + } ; + + seekpos = (int) sf_seek (file, 0, SEEK_CUR) + BUFFER_SIZE / 5 ; + k = (int) sf_seek (file, BUFFER_SIZE / 5, SEEK_CUR) ; + test_read_double_or_die (file, 0, data, channels, __LINE__) ; + if (error_function (data [0] * scale, orig [seekpos * channels] * scale, margin) || k != seekpos) + { printf ("\nLine %d: sf_seek (forwards, SEEK_CUR) followed by sf_read_double failed (%d, %d) (%d, %d).\n", __LINE__, (int) (data [0] * scale), (int) (orig [seekpos * channels] * scale), k, seekpos + 1) ; + exit (1) ; + } ; + + seekpos = (int) sf_seek (file, 0, SEEK_CUR) - 20 ; + /* Check seek backward from current position. */ + k = (int) sf_seek (file, -20, SEEK_CUR) ; + test_read_double_or_die (file, 0, data, channels, __LINE__) ; + if (error_function (data [0] * scale, orig [seekpos * channels] * scale, margin) || k != seekpos) + { printf ("\nLine %d: sf_seek (backwards, SEEK_CUR) followed by sf_read_double failed (%d, %d) (%d, %d).\n", __LINE__, (int) (data [0] * scale), (int) (orig [seekpos * channels] * scale), k, seekpos) ; + exit (1) ; + } ; + + /* Check that read past end of file returns number of items. */ + sf_seek (file, sfinfo.frames, SEEK_SET) ; + + if ((k = (int) sf_read_double (file, data, datalen)) != 0) + { printf ("\n\nLine %d: Return value from sf_read_double past end of file incorrect (%d).\n", __LINE__, k) ; + exit (1) ; + } ; + + /* Check seek backward from end. */ + + if ((k = (int) sf_seek (file, 5 - sfinfo.frames, SEEK_END)) != 5) + { printf ("\n\nLine %d: sf_seek (SEEK_END) returned %d instead of %d.\n", __LINE__, k, 5) ; + exit (1) ; + } ; + + test_read_double_or_die (file, 0, data, channels, __LINE__) ; + if (error_function (data [0] * scale, orig [5 * channels] * scale, margin)) + { printf ("\nLine %d: sf_seek (SEEK_END) followed by sf_read_double failed (%f should be %f).\n", __LINE__, data [0] * scale, orig [5 * channels] * scale) ; + exit (1) ; + } ; + } /* if (sfinfo.seekable) */ + + sf_close (file) ; + + unlink (filename) ; + printf ("ok\n") ; +} /* sdlcomp_test_double */ + +static void +read_raw_test (const char *filename, int filetype, int channels) +{ SNDFILE *file ; + SF_INFO sfinfo ; + sf_count_t count, datalen ; + short *orig, *data ; + int k ; + + get_unique_test_name (&filename, LCT_TEST_PREFIX) ; + print_test_name ("read_raw_test", filename) ; + + datalen = ARRAY_LEN (orig_buffer.s) / 2 ; + + orig = orig_buffer.s ; + data = data_buffer.s ; + + gen_signal_double (orig_buffer.d, 32000.0, channels, (int) datalen) ; + for (k = 0 ; k < datalen ; k++) + orig [k] = (short) lrint (orig_buffer.d [k]) ; + + sfinfo.samplerate = SAMPLE_RATE ; + sfinfo.frames = 123456789 ; /* Ridiculous value. */ + sfinfo.channels = channels ; + sfinfo.format = filetype ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_FALSE, __LINE__) ; + test_write_short_or_die (file, 0, orig, datalen, __LINE__) ; + sf_set_string (file, SF_STR_COMMENT, long_comment) ; + sf_close (file) ; + + memset (data, 0, datalen * sizeof (double)) ; + + if ((filetype & SF_FORMAT_TYPEMASK) != SF_FORMAT_RAW) + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + + if (sfinfo.format != filetype) + { printf ("Returned format incorrect (0x%08X => 0x%08X).\n", filetype, sfinfo.format) ; + exit (1) ; + } ; + + if (sfinfo.frames < datalen / channels) + { printf ("Too few.frames in file. (%" PRId64 " should be a little more than %" PRId64 ")\n", datalen, sfinfo.frames) ; + exit (1) ; + } ; + + if (sfinfo.frames > (datalen + 400)) + { printf ("Too many.frames in file. (%" PRId64 " should be a little more than %" PRId64 ")\n", sfinfo.frames, datalen) ; + exit (1) ; + } ; + + if (sfinfo.channels != channels) + { printf ("Incorrect number of channels in file.\n") ; + exit (1) ; + } ; + + check_comment (file, filetype, __LINE__) ; + + count = sf_read_raw (file, orig_buffer.c, datalen + 5 * channels) ; + if (count != sfinfo.channels * sfinfo.frames) + { printf ("\nLine %d : sf_read_raw returned %" PRId64 " should be %" PRId64 "\n", __LINE__, count, sfinfo.channels * sfinfo.frames) ; + exit (1) ; + } ; + + sf_close (file) ; + + unlink (filename) ; + printf ("ok\n") ; +} /* read_raw_test */ + +/*======================================================================================== +** Auxiliary functions +*/ + +#define SIGNAL_MAXVAL 30000.0 +#define DECAY_COUNT 1000 + +static int +decay_response (int k) +{ if (k < 1) + return (int) (1.2 * SIGNAL_MAXVAL) ; + if (k > DECAY_COUNT) + return 0 ; + return (int) (1.2 * SIGNAL_MAXVAL * (DECAY_COUNT - k) / (1.0 * DECAY_COUNT)) ; +} /* decay_response */ + +static void +gen_signal_double (double *data, double scale, int channels, int datalen) +{ int k, ramplen ; + double amp = 0.0 ; + + ramplen = DECAY_COUNT ; + + if (channels == 1) + { for (k = 0 ; k < datalen ; k++) + { if (k <= ramplen) + amp = scale * k / ((double) ramplen) ; + else if (k > datalen - ramplen) + amp = scale * (datalen - k) / ((double) ramplen) ; + +/*-printf ("%3d : %g\n", k, amp) ;-*/ + + data [k] = amp * (0.4 * sin (33.3 * 2.0 * M_PI * ((double) (k+1)) / ((double) SAMPLE_RATE)) + + 0.3 * cos (201.1 * 2.0 * M_PI * ((double) (k+1)) / ((double) SAMPLE_RATE))) ; + } ; + } + else + { for (k = 0 ; k < datalen ; k ++) + { if (k <= ramplen) + amp = scale * k / ((double) ramplen) ; + else if (k > datalen - ramplen) + amp = scale * (datalen - k) / ((double) ramplen) ; + + data [2 * k] = amp * (0.4 * sin (33.3 * 2.0 * M_PI * ((double) (k+1)) / ((double) SAMPLE_RATE)) + + 0.3 * cos (201.1 * 2.0 * M_PI * ((double) (k+1)) / ((double) SAMPLE_RATE))) ; + data [2 * k + 1] = amp * (0.4 * sin (55.5 * 2.0 * M_PI * ((double) (k+1)) / ((double) SAMPLE_RATE)) + + 0.3 * cos (201.1 * 2.0 * M_PI * ((double) (k+1)) / ((double) SAMPLE_RATE))) ; + } ; + } ; + + return ; +} /* gen_signal_double */ + +static int +error_function (double data, double orig, double margin) +{ double error ; + + if (fabs (orig) <= 500.0) + error = fabs (fabs (data) - fabs (orig)) / 2000.0 ; + else if (fabs (orig) <= 1000.0) + error = fabs (data - orig) / 3000.0 ; + else + error = fabs (data - orig) / fabs (orig) ; + + if (error > margin) + { printf ("\n\nerror_function (data = %f, orig = %f, margin = %f) -> %f\n", data, orig, margin, error) ; + return 1 ; + } ; + return 0 ; +} /* error_function */ + +static void +smoothed_diff_short (short *data, unsigned int datalen) +{ unsigned int k ; + double memory = 0.0 ; + + /* Calculate the smoothed sample-to-sample difference. */ + for (k = 0 ; k < datalen - 1 ; k++) + { memory = 0.7 * memory + (1 - 0.7) * (double) (data [k+1] - data [k]) ; + data [k] = (short) memory ; + } ; + data [datalen-1] = data [datalen-2] ; + +} /* smoothed_diff_short */ + +static void +smoothed_diff_int (int *data, unsigned int datalen) +{ unsigned int k ; + double memory = 0.0 ; + + /* Calculate the smoothed sample-to-sample difference. */ + for (k = 0 ; k < datalen - 1 ; k++) + { memory = 0.7 * memory + (1 - 0.7) * (double) (data [k+1] - data [k]) ; + data [k] = (int) memory ; + } ; + data [datalen-1] = data [datalen-2] ; + +} /* smoothed_diff_int */ + +static void +smoothed_diff_float (float *data, unsigned int datalen) +{ unsigned int k ; + float memory = 0.0 ; + + /* Calculate the smoothed sample-to-sample difference. */ + for (k = 0 ; k < datalen - 1 ; k++) + { memory = (float) (0.7 * memory + (1 - 0.7) * (data [k+1] - data [k])) ; + data [k] = memory ; + } ; + data [datalen-1] = data [datalen-2] ; + +} /* smoothed_diff_float */ + +static void +smoothed_diff_double (double *data, unsigned int datalen) +{ unsigned int k ; + double memory = 0.0 ; + + /* Calculate the smoothed sample-to-sample difference. */ + for (k = 0 ; k < datalen - 1 ; k++) + { memory = 0.7 * memory + (1 - 0.7) * (data [k+1] - data [k]) ; + data [k] = memory ; + } ; + data [datalen-1] = data [datalen-2] ; + +} /* smoothed_diff_double */ + +static void +check_comment (SNDFILE * file, int format, int lineno) +{ const char *comment ; + + switch (format & SF_FORMAT_TYPEMASK) + { case SF_FORMAT_AIFF : + case SF_FORMAT_WAV : + case SF_FORMAT_WAVEX : + break ; + default : + return ; + } ; + + comment = sf_get_string (file, SF_STR_COMMENT) ; + if (comment == NULL) + { printf ("\n\nLine %d : File does not contain a comment string.\n\n", lineno) ; + exit (1) ; + } ; + + if (strcmp (comment, long_comment) != 0) + { printf ("\n\nLine %d : File comment does not match comment written.\n\n", lineno) ; + exit (1) ; + } ; + + return ; +} /* check_comment */ + +static int +is_lossy (int filetype) +{ + switch (SF_FORMAT_SUBMASK & filetype) + { case SF_FORMAT_PCM_U8 : + case SF_FORMAT_PCM_S8 : + case SF_FORMAT_PCM_16 : + case SF_FORMAT_PCM_24 : + case SF_FORMAT_PCM_32 : + case SF_FORMAT_FLOAT : + case SF_FORMAT_DOUBLE : + return 0 ; + + default : + break ; + } ; + + return 1 ; +} /* is_lossy */ + + +static int +check_opus_version (SNDFILE *file) +{ char log_buf [256] ; + char *str, *p ; + const char *str_libopus = "Opus library version: " ; + int ver_major, ver_minor ; + + sf_command (file, SFC_GET_LOG_INFO, log_buf, sizeof (log_buf)) ; + str = strstr (log_buf, str_libopus) ; + if (str) + { str += strlen (str_libopus) ; + if ((p = strchr (str, '\n'))) + *p = '\0' ; + if (sscanf (str, "libopus %d.%d", &ver_major, &ver_minor) == 2) + { /* Reject versions prior to 1.3 */ + if (ver_major > 1 || (ver_major == 1 && ver_minor >= 3)) + { /* + ** Make sure that the libopus in use is not fixed-point, as it + ** sacrifices accuracy. libopus API documentation explicitly + ** allows checking for this suffix to determine if it is. + */ + if (!strstr (str, "-fixed")) + return 1 ; + } ; + } ; + } ; + + printf ("skipping (%s)\n", str ? str : "unknown libopus version") ; + return 0 ; +} /* check_opus_version */ diff --git a/extern/libsndfile-modified/tests/misc_test.c b/extern/libsndfile-modified/tests/misc_test.c new file mode 100644 index 000000000..31e93d185 --- /dev/null +++ b/extern/libsndfile-modified/tests/misc_test.c @@ -0,0 +1,533 @@ +/* +** Copyright (C) 2001-2017 Erik de Castro Lopo +** +** This program is free software ; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation ; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY ; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program ; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include +#include + +#include +#include + +#if HAVE_UNISTD_H +#include +#endif + +#if (HAVE_DECL_S_IRGRP == 0) +#include +#endif + +#if (defined (WIN32) || defined (_WIN32)) +#include +#include +#endif + +#include + +#include "utils.h" + +#define BUFFER_LEN (1 << 10) +#define LOG_BUFFER_SIZE 1024 + +static void zero_data_test (const char *filename, int format) ; +static void filesystem_full_test (int format) ; +static void permission_test (const char *filename, int typemajor) ; +static void wavex_amb_test (const char *filename) ; +static void rf64_downgrade_test (const char *filename) ; +static void rf64_long_file_downgrade_test (const char *filename) ; + +int +main (int argc, char *argv []) +{ int do_all = 0 ; + int test_count = 0 ; + + if (argc != 2) + { printf ("Usage : %s \n", argv [0]) ; + printf (" Where is one of the following:\n") ; + printf (" wav - test WAV file peak chunk\n") ; + printf (" aiff - test AIFF file PEAK chunk\n") ; + printf (" all - perform all tests\n") ; + exit (1) ; + } ; + + do_all = ! strcmp (argv [1], "all") ; + + if (do_all || ! strcmp (argv [1], "wav")) + { zero_data_test ("zerolen.wav", SF_FORMAT_WAV | SF_FORMAT_PCM_16) ; + filesystem_full_test (SF_FORMAT_WAV | SF_FORMAT_PCM_16) ; + permission_test ("readonly.wav", SF_FORMAT_WAV) ; + wavex_amb_test ("ambisonic.wav") ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "aiff")) + { zero_data_test ("zerolen.aiff", SF_FORMAT_AIFF | SF_FORMAT_PCM_16) ; + filesystem_full_test (SF_FORMAT_AIFF | SF_FORMAT_PCM_16) ; + permission_test ("readonly.aiff", SF_FORMAT_AIFF) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "au")) + { zero_data_test ("zerolen.au", SF_FORMAT_AU | SF_FORMAT_PCM_16) ; + filesystem_full_test (SF_FORMAT_AU | SF_FORMAT_PCM_16) ; + permission_test ("readonly.au", SF_FORMAT_AU) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "caf")) + { zero_data_test ("zerolen.caf", SF_FORMAT_CAF | SF_FORMAT_PCM_16) ; + filesystem_full_test (SF_FORMAT_CAF | SF_FORMAT_PCM_16) ; + permission_test ("readonly.caf", SF_FORMAT_CAF) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "svx")) + { zero_data_test ("zerolen.svx", SF_FORMAT_SVX | SF_FORMAT_PCM_16) ; + filesystem_full_test (SF_FORMAT_SVX | SF_FORMAT_PCM_16) ; + permission_test ("readonly.svx", SF_FORMAT_SVX) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "nist")) + { zero_data_test ("zerolen.nist", SF_FORMAT_NIST | SF_FORMAT_PCM_16) ; + filesystem_full_test (SF_FORMAT_NIST | SF_FORMAT_PCM_16) ; + permission_test ("readonly.nist", SF_FORMAT_NIST) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "paf")) + { zero_data_test ("zerolen.paf", SF_FORMAT_PAF | SF_FORMAT_PCM_16) ; + filesystem_full_test (SF_FORMAT_PAF | SF_FORMAT_PCM_16) ; + permission_test ("readonly.paf", SF_FORMAT_PAF) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "ircam")) + { zero_data_test ("zerolen.ircam", SF_FORMAT_IRCAM | SF_FORMAT_PCM_16) ; + filesystem_full_test (SF_FORMAT_IRCAM | SF_FORMAT_PCM_16) ; + permission_test ("readonly.ircam", SF_FORMAT_IRCAM) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "voc")) + { zero_data_test ("zerolen.voc", SF_FORMAT_VOC | SF_FORMAT_PCM_16) ; + filesystem_full_test (SF_FORMAT_VOC | SF_FORMAT_PCM_16) ; + permission_test ("readonly.voc", SF_FORMAT_VOC) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "w64")) + { zero_data_test ("zerolen.w64", SF_FORMAT_W64 | SF_FORMAT_PCM_16) ; + filesystem_full_test (SF_FORMAT_W64 | SF_FORMAT_PCM_16) ; + permission_test ("readonly.w64", SF_FORMAT_W64) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "rf64")) + { zero_data_test ("zerolen.rf64", SF_FORMAT_RF64 | SF_FORMAT_PCM_16) ; + filesystem_full_test (SF_FORMAT_RF64 | SF_FORMAT_PCM_16) ; + permission_test ("readonly.rf64", SF_FORMAT_RF64) ; + rf64_downgrade_test ("downgrade.wav") ; + /* Disable this by default, because it needs to write 4 gigabytes of data. */ + if (SF_FALSE) + rf64_long_file_downgrade_test ("no-downgrade.rf64") ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "mat4")) + { zero_data_test ("zerolen.mat4", SF_FORMAT_MAT4 | SF_FORMAT_PCM_16) ; + filesystem_full_test (SF_FORMAT_MAT4 | SF_FORMAT_PCM_16) ; + permission_test ("readonly.mat4", SF_FORMAT_MAT4) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "mat5")) + { zero_data_test ("zerolen.mat5", SF_FORMAT_MAT5 | SF_FORMAT_PCM_16) ; + filesystem_full_test (SF_FORMAT_MAT5 | SF_FORMAT_PCM_16) ; + permission_test ("readonly.mat5", SF_FORMAT_MAT5) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "pvf")) + { zero_data_test ("zerolen.pvf", SF_FORMAT_PVF | SF_FORMAT_PCM_16) ; + filesystem_full_test (SF_FORMAT_PVF | SF_FORMAT_PCM_16) ; + permission_test ("readonly.pvf", SF_FORMAT_PVF) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "htk")) + { zero_data_test ("zerolen.htk", SF_FORMAT_HTK | SF_FORMAT_PCM_16) ; + filesystem_full_test (SF_FORMAT_HTK | SF_FORMAT_PCM_16) ; + permission_test ("readonly.htk", SF_FORMAT_HTK) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "avr")) + { zero_data_test ("zerolen.avr", SF_FORMAT_AVR | SF_FORMAT_PCM_16) ; + filesystem_full_test (SF_FORMAT_AVR | SF_FORMAT_PCM_16) ; + permission_test ("readonly.avr", SF_FORMAT_AVR) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "sds")) + { zero_data_test ("zerolen.sds", SF_FORMAT_SDS | SF_FORMAT_PCM_16) ; + filesystem_full_test (SF_FORMAT_SDS | SF_FORMAT_PCM_16) ; + permission_test ("readonly.sds", SF_FORMAT_SDS) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "mpc2k")) + { zero_data_test ("zerolen.mpc", SF_FORMAT_MPC2K | SF_FORMAT_PCM_16) ; + filesystem_full_test (SF_FORMAT_MPC2K | SF_FORMAT_PCM_16) ; + permission_test ("readonly.mpc", SF_FORMAT_MPC2K) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "ogg")) + { zero_data_test ("zerolen.oga", SF_FORMAT_OGG | SF_FORMAT_VORBIS) ; + /*-filesystem_full_test (SF_FORMAT_OGG | SF_FORMAT_VORBIS) ;-*/ + permission_test ("readonly.oga", SF_FORMAT_OGG) ; + test_count++ ; + } ; + + if (test_count == 0) + { printf ("Mono : ************************************\n") ; + printf ("Mono : * No '%s' test defined.\n", argv [1]) ; + printf ("Mono : ************************************\n") ; + return 1 ; + } ; + + return 0 ; +} /* main */ + + +/*============================================================================================ +** Here are the test functions. +*/ + +static void +zero_data_test (const char *filename, int format) +{ SNDFILE *file ; + SF_INFO sfinfo ; + + switch (format & SF_FORMAT_TYPEMASK) + { case SF_FORMAT_OGG : + if (HAVE_EXTERNAL_XIPH_LIBS == 0) + return ; + break ; + default : + break ; + } ; + + print_test_name ("zero_data_test", filename) ; + + sfinfo.samplerate = 44100 ; + sfinfo.format = format ; + sfinfo.channels = 1 ; + sfinfo.frames = 0 ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + + sf_close (file) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + + sf_close (file) ; + + unlink (filename) ; + puts ("ok") ; +} /* zero_data_test */ + +static void +filesystem_full_test (int format) +{ +#if (defined (WIN32) || defined (_WIN32)) + (void) format ; + /* Can't run this test on Win32 so return. */ + return ; +#else + SNDFILE *file ; + SF_INFO sfinfo ; + struct stat buf ; + + const char *filename = "/dev/full", *errorstr ; + + /* Make sure errno is zero before doing anything else. */ + errno = 0 ; + + print_test_name ("filesystem_full_test", filename) ; + + if (stat (filename, &buf) != 0) + { puts ("/dev/full missing") ; + return ; + } ; + + if (S_ISCHR (buf.st_mode) == 0 && S_ISBLK (buf.st_mode) == 0) + { puts ("/dev/full is not a device file") ; + return ; + } ; + + sfinfo.samplerate = 44100 ; + sfinfo.format = format ; + sfinfo.channels = 1 ; + sfinfo.frames = 0 ; + + if ((file = sf_open (filename, SFM_WRITE, &sfinfo)) != NULL) + { printf ("\n\nLine %d : Error, file should not have openned.\n", __LINE__ - 1) ; + exit (1) ; + } ; + + errorstr = sf_strerror (file) ; + + if (strstr (errorstr, " space ") == NULL || strstr (errorstr, "device") == NULL) + { printf ("\n\nLine %d : Error bad error string : %s.\n", __LINE__ - 1, errorstr) ; + exit (1) ; + } ; + + puts ("ok") ; +#endif +} /* filesystem_full_test */ + +static void +permission_test (const char *filename, int typemajor) +{ +#if (OS_IS_WIN32) + /* Avoid compiler warnings. */ + (void) filename ; + (void) typemajor ; + + /* Can't run this test on Win32 so return. */ + return ; +#else + + FILE *textfile ; + SNDFILE *file ; + SF_INFO sfinfo ; + const char *errorstr ; + + /* Make sure errno is zero before doing anything else. */ + errno = 0 ; + + if (getuid () == 0) + { /* If running as root bypass this test. + ** Root is allowed to open a readonly file for write. + */ + return ; + } ; + + print_test_name ("permission_test", filename) ; + + if (access (filename, F_OK) == 0) + { chmod (filename, S_IWUSR) ; + unlink (filename) ; + } ; + + if ((textfile = fopen (filename, "w")) == NULL) + { printf ("\n\nLine %d : not able to open text file for write.\n", __LINE__) ; + exit (1) ; + } ; + + fprintf (textfile, "This is a read only file.\n") ; + fclose (textfile) ; + + if (chmod (filename, S_IRUSR | S_IRGRP)) + { printf ("\n\nLine %d : chmod failed", __LINE__) ; + fflush (stdout) ; + perror ("") ; + exit (1) ; + } ; + + sfinfo.samplerate = 44100 ; + sfinfo.format = (typemajor | SF_FORMAT_PCM_16) ; + sfinfo.channels = 1 ; + sfinfo.frames = 0 ; + + if ((file = sf_open (filename, SFM_WRITE, &sfinfo)) != NULL) + { printf ("\n\nLine %d : Error, file should not have opened.\n", __LINE__ - 1) ; + exit (1) ; + } ; + + errorstr = sf_strerror (file) ; + + if (strstr (errorstr, "ermission denied") == NULL) + { printf ("\n\nLine %d : Error bad error string : %s.\n", __LINE__ - 1, errorstr) ; + exit (1) ; + } ; + + if (chmod (filename, S_IWUSR | S_IWGRP)) + { printf ("\n\nLine %d : chmod failed", __LINE__) ; + fflush (stdout) ; + perror ("") ; + exit (1) ; + } ; + + unlink (filename) ; + + puts ("ok") ; + +#endif +} /* permission_test */ + +static void +wavex_amb_test (const char *filename) +{ static short buffer [800] ; + SNDFILE *file ; + SF_INFO sfinfo ; + sf_count_t frames ; + + print_test_name (__func__, filename) ; + + sfinfo.samplerate = 44100 ; + sfinfo.format = SF_FORMAT_WAVEX | SF_FORMAT_PCM_16 ; + sfinfo.channels = 4 ; + + frames = ARRAY_LEN (buffer) / sfinfo.channels ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + sf_command (file, SFC_WAVEX_SET_AMBISONIC, NULL, SF_AMBISONIC_B_FORMAT) ; + test_writef_short_or_die (file, 0, buffer, frames, __LINE__) ; + sf_close (file) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + + exit_if_true ( + sf_command (file, SFC_WAVEX_GET_AMBISONIC, NULL, 0) != SF_AMBISONIC_B_FORMAT, + "\n\nLine %d : Error, this file should be in Ambisonic B format.\n", __LINE__ + ) ; + + sf_close (file) ; + + unlink (filename) ; + puts ("ok") ; +} /* wavex_amb_test */ + +static void +rf64_downgrade_test (const char *filename) +{ static short output [BUFFER_LEN] ; + static short input [BUFFER_LEN] ; + + SNDFILE *file ; + SF_INFO sfinfo ; + unsigned k ; + + print_test_name (__func__, filename) ; + + sf_info_clear (&sfinfo) ; + + sfinfo.samplerate = 44100 ; + sfinfo.frames = ARRAY_LEN (output) ; + sfinfo.channels = 1 ; + sfinfo.format = SF_FORMAT_RF64 | SF_FORMAT_PCM_16 ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + + exit_if_true (sf_command (file, SFC_RF64_AUTO_DOWNGRADE, NULL, SF_FALSE) != SF_FALSE, "\n\nLine %d: sf_command failed.\n", __LINE__) ; + exit_if_true (sf_command (file, SFC_RF64_AUTO_DOWNGRADE, NULL, SF_TRUE) != SF_TRUE, "\n\nLine %d: sf_command failed.\n", __LINE__) ; + + test_write_short_or_die (file, 0, output, ARRAY_LEN (output), __LINE__) ; + + exit_if_true (sf_command (file, SFC_RF64_AUTO_DOWNGRADE, NULL, SF_FALSE) != SF_TRUE, "\n\nLine %d: sf_command failed.\n", __LINE__) ; + exit_if_true (sf_command (file, SFC_RF64_AUTO_DOWNGRADE, NULL, SF_TRUE) != SF_TRUE, "\n\nLine %d: sf_command failed.\n", __LINE__) ; + + sf_close (file) ; + + memset (input, 0, sizeof (input)) ; + sf_info_clear (&sfinfo) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + + exit_if_true (sfinfo.format != (SF_FORMAT_WAVEX | SF_FORMAT_PCM_16), "\n\nLine %d: RF64 to WAV downgrade failed.\n", __LINE__) ; + exit_if_true (sfinfo.frames != ARRAY_LEN (output), "\n\nLine %d: Incorrect number of frames in file (too short). (%d should be %d)\n", __LINE__, (int) sfinfo.frames, (int) ARRAY_LEN (output)) ; + exit_if_true (sfinfo.channels != 1, "\n\nLine %d: Incorrect number of channels in file.\n", __LINE__) ; + + check_log_buffer_or_die (file, __LINE__) ; + + test_read_short_or_die (file, 0, input, ARRAY_LEN (input), __LINE__) ; + + sf_close (file) ; + + for (k = 0 ; k < ARRAY_LEN (input) ; k++) + exit_if_true (input [k] != output [k], + "\n\nLine: %d: Error on input %d, expected %d, got %d\n", __LINE__, k, output [k], input [k]) ; + + puts ("ok") ; + unlink (filename) ; + + return ; +} /* rf64_downgrade_test */ + +static void +rf64_long_file_downgrade_test (const char *filename) +{ static int output [BUFFER_LEN] ; + static int input [1] = { 0 } ; + + SNDFILE *file ; + SF_INFO sfinfo ; + sf_count_t output_frames = 0 ; + + print_test_name (__func__, filename) ; + + sf_info_clear (&sfinfo) ; + + memset (output, 0, sizeof (output)) ; + output [0] = 0x1020304 ; + + sfinfo.samplerate = 44100 ; + sfinfo.frames = ARRAY_LEN (output) ; + sfinfo.channels = 1 ; + sfinfo.format = SF_FORMAT_RF64 | SF_FORMAT_PCM_32 ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + + exit_if_true (sf_command (file, SFC_RF64_AUTO_DOWNGRADE, NULL, SF_TRUE) != SF_TRUE, "\n\nLine %d: sf_command failed.\n", __LINE__) ; + + while (output_frames * sizeof (output [0]) < 0x100000000) + { test_write_int_or_die (file, 0, output, ARRAY_LEN (output), __LINE__) ; + output_frames += ARRAY_LEN (output) ; + } ; + + sf_close (file) ; + + sf_info_clear (&sfinfo) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + + exit_if_true (sfinfo.format != (SF_FORMAT_RF64 | SF_FORMAT_PCM_32), "\n\nLine %d: RF64 to WAV downgrade should have failed.\n", __LINE__) ; + exit_if_true (sfinfo.channels != 1, "\n\nLine %d: Incorrect number of channels in file.\n", __LINE__) ; + exit_if_true (sfinfo.frames != output_frames, "\n\nLine %d: Incorrect number of frames in file (%d should be %d).\n", __LINE__, (int) sfinfo.frames, (int) output_frames) ; + + /* Check that the first sample read is the same as the first written. */ + test_read_int_or_die (file, 0, input, ARRAY_LEN (input), __LINE__) ; + exit_if_true (input [0] != output [0], "\n\nLine %d: Bad first sample (0x%08x).\n", __LINE__, input [0]) ; + + check_log_buffer_or_die (file, __LINE__) ; + + sf_close (file) ; + + puts ("ok") ; + unlink (filename) ; + + return ; +} /* rf64_long_file_downgrade_test */ diff --git a/extern/libsndfile-modified/tests/mpeg_test.c b/extern/libsndfile-modified/tests/mpeg_test.c new file mode 100644 index 000000000..fe7f53d16 --- /dev/null +++ b/extern/libsndfile-modified/tests/mpeg_test.c @@ -0,0 +1,348 @@ +/* +** Copyright (C) 2007-2019 Erik de Castro Lopo +** Copyright (C) 2019 John ffitch +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include + +#include + +#include "utils.h" + +#define SAMPLE_RATE 44100 +#define DATA_LENGTH (SAMPLE_RATE / 8) + +typedef union +{ double d [DATA_LENGTH] ; + float f [DATA_LENGTH] ; + int i [DATA_LENGTH] ; + short s [DATA_LENGTH] ; +} BUFFER ; + +static BUFFER data_out ; +static BUFFER data_in ; + +static void +mpeg_short_test (void) +{ const char * filename = "mpeg_short.mp3" ; + + SNDFILE * file ; + SF_INFO sfinfo ; + short seek_data [10] ; + unsigned k ; + + print_test_name ("mpeg_short_test", filename) ; + + /* Generate float data. */ + gen_windowed_sine_float (data_out.f, ARRAY_LEN (data_out.f), 1.0 * 0x7F00) ; + + /* Convert to shorteger. */ + for (k = 0 ; k < ARRAY_LEN (data_out.s) ; k++) + data_out.s [k] = lrintf (data_out.f [k]) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + /* Set up output file type. */ + sfinfo.format = SF_FORMAT_MPEG | SF_FORMAT_MPEG_LAYER_III ; + sfinfo.channels = 1 ; + sfinfo.samplerate = SAMPLE_RATE ; + + /* Write the output file. */ + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_FALSE, __LINE__) ; + test_write_short_or_die (file, 0, data_out.s, ARRAY_LEN (data_out.s), __LINE__) ; + sf_close (file) ; + + /* Read the file in again. */ + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + test_read_short_or_die (file, 0, data_in.s, ARRAY_LEN (data_in.s), __LINE__) ; + sf_close (file) ; + + puts ("ok") ; + + /* Test seeking. */ + print_test_name ("mpeg_seek_test", filename) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + + test_seek_or_die (file, 10, SEEK_SET, 10, sfinfo.channels, __LINE__) ; + test_read_short_or_die (file, 0, seek_data, ARRAY_LEN (seek_data), __LINE__) ; + compare_short_or_die (seek_data, data_in.s + 10, ARRAY_LEN (seek_data), __LINE__) ; + + /* Test seek to end of file. */ + test_seek_or_die (file, 0, SEEK_END, sfinfo.frames, sfinfo.channels, __LINE__) ; + + sf_close (file) ; + + puts ("ok") ; + + unlink (filename) ; +} /* mpeg_short_test */ + +static void +mpeg_int_test (void) +{ const char * filename = "mpeg_int.mp3" ; + + SNDFILE * file ; + SF_INFO sfinfo ; + int seek_data [10] ; + unsigned k ; + + print_test_name ("mpeg_int_test", filename) ; + + /* Generate float data. */ + gen_windowed_sine_float (data_out.f, ARRAY_LEN (data_out.f), 1.0 * 0x7FFF0000) ; + + /* Convert to integer. */ + for (k = 0 ; k < ARRAY_LEN (data_out.i) ; k++) + data_out.i [k] = lrintf (data_out.f [k]) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + /* Set up output file type. */ + sfinfo.format = SF_FORMAT_MPEG | SF_FORMAT_MPEG_LAYER_III ; + sfinfo.channels = 1 ; + sfinfo.samplerate = SAMPLE_RATE ; + + /* Write the output file. */ + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_FALSE, __LINE__) ; + test_write_int_or_die (file, 0, data_out.i, ARRAY_LEN (data_out.i), __LINE__) ; + sf_close (file) ; + + /* Read the file in again. */ + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + test_read_int_or_die (file, 0, data_in.i, ARRAY_LEN (data_in.i), __LINE__) ; + sf_close (file) ; + + puts ("ok") ; + + /* Test seeking. */ + print_test_name ("mpeg_seek_test", filename) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + + test_seek_or_die (file, 10, SEEK_SET, 10, sfinfo.channels, __LINE__) ; + test_read_int_or_die (file, 0, seek_data, ARRAY_LEN (seek_data), __LINE__) ; + compare_int_or_die (seek_data, data_in.i + 10, ARRAY_LEN (seek_data), __LINE__) ; + + sf_close (file) ; + + puts ("ok") ; + + unlink (filename) ; +} /* mpeg_int_test */ + +static void +mpeg_float_test (void) +{ const char * filename = "mpeg_float.mp3" ; + + SNDFILE * file ; + SF_INFO sfinfo ; + float seek_data [10] ; + + print_test_name ("mpeg_float_test", filename) ; + + gen_windowed_sine_float (data_out.f, ARRAY_LEN (data_out.f), 0.95) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + /* Set up output file type. */ + sfinfo.format = SF_FORMAT_MPEG | SF_FORMAT_MPEG_LAYER_III ; + sfinfo.channels = 1 ; + sfinfo.samplerate = SAMPLE_RATE ; + + /* Write the output file. */ + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_FALSE, __LINE__) ; + test_write_float_or_die (file, 0, data_out.f, ARRAY_LEN (data_out.f), __LINE__) ; + sf_close (file) ; + + /* Read the file in again. */ + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + test_read_float_or_die (file, 0, data_in.f, ARRAY_LEN (data_in.f), __LINE__) ; + sf_close (file) ; + + puts ("ok") ; + + /* Test seeking. */ + print_test_name ("mpeg_seek_test", filename) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + + test_seek_or_die (file, 10, SEEK_SET, 10, sfinfo.channels, __LINE__) ; + test_read_float_or_die (file, 0, seek_data, ARRAY_LEN (seek_data), __LINE__) ; + compare_float_or_die (seek_data, data_in.f + 10, ARRAY_LEN (seek_data), __LINE__) ; + + sf_close (file) ; + + puts ("ok") ; + + unlink (filename) ; +} /* mpeg_float_test */ + +static void +mpeg_double_test (void) +{ const char * filename = "mpeg_double.mp3" ; + + SNDFILE * file ; + SF_INFO sfinfo ; + double seek_data [10] ; + + print_test_name ("mpeg_double_test", filename) ; + + gen_windowed_sine_double (data_out.d, ARRAY_LEN (data_out.d), 0.95) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + /* Set up output file type. */ + sfinfo.format = SF_FORMAT_MPEG | SF_FORMAT_MPEG_LAYER_III ; + sfinfo.channels = 1 ; + sfinfo.samplerate = SAMPLE_RATE ; + + /* Write the output file. */ + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_FALSE, __LINE__) ; + test_write_double_or_die (file, 0, data_out.d, ARRAY_LEN (data_out.d), __LINE__) ; + sf_close (file) ; + + /* Read the file in again. */ + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + test_read_double_or_die (file, 0, data_in.d, ARRAY_LEN (data_in.d), __LINE__) ; + sf_close (file) ; + + puts ("ok") ; + + /* Test seeking. */ + print_test_name ("mpeg_seek_test", filename) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + + test_seek_or_die (file, 10, SEEK_SET, 10, sfinfo.channels, __LINE__) ; + test_read_double_or_die (file, 0, seek_data, ARRAY_LEN (seek_data), __LINE__) ; + compare_double_or_die (seek_data, data_in.d + 10, ARRAY_LEN (seek_data), __LINE__) ; + + sf_close (file) ; + + puts ("ok") ; + + unlink (filename) ; +} /* mpeg_double_test */ + + +static void +mpeg_stereo_seek_test (const char * filename, int format) +{ static float data [SAMPLE_RATE] ; + static float stereo_out [SAMPLE_RATE * 2] ; + + SNDFILE * file ; + SF_INFO sfinfo ; + sf_count_t pos ; + unsigned k ; + + print_test_name (__func__, filename) ; + + gen_windowed_sine_float (data, ARRAY_LEN (data), 0.95) ; + for (k = 0 ; k < ARRAY_LEN (data) ; k++) + { stereo_out [2 * k] = data [k] ; + stereo_out [2 * k + 1] = data [ARRAY_LEN (data) - k - 1] ; + } ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + /* Set up output file type. */ + sfinfo.format = format ; + sfinfo.channels = 2 ; + sfinfo.samplerate = SAMPLE_RATE ; + + /* Write the output file. */ + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_FALSE, __LINE__) ; + test_write_float_or_die (file, 0, stereo_out, ARRAY_LEN (stereo_out), __LINE__) ; + sf_close (file) ; + + /* Open file in again for reading. */ + memset (&sfinfo, 0, sizeof (sfinfo)) ; + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + + /* Read in the whole file. */ + test_read_float_or_die (file, 0, stereo_out, ARRAY_LEN (stereo_out), __LINE__) ; + + /* Now hammer seeking code. */ + test_seek_or_die (file, 234, SEEK_SET, 234, sfinfo.channels, __LINE__) ; + test_readf_float_or_die (file, 0, data, 10, __LINE__) ; + compare_float_or_die (data, stereo_out + (234 * sfinfo.channels), 10, __LINE__) ; + + test_seek_or_die (file, 442, SEEK_SET, 442, sfinfo.channels, __LINE__) ; + test_readf_float_or_die (file, 0, data, 10, __LINE__) ; + compare_float_or_die (data, stereo_out + (442 * sfinfo.channels), 10, __LINE__) ; + + test_seek_or_die (file, 12, SEEK_CUR, 442 + 10 + 12, sfinfo.channels, __LINE__) ; + test_readf_float_or_die (file, 0, data, 10, __LINE__) ; + compare_float_or_die (data, stereo_out + ((442 + 10 + 12) * sfinfo.channels), 10, __LINE__) ; + + test_seek_or_die (file, 12, SEEK_CUR, 442 + 20 + 24, sfinfo.channels, __LINE__) ; + test_readf_float_or_die (file, 0, data, 10, __LINE__) ; + compare_float_or_die (data, stereo_out + ((442 + 20 + 24) * sfinfo.channels), 10, __LINE__) ; + + pos = 500 - sfinfo.frames ; + test_seek_or_die (file, pos, SEEK_END, 500, sfinfo.channels, __LINE__) ; + test_readf_float_or_die (file, 0, data, 10, __LINE__) ; + compare_float_or_die (data, stereo_out + (500 * sfinfo.channels), 10, __LINE__) ; + + pos = 10 - sfinfo.frames ; + test_seek_or_die (file, pos, SEEK_END, 10, sfinfo.channels, __LINE__) ; + test_readf_float_or_die (file, 0, data, 10, __LINE__) ; + compare_float_or_die (data, stereo_out + (10 * sfinfo.channels), 10, __LINE__) ; + + sf_close (file) ; + + puts ("ok") ; + unlink (filename) ; +} /* mpeg_stereo_seek_test */ + + +int +main (void) +{ + if (HAVE_MPEG) + { mpeg_short_test () ; + mpeg_int_test () ; + mpeg_float_test () ; + mpeg_double_test () ; + + mpeg_stereo_seek_test ("mpeg_seek.mp3", SF_FORMAT_MPEG | SF_FORMAT_MPEG_LAYER_III) ; + } + else + puts (" No MPEG tests because mpg123/lame support was not compiled in.") ; + return 0 ; +} /* main */ + diff --git a/extern/libsndfile-modified/tests/multi_file_test.c b/extern/libsndfile-modified/tests/multi_file_test.c new file mode 100644 index 000000000..690697316 --- /dev/null +++ b/extern/libsndfile-modified/tests/multi_file_test.c @@ -0,0 +1,238 @@ +/* +** Copyright (C) 1999-2012 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include +#include + +#if HAVE_UNISTD_H +#include +#endif + +#if (HAVE_DECL_S_IRGRP == 0) +#include +#endif + +#include +#include +#include + +#include + +#include "utils.h" + +#define DATA_LENGTH (512) + +static void write_file_at_end (int fd, int filetype, int channels, int file_num) ; + +static void multi_file_test (const char *filename, int *formats, int format_count) ; + +static short data [DATA_LENGTH] ; + +static int wav_formats [] = +{ SF_FORMAT_WAV | SF_FORMAT_PCM_16, + SF_FORMAT_WAV | SF_FORMAT_PCM_24, + SF_FORMAT_WAV | SF_FORMAT_ULAW, + SF_FORMAT_WAV | SF_FORMAT_ALAW, + /* Lite remove start */ + SF_FORMAT_WAV | SF_FORMAT_IMA_ADPCM, + SF_FORMAT_WAV | SF_FORMAT_MS_ADPCM, + /* Lite remove end */ + /*-SF_FORMAT_WAV | SF_FORMAT_GSM610 Doesn't work yet. -*/ +} ; + +static int aiff_formats [] = +{ SF_FORMAT_AIFF | SF_FORMAT_PCM_16, + SF_FORMAT_AIFF | SF_FORMAT_PCM_24, + SF_FORMAT_AIFF | SF_FORMAT_ULAW, + SF_FORMAT_AIFF | SF_FORMAT_ALAW +} ; + +static int au_formats [] = +{ SF_FORMAT_AU | SF_FORMAT_PCM_16, + SF_FORMAT_AU | SF_FORMAT_PCM_24, + SF_FORMAT_AU | SF_FORMAT_ULAW, + SF_FORMAT_AU | SF_FORMAT_ALAW +} ; + +static int verbose = SF_FALSE ; + +int +main (int argc, char **argv) +{ int do_all = 0 ; + int test_count = 0 ; + + if (argc == 3 && strcmp (argv [2], "-v") == 0) + { verbose = SF_TRUE ; + argc -- ; + } ; + + if (argc != 2) + { printf ("Usage : %s \n", argv [0]) ; + printf (" Where is one of the following:\n") ; + printf (" wav - test WAV file functions (little endian)\n") ; + printf (" aiff - test AIFF file functions (big endian)\n") ; + printf (" au - test AU file functions\n") ; +#if 0 + printf (" svx - test 8SVX/16SV file functions\n") ; + printf (" nist - test NIST Sphere file functions\n") ; + printf (" ircam - test IRCAM file functions\n") ; + printf (" voc - Create Voice file functions\n") ; + printf (" w64 - Sonic Foundry's W64 file functions\n") ; +#endif + printf (" all - perform all tests\n") ; + exit (1) ; + } ; + + do_all = !strcmp (argv [1], "all") ; + + if (do_all || ! strcmp (argv [1], "wav")) + { multi_file_test ("multi_wav.dat", wav_formats, ARRAY_LEN (wav_formats)) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "aiff")) + { multi_file_test ("multi_aiff.dat", aiff_formats, ARRAY_LEN (aiff_formats)) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "au")) + { multi_file_test ("multi_au.dat", au_formats, ARRAY_LEN (au_formats)) ; + test_count++ ; + } ; + + return 0 ; +} /* main */ + +/*====================================================================================== +*/ + +static void +multi_file_test (const char *filename, int *formats, int format_count) +{ SNDFILE *sndfile ; + SF_INFO sfinfo ; + SF_EMBED_FILE_INFO embed_info ; + sf_count_t filelen ; + int fd, k, file_count = 0 ; + + print_test_name ("multi_file_test", filename) ; + + unlink (filename) ; + + if ((fd = open (filename, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR)) < 0) + { printf ("\n\nLine %d: open failed : %s\n", __LINE__, strerror (errno)) ; + exit (1) ; + } ; + + k = write (fd, "1234", 4) ; + + for (k = 0 ; k < format_count ; k++) + write_file_at_end (fd, formats [k], 2, k) ; + + filelen = file_length_fd (fd) ; + + embed_info.offset = 4 ; + embed_info.length = 0 ; + + + for (file_count = 1 ; embed_info.offset + embed_info.length < filelen ; file_count ++) + { + if (verbose) + { puts ("\n------------------------------------") ; + printf ("This offset : %" PRId64 "\n", embed_info.offset + embed_info.length) ; + } ; + + if (lseek (fd, (long) (embed_info.offset + embed_info.length), SEEK_SET) < 0) + { printf ("\n\nLine %d: lseek failed : %s\n", __LINE__, strerror (errno)) ; + exit (1) ; + } ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + if ((sndfile = sf_open_fd (fd, SFM_READ, &sfinfo, SF_FALSE)) == NULL) + { printf ("\n\nLine %d: sf_open_fd failed\n", __LINE__) ; + printf ("Embedded file number : %d offset : %" PRId64 "\n", file_count, embed_info.offset) ; + puts (sf_strerror (sndfile)) ; + dump_log_buffer (sndfile) ; + exit (1) ; + } ; + + sf_command (sndfile, SFC_GET_EMBED_FILE_INFO, &embed_info, sizeof (embed_info)) ; + + sf_close (sndfile) ; + + if (verbose) + printf ("\nNext offset : %" PRId64 "\nNext length : %" PRId64 "\n", embed_info.offset, embed_info.length) ; + } ; + + file_count -- ; + + if (file_count != format_count) + { printf ("\n\nLine %d: file count (%d) not equal to %d.\n\n", __LINE__, file_count, format_count) ; + printf ("Embedded file number : %d\n", file_count) ; + exit (1) ; + } ; + + close (fd) ; + unlink (filename) ; + printf ("ok\n") ; + + return ; +} /* multi_file_test */ + +/*====================================================================================== +*/ + +static void +write_file_at_end (int fd, int filetype, int channels, int file_num) +{ SNDFILE *sndfile ; + SF_INFO sfinfo ; + + int frames, k ; + + lseek (fd, 0, SEEK_END) ; + + for (k = 0 ; k < DATA_LENGTH ; k++) + data [k] = k ; + + frames = DATA_LENGTH / channels ; + + sfinfo.format = filetype ; + sfinfo.channels = channels ; + sfinfo.samplerate = 44100 ; + + if ((sndfile = sf_open_fd (fd, SFM_WRITE, &sfinfo, SF_FALSE)) == NULL) + { printf ("\n\nLine %d: sf_open_fd failed\n", __LINE__) ; + printf ("Embedded file number : %d\n", file_num) ; + puts (sf_strerror (sndfile)) ; + dump_log_buffer (sndfile) ; + exit (1) ; + } ; + + if (sf_writef_short (sndfile, data, frames) != frames) + { printf ("\n\nLine %d: short write\n", __LINE__) ; + printf ("Embedded file number : %d\n", file_num) ; + exit (1) ; + } ; + + sf_close (sndfile) ; +} /* write_file_at_end */ + diff --git a/extern/libsndfile-modified/tests/ogg_opus_test.c b/extern/libsndfile-modified/tests/ogg_opus_test.c new file mode 100644 index 000000000..a850908c2 --- /dev/null +++ b/extern/libsndfile-modified/tests/ogg_opus_test.c @@ -0,0 +1,424 @@ +/* +** Copyright (C) 2007-2018 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include +#include +#include + +#include "utils.h" + +#define SAMPLE_RATE 48000 +#define DATA_LENGTH (SAMPLE_RATE / 8) + +typedef union +{ double d [DATA_LENGTH] ; + float f [DATA_LENGTH] ; + int i [DATA_LENGTH] ; + short s [DATA_LENGTH] ; +} BUFFER ; + +static BUFFER data_out ; +static BUFFER data_in ; + +static void +ogg_opus_short_test (void) +{ const char * filename = "ogg_opus_short.opus" ; + + SNDFILE * file ; + SF_INFO sfinfo ; + short seek_data [10] ; + unsigned k ; + + print_test_name ("ogg_opus_short_test", filename) ; + + /* Generate float data. */ + gen_windowed_sine_float (data_out.f, ARRAY_LEN (data_out.f), 1.0 * 0x7F00) ; + + /* Convert to short. */ + for (k = 0 ; k < ARRAY_LEN (data_out.s) ; k++) + data_out.s [k] = (short) lrintf (data_out.f [k]) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + /* Set up output file type. */ + sfinfo.format = SF_FORMAT_OGG | SF_FORMAT_OPUS ; + sfinfo.channels = 1 ; + sfinfo.samplerate = SAMPLE_RATE ; + + /* Write the output file. */ + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_FALSE, __LINE__) ; + test_write_short_or_die (file, 0, data_out.s, ARRAY_LEN (data_out.s), __LINE__) ; + sf_close (file) ; + + /* Read the file in again. */ + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + test_read_short_or_die (file, 0, data_in.s, ARRAY_LEN (data_in.s), __LINE__) ; + sf_close (file) ; + + puts ("ok") ; + + /* Test seeking. */ + print_test_name ("ogg_opus_seek_test", filename) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + + test_seek_or_die (file, 10, SEEK_SET, 10, sfinfo.channels, __LINE__) ; + test_read_short_or_die (file, 0, seek_data, ARRAY_LEN (seek_data), __LINE__) ; + compare_short_or_die (seek_data, data_in.s + 10, ARRAY_LEN (seek_data), __LINE__) ; + + /* Test seek to end of file. */ + test_seek_or_die (file, 0, SEEK_END, sfinfo.frames, sfinfo.channels, __LINE__) ; + + sf_close (file) ; + + puts ("ok") ; + + unlink (filename) ; +} /* ogg_opus_short_test */ + +static void +ogg_opus_int_test (void) +{ const char * filename = "ogg_opus_int.opus" ; + + SNDFILE * file ; + SF_INFO sfinfo ; + int seek_data [10] ; + unsigned k ; + + print_test_name ("ogg_opus_int_test", filename) ; + + /* Generate float data. */ + gen_windowed_sine_float (data_out.f, ARRAY_LEN (data_out.f), 1.0 * 0x7FFF0000) ; + + /* Convert to integer. */ + for (k = 0 ; k < ARRAY_LEN (data_out.i) ; k++) + data_out.i [k] = lrintf (data_out.f [k]) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + /* Set up output file type. */ + sfinfo.format = SF_FORMAT_OGG | SF_FORMAT_OPUS ; + sfinfo.channels = 1 ; + sfinfo.samplerate = SAMPLE_RATE ; + + /* Write the output file. */ + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_FALSE, __LINE__) ; + test_write_int_or_die (file, 0, data_out.i, ARRAY_LEN (data_out.i), __LINE__) ; + sf_close (file) ; + + /* Read the file in again. */ + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + test_read_int_or_die (file, 0, data_in.i, ARRAY_LEN (data_in.i), __LINE__) ; + sf_close (file) ; + + puts ("ok") ; + + /* Test seeking. */ + print_test_name ("ogg_opus_seek_test", filename) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + + test_seek_or_die (file, 10, SEEK_SET, 10, sfinfo.channels, __LINE__) ; + test_read_int_or_die (file, 0, seek_data, ARRAY_LEN (seek_data), __LINE__) ; + compare_int_or_die (seek_data, data_in.i + 10, ARRAY_LEN (seek_data), __LINE__) ; + + sf_close (file) ; + + puts ("ok") ; + + unlink (filename) ; +} /* ogg_opus_int_test */ + +static void +ogg_opus_float_test (void) +{ const char * filename = "ogg_opus_float.opus" ; + + SNDFILE * file ; + SF_INFO sfinfo ; + float seek_data [10] ; + + print_test_name ("ogg_opus_float_test", filename) ; + + gen_windowed_sine_float (data_out.f, ARRAY_LEN (data_out.f), 0.95) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + /* Set up output file type. */ + sfinfo.format = SF_FORMAT_OGG | SF_FORMAT_OPUS ; + sfinfo.channels = 1 ; + sfinfo.samplerate = SAMPLE_RATE ; + + /* Write the output file. */ + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_FALSE, __LINE__) ; + test_write_float_or_die (file, 0, data_out.f, ARRAY_LEN (data_out.f), __LINE__) ; + sf_close (file) ; + + /* Read the file in again. */ + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + test_read_float_or_die (file, 0, data_in.f, ARRAY_LEN (data_in.f), __LINE__) ; + sf_close (file) ; + + puts ("ok") ; + + /* Test seeking. */ + print_test_name ("ogg_opus_seek_test", filename) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + + test_seek_or_die (file, 10, SEEK_SET, 10, sfinfo.channels, __LINE__) ; + test_read_float_or_die (file, 0, seek_data, ARRAY_LEN (seek_data), __LINE__) ; + compare_float_or_die (seek_data, data_in.f + 10, ARRAY_LEN (seek_data), __LINE__) ; + + sf_close (file) ; + + puts ("ok") ; + + unlink (filename) ; +} /* ogg_opus_float_test */ + +static void +ogg_opus_double_test (void) +{ const char * filename = "ogg_opus_double.opus" ; + + SNDFILE * file ; + SF_INFO sfinfo ; + double seek_data [10] ; + + print_test_name ("ogg_opus_double_test", filename) ; + + gen_windowed_sine_double (data_out.d, ARRAY_LEN (data_out.d), 0.95) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + /* Set up output file type. */ + sfinfo.format = SF_FORMAT_OGG | SF_FORMAT_OPUS ; + sfinfo.channels = 1 ; + sfinfo.samplerate = SAMPLE_RATE ; + + /* Write the output file. */ + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_FALSE, __LINE__) ; + test_write_double_or_die (file, 0, data_out.d, ARRAY_LEN (data_out.d), __LINE__) ; + sf_close (file) ; + + /* Read the file in again. */ + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + test_read_double_or_die (file, 0, data_in.d, ARRAY_LEN (data_in.d), __LINE__) ; + sf_close (file) ; + + puts ("ok") ; + + /* Test seeking. */ + print_test_name ("ogg_opus_seek_test", filename) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + + test_seek_or_die (file, 10, SEEK_SET, 10, sfinfo.channels, __LINE__) ; + test_read_double_or_die (file, 0, seek_data, ARRAY_LEN (seek_data), __LINE__) ; + compare_double_or_die (seek_data, data_in.d + 10, ARRAY_LEN (seek_data), __LINE__) ; + + sf_close (file) ; + + puts ("ok") ; + + unlink (filename) ; +} /* ogg_opus_double_test */ + + +static void +ogg_opus_stereo_seek_test (const char * filename, int format) +{ static float data [SAMPLE_RATE] ; + static float stereo_out [SAMPLE_RATE * 2] ; + + SNDFILE * file ; + SF_INFO sfinfo ; + sf_count_t pos ; + unsigned k ; + + print_test_name (__func__, filename) ; + + gen_windowed_sine_float (data, ARRAY_LEN (data), 0.95) ; + for (k = 0 ; k < ARRAY_LEN (data) ; k++) + { stereo_out [2 * k] = data [k] ; + stereo_out [2 * k + 1] = data [ARRAY_LEN (data) - k - 1] ; + } ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + /* Set up output file type. */ + sfinfo.format = format ; + sfinfo.channels = 2 ; + sfinfo.samplerate = SAMPLE_RATE ; + + /* Write the output file. */ + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_FALSE, __LINE__) ; + test_write_float_or_die (file, 0, stereo_out, ARRAY_LEN (stereo_out), __LINE__) ; + sf_close (file) ; + + /* Open file in again for reading. */ + memset (&sfinfo, 0, sizeof (sfinfo)) ; + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + + /* Read in the whole file. */ + test_read_float_or_die (file, 0, stereo_out, ARRAY_LEN (stereo_out), __LINE__) ; + + /* Now hammer seeking code. */ + test_seek_or_die (file, 234, SEEK_SET, 234, sfinfo.channels, __LINE__) ; + test_readf_float_or_die (file, 0, data, 10, __LINE__) ; + compare_float_or_die (data, stereo_out + (234 * sfinfo.channels), 10, __LINE__) ; + + test_seek_or_die (file, 442, SEEK_SET, 442, sfinfo.channels, __LINE__) ; + test_readf_float_or_die (file, 0, data, 10, __LINE__) ; + compare_float_or_die (data, stereo_out + (442 * sfinfo.channels), 10, __LINE__) ; + + test_seek_or_die (file, 12, SEEK_CUR, 442 + 10 + 12, sfinfo.channels, __LINE__) ; + test_readf_float_or_die (file, 0, data, 10, __LINE__) ; + compare_float_or_die (data, stereo_out + ((442 + 10 + 12) * sfinfo.channels), 10, __LINE__) ; + + test_seek_or_die (file, 12, SEEK_CUR, 442 + 20 + 24, sfinfo.channels, __LINE__) ; + test_readf_float_or_die (file, 0, data, 10, __LINE__) ; + compare_float_or_die (data, stereo_out + ((442 + 20 + 24) * sfinfo.channels), 10, __LINE__) ; + + pos = 500 - sfinfo.frames ; + test_seek_or_die (file, pos, SEEK_END, 500, sfinfo.channels, __LINE__) ; + test_readf_float_or_die (file, 0, data, 10, __LINE__) ; + compare_float_or_die (data, stereo_out + (500 * sfinfo.channels), 10, __LINE__) ; + + pos = 10 - sfinfo.frames ; + test_seek_or_die (file, pos, SEEK_END, 10, sfinfo.channels, __LINE__) ; + test_readf_float_or_die (file, 0, data, 10, __LINE__) ; + compare_float_or_die (data, stereo_out + (10 * sfinfo.channels), 10, __LINE__) ; + + sf_close (file) ; + + puts ("ok") ; + unlink (filename) ; +} /* ogg_opus_stereo_seek_test */ + + +static void +ogg_opus_original_samplerate_test (void) +{ const char * filename = "ogg_opus_original_samplerate.opus" ; + + SNDFILE * file ; + SF_INFO sfinfo ; + int original_samplerate = 54321 ; + sf_count_t frames ; + + print_test_name ("ogg_opus_original_samplerate_test", filename) ; + + gen_windowed_sine_double (data_out.d, ARRAY_LEN (data_out.d), 0.95) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + /* Set up output file type. */ + sfinfo.format = SF_FORMAT_OGG | SF_FORMAT_OPUS ; + sfinfo.channels = 1 ; + sfinfo.samplerate = SAMPLE_RATE ; + + /* Write the output file. */ + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_FALSE, __LINE__) ; + if (sf_command (file, SFC_SET_ORIGINAL_SAMPLERATE, &original_samplerate, sizeof (original_samplerate)) != SF_TRUE) + { printf ("\nCommand SFC_SET_ORIGINAL_SAMPLERATE failed!\n") ; + exit (1) ; + } ; + test_write_double_or_die (file, 0, data_out.d, ARRAY_LEN (data_out.d), __LINE__) ; + if (sf_command (file, SFC_SET_ORIGINAL_SAMPLERATE, &original_samplerate, sizeof (original_samplerate)) != SF_FALSE) + { printf ("\nCommand SFC_SET_ORIGINAL_SAMPLERATE succeeded when it should have failed!") ; + exit (1) ; + } ; + sf_close (file) ; + + /* Read the file in again. */ + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + original_samplerate = 0 ; + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + if (sf_command (file, SFC_GET_ORIGINAL_SAMPLERATE, &original_samplerate, sizeof (original_samplerate)) != SF_TRUE + || original_samplerate != 54321) + { printf ("\nCommand SFC_GET_ORIGINAL_SAMPLERATE failed!\n") ; + exit (1) ; + } ; + test_read_double_or_die (file, 0, data_in.d, 8, __LINE__) ; + if (sf_command (file, SFC_SET_ORIGINAL_SAMPLERATE, &original_samplerate, sizeof (original_samplerate)) == SF_TRUE) + { printf ("\nCommand SFC_SET_ORIGINAL_SAMPLERATE succeeded when it should have failed!\n") ; + exit (1) ; + } ; + sf_close (file) ; + + /* Test changing the decoder. */ + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + frames = sfinfo.frames ; + original_samplerate = 16000 ; + if (sf_command (file, SFC_SET_ORIGINAL_SAMPLERATE, &original_samplerate, sizeof (original_samplerate)) != SF_TRUE) + { printf ("\nCommand SFC_SET_ORIGINAL_SAMPLERATE failed!\n") ; + exit (1) ; + } ; + if (sf_command (file, SFC_GET_CURRENT_SF_INFO, &sfinfo, sizeof (sfinfo))) + { printf ("\nCommand SFC_GET_CURRENT_SF_INFO failed!\n") ; + exit (1) ; + } ; + if (frames / (48000 / 16000) != sfinfo.frames) + { printf ("\nIncorrect frame count! (%" PRId64 " vs %" PRId64")\n", frames / (48000 / 16000), sfinfo.frames) ; + exit (1) ; + } ; + test_read_double_or_die (file, 0, data_out.d, sfinfo.frames, __LINE__) ; + + sf_close (file) ; + + puts ("ok") ; + + unlink (filename) ; +} /* ogg_opus_original_samplerate_test */ + + +int +main (void) +{ + if (HAVE_EXTERNAL_XIPH_LIBS) + { ogg_opus_short_test () ; + ogg_opus_int_test () ; + ogg_opus_float_test () ; + ogg_opus_double_test () ; + + ogg_opus_stereo_seek_test ("ogg_opus_seek.opus", SF_FORMAT_OGG | SF_FORMAT_OPUS) ; + ogg_opus_original_samplerate_test () ; + } + else + puts (" No Ogg/Opus tests because Ogg/Opus support was not compiled in.") ; + + return 0 ; +} /* main */ diff --git a/extern/libsndfile-modified/tests/ogg_test.c b/extern/libsndfile-modified/tests/ogg_test.c new file mode 100644 index 000000000..dcc5ed196 --- /dev/null +++ b/extern/libsndfile-modified/tests/ogg_test.c @@ -0,0 +1,348 @@ +/* +** Copyright (C) 2007-2016 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include + +#include + +#include "utils.h" + +#define SAMPLE_RATE 44100 +#define DATA_LENGTH (SAMPLE_RATE / 8) + +typedef union +{ double d [DATA_LENGTH] ; + float f [DATA_LENGTH] ; + int i [DATA_LENGTH] ; + short s [DATA_LENGTH] ; +} BUFFER ; + +static BUFFER data_out ; +static BUFFER data_in ; + +static void +ogg_short_test (void) +{ const char * filename = "vorbis_short.oga" ; + + SNDFILE * file ; + SF_INFO sfinfo ; + short seek_data [10] ; + unsigned k ; + + print_test_name ("ogg_short_test", filename) ; + + /* Generate float data. */ + gen_windowed_sine_float (data_out.f, ARRAY_LEN (data_out.f), 1.0 * 0x7F00) ; + + /* Convert to shorteger. */ + for (k = 0 ; k < ARRAY_LEN (data_out.s) ; k++) + data_out.s [k] = (short) lrintf (data_out.f [k]) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + /* Set up output file type. */ + sfinfo.format = SF_FORMAT_OGG | SF_FORMAT_VORBIS ; + sfinfo.channels = 1 ; + sfinfo.samplerate = SAMPLE_RATE ; + + /* Write the output file. */ + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_FALSE, __LINE__) ; + test_write_short_or_die (file, 0, data_out.s, ARRAY_LEN (data_out.s), __LINE__) ; + sf_close (file) ; + + /* Read the file in again. */ + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + test_read_short_or_die (file, 0, data_in.s, ARRAY_LEN (data_in.s), __LINE__) ; + sf_close (file) ; + + puts ("ok") ; + + /* Test seeking. */ + print_test_name ("ogg_seek_test", filename) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + + test_seek_or_die (file, 10, SEEK_SET, 10, sfinfo.channels, __LINE__) ; + test_read_short_or_die (file, 0, seek_data, ARRAY_LEN (seek_data), __LINE__) ; + compare_short_or_die (seek_data, data_in.s + 10, ARRAY_LEN (seek_data), __LINE__) ; + + /* Test seek to end of file. */ + test_seek_or_die (file, 0, SEEK_END, sfinfo.frames, sfinfo.channels, __LINE__) ; + + sf_close (file) ; + + puts ("ok") ; + + unlink (filename) ; +} /* ogg_short_test */ + +static void +ogg_int_test (void) +{ const char * filename = "vorbis_int.oga" ; + + SNDFILE * file ; + SF_INFO sfinfo ; + int seek_data [10] ; + unsigned k ; + + print_test_name ("ogg_int_test", filename) ; + + /* Generate float data. */ + gen_windowed_sine_float (data_out.f, ARRAY_LEN (data_out.f), 1.0 * 0x7FFF0000) ; + + /* Convert to integer. */ + for (k = 0 ; k < ARRAY_LEN (data_out.i) ; k++) + data_out.i [k] = lrintf (data_out.f [k]) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + /* Set up output file type. */ + sfinfo.format = SF_FORMAT_OGG | SF_FORMAT_VORBIS ; + sfinfo.channels = 1 ; + sfinfo.samplerate = SAMPLE_RATE ; + + /* Write the output file. */ + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_FALSE, __LINE__) ; + test_write_int_or_die (file, 0, data_out.i, ARRAY_LEN (data_out.i), __LINE__) ; + sf_close (file) ; + + /* Read the file in again. */ + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + test_read_int_or_die (file, 0, data_in.i, ARRAY_LEN (data_in.i), __LINE__) ; + sf_close (file) ; + + puts ("ok") ; + + /* Test seeking. */ + print_test_name ("ogg_seek_test", filename) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + + test_seek_or_die (file, 10, SEEK_SET, 10, sfinfo.channels, __LINE__) ; + test_read_int_or_die (file, 0, seek_data, ARRAY_LEN (seek_data), __LINE__) ; + compare_int_or_die (seek_data, data_in.i + 10, ARRAY_LEN (seek_data), __LINE__) ; + + sf_close (file) ; + + puts ("ok") ; + + unlink (filename) ; +} /* ogg_int_test */ + +static void +ogg_float_test (void) +{ const char * filename = "vorbis_float.oga" ; + + SNDFILE * file ; + SF_INFO sfinfo ; + float seek_data [10] ; + + print_test_name ("ogg_float_test", filename) ; + + gen_windowed_sine_float (data_out.f, ARRAY_LEN (data_out.f), 0.95) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + /* Set up output file type. */ + sfinfo.format = SF_FORMAT_OGG | SF_FORMAT_VORBIS ; + sfinfo.channels = 1 ; + sfinfo.samplerate = SAMPLE_RATE ; + + /* Write the output file. */ + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_FALSE, __LINE__) ; + test_write_float_or_die (file, 0, data_out.f, ARRAY_LEN (data_out.f), __LINE__) ; + sf_close (file) ; + + /* Read the file in again. */ + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + test_read_float_or_die (file, 0, data_in.f, ARRAY_LEN (data_in.f), __LINE__) ; + sf_close (file) ; + + puts ("ok") ; + + /* Test seeking. */ + print_test_name ("ogg_seek_test", filename) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + + test_seek_or_die (file, 10, SEEK_SET, 10, sfinfo.channels, __LINE__) ; + test_read_float_or_die (file, 0, seek_data, ARRAY_LEN (seek_data), __LINE__) ; + compare_float_or_die (seek_data, data_in.f + 10, ARRAY_LEN (seek_data), __LINE__) ; + + sf_close (file) ; + + puts ("ok") ; + + unlink (filename) ; +} /* ogg_float_test */ + +static void +ogg_double_test (void) +{ const char * filename = "vorbis_double.oga" ; + + SNDFILE * file ; + SF_INFO sfinfo ; + double seek_data [10] ; + + print_test_name ("ogg_double_test", filename) ; + + gen_windowed_sine_double (data_out.d, ARRAY_LEN (data_out.d), 0.95) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + /* Set up output file type. */ + sfinfo.format = SF_FORMAT_OGG | SF_FORMAT_VORBIS ; + sfinfo.channels = 1 ; + sfinfo.samplerate = SAMPLE_RATE ; + + /* Write the output file. */ + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_FALSE, __LINE__) ; + test_write_double_or_die (file, 0, data_out.d, ARRAY_LEN (data_out.d), __LINE__) ; + sf_close (file) ; + + /* Read the file in again. */ + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + test_read_double_or_die (file, 0, data_in.d, ARRAY_LEN (data_in.d), __LINE__) ; + sf_close (file) ; + + puts ("ok") ; + + /* Test seeking. */ + print_test_name ("ogg_seek_test", filename) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + + test_seek_or_die (file, 10, SEEK_SET, 10, sfinfo.channels, __LINE__) ; + test_read_double_or_die (file, 0, seek_data, ARRAY_LEN (seek_data), __LINE__) ; + compare_double_or_die (seek_data, data_in.d + 10, ARRAY_LEN (seek_data), __LINE__) ; + + sf_close (file) ; + + puts ("ok") ; + + unlink (filename) ; +} /* ogg_double_test */ + + +static void +ogg_stereo_seek_test (const char * filename, int format) +{ static float data [SAMPLE_RATE] ; + static float stereo_out [SAMPLE_RATE * 2] ; + + SNDFILE * file ; + SF_INFO sfinfo ; + sf_count_t pos ; + unsigned k ; + + print_test_name (__func__, filename) ; + + gen_windowed_sine_float (data, ARRAY_LEN (data), 0.95) ; + for (k = 0 ; k < ARRAY_LEN (data) ; k++) + { stereo_out [2 * k] = data [k] ; + stereo_out [2 * k + 1] = data [ARRAY_LEN (data) - k - 1] ; + } ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + /* Set up output file type. */ + sfinfo.format = format ; + sfinfo.channels = 2 ; + sfinfo.samplerate = SAMPLE_RATE ; + + /* Write the output file. */ + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_FALSE, __LINE__) ; + test_write_float_or_die (file, 0, stereo_out, ARRAY_LEN (stereo_out), __LINE__) ; + sf_close (file) ; + + /* Open file in again for reading. */ + memset (&sfinfo, 0, sizeof (sfinfo)) ; + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + + /* Read in the whole file. */ + test_read_float_or_die (file, 0, stereo_out, ARRAY_LEN (stereo_out), __LINE__) ; + + /* Now hammer seeking code. */ + test_seek_or_die (file, 234, SEEK_SET, 234, sfinfo.channels, __LINE__) ; + test_readf_float_or_die (file, 0, data, 10, __LINE__) ; + compare_float_or_die (data, stereo_out + (234 * sfinfo.channels), 10, __LINE__) ; + + test_seek_or_die (file, 442, SEEK_SET, 442, sfinfo.channels, __LINE__) ; + test_readf_float_or_die (file, 0, data, 10, __LINE__) ; + compare_float_or_die (data, stereo_out + (442 * sfinfo.channels), 10, __LINE__) ; + + test_seek_or_die (file, 12, SEEK_CUR, 442 + 10 + 12, sfinfo.channels, __LINE__) ; + test_readf_float_or_die (file, 0, data, 10, __LINE__) ; + compare_float_or_die (data, stereo_out + ((442 + 10 + 12) * sfinfo.channels), 10, __LINE__) ; + + test_seek_or_die (file, 12, SEEK_CUR, 442 + 20 + 24, sfinfo.channels, __LINE__) ; + test_readf_float_or_die (file, 0, data, 10, __LINE__) ; + compare_float_or_die (data, stereo_out + ((442 + 20 + 24) * sfinfo.channels), 10, __LINE__) ; + + pos = 500 - sfinfo.frames ; + test_seek_or_die (file, pos, SEEK_END, 500, sfinfo.channels, __LINE__) ; + test_readf_float_or_die (file, 0, data, 10, __LINE__) ; + compare_float_or_die (data, stereo_out + (500 * sfinfo.channels), 10, __LINE__) ; + + pos = 10 - sfinfo.frames ; + test_seek_or_die (file, pos, SEEK_END, 10, sfinfo.channels, __LINE__) ; + test_readf_float_or_die (file, 0, data, 10, __LINE__) ; + compare_float_or_die (data, stereo_out + (10 * sfinfo.channels), 10, __LINE__) ; + + sf_close (file) ; + + puts ("ok") ; + unlink (filename) ; +} /* ogg_stereo_seek_test */ + + +int +main (void) +{ + if (HAVE_EXTERNAL_XIPH_LIBS) + { ogg_short_test () ; + ogg_int_test () ; + ogg_float_test () ; + ogg_double_test () ; + + /*-ogg_stereo_seek_test ("pcm.wav", SF_FORMAT_WAV | SF_FORMAT_PCM_16) ;-*/ + ogg_stereo_seek_test ("vorbis_seek.ogg", SF_FORMAT_OGG | SF_FORMAT_VORBIS) ; + } + else + puts (" No Ogg/Vorbis tests because Ogg/Vorbis support was not compiled in.") ; + + return 0 ; +} /* main */ diff --git a/extern/libsndfile-modified/tests/pcm_test.def b/extern/libsndfile-modified/tests/pcm_test.def new file mode 100644 index 000000000..2cc91b5f3 --- /dev/null +++ b/extern/libsndfile-modified/tests/pcm_test.def @@ -0,0 +1,34 @@ +autogen definitions pcm_test.tpl; + +data_type = { + name = "bits_8" ; + item_count = 127 ; + short_func = "arith_shift_left (k * ((k % 2) ? 1 : -1), 8)" ; + int_func = "arith_shift_left (k * ((k % 2) ? 1 : -1), 24)" ; + float_func = "(k * ((k % 2) ? 1 : -1))" ; + } ; + +data_type = { + name = "bits_16" ; + item_count = 1024 ; + short_func = "(k * ((k % 2) ? 3 : -3))" ; + int_func = "arith_shift_left (k * ((k % 2) ? 3 : -3), 16)" ; + float_func = "(k * ((k % 2) ? 3 : -3))" ; + } ; + +data_type = { + name = "bits_24" ; + item_count = 1024 ; + short_func = "(k * ((k % 2) ? 3 : -3))" ; + int_func = "arith_shift_left (k * ((k % 2) ? 3333 : -3333), 8)" ; + float_func = "(k * ((k % 2) ? 3333 : -3333))" ; + } ; + +data_type = { + name = "bits_32" ; + item_count = 1024 ; + short_func = "(k * ((k % 2) ? 3 : -3))" ; + int_func = "(k * ((k % 2) ? 333333 : -333333))" ; + float_func = "(k * ((k % 2) ? 333333 : -333333))" ; + } ; + diff --git a/extern/libsndfile-modified/tests/pcm_test.tpl b/extern/libsndfile-modified/tests/pcm_test.tpl new file mode 100644 index 000000000..11226fb98 --- /dev/null +++ b/extern/libsndfile-modified/tests/pcm_test.tpl @@ -0,0 +1,919 @@ +[+ AutoGen5 template c +] +/* +** Copyright (C) 1999-2013 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include +#include + +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include + +#include "utils.h" + +#define BUFFER_SIZE (1 << 12) + +static void lrintf_test (void) ; + +[+ FOR data_type ++]static void pcm_test_[+ (get "name") +] (const char *filename, int filetype, uint64_t hash) ; +[+ ENDFOR data_type ++] +static void pcm_test_float (const char *filename, int filetype, uint64_t hash, int replace_float) ; +static void pcm_test_double (const char *filename, int filetype, uint64_t hash, int replace_float) ; + +typedef union +{ double d [BUFFER_SIZE + 1] ; + float f [BUFFER_SIZE + 1] ; + int i [BUFFER_SIZE + 1] ; + short s [BUFFER_SIZE + 1] ; +} BUFFER ; + +/* Data written to the file. */ +static BUFFER data_out ; + +/* Data read back from the file. */ +static BUFFER data_in ; + +int +main (void) +{ + lrintf_test () ; + + pcm_test_bits_8 ("pcm-s8.raw", SF_FORMAT_RAW | SF_FORMAT_PCM_S8, 0xa335091249dbfLL) ; + pcm_test_bits_8 ("pcm-u8.raw", SF_FORMAT_RAW | SF_FORMAT_PCM_U8, 0x48c433d695f3fLL) ; + + pcm_test_bits_16 ("le-pcm16.raw", SF_ENDIAN_LITTLE | SF_FORMAT_RAW | SF_FORMAT_PCM_16, 0xb956c881ebf08LL) ; + pcm_test_bits_16 ("be-pcm16.raw", SF_ENDIAN_BIG | SF_FORMAT_RAW | SF_FORMAT_PCM_16, 0x2f840c55750f8LL) ; + + pcm_test_bits_24 ("le-pcm24.raw", SF_ENDIAN_LITTLE | SF_FORMAT_RAW | SF_FORMAT_PCM_24, 0xb6a759ab496f8LL) ; + pcm_test_bits_24 ("be-pcm24.raw", SF_ENDIAN_BIG | SF_FORMAT_RAW | SF_FORMAT_PCM_24, 0xf3eaf9c30b6f8LL) ; + + pcm_test_bits_32 ("le-pcm32.raw", SF_ENDIAN_LITTLE | SF_FORMAT_RAW | SF_FORMAT_PCM_32, 0xaece1c1c17f08LL) ; + pcm_test_bits_32 ("be-pcm32.raw", SF_ENDIAN_BIG | SF_FORMAT_RAW | SF_FORMAT_PCM_32, 0x9ddf142d0b0f8LL) ; + + /* Lite remove start */ + pcm_test_float ("le-float.raw", SF_ENDIAN_LITTLE | SF_FORMAT_RAW | SF_FORMAT_FLOAT, 0xad04f7554267aLL, SF_FALSE) ; + pcm_test_float ("be-float.raw", SF_ENDIAN_BIG | SF_FORMAT_RAW | SF_FORMAT_FLOAT, 0xde3e248fa9186LL, SF_FALSE) ; + + pcm_test_double ("le-double.raw", SF_ENDIAN_LITTLE | SF_FORMAT_RAW | SF_FORMAT_DOUBLE, 0x2726f958f669cLL, SF_FALSE) ; + pcm_test_double ("be-double.raw", SF_ENDIAN_BIG | SF_FORMAT_RAW | SF_FORMAT_DOUBLE, 0x3583f8ee51164LL, SF_FALSE) ; + + pcm_test_float ("le-float.raw", SF_ENDIAN_LITTLE | SF_FORMAT_RAW | SF_FORMAT_FLOAT, 0xad04f7554267aLL, SF_TRUE) ; + pcm_test_float ("be-float.raw", SF_ENDIAN_BIG | SF_FORMAT_RAW | SF_FORMAT_FLOAT, 0xde3e248fa9186LL, SF_TRUE) ; + + pcm_test_double ("le-double.raw", SF_ENDIAN_LITTLE | SF_FORMAT_RAW | SF_FORMAT_DOUBLE, 0x2726f958f669cLL, SF_TRUE) ; + pcm_test_double ("be-double.raw", SF_ENDIAN_BIG | SF_FORMAT_RAW | SF_FORMAT_DOUBLE, 0x3583f8ee51164LL, SF_TRUE) ; + /* Lite remove end */ + + return 0 ; +} /* main */ + +/*============================================================================================ +** Here are the test functions. +*/ + +static void +lrintf_test (void) +{ int k, items ; + float *float_data ; + int *int_data ; + + print_test_name ("lrintf_test", "") ; + + items = 1024 ; + + float_data = data_out.f ; + int_data = data_in.i ; + + for (k = 0 ; k < items ; k++) + float_data [k] = (k * ((k % 2) ? 333333.0 : -333333.0)) ; + + for (k = 0 ; k < items ; k++) + int_data [k] = lrintf (float_data [k]) ; + + for (k = 0 ; k < items ; k++) + if (fabs (int_data [k] - float_data [k]) > 1.0) + { printf ("\n\nLine %d: float : Incorrect sample (#%d : %f => %d).\n", __LINE__, k, float_data [k], int_data [k]) ; + exit (1) ; + } ; + + printf ("ok\n") ; +} /* lrintf_test */ + +[+ FOR data_type ++]static void +pcm_test_[+ (get "name") +] (const char *filename, int filetype, uint64_t hash) +{ SNDFILE *file ; + SF_INFO sfinfo ; + int k, items, zero_count ; + short *short_out, *short_in ; + int *int_out, *int_in ; + /* Lite remove start */ + float *float_out, *float_in ; + double *double_out, *double_in ; + /* Lite remove end */ + + print_test_name ("pcm_test_[+ (get "name") +]", filename) ; + + items = [+ (get "item_count") +] ; + + short_out = data_out.s ; + short_in = data_in.s ; + + zero_count = 0 ; + for (k = 0 ; k < items ; k++) + { short_out [k] = [+ (get "short_func") +] ; + zero_count = short_out [k] ? zero_count : zero_count + 1 ; + } ; + + if (zero_count > items / 4) + { printf ("\n\nLine %d: too many zeros.\n", __LINE__) ; + exit (1) ; + } ; + + sfinfo.samplerate = 44100 ; + sfinfo.frames = 123456789 ; /* Wrong length. Library should correct this on sf_close. */ + sfinfo.channels = 1 ; + sfinfo.format = filetype ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + + test_write_short_or_die (file, 0, short_out, items, __LINE__) ; + + sf_close (file) ; + + memset (short_in, 0, items * sizeof (short)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + + if (sfinfo.format != filetype) + { printf ("\n\nLine %d: Returned format incorrect (0x%08X => 0x%08X).\n", __LINE__, filetype, sfinfo.format) ; + exit (1) ; + } ; + + if (sfinfo.frames != items) + { printf ("\n\nLine %d: Incorrect number of frames in file. (%d => %" PRId64 ")\n", __LINE__, items, sfinfo.frames) ; + exit (1) ; + } ; + + if (sfinfo.channels != 1) + { printf ("\n\nLine %d: Incorrect number of channels in file.\n", __LINE__) ; + exit (1) ; + } ; + + check_log_buffer_or_die (file, __LINE__) ; + + test_read_short_or_die (file, 0, short_in, items, __LINE__) ; + + for (k = 0 ; k < items ; k++) + if (short_out [k] != short_in [k]) + { printf ("\n\nLine %d: Incorrect sample (#%d : 0x%x => 0x%x).\n", __LINE__, k, short_out [k], short_in [k]) ; + exit (1) ; + } ; + + sf_close (file) ; + + /* Finally, check the file hash. */ + check_file_hash_or_die (filename, hash, __LINE__) ; + + /*-------------------------------------------------------------------------- + ** Test sf_read/write_int () + */ + zero_count = 0 ; + + int_out = data_out.i ; + int_in = data_in.i ; + for (k = 0 ; k < items ; k++) + { int_out [k] = [+ (get "int_func") +] ; + zero_count = int_out [k] ? zero_count : zero_count + 1 ; + } ; + + if (zero_count > items / 4) + { printf ("\n\nLine %d: too many zeros.\n", __LINE__) ; + exit (1) ; + } ; + + sfinfo.samplerate = 44100 ; + sfinfo.frames = 123456789 ; /* Wrong length. Library should correct this on sf_close. */ + sfinfo.channels = 1 ; + sfinfo.format = filetype ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + + test_write_int_or_die (file, 0, int_out, items, __LINE__) ; + + sf_close (file) ; + + memset (int_in, 0, items * sizeof (int)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + + if (sfinfo.format != filetype) + { printf ("\n\nLine %d: Returned format incorrect (0x%08X => 0x%08X).\n", __LINE__, filetype, sfinfo.format) ; + exit (1) ; + } ; + + if (sfinfo.frames != items) + { printf ("\n\nLine %d: Incorrect number of frames in file. (%d => %" PRId64 ")\n", __LINE__, items, sfinfo.frames) ; + exit (1) ; + } ; + + if (sfinfo.channels != 1) + { printf ("\n\nLine %d: Incorrect number of channels in file.\n", __LINE__) ; + exit (1) ; + } ; + + check_log_buffer_or_die (file, __LINE__) ; + + test_read_int_or_die (file, 0, int_in, items, __LINE__) ; + + for (k = 0 ; k < items ; k++) + if (int_out [k] != int_in [k]) + { printf ("\n\nLine %d: int : Incorrect sample (#%d : 0x%x => 0x%x).\n", __LINE__, k, int_out [k], int_in [k]) ; + exit (1) ; + } ; + + sf_close (file) ; + + /* Lite remove start */ + /*-------------------------------------------------------------------------- + ** Test sf_read/write_float () + */ + zero_count = 0 ; + + float_out = data_out.f ; + float_in = data_in.f ; + for (k = 0 ; k < items ; k++) + { float_out [k] = [+ (get "float_func") +] ; + zero_count = (fabs (float_out [k]) > 1e-10) ? zero_count : zero_count + 1 ; + } ; + + if (zero_count > items / 4) + { printf ("\n\nLine %d: too many zeros (%d/%d).\n", __LINE__, zero_count, items) ; + exit (1) ; + } ; + + sfinfo.samplerate = 44100 ; + sfinfo.frames = 123456789 ; /* Wrong length. Library should correct this on sf_close. */ + sfinfo.channels = 1 ; + sfinfo.format = filetype ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + + sf_command (file, SFC_SET_NORM_FLOAT, NULL, SF_FALSE) ; + + test_write_float_or_die (file, 0, float_out, items, __LINE__) ; + + sf_close (file) ; + + memset (float_in, 0, items * sizeof (float)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + + if (sfinfo.format != filetype) + { printf ("\n\nLine %d: Returned format incorrect (0x%08X => 0x%08X).\n", __LINE__, filetype, sfinfo.format) ; + exit (1) ; + } ; + + if (sfinfo.frames != items) + { printf ("\n\nLine %d: Incorrect number of frames in file. (%d => %" PRId64 ")\n", __LINE__, items, sfinfo.frames) ; + exit (1) ; + } ; + + if (sfinfo.channels != 1) + { printf ("\n\nLine %d: Incorrect number of channels in file.\n", __LINE__) ; + exit (1) ; + } ; + + check_log_buffer_or_die (file, __LINE__) ; + + sf_command (file, SFC_SET_NORM_FLOAT, NULL, SF_FALSE) ; + + test_read_float_or_die (file, 0, float_in, items, __LINE__) ; + + for (k = 0 ; k < items ; k++) + if (fabs (float_out [k] - float_in [k]) > 1e-10) + { printf ("\n\nLine %d: float : Incorrect sample (#%d : %f => %f).\n", __LINE__, k, (double) float_out [k], (double) float_in [k]) ; + exit (1) ; + } ; + + sf_close (file) ; + + /*-------------------------------------------------------------------------- + ** Test sf_read/write_double () + */ + zero_count = 0 ; + + double_out = data_out.d ; + double_in = data_in.d ; + for (k = 0 ; k < items ; k++) + { double_out [k] = [+ (get "float_func") +] ; + zero_count = (fabs (double_out [k]) > 1e-10) ? zero_count : zero_count + 1 ; + } ; + + if (zero_count > items / 4) + { printf ("\n\nLine %d: too many zeros (%d/%d).\n", __LINE__, zero_count, items) ; + exit (1) ; + } ; + + sfinfo.samplerate = 44100 ; + sfinfo.frames = 123456789 ; /* Wrong length. Library should correct this on sf_close. */ + sfinfo.channels = 1 ; + sfinfo.format = filetype ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + + sf_command (file, SFC_SET_NORM_DOUBLE, NULL, SF_FALSE) ; + + test_write_double_or_die (file, 0, double_out, items, __LINE__) ; + + sf_close (file) ; + + memset (double_in, 0, items * sizeof (double)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + + if (sfinfo.format != filetype) + { printf ("\n\nLine %d: Returned format incorrect (0x%08X => 0x%08X).\n", __LINE__, filetype, sfinfo.format) ; + exit (1) ; + } ; + + if (sfinfo.frames != items) + { printf ("\n\nLine %d: Incorrect number of frames in file. (%d => %" PRId64 ")\n", __LINE__, items, sfinfo.frames) ; + exit (1) ; + } ; + + if (sfinfo.channels != 1) + { printf ("\n\nLine %d: Incorrect number of channels in file.\n", __LINE__) ; + exit (1) ; + } ; + + check_log_buffer_or_die (file, __LINE__) ; + + sf_command (file, SFC_SET_NORM_DOUBLE, NULL, SF_FALSE) ; + + test_read_double_or_die (file, 0, double_in, items, __LINE__) ; + + for (k = 0 ; k < items ; k++) + if (fabs (double_out [k] - double_in [k]) > 1e-10) + { printf ("\n\nLine %d: double : Incorrect sample (#%d : %f => %f).\n", __LINE__, k, double_out [k], double_in [k]) ; + exit (1) ; + } ; + + sf_close (file) ; + /* Lite remove end */ + unlink (filename) ; + + puts ("ok") ; +} /* pcm_test_[+ (get "name") +] */ + +[+ ENDFOR data_type ++] + +/*============================================================================== +*/ + +static void +pcm_test_float (const char *filename, int filetype, uint64_t hash, int replace_float) +{ SNDFILE *file ; + SF_INFO sfinfo ; + int k, items, frames ; + int sign ; + double *data, error ; + + print_test_name (replace_float ? "pcm_test_float (replace)" : "pcm_test_float", filename) ; + + items = BUFFER_SIZE ; + + data = data_out.d ; + for (sign = 1, k = 0 ; k < items ; k++) + { data [k] = ((double) (k * sign)) / 100.0 ; + sign = (sign > 0) ? -1 : 1 ; + } ; + + sfinfo.samplerate = 44100 ; + sfinfo.frames = items ; + sfinfo.channels = 1 ; + sfinfo.format = filetype ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + sf_command (file, SFC_TEST_IEEE_FLOAT_REPLACE, NULL, replace_float) ; + if (replace_float && string_in_log_buffer (file, "Using IEEE replacement") == 0) + { printf ("\n\nLine %d : Float replacement code not working.\n\n", __LINE__) ; + dump_log_buffer (file) ; + exit (1) ; + } ; + + test_write_double_or_die (file, 0, data, items, __LINE__) ; + + sf_close (file) ; + + check_file_hash_or_die (filename, hash, __LINE__) ; + + memset (data, 0, items * sizeof (double)) ; + + if ((filetype & SF_FORMAT_TYPEMASK) != SF_FORMAT_RAW) + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + sf_command (file, SFC_TEST_IEEE_FLOAT_REPLACE, NULL, replace_float) ; + if (replace_float && string_in_log_buffer (file, "Using IEEE replacement") == 0) + { printf ("\n\nLine %d : Float replacement code not working.\n\n", __LINE__) ; + dump_log_buffer (file) ; + exit (1) ; + } ; + + if (sfinfo.format != filetype) + { printf ("\n\nError (%s:%d) Mono : Returned format incorrect (0x%08X => 0x%08X).\n", __FILE__, __LINE__, filetype, sfinfo.format) ; + exit (1) ; + } ; + + if (sfinfo.frames != items) + { printf ("\n\nError (%s:%d) Mono : Incorrect number of frames in file. (%d => %" PRId64 ")\n", __FILE__, __LINE__, items, sfinfo.frames) ; + exit (1) ; + } ; + + if (sfinfo.channels != 1) + { printf ("\n\nError (%s:%d) Mono : Incorrect number of channels in file.\n", __FILE__, __LINE__) ; + exit (1) ; + } ; + + check_log_buffer_or_die (file, __LINE__) ; + + test_read_double_or_die (file, 0, data, items, __LINE__) ; + + for (sign = -1, k = 0 ; k < items ; k++) + { error = fabs (data [k] - ((double) k) / 100.0 * (sign *= -1)) ; + if (fabs (data [k]) > 1e-100 && fabs (error / data [k]) > 1e-5) + { printf ("\n\nError (%s:%d) Mono : Incorrect sample (#%d : %f => %f).\n", __FILE__, __LINE__, k, ((double) k) / 100.0, data [k]) ; + exit (1) ; + } ; + } ; + + /* Seek to end of file. */ + test_seek_or_die (file, 0, SEEK_END, sfinfo.frames, sfinfo.channels, __LINE__) ; + + /* Seek to start of file. */ + test_seek_or_die (file, 0, SEEK_SET, 0, sfinfo.channels, __LINE__) ; + + test_read_double_or_die (file, 0, data, 4, __LINE__) ; + for (k = 0 ; k < 4 ; k++) + { error = fabs (data [k] - ((double) k) / 100.0 * (sign *= -1)) ; + if (fabs (data [k]) > 1e-100 && fabs (error / data [k]) > 1e-5) + { printf ("\n\nError (%s:%d) Mono : Incorrect sample (#%d : %f => %f).\n", __FILE__, __LINE__, k, ((double) k) / 100.0, data [k]) ; + exit (1) ; + } ; + } ; + + /* Seek to offset from start of file. */ + test_seek_or_die (file, 10, SEEK_SET, 10, sfinfo.channels, __LINE__) ; + + test_read_double_or_die (file, 0, data + 10, 4, __LINE__) ; + for (k = 10 ; k < 14 ; k++) + { error = fabs (data [k] - ((double) k) / 100.0 * (sign *= -1)) ; + if (fabs (data [k]) > 1e-100 && fabs (error / data [k]) > 1e-5) + { printf ("\n\nError (%s:%d) Mono : Incorrect sample (#%d : %f => %f).\n", __FILE__, __LINE__, k, ((double) k) / 100.0, data [k]) ; + exit (1) ; + } ; + } ; + + /* Seek to offset from current position. */ + test_seek_or_die (file, 6, SEEK_CUR, 20, sfinfo.channels, __LINE__) ; + + test_read_double_or_die (file, 0, data + 20, 4, __LINE__) ; + for (k = 20 ; k < 24 ; k++) + { error = fabs (data [k] - ((double) k) / 100.0 * (sign *= -1)) ; + if (fabs (data [k]) > 1e-100 && fabs (error / data [k]) > 1e-5) + { printf ("\n\nError (%s:%d) Mono : Incorrect sample (#%d : %f => %f).\n", __FILE__, __LINE__, k, ((double) k) / 100.0, data [k]) ; + exit (1) ; + } ; + } ; + + /* Seek to offset from end of file. */ + test_seek_or_die (file, -1 * (sfinfo.frames - 10), SEEK_END, 10, sfinfo.channels, __LINE__) ; + + test_read_double_or_die (file, 0, data + 10, 4, __LINE__) ; + for (k = 10 ; k < 14 ; k++) + { error = fabs (data [k] - ((double) k) / 100.0 * (sign *= -1)) ; + if (fabs (data [k]) > 1e-100 && fabs (error / data [k]) > 1e-5) + { printf ("\n\nError (%s:%d) Mono : Incorrect sample (#%d : %f => %f).\n", __FILE__, __LINE__, k, ((double) k) / 100.0, data [k]) ; + exit (1) ; + } ; + } ; + + sf_close (file) ; + + /* Now test Stereo. */ + + if ((filetype & SF_FORMAT_TYPEMASK) == SF_FORMAT_SVX) /* SVX is mono only */ + { printf ("ok\n") ; + return ; + } ; + + items = BUFFER_SIZE ; + + data = data_out.d ; + for (sign = -1, k = 0 ; k < items ; k++) + data [k] = ((double) k) / 100.0 * (sign *= -1) ; + + sfinfo.samplerate = 44100 ; + sfinfo.frames = items ; + sfinfo.channels = 2 ; + sfinfo.format = filetype ; + + frames = items / sfinfo.channels ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + sf_command (file, SFC_TEST_IEEE_FLOAT_REPLACE, NULL, replace_float) ; + if (replace_float && string_in_log_buffer (file, "Using IEEE replacement") == 0) + { printf ("\n\nLine %d : Float replacement code not working.\n\n", __LINE__) ; + dump_log_buffer (file) ; + exit (1) ; + } ; + + test_writef_double_or_die (file, 0, data, frames, __LINE__) ; + + sf_close (file) ; + + check_file_hash_or_die (filename, hash, __LINE__) ; + + memset (data, 0, items * sizeof (double)) ; + + if ((filetype & SF_FORMAT_TYPEMASK) != SF_FORMAT_RAW) + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + sf_command (file, SFC_TEST_IEEE_FLOAT_REPLACE, NULL, replace_float) ; + if (replace_float && string_in_log_buffer (file, "Using IEEE replacement") == 0) + { printf ("\n\nLine %d : Float replacement code not working.\n\n", __LINE__) ; + dump_log_buffer (file) ; + exit (1) ; + } ; + + if (sfinfo.format != filetype) + { printf ("\n\nError (%s:%d) Stereo : Returned format incorrect (0x%08X => 0x%08X).\n", __FILE__, __LINE__, filetype, sfinfo.format) ; + exit (1) ; + } ; + + if (sfinfo.frames != frames) + { printf ("\n\nError (%s:%d) Stereo : Incorrect number of frames in file. (%d => %" PRId64 ")\n", __FILE__, __LINE__, frames, sfinfo.frames) ; + exit (1) ; + } ; + + if (sfinfo.channels != 2) + { printf ("\n\nError (%s:%d) Stereo : Incorrect number of channels in file.\n", __FILE__, __LINE__) ; + exit (1) ; + } ; + + check_log_buffer_or_die (file, __LINE__) ; + + test_readf_double_or_die (file, 0, data, frames, __LINE__) ; + for (sign = -1, k = 0 ; k < items ; k++) + { error = fabs (data [k] - ((double) k) / 100.0 * (sign *= -1)) ; + if (fabs (data [k]) > 1e-100 && fabs (error / data [k]) > 1e-5) + { printf ("\n\nError (%s:%d) Stereo : Incorrect sample (#%d : %f => %f).\n", __FILE__, __LINE__, k, ((double) k) / 100.0, data [k]) ; + exit (1) ; + } ; + } ; + + /* Seek to start of file. */ + test_seek_or_die (file, 0, SEEK_SET, 0, sfinfo.channels, __LINE__) ; + + test_readf_double_or_die (file, 0, data, 4, __LINE__) ; + for (k = 0 ; k < 4 ; k++) + { error = fabs (data [k] - ((double) k) / 100.0 * (sign *= -1)) ; + if (fabs (data [k]) > 1e-100 && fabs (error / data [k]) > 1e-5) + { printf ("\n\nError (%s:%d) Stereo : Incorrect sample (#%d : %f => %f).\n", __FILE__, __LINE__, k, ((double) k) / 100.0, data [k]) ; + exit (1) ; + } ; + } ; + + /* Seek to offset from start of file. */ + test_seek_or_die (file, 10, SEEK_SET, 10, sfinfo.channels, __LINE__) ; + + test_readf_double_or_die (file, 0, data + 20, 2, __LINE__) ; + for (k = 20 ; k < 24 ; k++) + { error = fabs (data [k] - ((double) k) / 100.0 * (sign *= -1)) ; + if (fabs (data [k]) > 1e-100 && fabs (error / data [k]) > 1e-5) + { printf ("\n\nError (%s:%d) Stereo : Incorrect sample (#%d : %f => %f).\n", __FILE__, __LINE__, k, ((double) k) / 100.0, data [k]) ; + exit (1) ; + } ; + } ; + + /* Seek to offset from current position. */ + test_seek_or_die (file, 8, SEEK_CUR, 20, sfinfo.channels, __LINE__) ; + + test_readf_double_or_die (file, 0, data + 40, 2, __LINE__) ; + for (k = 40 ; k < 44 ; k++) + { error = fabs (data [k] - ((double) k) / 100.0 * (sign *= -1)) ; + if (fabs (data [k]) > 1e-100 && fabs (error / data [k]) > 1e-5) + { printf ("\n\nError (%s:%d) Stereo : Incorrect sample (#%d : %f => %f).\n", __FILE__, __LINE__, k, ((double) k) / 100.0, data [k]) ; + exit (1) ; + } ; + } ; + + /* Seek to offset from end of file. */ + test_seek_or_die (file, -1 * (sfinfo.frames - 10), SEEK_END, 10, sfinfo.channels, __LINE__) ; + + test_readf_double_or_die (file, 0, data + 20, 2, __LINE__) ; + for (k = 20 ; k < 24 ; k++) + { error = fabs (data [k] - ((double) k) / 100.0 * (sign *= -1)) ; + if (fabs (data [k]) > 1e-100 && fabs (error / data [k]) > 1e-5) + { printf ("\n\nError (%s:%d) Stereo : Incorrect sample (#%d : %f => %f).\n", __FILE__, __LINE__, k, ((double) k) / 100.0, data [k]) ; + exit (1) ; + } ; + } ; + + sf_close (file) ; + + printf ("ok\n") ; + unlink (filename) ; +} /* pcm_test_float */ + +static void +pcm_test_double (const char *filename, int filetype, uint64_t hash, int replace_float) +{ SNDFILE *file ; + SF_INFO sfinfo ; + int k, items, frames ; + int sign ; + double *data, error ; + + /* This is the best test routine. Other should be brought up to this standard. */ + + print_test_name (replace_float ? "pcm_test_double (replace)" : "pcm_test_double", filename) ; + + items = BUFFER_SIZE ; + + data = data_out.d ; + for (sign = 1, k = 0 ; k < items ; k++) + { data [k] = ((double) (k * sign)) / 100.0 ; + sign = (sign > 0) ? -1 : 1 ; + } ; + + sfinfo.samplerate = 44100 ; + sfinfo.frames = items ; + sfinfo.channels = 1 ; + sfinfo.format = filetype ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + sf_command (file, SFC_TEST_IEEE_FLOAT_REPLACE, NULL, replace_float) ; + if (replace_float && string_in_log_buffer (file, "Using IEEE replacement") == 0) + { printf ("\n\nLine %d : Float replacement code not working.\n\n", __LINE__) ; + dump_log_buffer (file) ; + exit (1) ; + } ; + + test_write_double_or_die (file, 0, data, items, __LINE__) ; + + sf_close (file) ; + + check_file_hash_or_die (filename, hash, __LINE__) ; + + memset (data, 0, items * sizeof (double)) ; + + if ((filetype & SF_FORMAT_TYPEMASK) != SF_FORMAT_RAW) + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + sf_command (file, SFC_TEST_IEEE_FLOAT_REPLACE, NULL, replace_float) ; + if (replace_float && string_in_log_buffer (file, "Using IEEE replacement") == 0) + { printf ("\n\nLine %d : Float replacement code not working.\n\n", __LINE__) ; + dump_log_buffer (file) ; + exit (1) ; + } ; + + if (sfinfo.format != filetype) + { printf ("\n\nError (%s:%d) Mono : Returned format incorrect (0x%08X => 0x%08X).\n", __FILE__, __LINE__, filetype, sfinfo.format) ; + exit (1) ; + } ; + + if (sfinfo.frames != items) + { printf ("\n\nError (%s:%d) Mono : Incorrect number of frames in file. (%d => %" PRId64 ")\n", __FILE__, __LINE__, items, sfinfo.frames) ; + exit (1) ; + } ; + + if (sfinfo.channels != 1) + { printf ("\n\nError (%s:%d) Mono : Incorrect number of channels in file.\n", __FILE__, __LINE__) ; + exit (1) ; + } ; + + check_log_buffer_or_die (file, __LINE__) ; + + test_read_double_or_die (file, 0, data, items, __LINE__) ; + + for (sign = -1, k = 0 ; k < items ; k++) + { error = fabs (data [k] - ((double) k) / 100.0 * (sign *= -1)) ; + if (fabs (data [k]) > 1e-100 && fabs (error / data [k]) > 1e-5) + { printf ("\n\nError (%s:%d) Mono : Incorrect sample (#%d : %f => %f).\n", __FILE__, __LINE__, k, ((double) k) / 100.0, data [k]) ; + exit (1) ; + } ; + } ; + + /* Seek to start of file. */ + test_seek_or_die (file, 0, SEEK_SET, 0, sfinfo.channels, __LINE__) ; + + test_read_double_or_die (file, 0, data, 4, __LINE__) ; + for (k = 0 ; k < 4 ; k++) + { error = fabs (data [k] - ((double) k) / 100.0 * (sign *= -1)) ; + if (fabs (data [k]) > 1e-100 && fabs (error / data [k]) > 1e-5) + { printf ("\n\nError (%s:%d) Mono : Incorrect sample (#%d : %f => %f).\n", __FILE__, __LINE__, k, ((double) k) / 100.0, data [k]) ; + exit (1) ; + } ; + } ; + + /* Seek to offset from start of file. */ + test_seek_or_die (file, 10, SEEK_SET, 10, sfinfo.channels, __LINE__) ; + + test_read_double_or_die (file, 0, data + 10, 4, __LINE__) ; + + test_seek_or_die (file, 0, SEEK_CUR, 14, sfinfo.channels, __LINE__) ; + + for (k = 10 ; k < 14 ; k++) + { error = fabs (data [k] - ((double) k) / 100.0 * (sign *= -1)) ; + if (fabs (data [k]) > 1e-100 && fabs (error / data [k]) > 1e-5) + { printf ("\n\nError (%s:%d) Mono : Incorrect sample (#%d : %f => %f).\n", __FILE__, __LINE__, k, ((double) k) / 100.0, data [k]) ; + exit (1) ; + } ; + } ; + + /* Seek to offset from current position. */ + test_seek_or_die (file, 6, SEEK_CUR, 20, sfinfo.channels, __LINE__) ; + + test_read_double_or_die (file, 0, data + 20, 4, __LINE__) ; + for (k = 20 ; k < 24 ; k++) + { error = fabs (data [k] - ((double) k) / 100.0 * (sign *= -1)) ; + if (fabs (data [k]) > 1e-100 && fabs (error / data [k]) > 1e-5) + { printf ("\n\nError (%s:%d) Mono : Incorrect sample (#%d : %f => %f).\n", __FILE__, __LINE__, k, ((double) k) / 100.0, data [k]) ; + exit (1) ; + } ; + } ; + + /* Seek to offset from end of file. */ + test_seek_or_die (file, -1 * (sfinfo.frames - 10), SEEK_END, 10, sfinfo.channels, __LINE__) ; + + test_read_double_or_die (file, 0, data + 10, 4, __LINE__) ; + for (k = 10 ; k < 14 ; k++) + { error = fabs (data [k] - ((double) k) / 100.0 * (sign *= -1)) ; + if (fabs (data [k]) > 1e-100 && fabs (error / data [k]) > 1e-5) + { printf ("\n\nError (%s:%d) Mono : Incorrect sample (#%d : %f => %f).\n", __FILE__, __LINE__, k, ((double) k) / 100.0, data [k]) ; + exit (1) ; + } ; + } ; + + sf_close (file) ; + + /* Now test Stereo. */ + + if ((filetype & SF_FORMAT_TYPEMASK) == SF_FORMAT_SVX) /* SVX is mono only */ + { printf ("ok\n") ; + return ; + } ; + + items = BUFFER_SIZE ; + + data = data_out.d ; + for (sign = -1, k = 0 ; k < items ; k++) + data [k] = ((double) k) / 100.0 * (sign *= -1) ; + + sfinfo.samplerate = 44100 ; + sfinfo.frames = items ; + sfinfo.channels = 2 ; + sfinfo.format = filetype ; + + frames = items / sfinfo.channels ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + sf_command (file, SFC_TEST_IEEE_FLOAT_REPLACE, NULL, replace_float) ; + if (replace_float && string_in_log_buffer (file, "Using IEEE replacement") == 0) + { printf ("\n\nLine %d : Float replacement code not working.\n\n", __LINE__) ; + dump_log_buffer (file) ; + exit (1) ; + } ; + + test_writef_double_or_die (file, 0, data, frames, __LINE__) ; + + sf_close (file) ; + + check_file_hash_or_die (filename, hash, __LINE__) ; + + memset (data, 0, items * sizeof (double)) ; + + if ((filetype & SF_FORMAT_TYPEMASK) != SF_FORMAT_RAW) + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + sf_command (file, SFC_TEST_IEEE_FLOAT_REPLACE, NULL, replace_float) ; + if (replace_float && string_in_log_buffer (file, "Using IEEE replacement") == 0) + { printf ("\n\nLine %d : Float replacement code not working.\n\n", __LINE__) ; + dump_log_buffer (file) ; + exit (1) ; + } ; + + if (sfinfo.format != filetype) + { printf ("\n\nError (%s:%d) Stereo : Returned format incorrect (0x%08X => 0x%08X).\n", __FILE__, __LINE__, filetype, sfinfo.format) ; + exit (1) ; + } ; + + if (sfinfo.frames != frames) + { printf ("\n\nError (%s:%d) Stereo : Incorrect number of frames in file. (%d => %" PRId64 ")\n", __FILE__, __LINE__, frames, sfinfo.frames) ; + exit (1) ; + } ; + + if (sfinfo.channels != 2) + { printf ("\n\nError (%s:%d) Stereo : Incorrect number of channels in file.\n", __FILE__, __LINE__) ; + exit (1) ; + } ; + + check_log_buffer_or_die (file, __LINE__) ; + + test_readf_double_or_die (file, 0, data, frames, __LINE__) ; + + for (sign = -1, k = 0 ; k < items ; k++) + { error = fabs (data [k] - ((double) k) / 100.0 * (sign *= -1)) ; + if (fabs (data [k]) > 1e-100 && fabs (error / data [k]) > 1e-5) + { printf ("\n\nError (%s:%d) Stereo : Incorrect sample (#%d : %f => %f).\n", __FILE__, __LINE__, k, ((double) k) / 100.0, data [k]) ; + exit (1) ; + } ; + } ; + + /* Seek to start of file. */ + test_seek_or_die (file, 0, SEEK_SET, 0, sfinfo.channels, __LINE__) ; + + test_read_double_or_die (file, 0, data, 4, __LINE__) ; + for (k = 0 ; k < 4 ; k++) + { error = fabs (data [k] - ((double) k) / 100.0 * (sign *= -1)) ; + if (fabs (data [k]) > 1e-100 && fabs (error / data [k]) > 1e-5) + { printf ("\n\nError (%s:%d) Stereo : Incorrect sample (#%d : %f => %f).\n", __FILE__, __LINE__, k, ((double) k) / 100.0, data [k]) ; + exit (1) ; + } ; + } ; + + /* Seek to offset from start of file. */ + test_seek_or_die (file, 10, SEEK_SET, 10, sfinfo.channels, __LINE__) ; + + test_read_double_or_die (file, 0, data + 10, 4, __LINE__) ; + for (k = 20 ; k < 24 ; k++) + { error = fabs (data [k] - ((double) k) / 100.0 * (sign *= -1)) ; + if (fabs (data [k]) > 1e-100 && fabs (error / data [k]) > 1e-5) + { printf ("\n\nError (%s:%d) Stereo : Incorrect sample (#%d : %f => %f).\n", __FILE__, __LINE__, k, ((double) k) / 100.0, data [k]) ; + exit (1) ; + } ; + } ; + + /* Seek to offset from current position. */ + test_seek_or_die (file, 8, SEEK_CUR, 20, sfinfo.channels, __LINE__) ; + + test_readf_double_or_die (file, 0, data + 40, 4, __LINE__) ; + for (k = 40 ; k < 44 ; k++) + { error = fabs (data [k] - ((double) k) / 100.0 * (sign *= -1)) ; + if (fabs (data [k]) > 1e-100 && fabs (error / data [k]) > 1e-5) + { printf ("\n\nError (%s:%d) Stereo : Incorrect sample (#%d : %f => %f).\n", __FILE__, __LINE__, k, ((double) k) / 100.0, data [k]) ; + exit (1) ; + } ; + } ; + + /* Seek to offset from end of file. */ + test_seek_or_die (file, -1 * (sfinfo.frames -10), SEEK_END, 10, sfinfo.channels, __LINE__) ; + + test_readf_double_or_die (file, 0, data + 20, 4, __LINE__) ; + for (k = 20 ; k < 24 ; k++) + { error = fabs (data [k] - ((double) k) / 100.0 * (sign *= -1)) ; + if (fabs (data [k]) > 1e-100 && fabs (error / data [k]) > 1e-5) + { printf ("\n\nError (%s:%d) Stereo : Incorrect sample (#%d : %f => %f).\n", __FILE__, __LINE__, k, ((double) k) / 100.0, data [k]) ; + exit (1) ; + } ; + } ; + + sf_close (file) ; + + printf ("ok\n") ; + unlink (filename) ; +} /* pcm_test_double */ + +/*============================================================================== +*/ diff --git a/extern/libsndfile-modified/tests/peak_chunk_test.c b/extern/libsndfile-modified/tests/peak_chunk_test.c new file mode 100644 index 000000000..3e1aa3d30 --- /dev/null +++ b/extern/libsndfile-modified/tests/peak_chunk_test.c @@ -0,0 +1,371 @@ +/* +** Copyright (C) 2001-2016 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include +#include + +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include + +#include "utils.h" + +#define BUFFER_LEN (1 << 15) +#define LOG_BUFFER_SIZE 1024 + + +static void test_float_peak (const char *filename, int filetype) ; +static void read_write_peak_test (const char *filename, int filetype) ; + +static void check_logged_peaks (char *buffer) ; + +/* Force the start of this buffer to be double aligned. Sparc-solaris will +** choke if its not. +*/ +static double data [BUFFER_LEN] ; +static char log_buffer [LOG_BUFFER_SIZE] ; + +int +main (int argc, char *argv []) +{ int do_all = 0 ; + int test_count = 0 ; + + if (argc != 2) + { printf ("Usage : %s \n", argv [0]) ; + printf (" Where is one of the following:\n") ; + printf (" aiff - test AIFF file PEAK chunk\n") ; + printf (" caf - test CAF file PEAK chunk\n") ; + printf (" wav - test WAV file peak chunk\n") ; + printf (" all - perform all tests\n") ; + exit (1) ; + } ; + + do_all = ! strcmp (argv [1], "all") ; + + if (do_all || ! strcmp (argv [1], "wav")) + { test_float_peak ("peak_float.wav", SF_FORMAT_WAV | SF_FORMAT_FLOAT) ; + test_float_peak ("peak_float.wavex", SF_FORMAT_WAVEX | SF_FORMAT_FLOAT) ; + test_float_peak ("peak_float.rifx", SF_ENDIAN_BIG | SF_FORMAT_WAV | SF_FORMAT_FLOAT) ; + + read_write_peak_test ("rw_peak.wav", SF_FORMAT_WAV | SF_FORMAT_FLOAT) ; + read_write_peak_test ("rw_peak.wavex", SF_FORMAT_WAVEX | SF_FORMAT_FLOAT) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "aiff")) + { test_float_peak ("peak_float.aiff", SF_FORMAT_AIFF | SF_FORMAT_FLOAT) ; + + read_write_peak_test ("rw_peak.aiff", SF_FORMAT_AIFF | SF_FORMAT_FLOAT) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "caf")) + { test_float_peak ("peak_float.caf", SF_FORMAT_CAF | SF_FORMAT_FLOAT) ; + + read_write_peak_test ("rw_peak.caf", SF_FORMAT_CAF | SF_FORMAT_FLOAT) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "rf64")) + { test_float_peak ("peak_float.rf64", SF_FORMAT_RF64 | SF_FORMAT_FLOAT) ; + + read_write_peak_test ("rw_peak.rf64", SF_FORMAT_RF64 | SF_FORMAT_FLOAT) ; + test_count++ ; + } ; + + if (test_count == 0) + { printf ("Mono : ************************************\n") ; + printf ("Mono : * No '%s' test defined.\n", argv [1]) ; + printf ("Mono : ************************************\n") ; + return 1 ; + } ; + + return 0 ; +} /* main */ + +/*============================================================================================ +** Here are the test functions. +*/ + +static void +test_float_peak (const char *filename, int filetype) +{ SNDFILE *file ; + SF_INFO sfinfo ; + int k, frames, count ; + + print_test_name ("test_float_peak", filename) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + sfinfo.samplerate = 44100 ; + sfinfo.format = filetype ; + sfinfo.channels = 4 ; + sfinfo.frames = 0 ; + + frames = BUFFER_LEN / sfinfo.channels ; + + /* Create some random data with a peak value of 0.66. */ + for (k = 0 ; k < BUFFER_LEN ; k++) + data [k] = (rand () % 2000) / 3000.0 ; + + /* Insert some larger peaks a know locations. */ + data [4 * (frames / 8) + 0] = (frames / 8) * 0.01 ; /* First channel */ + data [4 * (frames / 6) + 1] = (frames / 6) * 0.01 ; /* Second channel */ + data [4 * (frames / 4) + 2] = (frames / 4) * 0.01 ; /* Third channel */ + data [4 * (frames / 2) + 3] = (frames / 2) * 0.01 ; /* Fourth channel */ + + /* Write a file with PEAK chunks. */ + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, 0, __LINE__) ; + + /* Try to confuse the header writer by adding a removing the PEAK chunk. */ + sf_command (file, SFC_SET_ADD_PEAK_CHUNK, NULL, SF_TRUE) ; + sf_command (file, SFC_SET_ADD_PEAK_CHUNK, NULL, SF_FALSE) ; + sf_command (file, SFC_SET_ADD_PEAK_CHUNK, NULL, SF_TRUE) ; + + /* Write the data in four passed. The data is designed so that peaks will + ** be written in the different calls to sf_write_double (). + */ + for (count = 0 ; count < 4 ; count ++) + test_write_double_or_die (file, 0, data + count * BUFFER_LEN / 4, BUFFER_LEN / 4, BUFFER_LEN / 4) ; + + sf_close (file) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, 0, __LINE__) ; + + if (sfinfo.format != filetype) + { printf ("\n\nLine %d: Returned format incorrect (0x%08X => 0x%08X).\n", __LINE__, filetype, sfinfo.format) ; + exit (1) ; + } ; + + if (sfinfo.frames != frames) + { printf ("\n\nLine %d: Incorrect number of frames in file. (%d => %ld)\n", __LINE__, frames, (long) sfinfo.frames) ; + exit (1) ; + } ; + + if (sfinfo.channels != 4) + { printf ("\n\nLine %d: Incorrect number of channels in file.\n", __LINE__) ; + exit (1) ; + } ; + + /* Check these two commands. */ + if (sf_command (file, SFC_GET_SIGNAL_MAX, data, sizeof (double)) == SF_FALSE) + { printf ("\n\nLine %d: Command should have returned SF_TRUE.\n", __LINE__) ; + exit (1) ; + } ; + + if (fabs (data [0] - (frames / 2) * 0.01) > 0.01) + { printf ("\n\nLine %d: Bad peak value (%f should be %f) for command SFC_GET_SIGNAL_MAX.\n", __LINE__, data [0], (frames / 2) * 0.01) ; + exit (1) ; + } ; + + if (sf_command (file, SFC_GET_MAX_ALL_CHANNELS, data, sizeof (double) * sfinfo.channels) == SF_FALSE) + { printf ("\n\nLine %d: Command should have returned SF_TRUE.\n", __LINE__) ; + exit (1) ; + } ; + + if (fabs (data [3] - (frames / 2) * 0.01) > 0.01) + { printf ("\n\nLine %d: Bad peak value (%f should be %f) for command SFC_GET_MAX_ALL_CHANNELS.\n", __LINE__, data [0], (frames / 2) * 0.01) ; + exit (1) ; + } ; + + /* Get the log buffer data. */ + log_buffer [0] = 0 ; + sf_command (file, SFC_GET_LOG_INFO, log_buffer, LOG_BUFFER_SIZE) ; + + if (strlen (log_buffer) == 0) + { printf ("\n\nLine %d: Empty log buffer,\n", __LINE__) ; + exit (1) ; + } ; + + check_logged_peaks (log_buffer) ; + + sf_close (file) ; + + /* Write a file ***without*** PEAK chunks. */ + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, 0, __LINE__) ; + + /* Try to confuse the header writer by adding a removing the PEAK chunk. */ + sf_command (file, SFC_SET_ADD_PEAK_CHUNK, NULL, SF_FALSE) ; + sf_command (file, SFC_SET_ADD_PEAK_CHUNK, NULL, SF_TRUE) ; + sf_command (file, SFC_SET_ADD_PEAK_CHUNK, NULL, SF_FALSE) ; + + /* Write the data in four passed. The data is designed so that peaks will + ** be written in the different calls to sf_write_double (). + */ + for (count = 0 ; count < 4 ; count ++) + test_write_double_or_die (file, 0, data + count * BUFFER_LEN / 4, BUFFER_LEN / 4, BUFFER_LEN / 4) ; + + sf_close (file) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, 0, __LINE__) ; + + /* Check these two commands. */ + if (sf_command (file, SFC_GET_SIGNAL_MAX, data, sizeof (double))) + { printf ("\n\nLine %d: Command should have returned SF_FALSE.\n", __LINE__) ; + exit (1) ; + } ; + + if (sf_command (file, SFC_GET_MAX_ALL_CHANNELS, data, sizeof (double) * sfinfo.channels)) + { printf ("\n\nLine %d: Command should have returned SF_FALSE.\n", __LINE__) ; + exit (1) ; + } ; + + /* Get the log buffer data. */ + log_buffer [0] = 0 ; + sf_command (file, SFC_GET_LOG_INFO, log_buffer, LOG_BUFFER_SIZE) ; + + if (strlen (log_buffer) == 0) + { printf ("\n\nLine %d: Empty log buffer,\n", __LINE__) ; + exit (1) ; + } ; + + if (strstr (log_buffer, "PEAK :") != NULL) + { printf ("\n\nLine %d: Should not have a PEAK chunk in this file.\n\n", __LINE__) ; + puts (log_buffer) ; + exit (1) ; + } ; + + sf_close (file) ; + + unlink (filename) ; + printf ("ok\n") ; +} /* test_float_peak */ + +static void +check_logged_peaks (char *buffer) +{ char *cptr ; + int k, chan, channel_count, position ; + float value ; + + if (strstr (buffer, "should") || strstr (buffer, "*")) + { printf ("\n\nLine %d: Something wrong in buffer. Dumping.\n", __LINE__) ; + puts (buffer) ; + exit (1) ; + } ; + + channel_count = 0 ; + cptr = strstr (buffer, "Channels") ; + if (cptr && sscanf (cptr, "Channels : %d", &k) == 1) + channel_count = k ; + else if (cptr && sscanf (cptr, "Channels / frame : %d", &k) == 1) + channel_count = k ; + else + { printf ("\n\nLine %d: Couldn't find channel count.\n", __LINE__) ; + exit (1) ; + } ; + + if (channel_count != 4) + { printf ("\n\nLine %d: Wrong channel count (4 ->%d).\n", __LINE__, channel_count) ; + exit (1) ; + } ; + + if (! (cptr = strstr (buffer, "Ch Position Value"))) + { printf ("\n\nLine %d: Can't find PEAK data.\n", __LINE__) ; + exit (1) ; + } ; + + for (k = 0 ; k < channel_count ; k++) + { if (! (cptr = strchr (cptr, '\n'))) + { printf ("\n\nLine %d: Got lost.\n", __LINE__) ; + exit (1) ; + } ; + if (sscanf (cptr, "%d %d %f", &chan, &position, &value) != 3) + { printf ("\n\nLine %d: sscanf failed.\n", __LINE__) ; + exit (1) ; + } ; + if (position == 0) + { printf ("\n\nLine %d: peak position for channel %d should not be at offset 0.\n", __LINE__, chan) ; + printf ("%s", buffer) ; + exit (1) ; + } ; + if (chan != k || fabs ((position) * 0.01 - value) > 1e-6) + { printf ("\n\nLine %d: Error : peak value incorrect!\n", __LINE__) ; + printf ("%s", buffer) ; + printf ("\n\nLine %d: %d %f %f\n", __LINE__, chan, position * 0.01, value) ; + exit (1) ; + } ; + cptr ++ ; /* Move past current newline. */ + } ; + +} /* check_logged_peaks */ + +static void +read_write_peak_test (const char *filename, int filetype) +{ SNDFILE *file ; + SF_INFO sfinfo ; + + double small_data [10], max_peak = 0.0 ; + unsigned k ; + + print_test_name (__func__, filename) ; + + for (k = 0 ; k < ARRAY_LEN (small_data) ; k ++) + small_data [k] = 0.1 ; + + sfinfo.samplerate = 44100 ; + sfinfo.channels = 2 ; + sfinfo.format = filetype ; + sfinfo.frames = 0 ; + + /* Open the file, add peak chunk and write samples with value 0.1. */ + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_FALSE, __LINE__) ; + + sf_command (file, SFC_SET_ADD_PEAK_CHUNK, NULL, SF_TRUE) ; + + test_write_double_or_die (file, 0, small_data, ARRAY_LEN (small_data), __LINE__) ; + + sf_close (file) ; + + /* Open the fiel RDWR, write sample valied 1.25. */ + file = test_open_file_or_die (filename, SFM_RDWR, &sfinfo, SF_FALSE, __LINE__) ; + + for (k = 0 ; k < ARRAY_LEN (small_data) ; k ++) + small_data [k] = 1.0 ; + + test_write_double_or_die (file, 0, small_data, ARRAY_LEN (small_data), __LINE__) ; + + sf_command (file, SFC_GET_SIGNAL_MAX, &max_peak, sizeof (max_peak)) ; + + sf_close (file) ; + + exit_if_true (max_peak < 0.1, "\n\nLine %d : max peak (%5.3f) should not be 0.1.\n\n", __LINE__, max_peak) ; + + /* Open the file and test the values written to the PEAK chunk. */ + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + + exit_if_true (sfinfo.channels * sfinfo.frames != 2 * ARRAY_LEN (small_data), + "Line %d : frame count is %" PRId64 ", should be %zd\n", __LINE__, sfinfo.frames, 2 * ARRAY_LEN (small_data)) ; + + sf_command (file, SFC_GET_SIGNAL_MAX, &max_peak, sizeof (double)) ; + + sf_close (file) ; + + exit_if_true (max_peak < 1.0, "\n\nLine %d : max peak (%5.3f) should be 1.0.\n\n", __LINE__, max_peak) ; + + unlink (filename) ; + puts ("ok") ; +} /* read_write_peak_test */ + diff --git a/extern/libsndfile-modified/tests/pedantic-header-test.sh.in b/extern/libsndfile-modified/tests/pedantic-header-test.sh.in new file mode 100644 index 000000000..561628dcf --- /dev/null +++ b/extern/libsndfile-modified/tests/pedantic-header-test.sh.in @@ -0,0 +1,58 @@ +#!/bin/bash + +# Copyright (C) 2010-2017 Erik de Castro Lopo +# +# All rights reserved. +# +# 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 author nor the names of any 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 COPYRIGHT OWNER 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. + + +if test ! -f @top_srcdir@/tests/sfversion.c ; then + exit 0 + fi + +echo -n " Pedantic header test : " + +# Only do this if the compiler is GCC. +if test -n "@GCC_MAJOR_VERSION@" ; then + + CC=`echo "@CC@" | sed "s/.*shave cc //"` + # Compile with -Werror and -pedantic. + $CC -std=c99 -Werror -pedantic -I@top_srcdir@/src -I@abs_top_builddir@/src -I@top_srcdir@/include -c @top_srcdir@/tests/sfversion.c -o /dev/null + + # Check compiler return status. + if test $? -ne 0 ; then + echo + exit 1 + fi + + echo "ok" +else + echo "n/a" + fi + +exit 0 diff --git a/extern/libsndfile-modified/tests/pipe_test.def b/extern/libsndfile-modified/tests/pipe_test.def new file mode 100644 index 000000000..6469cca1e --- /dev/null +++ b/extern/libsndfile-modified/tests/pipe_test.def @@ -0,0 +1,14 @@ +autogen definitions pipe_test.tpl; + +data_type = { + type_name = short ; + }; + +data_type = { + type_name = float ; + }; + +data_type = { + type_name = double ; + }; + diff --git a/extern/libsndfile-modified/tests/pipe_test.tpl b/extern/libsndfile-modified/tests/pipe_test.tpl new file mode 100644 index 000000000..9bb30cc79 --- /dev/null +++ b/extern/libsndfile-modified/tests/pipe_test.tpl @@ -0,0 +1,362 @@ +[+ AutoGen5 template c +] +/* +** Copyright (C) 2001-2017 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/*========================================================================== +** This is a test program which tests reading from and writing to pipes. +*/ + +#include "sfconfig.h" + +#include +#include +#include + +#if (OS_IS_WIN32 || defined __OS2__ || HAVE_PIPE == 0 || HAVE_WAITPID == 0) + +int +main (void) +{ + puts (" pipe_test : this test doesn't work on this OS.") ; + return 0 ; +} /* main */ + +#else + +#if HAVE_UNISTD_H +#include +#endif + +#include +#include +#include +#include + +#include + +#include "utils.h" + +typedef struct +{ int format ; + const char *ext ; +} FILETYPE ; + +static void useek_pipe_rw_test (int filetype, const char *ext) ; +static void pipe_read_test (int filetype, const char *ext) ; +static void pipe_write_test (const char *ext) ; +static void pipe_test_others (FILETYPE*, FILETYPE*) ; + +static FILETYPE read_write_types [] = +{ { SF_FORMAT_RAW , "raw" }, + { SF_FORMAT_AU , "au" }, + /* Lite remove start */ + { SF_FORMAT_PAF , "paf" }, + { SF_FORMAT_IRCAM , "ircam" }, + { SF_FORMAT_PVF , "pvf" }, + /* Lite remove end */ + { 0 , NULL } +} ; + +static FILETYPE read_only_types [] = +{ { SF_FORMAT_RAW , "raw" }, + { SF_FORMAT_AU , "au" }, + { SF_FORMAT_AIFF , "aiff" }, + { SF_FORMAT_WAV , "wav" }, + { SF_FORMAT_W64 , "w64" }, + /* Lite remove start */ + { SF_FORMAT_PAF , "paf" }, + { SF_FORMAT_NIST , "nist" }, + { SF_FORMAT_IRCAM , "ircam" }, + { SF_FORMAT_MAT4 , "mat4" }, + { SF_FORMAT_MAT5 , "mat5" }, + { SF_FORMAT_SVX , "svx" }, + { SF_FORMAT_PVF , "pvf" }, + /* Lite remove end */ + { 0 , NULL } +} ; + +int +main (void) +{ int k ; + + for (k = 0 ; read_only_types [k].format ; k++) + pipe_read_test (read_only_types [k].format, read_only_types [k].ext) ; + + for (k = 0 ; read_write_types [k].format ; k++) + pipe_write_test (read_write_types [k].ext) ; + + for (k = 0 ; read_write_types [k].format ; k++) + useek_pipe_rw_test (read_write_types [k].format, read_write_types [k].ext) ; + + if (0) + pipe_test_others (read_write_types, read_only_types) ; + + return 0 ; +} /* main */ + +/*============================================================================== +*/ + +static void +pipe_read_test (int filetype, const char *ext) +{ static short data [PIPE_TEST_LEN] ; + static char buffer [256] ; + static char filename [256] ; + + SNDFILE *outfile ; + SF_INFO sfinfo ; + int k, retval ; + + snprintf (filename, sizeof (filename), "pipe_in.%s", ext) ; + print_test_name ("pipe_read_test", filename) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + sfinfo.format = filetype | SF_FORMAT_PCM_16 ; + sfinfo.channels = 1 ; + sfinfo.samplerate = 44100 ; + + for (k = 0 ; k < PIPE_TEST_LEN ; k++) + data [k] = PIPE_INDEX (k) ; + + outfile = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + test_writef_short_or_die (outfile, 0, data, PIPE_TEST_LEN, __LINE__) ; + sf_close (outfile) ; + + snprintf (buffer, sizeof (buffer), "cat %s | ./tests/stdin_test %s ", filename, ext) ; + if ((retval = system (buffer)) != 0) + { retval = WEXITSTATUS (retval) ; + printf ("\n\n Line %d : pipe test returned error for file type \"%s\".\n\n", __LINE__, ext) ; + exit (retval) ; + } ; + + unlink (filename) ; + puts ("ok") ; + + return ; +} /* pipe_read_test */ + +static void +pipe_write_test (const char *ext) +{ static char buffer [256] ; + + int retval ; + + print_test_name ("pipe_write_test", ext) ; + + snprintf (buffer, sizeof (buffer), "./tests/stdout_test %s | ./tests/stdin_test %s ", ext, ext) ; + if ((retval = system (buffer))) + { retval = WEXITSTATUS (retval) ; + printf ("\n\n Line %d : pipe test returned error file type \"%s\".\n\n", __LINE__, ext) ; + exit (retval) ; + } ; + + puts ("ok") ; + + return ; +} /* pipe_write_test */ + +/*============================================================================== +*/ + +[+ FOR data_type +] +static void +useek_pipe_rw_[+ (get "type_name") +] (const char * ext, SF_INFO * psfinfo_write, SF_INFO * psfinfo_read) +{ static [+ (get "type_name") +] buffer [PIPE_TEST_LEN] ; + static [+ (get "type_name") +] data [PIPE_TEST_LEN] ; + SNDFILE *outfile ; + SNDFILE *infile_piped ; + + int k, status = 0 ; + int pipefd [2] ; + pid_t pida ; + + for (k = 0 ; k < PIPE_TEST_LEN ; k++) + data [k] = PIPE_INDEX (k) ; + + /* + ** Create the pipe. + */ + exit_if_true (pipe (pipefd) != 0, "\n\n%s %d : pipe failed : %s\n", __func__, __LINE__, strerror (errno)) ; + + /* + ** Attach the write end of the pipe to be written to. + */ + if ((outfile = sf_open_fd (pipefd [1], SFM_WRITE, psfinfo_write, SF_TRUE)) == NULL) + { printf ("\n\n%s %d : unable to create unseekable pipe for write type \"%s\".\n", __func__, __LINE__, ext) ; + printf ("\t%s\n\n", sf_strerror (outfile)) ; + exit (1) ; + } ; + + if (sf_error (outfile) != SF_ERR_NO_ERROR) + { printf ("\n\n%s %d : unable to open unseekable pipe for write type \"%s\".\n\n", __func__, __LINE__, ext) ; + exit (1) ; + } ; + + /* + ** Attach the read end of the pipe to be read from. + */ + if ((infile_piped = sf_open_fd (pipefd [0], SFM_READ, psfinfo_read, SF_TRUE)) == NULL) + { printf ("\n\n%s %d : unable to create unseekable pipe for read type. \"%s\".\n\n", __func__, __LINE__, ext) ; + exit (1) ; + } ; + + if (sf_error (infile_piped) != SF_ERR_NO_ERROR) + { printf ("\n\n%s %d : unable to open unseekable pipe for read type \"%s\".\n\n", __func__, __LINE__, ext) ; + exit (1) ; + } ; + + /* Fork a child process that will write directly into the pipe. */ + if ((pida = fork ()) == 0) /* child process */ + { test_writef_[+ (get "type_name") +]_or_die (outfile, 0, data, PIPE_TEST_LEN, __LINE__) ; + exit (0) ; + } ; + + /* In the parent process, read from the pipe and compare what is read + ** to what is written, if they match everything went as planned. + */ + test_readf_[+ (get "type_name") +]_or_die (infile_piped, 0, buffer, PIPE_TEST_LEN, __LINE__) ; + if (memcmp (buffer, data, sizeof (buffer)) != 0) + { printf ("\n\n%s %d : unseekable pipe test failed for file type \"%s\".\n\n", __func__, __LINE__, ext) ; + exit (1) ; + } ; + + /* Wait for the child process to return. */ + waitpid (pida, &status, 0) ; + status = WEXITSTATUS (status) ; + sf_close (outfile) ; + sf_close (infile_piped) ; + + if (status != 0) + { printf ("\n\n%s %d : status of child process is %d for file type %s.\n\n", __func__, __LINE__, status, ext) ; + exit (1) ; + } ; + + return ; +} /* useek_pipe_rw_[+ (get "type_name") +] */ + +[+ ENDFOR data_type +] + + +static void +useek_pipe_rw_test (int filetype, const char *ext) +{ SF_INFO sfinfo_write ; + SF_INFO sfinfo_read ; + + print_test_name ("useek_pipe_rw_test", ext) ; + + /* + ** Setup the INFO structures for the filetype we will be + ** working with. + */ + sfinfo_write.format = filetype | SF_FORMAT_PCM_16 ; + sfinfo_write.channels = 1 ; + sfinfo_write.samplerate = 44100 ; + + + sfinfo_read.format = 0 ; + if (filetype == SF_FORMAT_RAW) + { sfinfo_read.format = filetype | SF_FORMAT_PCM_16 ; + sfinfo_read.channels = 1 ; + sfinfo_read.samplerate = 44100 ; + } ; + + useek_pipe_rw_short (ext, &sfinfo_write, &sfinfo_read) ; + + sfinfo_read.format = sfinfo_write.format = filetype | SF_FORMAT_FLOAT ; + if (sf_format_check (&sfinfo_read) != 0) + useek_pipe_rw_float (ext, &sfinfo_write, &sfinfo_read) ; + + sfinfo_read.format = sfinfo_write.format = filetype | SF_FORMAT_DOUBLE ; + if (sf_format_check (&sfinfo_read) != 0) + useek_pipe_rw_double (ext, &sfinfo_write, &sfinfo_read) ; + + puts ("ok") ; + return ; +} /* useek_pipe_rw_test */ + + + +static void +pipe_test_others (FILETYPE* list1, FILETYPE* list2) +{ SF_FORMAT_INFO info ; + int k, m, major_count, in_list ; + + print_test_name ("pipe_test_others", "") ; + + sf_command (NULL, SFC_GET_FORMAT_MAJOR_COUNT, &major_count, sizeof (int)) ; + + for (k = 0 ; k < major_count ; k++) + { info.format = k ; + + sf_command (NULL, SFC_GET_FORMAT_MAJOR, &info, sizeof (info)) ; + + in_list = SF_FALSE ; + for (m = 0 ; list1 [m].format ; m++) + if (info.format == list1 [m].format) + in_list = SF_TRUE ; + + for (m = 0 ; list2 [m].format ; m++) + if (info.format == list2 [m].format) + in_list = SF_TRUE ; + + if (in_list) + continue ; + + printf ("%s %x\n", info.name, info.format) ; + + if (1) + { static short data [PIPE_TEST_LEN] ; + static char buffer [256] ; + static const char *filename = "pipe_in.dat" ; + + SNDFILE *outfile ; + SF_INFO sfinfo ; + int retval ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + sfinfo.format = info.format | SF_FORMAT_PCM_16 ; + sfinfo.channels = 1 ; + sfinfo.samplerate = 44100 ; + + outfile = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + test_writef_short_or_die (outfile, 0, data, PIPE_TEST_LEN, __LINE__) ; + sf_close (outfile) ; + + snprintf (buffer, sizeof (buffer), "cat %s | ./tests/stdin_test %s %d ", filename, info.extension, PIPE_TEST_LEN) ; + if ((retval = system (buffer)) == 0) + { retval = WEXITSTATUS (retval) ; + printf ("\n\n Line %d : pipe test should have returned error file type \"%s\" but didn't.\n\n", __LINE__, info.name) ; + exit (1) ; + } ; + + unlink (filename) ; + } ; + } ; + + + puts ("ok") ; + + return ; +} /* pipe_test_others */ + + +/*============================================================================== +*/ + +#endif + diff --git a/extern/libsndfile-modified/tests/raw_test.c b/extern/libsndfile-modified/tests/raw_test.c new file mode 100644 index 000000000..be0f94dcf --- /dev/null +++ b/extern/libsndfile-modified/tests/raw_test.c @@ -0,0 +1,189 @@ +/* +** Copyright (C) 2002-2014 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include +#include + +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include + +#include "utils.h" + +#define BUFFER_LEN (1 << 10) +#define LOG_BUFFER_SIZE 1024 + +static void raw_offset_test (const char *filename, int typeminor) ; +static void bad_raw_test (void) ; + +/* Force the start of this buffer to be double aligned. Sparc-solaris will +** choke if its not. +*/ +static short data [BUFFER_LEN] ; + +int +main (void) +{ + raw_offset_test ("offset.raw", SF_FORMAT_PCM_16) ; + bad_raw_test () ; + + return 0 ; +} /* main */ + +/*============================================================================================ +** Here are the test functions. +*/ + +static void +raw_offset_test (const char *filename, int typeminor) +{ SNDFILE *sndfile ; + SF_INFO sfinfo ; + sf_count_t start ; + int k ; + + print_test_name ("raw_offset_test", filename) ; + + sfinfo.samplerate = 44100 ; + sfinfo.format = SF_FORMAT_RAW | typeminor ; + sfinfo.channels = 1 ; + sfinfo.frames = 0 ; + + sndfile = test_open_file_or_die (filename, SFM_RDWR, &sfinfo, SF_TRUE, __LINE__) ; + + start = 0 ; + sf_command (sndfile, SFC_FILE_TRUNCATE, &start, sizeof (start)) ; + + for (k = 0 ; k < BUFFER_LEN ; k++) + data [k] = k ; + test_write_short_or_die (sndfile, 0, data, BUFFER_LEN, __LINE__) ; + + sf_close (sndfile) ; + + sndfile = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + check_log_buffer_or_die (sndfile, __LINE__) ; + + if (ABS (BUFFER_LEN - sfinfo.frames) > 1) + { printf ("\n\nLine %d : Incorrect sample count (%" PRId64 " should be %d)\n", __LINE__, sfinfo.frames, BUFFER_LEN) ; + dump_log_buffer (sndfile) ; + exit (1) ; + } ; + + memset (data, 0 , sizeof (data)) ; + test_read_short_or_die (sndfile, 0, data, BUFFER_LEN, __LINE__) ; + for (k = 0 ; k < BUFFER_LEN ; k++) + if (data [k] != k) + printf ("Error : line %d\n", __LINE__) ; + + /* Set dataoffset to 2 bytes from beginning of file. */ + start = 2 ; + sf_command (sndfile, SFC_SET_RAW_START_OFFSET, &start, sizeof (start)) ; + + /* Seek to new start */ + test_seek_or_die (sndfile, 0, SEEK_SET, 0, sfinfo.channels, __LINE__) ; + + memset (data, 0 , sizeof (data)) ; + test_read_short_or_die (sndfile, 0, data, BUFFER_LEN - 1, __LINE__) ; + for (k = 0 ; k < BUFFER_LEN - 1 ; k++) + if (data [k] != k + 1) + { printf ("Error : line %d\n", __LINE__) ; + exit (1) ; + } ; + + /* Set dataoffset to 4 bytes from beginning of file. */ + start = 4 ; + sf_command (sndfile, SFC_SET_RAW_START_OFFSET, &start, sizeof (start)) ; + + /* Seek to new start */ + test_seek_or_die (sndfile, 0, SEEK_SET, 0, sfinfo.channels, __LINE__) ; + + memset (data, 0 , sizeof (data)) ; + test_read_short_or_die (sndfile, 0, data, BUFFER_LEN - 2, __LINE__) ; + for (k = 0 ; k < BUFFER_LEN - 2 ; k++) + if (data [k] != k + 2) + { printf ("Error : line %d\n", __LINE__) ; + exit (1) ; + } ; + + /* Set dataoffset back to 0 bytes from beginning of file. */ + start = 0 ; + sf_command (sndfile, SFC_SET_RAW_START_OFFSET, &start, sizeof (start)) ; + + /* Seek to new start */ + test_seek_or_die (sndfile, 0, SEEK_SET, 0, sfinfo.channels, __LINE__) ; + + memset (data, 0 , sizeof (data)) ; + test_read_short_or_die (sndfile, 0, data, BUFFER_LEN, __LINE__) ; + for (k = 0 ; k < BUFFER_LEN ; k++) + if (data [k] != k) + { printf ("Error : line %d\n", __LINE__) ; + exit (1) ; + } ; + + sf_close (sndfile) ; + unlink (filename) ; + + puts ("ok") ; +} /* raw_offset_test */ + +static void +bad_raw_test (void) +{ FILE *textfile ; + SNDFILE *file ; + SF_INFO sfinfo ; + const char *errorstr, *filename = "bad.raw" ; + + print_test_name ("bad_raw_test", filename) ; + + if ((textfile = fopen (filename, "w")) == NULL) + { printf ("\n\nLine %d : not able to open text file for write.\n", __LINE__) ; + exit (1) ; + } ; + + fprintf (textfile, "This is not a valid file.\n") ; + fclose (textfile) ; + + sfinfo.samplerate = 44100 ; + sfinfo.format = SF_FORMAT_RAW | 0xABCD ; + sfinfo.channels = 1 ; + + if ((file = sf_open (filename, SFM_READ, &sfinfo)) != NULL) + { printf ("\n\nLine %d : Error, file should not have opened.\n", __LINE__ - 1) ; + exit (1) ; + } ; + + errorstr = sf_strerror (file) ; + + if (strstr (errorstr, "Bad format field in SF_INFO struct") == NULL) + { printf ("\n\nLine %d : Error bad error string : %s.\n", __LINE__ - 1, errorstr) ; + exit (1) ; + } ; + + unlink (filename) ; + + puts ("ok") ; +} /* bad_raw_test */ + diff --git a/extern/libsndfile-modified/tests/rdwr_test.def b/extern/libsndfile-modified/tests/rdwr_test.def new file mode 100644 index 000000000..43c108981 --- /dev/null +++ b/extern/libsndfile-modified/tests/rdwr_test.def @@ -0,0 +1,32 @@ +autogen definitions rdwr_test.tpl; + +data_type = { + name = "short" ; + type = "short" ; + format = "SF_FORMAT_PCM_16" ; + } ; + +data_type = { + name = "int" ; + type = "int" ; + format = "SF_FORMAT_PCM_32" ; + } ; + +data_type = { + name = "float" ; + type = "float" ; + format = "SF_FORMAT_FLOAT" ; + } ; + +data_type = { + name = "double" ; + type = "double" ; + format = "SF_FORMAT_DOUBLE" ; + } ; + +data_type = { + name = "raw" ; + type = "unsigned char" ; + format = "SF_FORMAT_PCM_U8" ; + } ; + diff --git a/extern/libsndfile-modified/tests/rdwr_test.tpl b/extern/libsndfile-modified/tests/rdwr_test.tpl new file mode 100644 index 000000000..8cfdd3687 --- /dev/null +++ b/extern/libsndfile-modified/tests/rdwr_test.tpl @@ -0,0 +1,105 @@ +[+ AutoGen5 template c +] +/* +** Copyright (C) 2010-2012 Erik de Castro Lopo +** +** This program is free software ; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation ; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY ; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program ; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include + +#include +#include + +#if HAVE_UNISTD_H +#include +#endif + +#if (HAVE_DECL_S_IRGRP == 0) +#include +#endif + +#if (defined (WIN32) || defined (_WIN32)) +#include +#include +#endif + +#include + +#include "utils.h" + +[+ FOR data_type ++]static void rdwr_[+ (get "name") +]_test (const char *filename) ; +[+ ENDFOR data_type ++] + +int +main (void) +{ + rdwr_short_test ("rdwr_short.wav") ; + rdwr_int_test ("rdwr_int.wav") ; + rdwr_float_test ("rdwr_float.wav") ; + rdwr_double_test ("rdwr_double.wav") ; + rdwr_raw_test ("rdwr_raw.wav") ; + + return 0 ; +} /* main */ + + +/*============================================================================================ +** Here are the test functions. +*/ + +[+ FOR data_type ++]static void +rdwr_[+ (get "name") +]_test (const char *filename) +{ SNDFILE *file ; + SF_INFO sfinfo ; + sf_count_t frames ; + [+ (get "type") +] buffer [160] ; + + print_test_name ("rdwr_[+ (get "name") +]_test", filename) ; + + memset (buffer, 0, sizeof (buffer)) ; + + /* Create sound file with no data. */ + sfinfo.format = SF_FORMAT_WAV | [+ (get "format") +] ; + sfinfo.samplerate = 16000 ; + sfinfo.channels = 1 ; + + unlink (filename) ; + + frames = ARRAY_LEN (buffer) ; + + /* Open again for read/write. */ + file = test_open_file_or_die (filename, SFM_RDWR, &sfinfo, SF_TRUE, __LINE__) ; + + test_write_[+ (get "name") +]_or_die (file, 0, buffer, frames, __LINE__) ; + + test_read_[+ (get "name") +]_or_die (file, 0, buffer, frames, __LINE__) ; + + sf_close (file) ; + unlink (filename) ; + + puts ("ok") ; + return ; +} /* rdwr_[+ (get "name") +]_test */ + +[+ ENDFOR data_type ++] + diff --git a/extern/libsndfile-modified/tests/scale_clip_test.def b/extern/libsndfile-modified/tests/scale_clip_test.def new file mode 100644 index 000000000..9974f116d --- /dev/null +++ b/extern/libsndfile-modified/tests/scale_clip_test.def @@ -0,0 +1,56 @@ +autogen definitions scale_clip_test.tpl; + +float_type = { + float_type_name = "float" ; + float_short_name = "flt" ; + float_upper_name = "FLOAT" ; + float_to_int = "lrintf" ; + } ; + +float_type = { + float_type_name = "double" ; + float_short_name = "dbl" ; + float_upper_name = "DOUBLE" ; + float_to_int = "lrint" ; + } ; + + + +int_type = { + int_type_name = "short" ; + int_short_name = "s" ; + int_max_value = "0x7FFFF" ; + } ; + +int_type = { + int_type_name = "int" ; + int_short_name = "i" ; + int_max_value = "0x7FFFFFFF" ; + } ; + + + +data_type = { + name = "16" ; + bit_count = 16 ; + error_val = "1.0 / 0x8000" ; + } ; + +data_type = { + name = "24" ; + bit_count = 24 ; + error_val = "1.0 / 0x800000" ; + } ; + +data_type = { + name = "32" ; + bit_count = 32 ; + error_val = "1.0 / 0x80000000" ; + } ; + +data_type = { + name = "08" ; + bit_count = 8 ; + error_val = "1.0 / 0x80" ; + } ; + diff --git a/extern/libsndfile-modified/tests/scale_clip_test.tpl b/extern/libsndfile-modified/tests/scale_clip_test.tpl new file mode 100644 index 000000000..ad59ce16d --- /dev/null +++ b/extern/libsndfile-modified/tests/scale_clip_test.tpl @@ -0,0 +1,440 @@ +[+ AutoGen5 template c +] +/* +** Copyright (C) 1999-2012 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include +#include + +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include + +#include "utils.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846264338 +#endif + +#define HALF_BUFFER_SIZE (1 << 12) +#define BUFFER_SIZE (2 * HALF_BUFFER_SIZE) + +#define SINE_AMP 1.1 +#define MAX_ERROR 0.0202 + +[+ FOR float_type +] +[+ FOR data_type ++]static void [+ (get "float_short_name") +]_scale_clip_test_[+ (get "name") +] (const char *filename, int filetype, float maxval) ; +[+ ENDFOR data_type ++][+ ENDFOR float_type +] + +[+ FOR float_type +] +[+ FOR int_type ++]static void [+ (get "float_short_name") +]_[+ (get "int_type_name") +]_clip_read_test (const char *filename, int filetype) ; +[+ ENDFOR int_type ++][+ ENDFOR float_type +] + +[+ FOR int_type +] +[+ FOR float_type ++]static void [+ (get "int_type_name") +]_[+ (get "float_short_name") +]_scale_write_test (const char *filename, int filetype) ; +[+ ENDFOR float_type ++][+ ENDFOR int_type +] + +typedef union +{ double dbl [BUFFER_SIZE] ; + float flt [BUFFER_SIZE] ; + int i [BUFFER_SIZE] ; + short s [BUFFER_SIZE] ; +} BUFFER ; + +/* Data buffer. */ +static BUFFER buffer_out ; +static BUFFER buffer_in ; + +int +main (void) +{ + flt_scale_clip_test_08 ("scale_clip_s8.au", SF_FORMAT_AU | SF_FORMAT_PCM_S8, 1.0 * 0x80) ; + flt_scale_clip_test_08 ("scale_clip_u8.wav", SF_FORMAT_WAV | SF_FORMAT_PCM_U8, 1.0 * 0x80) ; + + dbl_scale_clip_test_08 ("scale_clip_s8.au", SF_FORMAT_AU | SF_FORMAT_PCM_S8, 1.0 * 0x80) ; + dbl_scale_clip_test_08 ("scale_clip_u8.wav", SF_FORMAT_WAV | SF_FORMAT_PCM_U8, 1.0 * 0x80) ; + + /* + ** Now use SF_FORMAT_AU where possible because it allows both + ** big and little endian files. + */ + + flt_scale_clip_test_16 ("scale_clip_be16.au", SF_ENDIAN_BIG | SF_FORMAT_AU | SF_FORMAT_PCM_16, 1.0 * 0x8000) ; + flt_scale_clip_test_16 ("scale_clip_le16.au", SF_ENDIAN_LITTLE | SF_FORMAT_AU | SF_FORMAT_PCM_16, 1.0 * 0x8000) ; + flt_scale_clip_test_24 ("scale_clip_be24.au", SF_ENDIAN_BIG | SF_FORMAT_AU | SF_FORMAT_PCM_24, 1.0 * 0x800000) ; + flt_scale_clip_test_24 ("scale_clip_le24.au", SF_ENDIAN_LITTLE | SF_FORMAT_AU | SF_FORMAT_PCM_24, 1.0 * 0x800000) ; + flt_scale_clip_test_32 ("scale_clip_be32.au", SF_ENDIAN_BIG | SF_FORMAT_AU | SF_FORMAT_PCM_32, 1.0 * 0x80000000) ; + flt_scale_clip_test_32 ("scale_clip_le32.au", SF_ENDIAN_LITTLE | SF_FORMAT_AU | SF_FORMAT_PCM_32, 1.0 * 0x80000000) ; + + dbl_scale_clip_test_16 ("scale_clip_be16.au", SF_ENDIAN_BIG | SF_FORMAT_AU | SF_FORMAT_PCM_16, 1.0 * 0x8000) ; + dbl_scale_clip_test_16 ("scale_clip_le16.au", SF_ENDIAN_LITTLE | SF_FORMAT_AU | SF_FORMAT_PCM_16, 1.0 * 0x8000) ; + dbl_scale_clip_test_24 ("scale_clip_be24.au", SF_ENDIAN_BIG | SF_FORMAT_AU | SF_FORMAT_PCM_24, 1.0 * 0x800000) ; + dbl_scale_clip_test_24 ("scale_clip_le24.au", SF_ENDIAN_LITTLE | SF_FORMAT_AU | SF_FORMAT_PCM_24, 1.0 * 0x800000) ; + dbl_scale_clip_test_32 ("scale_clip_be32.au", SF_ENDIAN_BIG | SF_FORMAT_AU | SF_FORMAT_PCM_32, 1.0 * 0x80000000) ; + dbl_scale_clip_test_32 ("scale_clip_le32.au", SF_ENDIAN_LITTLE | SF_FORMAT_AU | SF_FORMAT_PCM_32, 1.0 * 0x80000000) ; + + flt_short_clip_read_test ("flt_short.au" , SF_ENDIAN_BIG | SF_FORMAT_AU | SF_FORMAT_FLOAT) ; + flt_int_clip_read_test ("flt_int.au" , SF_ENDIAN_LITTLE | SF_FORMAT_AU | SF_FORMAT_FLOAT) ; + dbl_short_clip_read_test ("dbl_short.au" , SF_ENDIAN_BIG | SF_FORMAT_AU | SF_FORMAT_DOUBLE) ; + dbl_int_clip_read_test ("dbl_int.au" , SF_ENDIAN_LITTLE | SF_FORMAT_AU | SF_FORMAT_DOUBLE) ; + + short_flt_scale_write_test ("short_flt.au" , SF_ENDIAN_BIG | SF_FORMAT_AU | SF_FORMAT_FLOAT) ; + int_flt_scale_write_test ("int_flt.au" , SF_ENDIAN_LITTLE | SF_FORMAT_AU | SF_FORMAT_FLOAT) ; + short_dbl_scale_write_test ("short_dbl.au" , SF_ENDIAN_BIG | SF_FORMAT_AU | SF_FORMAT_DOUBLE) ; + int_dbl_scale_write_test ("int_dbl.au" , SF_ENDIAN_LITTLE | SF_FORMAT_AU | SF_FORMAT_DOUBLE) ; + + return 0 ; +} /* main */ + +/*============================================================================================ +** Here are the test functions. +*/ + +[+ FOR float_type +] +[+ FOR data_type ++]static void +[+ (get "float_short_name") +]_scale_clip_test_[+ (get "name") +] (const char *filename, int filetype, float maxval) +{ SNDFILE *file ; + SF_INFO sfinfo ; + int k ; + [+ (get "float_type_name") +] *data_out, *data_in ; + double diff, clip_max_diff ; + + print_test_name ("[+ (get "float_short_name") +]_scale_clip_test_[+ (get "name") +]", filename) ; + + data_out = buffer_out.[+ (get "float_short_name") +] ; + data_in = buffer_in.[+ (get "float_short_name") +] ; + + for (k = 0 ; k < HALF_BUFFER_SIZE ; k++) + { data_out [k] = 1.2 * sin (2 * M_PI * k / HALF_BUFFER_SIZE) ; + data_out [k + HALF_BUFFER_SIZE] = data_out [k] * maxval ; + } ; + + sfinfo.samplerate = 44100 ; + sfinfo.frames = 123456789 ; /* Wrong length. Library should correct this on sf_close. */ + sfinfo.channels = 1 ; + sfinfo.format = filetype ; + + /* + ** Write two versions of the data: + ** normalized and clipped + ** un-normalized and clipped. + */ + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + sf_command (file, SFC_SET_CLIPPING, NULL, SF_TRUE) ; + test_write_[+ (get "float_type_name") +]_or_die (file, 0, data_out, HALF_BUFFER_SIZE, __LINE__) ; + sf_command (file, SFC_SET_NORM_[+ (get "float_upper_name") +], NULL, SF_FALSE) ; + test_write_[+ (get "float_type_name") +]_or_die (file, 0, data_out + HALF_BUFFER_SIZE, HALF_BUFFER_SIZE, __LINE__) ; + sf_close (file) ; + + memset (&buffer_in, 0, sizeof (buffer_in)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + + sfinfo.format &= (SF_FORMAT_TYPEMASK | SF_FORMAT_SUBMASK) ; + + if (sfinfo.format != (filetype & (SF_FORMAT_TYPEMASK | SF_FORMAT_SUBMASK))) + { printf ("\n\nLine %d: Returned format incorrect (0x%08X => 0x%08X).\n\n", __LINE__, filetype, sfinfo.format) ; + exit (1) ; + } ; + + if (sfinfo.frames != BUFFER_SIZE) + { printf ("\n\nLine %d: Incorrect number of frames in file (%d => %" PRId64 ").\n\n", __LINE__, BUFFER_SIZE, sfinfo.frames) ; + exit (1) ; + } ; + + if (sfinfo.channels != 1) + { printf ("\n\nLine %d: Incorrect number of channels in file.\n\n", __LINE__) ; + exit (1) ; + } ; + + check_log_buffer_or_die (file, __LINE__) ; + + test_read_[+ (get "float_type_name") +]_or_die (file, 0, data_in, HALF_BUFFER_SIZE, __LINE__) ; + sf_command (file, SFC_SET_NORM_[+ (get "float_upper_name") +], NULL, SF_FALSE) ; + test_read_[+ (get "float_type_name") +]_or_die (file, 0, data_in + HALF_BUFFER_SIZE, HALF_BUFFER_SIZE, __LINE__) ; + sf_close (file) ; + + /* Check normalized version. */ + clip_max_diff = 0.0 ; + for (k = 0 ; k < HALF_BUFFER_SIZE ; k++) + { if (fabs (data_in [k]) > 1.0) + { printf ("\n\nLine %d: Input sample %d/%d (%f) has not been clipped.\n\n", __LINE__, k, BUFFER_SIZE, data_in [k]) ; + exit (1) ; + } ; + + if (data_out [k] * data_in [k] < 0.0) + { printf ("\n\nLine %d: Data wrap around at index %d/%d.\n\n", __LINE__, k, BUFFER_SIZE) ; + exit (1) ; + } ; + + if (fabs (data_out [k]) > 1.0) + continue ; + + diff = fabs (data_out [k] - data_in [k]) ; + if (diff > clip_max_diff) + clip_max_diff = diff ; + } ; + + if (clip_max_diff < 1e-20) + { printf ("\n\nLine %d: Clipping difference (%e) too small (normalized).\n\n", __LINE__, clip_max_diff) ; + exit (1) ; + } ; + + if (clip_max_diff > [+ (get "error_val") +]) + { printf ("\n\nLine %d: Clipping difference (%e) too large (normalized).\n\n", __LINE__, clip_max_diff) ; + exit (1) ; + } ; + + /* Check the un-normalized data. */ + clip_max_diff = 0.0 ; + for (k = HALF_BUFFER_SIZE ; k < BUFFER_SIZE ; k++) + { if (fabs (data_in [k]) > maxval) + { printf ("\n\nLine %d: Input sample %d/%d (%f) has not been clipped.\n\n", __LINE__, k, BUFFER_SIZE, data_in [k]) ; + exit (1) ; + } ; + + if (data_out [k] * data_in [k] < 0.0) + { printf ("\n\nLine %d: Data wrap around at index %d/%d.\n\n", __LINE__, k, BUFFER_SIZE) ; + exit (1) ; + } ; + + if (fabs (data_out [k]) > maxval) + continue ; + + diff = fabs (data_out [k] - data_in [k]) ; + if (diff > clip_max_diff) + clip_max_diff = diff ; + } ; + + if (clip_max_diff < 1e-20) + { printf ("\n\nLine %d: Clipping difference (%e) too small (un-normalized).\n\n", __LINE__, clip_max_diff) ; + exit (1) ; + } ; + + if (clip_max_diff > 1.0) + { printf ("\n\nLine %d: Clipping difference (%e) too large (un-normalised).\n\n", __LINE__, clip_max_diff) ; + exit (1) ; + } ; + + printf ("ok\n") ; + unlink (filename) ; +} /* [+ (get "float_short_name") +]_scale_clip_test_[+ (get "name") +] */ + +[+ ENDFOR data_type ++] +[+ ENDFOR float_type +] + +/*============================================================================== +*/ + +[+ FOR float_type +] +[+ FOR int_type ++]static void [+ (get "float_short_name") +]_[+ (get "int_type_name") +]_clip_read_test (const char *filename, int filetype) +{ SNDFILE *file ; + SF_INFO sfinfo ; + [+ (get "float_type_name") +] *data_out ; + [+ (get "int_type_name") +] *data_in, max_value ; + int k ; + + print_test_name ("[+ (get "float_short_name") +]_[+ (get "int_type_name") +]_clip_read_test", filename) ; + + data_out = buffer_out.[+ (get "float_short_name") +] ; + data_in = buffer_in.[+ (get "int_short_name") +] ; + + for (k = 0 ; k < BUFFER_SIZE ; k++) + data_out [k] = 0.995 * sin (4 * M_PI * k / BUFFER_SIZE) ; + data_out [BUFFER_SIZE / 8] = 1.0 ; + data_out [3 * BUFFER_SIZE / 8] = -1.000000001 ; + data_out [5 * BUFFER_SIZE / 8] = 1.0 ; + data_out [7 * BUFFER_SIZE / 8] = -1.000000001 ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + sfinfo.samplerate = 44100 ; + sfinfo.frames = 123456789 ; /* Wrong length. Library should correct this on sf_close. */ + sfinfo.channels = 1 ; + sfinfo.format = filetype ; + + /* Save unclipped data to the file. */ + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + test_write_[+ (get "float_type_name") +]_or_die (file, 0, data_out, BUFFER_SIZE, __LINE__) ; + sf_close (file) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + sf_command (file, SFC_SET_SCALE_FLOAT_INT_READ, NULL, SF_TRUE) ; + + sfinfo.format &= (SF_FORMAT_TYPEMASK | SF_FORMAT_SUBMASK) ; + + if (sfinfo.format != (filetype & (SF_FORMAT_TYPEMASK | SF_FORMAT_SUBMASK))) + { printf ("\n\nLine %d: Returned format incorrect (0x%08X => 0x%08X).\n\n", __LINE__, filetype, sfinfo.format) ; + exit (1) ; + } ; + + if (sfinfo.frames != BUFFER_SIZE) + { printf ("\n\nLine %d: Incorrect number of frames in file (%d => %" PRId64 ").\n\n", __LINE__, BUFFER_SIZE, sfinfo.frames) ; + exit (1) ; + } ; + + if (sfinfo.channels != 1) + { printf ("\n\nLine %d: Incorrect number of channels in file.\n\n", __LINE__) ; + exit (1) ; + } ; + + check_log_buffer_or_die (file, __LINE__) ; + + sf_command (file, SFC_SET_CLIPPING, NULL, SF_TRUE) ; + test_read_[+ (get "int_type_name") +]_or_die (file, 0, data_in, BUFFER_SIZE, __LINE__) ; + /*-sf_command (file, SFC_SET_NORM_[+ (get "float_upper_name") +], NULL, SF_FALSE) ;-*/ + sf_close (file) ; + + /* Check the first half. */ + max_value = 0 ; + for (k = 0 ; k < sfinfo.frames ; k++) + { /* Check if data_out has different sign from data_in. */ + if ((data_out [k] < 0.0 && data_in [k] > 0) || (data_out [k] > 0.0 && data_in [k] < 0)) + { printf ("\n\nLine %d: Data wrap around at index %d/%d (%f -> %d).\n\n", __LINE__, k, BUFFER_SIZE, data_out [k], data_in [k]) ; + exit (1) ; + } ; + max_value = (max_value > abs (data_in [k])) ? max_value : abs (data_in [k]) ; + } ; + + unlink (filename) ; + puts ("ok") ; +} /* [+ (get "float_short_name") +]_[+ (get "int_type_name") +]_clip_read_test */ +[+ ENDFOR int_type ++][+ ENDFOR float_type +] + +/*============================================================================== +*/ + +[+ FOR int_type +] +[+ FOR float_type ++]static void [+ (get "int_type_name") +]_[+ (get "float_short_name") +]_scale_write_test (const char *filename, int filetype) +{ SNDFILE *file ; + SF_INFO sfinfo ; + [+ (get "int_type_name") +] *data_out ; + [+ (get "float_type_name") +] *data_in, max_value ; + int k ; + + print_test_name ("[+ (get "int_type_name") +]_[+ (get "float_short_name") +]_clip_write_test", filename) ; + + data_out = buffer_out.[+ (get "int_short_name") +] ; + data_in = buffer_in.[+ (get "float_short_name") +] ; + + for (k = 0 ; k < BUFFER_SIZE ; k++) + data_out [k] = [+ (get "float_to_int") +] ([+ (get "int_max_value") +] * 0.995 * sin (4 * M_PI * k / BUFFER_SIZE)) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + sfinfo.samplerate = 44100 ; + sfinfo.frames = 123456789 ; /* Wrong length. Library should correct this on sf_close. */ + sfinfo.channels = 1 ; + sfinfo.format = filetype ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + test_write_[+ (get "int_type_name") +]_or_die (file, 0, data_out, BUFFER_SIZE, __LINE__) ; + sf_command (file, SFC_SET_SCALE_INT_FLOAT_WRITE, NULL, SF_TRUE) ; + test_write_[+ (get "int_type_name") +]_or_die (file, 0, data_out, BUFFER_SIZE, __LINE__) ; + sf_command (file, SFC_SET_SCALE_INT_FLOAT_WRITE, NULL, SF_FALSE) ; + test_write_[+ (get "int_type_name") +]_or_die (file, 0, data_out, BUFFER_SIZE, __LINE__) ; + sf_close (file) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + + sfinfo.format &= (SF_FORMAT_TYPEMASK | SF_FORMAT_SUBMASK) ; + + if (sfinfo.format != (filetype & (SF_FORMAT_TYPEMASK | SF_FORMAT_SUBMASK))) + { printf ("\n\nLine %d: Returned format incorrect (0x%08X => 0x%08X).\n\n", __LINE__, filetype, sfinfo.format) ; + exit (1) ; + } ; + + if (sfinfo.frames != 3 * BUFFER_SIZE) + { printf ("\n\nLine %d: Incorrect number of frames in file (%d => %" PRId64 ").\n\n", __LINE__, 3 * BUFFER_SIZE, sfinfo.frames) ; + exit (1) ; + } ; + + if (sfinfo.channels != 1) + { printf ("\n\nLine %d: Incorrect number of channels in file.\n\n", __LINE__) ; + exit (1) ; + } ; + + check_log_buffer_or_die (file, __LINE__) ; + + /* Check the first section. */ + test_read_[+ (get "float_type_name") +]_or_die (file, 0, data_in, BUFFER_SIZE, __LINE__) ; + + max_value = 0.0 ; + for (k = 0 ; k < BUFFER_SIZE ; k++) + max_value = (max_value > fabs (data_in [k])) ? max_value : fabs (data_in [k]) ; + + if (max_value < 1000.0) + { printf ("\n\nLine %d: Max value (%f) < 1000.0.\n\n", __LINE__, max_value) ; + exit (1) ; + } ; + + /* Check the second section. */ + test_read_[+ (get "float_type_name") +]_or_die (file, 0, data_in, BUFFER_SIZE, __LINE__) ; + + max_value = 0.0 ; + for (k = 0 ; k < BUFFER_SIZE ; k++) + max_value = (max_value > fabs (data_in [k])) ? max_value : fabs (data_in [k]) ; + + if (max_value > 1.0) + { printf ("\n\nLine %d: Max value (%f) > 1.0.\n\n", __LINE__, max_value) ; + exit (1) ; + } ; + + /* Check the third section. */ + test_read_[+ (get "float_type_name") +]_or_die (file, 0, data_in, BUFFER_SIZE, __LINE__) ; + + max_value = 0.0 ; + for (k = 0 ; k < BUFFER_SIZE ; k++) + max_value = (max_value > fabs (data_in [k])) ? max_value : fabs (data_in [k]) ; + + if (max_value < 1000.0) + { printf ("\n\nLine %d: Max value (%f) < 1000.0.\n\n", __LINE__, max_value) ; + exit (1) ; + } ; + + sf_close (file) ; + + unlink (filename) ; + puts ("ok") ; +} /* [+ (get "int_type_name") +]_[+ (get "float_short_name") +]_scale_write_test */ +[+ ENDFOR float_type ++][+ ENDFOR int_type +] + + diff --git a/extern/libsndfile-modified/tests/sftest.c b/extern/libsndfile-modified/tests/sftest.c new file mode 100644 index 000000000..497265c92 --- /dev/null +++ b/extern/libsndfile-modified/tests/sftest.c @@ -0,0 +1,67 @@ +/* +** Copyright (C) 1999-2011 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include + +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include + +#define BUFFER_SIZE (1024) + + +static short buffer [BUFFER_SIZE] ; + +int +main (int argc, char *argv []) +{ SNDFILE *file ; + SF_INFO sfinfo ; + int k, count, max = 0, total = 0 ; + + if (argc < 2) + { printf ("Expecting input file name.\n") ; + return 0 ; + } ; + + if (! (file = sf_open (argv [1], SFM_READ, &sfinfo))) + { printf ("sf_open_read failed with error : ") ; + puts (sf_strerror (NULL)) ; + exit (1) ; + } ; + + while ((count = sf_read_short (file, buffer, BUFFER_SIZE))) + { for (k = 0 ; k < count ; k++) + if (abs (buffer [k]) > max) + max = abs (buffer [k]) ; + total += count ; + } ; + + printf ("Total : %d\n", total) ; + printf ("Maximun value : %d\n", max) ; + + sf_close (file) ; + + return 0 ; +} /* main */ + diff --git a/extern/libsndfile-modified/tests/sfversion.c b/extern/libsndfile-modified/tests/sfversion.c new file mode 100644 index 000000000..6caa77ae2 --- /dev/null +++ b/extern/libsndfile-modified/tests/sfversion.c @@ -0,0 +1,48 @@ +/* +** Copyright (C) 1999-2011 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include + +#include + +#define BUFFER_SIZE (256) + + +int +main (void) +{ static char strbuffer [BUFFER_SIZE] ; + const char * ver ; + + sf_command (NULL, SFC_GET_LIB_VERSION, strbuffer, sizeof (strbuffer)) ; + ver = sf_version_string () ; + + if (strcmp (ver, strbuffer) != 0) + { printf ("Version mismatch : '%s' != '%s'\n\n", ver, strbuffer) ; + exit (1) ; + } ; + + printf ("%s", strbuffer) ; + + return 0 ; +} /* main */ + diff --git a/extern/libsndfile-modified/tests/stdin_test.c b/extern/libsndfile-modified/tests/stdin_test.c new file mode 100644 index 000000000..1a9c67b85 --- /dev/null +++ b/extern/libsndfile-modified/tests/stdin_test.c @@ -0,0 +1,206 @@ +/* +** Copyright (C) 2001-2012 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include + +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include + +#include "utils.h" + +#define BUFFER_LEN (1 << 16) + +static void stdin_test (int typemajor, int count) ; + +int +main (int argc, char *argv []) +{ int do_all = 0, test_count = 0 ; + + if (BUFFER_LEN < PIPE_TEST_LEN) + { fprintf (stderr, "Error : BUFFER_LEN < PIPE_TEST_LEN.\n\n") ; + exit (1) ; + } ; + + if (argc != 2) + { fprintf (stderr, "This program cannot be run by itself. It needs\n") ; + fprintf (stderr, "to be run from the stdio_test program.\n") ; + exit (1) ; + } ; + + do_all = ! strcmp (argv [1], "all") ; + + if (do_all || ! strcmp (argv [1], "raw")) + { stdin_test (SF_FORMAT_RAW, PIPE_TEST_LEN) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "wav")) + { stdin_test (SF_FORMAT_WAV, PIPE_TEST_LEN) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "aiff")) + { stdin_test (SF_FORMAT_AIFF, PIPE_TEST_LEN) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "au")) + { stdin_test (SF_FORMAT_AU, PIPE_TEST_LEN) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "paf")) + { stdin_test (SF_FORMAT_PAF, PIPE_TEST_LEN) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "svx")) + { stdin_test (SF_FORMAT_SVX, PIPE_TEST_LEN) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "nist")) + { stdin_test (SF_FORMAT_NIST, PIPE_TEST_LEN) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "ircam")) + { stdin_test (SF_FORMAT_IRCAM, PIPE_TEST_LEN) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "voc")) + { stdin_test (SF_FORMAT_VOC, PIPE_TEST_LEN) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "w64")) + { stdin_test (SF_FORMAT_W64, PIPE_TEST_LEN) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "mat4")) + { stdin_test (SF_FORMAT_MAT4, PIPE_TEST_LEN) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "mat5")) + { stdin_test (SF_FORMAT_MAT5, PIPE_TEST_LEN) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "pvf")) + { stdin_test (SF_FORMAT_PVF, PIPE_TEST_LEN) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "htk")) + { stdin_test (SF_FORMAT_HTK, PIPE_TEST_LEN) ; + test_count++ ; + } ; + + if (test_count == 0) + { fprintf (stderr, "\n*****************************************\n") ; + fprintf (stderr, "* stdin_test : No '%s' test defined.\n", argv [1]) ; + fprintf (stderr, "*****************************************\n") ; + return 1 ; + } ; + + return 0 ; +} /* main */ + +static void +stdin_test (int typemajor, int count) +{ static short data [BUFFER_LEN] ; + + SNDFILE *file ; + SF_INFO sfinfo ; + int k, total, err ; + + if (typemajor == SF_FORMAT_RAW) + { sfinfo.samplerate = 44100 ; + sfinfo.format = SF_FORMAT_RAW | SF_FORMAT_PCM_16 ; + sfinfo.channels = 1 ; + sfinfo.frames = 0 ; + } + else + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + if ((file = sf_open_fd (fileno (stdin), SFM_READ, &sfinfo, SF_TRUE)) == NULL) + { fprintf (stderr, "sf_open_fd failed with error : ") ; + puts (sf_strerror (NULL)) ; + dump_log_buffer (NULL) ; + exit (1) ; + } ; + + err = sf_error (file) ; + if (err != SF_ERR_NO_ERROR) + { printf ("Line %d : unexpected error : %s\n", __LINE__, sf_error_number (err)) ; + exit (1) ; + } ; + + if ((sfinfo.format & SF_FORMAT_TYPEMASK) != typemajor) + { fprintf (stderr, "\n\nError : File type doesn't match.\n") ; + exit (1) ; + } ; + + if (sfinfo.samplerate != 44100) + { fprintf (stderr, "\n\nError : Sample rate (%d) should be 44100\n", sfinfo.samplerate) ; + exit (1) ; + } ; + + if (sfinfo.channels != 1) + { fprintf (stderr, "\n\nError : Channels (%d) should be 1\n", sfinfo.channels) ; + exit (1) ; + } ; + + if (sfinfo.frames < count) + { fprintf (stderr, "\n\nError : Sample count (%ld) should be %d\n", (long) sfinfo.frames, count) ; + exit (1) ; + } ; + + total = 0 ; + while ((k = (int) sf_read_short (file, data + total, BUFFER_LEN - total)) > 0) + total += k ; + + if (total != count) + { fprintf (stderr, "\n\nError : Expected %d frames, read %d.\n", count, total) ; + exit (1) ; + } ; + + for (k = 0 ; k < total ; k++) + if (data [k] != PIPE_INDEX (k)) + { printf ("\n\nError : data [%d] == %d, should have been %d.\n\n", k, data [k], k) ; + exit (1) ; + } ; + + sf_close (file) ; + + return ; +} /* stdin_test */ + diff --git a/extern/libsndfile-modified/tests/stdio_test.c b/extern/libsndfile-modified/tests/stdio_test.c new file mode 100644 index 000000000..a065a040f --- /dev/null +++ b/extern/libsndfile-modified/tests/stdio_test.c @@ -0,0 +1,141 @@ +/* +** Copyright (C) 2001-2011 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/*========================================================================== +** This is a test program which tests reading from stdin and writing to +** stdout. +*/ + +#include "sfconfig.h" + +#include +#include +#include + +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include +#include + +#if HAVE_SYS_WAIT_H +#include +#endif + +#include "utils.h" + +/* EMX is OS/2. */ +#if (OS_IS_WIN32) || defined (__EMX__) + +int +main (void) +{ + puts (" stdio_test : this test doesn't work on win32.") ; + return 0 ; +} /* main */ + +#else + +#ifndef WIFEXITED +#define WIFEXITED(s) (((s) & 0xff) == 0) +#endif +#ifndef WEXITSTATUS +#define WEXITSTATUS(s) (((s) & 0xff00) >> 8) +#endif + + +static size_t file_length (const char *filename) ; +static void stdio_test (const char *filetype) ; + +static const char *filetypes [] = +{ "raw", "wav", "aiff", "au", "paf", "svx", "nist", "ircam", + "voc", "w64", "mat4", "mat5", "pvf", + NULL +} ; + +int +main (void) +{ int k ; + + for (k = 0 ; filetypes [k] ; k++) + stdio_test (filetypes [k]) ; + + return 0 ; +} /* main */ + + +static void +stdio_test (const char *filetype) +{ static char buffer [256] ; + + int file_size, retval ; + + print_test_name ("stdio_test", filetype) ; + + snprintf (buffer, sizeof (buffer), "./tests/stdout_test %s > stdio.%s", filetype, filetype) ; + if ((retval = system (buffer))) + { retval = WIFEXITED (retval) ? WEXITSTATUS (retval) : 1 ; + printf ("%s : %s", buffer, (strerror (retval))) ; + exit (1) ; + } ; + + snprintf (buffer, sizeof (buffer), "stdio.%s", filetype) ; + if ((file_size = file_length (buffer)) < PIPE_TEST_LEN) + { printf ("\n Error : test file '%s' too small (%d).\n\n", buffer, file_size) ; + exit (1) ; + } ; + + snprintf (buffer, sizeof (buffer), "./tests/stdin_test %s < stdio.%s", filetype, filetype) ; + if ((retval = system (buffer))) + { retval = WIFEXITED (retval) ? WEXITSTATUS (retval) : 1 ; + printf ("%s : %s", buffer, (strerror (retval))) ; + exit (1) ; + } ; + + snprintf (buffer, sizeof (buffer), "rm stdio.%s", filetype) ; + if ((retval = system (buffer))) + { retval = WIFEXITED (retval) ? WEXITSTATUS (retval) : 1 ; + printf ("%s : %s", buffer, (strerror (retval))) ; + exit (1) ; + } ; + + puts ("ok") ; + + return ; +} /* stdio_test */ + + + + +static size_t +file_length (const char *filename) +{ struct stat buf ; + + if (stat (filename, &buf)) + { perror (filename) ; + exit (1) ; + } ; + + return buf.st_size ; +} /* file_length */ + +#endif + diff --git a/extern/libsndfile-modified/tests/stdout_test.c b/extern/libsndfile-modified/tests/stdout_test.c new file mode 100644 index 000000000..e2cbe8d82 --- /dev/null +++ b/extern/libsndfile-modified/tests/stdout_test.c @@ -0,0 +1,169 @@ +/* +** Copyright (C) 2001-2014 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include + +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include + +#include "utils.h" + +static void stdout_test (int typemajor, int count) ; + +int +main (int argc, char *argv []) +{ int do_all, test_count = 0 ; + + if (argc != 2) + { fprintf (stderr, "This program cannot be run by itself. It needs\n") ; + fprintf (stderr, "to be run from the stdio_test program.\n") ; + exit (1) ; + } ; + + do_all = ! strcmp (argv [1], "all") ; + + if (do_all || ! strcmp (argv [1], "raw")) + { stdout_test (SF_FORMAT_RAW, PIPE_TEST_LEN) ; + test_count ++ ; + } ; + + if (do_all || ! strcmp (argv [1], "wav")) + { stdout_test (SF_FORMAT_WAV, PIPE_TEST_LEN) ; + test_count ++ ; + } ; + + if (do_all || ! strcmp (argv [1], "aiff")) + { stdout_test (SF_FORMAT_AIFF, PIPE_TEST_LEN) ; + test_count ++ ; + } ; + + if (do_all || ! strcmp (argv [1], "au")) + { stdout_test (SF_FORMAT_AU, PIPE_TEST_LEN) ; + test_count ++ ; + } ; + + if (do_all || ! strcmp (argv [1], "paf")) + { stdout_test (SF_FORMAT_PAF, PIPE_TEST_LEN) ; + test_count ++ ; + } ; + + if (do_all || ! strcmp (argv [1], "svx")) + { stdout_test (SF_FORMAT_SVX, PIPE_TEST_LEN) ; + test_count ++ ; + } ; + + if (do_all || ! strcmp (argv [1], "nist")) + { stdout_test (SF_FORMAT_NIST, PIPE_TEST_LEN) ; + test_count ++ ; + } ; + + if (do_all || ! strcmp (argv [1], "ircam")) + { stdout_test (SF_FORMAT_IRCAM, PIPE_TEST_LEN) ; + test_count ++ ; + } ; + + if (do_all || ! strcmp (argv [1], "voc")) + { stdout_test (SF_FORMAT_VOC, PIPE_TEST_LEN) ; + test_count ++ ; + } ; + + if (do_all || ! strcmp (argv [1], "w64")) + { stdout_test (SF_FORMAT_W64, PIPE_TEST_LEN) ; + test_count ++ ; + } ; + + if (do_all || ! strcmp (argv [1], "mat4")) + { stdout_test (SF_FORMAT_MAT4, PIPE_TEST_LEN) ; + test_count ++ ; + } ; + + if (do_all || ! strcmp (argv [1], "mat5")) + { stdout_test (SF_FORMAT_MAT5, PIPE_TEST_LEN) ; + test_count ++ ; + } ; + + if (do_all || ! strcmp (argv [1], "pvf")) + { stdout_test (SF_FORMAT_PVF, PIPE_TEST_LEN) ; + test_count ++ ; + } ; + + if (test_count == 0) + { fprintf (stderr, "\n******************************************\n") ; + fprintf (stderr, "* stdout_test : No '%s' test defined.\n", argv [1]) ; + fprintf (stderr, "******************************************\n") ; + return 1 ; + } ; + + return 0 ; +} /* main */ + +static void +stdout_test (int typemajor, int count) +{ static short data [PIPE_TEST_LEN] ; + + SNDFILE *file ; + SF_INFO sfinfo ; + int k, total, this_write ; + + sfinfo.samplerate = 44100 ; + sfinfo.format = (typemajor | SF_FORMAT_PCM_16) ; + sfinfo.channels = 1 ; + sfinfo.frames = 0 ; + + /* Create some random data. */ + for (k = 0 ; k < PIPE_TEST_LEN ; k++) + data [k] = PIPE_INDEX (k) ; + + if ((file = sf_open ("-", SFM_WRITE, &sfinfo)) == NULL) + { fprintf (stderr, "%s % d: sf_open_write failed with error : %s\n", + __func__, __LINE__, sf_strerror (NULL)) ; + exit (1) ; + } ; + + if (sfinfo.frames != 0) + { fprintf (stderr, "%s % d: Frames is %d (should be 0).\n", + __func__, __LINE__, (int) sfinfo.frames) ; + exit (1) ; + } ; + + total = 0 ; + + while (total < count) + { this_write = (count - total > 1024) ? 1024 : count - total ; + if ((k = (int) sf_write_short (file, data + total, this_write)) != this_write) + { fprintf (stderr, "sf_write_short # %d failed with short write (%d -> %d)\n", count, this_write, k) ; + exit (1) ; + } ; + total += k ; + } ; + + sf_close (file) ; + + return ; +} /* stdout_test */ + diff --git a/extern/libsndfile-modified/tests/string_test.c b/extern/libsndfile-modified/tests/string_test.c new file mode 100644 index 000000000..1e1d73386 --- /dev/null +++ b/extern/libsndfile-modified/tests/string_test.c @@ -0,0 +1,907 @@ +/* +** Copyright (C) 2003-2016 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include +#include + +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include + +#include "utils.h" + +#define BUFFER_LEN (1 << 10) +#define LOG_BUFFER_SIZE 1024 + +#define NULL_PRINTF_CHECK(X) (X ? X : "(null)") + +static const char STR_TEST_PREFIX[] = "str" ; + +static void string_start_test (const char *filename, int typemajor) ; +static void string_start_end_test (const char *filename, int typemajor) ; +static void string_multi_set_test (const char *filename, int typemajor) ; +static void string_rdwr_test (const char *filename, int typemajor) ; +static void string_short_rdwr_test (const char *filename, int typemajor) ; +static void string_rdwr_grow_test (const char *filename, int typemajor) ; +static void string_header_update (const char *filename, int typemajor) ; + +static void software_string_test (const char *filename) ; + +static int str_count (const char * haystack, const char * needle) ; + +int +main (int argc, char *argv []) +{ int do_all = 0 ; + int test_count = 0 ; + + if (argc != 2) + { printf ("Usage : %s \n", argv [0]) ; + printf (" Where is one of the following:\n") ; + printf (" wav - test adding strings to WAV files\n") ; + printf (" aiff - test adding strings to AIFF files\n") ; + printf (" flac - test adding strings to FLAC files\n") ; + printf (" ogg - test adding strings to OGG files\n") ; + printf (" opus - test adding strings to OPUS files\n") ; + printf (" all - perform all tests\n") ; + exit (1) ; + } ; + + do_all = ! strcmp (argv [1], "all") ; + + if (do_all || ! strcmp (argv [1], "wav")) + { string_start_end_test ("strings.wav", SF_FORMAT_WAV) ; + string_multi_set_test ("multi.wav", SF_FORMAT_WAV) ; + string_rdwr_test ("rdwr.wav", SF_FORMAT_WAV) ; + string_short_rdwr_test ("short_rdwr.wav", SF_FORMAT_WAV) ; + string_rdwr_grow_test ("rdwr_grow.wav", SF_FORMAT_WAV) ; + string_header_update ("header_update.wav", SF_FORMAT_WAV) ; + + string_start_end_test ("strings.wavex", SF_FORMAT_WAVEX) ; + string_multi_set_test ("multi.wavex", SF_FORMAT_WAVEX) ; + string_rdwr_test ("rdwr.wavex", SF_FORMAT_WAVEX) ; + string_short_rdwr_test ("short_rdwr.wavex", SF_FORMAT_WAVEX) ; + + string_start_end_test ("strings.rifx", SF_ENDIAN_BIG | SF_FORMAT_WAV) ; + string_multi_set_test ("multi.rifx", SF_ENDIAN_BIG | SF_FORMAT_WAV) ; + string_rdwr_test ("rdwr.rifx", SF_ENDIAN_BIG | SF_FORMAT_WAV) ; + string_short_rdwr_test ("short_rdwr.rifx", SF_ENDIAN_BIG | SF_FORMAT_WAV) ; + + software_string_test ("software_string.wav") ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "aiff")) + { string_start_test ("strings.aiff", SF_FORMAT_AIFF) ; + string_start_end_test ("strings.aiff", SF_FORMAT_AIFF) ; + /* + TODO : Fix src/aiff.c so these tests pass. + string_multi_set_test ("multi.aiff", SF_FORMAT_AIFF) ; + string_rdwr_test ("rdwr.aiff", SF_FORMAT_AIFF) ; + string_short_rdwr_test ("short_rdwr.aiff", SF_FORMAT_AIFF) ; + string_rdwr_grow_test ("rdwr_grow.aiff", SF_FORMAT_AIFF) ; + string_header_update ("header_update.aiff", SF_FORMAT_AIFF) ; + */ + + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "flac")) + { if (HAVE_EXTERNAL_XIPH_LIBS) + string_start_test ("strings.flac", SF_FORMAT_FLAC) ; + else + puts (" No FLAC tests because FLAC support was not compiled in.") ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "mpeg")) + { if (HAVE_MPEG) + string_start_test ("mpeg.mp3", SF_FORMAT_MPEG | SF_FORMAT_MPEG_LAYER_III) ; + else + puts (" No MP3 tests because MPEG support was not compiled in.") ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "ogg")) + { if (HAVE_EXTERNAL_XIPH_LIBS) + string_start_test ("vorbis.oga", SF_FORMAT_OGG | SF_FORMAT_VORBIS) ; + else + puts (" No Ogg/Vorbis tests because Ogg/Vorbis support was not compiled in.") ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "opus")) + { if (HAVE_EXTERNAL_XIPH_LIBS) + string_start_test ("opus.opus", SF_FORMAT_OGG | SF_FORMAT_OPUS) ; + else + puts (" No Ogg/Opus tests because Ogg/Opus support was not compiled in.") ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "caf")) + { string_start_test ("strings.caf", SF_FORMAT_CAF) ; + string_start_end_test ("strings.caf", SF_FORMAT_CAF) ; + string_multi_set_test ("multi.caf", SF_FORMAT_CAF) ; + /* + TODO : Fix src/caf.c so these tests pass. + string_rdwr_test ("rdwr.caf", SF_FORMAT_CAF) ; + string_short_rdwr_test ("short_rdwr.caf", SF_FORMAT_CAF) ; + string_header_update ("header_update.caf", SF_FORMAT_CAF) ; + */ + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "rf64")) + { string_start_test ("strings.rf64", SF_FORMAT_RF64) ; + string_start_end_test ("strings.rf64", SF_FORMAT_RF64) ; + string_multi_set_test ("multi.rf64", SF_FORMAT_RF64) ; + /* + TODO : Fix src/rf64.c so these tests pass. + string_rdwr_test ("rdwr.rf64", SF_FORMAT_RF64) ; + string_short_rdwr_test ("short_rdwr.rf64", SF_FORMAT_RF64) ; + string_header_update ("header_update.rf64", SF_FORMAT_RF64) ; + */ + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "w64")) + { puts ("\n\n **** String test not working yet for W64 format. ****\n") ; + /* + string_start_test ("strings.w64", SF_FORMAT_W64) ; + string_start_end_test ("strings.w64", SF_FORMAT_W64) ; + string_multi_set_test ("multi.w64", SF_FORMAT_W64) ; + string_rdwr_test ("rdwr.w64", SF_FORMAT_W64) ; + string_short_rdwr_test ("short_rdwr.w64", SF_FORMAT_W64) ; + string_header_update ("header_update.w64", SF_FORMAT_W64) ; + */ + test_count++ ; + } ; + + if (test_count == 0) + { printf ("Mono : ************************************\n") ; + printf ("Mono : * No '%s' test defined.\n", argv [1]) ; + printf ("Mono : ************************************\n") ; + return 1 ; + } ; + + return 0 ; +} /* main */ + + +/*============================================================================================ +** Here are the test functions. +*/ + +static const char + software [] = "software (libsndfile-X.Y.Z)", + artist [] = "The Artist", + copyright [] = "Copyright (c) 2001 Artist", + comment [] = "Comment goes here!!!", + date [] = "2001/01/27", + album [] = "The Album", + license [] = "The license", + title [] = "This is the title", + long_title [] = "This is a very long and very boring title for this file", + long_artist [] = "The artist who kept on changing its name", + genre [] = "The genre", + trackno [] = "Track three", + id3v1_genre [] = "Rock", + year [] = "2001" ; + + +static short data_out [BUFFER_LEN] ; + +static void +string_start_end_test (const char *filename, int typemajor) +{ const char *cptr ; + SNDFILE *file ; + SF_INFO sfinfo ; + int errors = 0 ; + + get_unique_test_name (&filename, STR_TEST_PREFIX) ; + print_test_name ("string_start_end_test", filename) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + sfinfo.samplerate = 44100 ; + sfinfo.channels = 1 ; + sfinfo.frames = 0 ; + sfinfo.format = typemajor | SF_FORMAT_PCM_16 ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + + /* Write stuff at start of file. */ + sf_set_string (file, SF_STR_TITLE, filename) ; + sf_set_string (file, SF_STR_SOFTWARE, software) ; + sf_set_string (file, SF_STR_ARTIST, artist) ; + sf_set_string (file, SF_STR_GENRE, genre) ; + sf_set_string (file, SF_STR_TRACKNUMBER, trackno) ; + + /* Write data to file. */ + test_write_short_or_die (file, 0, data_out, BUFFER_LEN, __LINE__) ; + test_seek_or_die (file, 0, SEEK_SET, 0, sfinfo.channels, __LINE__) ; + + /* Write more stuff at end of file. */ + sf_set_string (file, SF_STR_COPYRIGHT, copyright) ; + sf_set_string (file, SF_STR_COMMENT, comment) ; + sf_set_string (file, SF_STR_DATE, date) ; + sf_set_string (file, SF_STR_ALBUM, album) ; + sf_set_string (file, SF_STR_LICENSE, license) ; + + sf_close (file) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + + check_log_buffer_or_die (file, __LINE__) ; + + if (sfinfo.frames != BUFFER_LEN) + { printf ("***** Bad frame count %d (should be %d)\n\n", (int) sfinfo.frames, BUFFER_LEN) ; + errors ++ ; + } ; + + cptr = sf_get_string (file, SF_STR_TITLE) ; + if (cptr == NULL || strcmp (filename, cptr) != 0) + { if (errors++ == 0) + puts ("\n") ; + printf (" Bad filename : %s\n", NULL_PRINTF_CHECK(cptr)) ; + } ; + + cptr = sf_get_string (file, SF_STR_COPYRIGHT) ; + if (cptr == NULL || strcmp (copyright, cptr) != 0) + { if (errors++ == 0) + puts ("\n") ; + printf (" Bad copyright : %s\n", NULL_PRINTF_CHECK(cptr)) ; + } ; + + cptr = sf_get_string (file, SF_STR_SOFTWARE) ; + if (cptr == NULL || strstr (cptr, software) != cptr) + { if (errors++ == 0) + puts ("\n") ; + printf (" Bad software : %s\n", NULL_PRINTF_CHECK(cptr)) ; + } ; + + if (str_count (cptr, "libsndfile") != 1) + { if (errors++ == 0) + puts ("\n") ; + printf (" Bad software : %s\n", cptr) ; + } ; + + cptr = sf_get_string (file, SF_STR_ARTIST) ; + if (cptr == NULL || strcmp (artist, cptr) != 0) + { if (errors++ == 0) + puts ("\n") ; + printf (" Bad artist : %s\n", NULL_PRINTF_CHECK(cptr)) ; + } ; + + cptr = sf_get_string (file, SF_STR_COMMENT) ; + if (cptr == NULL || strcmp (comment, cptr) != 0) + { if (errors++ == 0) + puts ("\n") ; + printf (" Bad comment : %s\n", NULL_PRINTF_CHECK(cptr)) ; + } ; + + if (typemajor != SF_FORMAT_AIFF) + { cptr = sf_get_string (file, SF_STR_DATE) ; + if (cptr == NULL || strcmp (date, cptr) != 0) + { if (errors++ == 0) + puts ("\n") ; + printf (" Bad date : %s\n", NULL_PRINTF_CHECK(cptr)) ; + } ; + + cptr = sf_get_string (file, SF_STR_GENRE) ; + if (cptr == NULL || strcmp (genre, cptr) != 0) + { if (errors++ == 0) + puts ("\n") ; + printf (" Bad genre : %s\n", NULL_PRINTF_CHECK(cptr)) ; + } ; + } ; + + switch (typemajor) + { case SF_FORMAT_AIFF : + case SF_FORMAT_WAV : + case SF_FORMAT_WAVEX : + case SF_ENDIAN_BIG | SF_FORMAT_WAV : + case SF_FORMAT_RF64 : + /* These formats do not support the following. */ + break ; + + default : + cptr = sf_get_string (file, SF_STR_ALBUM) ; + if (cptr == NULL || strcmp (album, cptr) != 0) + { if (errors++ == 0) + puts ("\n") ; + printf (" Bad album : %s\n", NULL_PRINTF_CHECK(cptr)) ; + } ; + + cptr = sf_get_string (file, SF_STR_LICENSE) ; + if (cptr == NULL || strcmp (license, cptr) != 0) + { if (errors++ == 0) + puts ("\n") ; + printf (" Bad license : %s\n", NULL_PRINTF_CHECK(cptr)) ; + } ; + + cptr = sf_get_string (file, SF_STR_TRACKNUMBER) ; + if (cptr == NULL || strcmp (trackno, cptr) != 0) + { if (errors++ == 0) + puts ("\n") ; + printf (" Bad track no. : %s\n", NULL_PRINTF_CHECK(cptr)) ; + } ; + break ; + } ; + + if (errors > 0) + { printf ("\n*** Error count : %d ***\n\n", errors) ; + dump_log_buffer (file) ; + exit (1) ; + } ; + + sf_close (file) ; + unlink (filename) ; + + puts ("ok") ; +} /* string_start_end_test */ + +static void +string_start_test (const char *filename, int formattype) +{ const char *cptr ; + SNDFILE *file ; + SF_INFO sfinfo ; + int errors = 0 ; + int typemajor = SF_FORMAT_TYPEMASK & formattype ; + + get_unique_test_name (&filename, STR_TEST_PREFIX) ; + print_test_name ("string_start_test", filename) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + sfinfo.samplerate = 44100 ; + sfinfo.channels = 1 ; + sfinfo.frames = 0 ; + + switch (formattype) + { case SF_FORMAT_OGG | SF_FORMAT_OPUS : + /* Opus only supports some discrete sample rates. */ + sfinfo.samplerate = 48000 ; + break ; + + case SF_FORMAT_OGG | SF_FORMAT_VORBIS : + case SF_FORMAT_MPEG | SF_FORMAT_MPEG_LAYER_III : + break ; + + default : + formattype |= SF_FORMAT_PCM_16 ; + break ; + } ; + sfinfo.format = formattype ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + + /* Write stuff at start of file. */ + sf_set_string (file, SF_STR_TITLE, filename) ; + sf_set_string (file, SF_STR_SOFTWARE, software) ; + sf_set_string (file, SF_STR_ARTIST, artist) ; + sf_set_string (file, SF_STR_COPYRIGHT, copyright) ; + sf_set_string (file, SF_STR_COMMENT, comment) ; + sf_set_string (file, SF_STR_ALBUM, album) ; + sf_set_string (file, SF_STR_LICENSE, license) ; + if (typemajor == SF_FORMAT_MPEG) + { sf_set_string (file, SF_STR_GENRE, id3v1_genre) ; + sf_set_string (file, SF_STR_DATE, year) ; + } + else + { sf_set_string (file, SF_STR_DATE, date) ; + } ; + + /* Write data to file. */ + test_write_short_or_die (file, 0, data_out, BUFFER_LEN, __LINE__) ; + + sf_close (file) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + + check_log_buffer_or_die (file, __LINE__) ; + + if (sfinfo.frames != BUFFER_LEN) + { printf ("***** Bad frame count %d (should be %d)\n\n", (int) sfinfo.frames, BUFFER_LEN) ; + errors ++ ; + } ; + + cptr = sf_get_string (file, SF_STR_TITLE) ; + if (cptr == NULL || strcmp (filename, cptr) != 0) + { if (errors++ == 0) + puts ("\n") ; + printf (" Bad filename : %s\n", NULL_PRINTF_CHECK(cptr)) ; + } ; + + if (typemajor != SF_FORMAT_MPEG) + { cptr = sf_get_string (file, SF_STR_COPYRIGHT) ; + if (cptr == NULL || strcmp (copyright, cptr) != 0) + { if (errors++ == 0) + puts ("\n") ; + printf (" Bad copyright : %s\n", NULL_PRINTF_CHECK(cptr)) ; + } ; + + cptr = sf_get_string (file, SF_STR_SOFTWARE) ; + if (cptr == NULL || strstr (cptr, software) != cptr) + { if (errors++ == 0) + puts ("\n") ; + printf (" Bad software : %s\n", NULL_PRINTF_CHECK(cptr)) ; + } ; + + if (cptr && str_count (cptr, "libsndfile") != 1) + { if (errors++ == 0) + puts ("\n") ; + printf (" Bad software : %s\n", cptr) ; + } ; + } ; + + if (typemajor == SF_FORMAT_MPEG) + { cptr = sf_get_string (file, SF_STR_GENRE) ; + if (cptr == NULL || strcmp (id3v1_genre, cptr) != 0) + { if (errors++ == 0) + puts ("\n") ; + printf (" Bad genre : %s\n", NULL_PRINTF_CHECK(cptr)) ; + } ; + } ; + + cptr = sf_get_string (file, SF_STR_ARTIST) ; + if (cptr == NULL || strcmp (artist, cptr) != 0) + { if (errors++ == 0) + puts ("\n") ; + printf (" Bad artist : %s\n", NULL_PRINTF_CHECK(cptr)) ; + } ; + + cptr = sf_get_string (file, SF_STR_COMMENT) ; + if (cptr == NULL || strcmp (comment, cptr) != 0) + { if (errors++ == 0) + puts ("\n") ; + printf (" Bad comment : %s\n", NULL_PRINTF_CHECK(cptr)) ; + } ; + + switch (typemajor) + { case SF_FORMAT_AIFF : + /* not supported */ + break ; + + case SF_FORMAT_MPEG : + /* id3 only supports years */ + cptr = sf_get_string (file, SF_STR_DATE) ; + if (cptr == NULL || strcmp (year, cptr) != 0) + { if (errors++ == 0) + puts ("\n") ; + printf (" Bad date : %s\n", NULL_PRINTF_CHECK(cptr)) ; + } ; + break ; + + default : + cptr = sf_get_string (file, SF_STR_DATE) ; + if (cptr == NULL || strcmp (date, cptr) != 0) + { if (errors++ == 0) + puts ("\n") ; + printf (" Bad date : %s\n", NULL_PRINTF_CHECK(cptr)) ; + } ; + break ; + } ; + + if (typemajor != SF_FORMAT_WAV && typemajor != SF_FORMAT_AIFF) + { cptr = sf_get_string (file, SF_STR_ALBUM) ; + if (cptr == NULL || strcmp (album, cptr) != 0) + { if (errors++ == 0) + puts ("\n") ; + printf (" Bad album : %s\n", NULL_PRINTF_CHECK(cptr)) ; + } ; + } ; + + switch (typemajor) + { case SF_FORMAT_WAV : + case SF_FORMAT_AIFF : + case SF_FORMAT_RF64 : + case SF_FORMAT_MPEG : + /* not supported */ + break ; + + default: + cptr = sf_get_string (file, SF_STR_LICENSE) ; + if (cptr == NULL || strcmp (license, cptr) != 0) + { if (errors++ == 0) + puts ("\n") ; + printf (" Bad license : %s\n", NULL_PRINTF_CHECK(cptr)) ; + } ; + } ; + + if (errors > 0) + { printf ("\n*** Error count : %d ***\n\n", errors) ; + dump_log_buffer (file) ; + exit (1) ; + } ; + + sf_close (file) ; + unlink (filename) ; + + puts ("ok") ; +} /* string_start_test */ + +static void +string_multi_set_test (const char *filename, int typemajor) +{ static const char + new_software [] = "new software (libsndfile-X.Y.Z)", + new_copyright [] = "Copyright (c) 2001 New Artist", + new_artist [] = "The New Artist", + new_title [] = "This is the new title" ; + + static char buffer [2048] ; + SNDFILE *file ; + SF_INFO sfinfo ; + int count ; + + get_unique_test_name (&filename, STR_TEST_PREFIX) ; + print_test_name (__func__, filename) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + sfinfo.format = typemajor | SF_FORMAT_PCM_16 ; + sfinfo.samplerate = 44100 ; + sfinfo.channels = 1 ; + sfinfo.frames = 0 ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + + /* Write stuff at start of file. */ + sf_set_string (file, SF_STR_TITLE, title) ; + sf_set_string (file, SF_STR_SOFTWARE, software) ; + sf_set_string (file, SF_STR_ARTIST, artist) ; + + /* Write data to file. */ + test_write_short_or_die (file, 0, data_out, BUFFER_LEN, __LINE__) ; + + /* Write it all again. */ + + sf_set_string (file, SF_STR_TITLE, new_title) ; + sf_set_string (file, SF_STR_SOFTWARE, new_software) ; + sf_set_string (file, SF_STR_ARTIST, new_artist) ; + + sf_set_string (file, SF_STR_COPYRIGHT, copyright) ; + sf_set_string (file, SF_STR_COMMENT, comment) ; + sf_set_string (file, SF_STR_DATE, date) ; + sf_set_string (file, SF_STR_ALBUM, album) ; + sf_set_string (file, SF_STR_LICENSE, license) ; + sf_set_string (file, SF_STR_COPYRIGHT, new_copyright) ; + sf_set_string (file, SF_STR_COMMENT, comment) ; + sf_set_string (file, SF_STR_DATE, date) ; + sf_set_string (file, SF_STR_ALBUM, album) ; + sf_set_string (file, SF_STR_LICENSE, license) ; + + sf_close (file) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + sf_command (file, SFC_GET_LOG_INFO, buffer, sizeof (buffer)) ; + sf_close (file) ; + + count = str_count (buffer, new_title) ; + exit_if_true (count < 1, "\n\nLine %d : Could not find new_title in :\n%s\n", __LINE__, buffer) ; + exit_if_true (count > 1, "\n\nLine %d : new_title appears %d times in :\n\n%s\n", __LINE__, count, buffer) ; + + count = str_count (buffer, software) ; + exit_if_true (count < 1, "\n\nLine %d : Could not find new_software in :\n%s\n", __LINE__, buffer) ; + exit_if_true (count > 1, "\n\nLine %d : new_software appears %d times in :\n\n%s\n", __LINE__, count, buffer) ; + + count = str_count (buffer, new_artist) ; + exit_if_true (count < 1, "\n\nLine %d : Could not find new_artist in :\n%s\n", __LINE__, buffer) ; + exit_if_true (count > 1, "\n\nLine %d : new_artist appears %d times in :\n\n%s\n", __LINE__, count, buffer) ; + + count = str_count (buffer, new_copyright) ; + exit_if_true (count < 1, "\n\nLine %d : Could not find new_copyright in :\n%s\n", __LINE__, buffer) ; + exit_if_true (count > 1, "\n\nLine %d : new_copyright appears %d times in :\n\n%s\n", __LINE__, count, buffer) ; + + unlink (filename) ; + + puts ("ok") ; +} /* string_multi_set_test */ + +static void +string_rdwr_test (const char *filename, int typemajor) +{ SNDFILE *file ; + SF_INFO sfinfo ; + sf_count_t frames ; + const char * str ; + + get_unique_test_name (&filename, STR_TEST_PREFIX) ; + print_test_name (__func__, filename) ; + create_short_sndfile (filename, typemajor | SF_FORMAT_PCM_16, 2) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + file = test_open_file_or_die (filename, SFM_RDWR, &sfinfo, SF_FALSE, __LINE__) ; + frames = sfinfo.frames ; + sf_set_string (file, SF_STR_TITLE, title) ; + sf_close (file) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + exit_if_true (frames != sfinfo.frames, "\n\nLine %d : Frame count %" PRId64 " should be %" PRId64 ".\n", __LINE__, sfinfo.frames, frames) ; + str = sf_get_string (file, SF_STR_TITLE) ; + exit_if_true (str == NULL, "\n\nLine %d : SF_STR_TITLE string is NULL.\n", __LINE__) ; + exit_if_true (strcmp (str, title) != 0, "\n\nLine %d : SF_STR_TITLE doesn't match what was written.\n", __LINE__) ; + sf_close (file) ; + + file = test_open_file_or_die (filename, SFM_RDWR, &sfinfo, SF_FALSE, __LINE__) ; + frames = sfinfo.frames ; + sf_set_string (file, SF_STR_TITLE, title) ; + sf_close (file) ; + + file = test_open_file_or_die (filename, SFM_RDWR, &sfinfo, SF_FALSE, __LINE__) ; + str = sf_get_string (file, SF_STR_TITLE) ; + exit_if_true (str == NULL, "\n\nLine %d : SF_STR_TITLE string is NULL.\n", __LINE__) ; + sf_set_string (file, SF_STR_ARTIST, artist) ; + sf_close (file) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + + str = sf_get_string (file, SF_STR_ARTIST) ; + exit_if_true (str == NULL, "\n\nLine %d : SF_STR_ARTIST string is NULL.\n", __LINE__) ; + exit_if_true (strcmp (str, artist) != 0, "\n\nLine %d : SF_STR_ARTIST doesn't match what was written.\n", __LINE__) ; + + str = sf_get_string (file, SF_STR_TITLE) ; + exit_if_true (str == NULL, "\n\nLine %d : SF_STR_TITLE string is NULL.\n", __LINE__) ; + exit_if_true (strcmp (str, title) != 0, "\n\nLine %d : SF_STR_TITLE doesn't match what was written.\n", __LINE__) ; + + exit_if_true (frames != sfinfo.frames, "\n\nLine %d : Frame count %" PRId64 " should be %" PRId64 ".\n", __LINE__, sfinfo.frames, frames) ; + + sf_close (file) ; + unlink (filename) ; + + puts ("ok") ; +} /* string_rdwr_test */ + +static void +string_short_rdwr_test (const char *filename, int typemajor) +{ SNDFILE *file ; + SF_INFO sfinfo ; + sf_count_t frames = BUFFER_LEN ; + const char * str ; + + get_unique_test_name (&filename, STR_TEST_PREFIX) ; + print_test_name (__func__, filename) ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + sfinfo.format = typemajor | SF_FORMAT_PCM_16 ; + sfinfo.samplerate = 44100 ; + sfinfo.channels = 1 ; + sfinfo.frames = 0 ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_FALSE, __LINE__) ; + + /* Write data to file. */ + test_write_short_or_die (file, 0, data_out, BUFFER_LEN, __LINE__) ; + + sf_set_string (file, SF_STR_TITLE, long_title) ; + sf_set_string (file, SF_STR_ARTIST, long_artist) ; + sf_close (file) ; + + /* Open the file RDWR. */ + file = test_open_file_or_die (filename, SFM_RDWR, &sfinfo, SF_FALSE, __LINE__) ; + exit_if_true (frames != sfinfo.frames, "\n\nLine %d : Frame count %" PRId64 " should be %" PRId64 ".\n", __LINE__, sfinfo.frames, frames) ; + str = sf_get_string (file, SF_STR_TITLE) ; + exit_if_true (str == NULL, "\n\nLine %d : SF_STR_TITLE string is NULL.\n", __LINE__) ; + exit_if_true (strcmp (str, long_title) != 0, "\n\nLine %d : SF_STR_TITLE doesn't match what was written.\n", __LINE__) ; + str = sf_get_string (file, SF_STR_ARTIST) ; + exit_if_true (str == NULL, "\n\nLine %d : SF_STR_TITLE string is NULL.\n", __LINE__) ; + exit_if_true (strcmp (str, long_artist) != 0, "\n\nLine %d : SF_STR_ARTIST doesn't match what was written.\n", __LINE__) ; + + /* Change title and artist. */ + sf_set_string (file, SF_STR_TITLE, title) ; + sf_set_string (file, SF_STR_ARTIST, artist) ; + + sf_close (file) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_FALSE, __LINE__) ; + + check_log_buffer_or_die (file, __LINE__) ; + + str = sf_get_string (file, SF_STR_TITLE) ; + exit_if_true (str == NULL, "\n\nLine %d : SF_STR_TITLE string is NULL.\n", __LINE__) ; + exit_if_true (strcmp (str, title) != 0, "\n\nLine %d : SF_STR_TITLE doesn't match what was written.\n", __LINE__) ; + + str = sf_get_string (file, SF_STR_ARTIST) ; + exit_if_true (str == NULL, "\n\nLine %d : SF_STR_ARTIST string is NULL.\n", __LINE__) ; + exit_if_true (strcmp (str, artist) != 0, "\n\nLine %d : SF_STR_ARTIST doesn't match what was written.\n", __LINE__) ; + + sf_close (file) ; + unlink (filename) ; + + puts ("ok") ; +} /* string_short_rdwr_test */ + +static int +str_count (const char * haystack, const char * needle) +{ int count = 0 ; + + while ((haystack = strstr (haystack, needle)) != NULL) + { count ++ ; + haystack ++ ; + } ; + + return count ; +} /* str_count */ + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +static void +software_string_test (const char *filename) +{ size_t k ; + + get_unique_test_name (&filename, STR_TEST_PREFIX) ; + print_test_name (__func__, filename) ; + + for (k = 0 ; k < 50 ; k++) + { const char *result ; + char sfname [64] = "" ; + SNDFILE *file ; + SF_INFO info ; + + sf_info_setup (&info, SF_FORMAT_WAV | SF_FORMAT_PCM_16, 44100, 1) ; + file = test_open_file_or_die (filename, SFM_WRITE, &info, SF_TRUE, __LINE__) ; + + snprintf (sfname, MIN (k, sizeof (sfname)), "%s", "abcdefghijklmnopqrestvwxyz0123456789abcdefghijklmnopqrestvwxyz") ; + + exit_if_true (sf_set_string (file, SF_STR_SOFTWARE, sfname), + "\n\nLine %d : sf_set_string (f, SF_STR_SOFTWARE, '%s') failed : %s\n", __LINE__, sfname, sf_strerror (file)) ; + + sf_close (file) ; + + file = test_open_file_or_die (filename, SFM_READ, &info, SF_TRUE, __LINE__) ; + result = sf_get_string (file, SF_STR_SOFTWARE) ; + + exit_if_true (result == NULL, "\n\nLine %d : sf_get_string (file, SF_STR_SOFTWARE) returned NULL.\n\n", __LINE__) ; + + exit_if_true (strstr (result, sfname) != result, + "\n\nLine %d : Can't fine string '%s' in '%s'\n\n", __LINE__, sfname, result) ; + sf_close (file) ; + } ; + + unlink (filename) ; + puts ("ok") ; +} /* software_string_test */ + + +static void +string_rdwr_grow_test (const char *filename, int typemajor) +{ SNDFILE *file ; + SF_INFO sfinfo ; + sf_count_t frames ; + const char * str ; + + get_unique_test_name (&filename, STR_TEST_PREFIX) ; + print_test_name (__func__, filename) ; + + /* Create a file that contains some strings. Then open the file in RDWR mode and + grow the file by writing more audio data to it. Check that the audio data has + been added to the file, and that the strings are still there. */ + + /* Create a short file that contains a string. */ + memset (&sfinfo, 0, sizeof (sfinfo)) ; + sfinfo.samplerate = 44100 ; + sfinfo.channels = 2 ; + sfinfo.frames = 0 ; + sfinfo.format = typemajor | SF_FORMAT_PCM_16 ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + /* Write data to file. */ + test_write_short_or_die (file, 0, data_out, BUFFER_LEN, __LINE__) ; + + /* Write some strings at end of file. */ + sf_set_string (file, SF_STR_TITLE , title) ; + sf_set_string (file, SF_STR_COMMENT, comment) ; + sf_close (file) ; + + + /* Now open file again in SFM_RDWR mode and write more audio data to it. */ + file = test_open_file_or_die (filename, SFM_RDWR, &sfinfo, SF_TRUE, __LINE__) ; + /* Write more data to file. */ + test_write_short_or_die (file, 0, data_out, BUFFER_LEN, __LINE__) ; + sf_close (file) ; + + + /* Now open file again. It should now contain two BUFFER_LEN's worth of frames and the strings. */ + frames = 2 * BUFFER_LEN / sfinfo.channels ; + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + exit_if_true (frames != sfinfo.frames, "\n\nLine %d : Frame count %" PRId64 " should be %" PRId64 ".\n", __LINE__, sfinfo.frames, frames) ; + + /* Check the strings */ + str = sf_get_string (file, SF_STR_TITLE) ; + exit_if_true (str == NULL, "\n\nLine %d : SF_STR_TITLE string is NULL.\n", __LINE__) ; + exit_if_true (strcmp (str, title) != 0, "\n\nLine %d : SF_STR_TITLE doesn't match what was written.\n", __LINE__) ; + + str = sf_get_string (file, SF_STR_COMMENT) ; + exit_if_true (str == NULL, "\n\nLine %d : SF_STR_COMMENT string is NULL.\n", __LINE__) ; + exit_if_true (strcmp (str, comment) != 0, "\n\nLine %d : SF_STR_COMMENT doesn't match what was written.\n", __LINE__) ; + + sf_close (file) ; + unlink (filename) ; + + puts ("ok") ; +} /* string_rdwr_grow_test */ + +static void +string_header_update (const char *filename, int typemajor) +{ SNDFILE *file , *file1 ; + SF_INFO sfinfo , sfinfo1 ; + sf_count_t frames ; + const char * str ; + const int GROW_BUFFER_AMOUNT = 4 ; /* this should be less than half the size of the string header */ + + get_unique_test_name (&filename, STR_TEST_PREFIX) ; + print_test_name (__func__, filename) ; + + /* Create a short file. */ + memset (&sfinfo, 0, sizeof (sfinfo)) ; + sfinfo.samplerate = 44100 ; + sfinfo.channels = 2 ; + sfinfo.frames = 0 ; + sfinfo.format = typemajor | SF_FORMAT_PCM_16 ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ; + test_write_short_or_die (file, 0, data_out, BUFFER_LEN, __LINE__) ; + sf_set_string (file, SF_STR_TITLE, long_title) ; + sf_close (file) ; + + + /* Check that SFC_UPDATE_HEADER_NOW correctly calculates datalength. */ + file = test_open_file_or_die (filename, SFM_RDWR, &sfinfo, SF_TRUE, __LINE__) ; + /* Write a very small amount of new audio data that doesn't completely overwrite the existing header. */ + test_write_short_or_die (file, 0, data_out, GROW_BUFFER_AMOUNT, __LINE__) ; + + /* Update the header without closing the file. */ + sf_command (file, SFC_UPDATE_HEADER_NOW, NULL, 0) ; + + /* The file should now contain BUFFER_LEN + GROW_BUFFER_AMOUNT frames. + Open a second handle to the file and check the reported length. */ + memset (&sfinfo1, 0, sizeof (sfinfo1)) ; + file1 = test_open_file_or_die (filename, SFM_READ, &sfinfo1, SF_TRUE, __LINE__) ; + + frames = (BUFFER_LEN + GROW_BUFFER_AMOUNT) / sfinfo.channels ; + exit_if_true (frames != sfinfo1.frames, "\n\nLine %d : Frame count %" PRId64 " should be %" PRId64 ".\n", __LINE__, sfinfo1.frames, frames) ; + + /* The strings are probably not readable by the second soundfile handle because write_tailer has not yet been called. + It's a design decision whether SFC_UPDATE_HEADER_NOW should write the tailer. I think it's fine that it doesn't. */ + + sf_close (file1) ; + sf_close (file) ; + + + /* Check that sf_close correctly calculates datalength. */ + file = test_open_file_or_die (filename, SFM_RDWR, &sfinfo, SF_TRUE, __LINE__) ; + /* Write a very small amount of new audio data that doesn't completely overwrite the existing header. */ + test_write_short_or_die (file, 0, data_out, GROW_BUFFER_AMOUNT, __LINE__) ; + sf_close (file) ; + + + /* Open file again and verify data and string. */ + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, SF_TRUE, __LINE__) ; + frames = (BUFFER_LEN + 2*GROW_BUFFER_AMOUNT) / sfinfo.channels ; + exit_if_true (frames != sfinfo.frames, "\n\nLine %d : Frame count %" PRId64 " should be %" PRId64 ".\n", __LINE__, sfinfo.frames, frames) ; + str = sf_get_string (file, SF_STR_TITLE) ; + exit_if_true (str == NULL, "\n\nLine %d : SF_STR_TITLE string is NULL.\n", __LINE__) ; + exit_if_true (strcmp (str, long_title) != 0, "\n\nLine %d : SF_STR_TITLE doesn't match what was written.\n", __LINE__) ; + sf_close (file) ; + unlink (filename) ; + puts ("ok") ; +} /* string_header_update */ diff --git a/extern/libsndfile-modified/tests/test_wrapper.sh.in b/extern/libsndfile-modified/tests/test_wrapper.sh.in new file mode 100644 index 000000000..ab92f7c44 --- /dev/null +++ b/extern/libsndfile-modified/tests/test_wrapper.sh.in @@ -0,0 +1,380 @@ +#!/usr/bin/env sh + +# Copyright (C) 2008-2017 Erik de Castro Lopo +# +# All rights reserved. +# +# 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 author nor the names of any 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 COPYRIGHT OWNER 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. + + +HOST_TRIPLET=@HOST_TRIPLET@ +PACKAGE_VERSION=@PACKAGE_VERSION@ +LIB_VERSION=$(echo $PACKAGE_VERSION | sed "s/[a-z].*//") +ABS_TOP_SRCDIR=@abs_top_srcdir@ +PYTHON=@PYTHON@ + +sfversion=$(./tests/sfversion@EXEEXT@ | grep libsndfile | sed "s/-exp$//") + +if test "$sfversion" != libsndfile-$PACKAGE_VERSION ; then + echo "Error : sfversion ($sfversion) and PACKAGE_VERSION ($PACKAGE_VERSION) don't match." + exit 1 + fi + +# Force exit on errors. +set -e + +# Check the header file. +/usr/bin/env sh tests/pedantic-header-test.sh + +# Need this for when we're running from files collected into the +# libsndfile-testsuite-@PACKAGE_VERSION@ tarball. +echo "Running unit tests from src/ directory of source code tree." +./src/test_main@EXEEXT@ + +echo +echo "Running end-to-end tests from tests/ directory." + +./tests/error_test@EXEEXT@ +./tests/pcm_test@EXEEXT@ +./tests/ulaw_test@EXEEXT@ +./tests/alaw_test@EXEEXT@ +./tests/dwvw_test@EXEEXT@ +./tests/command_test@EXEEXT@ ver +./tests/command_test@EXEEXT@ norm +./tests/command_test@EXEEXT@ format +./tests/command_test@EXEEXT@ peak +./tests/command_test@EXEEXT@ trunc +./tests/command_test@EXEEXT@ inst +./tests/command_test@EXEEXT@ cue +./tests/command_test@EXEEXT@ current_sf_info +./tests/command_test@EXEEXT@ bext +./tests/command_test@EXEEXT@ bextch +./tests/command_test@EXEEXT@ chanmap +./tests/command_test@EXEEXT@ cart +./tests/floating_point_test@EXEEXT@ +./tests/checksum_test@EXEEXT@ +./tests/scale_clip_test@EXEEXT@ +./tests/headerless_test@EXEEXT@ +./tests/rdwr_test@EXEEXT@ +./tests/locale_test@EXEEXT@ +./tests/win32_ordinal_test@EXEEXT@ +./tests/external_libs_test@EXEEXT@ +./tests/format_check_test@EXEEXT@ +./tests/channel_test@EXEEXT@ + +# The w64 G++ compiler requires an extra runtime DLL which we don't have, +# so skip this test. +case "$HOST_TRIPLET" in + x86_64-w64-mingw32) + ;; + i686-w64-mingw32) + ;; + *) + ./tests/cpp_test@EXEEXT@ + ;; + esac + +echo "----------------------------------------------------------------------" +echo " $sfversion passed common tests." +echo "----------------------------------------------------------------------" + +# aiff-tests +./tests/write_read_test@EXEEXT@ aiff +./tests/lossy_comp_test@EXEEXT@ aiff_ulaw +./tests/lossy_comp_test@EXEEXT@ aiff_alaw +./tests/lossy_comp_test@EXEEXT@ aiff_gsm610 +echo "----------------------------------------------------------------------" +echo " lossy_comp_test@EXEEXT@ aiff_ima" +echo "----------------------------------------------------------------------" + +./tests/peak_chunk_test@EXEEXT@ aiff +./tests/header_test@EXEEXT@ aiff +./tests/misc_test@EXEEXT@ aiff +./tests/string_test@EXEEXT@ aiff +./tests/multi_file_test@EXEEXT@ aiff +./tests/aiff_rw_test@EXEEXT@ +./tests/chunk_test@EXEEXT@ aiff +echo "----------------------------------------------------------------------" +echo " $sfversion passed tests on AIFF files." +echo "----------------------------------------------------------------------" + +# au-tests +./tests/write_read_test@EXEEXT@ au +./tests/lossy_comp_test@EXEEXT@ au_ulaw +./tests/lossy_comp_test@EXEEXT@ au_alaw +./tests/lossy_comp_test@EXEEXT@ au_g721 +./tests/lossy_comp_test@EXEEXT@ au_g723 +./tests/header_test@EXEEXT@ au +./tests/misc_test@EXEEXT@ au +./tests/multi_file_test@EXEEXT@ au +echo "----------------------------------------------------------------------" +echo " $sfversion passed tests on AU files." +echo "----------------------------------------------------------------------" + +# caf-tests +./tests/write_read_test@EXEEXT@ caf +./tests/lossy_comp_test@EXEEXT@ caf_ulaw +./tests/lossy_comp_test@EXEEXT@ caf_alaw +./tests/header_test@EXEEXT@ caf +./tests/peak_chunk_test@EXEEXT@ caf +./tests/misc_test@EXEEXT@ caf +./tests/chunk_test@EXEEXT@ caf +./tests/string_test@EXEEXT@ caf +./tests/long_read_write_test@EXEEXT@ alac +echo "----------------------------------------------------------------------" +echo " $sfversion passed tests on CAF files." +echo "----------------------------------------------------------------------" + +# wav-tests +./tests/write_read_test@EXEEXT@ wav +./tests/lossy_comp_test@EXEEXT@ wav_pcm +./tests/lossy_comp_test@EXEEXT@ wav_ima +./tests/lossy_comp_test@EXEEXT@ wav_msadpcm +./tests/lossy_comp_test@EXEEXT@ wav_ulaw +./tests/lossy_comp_test@EXEEXT@ wav_alaw +./tests/lossy_comp_test@EXEEXT@ wav_gsm610 +./tests/lossy_comp_test@EXEEXT@ wav_g721 +./tests/peak_chunk_test@EXEEXT@ wav +./tests/header_test@EXEEXT@ wav +./tests/misc_test@EXEEXT@ wav +./tests/string_test@EXEEXT@ wav +./tests/multi_file_test@EXEEXT@ wav +./tests/chunk_test@EXEEXT@ wav +echo "----------------------------------------------------------------------" +echo " $sfversion passed tests on WAV files." +echo "----------------------------------------------------------------------" + +# w64-tests +./tests/write_read_test@EXEEXT@ w64 +./tests/lossy_comp_test@EXEEXT@ w64_ima +./tests/lossy_comp_test@EXEEXT@ w64_msadpcm +./tests/lossy_comp_test@EXEEXT@ w64_ulaw +./tests/lossy_comp_test@EXEEXT@ w64_alaw +./tests/lossy_comp_test@EXEEXT@ w64_gsm610 +./tests/header_test@EXEEXT@ w64 +./tests/misc_test@EXEEXT@ w64 +echo "----------------------------------------------------------------------" +echo " $sfversion passed tests on W64 files." +echo "----------------------------------------------------------------------" + +# rf64-tests +./tests/write_read_test@EXEEXT@ rf64 +./tests/header_test@EXEEXT@ rf64 +./tests/misc_test@EXEEXT@ rf64 +./tests/string_test@EXEEXT@ rf64 +./tests/peak_chunk_test@EXEEXT@ rf64 +./tests/chunk_test@EXEEXT@ rf64 +echo "----------------------------------------------------------------------" +echo " $sfversion passed tests on RF64 files." +echo "----------------------------------------------------------------------" + +# raw-tests +./tests/write_read_test@EXEEXT@ raw +./tests/lossy_comp_test@EXEEXT@ raw_ulaw +./tests/lossy_comp_test@EXEEXT@ raw_alaw +./tests/lossy_comp_test@EXEEXT@ raw_gsm610 +./tests/lossy_comp_test@EXEEXT@ vox_adpcm +./tests/raw_test@EXEEXT@ +echo "----------------------------------------------------------------------" +echo " $sfversion passed tests on RAW (header-less) files." +echo "----------------------------------------------------------------------" + +# paf-tests +./tests/write_read_test@EXEEXT@ paf +./tests/header_test@EXEEXT@ paf +./tests/misc_test@EXEEXT@ paf +echo "----------------------------------------------------------------------" +echo " $sfversion passed tests on PAF files." +echo "----------------------------------------------------------------------" + +# svx-tests +./tests/write_read_test@EXEEXT@ svx +./tests/header_test@EXEEXT@ svx +./tests/misc_test@EXEEXT@ svx +echo "----------------------------------------------------------------------" +echo " $sfversion passed tests on SVX files." +echo "----------------------------------------------------------------------" + +# nist-tests +./tests/write_read_test@EXEEXT@ nist +./tests/lossy_comp_test@EXEEXT@ nist_ulaw +./tests/lossy_comp_test@EXEEXT@ nist_alaw +./tests/header_test@EXEEXT@ nist +./tests/misc_test@EXEEXT@ nist +echo "----------------------------------------------------------------------" +echo " $sfversion passed tests on NIST files." +echo "----------------------------------------------------------------------" + +# ircam-tests +./tests/write_read_test@EXEEXT@ ircam +./tests/lossy_comp_test@EXEEXT@ ircam_ulaw +./tests/lossy_comp_test@EXEEXT@ ircam_alaw +./tests/header_test@EXEEXT@ ircam +./tests/misc_test@EXEEXT@ ircam +echo "----------------------------------------------------------------------" +echo " $sfversion passed tests on IRCAM files." +echo "----------------------------------------------------------------------" + +# voc-tests +./tests/write_read_test@EXEEXT@ voc +./tests/lossy_comp_test@EXEEXT@ voc_ulaw +./tests/lossy_comp_test@EXEEXT@ voc_alaw +./tests/header_test@EXEEXT@ voc +./tests/misc_test@EXEEXT@ voc +echo "----------------------------------------------------------------------" +echo " $sfversion passed tests on VOC files." +echo "----------------------------------------------------------------------" + +# mat4-tests +./tests/write_read_test@EXEEXT@ mat4 +./tests/header_test@EXEEXT@ mat4 +./tests/misc_test@EXEEXT@ mat4 +echo "----------------------------------------------------------------------" +echo " $sfversion passed tests on MAT4 files." +echo "----------------------------------------------------------------------" + +# mat5-tests +./tests/write_read_test@EXEEXT@ mat5 +./tests/header_test@EXEEXT@ mat5 +./tests/misc_test@EXEEXT@ mat5 +echo "----------------------------------------------------------------------" +echo " $sfversion passed tests on MAT5 files." +echo "----------------------------------------------------------------------" + +# pvf-tests +./tests/write_read_test@EXEEXT@ pvf +./tests/header_test@EXEEXT@ pvf +./tests/misc_test@EXEEXT@ pvf +echo "----------------------------------------------------------------------" +echo " $sfversion passed tests on PVF files." +echo "----------------------------------------------------------------------" + +# xi-tests +./tests/lossy_comp_test@EXEEXT@ xi_dpcm +echo "----------------------------------------------------------------------" +echo " $sfversion passed tests on XI files." +echo "----------------------------------------------------------------------" + +# htk-tests +./tests/write_read_test@EXEEXT@ htk +./tests/header_test@EXEEXT@ htk +./tests/misc_test@EXEEXT@ htk +echo "----------------------------------------------------------------------" +echo " $sfversion passed tests on HTK files." +echo "----------------------------------------------------------------------" + +# avr-tests +./tests/write_read_test@EXEEXT@ avr +./tests/header_test@EXEEXT@ avr +./tests/misc_test@EXEEXT@ avr +echo "----------------------------------------------------------------------" +echo " $sfversion passed tests on AVR files." +echo "----------------------------------------------------------------------" + +# sds-tests +./tests/write_read_test@EXEEXT@ sds +./tests/header_test@EXEEXT@ sds +./tests/misc_test@EXEEXT@ sds +echo "----------------------------------------------------------------------" +echo " $sfversion passed tests on SDS files." +echo "----------------------------------------------------------------------" + +# sd2-tests +./tests/write_read_test@EXEEXT@ sd2 +echo "----------------------------------------------------------------------" +echo " $sfversion passed tests on SD2 files." +echo "----------------------------------------------------------------------" + +# wve-tests +./tests/lossy_comp_test@EXEEXT@ wve +echo "----------------------------------------------------------------------" +echo " $sfversion passed tests on WVE files." +echo "----------------------------------------------------------------------" + +# mpc2k-tests +./tests/write_read_test@EXEEXT@ mpc2k +./tests/header_test@EXEEXT@ mpc2k +./tests/misc_test@EXEEXT@ mpc2k +echo "----------------------------------------------------------------------" +echo " $sfversion passed tests on MPC 2000 files." +echo "----------------------------------------------------------------------" + +# flac-tests +./tests/write_read_test@EXEEXT@ flac +./tests/compression_size_test@EXEEXT@ flac +./tests/string_test@EXEEXT@ flac +./tests/header_test@EXEEXT@ flac +echo "----------------------------------------------------------------------" +echo " $sfversion passed tests on FLAC files." +echo "----------------------------------------------------------------------" + +# vorbis-tests +./tests/ogg_test@EXEEXT@ +./tests/compression_size_test@EXEEXT@ vorbis +./tests/lossy_comp_test@EXEEXT@ ogg_vorbis +./tests/string_test@EXEEXT@ ogg +./tests/misc_test@EXEEXT@ ogg +echo "----------------------------------------------------------------------" +echo " $sfversion passed tests on OGG/VORBIS files." +echo "----------------------------------------------------------------------" + +# opus-tests +./tests/ogg_opus_test@EXEEXT@ +./tests/compression_size_test@EXEEXT@ opus +./tests/lossy_comp_test@EXEEXT@ ogg_opus +./tests/string_test@EXEEXT@ opus + +echo "----------------------------------------------------------------------" +echo " $sfversion passed tests on OPUS files." +echo "----------------------------------------------------------------------" + +# mpeg-tests +./tests/mpeg_test@EXEEXT@ +./tests/compression_size_test@EXEEXT@ mpeg +./tests/string_test@EXEEXT@ mpeg + +echo "----------------------------------------------------------------------" +echo " $sfversion passed tests on MPEG files." +echo "----------------------------------------------------------------------" + +# io-tests +./tests/stdio_test@EXEEXT@ +./tests/pipe_test@EXEEXT@ +./tests/virtual_io_test@EXEEXT@ +echo "----------------------------------------------------------------------" +echo " $sfversion passed stdio/pipe/vio tests." +echo "----------------------------------------------------------------------" + +"${PYTHON}" "${ABS_TOP_SRCDIR}/src/binheader_writef_check.py" "${ABS_TOP_SRCDIR}/src"/*.c +echo "----------------------------------------------------------------------" +echo " $sfversion passed binary header tests." +echo "----------------------------------------------------------------------" + +"${PYTHON}" "${ABS_TOP_SRCDIR}/programs/test-sndfile-metadata-set.py" "${HOST_TRIPLET}" +echo "----------------------------------------------------------------------" +echo " $sfversion passed sndfile metadata tests." +echo "----------------------------------------------------------------------" diff --git a/extern/libsndfile-modified/tests/ulaw_test.c b/extern/libsndfile-modified/tests/ulaw_test.c new file mode 100644 index 000000000..cf2084bd4 --- /dev/null +++ b/extern/libsndfile-modified/tests/ulaw_test.c @@ -0,0 +1,259 @@ +/* +** Copyright (C) 1999-2012 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include + +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include + +#include "utils.h" + +#define BUFFER_SIZE (65536) + +static unsigned char ulaw_encode (int sample) ; +static int ulaw_decode (unsigned int ulawbyte) ; + +static short short_buffer [BUFFER_SIZE] ; +static unsigned char ulaw_buffer [BUFFER_SIZE] ; + +int +main (void) +{ SNDFILE *file ; + SF_INFO sfinfo ; + const char *filename ; + int k ; + + print_test_name ("ulaw_test", "encoder") ; + + filename = "ulaw_test.raw" ; + + sf_info_setup (&sfinfo, SF_FORMAT_RAW | SF_FORMAT_ULAW, 44100, 1) ; + + if ((file = sf_open (filename, SFM_WRITE, &sfinfo)) == NULL) + { printf ("sf_open_write failed with error : ") ; + fflush (stdout) ; + puts (sf_strerror (NULL)) ; + exit (1) ; + } ; + + /* Generate a file containing all possible 16 bit sample values + ** and write it to disk as ulaw encoded.frames. + */ + + for (k = 0 ; k < 0x10000 ; k++) + short_buffer [k] = k & 0xFFFF ; + + sf_write_short (file, short_buffer, BUFFER_SIZE) ; + sf_close (file) ; + + /* Now open that file and compare the ulaw encoded sample values + ** with what they should be. + */ + + if ((file = sf_open (filename, SFM_READ, &sfinfo)) == NULL) + { printf ("sf_open_write failed with error : ") ; + puts (sf_strerror (NULL)) ; + exit (1) ; + } ; + + check_log_buffer_or_die (file, __LINE__) ; + + if (sf_read_raw (file, ulaw_buffer, BUFFER_SIZE) != BUFFER_SIZE) + { printf ("sf_read_raw : ") ; + puts (sf_strerror (file)) ; + exit (1) ; + } ; + + for (k = 0 ; k < 0x10000 ; k++) + if (ulaw_encode (short_buffer [k]) != ulaw_buffer [k]) + { printf ("Encoder error : sample #%d (0x%02X should be 0x%02X)\n", k, ulaw_buffer [k], ulaw_encode (short_buffer [k])) ; + exit (1) ; + } ; + + sf_close (file) ; + + puts ("ok") ; + + print_test_name ("ulaw_test", "decoder") ; + + /* Now generate a file containing all possible 8 bit encoded + ** sample values and write it to disk as ulaw encoded.frames. + */ + + if (! (file = sf_open (filename, SFM_WRITE, &sfinfo))) + { printf ("sf_open_write failed with error : ") ; + puts (sf_strerror (NULL)) ; + exit (1) ; + } ; + + for (k = 0 ; k < 256 ; k++) + ulaw_buffer [k] = k & 0xFF ; + + sf_write_raw (file, ulaw_buffer, 256) ; + sf_close (file) ; + + /* Now open that file and compare the ulaw decoded sample values + ** with what they should be. + */ + + if (! (file = sf_open (filename, SFM_READ, &sfinfo))) + { printf ("sf_open_write failed with error : ") ; + puts (sf_strerror (NULL)) ; + exit (1) ; + } ; + + check_log_buffer_or_die (file, __LINE__) ; + + if (sf_read_short (file, short_buffer, 256) != 256) + { printf ("sf_read_short : ") ; + puts (sf_strerror (file)) ; + exit (1) ; + } ; + + + for (k = 0 ; k < 256 ; k++) + if (short_buffer [k] != ulaw_decode (ulaw_buffer [k])) + { printf ("Decoder error : sample #%d (0x%04X should be 0x%04X)\n", k, short_buffer [k], ulaw_decode (ulaw_buffer [k])) ; + exit (1) ; + } ; + + sf_close (file) ; + + puts ("ok") ; + + unlink (filename) ; + + return 0 ; +} /* main */ + + +/*================================================================================= +** The following routines came from the sox-12.15 (Sound eXcahcnge) distribution. +** +** This code is not compiled into libsndfile. It is only used to test the +** libsndfile lookup tables for correctness. +** +** I have included the original authors comments. +*/ + +/* +** This routine converts from linear to ulaw. +** +** Craig Reese: IDA/Supercomputing Research Center +** Joe Campbell: Department of Defense +** 29 September 1989 +** +** References: +** 1) CCITT Recommendation G.711 (very difficult to follow) +** 2) "A New Digital Technique for Implementation of Any +** Continuous PCM Companding Law," Villeret, Michel, +** et al. 1973 IEEE Int. Conf. on Communications, Vol 1, +** 1973, pg. 11.12-11.17 +** 3) MIL-STD-188-113,"Interoperability and Performance Standards +** for Analog-to_Digital Conversion Techniques," +** 17 February 1987 +** +** Input: Signed 16 bit linear sample +** Output: 8 bit ulaw sample +*/ + +#define uBIAS 0x84 /* define the add-in bias for 16 bit.frames */ +#define uCLIP 32635 + +static +unsigned char ulaw_encode (int sample) +{ static int exp_lut [256] = + { 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + } ; + + int sign, exponent, mantissa ; + unsigned char ulawbyte ; + + /* Get the sample into sign-magnitude. */ + sign = (sample >> 8) & 0x80 ; /* set aside the sign */ + if (sign != 0) + sample = -sample ; /* get magnitude */ + if (sample > uCLIP) + sample = uCLIP ; /* clip the magnitude */ + + /* Convert from 16 bit linear to ulaw. */ + sample = sample + uBIAS ; + exponent = exp_lut [(sample >> 7) & 0xFF] ; + mantissa = (sample >> (exponent + 3)) & 0x0F ; + ulawbyte = ~ (sign | (exponent << 4) | mantissa) ; + + return ulawbyte ; +} /* ulaw_encode */ + + +/* +** This routine converts from ulaw to 16 bit linear. +** +** Craig Reese: IDA/Supercomputing Research Center +** 29 September 1989 +** +** References: +** 1) CCITT Recommendation G.711 (very difficult to follow) +** 2) MIL-STD-188-113,"Interoperability and Performance Standards +** for Analog-to_Digital Conversion Techniques," +** 17 February 1987 +** +** Input: 8 bit ulaw sample +** Output: signed 16 bit linear sample +*/ + +static +int ulaw_decode (unsigned int ulawbyte) +{ static int exp_lut [8] = { 0, 132, 396, 924, 1980, 4092, 8316, 16764 } ; + int sign, exponent, mantissa, sample ; + + ulawbyte = ~ ulawbyte ; + sign = (ulawbyte & 0x80) ; + exponent = (ulawbyte >> 4) & 0x07 ; + mantissa = ulawbyte & 0x0F ; + sample = exp_lut [exponent] + (mantissa << (exponent + 3)) ; + if (sign != 0) + sample = -sample ; + + return sample ; +} /* ulaw_decode */ + diff --git a/extern/libsndfile-modified/tests/utils.def b/extern/libsndfile-modified/tests/utils.def new file mode 100644 index 000000000..0d94183d2 --- /dev/null +++ b/extern/libsndfile-modified/tests/utils.def @@ -0,0 +1,52 @@ +autogen definitions utils.tpl; + +float_type = { + name = float ; + }; + +float_type = { + name = double ; + }; + +/*----------------------------------*/ + +io_type = { + io_element = short ; + format_str = "\"% d\"" ; + }; + +io_type = { + io_element = int ; + format_str = "\"% d\"" ; + }; + +io_type = { + io_element = float ; + format_str = "\"% g\"" ; + }; + +io_type = { + io_element = double ; + format_str = "\"% g\"" ; + }; + +read_op = { + op_element = read ; + count_name = items ; + }; + +read_op = { + op_element = readf ; + count_name = frames ; + }; + +write_op = { + op_element = write ; + count_name = items ; + }; + +write_op = { + op_element = writef ; + count_name = frames ; + }; + diff --git a/extern/libsndfile-modified/tests/utils.tpl b/extern/libsndfile-modified/tests/utils.tpl new file mode 100644 index 000000000..0d1cd8bb9 --- /dev/null +++ b/extern/libsndfile-modified/tests/utils.tpl @@ -0,0 +1,961 @@ +[+ AutoGen5 template h c +] +/* +** Copyright (C) 2002-2018 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/* +** Utility functions to make writing the test suite easier. +** +** The .c and .h files were generated automagically with Autogen from +** the files utils.def and utils.tpl. +*/ + +[+ CASE (suffix) +] +[+ == h +] + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "sfconfig.h" + +#include +#include + +#define ARRAY_LEN(x) ((int) (sizeof (x)) / (sizeof ((x) [0]))) +#define SIGNED_SIZEOF(x) ((int64_t) (sizeof (x))) +#define NOT(x) (! (x)) +#define ABS(x) ((x) >= 0 ? (x) : - (x)) + +#define PIPE_INDEX(x) ((x) + 500) +#define PIPE_TEST_LEN 12345 + + +[+ FOR float_type ++]void gen_windowed_sine_[+ (get "name") +] ([+ (get "name") +] *data, int len, double maximum) ; +[+ ENDFOR float_type ++] + +void create_short_sndfile (const char *filename, int format, int channels) ; + +void check_file_hash_or_die (const char *filename, uint64_t target_hash, int line_num) ; + +void print_test_name (const char *test, const char *filename) ; + +void dump_data_to_file (const char *filename, const void *data, unsigned int datalen) ; + +void write_mono_file (const char * filename, int format, int srate, float * output, int len) ; + +#ifdef __GNUC__ +static inline void +exit_if_true (int test, const char *format, ...) +#if (defined (__USE_MINGW_ANSI_STDIO) && __USE_MINGW_ANSI_STDIO && !defined (__clang__)) + __attribute__ ((format (gnu_printf, 2, 3))) ; +#else + __attribute__ ((format (printf, 2, 3))) ; +#endif +#endif + +static inline void +exit_if_true (int test, const char *format, ...) +{ if (test) + { va_list argptr ; + va_start (argptr, format) ; + vprintf (format, argptr) ; + va_end (argptr) ; + exit (1) ; + } ; +} /* exit_if_true */ + +static inline int32_t +arith_shift_left (int32_t x, int shift) +{ return (int32_t) (((uint32_t) x) << shift) ; +} /* arith_shift_left */ + +/* +** Functions for saving two vectors of data in an ascii text file which +** can then be loaded into GNU octave for comparison. +*/ + +[+ FOR io_type ++]int oct_save_[+ (get "io_element") +] (const [+ (get "io_element") +] *a, const [+ (get "io_element") +] *b, int len) ; +[+ ENDFOR io_type ++] + +void delete_file (int format, const char *filename) ; + +int truncate_file_to_zero (const char *fname) ; + +void count_open_files (void) ; +void increment_open_file_count (void) ; +void check_open_file_count_or_die (int lineno) ; + +void get_unique_test_name (const char ** filename, const char * test) ; + +#ifdef SNDFILE_H + +static inline void +sf_info_clear (SF_INFO * info) +{ memset (info, 0, sizeof (SF_INFO)) ; +} /* sf_info_clear */ + +static inline void +sf_info_setup (SF_INFO * info, int format, int samplerate, int channels) +{ sf_info_clear (info) ; + + info->format = format ; + info->samplerate = samplerate ; + info->channels = channels ; +} /* sf_info_setup */ + + +void dump_log_buffer (SNDFILE *file) ; +void check_log_buffer_or_die (SNDFILE *file, int line_num) ; +int string_in_log_buffer (SNDFILE *file, const char *s) ; +void hexdump_file (const char * filename, sf_count_t offset, sf_count_t length) ; + +void test_sf_format_or_die (const SF_INFO *info, int line_num) ; + +SNDFILE *test_open_file_or_die + (const char *filename, int mode, SF_INFO *sfinfo, int allow_fd, int line_num) ; + +void test_read_write_position_or_die + (SNDFILE *file, int line_num, int pass, sf_count_t read_pos, sf_count_t write_pos) ; + +void test_seek_or_die + (SNDFILE *file, sf_count_t offset, int whence, sf_count_t new_pos, int channels, int line_num) ; + +[+ FOR read_op +] +[+ FOR io_type ++]void test_[+ (get "op_element") +]_[+ (get "io_element") +]_or_die + (SNDFILE *file, int pass, [+ (get "io_element") +] *test, sf_count_t [+ (get "count_name") +], int line_num) ; +[+ ENDFOR io_type +][+ ENDFOR read_op +] + +void +test_read_raw_or_die (SNDFILE *file, int pass, void *test, sf_count_t items, int line_num) ; + +[+ FOR write_op +] +[+ FOR io_type ++]void test_[+ (get "op_element") +]_[+ (get "io_element") +]_or_die + (SNDFILE *file, int pass, const [+ (get "io_element") +] *test, sf_count_t [+ (get "count_name") +], int line_num) ; +[+ ENDFOR io_type +][+ ENDFOR write_op +] + +void +test_write_raw_or_die (SNDFILE *file, int pass, const void *test, sf_count_t items, int line_num) ; + +[+ FOR io_type ++]void compare_[+ (get "io_element") +]_or_die (const [+ (get "io_element") +] *expected, const [+ (get "io_element") +] *actual, unsigned count, int line_num) ; +[+ ENDFOR io_type +] + + +void gen_lowpass_signal_float (float *data, int len) ; + +sf_count_t file_length (const char * fname) ; +sf_count_t file_length_fd (int fd) ; + +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +[+ == c +] + +#include "sfconfig.h" + +#include +#include +#include + +#if HAVE_UNISTD_H +#include +#endif + +#if (HAVE_DECL_S_IRGRP == 0) +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "utils.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846264338 +#endif + +#define LOG_BUFFER_SIZE 4096 + +/* +** Neat solution to the Win32/OS2 binary file flage requirement. +** If O_BINARY isn't already defined by the inclusion of the system +** headers, set it to zero. +*/ +#ifndef O_BINARY +#define O_BINARY 0 +#endif + + +/* +** Compare for equality, with epsilon +*/ +static inline int +equals_short (const short a, const short b) +{ return (a == b); +} /* equals_short */ +static inline int +equals_int (const int a, const int b) +{ return (a == b); +} /* equals_int */ +static inline int +equals_float (const float a, const float b) +{ return (fabsf(a - b) <= FLT_EPSILON); +} /* equals_float */ +static inline int +equals_double (const double a, const double b) +{ return (fabs(a - b) <= DBL_EPSILON); +} /* equals_double */ + + +[+ FOR float_type +] +void +gen_windowed_sine_[+ (get "name") +] ([+ (get "name") +] *data, int len, double maximum) +{ int k ; + + memset (data, 0, len * sizeof ([+ (get "name") +])) ; + + len = (5 * len) / 6 ; + + for (k = 0 ; k < len ; k++) + { data [k] = sin (2.0 * k * M_PI * 1.0 / 32.0 + 0.4) ; + + /* Apply Hanning Window. */ + data [k] *= maximum * (0.5 - 0.5 * cos (2.0 * M_PI * k / ((len) - 1))) ; + } + + return ; +} /* gen_windowed_sine_[+ (get "name") +] */ +[+ ENDFOR float_type +] + +void +create_short_sndfile (const char *filename, int format, int channels) +{ short data [2 * 3 * 4 * 5 * 6 * 7] = { 0, } ; + SNDFILE *file ; + SF_INFO sfinfo ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + sfinfo.samplerate = 44100 ; + sfinfo.channels = channels ; + sfinfo.format = format ; + + if ((file = sf_open (filename, SFM_WRITE, &sfinfo)) == NULL) + { printf ("Error (%s, %d) : sf_open failed : %s\n", __FILE__, __LINE__, sf_strerror (file)) ; + exit (1) ; + } ; + + sf_write_short (file, data, ARRAY_LEN (data)) ; + + sf_close (file) ; +} /* create_short_sndfile */ + +void +check_file_hash_or_die (const char *filename, uint64_t target_hash, int line_num) +{ static unsigned char buf [4096] ; + uint64_t cksum ; + FILE *file ; + int k, read_count ; + + memset (buf, 0, sizeof (buf)) ; + + /* The 'b' in the mode string means binary for Win32. */ + if ((file = fopen (filename, "rb")) == NULL) + { printf ("\n\nLine %d: could not open file '%s'\n\n", line_num, filename) ; + exit (1) ; + } ; + + cksum = 0 ; + + while ((read_count = fread (buf, 1, sizeof (buf), file))) + for (k = 0 ; k < read_count ; k++) + cksum = (cksum * 511 + buf [k]) & 0xfffffffffffff ; + + fclose (file) ; + + if (target_hash == 0) + { printf (" 0x%" PRIx64 "\n", cksum) ; + return ; + } ; + + if (cksum != target_hash) + { printf ("\n\nLine %d: incorrect hash value 0x%" PRIx64 " should be 0x%" PRIx64 ".\n\n", line_num, cksum, target_hash) ; + exit (1) ; + } ; + + return ; +} /* check_file_hash_or_die */ + +void +print_test_name (const char *test, const char *filename) +{ int count ; + + if (test == NULL) + { printf (__FILE__ ": bad test of filename parameter.\n") ; + exit (1) ; + } ; + + if (filename == NULL || strlen (filename) == 0) + { printf (" %-30s : ", test) ; + count = 25 ; + } + else + { printf (" %-30s : %s ", test, filename) ; + count = 24 - strlen (filename) ; + } ; + + while (count -- > 0) + putchar ('.') ; + putchar (' ') ; + + fflush (stdout) ; +} /* print_test_name */ + +void +dump_data_to_file (const char *filename, const void *data, unsigned int datalen) +{ FILE *file ; + + if ((file = fopen (filename, "wb")) == NULL) + { printf ("\n\nLine %d : could not open file : %s\n\n", __LINE__, filename) ; + exit (1) ; + } ; + + if (fwrite (data, 1, datalen, file) != datalen) + { printf ("\n\nLine %d : fwrite failed.\n\n", __LINE__) ; + exit (1) ; + } ; + + fclose (file) ; + +} /* dump_data_to_file */ + +/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +*/ + +static char octfilename [] = "error.dat" ; + +[+ FOR io_type ++]int +oct_save_[+ (get "io_element") +] (const [+ (get "io_element") +] *a, const [+ (get "io_element") +] *b, int len) +{ FILE *file ; + int k ; + + if (! (file = fopen (octfilename, "w"))) + return 1 ; + + fprintf (file, "# Not created by Octave\n") ; + + fprintf (file, "# name: a\n") ; + fprintf (file, "# type: matrix\n") ; + fprintf (file, "# rows: %d\n", len) ; + fprintf (file, "# columns: 1\n") ; + + for (k = 0 ; k < len ; k++) + fprintf (file, [+ (get "format_str") +] "\n", a [k]) ; + + fprintf (file, "# name: b\n") ; + fprintf (file, "# type: matrix\n") ; + fprintf (file, "# rows: %d\n", len) ; + fprintf (file, "# columns: 1\n") ; + + for (k = 0 ; k < len ; k++) + fprintf (file, [+ (get "format_str") +] "\n", b [k]) ; + + fclose (file) ; + return 0 ; +} /* oct_save_[+ (get "io_element") +] */ +[+ ENDFOR io_type ++] + +void +check_log_buffer_or_die (SNDFILE *file, int line_num) +{ static char buffer [LOG_BUFFER_SIZE] ; + int count ; + + memset (buffer, 0, sizeof (buffer)) ; + + /* Get the log buffer data. */ + count = sf_command (file, SFC_GET_LOG_INFO, buffer, LOG_BUFFER_SIZE) ; + + if (LOG_BUFFER_SIZE - count < 2) + { printf ("\n\nLine %d : Possible long log buffer.\n", line_num) ; + exit (1) ; + } + + /* Look for "Should" */ + if (strstr (buffer, "ould")) + { printf ("\n\nLine %d : Log buffer contains `ould'. Dumping.\n", line_num) ; + puts (buffer) ; + exit (1) ; + } ; + + /* Look for "**" */ + if (strstr (buffer, "*")) + { printf ("\n\nLine %d : Log buffer contains `*'. Dumping.\n", line_num) ; + puts (buffer) ; + exit (1) ; + } ; + + /* Look for "Should" */ + if (strstr (buffer, "nknown marker")) + { printf ("\n\nLine %d : Log buffer contains `nknown marker'. Dumping.\n", line_num) ; + puts (buffer) ; + exit (1) ; + } ; + + return ; +} /* check_log_buffer_or_die */ + +int +string_in_log_buffer (SNDFILE *file, const char *s) +{ static char buffer [LOG_BUFFER_SIZE] ; + int count ; + + memset (buffer, 0, sizeof (buffer)) ; + + /* Get the log buffer data. */ + count = sf_command (file, SFC_GET_LOG_INFO, buffer, LOG_BUFFER_SIZE) ; + + if (LOG_BUFFER_SIZE - count < 2) + { printf ("Possible long log buffer.\n") ; + exit (1) ; + } + + /* Look for string */ + return strstr (buffer, s) ? SF_TRUE : SF_FALSE ; +} /* string_in_log_buffer */ + +void +hexdump_file (const char * filename, sf_count_t offset, sf_count_t length) +{ + FILE * file ; + char buffer [16] ; + int k, m, ch, readcount ; + + if (length > 1000000) + { printf ("\n\nError : length (%" PRId64 ") too long.\n\n", offset) ; + exit (1) ; + } ; + + if ((file = fopen (filename, "r")) == NULL) + { printf ("\n\nError : hexdump_file (%s) could not open file for read.\n\n", filename) ; + exit (1) ; + } ; + + if (fseek (file, offset, SEEK_SET) != 0) + { printf ("\n\nError : fseek(file, %" PRId64 ", SEEK_SET) failed : %s\n\n", offset, strerror (errno)) ; + exit (1) ; + } ; + + puts ("\n\n") ; + + for (k = 0 ; k < length ; k+= sizeof (buffer)) + { readcount = fread (buffer, 1, sizeof (buffer), file) ; + + printf ("%08" PRIx64 " : ", offset + k) ; + + for (m = 0 ; m < readcount ; m++) + printf ("%02x ", buffer [m] & 0xFF) ; + + for (m = readcount ; m < SIGNED_SIZEOF (buffer) ; m++) + printf (" ") ; + + printf (" ") ; + for (m = 0 ; m < readcount ; m++) + { ch = isprint (buffer [m]) ? buffer [m] : '.' ; + putchar (ch) ; + } ; + + if (readcount < SIGNED_SIZEOF (buffer)) + break ; + + putchar ('\n') ; + } ; + + puts ("\n") ; + + fclose (file) ; +} /* hexdump_file */ + +void +dump_log_buffer (SNDFILE *file) +{ static char buffer [LOG_BUFFER_SIZE] ; + + memset (buffer, 0, sizeof (buffer)) ; + + /* Get the log buffer data. */ + sf_command (file, SFC_GET_LOG_INFO, buffer, LOG_BUFFER_SIZE) ; + + if (strlen (buffer) < 1) + puts ("Log buffer empty.\n") ; + else + puts (buffer) ; + + return ; +} /* dump_log_buffer */ + +void +test_sf_format_or_die (const SF_INFO *info, int line_num) +{ int res ; + + if ((res = sf_format_check (info)) != 1) + { printf ("\n\nLine %d : sf_format_check returned error (%d)\n\n", line_num, res) ; + exit (1) ; + } ; + + return ; +} /* test_sf_format_or_die */ + +SNDFILE * +test_open_file_or_die (const char *filename, int mode, SF_INFO *sfinfo, int allow_fd, int line_num) +{ static int count = 0 ; + + SNDFILE *file ; + const char *modestr, *func_name ; + int oflags = 0, omode = 0, err ; + + /* + ** Need to test both sf_open() and sf_open_fd(). + ** Do so alternately. + */ + switch (mode) + { case SFM_READ : + modestr = "SFM_READ" ; + oflags = O_RDONLY | O_BINARY ; + omode = 0 ; + break ; + + case SFM_WRITE : + modestr = "SFM_WRITE" ; + oflags = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY ; + omode = S_IRUSR | S_IWUSR | S_IRGRP ; + break ; + + case SFM_RDWR : + modestr = "SFM_RDWR" ; + oflags = O_RDWR | O_CREAT | O_BINARY ; + omode = S_IRUSR | S_IWUSR | S_IRGRP ; + break ; + default : + printf ("\n\nLine %d: Bad mode.\n", line_num) ; + fflush (stdout) ; + exit (1) ; + } ; + + if (OS_IS_WIN32) + { /* Windows does not understand and ignores the S_IRGRP flag, but Wine + ** gives a run time warning message, so just clear it. + */ + omode &= ~S_IRGRP ; + } ; + + if (allow_fd && ((++count) & 1) == 1) + { int fd ; + + /* Only use the three argument open() function if omode != 0. */ + fd = (omode == 0) ? open (filename, oflags) : open (filename, oflags, omode) ; + + if (fd < 0) + { printf ("\n\n%s : open failed : %s\n", __func__, strerror (errno)) ; + exit (1) ; + } ; + + func_name = "sf_open_fd" ; + file = sf_open_fd (fd, mode, sfinfo, SF_TRUE) ; + } + else + { func_name = "sf_open" ; + file = sf_open (filename, mode, sfinfo) ; + } ; + + if (file == NULL) + { printf ("\n\nLine %d: %s (%s) failed : %s\n\n", line_num, func_name, modestr, sf_strerror (NULL)) ; + dump_log_buffer (file) ; + exit (1) ; + } ; + + err = sf_error (file) ; + if (err != SF_ERR_NO_ERROR) + { printf ("\n\nLine %d : sf_error : %s\n\n", line_num, sf_error_number (err)) ; + dump_log_buffer (file) ; + exit (1) ; + } ; + + return file ; +} /* test_open_file_or_die */ + +void +test_read_write_position_or_die (SNDFILE *file, int line_num, int pass, sf_count_t read_pos, sf_count_t write_pos) +{ sf_count_t pos ; + + /* Check the current read position. */ + if (read_pos >= 0 && (pos = sf_seek (file, 0, SEEK_CUR | SFM_READ)) != read_pos) + { printf ("\n\nLine %d ", line_num) ; + if (pass > 0) + printf ("(pass %d): ", pass) ; + printf ("Read position (%" PRId64 ") should be %" PRId64 ".\n", pos, read_pos) ; + exit (1) ; + } ; + + /* Check the current write position. */ + if (write_pos >= 0 && (pos = sf_seek (file, 0, SEEK_CUR | SFM_WRITE)) != write_pos) + { printf ("\n\nLine %d", line_num) ; + if (pass > 0) + printf (" (pass %d)", pass) ; + printf (" : Write position (%" PRId64 ") should be %" PRId64 ".\n", pos, write_pos) ; + exit (1) ; + } ; + + return ; +} /* test_read_write_position */ + +void +test_seek_or_die (SNDFILE *file, sf_count_t offset, int whence, sf_count_t new_pos, int channels, int line_num) +{ sf_count_t position ; + const char *channel_name, *whence_name ; + + switch (whence) + { case SEEK_SET : + whence_name = "SEEK_SET" ; + break ; + case SEEK_CUR : + whence_name = "SEEK_CUR" ; + break ; + case SEEK_END : + whence_name = "SEEK_END" ; + break ; + + /* SFM_READ */ + case SEEK_SET | SFM_READ : + whence_name = "SFM_READ | SEEK_SET" ; + break ; + case SEEK_CUR | SFM_READ : + whence_name = "SFM_READ | SEEK_CUR" ; + break ; + case SEEK_END | SFM_READ : + whence_name = "SFM_READ | SEEK_END" ; + break ; + + /* SFM_WRITE */ + case SEEK_SET | SFM_WRITE : + whence_name = "SFM_WRITE | SEEK_SET" ; + break ; + case SEEK_CUR | SFM_WRITE : + whence_name = "SFM_WRITE | SEEK_CUR" ; + break ; + case SEEK_END | SFM_WRITE : + whence_name = "SFM_WRITE | SEEK_END" ; + break ; + + default : + printf ("\n\nLine %d: bad whence parameter.\n", line_num) ; + exit (1) ; + } ; + + channel_name = (channels == 1) ? "Mono" : "Stereo" ; + + if ((position = sf_seek (file, offset, whence)) != new_pos) + { printf ("\n\nLine %d : %s : sf_seek (file, %" PRId64 ", %s) returned %" PRId64 " (should be %" PRId64 ").\n\n", + line_num, channel_name, offset, whence_name, position, new_pos) ; + exit (1) ; + } ; + +} /* test_seek_or_die */ + +[+ FOR read_op +] +[+ FOR io_type +] +void +test_[+ (get "op_element") +]_[+ (get "io_element") +]_or_die (SNDFILE *file, int pass, [+ (get "io_element") +] *test, sf_count_t [+ (get "count_name") +], int line_num) +{ sf_count_t count ; + + if ((count = sf_[+ (get "op_element") +]_[+ (get "io_element") +] (file, test, [+ (get "count_name") +])) != [+ (get "count_name") +]) + { printf ("\n\nLine %d", line_num) ; + if (pass > 0) + printf (" (pass %d)", pass) ; + printf (" : sf_[+ (get "op_element") +]_[+ (get "io_element") +] failed with short [+ (get "op_element") +] (%" PRId64 " => %" PRId64 ").\n", + [+ (get "count_name") +], count) ; + fflush (stdout) ; + puts (sf_strerror (file)) ; + exit (1) ; + } ; + + return ; +} /* test_[+ (get "op_element") +]_[+ (get "io_element") +]_or_die */ +[+ ENDFOR io_type +][+ ENDFOR read_op +] + +void +test_read_raw_or_die (SNDFILE *file, int pass, void *test, sf_count_t items, int line_num) +{ sf_count_t count ; + + if ((count = sf_read_raw (file, test, items)) != items) + { printf ("\n\nLine %d", line_num) ; + if (pass > 0) + printf (" (pass %d)", pass) ; + printf (" : sf_read_raw failed with short read (%" PRId64 " => %" PRId64 ").\n", items, count) ; + fflush (stdout) ; + puts (sf_strerror (file)) ; + exit (1) ; + } ; + + return ; +} /* test_read_raw_or_die */ + +[+ FOR write_op +] +[+ FOR io_type +] +void +test_[+ (get "op_element") +]_[+ (get "io_element") +]_or_die (SNDFILE *file, int pass, const [+ (get "io_element") +] *test, sf_count_t [+ (get "count_name") +], int line_num) +{ sf_count_t count ; + + if ((count = sf_[+ (get "op_element") +]_[+ (get "io_element") +] (file, test, [+ (get "count_name") +])) != [+ (get "count_name") +]) + { printf ("\n\nLine %d", line_num) ; + if (pass > 0) + printf (" (pass %d)", pass) ; + printf (" : sf_[+ (get "op_element") +]_[+ (get "io_element") +] failed with short [+ (get "op_element") +] (%" PRId64 " => %" PRId64 ").\n", + [+ (get "count_name") +], count) ; + fflush (stdout) ; + puts (sf_strerror (file)) ; + exit (1) ; + } ; + + return ; +} /* test_[+ (get "op_element") +]_[+ (get "io_element") +]_or_die */ +[+ ENDFOR io_type +][+ ENDFOR write_op +] + +void +test_write_raw_or_die (SNDFILE *file, int pass, const void *test, sf_count_t items, int line_num) +{ sf_count_t count ; + + if ((count = sf_write_raw (file, test, items)) != items) + { printf ("\n\nLine %d", line_num) ; + if (pass > 0) + printf (" (pass %d)", pass) ; + printf (" : sf_write_raw failed with short write (%" PRId64 " => %" PRId64 ").\n", items, count) ; + fflush (stdout) ; + puts (sf_strerror (file)) ; + exit (1) ; + } ; + + return ; +} /* test_write_raw_or_die */ + + +[+ FOR io_type ++]void +compare_[+ (get "io_element") +]_or_die (const [+ (get "io_element") +] *expected, const [+ (get "io_element") +] *actual, unsigned count, int line_num) +{ + unsigned k ; + + for (k = 0 ; k < count ; k++) + if (!equals_[+ (get "io_element") +](expected [k], actual [k])) + { printf ("\n\nLine %d : Error at index %d, got " [+ (get "format_str") +] ", should be " [+ (get "format_str") +] "(delta=" [+ (get "format_str") +] " ).\n\n", line_num, k, actual [k], expected [k], actual [k] - expected [k]) ; + exit (1) ; + } ; + + return ; +} /* compare_[+ (get "io_element") +]_or_die */ +[+ ENDFOR io_type +] + + +void +delete_file (int format, const char *filename) +{ char rsrc_name [512], *fname ; + + unlink (filename) ; + + if ((format & SF_FORMAT_TYPEMASK) != SF_FORMAT_SD2) + return ; + + /* + ** Now try for a resource fork stored as a separate file. + ** Grab the un-adulterated filename again. + */ + snprintf (rsrc_name, sizeof (rsrc_name), "%s", filename) ; + + if ((fname = strrchr (rsrc_name, '/')) != NULL) + fname ++ ; + else if ((fname = strrchr (rsrc_name, '\\')) != NULL) + fname ++ ; + else + fname = rsrc_name ; + + memmove (fname + 2, fname, strlen (fname) + 1) ; + fname [0] = '.' ; + fname [1] = '_' ; + + unlink (rsrc_name) ; +} /* delete_file */ + +int +truncate_file_to_zero (const char * fname) +{ FILE * file ; + + if ((file = fopen (fname, "w")) == NULL) + return errno ; + fclose (file) ; + + return 0 ; +} /* truncate_file_to_zero */ + +static int allowed_open_files = -1 ; + +void +count_open_files (void) +{ +#if OS_IS_WIN32 + return ; +#else + int k, count = 0 ; + struct stat statbuf ; + + if (allowed_open_files > 0) + return ; + + for (k = 0 ; k < 1024 ; k++) + if (fstat (k, &statbuf) == 0) + count ++ ; + + allowed_open_files = count ; +#endif +} /* count_open_files */ + +void +increment_open_file_count (void) +{ allowed_open_files ++ ; +} /* increment_open_file_count */ + +void +check_open_file_count_or_die (int lineno) +{ +#if OS_IS_WIN32 + (void) lineno ; + return ; +#else + int k, count = 0 ; + struct stat statbuf ; + + if (allowed_open_files < 0) + count_open_files () ; + + for (k = 0 ; k < 1024 ; k++) + if (fstat (k, &statbuf) == 0) + count ++ ; + + if (count > allowed_open_files) + { printf ("\nLine %d : number of open files (%d) > allowed (%d).\n\n", lineno, count, allowed_open_files) ; + exit (1) ; + } ; +#endif +} /* check_open_file_count_or_die */ + +void +get_unique_test_name (const char ** filename, const char * test) +{ static char buffer [1024] ; + + snprintf (buffer, sizeof (buffer), "%s_%s", test, *filename) ; + + *filename = buffer ; +} /* get_unique_test_name */ + +void +write_mono_file (const char * filename, int format, int srate, float * output, int len) +{ SNDFILE * file ; + SF_INFO sfinfo ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + sfinfo.samplerate = srate ; + sfinfo.channels = 1 ; + sfinfo.format = format ; + + if ((file = sf_open (filename, SFM_WRITE, &sfinfo)) == NULL) + { printf ("sf_open (%s) : %s\n", filename, sf_strerror (NULL)) ; + exit (1) ; + } ; + + sf_write_float (file, output, len) ; + + sf_close (file) ; +} /* write_mono_file */ + +void +gen_lowpass_signal_float (float *data, int len) +{ int64_t value = 0x1243456 ; + double sample, last_val = 0.0 ; + int k ; + + for (k = 0 ; k < len ; k++) + { /* Not a crypto quality RNG. */ + value = (11117 * value + 211231) & 0xffffffff ; + value = (11117 * value + 211231) & 0xffffffff ; + value = (11117 * value + 211231) & 0xffffffff ; + + sample = value / (0x7fffffff * 1.000001) ; + sample = 0.2 * sample - 0.9 * last_val ; + + last_val = sample ; + + data [k] = 0.5 * (sample + sin (2.0 * k * M_PI * 1.0 / 32.0)) ; + } ; + +} /* gen_lowpass_signal_float */ + + +/* +** Windows is fucked. +** If a file is opened R/W and data is written to it, then fstat will return +** the correct file length, but stat will return zero. +*/ + +sf_count_t +file_length (const char * fname) +{ struct stat data ; + + if (stat (fname, &data) != 0) + return 0 ; + + return (sf_count_t) data.st_size ; +} /* file_length */ + +sf_count_t +file_length_fd (int fd) +{ struct stat data ; + + memset (&data, 0, sizeof (data)) ; + if (fstat (fd, &data) != 0) + return 0 ; + + return (sf_count_t) data.st_size ; +} /* file_length_fd */ + + +[+ ESAC +] + diff --git a/extern/libsndfile-modified/tests/virtual_io_test.c b/extern/libsndfile-modified/tests/virtual_io_test.c new file mode 100644 index 000000000..b5f84ac2e --- /dev/null +++ b/extern/libsndfile-modified/tests/virtual_io_test.c @@ -0,0 +1,237 @@ +/* +** Copyright (C) 1999-2011 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "utils.h" + +static void vio_test (const char *fname, int format) ; + +int +main (void) +{ + vio_test ("vio_pcm16.wav", SF_FORMAT_WAV | SF_FORMAT_PCM_16) ; + vio_test ("vio_pcm24.aiff", SF_FORMAT_AIFF | SF_FORMAT_PCM_24) ; + vio_test ("vio_float.au", SF_FORMAT_AU | SF_FORMAT_FLOAT) ; + vio_test ("vio_pcm24.paf", SF_FORMAT_PAF | SF_FORMAT_PCM_24) ; + + return 0 ; +} /* main */ + +/*============================================================================== +*/ + +typedef struct +{ sf_count_t offset, length ; + unsigned char data [16 * 1024] ; +} VIO_DATA ; + +static sf_count_t +vfget_filelen (void *user_data) +{ VIO_DATA *vf = (VIO_DATA *) user_data ; + + return vf->length ; +} /* vfget_filelen */ + +static sf_count_t +vfseek (sf_count_t offset, int whence, void *user_data) +{ VIO_DATA *vf = (VIO_DATA *) user_data ; + + switch (whence) + { case SEEK_SET : + vf->offset = offset ; + break ; + + case SEEK_CUR : + vf->offset = vf->offset + offset ; + break ; + + case SEEK_END : + vf->offset = vf->length + offset ; + break ; + default : + break ; + } ; + + return vf->offset ; +} /* vfseek */ + +static sf_count_t +vfread (void *ptr, sf_count_t count, void *user_data) +{ VIO_DATA *vf = (VIO_DATA *) user_data ; + + /* + ** This will break badly for files over 2Gig in length, but + ** is sufficient for testing. + */ + if (vf->offset + count > vf->length) + count = vf->length - vf->offset ; + + memcpy (ptr, vf->data + vf->offset, count) ; + vf->offset += count ; + + return count ; +} /* vfread */ + +static sf_count_t +vfwrite (const void *ptr, sf_count_t count, void *user_data) +{ VIO_DATA *vf = (VIO_DATA *) user_data ; + + /* + ** This will break badly for files over 2Gig in length, but + ** is sufficient for testing. + */ + if (vf->offset >= SIGNED_SIZEOF (vf->data)) + return 0 ; + + if (vf->offset + count > SIGNED_SIZEOF (vf->data)) + count = sizeof (vf->data) - vf->offset ; + + memcpy (vf->data + vf->offset, ptr, (size_t) count) ; + vf->offset += count ; + + if (vf->offset > vf->length) + vf->length = vf->offset ; + + return count ; +} /* vfwrite */ + +static sf_count_t +vftell (void *user_data) +{ VIO_DATA *vf = (VIO_DATA *) user_data ; + + return vf->offset ; +} /* vftell */ + + +/*============================================================================== +*/ + +static void +gen_short_data (short * data, int len, int start) +{ int k ; + + for (k = 0 ; k < len ; k++) + data [k] = start + k ; +} /* gen_short_data */ + + +static void +check_short_data (short * data, int len, int start, int line) +{ int k ; + + for (k = 0 ; k < len ; k++) + if (data [k] != start + k) + { printf ("\n\nLine %d : data [%d] = %d (should be %d).\n\n", line, k, data [k], start + k) ; + exit (1) ; + } ; +} /* gen_short_data */ + +/*------------------------------------------------------------------------------ +*/ + +static void +vio_test (const char *fname, int format) +{ static VIO_DATA vio_data ; + static short data [256] ; + + SF_VIRTUAL_IO vio ; + SNDFILE * file ; + SF_INFO sfinfo ; + + print_test_name ("virtual i/o test", fname) ; + + /* Set up pointers to the locally defined functions. */ + vio.get_filelen = vfget_filelen ; + vio.seek = vfseek ; + vio.read = vfread ; + vio.write = vfwrite ; + vio.tell = vftell ; + + /* Set virtual file offset and length to zero. */ + vio_data.offset = 0 ; + vio_data.length = 0 ; + + memset (&sfinfo, 0, sizeof (sfinfo)) ; + sfinfo.format = format ; + sfinfo.channels = 2 ; + sfinfo.samplerate = 44100 ; + + if ((file = sf_open_virtual (&vio, SFM_WRITE, &sfinfo, &vio_data)) == NULL) + { printf ("\n\nLine %d : sf_open_write failed with error : ", __LINE__) ; + fflush (stdout) ; + puts (sf_strerror (NULL)) ; + exit (1) ; + } ; + + if (vfget_filelen (&vio_data) < 0) + { printf ("\n\nLine %d : vfget_filelen returned negative length.\n\n", __LINE__) ; + exit (1) ; + } ; + + gen_short_data (data, ARRAY_LEN (data), 0) ; + sf_write_short (file, data, ARRAY_LEN (data)) ; + + gen_short_data (data, ARRAY_LEN (data), 1) ; + sf_write_short (file, data, ARRAY_LEN (data)) ; + + gen_short_data (data, ARRAY_LEN (data), 2) ; + sf_write_short (file, data, ARRAY_LEN (data)) ; + + sf_close (file) ; + + /* Now test read. */ + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + vio_data.offset = 0 ; + + if ((file = sf_open_virtual (&vio, SFM_READ, &sfinfo, &vio_data)) == NULL) + { printf ("\n\nLine %d : sf_open_write failed with error : ", __LINE__) ; + fflush (stdout) ; + puts (sf_strerror (NULL)) ; + + dump_data_to_file (fname, vio_data.data, (unsigned int) vio_data.length) ; + exit (1) ; + } ; + + + sf_read_short (file, data, ARRAY_LEN (data)) ; + check_short_data (data, ARRAY_LEN (data), 0, __LINE__) ; + + sf_read_short (file, data, ARRAY_LEN (data)) ; + check_short_data (data, ARRAY_LEN (data), 1, __LINE__) ; + + sf_read_short (file, data, ARRAY_LEN (data)) ; + check_short_data (data, ARRAY_LEN (data), 2, __LINE__) ; + + sf_close (file) ; + + puts ("ok") ; +} /* vio_test */ + diff --git a/extern/libsndfile-modified/tests/win32_ordinal_test.c b/extern/libsndfile-modified/tests/win32_ordinal_test.c new file mode 100644 index 000000000..7c9adb153 --- /dev/null +++ b/extern/libsndfile-modified/tests/win32_ordinal_test.c @@ -0,0 +1,148 @@ +/* +** Copyright (C) 2006-2017 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include + +#if HAVE_UNISTD_H +#include +#endif + +#if (HAVE_DECL_S_IRGRP == 0) +#include +#endif + +#include +#include +#ifdef HAVE_DIRECT_H +#include +#endif +#include + +#include "utils.h" + +#if (defined (WIN32) || defined (_WIN32) || defined (__CYGWIN__)) +#define TEST_WIN32 1 +#else +#define TEST_WIN32 0 +#endif + +#if TEST_WIN32 +#include + + +static const char * locations [] = +{ ".", "../src/", "src/", "../src/.libs/", "src/.libs/", + NULL +} ; /* locations. */ + +static int +test_ordinal (HMODULE hmod, const char * func_name, int ordinal) +{ char *lpmsg ; + void *name, *ord ; + + print_test_name ("win32_ordinal_test", func_name) ; + +#if SIZEOF_VOIDP == 8 +#define LPCSTR_OF_ORDINAL(x) ((LPCSTR) ((int64_t) (x))) +#else +#define LPCSTR_OF_ORDINAL(x) ((LPCSTR) (x)) +#endif + + ord = GetProcAddress (hmod, LPCSTR_OF_ORDINAL (ordinal)) ; + if ((name = GetProcAddress (hmod, func_name)) == NULL) + { FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError (), + MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpmsg, 0, NULL) ; + /*-puts (lpmsg) ;-*/ + } ; + + if (name != NULL && ord != NULL && name == ord) + { puts ("ok") ; + return 0 ; + } ; + + puts ("fail") ; + return 1 ; +} /* test_ordinal */ + +static void +win32_ordinal_test (void) +{ static char buffer [1024] ; + static char func_name [1024] ; + HMODULE hmod = NULL ; + FILE * file = NULL ; + int k, ordinal, errors = 0 ; + + for (k = 0 ; locations [k] != NULL ; k++) + { snprintf (buffer, sizeof (buffer), "%s/libsndfile-1.def", locations [k]) ; + if ((file = fopen (buffer, "r")) != NULL) + break ; + } ; + + if (file == NULL) + { puts ("\n\nError : cannot open DEF file.\n") ; + exit (1) ; + } ; + + for (k = 0 ; locations [k] != NULL ; k++) + { snprintf (buffer, sizeof (buffer), "%s/libsndfile-1.dll", locations [k]) ; + if ((hmod = (HMODULE) LoadLibrary (buffer)) != NULL) + break ; + } ; + + if (hmod == NULL) + { printf ("\n\nError : cannot load DLL (cwd is %s).\n", getcwd (buffer, sizeof (buffer))) ; + exit (1) ; + } ; + + while (fgets (buffer, sizeof (buffer), file) != NULL) + { func_name [0] = 0 ; + ordinal = 0 ; + + if (sscanf (buffer, "%s @%d", func_name, &ordinal) != 2) + continue ; + + errors += test_ordinal (hmod, func_name, ordinal) ; + } ; + + FreeLibrary (hmod) ; + + fclose (file) ; + + if (errors > 0) + { printf ("\n\nErrors : %d\n\n", errors) ; + exit (1) ; + } ; + + return ; +} /* win32_ordinal_test */ + +#endif + +int +main (void) +{ +#if (TEST_WIN32 && WIN32_TARGET_DLL) + win32_ordinal_test () ; +#endif + + return 0 ; +} /* main */ + diff --git a/extern/libsndfile-modified/tests/win32_test.c b/extern/libsndfile-modified/tests/win32_test.c new file mode 100644 index 000000000..d0dc6d8ea --- /dev/null +++ b/extern/libsndfile-modified/tests/win32_test.c @@ -0,0 +1,318 @@ +/* +** Copyright (C) 2001-2011 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" +#include "sndfile.h" + +#include +#include +#include + +#if HAVE_UNISTD_H +#include +#endif + +#if (HAVE_DECL_S_IRGRP == 0) +#include +#endif + +#include +#include +#include +#include +#include + +#define SIGNED_SIZEOF(x) ((int) sizeof (x)) + +/* EMX is OS/2. */ +#if defined (__CYGWIN__) || defined (__EMX__) + + #define LSEEK lseek + #define FSTAT fstat + + typedef struct stat STATBUF ; + typedef off_t INT64 ; + + static char dir_cmd [] = "ls -l" ; + +#elif (defined (WIN32) || defined (_WIN32)) + + #define LSEEK _lseeki64 + #define FSTAT _fstati64 + + typedef struct _stati64 STATBUF ; + typedef __int64 INT64 ; + + static char dir_cmd [] = "dir" ; + +#else + + #define LSEEK lseek + #define FSTAT fstat + + typedef struct stat STATBUF ; + typedef sf_count_t INT64 ; + + #define O_BINARY 0 + static char dir_cmd [] = "ls -l" ; + +#endif + +static void show_fstat_error (void) ; +static void show_lseek_error (void) ; +static void show_stat_fstat_error (void) ; +static void write_to_closed_file (void) ; + +int +main (void) +{ + puts ("\n\n\n\n" + "This program shows up errors in the Win32 implementation of\n" + "a couple of POSIX API functions on some versions of windoze.\n" + "It can also be compiled on Linux (which works correctly) and\n" + "other OSes just to provide a sanity check.\n" + ) ; + + show_fstat_error () ; + show_lseek_error () ; + show_stat_fstat_error () ; + write_to_closed_file () ; + + puts ("\n\n") ; + + return 0 ; +} /* main */ + +static void +show_fstat_error (void) +{ static const char *filename = "fstat.dat" ; + static char data [256] ; + + STATBUF statbuf ; + int fd, mode, flags ; + + if (sizeof (statbuf.st_size) != sizeof (INT64)) + { printf ("\n\nLine %d: Error, sizeof (statbuf.st_size) != 8.\n\n", __LINE__) ; + return ; + } ; + + puts ("\n64 bit fstat() test.\n--------------------") ; + + printf ("0) Create a file, write %d bytes and close it.\n", SIGNED_SIZEOF (data)) ; + mode = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY ; + flags = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ; + if ((fd = open (filename, mode, flags)) < 0) + { printf ("\n\nLine %d: open() failed : %s\n\n", __LINE__, strerror (errno)) ; + return ; + } ; + assert (write (fd, data, sizeof (data)) > 0) ; + close (fd) ; + + printf ("1) Re-open file in read/write mode and write another %d bytes at the end.\n", SIGNED_SIZEOF (data)) ; + mode = O_RDWR | O_BINARY ; + flags = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ; + if ((fd = open (filename, mode, flags)) < 0) + { printf ("\n\nLine %d: open() failed : %s\n\n", __LINE__, strerror (errno)) ; + return ; + } ; + LSEEK (fd, 0, SEEK_END) ; + assert (write (fd, data, sizeof (data)) > 0) ; + + printf ("2) Now use system (\"%s %s\") to show the file length.\n\n", dir_cmd, filename) ; + + /* Would use snprintf, but thats not really available on windows. */ + memset (data, 0, sizeof (data)) ; + strncpy (data, dir_cmd, sizeof (data) - 1) ; + strncat (data, " ", sizeof (data) - 1 - strlen (data)) ; + strncat (data, filename, sizeof (data) - 1 - strlen (data)) ; + + assert (system (data) >= 0) ; + puts ("") ; + + printf ("3) Now use fstat() to get the file length.\n") ; + if (FSTAT (fd, &statbuf) != 0) + { printf ("\n\nLine %d: fstat() returned error : %s\n", __LINE__, strerror (errno)) ; + return ; + } ; + + printf ("4) According to fstat(), the file length is %ld, ", (long) statbuf.st_size) ; + + close (fd) ; + + if (statbuf.st_size != 2 * sizeof (data)) + printf ("but thats just plain ***WRONG***.\n\n") ; + else + { printf ("which is correct.\n\n") ; + unlink (filename) ; + } ; + +} /* show_fstat_error */ + +static void +show_lseek_error (void) +{ static const char *filename = "fstat.dat" ; + static char data [256] ; + + INT64 retval ; + int fd, mode, flags ; + + puts ("\n64 bit lseek() test.\n--------------------") ; + + printf ("0) Create a file, write %d bytes and close it.\n", SIGNED_SIZEOF (data)) ; + mode = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY ; + flags = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ; + if ((fd = open (filename, mode, flags)) < 0) + { printf ("\n\nLine %d: open() failed : %s\n\n", __LINE__, strerror (errno)) ; + return ; + } ; + assert (write (fd, data, sizeof (data)) > 0) ; + close (fd) ; + + printf ("1) Re-open file in read/write mode and write another %d bytes at the end.\n", SIGNED_SIZEOF (data)) ; + mode = O_RDWR | O_BINARY ; + flags = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ; + if ((fd = open (filename, mode, flags)) < 0) + { printf ("\n\nLine %d: open() failed : %s\n\n", __LINE__, strerror (errno)) ; + return ; + } ; + + LSEEK (fd, 0, SEEK_END) ; + assert (write (fd, data, sizeof (data)) > 0) ; + + printf ("2) Now use system (\"%s %s\") to show the file length.\n\n", dir_cmd, filename) ; + + /* Would use snprintf, but thats not really available on windows. */ + memset (data, 0, sizeof (data)) ; + strncpy (data, dir_cmd, sizeof (data) - 1) ; + strncat (data, " ", sizeof (data) - 1 - strlen (data)) ; + strncat (data, filename, sizeof (data) - 1 - strlen (data)) ; + + assert (system (data) >= 0) ; + puts ("") ; + + printf ("3) Now use lseek() to go to the end of the file.\n") ; + retval = LSEEK (fd, 0, SEEK_END) ; + + printf ("4) We are now at position %ld, ", (long) retval) ; + + close (fd) ; + + if (retval != 2 * sizeof (data)) + printf ("but thats just plain ***WRONG***.\n\n") ; + else + { printf ("which is correct.\n\n") ; + unlink (filename) ; + } ; + +} /* show_lseek_error */ + +static void +show_stat_fstat_error (void) +{ static const char *filename = "stat_fstat.dat" ; + static char data [256] ; + + int fd, mode, flags ; + int stat_size, fstat_size ; + struct stat buf ; + + /* Known to fail on WinXP. */ + puts ("\nstat/fstat test.\n----------------") ; + + printf ("0) Create a file and write %d bytes.\n", SIGNED_SIZEOF (data)) ; + + mode = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY ; + flags = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ; + if ((fd = open (filename, mode, flags)) < 0) + { printf ("\n\nLine %d: open() failed : %s\n\n", __LINE__, strerror (errno)) ; + return ; + } ; + + assert (write (fd, data, sizeof (data)) > 0) ; + + printf ("1) Now call stat and fstat on the file and retreive the file lengths.\n") ; + + if (stat (filename, &buf) != 0) + { printf ("\n\nLine %d: stat() failed : %s\n\n", __LINE__, strerror (errno)) ; + goto error_exit ; + } ; + stat_size = buf.st_size ; + + if (fstat (fd, &buf) != 0) + { printf ("\n\nLine %d: fstat() failed : %s\n\n", __LINE__, strerror (errno)) ; + goto error_exit ; + } ; + fstat_size = buf.st_size ; + + printf ("2) Size returned by stat and fstat is %d and %d, ", stat_size, fstat_size) ; + + + if (stat_size == 0 || stat_size != fstat_size) + printf ("but thats just plain ***WRONG***.\n\n") ; + else + printf ("which is correct.\n\n") ; + +error_exit : + + close (fd) ; + unlink (filename) ; + + return ; +} /* show_stat_fstat_error */ + + +static void +write_to_closed_file (void) +{ const char * filename = "closed_write_test.txt" ; + struct stat buf ; + FILE * file ; + int fd ; + + puts ("\nWrite to closed file test.\n--------------------------") ; + + printf ("0) First we open file for write using fopen().\n") ; + if ((file = fopen (filename, "w")) == NULL) + { printf ("\n\nLine %d: fopen() failed : %s\n\n", __LINE__, strerror (errno)) ; + return ; + } ; + + printf ("1) Now we grab the file descriptor fileno().\n") ; + fd = fileno (file) ; + + printf ("2) Write some text via the file descriptor.\n") ; + assert (write (fd, "a\n", 2) > 0) ; + + printf ("3) Now we close the file using fclose().\n") ; + fclose (file) ; + + stat (filename, &buf) ; + printf (" File size is %d bytes.\n", (int) buf.st_size) ; + + printf ("4) Now write more data to the file descriptor which should fail.\n") ; + if (write (fd, "b\n", 2) < 0) + printf ("5) Good, write returned an error code as it should have.\n") ; + else + { printf ("5) Attempting to write to a closed file should have failed but didn't! *** WRONG ***\n") ; + + stat (filename, &buf) ; + printf (" File size is %d bytes.\n", (int) buf.st_size) ; + } ; + + unlink (filename) ; + + return ; +} /* write_to_closed_file */ diff --git a/extern/libsndfile-modified/tests/write_read_test.def b/extern/libsndfile-modified/tests/write_read_test.def new file mode 100644 index 000000000..3316aec57 --- /dev/null +++ b/extern/libsndfile-modified/tests/write_read_test.def @@ -0,0 +1,75 @@ +autogen definitions write_read_test.tpl; + +data_type = { + type_name = char ; + data_type = short ; + data_field = s ; + error_func = CHAR_ERROR ; + format_char = "0x%X" ; + max_val = "32000.0" ; + max_error = "255" ; + } ; + +data_type = { + type_name = short ; + data_type = short ; + data_field = s ; + error_func = INT_ERROR ; + format_char = "0x%X" ; + max_val = "32000.0" ; + max_error = "0" ; + } ; + +data_type = { + type_name = "20bit" ; + data_type = int ; + data_field = i ; + error_func = BIT_20_ERROR ; + format_char = "0x%X" ; + max_val = "(1.0 * 0x7F00000)" ; + max_error = "4096" ; + } ; + +data_type = { + type_name = "24bit" ; + data_type = int ; + data_field = i ; + error_func = TRIBYTE_ERROR ; + format_char = "0x%X" ; + max_val = "(1.0 * 0x7F000000)" ; + max_error = "256" ; + } ; + +data_type = { + type_name = int ; + data_type = int ; + data_field = i ; + error_func = INT_ERROR ; + format_char = "0x%X" ; + max_val = "(1.0 * 0x7F000000)" ; + max_error = "0" ; + } ; + +/* Lite remove start */ + +data_type = { + type_name = float ; + data_type = float ; + data_field = f ; + error_func = FLOAT_ERROR ; + format_char = "%g" ; + max_val = "1.0" ; + max_error = "0" ; + } ; + +data_type = { + type_name = double ; + data_type = double ; + data_field = d ; + error_func = FLOAT_ERROR ; + format_char = "%g" ; + max_val = "1.0" ; + max_error = "0" ; + } ; + +/* Lite remove end */ diff --git a/extern/libsndfile-modified/tests/write_read_test.tpl b/extern/libsndfile-modified/tests/write_read_test.tpl new file mode 100644 index 000000000..ed152f893 --- /dev/null +++ b/extern/libsndfile-modified/tests/write_read_test.tpl @@ -0,0 +1,1208 @@ +[+ AutoGen5 template c +] +/* +** Copyright (C) 1999-2017 Erik de Castro Lopo +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "sfconfig.h" + +#include +#include +#include +#include +#include + + +#if HAVE_UNISTD_H +#include +#else +#include "sf_unistd.h" +#endif + +#include + +#include "utils.h" +#include "generate.h" + +#define SAMPLE_RATE 11025 +#define DATA_LENGTH (1 << 12) + +#define SILLY_WRITE_COUNT (234) + +static const char WRT_TEST_PREFIX[] = "wrt" ; + +[+ FOR data_type ++]static void pcm_test_[+ (get "type_name") +] (const char *str, int format, int long_file_ok) ; +[+ ENDFOR data_type ++] +static void empty_file_test (const char *filename, int format) ; + +typedef union +{ double d [DATA_LENGTH] ; + float f [DATA_LENGTH] ; + int i [DATA_LENGTH] ; + short s [DATA_LENGTH] ; + char c [DATA_LENGTH] ; +} BUFFER ; + +static BUFFER orig_data ; +static BUFFER test_data ; + +int +main (int argc, char **argv) +{ int do_all = 0 ; + int test_count = 0 ; + + count_open_files () ; + + if (argc != 2) + { printf ("Usage : %s \n", argv [0]) ; + printf (" Where is one of the following:\n") ; + printf (" wav - test WAV file functions (little endian)\n") ; + printf (" aiff - test AIFF file functions (big endian)\n") ; + printf (" au - test AU file functions\n") ; + printf (" avr - test AVR file functions\n") ; + printf (" caf - test CAF file functions\n") ; + printf (" raw - test RAW header-less PCM file functions\n") ; + printf (" paf - test PAF file functions\n") ; + printf (" svx - test 8SVX/16SV file functions\n") ; + printf (" nist - test NIST Sphere file functions\n") ; + printf (" ircam - test IRCAM file functions\n") ; + printf (" voc - Create Voice file functions\n") ; + printf (" w64 - Sonic Foundry's W64 file functions\n") ; + printf (" flac - test FLAC file functions\n") ; + printf (" mpc2k - test MPC 2000 file functions\n") ; + printf (" rf64 - test RF64 file functions\n") ; + printf (" all - perform all tests\n") ; + exit (1) ; + } ; + + do_all = !strcmp (argv [1], "all") ; + + if (do_all || ! strcmp (argv [1], "wav")) + { pcm_test_char ("char.wav" , SF_FORMAT_WAV | SF_FORMAT_PCM_U8, SF_FALSE) ; + pcm_test_short ("short.wav" , SF_FORMAT_WAV | SF_FORMAT_PCM_16, SF_FALSE) ; + pcm_test_24bit ("24bit.wav" , SF_FORMAT_WAV | SF_FORMAT_PCM_24, SF_FALSE) ; + pcm_test_int ("int.wav" , SF_FORMAT_WAV | SF_FORMAT_PCM_32, SF_FALSE) ; + + pcm_test_char ("char.rifx" , SF_ENDIAN_BIG | SF_FORMAT_WAV | SF_FORMAT_PCM_U8, SF_FALSE) ; + pcm_test_short ("short.rifx" , SF_ENDIAN_BIG | SF_FORMAT_WAV | SF_FORMAT_PCM_16, SF_FALSE) ; + pcm_test_24bit ("24bit.rifx" , SF_ENDIAN_BIG | SF_FORMAT_WAV | SF_FORMAT_PCM_24, SF_FALSE) ; + pcm_test_int ("int.rifx" , SF_ENDIAN_BIG | SF_FORMAT_WAV | SF_FORMAT_PCM_32, SF_FALSE) ; + + pcm_test_24bit ("24bit.wavex" , SF_FORMAT_WAVEX | SF_FORMAT_PCM_24, SF_FALSE) ; + pcm_test_int ("int.wavex" , SF_FORMAT_WAVEX | SF_FORMAT_PCM_32, SF_FALSE) ; + + /* Lite remove start */ + pcm_test_float ("float.wav" , SF_FORMAT_WAV | SF_FORMAT_FLOAT , SF_FALSE) ; + pcm_test_double ("double.wav" , SF_FORMAT_WAV | SF_FORMAT_DOUBLE, SF_FALSE) ; + + pcm_test_float ("float.rifx" , SF_ENDIAN_BIG | SF_FORMAT_WAV | SF_FORMAT_FLOAT , SF_FALSE) ; + pcm_test_double ("double.rifx" , SF_ENDIAN_BIG | SF_FORMAT_WAV | SF_FORMAT_DOUBLE, SF_FALSE) ; + + pcm_test_float ("float.wavex" , SF_FORMAT_WAVEX | SF_FORMAT_FLOAT , SF_FALSE) ; + pcm_test_double ("double.wavex" , SF_FORMAT_WAVEX | SF_FORMAT_DOUBLE, SF_FALSE) ; + /* Lite remove end */ + + empty_file_test ("empty_char.wav", SF_FORMAT_WAV | SF_FORMAT_PCM_U8) ; + empty_file_test ("empty_short.wav", SF_FORMAT_WAV | SF_FORMAT_PCM_16) ; + empty_file_test ("empty_float.wav", SF_FORMAT_WAV | SF_FORMAT_FLOAT) ; + + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "aiff")) + { pcm_test_char ("char_u8.aiff" , SF_FORMAT_AIFF | SF_FORMAT_PCM_U8, SF_FALSE) ; + pcm_test_char ("char_s8.aiff" , SF_FORMAT_AIFF | SF_FORMAT_PCM_S8, SF_FALSE) ; + pcm_test_short ("short.aiff" , SF_FORMAT_AIFF | SF_FORMAT_PCM_16, SF_FALSE) ; + pcm_test_24bit ("24bit.aiff" , SF_FORMAT_AIFF | SF_FORMAT_PCM_24, SF_FALSE) ; + pcm_test_int ("int.aiff" , SF_FORMAT_AIFF | SF_FORMAT_PCM_32, SF_FALSE) ; + + pcm_test_short ("short_sowt.aifc" , SF_ENDIAN_LITTLE | SF_FORMAT_AIFF | SF_FORMAT_PCM_16, SF_FALSE) ; + pcm_test_24bit ("24bit_sowt.aifc" , SF_ENDIAN_LITTLE | SF_FORMAT_AIFF | SF_FORMAT_PCM_24, SF_FALSE) ; + pcm_test_int ("int_sowt.aifc" , SF_ENDIAN_LITTLE | SF_FORMAT_AIFF | SF_FORMAT_PCM_32, SF_FALSE) ; + + pcm_test_short ("short_twos.aifc" , SF_ENDIAN_BIG | SF_FORMAT_AIFF | SF_FORMAT_PCM_16, SF_FALSE) ; + pcm_test_24bit ("24bit_twos.aifc" , SF_ENDIAN_BIG | SF_FORMAT_AIFF | SF_FORMAT_PCM_24, SF_FALSE) ; + pcm_test_int ("int_twos.aifc" , SF_ENDIAN_BIG | SF_FORMAT_AIFF | SF_FORMAT_PCM_32, SF_FALSE) ; + + /* Lite remove start */ + pcm_test_short ("dwvw16.aifc", SF_FORMAT_AIFF | SF_FORMAT_DWVW_16, SF_TRUE) ; + pcm_test_24bit ("dwvw24.aifc", SF_FORMAT_AIFF | SF_FORMAT_DWVW_24, SF_TRUE) ; + + pcm_test_float ("float.aifc" , SF_FORMAT_AIFF | SF_FORMAT_FLOAT , SF_FALSE) ; + pcm_test_double ("double.aifc" , SF_FORMAT_AIFF | SF_FORMAT_DOUBLE, SF_FALSE) ; + /* Lite remove end */ + + empty_file_test ("empty_char.aiff", SF_FORMAT_AIFF | SF_FORMAT_PCM_U8) ; + empty_file_test ("empty_short.aiff", SF_FORMAT_AIFF | SF_FORMAT_PCM_16) ; + empty_file_test ("empty_float.aiff", SF_FORMAT_AIFF | SF_FORMAT_FLOAT) ; + + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "au")) + { pcm_test_char ("char.au" , SF_FORMAT_AU | SF_FORMAT_PCM_S8, SF_FALSE) ; + pcm_test_short ("short.au" , SF_FORMAT_AU | SF_FORMAT_PCM_16, SF_FALSE) ; + pcm_test_24bit ("24bit.au" , SF_FORMAT_AU | SF_FORMAT_PCM_24, SF_FALSE) ; + pcm_test_int ("int.au" , SF_FORMAT_AU | SF_FORMAT_PCM_32, SF_FALSE) ; + /* Lite remove start */ + pcm_test_float ("float.au" , SF_FORMAT_AU | SF_FORMAT_FLOAT , SF_FALSE) ; + pcm_test_double ("double.au", SF_FORMAT_AU | SF_FORMAT_DOUBLE, SF_FALSE) ; + /* Lite remove end */ + + pcm_test_char ("char_le.au" , SF_ENDIAN_LITTLE | SF_FORMAT_AU | SF_FORMAT_PCM_S8, SF_FALSE) ; + pcm_test_short ("short_le.au" , SF_ENDIAN_LITTLE | SF_FORMAT_AU | SF_FORMAT_PCM_16, SF_FALSE) ; + pcm_test_24bit ("24bit_le.au" , SF_ENDIAN_LITTLE | SF_FORMAT_AU | SF_FORMAT_PCM_24, SF_FALSE) ; + pcm_test_int ("int_le.au" , SF_ENDIAN_LITTLE | SF_FORMAT_AU | SF_FORMAT_PCM_32, SF_FALSE) ; + /* Lite remove start */ + pcm_test_float ("float_le.au" , SF_ENDIAN_LITTLE | SF_FORMAT_AU | SF_FORMAT_FLOAT , SF_FALSE) ; + pcm_test_double ("double_le.au" , SF_ENDIAN_LITTLE | SF_FORMAT_AU | SF_FORMAT_DOUBLE, SF_FALSE) ; + /* Lite remove end */ + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "caf")) + { pcm_test_char ("char.caf" , SF_FORMAT_CAF | SF_FORMAT_PCM_S8, SF_FALSE) ; + pcm_test_short ("short.caf" , SF_FORMAT_CAF | SF_FORMAT_PCM_16, SF_FALSE) ; + pcm_test_24bit ("24bit.caf" , SF_FORMAT_CAF | SF_FORMAT_PCM_24, SF_FALSE) ; + pcm_test_int ("int.caf" , SF_FORMAT_CAF | SF_FORMAT_PCM_32, SF_FALSE) ; + /* Lite remove start */ + pcm_test_float ("float.caf" , SF_FORMAT_CAF | SF_FORMAT_FLOAT , SF_FALSE) ; + pcm_test_double ("double.caf" , SF_FORMAT_CAF | SF_FORMAT_DOUBLE, SF_FALSE) ; + /* Lite remove end */ + + pcm_test_short ("short_le.caf" , SF_ENDIAN_LITTLE | SF_FORMAT_CAF | SF_FORMAT_PCM_16, SF_FALSE) ; + pcm_test_24bit ("24bit_le.caf" , SF_ENDIAN_LITTLE | SF_FORMAT_CAF | SF_FORMAT_PCM_24, SF_FALSE) ; + pcm_test_int ("int_le.caf" , SF_ENDIAN_LITTLE | SF_FORMAT_CAF | SF_FORMAT_PCM_32, SF_FALSE) ; + /* Lite remove start */ + pcm_test_float ("float_le.caf" , SF_ENDIAN_LITTLE | SF_FORMAT_CAF | SF_FORMAT_FLOAT , SF_FALSE) ; + pcm_test_double ("double_le.caf", SF_ENDIAN_LITTLE | SF_FORMAT_CAF | SF_FORMAT_DOUBLE, SF_FALSE) ; + + pcm_test_short ("alac16.caf" , SF_FORMAT_CAF | SF_FORMAT_ALAC_16, SF_FALSE) ; + pcm_test_20bit ("alac20.caf" , SF_FORMAT_CAF | SF_FORMAT_ALAC_20, SF_FALSE) ; + pcm_test_24bit ("alac24.caf" , SF_FORMAT_CAF | SF_FORMAT_ALAC_24, SF_FALSE) ; + pcm_test_int ("alac32.caf" , SF_FORMAT_CAF | SF_FORMAT_ALAC_32, SF_FALSE) ; + + /* Lite remove end */ + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "raw")) + { pcm_test_char ("char_s8.raw" , SF_FORMAT_RAW | SF_FORMAT_PCM_S8, SF_FALSE) ; + pcm_test_char ("char_u8.raw" , SF_FORMAT_RAW | SF_FORMAT_PCM_U8, SF_FALSE) ; + + pcm_test_short ("short_le.raw" , SF_ENDIAN_LITTLE | SF_FORMAT_RAW | SF_FORMAT_PCM_16, SF_FALSE) ; + pcm_test_short ("short_be.raw" , SF_ENDIAN_BIG | SF_FORMAT_RAW | SF_FORMAT_PCM_16, SF_FALSE) ; + pcm_test_24bit ("24bit_le.raw" , SF_ENDIAN_LITTLE | SF_FORMAT_RAW | SF_FORMAT_PCM_24, SF_FALSE) ; + pcm_test_24bit ("24bit_be.raw" , SF_ENDIAN_BIG | SF_FORMAT_RAW | SF_FORMAT_PCM_24, SF_FALSE) ; + pcm_test_int ("int_le.raw" , SF_ENDIAN_LITTLE | SF_FORMAT_RAW | SF_FORMAT_PCM_32, SF_FALSE) ; + pcm_test_int ("int_be.raw" , SF_ENDIAN_BIG | SF_FORMAT_RAW | SF_FORMAT_PCM_32, SF_FALSE) ; + + /* Lite remove start */ + pcm_test_float ("float_le.raw" , SF_ENDIAN_LITTLE | SF_FORMAT_RAW | SF_FORMAT_FLOAT , SF_FALSE) ; + pcm_test_float ("float_be.raw" , SF_ENDIAN_BIG | SF_FORMAT_RAW | SF_FORMAT_FLOAT , SF_FALSE) ; + + pcm_test_double ("double_le.raw", SF_ENDIAN_LITTLE | SF_FORMAT_RAW | SF_FORMAT_DOUBLE, SF_FALSE) ; + pcm_test_double ("double_be.raw", SF_ENDIAN_BIG | SF_FORMAT_RAW | SF_FORMAT_DOUBLE, SF_FALSE) ; + /* Lite remove end */ + test_count++ ; + } ; + + /* Lite remove start */ + if (do_all || ! strcmp (argv [1], "paf")) + { pcm_test_char ("char_le.paf", SF_ENDIAN_LITTLE | SF_FORMAT_PAF | SF_FORMAT_PCM_S8, SF_FALSE) ; + pcm_test_char ("char_be.paf", SF_ENDIAN_BIG | SF_FORMAT_PAF | SF_FORMAT_PCM_S8, SF_FALSE) ; + pcm_test_short ("short_le.paf", SF_ENDIAN_LITTLE | SF_FORMAT_PAF | SF_FORMAT_PCM_16, SF_FALSE) ; + pcm_test_short ("short_be.paf", SF_ENDIAN_BIG | SF_FORMAT_PAF | SF_FORMAT_PCM_16, SF_FALSE) ; + pcm_test_24bit ("24bit_le.paf", SF_ENDIAN_LITTLE | SF_FORMAT_PAF | SF_FORMAT_PCM_24, SF_TRUE) ; + pcm_test_24bit ("24bit_be.paf", SF_ENDIAN_BIG | SF_FORMAT_PAF | SF_FORMAT_PCM_24, SF_TRUE) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "svx")) + { pcm_test_char ("char.svx" , SF_FORMAT_SVX | SF_FORMAT_PCM_S8, SF_FALSE) ; + pcm_test_short ("short.svx", SF_FORMAT_SVX | SF_FORMAT_PCM_16, SF_FALSE) ; + + empty_file_test ("empty_char.svx", SF_FORMAT_SVX | SF_FORMAT_PCM_S8) ; + empty_file_test ("empty_short.svx", SF_FORMAT_SVX | SF_FORMAT_PCM_16) ; + + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "nist")) + { pcm_test_short ("short_le.nist", SF_ENDIAN_LITTLE | SF_FORMAT_NIST | SF_FORMAT_PCM_16, SF_FALSE) ; + pcm_test_short ("short_be.nist", SF_ENDIAN_BIG | SF_FORMAT_NIST | SF_FORMAT_PCM_16, SF_FALSE) ; + pcm_test_24bit ("24bit_le.nist", SF_ENDIAN_LITTLE | SF_FORMAT_NIST | SF_FORMAT_PCM_24, SF_FALSE) ; + pcm_test_24bit ("24bit_be.nist", SF_ENDIAN_BIG | SF_FORMAT_NIST | SF_FORMAT_PCM_24, SF_FALSE) ; + pcm_test_int ("int_le.nist" , SF_ENDIAN_LITTLE | SF_FORMAT_NIST | SF_FORMAT_PCM_32, SF_FALSE) ; + pcm_test_int ("int_be.nist" , SF_ENDIAN_BIG | SF_FORMAT_NIST | SF_FORMAT_PCM_32, SF_FALSE) ; + + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "ircam")) + { pcm_test_short ("short_be.ircam" , SF_ENDIAN_BIG | SF_FORMAT_IRCAM | SF_FORMAT_PCM_16, SF_FALSE) ; + pcm_test_short ("short_le.ircam" , SF_ENDIAN_LITTLE | SF_FORMAT_IRCAM | SF_FORMAT_PCM_16, SF_FALSE) ; + pcm_test_int ("int_be.ircam" , SF_ENDIAN_BIG | SF_FORMAT_IRCAM | SF_FORMAT_PCM_32, SF_FALSE) ; + pcm_test_int ("int_le.ircam" , SF_ENDIAN_LITTLE | SF_FORMAT_IRCAM | SF_FORMAT_PCM_32, SF_FALSE) ; + pcm_test_float ("float_be.ircam" , SF_ENDIAN_BIG | SF_FORMAT_IRCAM | SF_FORMAT_FLOAT , SF_FALSE) ; + pcm_test_float ("float_le.ircam" , SF_ENDIAN_LITTLE | SF_FORMAT_IRCAM | SF_FORMAT_FLOAT , SF_FALSE) ; + + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "voc")) + { pcm_test_char ("char.voc" , SF_FORMAT_VOC | SF_FORMAT_PCM_U8, SF_FALSE) ; + pcm_test_short ("short.voc", SF_FORMAT_VOC | SF_FORMAT_PCM_16, SF_FALSE) ; + + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "mat4")) + { pcm_test_short ("short_be.mat4" , SF_ENDIAN_BIG | SF_FORMAT_MAT4 | SF_FORMAT_PCM_16, SF_FALSE) ; + pcm_test_short ("short_le.mat4" , SF_ENDIAN_LITTLE | SF_FORMAT_MAT4 | SF_FORMAT_PCM_16, SF_FALSE) ; + pcm_test_int ("int_be.mat4" , SF_ENDIAN_BIG | SF_FORMAT_MAT4 | SF_FORMAT_PCM_32, SF_FALSE) ; + pcm_test_int ("int_le.mat4" , SF_ENDIAN_LITTLE | SF_FORMAT_MAT4 | SF_FORMAT_PCM_32, SF_FALSE) ; + pcm_test_float ("float_be.mat4" , SF_ENDIAN_BIG | SF_FORMAT_MAT4 | SF_FORMAT_FLOAT , SF_FALSE) ; + pcm_test_float ("float_le.mat4" , SF_ENDIAN_LITTLE | SF_FORMAT_MAT4 | SF_FORMAT_FLOAT , SF_FALSE) ; + pcm_test_double ("double_be.mat4" , SF_ENDIAN_BIG | SF_FORMAT_MAT4 | SF_FORMAT_DOUBLE, SF_FALSE) ; + pcm_test_double ("double_le.mat4" , SF_ENDIAN_LITTLE | SF_FORMAT_MAT4 | SF_FORMAT_DOUBLE, SF_FALSE) ; + + empty_file_test ("empty_short.mat4", SF_FORMAT_MAT4 | SF_FORMAT_PCM_16) ; + empty_file_test ("empty_float.mat4", SF_FORMAT_MAT4 | SF_FORMAT_FLOAT) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "mat5")) + { pcm_test_char ("char_be.mat5" , SF_ENDIAN_BIG | SF_FORMAT_MAT5 | SF_FORMAT_PCM_U8, SF_FALSE) ; + pcm_test_char ("char_le.mat5" , SF_ENDIAN_LITTLE | SF_FORMAT_MAT5 | SF_FORMAT_PCM_U8, SF_FALSE) ; + pcm_test_short ("short_be.mat5" , SF_ENDIAN_BIG | SF_FORMAT_MAT5 | SF_FORMAT_PCM_16, SF_FALSE) ; + pcm_test_short ("short_le.mat5" , SF_ENDIAN_LITTLE | SF_FORMAT_MAT5 | SF_FORMAT_PCM_16, SF_FALSE) ; + pcm_test_int ("int_be.mat5" , SF_ENDIAN_BIG | SF_FORMAT_MAT5 | SF_FORMAT_PCM_32, SF_FALSE) ; + pcm_test_int ("int_le.mat5" , SF_ENDIAN_LITTLE | SF_FORMAT_MAT5 | SF_FORMAT_PCM_32, SF_FALSE) ; + pcm_test_float ("float_be.mat5" , SF_ENDIAN_BIG | SF_FORMAT_MAT5 | SF_FORMAT_FLOAT , SF_FALSE) ; + pcm_test_float ("float_le.mat5" , SF_ENDIAN_LITTLE | SF_FORMAT_MAT5 | SF_FORMAT_FLOAT , SF_FALSE) ; + pcm_test_double ("double_be.mat5" , SF_ENDIAN_BIG | SF_FORMAT_MAT5 | SF_FORMAT_DOUBLE, SF_FALSE) ; + pcm_test_double ("double_le.mat5" , SF_ENDIAN_LITTLE | SF_FORMAT_MAT5 | SF_FORMAT_DOUBLE, SF_FALSE) ; + + increment_open_file_count () ; + + empty_file_test ("empty_char.mat5", SF_FORMAT_MAT5 | SF_FORMAT_PCM_U8) ; + empty_file_test ("empty_short.mat5", SF_FORMAT_MAT5 | SF_FORMAT_PCM_16) ; + empty_file_test ("empty_float.mat5", SF_FORMAT_MAT5 | SF_FORMAT_FLOAT) ; + + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "pvf")) + { pcm_test_char ("char.pvf" , SF_FORMAT_PVF | SF_FORMAT_PCM_S8, SF_FALSE) ; + pcm_test_short ("short.pvf", SF_FORMAT_PVF | SF_FORMAT_PCM_16, SF_FALSE) ; + pcm_test_int ("int.pvf" , SF_FORMAT_PVF | SF_FORMAT_PCM_32, SF_FALSE) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "htk")) + { pcm_test_short ("short.htk", SF_FORMAT_HTK | SF_FORMAT_PCM_16, SF_FALSE) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "mpc2k")) + { pcm_test_short ("short.mpc", SF_FORMAT_MPC2K | SF_FORMAT_PCM_16, SF_FALSE) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "avr")) + { pcm_test_char ("char_u8.avr" , SF_FORMAT_AVR | SF_FORMAT_PCM_U8, SF_FALSE) ; + pcm_test_char ("char_s8.avr" , SF_FORMAT_AVR | SF_FORMAT_PCM_S8, SF_FALSE) ; + pcm_test_short ("short.avr" , SF_FORMAT_AVR | SF_FORMAT_PCM_16, SF_FALSE) ; + test_count++ ; + } ; + /* Lite remove end */ + + if (do_all || ! strcmp (argv [1], "w64")) + { pcm_test_char ("char.w64" , SF_FORMAT_W64 | SF_FORMAT_PCM_U8, SF_FALSE) ; + pcm_test_short ("short.w64" , SF_FORMAT_W64 | SF_FORMAT_PCM_16, SF_FALSE) ; + pcm_test_24bit ("24bit.w64" , SF_FORMAT_W64 | SF_FORMAT_PCM_24, SF_FALSE) ; + pcm_test_int ("int.w64" , SF_FORMAT_W64 | SF_FORMAT_PCM_32, SF_FALSE) ; + /* Lite remove start */ + pcm_test_float ("float.w64" , SF_FORMAT_W64 | SF_FORMAT_FLOAT , SF_FALSE) ; + pcm_test_double ("double.w64" , SF_FORMAT_W64 | SF_FORMAT_DOUBLE, SF_FALSE) ; + /* Lite remove end */ + + empty_file_test ("empty_char.w64", SF_FORMAT_W64 | SF_FORMAT_PCM_U8) ; + empty_file_test ("empty_short.w64", SF_FORMAT_W64 | SF_FORMAT_PCM_16) ; + empty_file_test ("empty_float.w64", SF_FORMAT_W64 | SF_FORMAT_FLOAT) ; + + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "sds")) + { pcm_test_char ("char.sds" , SF_FORMAT_SDS | SF_FORMAT_PCM_S8, SF_FALSE) ; + pcm_test_short ("short.sds" , SF_FORMAT_SDS | SF_FORMAT_PCM_16, SF_FALSE) ; + pcm_test_24bit ("24bit.sds" , SF_FORMAT_SDS | SF_FORMAT_PCM_24, SF_FALSE) ; + + empty_file_test ("empty_char.sds", SF_FORMAT_SDS | SF_FORMAT_PCM_S8) ; + empty_file_test ("empty_short.sds", SF_FORMAT_SDS | SF_FORMAT_PCM_16) ; + + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "sd2")) + { pcm_test_char ("char.sd2" , SF_FORMAT_SD2 | SF_FORMAT_PCM_S8, SF_TRUE) ; + pcm_test_short ("short.sd2" , SF_FORMAT_SD2 | SF_FORMAT_PCM_16, SF_TRUE) ; + pcm_test_24bit ("24bit.sd2" , SF_FORMAT_SD2 | SF_FORMAT_PCM_24, SF_TRUE) ; + pcm_test_int ("32bit.sd2" , SF_FORMAT_SD2 | SF_FORMAT_PCM_32, SF_TRUE) ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "flac")) + { if (HAVE_EXTERNAL_XIPH_LIBS) + { pcm_test_char ("char.flac" , SF_FORMAT_FLAC | SF_FORMAT_PCM_S8, SF_TRUE) ; + pcm_test_short ("short.flac" , SF_FORMAT_FLAC | SF_FORMAT_PCM_16, SF_TRUE) ; + pcm_test_24bit ("24bit.flac" , SF_FORMAT_FLAC | SF_FORMAT_PCM_24, SF_TRUE) ; + } + else + puts (" No FLAC tests because FLAC support was not compiled in.") ; + test_count++ ; + } ; + + if (do_all || ! strcmp (argv [1], "rf64")) + { pcm_test_char ("char.rf64" , SF_FORMAT_RF64 | SF_FORMAT_PCM_U8, SF_FALSE) ; + pcm_test_short ("short.rf64" , SF_FORMAT_RF64 | SF_FORMAT_PCM_16, SF_FALSE) ; + pcm_test_24bit ("24bit.rf64" , SF_FORMAT_RF64 | SF_FORMAT_PCM_24, SF_FALSE) ; + pcm_test_int ("int.rf64" , SF_FORMAT_RF64 | SF_FORMAT_PCM_32, SF_FALSE) ; + + /* Lite remove start */ + pcm_test_float ("float.rf64" , SF_FORMAT_RF64 | SF_FORMAT_FLOAT , SF_FALSE) ; + pcm_test_double ("double.rf64" , SF_FORMAT_RF64 | SF_FORMAT_DOUBLE, SF_FALSE) ; + empty_file_test ("empty_char.rf64", SF_FORMAT_RF64 | SF_FORMAT_PCM_U8) ; + empty_file_test ("empty_short.rf64", SF_FORMAT_RF64 | SF_FORMAT_PCM_16) ; + empty_file_test ("empty_float.rf64", SF_FORMAT_RF64 | SF_FORMAT_FLOAT) ; + /* Lite remove end */ + + test_count++ ; + } ; + + if (test_count == 0) + { printf ("Mono : ************************************\n") ; + printf ("Mono : * No '%s' test defined.\n", argv [1]) ; + printf ("Mono : ************************************\n") ; + return 1 ; + } ; + + /* Only open file descriptors should be stdin, stdout and stderr. */ + check_open_file_count_or_die (__LINE__) ; + + return 0 ; +} /* main */ + +/*============================================================================================ +** Helper functions and macros. +*/ + +static void create_short_file (const char *filename) ; + +#define CHAR_ERROR(x, y) (abs ((x) - (y)) > 255) +#define INT_ERROR(x, y) (((x) - (y)) != 0) +#define BIT_20_ERROR(x, y) (abs ((x) - (y)) > 4095) +#define TRIBYTE_ERROR(x, y) (abs ((x) - (y)) > 255) +#define FLOAT_ERROR(x, y) (fabs ((x) - (y)) > 1e-5) + +#define CONVERT_DATA(k, len, new, orig) \ + { for ((k) = 0 ; (k) < (len) ; (k) ++) \ + (new) [k] = (orig) [k] ; \ + } + +[+ FOR data_type ++] +/*====================================================================================== +*/ + +static void mono_[+ (get "type_name") +]_test (const char *filename, int format, int long_file_ok, int allow_fd) ; +static void stereo_[+ (get "type_name") +]_test (const char *filename, int format, int long_file_ok, int allow_fd) ; +static void mono_rdwr_[+ (get "type_name") +]_test (const char *filename, int format, int long_file_ok, int allow_fd) ; +static void new_rdwr_[+ (get "type_name") +]_test (const char *filename, int format, int allow_fd) ; +static void multi_seek_test (const char * filename, int format) ; +static void write_seek_extend_test (const char * filename, int format) ; + +static void +pcm_test_[+ (get "type_name") +] (const char *filename, int format, int long_file_ok) +{ SF_INFO sfinfo ; + [+ (get "data_type") +] *orig ; + int k, allow_fd ; + + /* Sd2 files cannot be opened from an existing file descriptor. */ + allow_fd = ((format & SF_FORMAT_TYPEMASK) == SF_FORMAT_SD2) ? SF_FALSE : SF_TRUE ; + + get_unique_test_name (&filename, WRT_TEST_PREFIX) ; + print_test_name ("pcm_test_[+ (get "type_name") +]", filename) ; + + sfinfo.samplerate = 44100 ; + sfinfo.frames = SILLY_WRITE_COUNT ; /* Wrong length. Library should correct this on sf_close. */ + sfinfo.channels = 1 ; + sfinfo.format = format ; + + test_sf_format_or_die (&sfinfo, __LINE__) ; + + gen_windowed_sine_double (orig_data.d, DATA_LENGTH, [+ (get "max_val") +]) ; + + orig = orig_data.[+ (get "data_field") +] ; + + /* Make this a macro so gdb steps over it in one go. */ + CONVERT_DATA (k, DATA_LENGTH, orig, orig_data.d) ; + + /* Some test broken out here. */ + + mono_[+ (get "type_name") +]_test (filename, format, long_file_ok, allow_fd) ; + + /* Sub format DWVW does not allow seeking. */ + if ((format & SF_FORMAT_SUBMASK) == SF_FORMAT_DWVW_16 || + (format & SF_FORMAT_SUBMASK) == SF_FORMAT_DWVW_24) + { unlink (filename) ; + printf ("no seek : ok\n") ; + return ; + } ; + + if ((format & SF_FORMAT_TYPEMASK) != SF_FORMAT_FLAC + && (format & SF_FORMAT_SUBMASK) != SF_FORMAT_ALAC_16 + && (format & SF_FORMAT_SUBMASK) != SF_FORMAT_ALAC_20 + && (format & SF_FORMAT_SUBMASK) != SF_FORMAT_ALAC_24 + && (format & SF_FORMAT_SUBMASK) != SF_FORMAT_ALAC_32 + ) + mono_rdwr_[+ (get "type_name") +]_test (filename, format, long_file_ok, allow_fd) ; + + /* If the format doesn't support stereo we're done. */ + sfinfo.channels = 2 ; + if (sf_format_check (&sfinfo) == 0) + { unlink (filename) ; + puts ("no stereo : ok") ; + return ; + } ; + + stereo_[+ (get "type_name") +]_test (filename, format, long_file_ok, allow_fd) ; + + /* New read/write test. Not sure if this is needed yet. */ + + if ((format & SF_FORMAT_TYPEMASK) != SF_FORMAT_PAF + && (format & SF_FORMAT_TYPEMASK) != SF_FORMAT_VOC + && (format & SF_FORMAT_TYPEMASK) != SF_FORMAT_FLAC + && (format & SF_FORMAT_SUBMASK) != SF_FORMAT_ALAC_16 + && (format & SF_FORMAT_SUBMASK) != SF_FORMAT_ALAC_20 + && (format & SF_FORMAT_SUBMASK) != SF_FORMAT_ALAC_24 + && (format & SF_FORMAT_SUBMASK) != SF_FORMAT_ALAC_32 + ) + new_rdwr_[+ (get "type_name") +]_test (filename, format, allow_fd) ; + + delete_file (format, filename) ; + + puts ("ok") ; + return ; +} /* pcm_test_[+ (get "type_name") +] */ + +static void +mono_[+ (get "type_name") +]_test (const char *filename, int format, int long_file_ok, int allow_fd) +{ SNDFILE *file ; + SF_INFO sfinfo ; + [+ (get "data_type") +] *orig, *test ; + sf_count_t count ; + int k, items, total ; + + sfinfo.samplerate = 44100 ; + sfinfo.frames = SILLY_WRITE_COUNT ; /* Wrong length. Library should correct this on sf_close. */ + sfinfo.channels = 1 ; + sfinfo.format = format ; + + orig = orig_data.[+ (get "data_field") +] ; + test = test_data.[+ (get "data_field") +] ; + + items = DATA_LENGTH ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, allow_fd, __LINE__) ; + + if (sfinfo.frames || sfinfo.sections || sfinfo.seekable) + { printf ("\n\nLine %d : Weird SF_INFO fields.\n", __LINE__) ; + exit (1) ; + } ; + + sf_set_string (file, SF_STR_ARTIST, "Your name here") ; + + test_write_[+ (get "data_type") +]_or_die (file, 0, orig, items, __LINE__) ; + sf_write_sync (file) ; + test_write_[+ (get "data_type") +]_or_die (file, 0, orig, items, __LINE__) ; + sf_write_sync (file) ; + + /* Add non-audio data after the audio. */ + sf_set_string (file, SF_STR_COPYRIGHT, "Copyright (c) 2003") ; + + sf_close (file) ; + + memset (test, 0, items * sizeof ([+ (get "data_type") +])) ; + + if ((format & SF_FORMAT_TYPEMASK) != SF_FORMAT_RAW) + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, allow_fd, __LINE__) ; + + if (sfinfo.format != format) + { printf ("\n\nLine %d : Mono : Returned format incorrect (0x%08X => 0x%08X).\n", __LINE__, format, sfinfo.format) ; + exit (1) ; + } ; + + if (sfinfo.frames < 2 * items) + { printf ("\n\nLine %d : Mono : Incorrect number of frames in file (too short). (%" PRId64 " should be %d)\n", __LINE__, sfinfo.frames, items) ; + exit (1) ; + } ; + + if (! long_file_ok && sfinfo.frames > 2 * items) + { printf ("\n\nLine %d : Mono : Incorrect number of frames in file (too long). (%" PRId64 " should be %d)\n", __LINE__, sfinfo.frames, items) ; + exit (1) ; + } ; + + if (sfinfo.channels != 1) + { printf ("\n\nLine %d : Mono : Incorrect number of channels in file.\n", __LINE__) ; + exit (1) ; + } ; + + if (sfinfo.seekable != 1) + { printf ("\n\nLine %d : File should be seekable.\n", __LINE__) ; + exit (1) ; + } ; + + check_log_buffer_or_die (file, __LINE__) ; + + test_read_[+ (get "data_type") +]_or_die (file, 0, test, items, __LINE__) ; + for (k = 0 ; k < items ; k++) + if ([+ (get "error_func") +] (orig [k], test [k])) + { printf ("\n\nLine %d: Mono : Incorrect sample A (#%d : [+ (get "format_char") +] => [+ (get "format_char") +]).\n", __LINE__, k, orig [k], test [k]) ; + oct_save_[+ (get "data_type") +] (orig, test, items) ; + exit (1) ; + } ; + + /* Test multiple short reads. */ + test_seek_or_die (file, 0, SEEK_SET, 0, sfinfo.channels, __LINE__) ; + + total = 0 ; + for (k = 1 ; k <= 32 ; k++) + { int ik ; + + test_read_[+ (get "data_type") +]_or_die (file, 0, test + total, k, __LINE__) ; + total += k ; + + for (ik = 0 ; ik < total ; ik++) + if ([+ (get "error_func") +] (orig [ik], test [ik])) + { printf ("\n\nLine %d : Mono : Incorrect sample A (#%d : [+ (get "format_char") +] => [+ (get "format_char") +]).\n", __LINE__, ik, orig [ik], test [ik]) ; + exit (1) ; + } ; + } ; + + /* Seek to start of file. */ + test_seek_or_die (file, 0, SEEK_SET, 0, sfinfo.channels, __LINE__) ; + + test_read_[+ (get "data_type") +]_or_die (file, 0, test, 4, __LINE__) ; + for (k = 0 ; k < 4 ; k++) + if ([+ (get "error_func") +] (orig [k], test [k])) + { printf ("\n\nLine %d : Mono : Incorrect sample A (#%d : [+ (get "format_char") +] => [+ (get "format_char") +]).\n", __LINE__, k, orig [k], test [k]) ; + exit (1) ; + } ; + + /* For some codecs we can't go past here. */ + if ((format & SF_FORMAT_SUBMASK) == SF_FORMAT_DWVW_16 || + (format & SF_FORMAT_SUBMASK) == SF_FORMAT_DWVW_24) + { sf_close (file) ; + unlink (filename) ; + printf ("no seek : ") ; + return ; + } ; + + /* Seek to offset from start of file. */ + test_seek_or_die (file, items + 10, SEEK_SET, items + 10, sfinfo.channels, __LINE__) ; + + test_read_[+ (get "data_type") +]_or_die (file, 0, test + 10, 4, __LINE__) ; + for (k = 10 ; k < 14 ; k++) + if ([+ (get "error_func") +] (orig [k], test [k])) + { printf ("\n\nLine %d : Mono : Incorrect sample A (#%d : [+ (get "format_char") +] => [+ (get "format_char") +]).\n", __LINE__, k, test [k], orig [k]) ; + exit (1) ; + } ; + + /* Seek to offset from current position. */ + test_seek_or_die (file, 6, SEEK_CUR, items + 20, sfinfo.channels, __LINE__) ; + + test_read_[+ (get "data_type") +]_or_die (file, 0, test + 20, 4, __LINE__) ; + for (k = 20 ; k < 24 ; k++) + if ([+ (get "error_func") +] (orig [k], test [k])) + { printf ("\n\nLine %d : Mono : Incorrect sample A (#%d : [+ (get "format_char") +] => [+ (get "format_char") +]).\n", __LINE__, k, test [k], orig [k]) ; + exit (1) ; + } ; + + /* Seek to offset from end of file. */ + test_seek_or_die (file, -1 * (sfinfo.frames - 10), SEEK_END, 10, sfinfo.channels, __LINE__) ; + + test_read_[+ (get "data_type") +]_or_die (file, 0, test + 10, 4, __LINE__) ; + for (k = 10 ; k < 14 ; k++) + if ([+ (get "error_func") +] (orig [k], test [k])) + { printf ("\n\nLine %d : Mono : Incorrect sample D (#%d : [+ (get "format_char") +] => [+ (get "format_char") +]).\n", __LINE__, k, test [k], orig [k]) ; + exit (1) ; + } ; + + /* Check read past end of file followed by sf_seek (sndfile, 0, SEEK_CUR). */ + test_seek_or_die (file, 0, SEEK_SET, 0, sfinfo.channels, __LINE__) ; + + count = 0 ; + while (count < sfinfo.frames) + count += sf_read_[+ (get "data_type") +] (file, test, 311) ; + + /* Check that no error has occurred. */ + if (sf_error (file)) + { printf ("\n\nLine %d : Mono : error where there shouldn't have been one.\n", __LINE__) ; + puts (sf_strerror (file)) ; + exit (1) ; + } ; + + /* Check that we haven't read beyond EOF. */ + if (count > sfinfo.frames) + { printf ("\n\nLines %d : read past end of file (%" PRId64 " should be %" PRId64 ")\n", __LINE__, count, sfinfo.frames) ; + exit (1) ; + } ; + + test_seek_or_die (file, 0, SEEK_CUR, sfinfo.frames, sfinfo.channels, __LINE__) ; + + sf_close (file) ; + + multi_seek_test (filename, format) ; + write_seek_extend_test (filename, format) ; + +} /* mono_[+ (get "type_name") +]_test */ + +static void +stereo_[+ (get "type_name") +]_test (const char *filename, int format, int long_file_ok, int allow_fd) +{ SNDFILE *file ; + SF_INFO sfinfo ; + [+ (get "data_type") +] *orig, *test ; + int k, items, frames ; + + sfinfo.samplerate = 44100 ; + sfinfo.frames = SILLY_WRITE_COUNT ; /* Wrong length. Library should correct this on sf_close. */ + sfinfo.channels = 2 ; + sfinfo.format = format ; + + gen_windowed_sine_double (orig_data.d, DATA_LENGTH, [+ (get "max_val") +]) ; + + orig = orig_data.[+ (get "data_field") +] ; + test = test_data.[+ (get "data_field") +] ; + + /* Make this a macro so gdb steps over it in one go. */ + CONVERT_DATA (k, DATA_LENGTH, orig, orig_data.d) ; + + items = DATA_LENGTH ; + frames = items / sfinfo.channels ; + + file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, allow_fd, __LINE__) ; + + sf_set_string (file, SF_STR_ARTIST, "Your name here") ; + + test_writef_[+ (get "data_type") +]_or_die (file, 0, orig, frames, __LINE__) ; + + sf_set_string (file, SF_STR_COPYRIGHT, "Copyright (c) 2003") ; + + sf_close (file) ; + + memset (test, 0, items * sizeof ([+ (get "data_type") +])) ; + + if ((format & SF_FORMAT_TYPEMASK) != SF_FORMAT_RAW) + memset (&sfinfo, 0, sizeof (sfinfo)) ; + + file = test_open_file_or_die (filename, SFM_READ, &sfinfo, allow_fd, __LINE__) ; + + if (sfinfo.format != format) + { printf ("\n\nLine %d : Stereo : Returned format incorrect (0x%08X => 0x%08X).\n", + __LINE__, format, sfinfo.format) ; + exit (1) ; + } ; + + if (sfinfo.frames < frames) + { printf ("\n\nLine %d : Stereo : Incorrect number of frames in file (too short). (%" PRId64 " should be %d)\n", + __LINE__, sfinfo.frames, frames) ; + exit (1) ; + } ; + + if (! long_file_ok && sfinfo.frames > frames) + { printf ("\n\nLine %d : Stereo : Incorrect number of frames in file (too long). (%" PRId64 " should be %d)\n", + __LINE__, sfinfo.frames, frames) ; + exit (1) ; + } ; + + if (sfinfo.channels != 2) + { printf ("\n\nLine %d : Stereo : Incorrect number of channels in file.\n", __LINE__) ; + exit (1) ; + } ; + + check_log_buffer_or_die (file, __LINE__) ; + + test_readf_[+ (get "data_type") +]_or_die (file, 0, test, frames, __LINE__) ; + for (k = 0 ; k < items ; k++) + if ([+ (get "error_func") +] (test [k], orig [k])) + { printf ("\n\nLine %d : Stereo : Incorrect sample (#%d : [+ (get "format_char") +] => [+ (get "format_char") +]).\n", __LINE__, k, orig [k], test [k]) ; + exit (1) ; + } ; + + /* Seek to start of file. */ + test_seek_or_die (file, 0, SEEK_SET, 0, sfinfo.channels, __LINE__) ; + + test_readf_[+ (get "data_type") +]_or_die (file, 0, test, 2, __LINE__) ; + for (k = 0 ; k < 4 ; k++) + if ([+ (get "error_func") +] (test [k], orig [k])) + { printf ("\n\nLine %d : Stereo : Incorrect sample (#%d : [+ (get "format_char") +] => [+ (get "format_char") +]).\n", __LINE__, k, orig [k], test [k]) ; + exit (1) ; + } ; + + /* Seek to offset from start of file. */ + test_seek_or_die (file, 10, SEEK_SET, 10, sfinfo.channels, __LINE__) ; + + /* Check for errors here. */ + if (sf_error (file)) + { printf ("Line %d: Should NOT return an error.\n", __LINE__) ; + puts (sf_strerror (file)) ; + exit (1) ; + } ; + + if (sf_read_[+ (get "data_type") +] (file, test, 1) > 0) + { printf ("Line %d: Should return 0.\n", __LINE__) ; + exit (1) ; + } ; + + if (! sf_error (file)) + { printf ("Line %d: Should return an error.\n", __LINE__) ; + exit (1) ; + } ; + /*-----------------------*/ + + test_readf_[+ (get "data_type") +]_or_die (file, 0, test + 10, 2, __LINE__) ; + for (k = 20 ; k < 24 ; k++) + if ([+ (get "error_func") +] (test [k], orig [k])) + { printf ("\n\nLine %d : Stereo : Incorrect sample (#%d : [+ (get "format_char") +] => [+ (get "format_char") +]).\n", __LINE__, k, orig [k], test [k]) ; + exit (1) ; + } ; + + /* Seek to offset from current position. */ + test_seek_or_die (file, 8, SEEK_CUR, 20, sfinfo.channels, __LINE__) ; + + test_readf_[+ (get "data_type") +]_or_die (file, 0, test + 20, 2, __LINE__) ; + for (k = 40 ; k < 44 ; k++) + if ([+ (get "error_func") +] (test [k], orig [k])) + { printf ("\n\nLine %d : Stereo : Incorrect sample (#%d : [+ (get "format_char") +] => [+ (get "format_char") +]).\n", __LINE__, k, orig [k], test [k]) ; + exit (1) ; + } ; + + /* Seek to offset from end of file. */ + test_seek_or_die (file, -1 * (sfinfo.frames - 10), SEEK_END, 10, sfinfo.channels, __LINE__) ; + + test_readf_[+ (get "data_type") +]_or_die (file, 0, test + 20, 2, __LINE__) ; + for (k = 20 ; k < 24 ; k++) + if ([+ (get "error_func") +] (test [k], orig [k])) + { printf ("\n\nLine %d : Stereo : Incorrect sample (#%d : [+ (get "format_char") +] => [+ (get "format_char") +]).\n", __LINE__, k, orig [k], test [k]) ; + exit (1) ; + } ; + + sf_close (file) ; +} /* stereo_[+ (get "type_name") +]_test */ + +static void +mono_rdwr_[+ (get "type_name") +]_test (const char *filename, int format, int long_file_ok, int allow_fd) +{ SNDFILE *file ; + SF_INFO sfinfo ; + [+ (get "data_type") +] *orig, *test ; + int k, pass ; + + switch (format & SF_FORMAT_SUBMASK) + { case SF_FORMAT_ALAC_16 : + case SF_FORMAT_ALAC_20 : + case SF_FORMAT_ALAC_24 : + case SF_FORMAT_ALAC_32 : + allow_fd = 0 ; + break ; + + default : + break ; + } ; + + orig = orig_data.[+ (get "data_field") +] ; + test = test_data.[+ (get "data_field") +] ; + + sfinfo.samplerate = SAMPLE_RATE ; + sfinfo.frames = DATA_LENGTH ; + sfinfo.channels = 1 ; + sfinfo.format = format ; + + if ((format & SF_FORMAT_TYPEMASK) == SF_FORMAT_RAW + || (format & SF_FORMAT_TYPEMASK) == SF_FORMAT_AU + || (format & SF_FORMAT_TYPEMASK) == SF_FORMAT_SD2) + unlink (filename) ; + else + { /* Create a short file. */ + create_short_file (filename) ; + + /* Opening a already existing short file (ie invalid header) RDWR is disallowed. + ** If this returns a valif pointer sf_open() screwed up. + */ + if ((file = sf_open (filename, SFM_RDWR, &sfinfo))) + { printf ("\n\nLine %d: sf_open should (SFM_RDWR) have failed but didn't.\n", __LINE__) ; + exit (1) ; + } ; + + /* Truncate the file to zero bytes. */ + if (truncate_file_to_zero (filename) < 0) + { printf ("\n\nLine %d: truncate_file_to_zero (%s) failed", __LINE__, filename) ; + perror (NULL) ; + exit (1) ; + } ; + } ; + + /* Opening a zero length file RDWR is allowed, but the SF_INFO struct must contain + ** all the usual data required when opening the file in WRITE mode. + */ + sfinfo.samplerate = SAMPLE_RATE ; + sfinfo.frames = DATA_LENGTH ; + sfinfo.channels = 1 ; + sfinfo.format = format ; + + file = test_open_file_or_die (filename, SFM_RDWR, &sfinfo, allow_fd, __LINE__) ; + + /* Do 3 writes followed by reads. After each, check the data and the current + ** read and write offsets. + */ + for (pass = 1 ; pass <= 3 ; pass ++) + { orig [20] = pass * 2 ; + + /* Write some data. */ + test_write_[+ (get "data_type") +]_or_die (file, pass, orig, DATA_LENGTH, __LINE__) ; + + test_read_write_position_or_die (file, __LINE__, pass, (pass - 1) * DATA_LENGTH, pass * DATA_LENGTH) ; + + /* Read what we just wrote. */ + test_read_[+ (get "data_type") +]_or_die (file, 0, test, DATA_LENGTH, __LINE__) ; + + /* Check the data. */ + for (k = 0 ; k < DATA_LENGTH ; k++) + if ([+ (get "error_func") +] (orig [k], test [k])) + { printf ("\n\nLine %d (pass %d) A : Error at sample %d ([+ (get "format_char") +] => [+ (get "format_char") +]).\n", __LINE__, pass, k, orig [k], test [k]) ; + oct_save_[+ (get "data_type") +] (orig, test, DATA_LENGTH) ; + exit (1) ; + } ; + + test_read_write_position_or_die (file, __LINE__, pass, pass * DATA_LENGTH, pass * DATA_LENGTH) ; + } ; /* for (pass ...) */ + + sf_close (file) ; + + /* Open the file again to check the data. */ + file = test_open_file_or_die (filename, SFM_RDWR, &sfinfo, allow_fd, __LINE__) ; + + if (sfinfo.format != format) + { printf ("\n\nLine %d : Returned format incorrect (0x%08X => 0x%08X).\n", __LINE__, format, sfinfo.format) ; + exit (1) ; + } ; + + if (sfinfo.frames < 3 * DATA_LENGTH) + { printf ("\n\nLine %d : Not enough frames in file. (%" PRId64 " < %d)\n", __LINE__, sfinfo.frames, 3 * DATA_LENGTH) ; + exit (1) ; + } + + if (! long_file_ok && sfinfo.frames != 3 * DATA_LENGTH) + { printf ("\n\nLine %d : Incorrect number of frames in file. (%" PRId64 " should be %d)\n", __LINE__, sfinfo.frames, 3 * DATA_LENGTH) ; + exit (1) ; + } ; + + if (sfinfo.channels != 1) + { printf ("\n\nLine %d : Incorrect number of channels in file.\n", __LINE__) ; + exit (1) ; + } ; + + if (! long_file_ok) + test_read_write_position_or_die (file, __LINE__, 0, 0, 3 * DATA_LENGTH) ; + else + test_seek_or_die (file, 3 * DATA_LENGTH, SFM_WRITE | SEEK_SET, 3 * DATA_LENGTH, sfinfo.channels, __LINE__) ; + + for (pass = 1 ; pass <= 3 ; pass ++) + { orig [20] = pass * 2 ; + + test_read_write_position_or_die (file, __LINE__, pass, (pass - 1) * DATA_LENGTH, 3 * DATA_LENGTH) ; + + /* Read what we just wrote. */ + test_read_[+ (get "data_type") +]_or_die (file, pass, test, DATA_LENGTH, __LINE__) ; + + /* Check the data. */ + for (k = 0 ; k < DATA_LENGTH ; k++) + if ([+ (get "error_func") +] (orig [k], test [k])) + { printf ("\n\nLine %d (pass %d) B : Error at sample %d ([+ (get "format_char") +] => [+ (get "format_char") +]).\n", __LINE__, pass, k, orig [k], test [k]) ; + oct_save_[+ (get "data_type") +] (orig, test, DATA_LENGTH) ; + exit (1) ; + } ; + + } ; /* for (pass ...) */ + + sf_close (file) ; +} /* mono_rdwr_[+ (get "data_type") +]_test */ + +static void +new_rdwr_[+ (get "type_name") +]_test (const char *filename, int format, int allow_fd) +{ SNDFILE *wfile, *rwfile ; + SF_INFO sfinfo ; + [+ (get "data_type") +] *orig, *test ; + int items, frames ; + + orig = orig_data.[+ (get "data_field") +] ; + test = test_data.[+ (get "data_field") +] ; + + sfinfo.samplerate = 44100 ; + sfinfo.frames = SILLY_WRITE_COUNT ; /* Wrong length. Library should correct this on sf_close. */ + sfinfo.channels = 2 ; + sfinfo.format = format ; + + items = DATA_LENGTH ; + frames = items / sfinfo.channels ; + + wfile = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, allow_fd, __LINE__) ; + sf_command (wfile, SFC_SET_UPDATE_HEADER_AUTO, NULL, SF_TRUE) ; + test_writef_[+ (get "data_type") +]_or_die (wfile, 1, orig, frames, __LINE__) ; + sf_write_sync (wfile) ; + test_writef_[+ (get "data_type") +]_or_die (wfile, 2, orig, frames, __LINE__) ; + sf_write_sync (wfile) ; + + rwfile = test_open_file_or_die (filename, SFM_RDWR, &sfinfo, allow_fd, __LINE__) ; + if (sfinfo.frames != 2 * frames) + { printf ("\n\nLine %d : incorrect number of frames in file (%" PRId64 " should be %d)\n\n", __LINE__, sfinfo.frames, 2 * frames) ; + exit (1) ; + } ; + + test_writef_[+ (get "data_type") +]_or_die (wfile, 3, orig, frames, __LINE__) ; + + test_readf_[+ (get "data_type") +]_or_die (rwfile, 1, test, frames, __LINE__) ; + test_readf_[+ (get "data_type") +]_or_die (rwfile, 2, test, frames, __LINE__) ; + + sf_close (wfile) ; + sf_close (rwfile) ; +} /* new_rdwr_[+ (get "type_name") +]_test */ + +[+ ENDFOR data_type +] + +/*---------------------------------------------------------------------------------------- +*/ + +static void +empty_file_test (const char *filename, int format) +{ SNDFILE *file ; + SF_INFO info ; + int allow_fd ; + + /* Sd2 files cannot be opened from an existing file descriptor. */ + allow_fd = ((format & SF_FORMAT_TYPEMASK) == SF_FORMAT_SD2) ? SF_FALSE : SF_TRUE ; + + get_unique_test_name (&filename, WRT_TEST_PREFIX) ; + print_test_name ("empty_file_test", filename) ; + + unlink (filename) ; + + info.samplerate = 48000 ; + info.channels = 2 ; + info.format = format ; + info.frames = 0 ; + + if (sf_format_check (&info) == SF_FALSE) + { info.channels = 1 ; + if (sf_format_check (&info) == SF_FALSE) + { puts ("invalid file format") ; + return ; + } ; + } ; + + /* Create an empty file. */ + file = test_open_file_or_die (filename, SFM_WRITE, &info, allow_fd, __LINE__) ; + sf_close (file) ; + + /* Open for read and check the length. */ + file = test_open_file_or_die (filename, SFM_READ, &info, allow_fd, __LINE__) ; + + if (info.frames != 0) + { printf ("\n\nError : frame count (%" PRId64 ") should be zero.\n", info.frames) ; + exit (1) ; + } ; + + sf_close (file) ; + + /* Open for read/write and check the length. */ + file = test_open_file_or_die (filename, SFM_RDWR, &info, allow_fd, __LINE__) ; + + if (info.frames != 0) + { printf ("\n\nError : frame count (%" PRId64 ") should be zero.\n", info.frames) ; + exit (1) ; + } ; + + sf_close (file) ; + + /* Open for read and check the length. */ + file = test_open_file_or_die (filename, SFM_READ, &info, allow_fd, __LINE__) ; + + if (info.frames != 0) + { printf ("\n\nError : frame count (%" PRId64 ") should be zero.\n", info.frames) ; + exit (1) ; + } ; + + sf_close (file) ; + + check_open_file_count_or_die (__LINE__) ; + + unlink (filename) ; + puts ("ok") ; + + return ; +} /* empty_file_test */ + + +/*---------------------------------------------------------------------------------------- +*/ + +static void +create_short_file (const char *filename) +{ FILE *file ; + + if (! (file = fopen (filename, "w"))) + { printf ("create_short_file : fopen (%s, \"w\") failed.", filename) ; + fflush (stdout) ; + perror (NULL) ; + exit (1) ; + } ; + + fprintf (file, "This is the file data.\n") ; + + fclose (file) ; +} /* create_short_file */ + + +static void +multi_seek_test (const char * filename, int format) +{ SNDFILE * file ; + SF_INFO info ; + sf_count_t pos ; + int k ; + + /* This test doesn't work on the following. */ + switch (format & SF_FORMAT_TYPEMASK) + { case SF_FORMAT_RAW : + return ; + + default : + break ; + } ; + + memset (&info, 0, sizeof (info)) ; + + generate_file (filename, format, 88200) ; + + file = test_open_file_or_die (filename, SFM_READ, &info, SF_FALSE, __LINE__) ; + + for (k = 0 ; k < 10 ; k++) + { pos = info.frames / (k + 2) ; + test_seek_or_die (file, pos, SEEK_SET, pos, info.channels, __LINE__) ; + } ; + + sf_close (file) ; +} /* multi_seek_test */ + +static void +write_seek_extend_test (const char * filename, int format) +{ SNDFILE * file ; + SF_INFO info ; + short *orig, *test ; + unsigned items, k ; + + /* This test doesn't work on the following container formats. */ + switch (format & SF_FORMAT_TYPEMASK) + { case SF_FORMAT_FLAC : + case SF_FORMAT_HTK : + case SF_FORMAT_PAF : + case SF_FORMAT_SDS : + case SF_FORMAT_SVX : + return ; + + default : + break ; + } ; + + /* This test doesn't work on the following codec formats. */ + switch (format & SF_FORMAT_SUBMASK) + { case SF_FORMAT_ALAC_16 : + case SF_FORMAT_ALAC_20 : + case SF_FORMAT_ALAC_24 : + case SF_FORMAT_ALAC_32 : + return ; + + default : + break ; + } ; + + memset (&info, 0, sizeof (info)) ; + + info.samplerate = 48000 ; + info.channels = 1 ; + info.format = format ; + + items = 512 ; + exit_if_true (items > ARRAY_LEN (orig_data.s), "Line %d : Bad assumption.\n", __LINE__) ; + + orig = orig_data.s ; + test = test_data.s ; + + for (k = 0 ; k < ARRAY_LEN (orig_data.s) ; k++) + orig [k] = 0x3fff ; + + file = test_open_file_or_die (filename, SFM_WRITE, &info, SF_FALSE, __LINE__) ; + test_write_short_or_die (file, 0, orig, items, __LINE__) ; + + /* Extend the file using a seek. */ + test_seek_or_die (file, 2 * items, SEEK_SET, 2 * items, info.channels, __LINE__) ; + + test_writef_short_or_die (file, 0, orig, items, __LINE__) ; + sf_close (file) ; + + file = test_open_file_or_die (filename, SFM_READ, &info, SF_FALSE, __LINE__) ; + test_read_short_or_die (file, 0, test, 3 * items, __LINE__) ; + sf_close (file) ; + + if (info.frames < 3 * items) + { printf ("\n\nLine %d : Incorrect number of frames in file (too short). (%" PRId64 " should be %d)\n", __LINE__, info.frames, 3 * items) ; + exit (1) ; + } ; + + /* Can't do these formats due to scaling. */ + switch (format & SF_FORMAT_SUBMASK) + { case SF_FORMAT_PCM_S8 : + case SF_FORMAT_PCM_U8 : + return ; + default : + break ; + } ; + + for (k = 0 ; k < items ; k++) + { exit_if_true (test [k] != 0x3fff, "Line %d : test [%d] == %d, should be 0x3fff.\n", __LINE__, k, test [k]) ; + exit_if_true (test [items + k] != 0, "Line %d : test [%d] == %d, should be 0.\n", __LINE__, items + k, test [items + k]) ; + exit_if_true (test [2 * items + k] != 0x3fff, "Line %d : test [%d] == %d, should be 0x3fff.\n", __LINE__, 2 * items + k, test [2 * items + k]) ; + } ; + + return ; +} /* write_seek_extend_test */ + + diff --git a/extern/libsndfile-modified/vcpkg.json b/extern/libsndfile-modified/vcpkg.json new file mode 100644 index 000000000..de8a94883 --- /dev/null +++ b/extern/libsndfile-modified/vcpkg.json @@ -0,0 +1,39 @@ +{ + "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json", + "name": "libsndfile", + "description": "A library for reading and writing audio files", + "version-semver": "1.2.0", + "default-features": [ + "external-libs", + "mpeg" + ], + "features": { + "external-libs": { + "description": "Enable FLAC, Vorbis, and Opus codecs", + "dependencies": [ + "libvorbis", + "libflac", + "opus" + ] + }, + "mpeg": { + "description": "Enable MPEG codecs", + "dependencies": [ + "mpg123", + "mp3lame" + ] + }, + "regtest": { + "description": "Build regtest", + "dependencies": [ + "sqlite3" + ] + }, + "experimental": { + "description": "Enable experimental code", + "dependencies": [ + "speex" + ] + } + } +}